xref: /titanic_51/usr/src/uts/common/os/sunmdi.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * Multipath driver interface (MDI) implementation; see mdi_impl.h for a more
30*7c478bd9Sstevel@tonic-gate  * detailed discussion of the overall mpxio architecture.
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * Default locking order:
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * _NOTE(LOCK_ORDER(mdi_mutex, mdi_phci::ph_mutex))
35*7c478bd9Sstevel@tonic-gate  * _NOTE(LOCK_ORDER(mdi_mutex, mdi_client::ct_mutex))
36*7c478bd9Sstevel@tonic-gate  * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex))
37*7c478bd9Sstevel@tonic-gate  * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex))
38*7c478bd9Sstevel@tonic-gate  * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex))
39*7c478bd9Sstevel@tonic-gate  */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #include <sys/note.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/buf.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/open.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/poll.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/promif.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/taskq.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/epm.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/sunpm.h>
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
69*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
70*7c478bd9Sstevel@tonic-gate int	mdi_debug = 1;
71*7c478bd9Sstevel@tonic-gate #define	MDI_DEBUG(level, stmnt) \
72*7c478bd9Sstevel@tonic-gate 	    if (mdi_debug >= (level)) i_mdi_log stmnt
73*7c478bd9Sstevel@tonic-gate static void i_mdi_log(int, dev_info_t *, const char *fmt, ...);
74*7c478bd9Sstevel@tonic-gate #else	/* !DEBUG */
75*7c478bd9Sstevel@tonic-gate #define	MDI_DEBUG(level, stmnt)
76*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate extern pri_t	minclsyspri;
79*7c478bd9Sstevel@tonic-gate extern int	modrootloaded;
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * Global mutex:
83*7c478bd9Sstevel@tonic-gate  * Protects vHCI list and structure members, pHCI and Client lists.
84*7c478bd9Sstevel@tonic-gate  */
85*7c478bd9Sstevel@tonic-gate kmutex_t	mdi_mutex;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate /*
88*7c478bd9Sstevel@tonic-gate  * Registered vHCI class driver lists
89*7c478bd9Sstevel@tonic-gate  */
90*7c478bd9Sstevel@tonic-gate int		mdi_vhci_count;
91*7c478bd9Sstevel@tonic-gate mdi_vhci_t	*mdi_vhci_head;
92*7c478bd9Sstevel@tonic-gate mdi_vhci_t	*mdi_vhci_tail;
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /*
95*7c478bd9Sstevel@tonic-gate  * Client Hash Table size
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate static int	mdi_client_table_size = CLIENT_HASH_TABLE_SIZE;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * taskq interface definitions
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate #define	MDI_TASKQ_N_THREADS	8
103*7c478bd9Sstevel@tonic-gate #define	MDI_TASKQ_PRI		minclsyspri
104*7c478bd9Sstevel@tonic-gate #define	MDI_TASKQ_MINALLOC	(4*mdi_taskq_n_threads)
105*7c478bd9Sstevel@tonic-gate #define	MDI_TASKQ_MAXALLOC	(500*mdi_taskq_n_threads)
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate taskq_t				*mdi_taskq;
108*7c478bd9Sstevel@tonic-gate static uint_t			mdi_taskq_n_threads = MDI_TASKQ_N_THREADS;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate static int		mdi_max_bus_config_threads = 100;
111*7c478bd9Sstevel@tonic-gate /*
112*7c478bd9Sstevel@tonic-gate  * To reduce unnecessary BUS_CONFIG_ALLs, do not BUS_CONFIG_ALL phcis in the
113*7c478bd9Sstevel@tonic-gate  * context of a BUS_CONFIG_ONE if a BUS_CONFIG_ALL has already been performed
114*7c478bd9Sstevel@tonic-gate  * in the last mdi_bus_config_timeout seconds.
115*7c478bd9Sstevel@tonic-gate  */
116*7c478bd9Sstevel@tonic-gate static int		mdi_bus_config_timeout = 60;	/* in seconds */
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate /*
119*7c478bd9Sstevel@tonic-gate  * MDI component property name/value string definitions
120*7c478bd9Sstevel@tonic-gate  */
121*7c478bd9Sstevel@tonic-gate const char 		*mdi_component_prop = "mpxio-component";
122*7c478bd9Sstevel@tonic-gate const char		*mdi_component_prop_vhci = "vhci";
123*7c478bd9Sstevel@tonic-gate const char		*mdi_component_prop_phci = "phci";
124*7c478bd9Sstevel@tonic-gate const char		*mdi_component_prop_client = "client";
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate /*
127*7c478bd9Sstevel@tonic-gate  * MDI client global unique identifier property name
128*7c478bd9Sstevel@tonic-gate  */
129*7c478bd9Sstevel@tonic-gate const char		*mdi_client_guid_prop = "client-guid";
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate /*
132*7c478bd9Sstevel@tonic-gate  * MDI client load balancing property name/value string definitions
133*7c478bd9Sstevel@tonic-gate  */
134*7c478bd9Sstevel@tonic-gate const char		*mdi_load_balance = "load-balance";
135*7c478bd9Sstevel@tonic-gate const char		*mdi_load_balance_none = "none";
136*7c478bd9Sstevel@tonic-gate const char		*mdi_load_balance_rr = "round-robin";
137*7c478bd9Sstevel@tonic-gate const char		*mdi_load_balance_lba = "logical-block";
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate /*
140*7c478bd9Sstevel@tonic-gate  * Obsolete vHCI class definition; to be removed after Leadville update
141*7c478bd9Sstevel@tonic-gate  */
142*7c478bd9Sstevel@tonic-gate const char *mdi_vhci_class_scsi = MDI_HCI_CLASS_SCSI;
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate static char vhci_greeting[] =
145*7c478bd9Sstevel@tonic-gate 	"\tThere already exists one vHCI driver for class %s\n"
146*7c478bd9Sstevel@tonic-gate 	"\tOnly one vHCI driver for each class is allowed\n";
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate /*
149*7c478bd9Sstevel@tonic-gate  * Static function prototypes
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate static int		i_mdi_phci_offline(dev_info_t *, uint_t);
152*7c478bd9Sstevel@tonic-gate static int		i_mdi_client_offline(dev_info_t *, uint_t);
153*7c478bd9Sstevel@tonic-gate static int		i_mdi_phci_pre_detach(dev_info_t *, ddi_detach_cmd_t);
154*7c478bd9Sstevel@tonic-gate static void		i_mdi_phci_post_detach(dev_info_t *,
155*7c478bd9Sstevel@tonic-gate 			    ddi_detach_cmd_t, int);
156*7c478bd9Sstevel@tonic-gate static int		i_mdi_client_pre_detach(dev_info_t *,
157*7c478bd9Sstevel@tonic-gate 			    ddi_detach_cmd_t);
158*7c478bd9Sstevel@tonic-gate static void		i_mdi_client_post_detach(dev_info_t *,
159*7c478bd9Sstevel@tonic-gate 			    ddi_detach_cmd_t, int);
160*7c478bd9Sstevel@tonic-gate static void		i_mdi_pm_hold_pip(mdi_pathinfo_t *);
161*7c478bd9Sstevel@tonic-gate static void		i_mdi_pm_rele_pip(mdi_pathinfo_t *);
162*7c478bd9Sstevel@tonic-gate static int 		i_mdi_lba_lb(mdi_client_t *ct,
163*7c478bd9Sstevel@tonic-gate 			    mdi_pathinfo_t **ret_pip, struct buf *buf);
164*7c478bd9Sstevel@tonic-gate static void		i_mdi_pm_hold_client(mdi_client_t *, int);
165*7c478bd9Sstevel@tonic-gate static void		i_mdi_pm_rele_client(mdi_client_t *, int);
166*7c478bd9Sstevel@tonic-gate static void		i_mdi_pm_reset_client(mdi_client_t *);
167*7c478bd9Sstevel@tonic-gate static void		i_mdi_pm_hold_all_phci(mdi_client_t *);
168*7c478bd9Sstevel@tonic-gate static int		i_mdi_power_all_phci(mdi_client_t *);
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate /*
172*7c478bd9Sstevel@tonic-gate  * Internal mdi_pathinfo node functions
173*7c478bd9Sstevel@tonic-gate  */
174*7c478bd9Sstevel@tonic-gate static int		i_mdi_pi_kstat_create(mdi_pathinfo_t *);
175*7c478bd9Sstevel@tonic-gate static void		i_mdi_pi_kstat_destroy(mdi_pathinfo_t *);
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate static mdi_vhci_t	*i_mdi_vhci_class2vhci(char *);
178*7c478bd9Sstevel@tonic-gate static mdi_vhci_t	*i_devi_get_vhci(dev_info_t *);
179*7c478bd9Sstevel@tonic-gate static mdi_phci_t	*i_devi_get_phci(dev_info_t *);
180*7c478bd9Sstevel@tonic-gate static void		i_mdi_phci_lock(mdi_phci_t *, mdi_pathinfo_t *);
181*7c478bd9Sstevel@tonic-gate static void		i_mdi_phci_get_client_lock(mdi_phci_t *,
182*7c478bd9Sstevel@tonic-gate 			    mdi_client_t *);
183*7c478bd9Sstevel@tonic-gate static void		i_mdi_phci_unlock(mdi_phci_t *);
184*7c478bd9Sstevel@tonic-gate static mdi_pathinfo_t	*i_mdi_pi_alloc(mdi_phci_t *, char *,
185*7c478bd9Sstevel@tonic-gate 			    mdi_client_t *, int);
186*7c478bd9Sstevel@tonic-gate static void		i_mdi_phci_add_path(mdi_phci_t *, mdi_pathinfo_t *);
187*7c478bd9Sstevel@tonic-gate static void		i_mdi_client_add_path(mdi_client_t *, mdi_pathinfo_t *);
188*7c478bd9Sstevel@tonic-gate static void		i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *,
189*7c478bd9Sstevel@tonic-gate 			    mdi_client_t *);
190*7c478bd9Sstevel@tonic-gate static void		i_mdi_phci_remove_path(mdi_phci_t *, mdi_pathinfo_t *);
191*7c478bd9Sstevel@tonic-gate static void		i_mdi_client_remove_path(mdi_client_t *,
192*7c478bd9Sstevel@tonic-gate 			    mdi_pathinfo_t *);
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate static int		i_mdi_pi_state_change(mdi_pathinfo_t *,
195*7c478bd9Sstevel@tonic-gate 			    mdi_pathinfo_state_t, int);
196*7c478bd9Sstevel@tonic-gate static int		i_mdi_pi_offline(mdi_pathinfo_t *, int);
197*7c478bd9Sstevel@tonic-gate static dev_info_t	*i_mdi_devinfo_create(mdi_vhci_t *, char *, char *,
198*7c478bd9Sstevel@tonic-gate 			    char **, int, int);
199*7c478bd9Sstevel@tonic-gate static dev_info_t	*i_mdi_devinfo_find(mdi_vhci_t *, char *, char *);
200*7c478bd9Sstevel@tonic-gate static int		i_mdi_devinfo_remove(dev_info_t *, dev_info_t *, int);
201*7c478bd9Sstevel@tonic-gate static int		i_mdi_is_child_present(dev_info_t *, dev_info_t *);
202*7c478bd9Sstevel@tonic-gate static mdi_client_t	*i_mdi_client_alloc(mdi_vhci_t *, char *, char *, int);
203*7c478bd9Sstevel@tonic-gate static void		i_mdi_client_enlist_table(mdi_vhci_t *, mdi_client_t *);
204*7c478bd9Sstevel@tonic-gate static void		i_mdi_client_delist_table(mdi_vhci_t *, mdi_client_t *);
205*7c478bd9Sstevel@tonic-gate static mdi_client_t	*i_mdi_client_find(mdi_vhci_t *, char *);
206*7c478bd9Sstevel@tonic-gate static void		i_mdi_client_update_state(mdi_client_t *);
207*7c478bd9Sstevel@tonic-gate static int		i_mdi_client_compute_state(mdi_client_t *,
208*7c478bd9Sstevel@tonic-gate 			    mdi_phci_t *);
209*7c478bd9Sstevel@tonic-gate static void		i_mdi_client_lock(mdi_client_t *, mdi_pathinfo_t *);
210*7c478bd9Sstevel@tonic-gate static void		i_mdi_client_unlock(mdi_client_t *);
211*7c478bd9Sstevel@tonic-gate static int		i_mdi_client_free(mdi_vhci_t *, mdi_client_t *);
212*7c478bd9Sstevel@tonic-gate static mdi_client_t	*i_devi_get_client(dev_info_t *);
213*7c478bd9Sstevel@tonic-gate static int		i_mdi_pi_enable_disable(dev_info_t *, dev_info_t *, int,
214*7c478bd9Sstevel@tonic-gate 			int);
215*7c478bd9Sstevel@tonic-gate /*
216*7c478bd9Sstevel@tonic-gate  * Failover related function prototypes
217*7c478bd9Sstevel@tonic-gate  */
218*7c478bd9Sstevel@tonic-gate static int		i_mdi_failover(void *);
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate /*
221*7c478bd9Sstevel@tonic-gate  * misc internal functions
222*7c478bd9Sstevel@tonic-gate  */
223*7c478bd9Sstevel@tonic-gate static int		i_mdi_get_hash_key(char *);
224*7c478bd9Sstevel@tonic-gate static int		i_map_nvlist_error_to_mdi(int);
225*7c478bd9Sstevel@tonic-gate static void		i_mdi_report_path_state(mdi_client_t *,
226*7c478bd9Sstevel@tonic-gate 			    mdi_pathinfo_t *);
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate /* called once when first vhci registers with mdi */
229*7c478bd9Sstevel@tonic-gate static void
230*7c478bd9Sstevel@tonic-gate i_mdi_init()
231*7c478bd9Sstevel@tonic-gate {
232*7c478bd9Sstevel@tonic-gate 	static int initialized = 0;
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	if (initialized)
235*7c478bd9Sstevel@tonic-gate 		return;
236*7c478bd9Sstevel@tonic-gate 	initialized = 1;
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	mutex_init(&mdi_mutex, NULL, MUTEX_DEFAULT, NULL);
239*7c478bd9Sstevel@tonic-gate 	/*
240*7c478bd9Sstevel@tonic-gate 	 * Create our taskq resources
241*7c478bd9Sstevel@tonic-gate 	 */
242*7c478bd9Sstevel@tonic-gate 	mdi_taskq = taskq_create("mdi_taskq", mdi_taskq_n_threads,
243*7c478bd9Sstevel@tonic-gate 	    MDI_TASKQ_PRI, MDI_TASKQ_MINALLOC, MDI_TASKQ_MAXALLOC,
244*7c478bd9Sstevel@tonic-gate 	    TASKQ_PREPOPULATE | TASKQ_CPR_SAFE);
245*7c478bd9Sstevel@tonic-gate 	ASSERT(mdi_taskq != NULL);	/* taskq_create never fails */
246*7c478bd9Sstevel@tonic-gate }
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate /*
249*7c478bd9Sstevel@tonic-gate  * mdi_get_component_type():
250*7c478bd9Sstevel@tonic-gate  *		Return mpxio component type
251*7c478bd9Sstevel@tonic-gate  * Return Values:
252*7c478bd9Sstevel@tonic-gate  *		MDI_COMPONENT_NONE
253*7c478bd9Sstevel@tonic-gate  *		MDI_COMPONENT_VHCI
254*7c478bd9Sstevel@tonic-gate  *		MDI_COMPONENT_PHCI
255*7c478bd9Sstevel@tonic-gate  *		MDI_COMPONENT_CLIENT
256*7c478bd9Sstevel@tonic-gate  * XXX This doesn't work under multi-level MPxIO and should be
257*7c478bd9Sstevel@tonic-gate  *	removed when clients migrate mdi_is_*() interfaces.
258*7c478bd9Sstevel@tonic-gate  */
259*7c478bd9Sstevel@tonic-gate int
260*7c478bd9Sstevel@tonic-gate mdi_get_component_type(dev_info_t *dip)
261*7c478bd9Sstevel@tonic-gate {
262*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_mdi_component);
263*7c478bd9Sstevel@tonic-gate }
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate /*
266*7c478bd9Sstevel@tonic-gate  * mdi_vhci_register():
267*7c478bd9Sstevel@tonic-gate  *		Register a vHCI module with the mpxio framework
268*7c478bd9Sstevel@tonic-gate  *		mdi_vhci_register() is called by vHCI drivers to register the
269*7c478bd9Sstevel@tonic-gate  *		'class_driver' vHCI driver and its MDI entrypoints with the
270*7c478bd9Sstevel@tonic-gate  *		mpxio framework.  The vHCI driver must call this interface as
271*7c478bd9Sstevel@tonic-gate  *		part of its attach(9e) handler.
272*7c478bd9Sstevel@tonic-gate  *		Competing threads may try to attach mdi_vhci_register() as
273*7c478bd9Sstevel@tonic-gate  *		the vHCI drivers are loaded and attached as a result of pHCI
274*7c478bd9Sstevel@tonic-gate  *		driver instance registration (mdi_phci_register()) with the
275*7c478bd9Sstevel@tonic-gate  *		framework.
276*7c478bd9Sstevel@tonic-gate  * Return Values:
277*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
278*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
279*7c478bd9Sstevel@tonic-gate  */
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
282*7c478bd9Sstevel@tonic-gate int
283*7c478bd9Sstevel@tonic-gate mdi_vhci_register(char *class, dev_info_t *vdip, mdi_vhci_ops_t *vops,
284*7c478bd9Sstevel@tonic-gate     int flags)
285*7c478bd9Sstevel@tonic-gate {
286*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t		*vh = NULL;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	ASSERT(vops->vo_revision == MDI_VHCI_OPS_REV);
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	i_mdi_init();
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
293*7c478bd9Sstevel@tonic-gate 	/*
294*7c478bd9Sstevel@tonic-gate 	 * Scan for already registered vhci
295*7c478bd9Sstevel@tonic-gate 	 */
296*7c478bd9Sstevel@tonic-gate 	for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) {
297*7c478bd9Sstevel@tonic-gate 		if (strcmp(vh->vh_class, class) == 0) {
298*7c478bd9Sstevel@tonic-gate 			/*
299*7c478bd9Sstevel@tonic-gate 			 * vHCI has already been created.  Check for valid
300*7c478bd9Sstevel@tonic-gate 			 * vHCI ops registration.  We only support one vHCI
301*7c478bd9Sstevel@tonic-gate 			 * module per class
302*7c478bd9Sstevel@tonic-gate 			 */
303*7c478bd9Sstevel@tonic-gate 			if (vh->vh_ops != NULL) {
304*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mdi_mutex);
305*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, vhci_greeting, class);
306*7c478bd9Sstevel@tonic-gate 				return (MDI_FAILURE);
307*7c478bd9Sstevel@tonic-gate 			}
308*7c478bd9Sstevel@tonic-gate 			break;
309*7c478bd9Sstevel@tonic-gate 		}
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	/*
313*7c478bd9Sstevel@tonic-gate 	 * if not yet created, create the vHCI component
314*7c478bd9Sstevel@tonic-gate 	 */
315*7c478bd9Sstevel@tonic-gate 	if (vh == NULL) {
316*7c478bd9Sstevel@tonic-gate 		struct client_hash	*hash = NULL;
317*7c478bd9Sstevel@tonic-gate 		char			*load_balance;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 		/*
320*7c478bd9Sstevel@tonic-gate 		 * Allocate and initialize the mdi extensions
321*7c478bd9Sstevel@tonic-gate 		 */
322*7c478bd9Sstevel@tonic-gate 		vh = kmem_zalloc(sizeof (mdi_vhci_t), KM_SLEEP);
323*7c478bd9Sstevel@tonic-gate 		hash = kmem_zalloc(mdi_client_table_size * sizeof (*hash),
324*7c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
325*7c478bd9Sstevel@tonic-gate 		vh->vh_client_table = hash;
326*7c478bd9Sstevel@tonic-gate 		vh->vh_class = kmem_zalloc(strlen(class) + 1, KM_SLEEP);
327*7c478bd9Sstevel@tonic-gate 		(void) strcpy(vh->vh_class, class);
328*7c478bd9Sstevel@tonic-gate 		vh->vh_lb = LOAD_BALANCE_RR;
329*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vdip,
330*7c478bd9Sstevel@tonic-gate 		    0, LOAD_BALANCE_PROP, &load_balance) == DDI_SUCCESS) {
331*7c478bd9Sstevel@tonic-gate 			if (strcmp(load_balance, LOAD_BALANCE_PROP_NONE) == 0) {
332*7c478bd9Sstevel@tonic-gate 				vh->vh_lb = LOAD_BALANCE_NONE;
333*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(load_balance, LOAD_BALANCE_PROP_LBA)
334*7c478bd9Sstevel@tonic-gate 				    == 0) {
335*7c478bd9Sstevel@tonic-gate 				vh->vh_lb = LOAD_BALANCE_LBA;
336*7c478bd9Sstevel@tonic-gate 			}
337*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(load_balance);
338*7c478bd9Sstevel@tonic-gate 		}
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 		/*
341*7c478bd9Sstevel@tonic-gate 		 * Store the vHCI ops vectors
342*7c478bd9Sstevel@tonic-gate 		 */
343*7c478bd9Sstevel@tonic-gate 		vh->vh_dip = vdip;
344*7c478bd9Sstevel@tonic-gate 		vh->vh_ops = vops;
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 		/*
347*7c478bd9Sstevel@tonic-gate 		 * other members of vh_bus_config are initialized by
348*7c478bd9Sstevel@tonic-gate 		 * the above kmem_zalloc of the vhci structure.
349*7c478bd9Sstevel@tonic-gate 		 */
350*7c478bd9Sstevel@tonic-gate 		cv_init(&vh->vh_bus_config.vhc_cv, NULL, CV_DRIVER, NULL);
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 		if (mdi_vhci_head == NULL) {
353*7c478bd9Sstevel@tonic-gate 			mdi_vhci_head = vh;
354*7c478bd9Sstevel@tonic-gate 		}
355*7c478bd9Sstevel@tonic-gate 		if (mdi_vhci_tail) {
356*7c478bd9Sstevel@tonic-gate 			mdi_vhci_tail->vh_next = vh;
357*7c478bd9Sstevel@tonic-gate 		}
358*7c478bd9Sstevel@tonic-gate 		mdi_vhci_tail = vh;
359*7c478bd9Sstevel@tonic-gate 		mdi_vhci_count++;
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	/*
363*7c478bd9Sstevel@tonic-gate 	 * Claim the devfs node as a vhci component
364*7c478bd9Sstevel@tonic-gate 	 */
365*7c478bd9Sstevel@tonic-gate 	DEVI(vdip)->devi_mdi_component |= MDI_COMPONENT_VHCI;
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	/*
368*7c478bd9Sstevel@tonic-gate 	 * Initialize our back reference from dev_info node
369*7c478bd9Sstevel@tonic-gate 	 */
370*7c478bd9Sstevel@tonic-gate 	DEVI(vdip)->devi_mdi_xhci = (caddr_t)vh;
371*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
372*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
373*7c478bd9Sstevel@tonic-gate }
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate /*
376*7c478bd9Sstevel@tonic-gate  * mdi_vhci_unregister():
377*7c478bd9Sstevel@tonic-gate  *		Unregister a vHCI module from mpxio framework
378*7c478bd9Sstevel@tonic-gate  *		mdi_vhci_unregister() is called from the detach(9E) entrypoint
379*7c478bd9Sstevel@tonic-gate  * 		of a vhci to unregister it from the framework.
380*7c478bd9Sstevel@tonic-gate  * Return Values:
381*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
382*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
383*7c478bd9Sstevel@tonic-gate  */
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
386*7c478bd9Sstevel@tonic-gate int
387*7c478bd9Sstevel@tonic-gate mdi_vhci_unregister(dev_info_t *vdip, int flags)
388*7c478bd9Sstevel@tonic-gate {
389*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*found, *vh, *prev = NULL;
390*7c478bd9Sstevel@tonic-gate 	mdi_phci_config_t *phc, *next_phc;
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	/*
393*7c478bd9Sstevel@tonic-gate 	 * Check for invalid VHCI
394*7c478bd9Sstevel@tonic-gate 	 */
395*7c478bd9Sstevel@tonic-gate 	if ((vh = i_devi_get_vhci(vdip)) == NULL)
396*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	/*
401*7c478bd9Sstevel@tonic-gate 	 * Scan the list of registered vHCIs for a match
402*7c478bd9Sstevel@tonic-gate 	 */
403*7c478bd9Sstevel@tonic-gate 	for (found = mdi_vhci_head; found != NULL; found = found->vh_next) {
404*7c478bd9Sstevel@tonic-gate 		if (found == vh)
405*7c478bd9Sstevel@tonic-gate 			break;
406*7c478bd9Sstevel@tonic-gate 		prev = found;
407*7c478bd9Sstevel@tonic-gate 	}
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	if (found == NULL) {
410*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mdi_mutex);
411*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
412*7c478bd9Sstevel@tonic-gate 	}
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	/*
415*7c478bd9Sstevel@tonic-gate 	 * Check the pHCI and client count. All the pHCIs and clients
416*7c478bd9Sstevel@tonic-gate 	 * should have been unregistered, before a vHCI can be
417*7c478bd9Sstevel@tonic-gate 	 * unregistered.
418*7c478bd9Sstevel@tonic-gate 	 */
419*7c478bd9Sstevel@tonic-gate 	if (vh->vh_phci_count || vh->vh_client_count) {
420*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_NOTE, NULL,
421*7c478bd9Sstevel@tonic-gate 		    "!mdi_vhci_unregister: pHCI in registered state.\n"));
422*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mdi_mutex);
423*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
424*7c478bd9Sstevel@tonic-gate 	}
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	/*
427*7c478bd9Sstevel@tonic-gate 	 * Remove the vHCI from the global list
428*7c478bd9Sstevel@tonic-gate 	 */
429*7c478bd9Sstevel@tonic-gate 	if (vh == mdi_vhci_head) {
430*7c478bd9Sstevel@tonic-gate 		mdi_vhci_head = vh->vh_next;
431*7c478bd9Sstevel@tonic-gate 	} else {
432*7c478bd9Sstevel@tonic-gate 		prev->vh_next = vh->vh_next;
433*7c478bd9Sstevel@tonic-gate 	}
434*7c478bd9Sstevel@tonic-gate 	if (vh == mdi_vhci_tail) {
435*7c478bd9Sstevel@tonic-gate 		mdi_vhci_tail = prev;
436*7c478bd9Sstevel@tonic-gate 	}
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	vh->vh_ops = NULL;
439*7c478bd9Sstevel@tonic-gate 	mdi_vhci_count--;
440*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
441*7c478bd9Sstevel@tonic-gate 	DEVI(vdip)->devi_mdi_component &= ~MDI_COMPONENT_VHCI;
442*7c478bd9Sstevel@tonic-gate 	DEVI(vdip)->devi_mdi_xhci = NULL;
443*7c478bd9Sstevel@tonic-gate 	kmem_free(vh->vh_class, strlen(vh->vh_class)+1);
444*7c478bd9Sstevel@tonic-gate 	kmem_free(vh->vh_client_table,
445*7c478bd9Sstevel@tonic-gate 	    mdi_client_table_size * sizeof (struct client_hash));
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	/*
448*7c478bd9Sstevel@tonic-gate 	 * there must be no more tasks on the bus config taskq as the vhci
449*7c478bd9Sstevel@tonic-gate 	 * driver can not be detached while bus config is in progress.
450*7c478bd9Sstevel@tonic-gate 	 */
451*7c478bd9Sstevel@tonic-gate 	ASSERT(vh->vh_bus_config.vhc_start_time == 0);
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	if (vh->vh_bus_config.vhc_taskq != NULL)
454*7c478bd9Sstevel@tonic-gate 		taskq_destroy(vh->vh_bus_config.vhc_taskq);
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	for (phc = vh->vh_bus_config.vhc_phc; phc != NULL; phc = next_phc) {
457*7c478bd9Sstevel@tonic-gate 		next_phc = phc->phc_next;
458*7c478bd9Sstevel@tonic-gate 		kmem_free(phc, sizeof (*phc));
459*7c478bd9Sstevel@tonic-gate 	}
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	cv_destroy(&vh->vh_bus_config.vhc_cv);
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	kmem_free(vh, sizeof (mdi_vhci_t));
464*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
465*7c478bd9Sstevel@tonic-gate }
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate /*
468*7c478bd9Sstevel@tonic-gate  * i_mdi_vhci_class2vhci():
469*7c478bd9Sstevel@tonic-gate  *		Look for a matching vHCI module given a vHCI class name
470*7c478bd9Sstevel@tonic-gate  * Return Values:
471*7c478bd9Sstevel@tonic-gate  *		Handle to a vHCI component
472*7c478bd9Sstevel@tonic-gate  *		NULL
473*7c478bd9Sstevel@tonic-gate  */
474*7c478bd9Sstevel@tonic-gate static mdi_vhci_t *
475*7c478bd9Sstevel@tonic-gate i_mdi_vhci_class2vhci(char *class)
476*7c478bd9Sstevel@tonic-gate {
477*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*vh = NULL;
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&mdi_mutex));
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
482*7c478bd9Sstevel@tonic-gate 	for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) {
483*7c478bd9Sstevel@tonic-gate 		if (strcmp(vh->vh_class, class) == 0) {
484*7c478bd9Sstevel@tonic-gate 			break;
485*7c478bd9Sstevel@tonic-gate 		}
486*7c478bd9Sstevel@tonic-gate 	}
487*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
488*7c478bd9Sstevel@tonic-gate 	return (vh);
489*7c478bd9Sstevel@tonic-gate }
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate /*
492*7c478bd9Sstevel@tonic-gate  * i_devi_get_vhci():
493*7c478bd9Sstevel@tonic-gate  *		Utility function to get the handle to a vHCI component
494*7c478bd9Sstevel@tonic-gate  * Return Values:
495*7c478bd9Sstevel@tonic-gate  *		Handle to a vHCI component
496*7c478bd9Sstevel@tonic-gate  *		NULL
497*7c478bd9Sstevel@tonic-gate  */
498*7c478bd9Sstevel@tonic-gate mdi_vhci_t *
499*7c478bd9Sstevel@tonic-gate i_devi_get_vhci(dev_info_t *vdip)
500*7c478bd9Sstevel@tonic-gate {
501*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*vh = NULL;
502*7c478bd9Sstevel@tonic-gate 	if (MDI_VHCI(vdip)) {
503*7c478bd9Sstevel@tonic-gate 		vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci;
504*7c478bd9Sstevel@tonic-gate 	}
505*7c478bd9Sstevel@tonic-gate 	return (vh);
506*7c478bd9Sstevel@tonic-gate }
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate /*
509*7c478bd9Sstevel@tonic-gate  * mdi_phci_register():
510*7c478bd9Sstevel@tonic-gate  *		Register a pHCI module with mpxio framework
511*7c478bd9Sstevel@tonic-gate  *		mdi_phci_register() is called by pHCI drivers to register with
512*7c478bd9Sstevel@tonic-gate  *		the mpxio framework and a specific 'class_driver' vHCI.  The
513*7c478bd9Sstevel@tonic-gate  *		pHCI driver must call this interface as part of its attach(9e)
514*7c478bd9Sstevel@tonic-gate  *		handler.
515*7c478bd9Sstevel@tonic-gate  * Return Values:
516*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
517*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
518*7c478bd9Sstevel@tonic-gate  */
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
521*7c478bd9Sstevel@tonic-gate int
522*7c478bd9Sstevel@tonic-gate mdi_phci_register(char *class, dev_info_t *pdip, int flags)
523*7c478bd9Sstevel@tonic-gate {
524*7c478bd9Sstevel@tonic-gate 	mdi_phci_t		*ph;
525*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t		*vh;
526*7c478bd9Sstevel@tonic-gate 	char			*data;
527*7c478bd9Sstevel@tonic-gate 	char			*pathname;
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
530*7c478bd9Sstevel@tonic-gate 	(void) ddi_pathname(pdip, pathname);
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	/*
533*7c478bd9Sstevel@tonic-gate 	 * Check for mpxio-disable property. Enable mpxio if the property is
534*7c478bd9Sstevel@tonic-gate 	 * missing or not set to "yes".
535*7c478bd9Sstevel@tonic-gate 	 * If the property is set to "yes" then emit a brief message.
536*7c478bd9Sstevel@tonic-gate 	 */
537*7c478bd9Sstevel@tonic-gate 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0, "mpxio-disable",
538*7c478bd9Sstevel@tonic-gate 	    &data) == DDI_SUCCESS)) {
539*7c478bd9Sstevel@tonic-gate 		if (strcmp(data, "yes") == 0) {
540*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_CONT, pdip,
541*7c478bd9Sstevel@tonic-gate 			    "?%s (%s%d) multipath capabilities "
542*7c478bd9Sstevel@tonic-gate 			    "disabled via %s.conf.\n", pathname,
543*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(pdip), ddi_get_instance(pdip),
544*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(pdip)));
545*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(data);
546*7c478bd9Sstevel@tonic-gate 			kmem_free(pathname, MAXPATHLEN);
547*7c478bd9Sstevel@tonic-gate 			return (MDI_FAILURE);
548*7c478bd9Sstevel@tonic-gate 		}
549*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(data);
550*7c478bd9Sstevel@tonic-gate 	}
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	kmem_free(pathname, MAXPATHLEN);
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	/*
555*7c478bd9Sstevel@tonic-gate 	 * Search for a matching vHCI
556*7c478bd9Sstevel@tonic-gate 	 */
557*7c478bd9Sstevel@tonic-gate 	vh = (mdi_vhci_t *)i_mdi_vhci_class2vhci(class);
558*7c478bd9Sstevel@tonic-gate 	if (vh == NULL) {
559*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
560*7c478bd9Sstevel@tonic-gate 	}
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	ph = kmem_zalloc(sizeof (mdi_phci_t), KM_SLEEP);
563*7c478bd9Sstevel@tonic-gate 	mutex_init(&ph->ph_mutex, NULL, MUTEX_DEFAULT, NULL);
564*7c478bd9Sstevel@tonic-gate 	ph->ph_dip = pdip;
565*7c478bd9Sstevel@tonic-gate 	ph->ph_vhci = vh;
566*7c478bd9Sstevel@tonic-gate 	ph->ph_next = NULL;
567*7c478bd9Sstevel@tonic-gate 	ph->ph_unstable = 0;
568*7c478bd9Sstevel@tonic-gate 	ph->ph_vprivate = 0;
569*7c478bd9Sstevel@tonic-gate 	cv_init(&ph->ph_unstable_cv, NULL, CV_DRIVER, NULL);
570*7c478bd9Sstevel@tonic-gate 	cv_init(&ph->ph_powerchange_cv, NULL, CV_DRIVER, NULL);
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_SET_POWER_UP(ph);
573*7c478bd9Sstevel@tonic-gate 	DEVI(pdip)->devi_mdi_component |= MDI_COMPONENT_PHCI;
574*7c478bd9Sstevel@tonic-gate 	DEVI(pdip)->devi_mdi_xhci = (caddr_t)ph;
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
577*7c478bd9Sstevel@tonic-gate 	if (vh->vh_phci_head == NULL) {
578*7c478bd9Sstevel@tonic-gate 		vh->vh_phci_head = ph;
579*7c478bd9Sstevel@tonic-gate 	}
580*7c478bd9Sstevel@tonic-gate 	if (vh->vh_phci_tail) {
581*7c478bd9Sstevel@tonic-gate 		vh->vh_phci_tail->ph_next = ph;
582*7c478bd9Sstevel@tonic-gate 	}
583*7c478bd9Sstevel@tonic-gate 	vh->vh_phci_tail = ph;
584*7c478bd9Sstevel@tonic-gate 	vh->vh_phci_count++;
585*7c478bd9Sstevel@tonic-gate 	/* to force discovery of all phci children during busconfig */
586*7c478bd9Sstevel@tonic-gate 	vh->vh_bus_config.vhc_cutoff_time = -1;
587*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
588*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
589*7c478bd9Sstevel@tonic-gate }
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate /*
592*7c478bd9Sstevel@tonic-gate  * mdi_phci_unregister():
593*7c478bd9Sstevel@tonic-gate  *		Unregister a pHCI module from mpxio framework
594*7c478bd9Sstevel@tonic-gate  *		mdi_phci_unregister() is called by the pHCI drivers from their
595*7c478bd9Sstevel@tonic-gate  *		detach(9E) handler to unregister their instances from the
596*7c478bd9Sstevel@tonic-gate  *		framework.
597*7c478bd9Sstevel@tonic-gate  * Return Values:
598*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
599*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
600*7c478bd9Sstevel@tonic-gate  */
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
603*7c478bd9Sstevel@tonic-gate int
604*7c478bd9Sstevel@tonic-gate mdi_phci_unregister(dev_info_t *pdip, int flags)
605*7c478bd9Sstevel@tonic-gate {
606*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t		*vh;
607*7c478bd9Sstevel@tonic-gate 	mdi_phci_t		*ph;
608*7c478bd9Sstevel@tonic-gate 	mdi_phci_t		*tmp;
609*7c478bd9Sstevel@tonic-gate 	mdi_phci_t		*prev = NULL;
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	ph = i_devi_get_phci(pdip);
612*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
613*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, pdip,
614*7c478bd9Sstevel@tonic-gate 		    "!pHCI unregister: Not a valid pHCI"));
615*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 	vh = ph->ph_vhci;
619*7c478bd9Sstevel@tonic-gate 	ASSERT(vh != NULL);
620*7c478bd9Sstevel@tonic-gate 	if (vh == NULL) {
621*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, pdip,
622*7c478bd9Sstevel@tonic-gate 		    "!pHCI unregister: Not a valid vHCI"));
623*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
624*7c478bd9Sstevel@tonic-gate 	}
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
627*7c478bd9Sstevel@tonic-gate 	tmp = vh->vh_phci_head;
628*7c478bd9Sstevel@tonic-gate 	while (tmp) {
629*7c478bd9Sstevel@tonic-gate 		if (tmp == ph) {
630*7c478bd9Sstevel@tonic-gate 			break;
631*7c478bd9Sstevel@tonic-gate 		}
632*7c478bd9Sstevel@tonic-gate 		prev = tmp;
633*7c478bd9Sstevel@tonic-gate 		tmp = tmp->ph_next;
634*7c478bd9Sstevel@tonic-gate 	}
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	if (ph == vh->vh_phci_head) {
637*7c478bd9Sstevel@tonic-gate 		vh->vh_phci_head = ph->ph_next;
638*7c478bd9Sstevel@tonic-gate 	} else {
639*7c478bd9Sstevel@tonic-gate 		prev->ph_next = ph->ph_next;
640*7c478bd9Sstevel@tonic-gate 	}
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	if (ph == vh->vh_phci_tail) {
643*7c478bd9Sstevel@tonic-gate 		vh->vh_phci_tail = prev;
644*7c478bd9Sstevel@tonic-gate 	}
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	vh->vh_phci_count--;
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	/*
649*7c478bd9Sstevel@tonic-gate 	 * If no busconfig is in progress, release the phci busconfig resources.
650*7c478bd9Sstevel@tonic-gate 	 * We only need vh->vh_phci_count of busconfig resources.
651*7c478bd9Sstevel@tonic-gate 	 */
652*7c478bd9Sstevel@tonic-gate 	if (vh->vh_bus_config.vhc_start_time == 0 &&
653*7c478bd9Sstevel@tonic-gate 	    vh->vh_bus_config.vhc_phc_cnt > vh->vh_phci_count) {
654*7c478bd9Sstevel@tonic-gate 		int count;
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 		count = vh->vh_bus_config.vhc_phc_cnt - vh->vh_phci_count;
657*7c478bd9Sstevel@tonic-gate 		while (count--) {
658*7c478bd9Sstevel@tonic-gate 			mdi_phci_config_t *phc;
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 			phc = vh->vh_bus_config.vhc_phc;
661*7c478bd9Sstevel@tonic-gate 			vh->vh_bus_config.vhc_phc = phc->phc_next;
662*7c478bd9Sstevel@tonic-gate 			kmem_free(phc, sizeof (*phc));
663*7c478bd9Sstevel@tonic-gate 		}
664*7c478bd9Sstevel@tonic-gate 		vh->vh_bus_config.vhc_phc_cnt = vh->vh_phci_count;
665*7c478bd9Sstevel@tonic-gate 	}
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 	cv_destroy(&ph->ph_unstable_cv);
670*7c478bd9Sstevel@tonic-gate 	cv_destroy(&ph->ph_powerchange_cv);
671*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&ph->ph_mutex);
672*7c478bd9Sstevel@tonic-gate 	kmem_free(ph, sizeof (mdi_phci_t));
673*7c478bd9Sstevel@tonic-gate 	DEVI(pdip)->devi_mdi_component &= ~MDI_COMPONENT_PHCI;
674*7c478bd9Sstevel@tonic-gate 	DEVI(pdip)->devi_mdi_xhci = NULL;
675*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
676*7c478bd9Sstevel@tonic-gate }
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate /*
679*7c478bd9Sstevel@tonic-gate  * i_devi_get_phci():
680*7c478bd9Sstevel@tonic-gate  * 		Utility function to return the phci extensions.
681*7c478bd9Sstevel@tonic-gate  */
682*7c478bd9Sstevel@tonic-gate static mdi_phci_t *
683*7c478bd9Sstevel@tonic-gate i_devi_get_phci(dev_info_t *pdip)
684*7c478bd9Sstevel@tonic-gate {
685*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph = NULL;
686*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI(pdip)) {
687*7c478bd9Sstevel@tonic-gate 		ph = (mdi_phci_t *)DEVI(pdip)->devi_mdi_xhci;
688*7c478bd9Sstevel@tonic-gate 	}
689*7c478bd9Sstevel@tonic-gate 	return (ph);
690*7c478bd9Sstevel@tonic-gate }
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate /*
693*7c478bd9Sstevel@tonic-gate  * mdi_phci_path2devinfo():
694*7c478bd9Sstevel@tonic-gate  * 		Utility function to search for a valid phci device given
695*7c478bd9Sstevel@tonic-gate  *		the devfs pathname.
696*7c478bd9Sstevel@tonic-gate  */
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate dev_info_t *
699*7c478bd9Sstevel@tonic-gate mdi_phci_path2devinfo(dev_info_t *vdip, caddr_t pathname)
700*7c478bd9Sstevel@tonic-gate {
701*7c478bd9Sstevel@tonic-gate 	char		*temp_pathname;
702*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*vh;
703*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
704*7c478bd9Sstevel@tonic-gate 	dev_info_t 	*pdip = NULL;
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 	vh = i_devi_get_vhci(vdip);
707*7c478bd9Sstevel@tonic-gate 	ASSERT(vh != NULL);
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	if (vh == NULL) {
710*7c478bd9Sstevel@tonic-gate 		/*
711*7c478bd9Sstevel@tonic-gate 		 * Invalid vHCI component, return failure
712*7c478bd9Sstevel@tonic-gate 		 */
713*7c478bd9Sstevel@tonic-gate 		return (NULL);
714*7c478bd9Sstevel@tonic-gate 	}
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
717*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
718*7c478bd9Sstevel@tonic-gate 	ph = vh->vh_phci_head;
719*7c478bd9Sstevel@tonic-gate 	while (ph != NULL) {
720*7c478bd9Sstevel@tonic-gate 		pdip = ph->ph_dip;
721*7c478bd9Sstevel@tonic-gate 		ASSERT(pdip != NULL);
722*7c478bd9Sstevel@tonic-gate 		*temp_pathname = '\0';
723*7c478bd9Sstevel@tonic-gate 		(void) ddi_pathname(pdip, temp_pathname);
724*7c478bd9Sstevel@tonic-gate 		if (strcmp(temp_pathname, pathname) == 0) {
725*7c478bd9Sstevel@tonic-gate 			break;
726*7c478bd9Sstevel@tonic-gate 		}
727*7c478bd9Sstevel@tonic-gate 		ph = ph->ph_next;
728*7c478bd9Sstevel@tonic-gate 	}
729*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
730*7c478bd9Sstevel@tonic-gate 		pdip = NULL;
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
733*7c478bd9Sstevel@tonic-gate 	kmem_free(temp_pathname, MAXPATHLEN);
734*7c478bd9Sstevel@tonic-gate 	return (pdip);
735*7c478bd9Sstevel@tonic-gate }
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate /*
738*7c478bd9Sstevel@tonic-gate  * mdi_phci_get_path_count():
739*7c478bd9Sstevel@tonic-gate  * 		get number of path information nodes associated with a given
740*7c478bd9Sstevel@tonic-gate  *		pHCI device.
741*7c478bd9Sstevel@tonic-gate  */
742*7c478bd9Sstevel@tonic-gate int
743*7c478bd9Sstevel@tonic-gate mdi_phci_get_path_count(dev_info_t *pdip)
744*7c478bd9Sstevel@tonic-gate {
745*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
746*7c478bd9Sstevel@tonic-gate 	int		count = 0;
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	ph = i_devi_get_phci(pdip);
749*7c478bd9Sstevel@tonic-gate 	if (ph != NULL) {
750*7c478bd9Sstevel@tonic-gate 		count = ph->ph_path_count;
751*7c478bd9Sstevel@tonic-gate 	}
752*7c478bd9Sstevel@tonic-gate 	return (count);
753*7c478bd9Sstevel@tonic-gate }
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate /*
756*7c478bd9Sstevel@tonic-gate  * i_mdi_phci_lock():
757*7c478bd9Sstevel@tonic-gate  *		Lock a pHCI device
758*7c478bd9Sstevel@tonic-gate  * Return Values:
759*7c478bd9Sstevel@tonic-gate  *		None
760*7c478bd9Sstevel@tonic-gate  * Note:
761*7c478bd9Sstevel@tonic-gate  *		The default locking order is:
762*7c478bd9Sstevel@tonic-gate  *		_NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex))
763*7c478bd9Sstevel@tonic-gate  *		But there are number of situations where locks need to be
764*7c478bd9Sstevel@tonic-gate  *		grabbed in reverse order.  This routine implements try and lock
765*7c478bd9Sstevel@tonic-gate  *		mechanism depending on the requested parameter option.
766*7c478bd9Sstevel@tonic-gate  */
767*7c478bd9Sstevel@tonic-gate static void
768*7c478bd9Sstevel@tonic-gate i_mdi_phci_lock(mdi_phci_t *ph, mdi_pathinfo_t *pip)
769*7c478bd9Sstevel@tonic-gate {
770*7c478bd9Sstevel@tonic-gate 	if (pip) {
771*7c478bd9Sstevel@tonic-gate 		/* Reverse locking is requested. */
772*7c478bd9Sstevel@tonic-gate 		while (MDI_PHCI_TRYLOCK(ph) == 0) {
773*7c478bd9Sstevel@tonic-gate 			/*
774*7c478bd9Sstevel@tonic-gate 			 * tryenter failed. Try to grab again
775*7c478bd9Sstevel@tonic-gate 			 * after a small delay
776*7c478bd9Sstevel@tonic-gate 			 */
777*7c478bd9Sstevel@tonic-gate 			MDI_PI_HOLD(pip);
778*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
779*7c478bd9Sstevel@tonic-gate 			delay(1);
780*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
781*7c478bd9Sstevel@tonic-gate 			MDI_PI_RELE(pip);
782*7c478bd9Sstevel@tonic-gate 		}
783*7c478bd9Sstevel@tonic-gate 	} else {
784*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_LOCK(ph);
785*7c478bd9Sstevel@tonic-gate 	}
786*7c478bd9Sstevel@tonic-gate }
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate /*
789*7c478bd9Sstevel@tonic-gate  * i_mdi_phci_get_client_lock():
790*7c478bd9Sstevel@tonic-gate  *		Lock a pHCI device
791*7c478bd9Sstevel@tonic-gate  * Return Values:
792*7c478bd9Sstevel@tonic-gate  *		None
793*7c478bd9Sstevel@tonic-gate  * Note:
794*7c478bd9Sstevel@tonic-gate  *		The default locking order is:
795*7c478bd9Sstevel@tonic-gate  *		_NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex))
796*7c478bd9Sstevel@tonic-gate  *		But there are number of situations where locks need to be
797*7c478bd9Sstevel@tonic-gate  *		grabbed in reverse order.  This routine implements try and lock
798*7c478bd9Sstevel@tonic-gate  *		mechanism depending on the requested parameter option.
799*7c478bd9Sstevel@tonic-gate  */
800*7c478bd9Sstevel@tonic-gate static void
801*7c478bd9Sstevel@tonic-gate i_mdi_phci_get_client_lock(mdi_phci_t *ph, mdi_client_t *ct)
802*7c478bd9Sstevel@tonic-gate {
803*7c478bd9Sstevel@tonic-gate 	if (ct) {
804*7c478bd9Sstevel@tonic-gate 		/* Reverse locking is requested. */
805*7c478bd9Sstevel@tonic-gate 		while (MDI_PHCI_TRYLOCK(ph) == 0) {
806*7c478bd9Sstevel@tonic-gate 			/*
807*7c478bd9Sstevel@tonic-gate 			 * tryenter failed. Try to grab again
808*7c478bd9Sstevel@tonic-gate 			 * after a small delay
809*7c478bd9Sstevel@tonic-gate 			 */
810*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
811*7c478bd9Sstevel@tonic-gate 			delay(1);
812*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_LOCK(ct);
813*7c478bd9Sstevel@tonic-gate 		}
814*7c478bd9Sstevel@tonic-gate 	} else {
815*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_LOCK(ph);
816*7c478bd9Sstevel@tonic-gate 	}
817*7c478bd9Sstevel@tonic-gate }
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate /*
820*7c478bd9Sstevel@tonic-gate  * i_mdi_phci_unlock():
821*7c478bd9Sstevel@tonic-gate  *		Unlock the pHCI component
822*7c478bd9Sstevel@tonic-gate  */
823*7c478bd9Sstevel@tonic-gate static void
824*7c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(mdi_phci_t *ph)
825*7c478bd9Sstevel@tonic-gate {
826*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNLOCK(ph);
827*7c478bd9Sstevel@tonic-gate }
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate /*
830*7c478bd9Sstevel@tonic-gate  * i_mdi_devinfo_create():
831*7c478bd9Sstevel@tonic-gate  *		create client device's devinfo node
832*7c478bd9Sstevel@tonic-gate  * Return Values:
833*7c478bd9Sstevel@tonic-gate  *		dev_info
834*7c478bd9Sstevel@tonic-gate  *		NULL
835*7c478bd9Sstevel@tonic-gate  * Notes:
836*7c478bd9Sstevel@tonic-gate  */
837*7c478bd9Sstevel@tonic-gate static dev_info_t *
838*7c478bd9Sstevel@tonic-gate i_mdi_devinfo_create(mdi_vhci_t *vh, char *name, char *guid,
839*7c478bd9Sstevel@tonic-gate 	char **compatible, int ncompatible, int flags)
840*7c478bd9Sstevel@tonic-gate {
841*7c478bd9Sstevel@tonic-gate 	dev_info_t *cdip = NULL;
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mdi_mutex));
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	/* Verify for duplicate entry */
846*7c478bd9Sstevel@tonic-gate 	cdip = i_mdi_devinfo_find(vh, name, guid);
847*7c478bd9Sstevel@tonic-gate 	ASSERT(cdip == NULL);
848*7c478bd9Sstevel@tonic-gate 	if (cdip) {
849*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
850*7c478bd9Sstevel@tonic-gate 		    "i_mdi_devinfo_create: client dip %p already exists",
851*7c478bd9Sstevel@tonic-gate 			(void *)cdip);
852*7c478bd9Sstevel@tonic-gate 	}
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	if (flags == DDI_SLEEP) {
855*7c478bd9Sstevel@tonic-gate 		ndi_devi_alloc_sleep(vh->vh_dip, name,
856*7c478bd9Sstevel@tonic-gate 		    DEVI_SID_NODEID, &cdip);
857*7c478bd9Sstevel@tonic-gate 	} else {
858*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_alloc(vh->vh_dip, name,
859*7c478bd9Sstevel@tonic-gate 		    DEVI_SID_NODEID, &cdip);
860*7c478bd9Sstevel@tonic-gate 	}
861*7c478bd9Sstevel@tonic-gate 	if (cdip == NULL)
862*7c478bd9Sstevel@tonic-gate 		goto fail;
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	/*
865*7c478bd9Sstevel@tonic-gate 	 * Create component type and Global unique identifier
866*7c478bd9Sstevel@tonic-gate 	 * properties
867*7c478bd9Sstevel@tonic-gate 	 */
868*7c478bd9Sstevel@tonic-gate 	if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip,
869*7c478bd9Sstevel@tonic-gate 	    MDI_CLIENT_GUID_PROP, guid) != DDI_PROP_SUCCESS) {
870*7c478bd9Sstevel@tonic-gate 		goto fail;
871*7c478bd9Sstevel@tonic-gate 	}
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	/* Decorate the node with compatible property */
874*7c478bd9Sstevel@tonic-gate 	if (compatible &&
875*7c478bd9Sstevel@tonic-gate 	    (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
876*7c478bd9Sstevel@tonic-gate 	    "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS)) {
877*7c478bd9Sstevel@tonic-gate 		goto fail;
878*7c478bd9Sstevel@tonic-gate 	}
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	return (cdip);
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate fail:
883*7c478bd9Sstevel@tonic-gate 	if (cdip) {
884*7c478bd9Sstevel@tonic-gate 		(void) ndi_prop_remove_all(cdip);
885*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(cdip);
886*7c478bd9Sstevel@tonic-gate 	}
887*7c478bd9Sstevel@tonic-gate 	return (NULL);
888*7c478bd9Sstevel@tonic-gate }
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate /*
891*7c478bd9Sstevel@tonic-gate  * i_mdi_devinfo_find():
892*7c478bd9Sstevel@tonic-gate  *		Find a matching devinfo node for given client node name
893*7c478bd9Sstevel@tonic-gate  *		and its guid.
894*7c478bd9Sstevel@tonic-gate  * Return Values:
895*7c478bd9Sstevel@tonic-gate  *		Handle to a dev_info node or NULL
896*7c478bd9Sstevel@tonic-gate  */
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate static dev_info_t *
899*7c478bd9Sstevel@tonic-gate i_mdi_devinfo_find(mdi_vhci_t *vh, caddr_t name, char *guid)
900*7c478bd9Sstevel@tonic-gate {
901*7c478bd9Sstevel@tonic-gate 	char			*data;
902*7c478bd9Sstevel@tonic-gate 	dev_info_t 		*cdip = NULL;
903*7c478bd9Sstevel@tonic-gate 	dev_info_t 		*ndip = NULL;
904*7c478bd9Sstevel@tonic-gate 	int			circular;
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(vh->vh_dip, &circular);
907*7c478bd9Sstevel@tonic-gate 	ndip = (dev_info_t *)DEVI(vh->vh_dip)->devi_child;
908*7c478bd9Sstevel@tonic-gate 	while ((cdip = ndip) != NULL) {
909*7c478bd9Sstevel@tonic-gate 		ndip = (dev_info_t *)DEVI(cdip)->devi_sibling;
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 		if (strcmp(DEVI(cdip)->devi_node_name, name)) {
912*7c478bd9Sstevel@tonic-gate 			continue;
913*7c478bd9Sstevel@tonic-gate 		}
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip,
916*7c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, MDI_CLIENT_GUID_PROP,
917*7c478bd9Sstevel@tonic-gate 		    &data) != DDI_PROP_SUCCESS) {
918*7c478bd9Sstevel@tonic-gate 			continue;
919*7c478bd9Sstevel@tonic-gate 		}
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 		if (strcmp(data, guid) != 0) {
922*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(data);
923*7c478bd9Sstevel@tonic-gate 			continue;
924*7c478bd9Sstevel@tonic-gate 		}
925*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(data);
926*7c478bd9Sstevel@tonic-gate 		break;
927*7c478bd9Sstevel@tonic-gate 	}
928*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(vh->vh_dip, circular);
929*7c478bd9Sstevel@tonic-gate 	return (cdip);
930*7c478bd9Sstevel@tonic-gate }
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate /*
933*7c478bd9Sstevel@tonic-gate  * i_mdi_devinfo_remove():
934*7c478bd9Sstevel@tonic-gate  *		Remove a client device node
935*7c478bd9Sstevel@tonic-gate  */
936*7c478bd9Sstevel@tonic-gate static int
937*7c478bd9Sstevel@tonic-gate i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags)
938*7c478bd9Sstevel@tonic-gate {
939*7c478bd9Sstevel@tonic-gate 	int	rv = MDI_SUCCESS;
940*7c478bd9Sstevel@tonic-gate 	if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS ||
941*7c478bd9Sstevel@tonic-gate 	    (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) {
942*7c478bd9Sstevel@tonic-gate 		rv = ndi_devi_offline(cdip, NDI_DEVI_REMOVE);
943*7c478bd9Sstevel@tonic-gate 		if (rv != NDI_SUCCESS) {
944*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_devinfo_remove:"
945*7c478bd9Sstevel@tonic-gate 			    " failed. cdip = %p\n", cdip));
946*7c478bd9Sstevel@tonic-gate 		}
947*7c478bd9Sstevel@tonic-gate 		/*
948*7c478bd9Sstevel@tonic-gate 		 * Convert to MDI error code
949*7c478bd9Sstevel@tonic-gate 		 */
950*7c478bd9Sstevel@tonic-gate 		switch (rv) {
951*7c478bd9Sstevel@tonic-gate 		case NDI_SUCCESS:
952*7c478bd9Sstevel@tonic-gate 			rv = MDI_SUCCESS;
953*7c478bd9Sstevel@tonic-gate 			break;
954*7c478bd9Sstevel@tonic-gate 		case NDI_BUSY:
955*7c478bd9Sstevel@tonic-gate 			rv = MDI_BUSY;
956*7c478bd9Sstevel@tonic-gate 			break;
957*7c478bd9Sstevel@tonic-gate 		default:
958*7c478bd9Sstevel@tonic-gate 			rv = MDI_FAILURE;
959*7c478bd9Sstevel@tonic-gate 			break;
960*7c478bd9Sstevel@tonic-gate 		}
961*7c478bd9Sstevel@tonic-gate 	}
962*7c478bd9Sstevel@tonic-gate 	return (rv);
963*7c478bd9Sstevel@tonic-gate }
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate /*
966*7c478bd9Sstevel@tonic-gate  * i_devi_get_client()
967*7c478bd9Sstevel@tonic-gate  *		Utility function to get mpxio component extensions
968*7c478bd9Sstevel@tonic-gate  */
969*7c478bd9Sstevel@tonic-gate static mdi_client_t *
970*7c478bd9Sstevel@tonic-gate i_devi_get_client(dev_info_t *cdip)
971*7c478bd9Sstevel@tonic-gate {
972*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct = NULL;
973*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT(cdip)) {
974*7c478bd9Sstevel@tonic-gate 		ct = (mdi_client_t *)DEVI(cdip)->devi_mdi_client;
975*7c478bd9Sstevel@tonic-gate 	}
976*7c478bd9Sstevel@tonic-gate 	return (ct);
977*7c478bd9Sstevel@tonic-gate }
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate /*
980*7c478bd9Sstevel@tonic-gate  * i_mdi_is_child_present():
981*7c478bd9Sstevel@tonic-gate  *		Search for the presence of client device dev_info node
982*7c478bd9Sstevel@tonic-gate  */
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate static int
985*7c478bd9Sstevel@tonic-gate i_mdi_is_child_present(dev_info_t *vdip, dev_info_t *cdip)
986*7c478bd9Sstevel@tonic-gate {
987*7c478bd9Sstevel@tonic-gate 	int		rv = MDI_FAILURE;
988*7c478bd9Sstevel@tonic-gate 	struct dev_info	*dip;
989*7c478bd9Sstevel@tonic-gate 	int		circular;
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(vdip, &circular);
992*7c478bd9Sstevel@tonic-gate 	dip = DEVI(vdip)->devi_child;
993*7c478bd9Sstevel@tonic-gate 	while (dip) {
994*7c478bd9Sstevel@tonic-gate 		if (dip == DEVI(cdip)) {
995*7c478bd9Sstevel@tonic-gate 			rv = MDI_SUCCESS;
996*7c478bd9Sstevel@tonic-gate 			break;
997*7c478bd9Sstevel@tonic-gate 		}
998*7c478bd9Sstevel@tonic-gate 		dip = dip->devi_sibling;
999*7c478bd9Sstevel@tonic-gate 	}
1000*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(vdip, circular);
1001*7c478bd9Sstevel@tonic-gate 	return (rv);
1002*7c478bd9Sstevel@tonic-gate }
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate /*
1006*7c478bd9Sstevel@tonic-gate  * i_mdi_client_lock():
1007*7c478bd9Sstevel@tonic-gate  *		Grab client component lock
1008*7c478bd9Sstevel@tonic-gate  * Return Values:
1009*7c478bd9Sstevel@tonic-gate  *		None
1010*7c478bd9Sstevel@tonic-gate  * Note:
1011*7c478bd9Sstevel@tonic-gate  *		The default locking order is:
1012*7c478bd9Sstevel@tonic-gate  *		_NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex))
1013*7c478bd9Sstevel@tonic-gate  *		But there are number of situations where locks need to be
1014*7c478bd9Sstevel@tonic-gate  *		grabbed in reverse order.  This routine implements try and lock
1015*7c478bd9Sstevel@tonic-gate  *		mechanism depending on the requested parameter option.
1016*7c478bd9Sstevel@tonic-gate  */
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate static void
1019*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(mdi_client_t *ct, mdi_pathinfo_t *pip)
1020*7c478bd9Sstevel@tonic-gate {
1021*7c478bd9Sstevel@tonic-gate 	if (pip) {
1022*7c478bd9Sstevel@tonic-gate 		/*
1023*7c478bd9Sstevel@tonic-gate 		 * Reverse locking is requested.
1024*7c478bd9Sstevel@tonic-gate 		 */
1025*7c478bd9Sstevel@tonic-gate 		while (MDI_CLIENT_TRYLOCK(ct) == 0) {
1026*7c478bd9Sstevel@tonic-gate 			/*
1027*7c478bd9Sstevel@tonic-gate 			 * tryenter failed. Try to grab again
1028*7c478bd9Sstevel@tonic-gate 			 * after a small delay
1029*7c478bd9Sstevel@tonic-gate 			 */
1030*7c478bd9Sstevel@tonic-gate 			MDI_PI_HOLD(pip);
1031*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
1032*7c478bd9Sstevel@tonic-gate 			delay(1);
1033*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
1034*7c478bd9Sstevel@tonic-gate 			MDI_PI_RELE(pip);
1035*7c478bd9Sstevel@tonic-gate 		}
1036*7c478bd9Sstevel@tonic-gate 	} else {
1037*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_LOCK(ct);
1038*7c478bd9Sstevel@tonic-gate 	}
1039*7c478bd9Sstevel@tonic-gate }
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate /*
1042*7c478bd9Sstevel@tonic-gate  * i_mdi_client_unlock():
1043*7c478bd9Sstevel@tonic-gate  *		Unlock a client component
1044*7c478bd9Sstevel@tonic-gate  */
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate static void
1047*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(mdi_client_t *ct)
1048*7c478bd9Sstevel@tonic-gate {
1049*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
1050*7c478bd9Sstevel@tonic-gate }
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate /*
1053*7c478bd9Sstevel@tonic-gate  * i_mdi_client_alloc():
1054*7c478bd9Sstevel@tonic-gate  * 		Allocate and initialize a client structure.  Caller should
1055*7c478bd9Sstevel@tonic-gate  *		hold the global mdi_mutex.
1056*7c478bd9Sstevel@tonic-gate  * Return Values:
1057*7c478bd9Sstevel@tonic-gate  *		Handle to a client component
1058*7c478bd9Sstevel@tonic-gate  */
1059*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1060*7c478bd9Sstevel@tonic-gate static mdi_client_t *
1061*7c478bd9Sstevel@tonic-gate i_mdi_client_alloc(mdi_vhci_t *vh, char *name, char *lguid, int flags)
1062*7c478bd9Sstevel@tonic-gate {
1063*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
1064*7c478bd9Sstevel@tonic-gate 	char		*drvname = NULL;
1065*7c478bd9Sstevel@tonic-gate 	char		*guid = NULL;
1066*7c478bd9Sstevel@tonic-gate 	client_lb_args_t 	*lb_args = NULL;
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mdi_mutex));
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate 	/*
1071*7c478bd9Sstevel@tonic-gate 	 * Allocate and initialize a component structure.
1072*7c478bd9Sstevel@tonic-gate 	 */
1073*7c478bd9Sstevel@tonic-gate 	ct = kmem_zalloc(sizeof (*ct),
1074*7c478bd9Sstevel@tonic-gate 	    (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1075*7c478bd9Sstevel@tonic-gate 	if (ct == NULL)
1076*7c478bd9Sstevel@tonic-gate 		goto fail;
1077*7c478bd9Sstevel@tonic-gate 	mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL);
1078*7c478bd9Sstevel@tonic-gate 	ct->ct_hnext = NULL;
1079*7c478bd9Sstevel@tonic-gate 	ct->ct_hprev = NULL;
1080*7c478bd9Sstevel@tonic-gate 	ct->ct_dip = NULL;
1081*7c478bd9Sstevel@tonic-gate 	ct->ct_vhci = vh;
1082*7c478bd9Sstevel@tonic-gate 	drvname = kmem_alloc(strlen(name) + 1,
1083*7c478bd9Sstevel@tonic-gate 	    (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1084*7c478bd9Sstevel@tonic-gate 	if (drvname == NULL)
1085*7c478bd9Sstevel@tonic-gate 		goto fail;
1086*7c478bd9Sstevel@tonic-gate 	ct->ct_drvname = drvname;
1087*7c478bd9Sstevel@tonic-gate 	(void) strcpy(ct->ct_drvname, name);
1088*7c478bd9Sstevel@tonic-gate 	guid = kmem_alloc(strlen(lguid) + 1,
1089*7c478bd9Sstevel@tonic-gate 	    (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1090*7c478bd9Sstevel@tonic-gate 	if (guid == NULL)
1091*7c478bd9Sstevel@tonic-gate 		goto fail;
1092*7c478bd9Sstevel@tonic-gate 	ct->ct_guid = guid;
1093*7c478bd9Sstevel@tonic-gate 	(void) strcpy(ct->ct_guid, lguid);
1094*7c478bd9Sstevel@tonic-gate 	ct->ct_cprivate = NULL;
1095*7c478bd9Sstevel@tonic-gate 	ct->ct_vprivate = NULL;
1096*7c478bd9Sstevel@tonic-gate 	ct->ct_flags = 0;
1097*7c478bd9Sstevel@tonic-gate 	ct->ct_state = MDI_CLIENT_STATE_FAILED;
1098*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_SET_OFFLINE(ct);
1099*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_SET_DETACH(ct);
1100*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_SET_POWER_UP(ct);
1101*7c478bd9Sstevel@tonic-gate 	ct->ct_failover_flags = 0;
1102*7c478bd9Sstevel@tonic-gate 	ct->ct_failover_status = 0;
1103*7c478bd9Sstevel@tonic-gate 	cv_init(&ct->ct_failover_cv, NULL, CV_DRIVER, NULL);
1104*7c478bd9Sstevel@tonic-gate 	ct->ct_unstable = 0;
1105*7c478bd9Sstevel@tonic-gate 	cv_init(&ct->ct_unstable_cv, NULL, CV_DRIVER, NULL);
1106*7c478bd9Sstevel@tonic-gate 	cv_init(&ct->ct_powerchange_cv, NULL, CV_DRIVER, NULL);
1107*7c478bd9Sstevel@tonic-gate 	ct->ct_lb = vh->vh_lb;
1108*7c478bd9Sstevel@tonic-gate 	lb_args =  kmem_zalloc(sizeof (client_lb_args_t),
1109*7c478bd9Sstevel@tonic-gate 		(flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1110*7c478bd9Sstevel@tonic-gate 	if (lb_args == NULL)
1111*7c478bd9Sstevel@tonic-gate 		goto fail;
1112*7c478bd9Sstevel@tonic-gate 	ct->ct_lb_args = lb_args;
1113*7c478bd9Sstevel@tonic-gate 	ct->ct_lb_args->region_size = LOAD_BALANCE_DEFAULT_REGION_SIZE;
1114*7c478bd9Sstevel@tonic-gate 	ct->ct_path_count = 0;
1115*7c478bd9Sstevel@tonic-gate 	ct->ct_path_head = NULL;
1116*7c478bd9Sstevel@tonic-gate 	ct->ct_path_tail = NULL;
1117*7c478bd9Sstevel@tonic-gate 	ct->ct_path_last = NULL;
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 	/*
1121*7c478bd9Sstevel@tonic-gate 	 * Add this client component to our client hash queue
1122*7c478bd9Sstevel@tonic-gate 	 */
1123*7c478bd9Sstevel@tonic-gate 	i_mdi_client_enlist_table(vh, ct);
1124*7c478bd9Sstevel@tonic-gate 	return (ct);
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate fail:
1127*7c478bd9Sstevel@tonic-gate 	if (guid)
1128*7c478bd9Sstevel@tonic-gate 		kmem_free(guid, strlen(lguid) + 1);
1129*7c478bd9Sstevel@tonic-gate 	if (drvname)
1130*7c478bd9Sstevel@tonic-gate 		kmem_free(drvname, strlen(name) + 1);
1131*7c478bd9Sstevel@tonic-gate 	if (lb_args)
1132*7c478bd9Sstevel@tonic-gate 		kmem_free(lb_args, sizeof (client_lb_args_t));
1133*7c478bd9Sstevel@tonic-gate 	kmem_free(ct, sizeof (*ct));
1134*7c478bd9Sstevel@tonic-gate 	return (NULL);
1135*7c478bd9Sstevel@tonic-gate }
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate /*
1138*7c478bd9Sstevel@tonic-gate  * i_mdi_client_enlist_table():
1139*7c478bd9Sstevel@tonic-gate  *		Attach the client device to the client hash table. Caller
1140*7c478bd9Sstevel@tonic-gate  *		should hold the mdi_mutex
1141*7c478bd9Sstevel@tonic-gate  */
1142*7c478bd9Sstevel@tonic-gate 
1143*7c478bd9Sstevel@tonic-gate static void
1144*7c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(mdi_vhci_t *vh, mdi_client_t *ct)
1145*7c478bd9Sstevel@tonic-gate {
1146*7c478bd9Sstevel@tonic-gate 	int 			index;
1147*7c478bd9Sstevel@tonic-gate 	struct client_hash	*head;
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mdi_mutex));
1150*7c478bd9Sstevel@tonic-gate 	index = i_mdi_get_hash_key(ct->ct_guid);
1151*7c478bd9Sstevel@tonic-gate 	head = &vh->vh_client_table[index];
1152*7c478bd9Sstevel@tonic-gate 	ct->ct_hnext = (mdi_client_t *)head->ct_hash_head;
1153*7c478bd9Sstevel@tonic-gate 	head->ct_hash_head = ct;
1154*7c478bd9Sstevel@tonic-gate 	head->ct_hash_count++;
1155*7c478bd9Sstevel@tonic-gate 	vh->vh_client_count++;
1156*7c478bd9Sstevel@tonic-gate }
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate /*
1159*7c478bd9Sstevel@tonic-gate  * i_mdi_client_delist_table():
1160*7c478bd9Sstevel@tonic-gate  *		Attach the client device to the client hash table.
1161*7c478bd9Sstevel@tonic-gate  *		Caller should hold the mdi_mutex
1162*7c478bd9Sstevel@tonic-gate  */
1163*7c478bd9Sstevel@tonic-gate 
1164*7c478bd9Sstevel@tonic-gate static void
1165*7c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(mdi_vhci_t *vh, mdi_client_t *ct)
1166*7c478bd9Sstevel@tonic-gate {
1167*7c478bd9Sstevel@tonic-gate 	int			index;
1168*7c478bd9Sstevel@tonic-gate 	char			*guid;
1169*7c478bd9Sstevel@tonic-gate 	struct client_hash 	*head;
1170*7c478bd9Sstevel@tonic-gate 	mdi_client_t		*next;
1171*7c478bd9Sstevel@tonic-gate 	mdi_client_t		*last;
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mdi_mutex));
1174*7c478bd9Sstevel@tonic-gate 	guid = ct->ct_guid;
1175*7c478bd9Sstevel@tonic-gate 	index = i_mdi_get_hash_key(guid);
1176*7c478bd9Sstevel@tonic-gate 	head = &vh->vh_client_table[index];
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate 	last = NULL;
1179*7c478bd9Sstevel@tonic-gate 	next = (mdi_client_t *)head->ct_hash_head;
1180*7c478bd9Sstevel@tonic-gate 	while (next != NULL) {
1181*7c478bd9Sstevel@tonic-gate 		if (next == ct) {
1182*7c478bd9Sstevel@tonic-gate 			break;
1183*7c478bd9Sstevel@tonic-gate 		}
1184*7c478bd9Sstevel@tonic-gate 		last = next;
1185*7c478bd9Sstevel@tonic-gate 		next = next->ct_hnext;
1186*7c478bd9Sstevel@tonic-gate 	}
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate 	if (next) {
1189*7c478bd9Sstevel@tonic-gate 		head->ct_hash_count--;
1190*7c478bd9Sstevel@tonic-gate 		if (last == NULL) {
1191*7c478bd9Sstevel@tonic-gate 			head->ct_hash_head = ct->ct_hnext;
1192*7c478bd9Sstevel@tonic-gate 		} else {
1193*7c478bd9Sstevel@tonic-gate 			last->ct_hnext = ct->ct_hnext;
1194*7c478bd9Sstevel@tonic-gate 		}
1195*7c478bd9Sstevel@tonic-gate 		ct->ct_hnext = NULL;
1196*7c478bd9Sstevel@tonic-gate 		vh->vh_client_count--;
1197*7c478bd9Sstevel@tonic-gate 	}
1198*7c478bd9Sstevel@tonic-gate }
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate /*
1202*7c478bd9Sstevel@tonic-gate  * i_mdi_client_free():
1203*7c478bd9Sstevel@tonic-gate  *		Free a client component
1204*7c478bd9Sstevel@tonic-gate  */
1205*7c478bd9Sstevel@tonic-gate static int
1206*7c478bd9Sstevel@tonic-gate i_mdi_client_free(mdi_vhci_t *vh, mdi_client_t *ct)
1207*7c478bd9Sstevel@tonic-gate {
1208*7c478bd9Sstevel@tonic-gate 	int		rv = MDI_SUCCESS;
1209*7c478bd9Sstevel@tonic-gate 	int		flags = ct->ct_flags;
1210*7c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip;
1211*7c478bd9Sstevel@tonic-gate 	dev_info_t	*vdip;
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mdi_mutex));
1214*7c478bd9Sstevel@tonic-gate 	vdip = vh->vh_dip;
1215*7c478bd9Sstevel@tonic-gate 	cdip = ct->ct_dip;
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate 	(void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, MDI_CLIENT_GUID_PROP);
1218*7c478bd9Sstevel@tonic-gate 	DEVI(cdip)->devi_mdi_component &= ~MDI_COMPONENT_CLIENT;
1219*7c478bd9Sstevel@tonic-gate 	DEVI(cdip)->devi_mdi_client = NULL;
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 	/*
1222*7c478bd9Sstevel@tonic-gate 	 * Clear out back ref. to dev_info_t node
1223*7c478bd9Sstevel@tonic-gate 	 */
1224*7c478bd9Sstevel@tonic-gate 	ct->ct_dip = NULL;
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	/*
1227*7c478bd9Sstevel@tonic-gate 	 * Remove this client from our hash queue
1228*7c478bd9Sstevel@tonic-gate 	 */
1229*7c478bd9Sstevel@tonic-gate 	i_mdi_client_delist_table(vh, ct);
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 	/*
1232*7c478bd9Sstevel@tonic-gate 	 * Uninitialize and free the component
1233*7c478bd9Sstevel@tonic-gate 	 */
1234*7c478bd9Sstevel@tonic-gate 	kmem_free(ct->ct_drvname, strlen(ct->ct_drvname) + 1);
1235*7c478bd9Sstevel@tonic-gate 	kmem_free(ct->ct_guid, strlen(ct->ct_guid) + 1);
1236*7c478bd9Sstevel@tonic-gate 	kmem_free(ct->ct_lb_args, sizeof (client_lb_args_t));
1237*7c478bd9Sstevel@tonic-gate 	cv_destroy(&ct->ct_failover_cv);
1238*7c478bd9Sstevel@tonic-gate 	cv_destroy(&ct->ct_unstable_cv);
1239*7c478bd9Sstevel@tonic-gate 	cv_destroy(&ct->ct_powerchange_cv);
1240*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&ct->ct_mutex);
1241*7c478bd9Sstevel@tonic-gate 	kmem_free(ct, sizeof (*ct));
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	if (cdip != NULL) {
1244*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mdi_mutex);
1245*7c478bd9Sstevel@tonic-gate 		(void) i_mdi_devinfo_remove(vdip, cdip, flags);
1246*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mdi_mutex);
1247*7c478bd9Sstevel@tonic-gate 	}
1248*7c478bd9Sstevel@tonic-gate 	return (rv);
1249*7c478bd9Sstevel@tonic-gate }
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate /*
1252*7c478bd9Sstevel@tonic-gate  * i_mdi_client_find():
1253*7c478bd9Sstevel@tonic-gate  * 		Find the client structure corresponding to a given guid
1254*7c478bd9Sstevel@tonic-gate  *		Caller should hold the mdi_mutex
1255*7c478bd9Sstevel@tonic-gate  */
1256*7c478bd9Sstevel@tonic-gate static mdi_client_t *
1257*7c478bd9Sstevel@tonic-gate i_mdi_client_find(mdi_vhci_t *vh, char *guid)
1258*7c478bd9Sstevel@tonic-gate {
1259*7c478bd9Sstevel@tonic-gate 	int			index;
1260*7c478bd9Sstevel@tonic-gate 	struct client_hash	*head;
1261*7c478bd9Sstevel@tonic-gate 	mdi_client_t		*ct;
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mdi_mutex));
1264*7c478bd9Sstevel@tonic-gate 	index = i_mdi_get_hash_key(guid);
1265*7c478bd9Sstevel@tonic-gate 	head = &vh->vh_client_table[index];
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 	ct = head->ct_hash_head;
1268*7c478bd9Sstevel@tonic-gate 	while (ct != NULL) {
1269*7c478bd9Sstevel@tonic-gate 		if (strcmp(ct->ct_guid, guid) == 0) {
1270*7c478bd9Sstevel@tonic-gate 			break;
1271*7c478bd9Sstevel@tonic-gate 		}
1272*7c478bd9Sstevel@tonic-gate 		ct = ct->ct_hnext;
1273*7c478bd9Sstevel@tonic-gate 	}
1274*7c478bd9Sstevel@tonic-gate 	return (ct);
1275*7c478bd9Sstevel@tonic-gate }
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate /*
1280*7c478bd9Sstevel@tonic-gate  * i_mdi_client_update_state():
1281*7c478bd9Sstevel@tonic-gate  *		Compute and update client device state
1282*7c478bd9Sstevel@tonic-gate  * Notes:
1283*7c478bd9Sstevel@tonic-gate  *		A client device can be in any of three possible states:
1284*7c478bd9Sstevel@tonic-gate  *
1285*7c478bd9Sstevel@tonic-gate  *		MDI_CLIENT_STATE_OPTIMAL - Client in optimal state with more
1286*7c478bd9Sstevel@tonic-gate  *		one online/standby paths. Can tolerate failures.
1287*7c478bd9Sstevel@tonic-gate  *		MDI_CLIENT_STATE_DEGRADED - Client device in degraded state with
1288*7c478bd9Sstevel@tonic-gate  *		no alternate paths available as standby. A failure on the online
1289*7c478bd9Sstevel@tonic-gate  *		would result in loss of access to device data.
1290*7c478bd9Sstevel@tonic-gate  *		MDI_CLIENT_STATE_FAILED - Client device in failed state with
1291*7c478bd9Sstevel@tonic-gate  *		no paths available to access the device.
1292*7c478bd9Sstevel@tonic-gate  */
1293*7c478bd9Sstevel@tonic-gate static void
1294*7c478bd9Sstevel@tonic-gate i_mdi_client_update_state(mdi_client_t *ct)
1295*7c478bd9Sstevel@tonic-gate {
1296*7c478bd9Sstevel@tonic-gate 	int state;
1297*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ct->ct_mutex));
1298*7c478bd9Sstevel@tonic-gate 	state = i_mdi_client_compute_state(ct, NULL);
1299*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_SET_STATE(ct, state);
1300*7c478bd9Sstevel@tonic-gate }
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate /*
1303*7c478bd9Sstevel@tonic-gate  * i_mdi_client_compute_state():
1304*7c478bd9Sstevel@tonic-gate  *		Compute client device state
1305*7c478bd9Sstevel@tonic-gate  *
1306*7c478bd9Sstevel@tonic-gate  *		mdi_phci_t *	Pointer to pHCI structure which should
1307*7c478bd9Sstevel@tonic-gate  *				while computing the new value.  Used by
1308*7c478bd9Sstevel@tonic-gate  *				i_mdi_phci_offline() to find the new
1309*7c478bd9Sstevel@tonic-gate  *				client state after DR of a pHCI.
1310*7c478bd9Sstevel@tonic-gate  */
1311*7c478bd9Sstevel@tonic-gate static int
1312*7c478bd9Sstevel@tonic-gate i_mdi_client_compute_state(mdi_client_t *ct, mdi_phci_t *ph)
1313*7c478bd9Sstevel@tonic-gate {
1314*7c478bd9Sstevel@tonic-gate 	int		state;
1315*7c478bd9Sstevel@tonic-gate 	int		online_count = 0;
1316*7c478bd9Sstevel@tonic-gate 	int		standby_count = 0;
1317*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*pip, *next;
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ct->ct_mutex));
1320*7c478bd9Sstevel@tonic-gate 	pip = ct->ct_path_head;
1321*7c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
1322*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
1323*7c478bd9Sstevel@tonic-gate 		next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
1324*7c478bd9Sstevel@tonic-gate 		if (MDI_PI(pip)->pi_phci == ph) {
1325*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
1326*7c478bd9Sstevel@tonic-gate 			pip = next;
1327*7c478bd9Sstevel@tonic-gate 			continue;
1328*7c478bd9Sstevel@tonic-gate 		}
1329*7c478bd9Sstevel@tonic-gate 		if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK)
1330*7c478bd9Sstevel@tonic-gate 				== MDI_PATHINFO_STATE_ONLINE)
1331*7c478bd9Sstevel@tonic-gate 			online_count++;
1332*7c478bd9Sstevel@tonic-gate 		else if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK)
1333*7c478bd9Sstevel@tonic-gate 				== MDI_PATHINFO_STATE_STANDBY)
1334*7c478bd9Sstevel@tonic-gate 			standby_count++;
1335*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
1336*7c478bd9Sstevel@tonic-gate 		pip = next;
1337*7c478bd9Sstevel@tonic-gate 	}
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 	if (online_count == 0) {
1340*7c478bd9Sstevel@tonic-gate 		if (standby_count == 0) {
1341*7c478bd9Sstevel@tonic-gate 			state = MDI_CLIENT_STATE_FAILED;
1342*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(2, (CE_NOTE, NULL, "!client state: failed"
1343*7c478bd9Sstevel@tonic-gate 			    " ct = %p\n", ct));
1344*7c478bd9Sstevel@tonic-gate 		} else if (standby_count == 1) {
1345*7c478bd9Sstevel@tonic-gate 			state = MDI_CLIENT_STATE_DEGRADED;
1346*7c478bd9Sstevel@tonic-gate 		} else {
1347*7c478bd9Sstevel@tonic-gate 			state = MDI_CLIENT_STATE_OPTIMAL;
1348*7c478bd9Sstevel@tonic-gate 		}
1349*7c478bd9Sstevel@tonic-gate 	} else if (online_count == 1) {
1350*7c478bd9Sstevel@tonic-gate 		if (standby_count == 0) {
1351*7c478bd9Sstevel@tonic-gate 			state = MDI_CLIENT_STATE_DEGRADED;
1352*7c478bd9Sstevel@tonic-gate 		} else {
1353*7c478bd9Sstevel@tonic-gate 			state = MDI_CLIENT_STATE_OPTIMAL;
1354*7c478bd9Sstevel@tonic-gate 		}
1355*7c478bd9Sstevel@tonic-gate 	} else {
1356*7c478bd9Sstevel@tonic-gate 		state = MDI_CLIENT_STATE_OPTIMAL;
1357*7c478bd9Sstevel@tonic-gate 	}
1358*7c478bd9Sstevel@tonic-gate 	return (state);
1359*7c478bd9Sstevel@tonic-gate }
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate /*
1362*7c478bd9Sstevel@tonic-gate  * i_mdi_client2devinfo():
1363*7c478bd9Sstevel@tonic-gate  *		Utility function
1364*7c478bd9Sstevel@tonic-gate  */
1365*7c478bd9Sstevel@tonic-gate dev_info_t *
1366*7c478bd9Sstevel@tonic-gate i_mdi_client2devinfo(mdi_client_t *ct)
1367*7c478bd9Sstevel@tonic-gate {
1368*7c478bd9Sstevel@tonic-gate 	return (ct->ct_dip);
1369*7c478bd9Sstevel@tonic-gate }
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate /*
1372*7c478bd9Sstevel@tonic-gate  * mdi_client_path2_devinfo():
1373*7c478bd9Sstevel@tonic-gate  * 		Given the parent devinfo and child devfs pathname, search for
1374*7c478bd9Sstevel@tonic-gate  *		a valid devfs node handle.
1375*7c478bd9Sstevel@tonic-gate  */
1376*7c478bd9Sstevel@tonic-gate dev_info_t *
1377*7c478bd9Sstevel@tonic-gate mdi_client_path2devinfo(dev_info_t *vdip, char *pathname)
1378*7c478bd9Sstevel@tonic-gate {
1379*7c478bd9Sstevel@tonic-gate 	dev_info_t 	*cdip = NULL;
1380*7c478bd9Sstevel@tonic-gate 	dev_info_t 	*ndip = NULL;
1381*7c478bd9Sstevel@tonic-gate 	char		*temp_pathname;
1382*7c478bd9Sstevel@tonic-gate 	int		circular;
1383*7c478bd9Sstevel@tonic-gate 
1384*7c478bd9Sstevel@tonic-gate 	/*
1385*7c478bd9Sstevel@tonic-gate 	 * Allocate temp buffer
1386*7c478bd9Sstevel@tonic-gate 	 */
1387*7c478bd9Sstevel@tonic-gate 	temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate 	/*
1390*7c478bd9Sstevel@tonic-gate 	 * Lock parent against changes
1391*7c478bd9Sstevel@tonic-gate 	 */
1392*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(vdip, &circular);
1393*7c478bd9Sstevel@tonic-gate 	ndip = (dev_info_t *)DEVI(vdip)->devi_child;
1394*7c478bd9Sstevel@tonic-gate 	while ((cdip = ndip) != NULL) {
1395*7c478bd9Sstevel@tonic-gate 		ndip = (dev_info_t *)DEVI(cdip)->devi_sibling;
1396*7c478bd9Sstevel@tonic-gate 
1397*7c478bd9Sstevel@tonic-gate 		*temp_pathname = '\0';
1398*7c478bd9Sstevel@tonic-gate 		(void) ddi_pathname(cdip, temp_pathname);
1399*7c478bd9Sstevel@tonic-gate 		if (strcmp(temp_pathname, pathname) == 0) {
1400*7c478bd9Sstevel@tonic-gate 			break;
1401*7c478bd9Sstevel@tonic-gate 		}
1402*7c478bd9Sstevel@tonic-gate 	}
1403*7c478bd9Sstevel@tonic-gate 	/*
1404*7c478bd9Sstevel@tonic-gate 	 * Release devinfo lock
1405*7c478bd9Sstevel@tonic-gate 	 */
1406*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(vdip, circular);
1407*7c478bd9Sstevel@tonic-gate 
1408*7c478bd9Sstevel@tonic-gate 	/*
1409*7c478bd9Sstevel@tonic-gate 	 * Free the temp buffer
1410*7c478bd9Sstevel@tonic-gate 	 */
1411*7c478bd9Sstevel@tonic-gate 	kmem_free(temp_pathname, MAXPATHLEN);
1412*7c478bd9Sstevel@tonic-gate 	return (cdip);
1413*7c478bd9Sstevel@tonic-gate }
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate /*
1417*7c478bd9Sstevel@tonic-gate  * mdi_client_get_path_count():
1418*7c478bd9Sstevel@tonic-gate  * 		Utility function to get number of path information nodes
1419*7c478bd9Sstevel@tonic-gate  *		associated with a given client device.
1420*7c478bd9Sstevel@tonic-gate  */
1421*7c478bd9Sstevel@tonic-gate int
1422*7c478bd9Sstevel@tonic-gate mdi_client_get_path_count(dev_info_t *cdip)
1423*7c478bd9Sstevel@tonic-gate {
1424*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
1425*7c478bd9Sstevel@tonic-gate 	int		count = 0;
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(cdip);
1428*7c478bd9Sstevel@tonic-gate 	if (ct != NULL) {
1429*7c478bd9Sstevel@tonic-gate 		count = ct->ct_path_count;
1430*7c478bd9Sstevel@tonic-gate 	}
1431*7c478bd9Sstevel@tonic-gate 	return (count);
1432*7c478bd9Sstevel@tonic-gate }
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate /*
1436*7c478bd9Sstevel@tonic-gate  * i_mdi_get_hash_key():
1437*7c478bd9Sstevel@tonic-gate  * 		Create a hash using strings as keys
1438*7c478bd9Sstevel@tonic-gate  *
1439*7c478bd9Sstevel@tonic-gate  */
1440*7c478bd9Sstevel@tonic-gate static int
1441*7c478bd9Sstevel@tonic-gate i_mdi_get_hash_key(char *str)
1442*7c478bd9Sstevel@tonic-gate {
1443*7c478bd9Sstevel@tonic-gate 	uint32_t	g, hash = 0;
1444*7c478bd9Sstevel@tonic-gate 	char		*p;
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate 	for (p = str; *p != '\0'; p++) {
1447*7c478bd9Sstevel@tonic-gate 		g = *p;
1448*7c478bd9Sstevel@tonic-gate 		hash += g;
1449*7c478bd9Sstevel@tonic-gate 	}
1450*7c478bd9Sstevel@tonic-gate 	return (hash % (CLIENT_HASH_TABLE_SIZE - 1));
1451*7c478bd9Sstevel@tonic-gate }
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate /*
1454*7c478bd9Sstevel@tonic-gate  * mdi_get_lb_policy():
1455*7c478bd9Sstevel@tonic-gate  * 		Get current load balancing policy for a given client device
1456*7c478bd9Sstevel@tonic-gate  */
1457*7c478bd9Sstevel@tonic-gate client_lb_t
1458*7c478bd9Sstevel@tonic-gate mdi_get_lb_policy(dev_info_t *cdip)
1459*7c478bd9Sstevel@tonic-gate {
1460*7c478bd9Sstevel@tonic-gate 	client_lb_t	lb = LOAD_BALANCE_NONE;
1461*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
1462*7c478bd9Sstevel@tonic-gate 
1463*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(cdip);
1464*7c478bd9Sstevel@tonic-gate 	if (ct != NULL) {
1465*7c478bd9Sstevel@tonic-gate 		lb = ct->ct_lb;
1466*7c478bd9Sstevel@tonic-gate 	}
1467*7c478bd9Sstevel@tonic-gate 	return (lb);
1468*7c478bd9Sstevel@tonic-gate }
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate /*
1471*7c478bd9Sstevel@tonic-gate  * mdi_set_lb_region_size():
1472*7c478bd9Sstevel@tonic-gate  * 		Set current region size for the load-balance
1473*7c478bd9Sstevel@tonic-gate  */
1474*7c478bd9Sstevel@tonic-gate int
1475*7c478bd9Sstevel@tonic-gate mdi_set_lb_region_size(dev_info_t *cdip, int region_size)
1476*7c478bd9Sstevel@tonic-gate {
1477*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
1478*7c478bd9Sstevel@tonic-gate 	int		rv = MDI_FAILURE;
1479*7c478bd9Sstevel@tonic-gate 
1480*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(cdip);
1481*7c478bd9Sstevel@tonic-gate 	if (ct != NULL && ct->ct_lb_args != NULL) {
1482*7c478bd9Sstevel@tonic-gate 		ct->ct_lb_args->region_size = region_size;
1483*7c478bd9Sstevel@tonic-gate 		rv = MDI_SUCCESS;
1484*7c478bd9Sstevel@tonic-gate 	}
1485*7c478bd9Sstevel@tonic-gate 	return (rv);
1486*7c478bd9Sstevel@tonic-gate }
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate /*
1489*7c478bd9Sstevel@tonic-gate  * mdi_Set_lb_policy():
1490*7c478bd9Sstevel@tonic-gate  * 		Set current load balancing policy for a given client device
1491*7c478bd9Sstevel@tonic-gate  */
1492*7c478bd9Sstevel@tonic-gate int
1493*7c478bd9Sstevel@tonic-gate mdi_set_lb_policy(dev_info_t *cdip, client_lb_t lb)
1494*7c478bd9Sstevel@tonic-gate {
1495*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
1496*7c478bd9Sstevel@tonic-gate 	int		rv = MDI_FAILURE;
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(cdip);
1499*7c478bd9Sstevel@tonic-gate 	if (ct != NULL) {
1500*7c478bd9Sstevel@tonic-gate 		ct->ct_lb = lb;
1501*7c478bd9Sstevel@tonic-gate 		rv = MDI_SUCCESS;
1502*7c478bd9Sstevel@tonic-gate 	}
1503*7c478bd9Sstevel@tonic-gate 	return (rv);
1504*7c478bd9Sstevel@tonic-gate }
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate /*
1507*7c478bd9Sstevel@tonic-gate  * mdi_failover():
1508*7c478bd9Sstevel@tonic-gate  *		failover function called by the vHCI drivers to initiate
1509*7c478bd9Sstevel@tonic-gate  *		a failover operation.  This is typically due to non-availability
1510*7c478bd9Sstevel@tonic-gate  *		of online paths to route I/O requests.  Failover can be
1511*7c478bd9Sstevel@tonic-gate  *		triggered through user application also.
1512*7c478bd9Sstevel@tonic-gate  *
1513*7c478bd9Sstevel@tonic-gate  *		The vHCI driver calls mdi_failover() to initiate a failover
1514*7c478bd9Sstevel@tonic-gate  *		operation. mdi_failover() calls back into the vHCI driver's
1515*7c478bd9Sstevel@tonic-gate  *		vo_failover() entry point to perform the actual failover
1516*7c478bd9Sstevel@tonic-gate  *		operation.  The reason for requiring the vHCI driver to
1517*7c478bd9Sstevel@tonic-gate  *		initiate failover by calling mdi_failover(), instead of directly
1518*7c478bd9Sstevel@tonic-gate  *		executing vo_failover() itself, is to ensure that the mdi
1519*7c478bd9Sstevel@tonic-gate  *		framework can keep track of the client state properly.
1520*7c478bd9Sstevel@tonic-gate  *		Additionally, mdi_failover() provides as a convenience the
1521*7c478bd9Sstevel@tonic-gate  *		option of performing the failover operation synchronously or
1522*7c478bd9Sstevel@tonic-gate  *		asynchronously
1523*7c478bd9Sstevel@tonic-gate  *
1524*7c478bd9Sstevel@tonic-gate  *		Upon successful completion of the failover operation, the
1525*7c478bd9Sstevel@tonic-gate  *		paths that were previously ONLINE will be in the STANDBY state,
1526*7c478bd9Sstevel@tonic-gate  *		and the newly activated paths will be in the ONLINE state.
1527*7c478bd9Sstevel@tonic-gate  *
1528*7c478bd9Sstevel@tonic-gate  *		The flags modifier determines whether the activation is done
1529*7c478bd9Sstevel@tonic-gate  *		synchronously: MDI_FAILOVER_SYNC
1530*7c478bd9Sstevel@tonic-gate  * Return Values:
1531*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
1532*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
1533*7c478bd9Sstevel@tonic-gate  *		MDI_BUSY
1534*7c478bd9Sstevel@tonic-gate  */
1535*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1536*7c478bd9Sstevel@tonic-gate int
1537*7c478bd9Sstevel@tonic-gate mdi_failover(dev_info_t *vdip, dev_info_t *cdip, int flags)
1538*7c478bd9Sstevel@tonic-gate {
1539*7c478bd9Sstevel@tonic-gate 	int			rv;
1540*7c478bd9Sstevel@tonic-gate 	mdi_client_t		*ct;
1541*7c478bd9Sstevel@tonic-gate 
1542*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(cdip);
1543*7c478bd9Sstevel@tonic-gate 	ASSERT(ct != NULL);
1544*7c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
1545*7c478bd9Sstevel@tonic-gate 		/* cdip is not a valid client device. Nothing more to do. */
1546*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
1547*7c478bd9Sstevel@tonic-gate 	}
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT_IS_PATH_FREE_IN_PROGRESS(ct)) {
1552*7c478bd9Sstevel@tonic-gate 		/* A path to the client is being freed */
1553*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
1554*7c478bd9Sstevel@tonic-gate 		return (MDI_BUSY);
1555*7c478bd9Sstevel@tonic-gate 	}
1556*7c478bd9Sstevel@tonic-gate 
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT_IS_FAILED(ct)) {
1559*7c478bd9Sstevel@tonic-gate 		/*
1560*7c478bd9Sstevel@tonic-gate 		 * Client is in failed state. Nothing more to do.
1561*7c478bd9Sstevel@tonic-gate 		 */
1562*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
1563*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
1564*7c478bd9Sstevel@tonic-gate 	}
1565*7c478bd9Sstevel@tonic-gate 
1566*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) {
1567*7c478bd9Sstevel@tonic-gate 		/*
1568*7c478bd9Sstevel@tonic-gate 		 * Failover is already in progress; return BUSY
1569*7c478bd9Sstevel@tonic-gate 		 */
1570*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
1571*7c478bd9Sstevel@tonic-gate 		return (MDI_BUSY);
1572*7c478bd9Sstevel@tonic-gate 	}
1573*7c478bd9Sstevel@tonic-gate 	/*
1574*7c478bd9Sstevel@tonic-gate 	 * Make sure that mdi_pathinfo node state changes are processed.
1575*7c478bd9Sstevel@tonic-gate 	 * We do not allow failovers to progress while client path state
1576*7c478bd9Sstevel@tonic-gate 	 * changes are in progress
1577*7c478bd9Sstevel@tonic-gate 	 */
1578*7c478bd9Sstevel@tonic-gate 	if (ct->ct_unstable) {
1579*7c478bd9Sstevel@tonic-gate 		if (flags == MDI_FAILOVER_ASYNC) {
1580*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
1581*7c478bd9Sstevel@tonic-gate 			return (MDI_BUSY);
1582*7c478bd9Sstevel@tonic-gate 		} else {
1583*7c478bd9Sstevel@tonic-gate 			while (ct->ct_unstable)
1584*7c478bd9Sstevel@tonic-gate 				cv_wait(&ct->ct_unstable_cv, &ct->ct_mutex);
1585*7c478bd9Sstevel@tonic-gate 		}
1586*7c478bd9Sstevel@tonic-gate 	}
1587*7c478bd9Sstevel@tonic-gate 
1588*7c478bd9Sstevel@tonic-gate 	/*
1589*7c478bd9Sstevel@tonic-gate 	 * Client device is in stable state. Before proceeding, perform sanity
1590*7c478bd9Sstevel@tonic-gate 	 * checks again.
1591*7c478bd9Sstevel@tonic-gate 	 */
1592*7c478bd9Sstevel@tonic-gate 	if ((MDI_CLIENT_IS_DETACHED(ct)) || (MDI_CLIENT_IS_FAILED(ct)) ||
1593*7c478bd9Sstevel@tonic-gate 	    (i_ddi_node_state(ct->ct_dip) < DS_READY)) {
1594*7c478bd9Sstevel@tonic-gate 		/*
1595*7c478bd9Sstevel@tonic-gate 		 * Client is in failed state. Nothing more to do.
1596*7c478bd9Sstevel@tonic-gate 		 */
1597*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
1598*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
1599*7c478bd9Sstevel@tonic-gate 	}
1600*7c478bd9Sstevel@tonic-gate 
1601*7c478bd9Sstevel@tonic-gate 	/*
1602*7c478bd9Sstevel@tonic-gate 	 * Set the client state as failover in progress.
1603*7c478bd9Sstevel@tonic-gate 	 */
1604*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_SET_FAILOVER_IN_PROGRESS(ct);
1605*7c478bd9Sstevel@tonic-gate 	ct->ct_failover_flags = flags;
1606*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
1607*7c478bd9Sstevel@tonic-gate 
1608*7c478bd9Sstevel@tonic-gate 	if (flags == MDI_FAILOVER_ASYNC) {
1609*7c478bd9Sstevel@tonic-gate 		/*
1610*7c478bd9Sstevel@tonic-gate 		 * Submit the initiate failover request via CPR safe
1611*7c478bd9Sstevel@tonic-gate 		 * taskq threads.
1612*7c478bd9Sstevel@tonic-gate 		 */
1613*7c478bd9Sstevel@tonic-gate 		(void) taskq_dispatch(mdi_taskq, (task_func_t *)i_mdi_failover,
1614*7c478bd9Sstevel@tonic-gate 		    ct, KM_SLEEP);
1615*7c478bd9Sstevel@tonic-gate 		return (MDI_ACCEPT);
1616*7c478bd9Sstevel@tonic-gate 	} else {
1617*7c478bd9Sstevel@tonic-gate 		/*
1618*7c478bd9Sstevel@tonic-gate 		 * Synchronous failover mode.  Typically invoked from the user
1619*7c478bd9Sstevel@tonic-gate 		 * land.
1620*7c478bd9Sstevel@tonic-gate 		 */
1621*7c478bd9Sstevel@tonic-gate 		rv = i_mdi_failover(ct);
1622*7c478bd9Sstevel@tonic-gate 	}
1623*7c478bd9Sstevel@tonic-gate 	return (rv);
1624*7c478bd9Sstevel@tonic-gate }
1625*7c478bd9Sstevel@tonic-gate 
1626*7c478bd9Sstevel@tonic-gate /*
1627*7c478bd9Sstevel@tonic-gate  * i_mdi_failover():
1628*7c478bd9Sstevel@tonic-gate  *		internal failover function. Invokes vHCI drivers failover
1629*7c478bd9Sstevel@tonic-gate  *		callback function and process the failover status
1630*7c478bd9Sstevel@tonic-gate  * Return Values:
1631*7c478bd9Sstevel@tonic-gate  *		None
1632*7c478bd9Sstevel@tonic-gate  *
1633*7c478bd9Sstevel@tonic-gate  * Note: A client device in failover state can not be detached or freed.
1634*7c478bd9Sstevel@tonic-gate  */
1635*7c478bd9Sstevel@tonic-gate static int
1636*7c478bd9Sstevel@tonic-gate i_mdi_failover(void *arg)
1637*7c478bd9Sstevel@tonic-gate {
1638*7c478bd9Sstevel@tonic-gate 	int		rv = MDI_SUCCESS;
1639*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct = (mdi_client_t *)arg;
1640*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*vh = ct->ct_vhci;
1641*7c478bd9Sstevel@tonic-gate 
1642*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&ct->ct_mutex));
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate 	if (vh->vh_ops->vo_failover != NULL) {
1645*7c478bd9Sstevel@tonic-gate 		/*
1646*7c478bd9Sstevel@tonic-gate 		 * Call vHCI drivers callback routine
1647*7c478bd9Sstevel@tonic-gate 		 */
1648*7c478bd9Sstevel@tonic-gate 		rv = (*vh->vh_ops->vo_failover)(vh->vh_dip, ct->ct_dip,
1649*7c478bd9Sstevel@tonic-gate 		    ct->ct_failover_flags);
1650*7c478bd9Sstevel@tonic-gate 	}
1651*7c478bd9Sstevel@tonic-gate 
1652*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
1653*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_CLEAR_FAILOVER_IN_PROGRESS(ct);
1654*7c478bd9Sstevel@tonic-gate 
1655*7c478bd9Sstevel@tonic-gate 	/*
1656*7c478bd9Sstevel@tonic-gate 	 * Save the failover return status
1657*7c478bd9Sstevel@tonic-gate 	 */
1658*7c478bd9Sstevel@tonic-gate 	ct->ct_failover_status = rv;
1659*7c478bd9Sstevel@tonic-gate 
1660*7c478bd9Sstevel@tonic-gate 	/*
1661*7c478bd9Sstevel@tonic-gate 	 * As a result of failover, client status would have been changed.
1662*7c478bd9Sstevel@tonic-gate 	 * Update the client state and wake up anyone waiting on this client
1663*7c478bd9Sstevel@tonic-gate 	 * device.
1664*7c478bd9Sstevel@tonic-gate 	 */
1665*7c478bd9Sstevel@tonic-gate 	i_mdi_client_update_state(ct);
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&ct->ct_failover_cv);
1668*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
1669*7c478bd9Sstevel@tonic-gate 	return (rv);
1670*7c478bd9Sstevel@tonic-gate }
1671*7c478bd9Sstevel@tonic-gate 
1672*7c478bd9Sstevel@tonic-gate /*
1673*7c478bd9Sstevel@tonic-gate  * Load balancing is logical block.
1674*7c478bd9Sstevel@tonic-gate  * IOs within the range described by region_size
1675*7c478bd9Sstevel@tonic-gate  * would go on the same path. This would improve the
1676*7c478bd9Sstevel@tonic-gate  * performance by cache-hit on some of the RAID devices.
1677*7c478bd9Sstevel@tonic-gate  * Search only for online paths(At some point we
1678*7c478bd9Sstevel@tonic-gate  * may want to balance across target ports).
1679*7c478bd9Sstevel@tonic-gate  * If no paths are found then default to round-robin.
1680*7c478bd9Sstevel@tonic-gate  */
1681*7c478bd9Sstevel@tonic-gate static int
1682*7c478bd9Sstevel@tonic-gate i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp)
1683*7c478bd9Sstevel@tonic-gate {
1684*7c478bd9Sstevel@tonic-gate 	int		path_index = -1;
1685*7c478bd9Sstevel@tonic-gate 	int		online_path_count = 0;
1686*7c478bd9Sstevel@tonic-gate 	int		online_nonpref_path_count = 0;
1687*7c478bd9Sstevel@tonic-gate 	int 		region_size = ct->ct_lb_args->region_size;
1688*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*pip;
1689*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*next;
1690*7c478bd9Sstevel@tonic-gate 	int		preferred, path_cnt;
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate 	pip = ct->ct_path_head;
1693*7c478bd9Sstevel@tonic-gate 	while (pip) {
1694*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
1695*7c478bd9Sstevel@tonic-gate 		if (MDI_PI(pip)->pi_state ==
1696*7c478bd9Sstevel@tonic-gate 		    MDI_PATHINFO_STATE_ONLINE && MDI_PI(pip)->pi_preferred) {
1697*7c478bd9Sstevel@tonic-gate 			online_path_count++;
1698*7c478bd9Sstevel@tonic-gate 		} else if (MDI_PI(pip)->pi_state ==
1699*7c478bd9Sstevel@tonic-gate 		    MDI_PATHINFO_STATE_ONLINE && !MDI_PI(pip)->pi_preferred) {
1700*7c478bd9Sstevel@tonic-gate 			online_nonpref_path_count++;
1701*7c478bd9Sstevel@tonic-gate 		}
1702*7c478bd9Sstevel@tonic-gate 		next = (mdi_pathinfo_t *)
1703*7c478bd9Sstevel@tonic-gate 		    MDI_PI(pip)->pi_client_link;
1704*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
1705*7c478bd9Sstevel@tonic-gate 		pip = next;
1706*7c478bd9Sstevel@tonic-gate 	}
1707*7c478bd9Sstevel@tonic-gate 	/* if found any online/preferred then use this type */
1708*7c478bd9Sstevel@tonic-gate 	if (online_path_count > 0) {
1709*7c478bd9Sstevel@tonic-gate 		path_cnt = online_path_count;
1710*7c478bd9Sstevel@tonic-gate 		preferred = 1;
1711*7c478bd9Sstevel@tonic-gate 	} else if (online_nonpref_path_count > 0) {
1712*7c478bd9Sstevel@tonic-gate 		path_cnt = online_nonpref_path_count;
1713*7c478bd9Sstevel@tonic-gate 		preferred = 0;
1714*7c478bd9Sstevel@tonic-gate 	} else {
1715*7c478bd9Sstevel@tonic-gate 		path_cnt = 0;
1716*7c478bd9Sstevel@tonic-gate 	}
1717*7c478bd9Sstevel@tonic-gate 	if (path_cnt) {
1718*7c478bd9Sstevel@tonic-gate 		path_index = (bp->b_blkno >> region_size) % path_cnt;
1719*7c478bd9Sstevel@tonic-gate 		pip = ct->ct_path_head;
1720*7c478bd9Sstevel@tonic-gate 		while (pip && path_index != -1) {
1721*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
1722*7c478bd9Sstevel@tonic-gate 			if (path_index == 0 &&
1723*7c478bd9Sstevel@tonic-gate 			    (MDI_PI(pip)->pi_state ==
1724*7c478bd9Sstevel@tonic-gate 			    MDI_PATHINFO_STATE_ONLINE) &&
1725*7c478bd9Sstevel@tonic-gate 				MDI_PI(pip)->pi_preferred == preferred) {
1726*7c478bd9Sstevel@tonic-gate 				MDI_PI_HOLD(pip);
1727*7c478bd9Sstevel@tonic-gate 				MDI_PI_UNLOCK(pip);
1728*7c478bd9Sstevel@tonic-gate 				*ret_pip = pip;
1729*7c478bd9Sstevel@tonic-gate 				return (MDI_SUCCESS);
1730*7c478bd9Sstevel@tonic-gate 			}
1731*7c478bd9Sstevel@tonic-gate 			path_index --;
1732*7c478bd9Sstevel@tonic-gate 			next = (mdi_pathinfo_t *)
1733*7c478bd9Sstevel@tonic-gate 			    MDI_PI(pip)->pi_client_link;
1734*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
1735*7c478bd9Sstevel@tonic-gate 			pip = next;
1736*7c478bd9Sstevel@tonic-gate 		}
1737*7c478bd9Sstevel@tonic-gate 		if (pip == NULL) {
1738*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, NULL,
1739*7c478bd9Sstevel@tonic-gate 			    "!lba %p, no pip !!\n",
1740*7c478bd9Sstevel@tonic-gate 				bp->b_blkno));
1741*7c478bd9Sstevel@tonic-gate 		} else {
1742*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, NULL,
1743*7c478bd9Sstevel@tonic-gate 			    "!lba %p, no pip for path_index, "
1744*7c478bd9Sstevel@tonic-gate 			    "pip %p\n", pip));
1745*7c478bd9Sstevel@tonic-gate 		}
1746*7c478bd9Sstevel@tonic-gate 	}
1747*7c478bd9Sstevel@tonic-gate 	return (MDI_FAILURE);
1748*7c478bd9Sstevel@tonic-gate }
1749*7c478bd9Sstevel@tonic-gate 
1750*7c478bd9Sstevel@tonic-gate /*
1751*7c478bd9Sstevel@tonic-gate  * mdi_select_path():
1752*7c478bd9Sstevel@tonic-gate  *		select a path to access a client device.
1753*7c478bd9Sstevel@tonic-gate  *
1754*7c478bd9Sstevel@tonic-gate  *		mdi_select_path() function is called by the vHCI drivers to
1755*7c478bd9Sstevel@tonic-gate  *		select a path to route the I/O request to.  The caller passes
1756*7c478bd9Sstevel@tonic-gate  *		the block I/O data transfer structure ("buf") as one of the
1757*7c478bd9Sstevel@tonic-gate  *		parameters.  The mpxio framework uses the buf structure
1758*7c478bd9Sstevel@tonic-gate  *		contents to maintain per path statistics (total I/O size /
1759*7c478bd9Sstevel@tonic-gate  *		count pending).  If more than one online paths are available to
1760*7c478bd9Sstevel@tonic-gate  *		select, the framework automatically selects a suitable path
1761*7c478bd9Sstevel@tonic-gate  *		for routing I/O request. If a failover operation is active for
1762*7c478bd9Sstevel@tonic-gate  *		this client device the call shall be failed with MDI_BUSY error
1763*7c478bd9Sstevel@tonic-gate  *		code.
1764*7c478bd9Sstevel@tonic-gate  *
1765*7c478bd9Sstevel@tonic-gate  *		By default this function returns a suitable path in online
1766*7c478bd9Sstevel@tonic-gate  *		state based on the current load balancing policy.  Currently
1767*7c478bd9Sstevel@tonic-gate  *		we support LOAD_BALANCE_NONE (Previously selected online path
1768*7c478bd9Sstevel@tonic-gate  *		will continue to be used till the path is usable) and
1769*7c478bd9Sstevel@tonic-gate  *		LOAD_BALANCE_RR (Online paths will be selected in a round
1770*7c478bd9Sstevel@tonic-gate  *		robin fashion), LOAD_BALANCE_LB(Online paths will be selected
1771*7c478bd9Sstevel@tonic-gate  *		based on the logical block).  The load balancing
1772*7c478bd9Sstevel@tonic-gate  *		through vHCI drivers configuration file (driver.conf).
1773*7c478bd9Sstevel@tonic-gate  *
1774*7c478bd9Sstevel@tonic-gate  *		vHCI drivers may override this default behavior by specifying
1775*7c478bd9Sstevel@tonic-gate  *		appropriate flags.  If start_pip is specified (non NULL) is
1776*7c478bd9Sstevel@tonic-gate  *		used as start point to walk and find the next appropriate path.
1777*7c478bd9Sstevel@tonic-gate  *		The following values are currently defined:
1778*7c478bd9Sstevel@tonic-gate  *		MDI_SELECT_ONLINE_PATH (to select an ONLINE path) and/or
1779*7c478bd9Sstevel@tonic-gate  *		MDI_SELECT_STANDBY_PATH (to select an STANDBY path).
1780*7c478bd9Sstevel@tonic-gate  *
1781*7c478bd9Sstevel@tonic-gate  *		The non-standard behavior is used by the scsi_vhci driver,
1782*7c478bd9Sstevel@tonic-gate  *		whenever it has to use a STANDBY/FAULTED path.  Eg. during
1783*7c478bd9Sstevel@tonic-gate  *		attach of client devices (to avoid an unnecessary failover
1784*7c478bd9Sstevel@tonic-gate  *		when the STANDBY path comes up first), during failover
1785*7c478bd9Sstevel@tonic-gate  *		(to activate a STANDBY path as ONLINE).
1786*7c478bd9Sstevel@tonic-gate  *
1787*7c478bd9Sstevel@tonic-gate  *		The selected path in returned in a held state (ref_cnt).
1788*7c478bd9Sstevel@tonic-gate  *		Caller should release the hold by calling mdi_rele_path().
1789*7c478bd9Sstevel@tonic-gate  *
1790*7c478bd9Sstevel@tonic-gate  * Return Values:
1791*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS	- Completed successfully
1792*7c478bd9Sstevel@tonic-gate  *		MDI_BUSY 	- Client device is busy failing over
1793*7c478bd9Sstevel@tonic-gate  *		MDI_NOPATH	- Client device is online, but no valid path are
1794*7c478bd9Sstevel@tonic-gate  *				  available to access this client device
1795*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE	- Invalid client device or state
1796*7c478bd9Sstevel@tonic-gate  *		MDI_DEVI_ONLINING
1797*7c478bd9Sstevel@tonic-gate  *				- Client device (struct dev_info state) is in
1798*7c478bd9Sstevel@tonic-gate  *				  onlining state.
1799*7c478bd9Sstevel@tonic-gate  */
1800*7c478bd9Sstevel@tonic-gate 
1801*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1802*7c478bd9Sstevel@tonic-gate int
1803*7c478bd9Sstevel@tonic-gate mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags,
1804*7c478bd9Sstevel@tonic-gate     mdi_pathinfo_t *start_pip, mdi_pathinfo_t **ret_pip)
1805*7c478bd9Sstevel@tonic-gate {
1806*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
1807*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*pip;
1808*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*next;
1809*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*head;
1810*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*start;
1811*7c478bd9Sstevel@tonic-gate 	client_lb_t	lbp;	/* load balancing policy */
1812*7c478bd9Sstevel@tonic-gate 	int		sb = 1;	/* standard behavior */
1813*7c478bd9Sstevel@tonic-gate 	int		preferred = 1;	/* preferred path */
1814*7c478bd9Sstevel@tonic-gate 	int		cond, cont = 1;
1815*7c478bd9Sstevel@tonic-gate 	int		retry = 0;
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate 	if (flags != 0) {
1818*7c478bd9Sstevel@tonic-gate 		/*
1819*7c478bd9Sstevel@tonic-gate 		 * disable default behavior
1820*7c478bd9Sstevel@tonic-gate 		 */
1821*7c478bd9Sstevel@tonic-gate 		sb = 0;
1822*7c478bd9Sstevel@tonic-gate 	}
1823*7c478bd9Sstevel@tonic-gate 
1824*7c478bd9Sstevel@tonic-gate 	*ret_pip = NULL;
1825*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(cdip);
1826*7c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
1827*7c478bd9Sstevel@tonic-gate 		/* mdi extensions are NULL, Nothing more to do */
1828*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
1829*7c478bd9Sstevel@tonic-gate 	}
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
1832*7c478bd9Sstevel@tonic-gate 
1833*7c478bd9Sstevel@tonic-gate 	if (sb) {
1834*7c478bd9Sstevel@tonic-gate 		if (MDI_CLIENT_IS_FAILED(ct)) {
1835*7c478bd9Sstevel@tonic-gate 			/*
1836*7c478bd9Sstevel@tonic-gate 			 * Client is not ready to accept any I/O requests.
1837*7c478bd9Sstevel@tonic-gate 			 * Fail this request.
1838*7c478bd9Sstevel@tonic-gate 			 */
1839*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: "
1840*7c478bd9Sstevel@tonic-gate 			    "client state offline ct = %p\n", ct));
1841*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
1842*7c478bd9Sstevel@tonic-gate 			return (MDI_FAILURE);
1843*7c478bd9Sstevel@tonic-gate 		}
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 		if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) {
1846*7c478bd9Sstevel@tonic-gate 			/*
1847*7c478bd9Sstevel@tonic-gate 			 * Check for Failover is in progress. If so tell the
1848*7c478bd9Sstevel@tonic-gate 			 * caller that this device is busy.
1849*7c478bd9Sstevel@tonic-gate 			 */
1850*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: "
1851*7c478bd9Sstevel@tonic-gate 			    "client failover in progress ct = %p\n", ct));
1852*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
1853*7c478bd9Sstevel@tonic-gate 			return (MDI_BUSY);
1854*7c478bd9Sstevel@tonic-gate 		}
1855*7c478bd9Sstevel@tonic-gate 
1856*7c478bd9Sstevel@tonic-gate 		/*
1857*7c478bd9Sstevel@tonic-gate 		 * Check to see whether the client device is attached.
1858*7c478bd9Sstevel@tonic-gate 		 * If not so, let the vHCI driver manually select a path
1859*7c478bd9Sstevel@tonic-gate 		 * (standby) and let the probe/attach process to continue.
1860*7c478bd9Sstevel@tonic-gate 		 */
1861*7c478bd9Sstevel@tonic-gate 		if ((MDI_CLIENT_IS_DETACHED(ct)) ||
1862*7c478bd9Sstevel@tonic-gate 		    i_ddi_node_state(cdip) < DS_READY) {
1863*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, cdip, "!Devi is onlining\n"));
1864*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
1865*7c478bd9Sstevel@tonic-gate 			return (MDI_DEVI_ONLINING);
1866*7c478bd9Sstevel@tonic-gate 		}
1867*7c478bd9Sstevel@tonic-gate 	}
1868*7c478bd9Sstevel@tonic-gate 
1869*7c478bd9Sstevel@tonic-gate 	/*
1870*7c478bd9Sstevel@tonic-gate 	 * Cache in the client list head.  If head of the list is NULL
1871*7c478bd9Sstevel@tonic-gate 	 * return MDI_NOPATH
1872*7c478bd9Sstevel@tonic-gate 	 */
1873*7c478bd9Sstevel@tonic-gate 	head = ct->ct_path_head;
1874*7c478bd9Sstevel@tonic-gate 	if (head == NULL) {
1875*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
1876*7c478bd9Sstevel@tonic-gate 		return (MDI_NOPATH);
1877*7c478bd9Sstevel@tonic-gate 	}
1878*7c478bd9Sstevel@tonic-gate 
1879*7c478bd9Sstevel@tonic-gate 	/*
1880*7c478bd9Sstevel@tonic-gate 	 * for non default behavior, bypass current
1881*7c478bd9Sstevel@tonic-gate 	 * load balancing policy and always use LOAD_BALANCE_RR
1882*7c478bd9Sstevel@tonic-gate 	 * except that the start point will be adjusted based
1883*7c478bd9Sstevel@tonic-gate 	 * on the provided start_pip
1884*7c478bd9Sstevel@tonic-gate 	 */
1885*7c478bd9Sstevel@tonic-gate 	lbp = sb ? ct->ct_lb : LOAD_BALANCE_RR;
1886*7c478bd9Sstevel@tonic-gate 
1887*7c478bd9Sstevel@tonic-gate 	switch (lbp) {
1888*7c478bd9Sstevel@tonic-gate 	case LOAD_BALANCE_NONE:
1889*7c478bd9Sstevel@tonic-gate 		/*
1890*7c478bd9Sstevel@tonic-gate 		 * Load balancing is None  or Alternate path mode
1891*7c478bd9Sstevel@tonic-gate 		 * Start looking for a online mdi_pathinfo node starting from
1892*7c478bd9Sstevel@tonic-gate 		 * last known selected path
1893*7c478bd9Sstevel@tonic-gate 		 */
1894*7c478bd9Sstevel@tonic-gate 		preferred = 1;
1895*7c478bd9Sstevel@tonic-gate 		pip = (mdi_pathinfo_t *)ct->ct_path_last;
1896*7c478bd9Sstevel@tonic-gate 		if (pip == NULL) {
1897*7c478bd9Sstevel@tonic-gate 			pip = head;
1898*7c478bd9Sstevel@tonic-gate 		}
1899*7c478bd9Sstevel@tonic-gate 		start = pip;
1900*7c478bd9Sstevel@tonic-gate 		do {
1901*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
1902*7c478bd9Sstevel@tonic-gate 			/*
1903*7c478bd9Sstevel@tonic-gate 			 * No need to explicitly check if the path is disabled.
1904*7c478bd9Sstevel@tonic-gate 			 * Since we are checking for state == ONLINE and the
1905*7c478bd9Sstevel@tonic-gate 			 * same veriable is used for DISABLE/ENABLE information.
1906*7c478bd9Sstevel@tonic-gate 			 */
1907*7c478bd9Sstevel@tonic-gate 			if (MDI_PI(pip)->pi_state  ==
1908*7c478bd9Sstevel@tonic-gate 				MDI_PATHINFO_STATE_ONLINE &&
1909*7c478bd9Sstevel@tonic-gate 				preferred == MDI_PI(pip)->pi_preferred) {
1910*7c478bd9Sstevel@tonic-gate 				/*
1911*7c478bd9Sstevel@tonic-gate 				 * Return the path in hold state. Caller should
1912*7c478bd9Sstevel@tonic-gate 				 * release the lock by calling mdi_rele_path()
1913*7c478bd9Sstevel@tonic-gate 				 */
1914*7c478bd9Sstevel@tonic-gate 				MDI_PI_HOLD(pip);
1915*7c478bd9Sstevel@tonic-gate 				MDI_PI_UNLOCK(pip);
1916*7c478bd9Sstevel@tonic-gate 				ct->ct_path_last = pip;
1917*7c478bd9Sstevel@tonic-gate 				*ret_pip = pip;
1918*7c478bd9Sstevel@tonic-gate 				MDI_CLIENT_UNLOCK(ct);
1919*7c478bd9Sstevel@tonic-gate 				return (MDI_SUCCESS);
1920*7c478bd9Sstevel@tonic-gate 			}
1921*7c478bd9Sstevel@tonic-gate 
1922*7c478bd9Sstevel@tonic-gate 			/*
1923*7c478bd9Sstevel@tonic-gate 			 * Path is busy.
1924*7c478bd9Sstevel@tonic-gate 			 */
1925*7c478bd9Sstevel@tonic-gate 			if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) ||
1926*7c478bd9Sstevel@tonic-gate 			    MDI_PI_IS_TRANSIENT(pip))
1927*7c478bd9Sstevel@tonic-gate 				retry = 1;
1928*7c478bd9Sstevel@tonic-gate 			/*
1929*7c478bd9Sstevel@tonic-gate 			 * Keep looking for a next available online path
1930*7c478bd9Sstevel@tonic-gate 			 */
1931*7c478bd9Sstevel@tonic-gate 			next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
1932*7c478bd9Sstevel@tonic-gate 			if (next == NULL) {
1933*7c478bd9Sstevel@tonic-gate 				next = head;
1934*7c478bd9Sstevel@tonic-gate 			}
1935*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
1936*7c478bd9Sstevel@tonic-gate 			pip = next;
1937*7c478bd9Sstevel@tonic-gate 			if (start == pip && preferred) {
1938*7c478bd9Sstevel@tonic-gate 				preferred = 0;
1939*7c478bd9Sstevel@tonic-gate 			} else if (start == pip && !preferred) {
1940*7c478bd9Sstevel@tonic-gate 				cont = 0;
1941*7c478bd9Sstevel@tonic-gate 			}
1942*7c478bd9Sstevel@tonic-gate 		} while (cont);
1943*7c478bd9Sstevel@tonic-gate 		break;
1944*7c478bd9Sstevel@tonic-gate 
1945*7c478bd9Sstevel@tonic-gate 	case LOAD_BALANCE_LBA:
1946*7c478bd9Sstevel@tonic-gate 		/*
1947*7c478bd9Sstevel@tonic-gate 		 * Make sure we are looking
1948*7c478bd9Sstevel@tonic-gate 		 * for an online path. Otherwise, if it is for a STANDBY
1949*7c478bd9Sstevel@tonic-gate 		 * path request, it will go through and fetch an ONLINE
1950*7c478bd9Sstevel@tonic-gate 		 * path which is not desirable.
1951*7c478bd9Sstevel@tonic-gate 		 */
1952*7c478bd9Sstevel@tonic-gate 		if ((ct->ct_lb_args != NULL) &&
1953*7c478bd9Sstevel@tonic-gate 			    (ct->ct_lb_args->region_size) && bp &&
1954*7c478bd9Sstevel@tonic-gate 				(sb || (flags == MDI_SELECT_ONLINE_PATH))) {
1955*7c478bd9Sstevel@tonic-gate 			if (i_mdi_lba_lb(ct, ret_pip, bp)
1956*7c478bd9Sstevel@tonic-gate 				    == MDI_SUCCESS) {
1957*7c478bd9Sstevel@tonic-gate 				MDI_CLIENT_UNLOCK(ct);
1958*7c478bd9Sstevel@tonic-gate 				return (MDI_SUCCESS);
1959*7c478bd9Sstevel@tonic-gate 			}
1960*7c478bd9Sstevel@tonic-gate 		}
1961*7c478bd9Sstevel@tonic-gate 		/*  FALLTHROUGH */
1962*7c478bd9Sstevel@tonic-gate 	case LOAD_BALANCE_RR:
1963*7c478bd9Sstevel@tonic-gate 		/*
1964*7c478bd9Sstevel@tonic-gate 		 * Load balancing is Round Robin. Start looking for a online
1965*7c478bd9Sstevel@tonic-gate 		 * mdi_pathinfo node starting from last known selected path
1966*7c478bd9Sstevel@tonic-gate 		 * as the start point.  If override flags are specified,
1967*7c478bd9Sstevel@tonic-gate 		 * process accordingly.
1968*7c478bd9Sstevel@tonic-gate 		 * If the search is already in effect(start_pip not null),
1969*7c478bd9Sstevel@tonic-gate 		 * then lets just use the same path preference to continue the
1970*7c478bd9Sstevel@tonic-gate 		 * traversal.
1971*7c478bd9Sstevel@tonic-gate 		 */
1972*7c478bd9Sstevel@tonic-gate 
1973*7c478bd9Sstevel@tonic-gate 		if (start_pip != NULL) {
1974*7c478bd9Sstevel@tonic-gate 			preferred = MDI_PI(start_pip)->pi_preferred;
1975*7c478bd9Sstevel@tonic-gate 		} else {
1976*7c478bd9Sstevel@tonic-gate 			preferred = 1;
1977*7c478bd9Sstevel@tonic-gate 		}
1978*7c478bd9Sstevel@tonic-gate 
1979*7c478bd9Sstevel@tonic-gate 		start = sb ? (mdi_pathinfo_t *)ct->ct_path_last : start_pip;
1980*7c478bd9Sstevel@tonic-gate 		if (start == NULL) {
1981*7c478bd9Sstevel@tonic-gate 			pip = head;
1982*7c478bd9Sstevel@tonic-gate 		} else {
1983*7c478bd9Sstevel@tonic-gate 			pip = (mdi_pathinfo_t *)MDI_PI(start)->pi_client_link;
1984*7c478bd9Sstevel@tonic-gate 			if (pip == NULL) {
1985*7c478bd9Sstevel@tonic-gate 				if (!sb) {
1986*7c478bd9Sstevel@tonic-gate 					if (preferred == 0) {
1987*7c478bd9Sstevel@tonic-gate 						/*
1988*7c478bd9Sstevel@tonic-gate 						 * Looks like we have completed
1989*7c478bd9Sstevel@tonic-gate 						 * the traversal as preferred
1990*7c478bd9Sstevel@tonic-gate 						 * value is 0. Time to bail out.
1991*7c478bd9Sstevel@tonic-gate 						 */
1992*7c478bd9Sstevel@tonic-gate 						*ret_pip = NULL;
1993*7c478bd9Sstevel@tonic-gate 						MDI_CLIENT_UNLOCK(ct);
1994*7c478bd9Sstevel@tonic-gate 						return (MDI_NOPATH);
1995*7c478bd9Sstevel@tonic-gate 					} else {
1996*7c478bd9Sstevel@tonic-gate 						/*
1997*7c478bd9Sstevel@tonic-gate 						 * Looks like we reached the
1998*7c478bd9Sstevel@tonic-gate 						 * end of the list. Lets enable
1999*7c478bd9Sstevel@tonic-gate 						 * traversal of non preferred
2000*7c478bd9Sstevel@tonic-gate 						 * paths.
2001*7c478bd9Sstevel@tonic-gate 						 */
2002*7c478bd9Sstevel@tonic-gate 						preferred = 0;
2003*7c478bd9Sstevel@tonic-gate 					}
2004*7c478bd9Sstevel@tonic-gate 				}
2005*7c478bd9Sstevel@tonic-gate 				pip = head;
2006*7c478bd9Sstevel@tonic-gate 			}
2007*7c478bd9Sstevel@tonic-gate 		}
2008*7c478bd9Sstevel@tonic-gate 		start = pip;
2009*7c478bd9Sstevel@tonic-gate 		do {
2010*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
2011*7c478bd9Sstevel@tonic-gate 			if (sb) {
2012*7c478bd9Sstevel@tonic-gate 				cond = ((MDI_PI(pip)->pi_state ==
2013*7c478bd9Sstevel@tonic-gate 				    MDI_PATHINFO_STATE_ONLINE &&
2014*7c478bd9Sstevel@tonic-gate 					MDI_PI(pip)->pi_preferred ==
2015*7c478bd9Sstevel@tonic-gate 						preferred) ? 1 : 0);
2016*7c478bd9Sstevel@tonic-gate 			} else {
2017*7c478bd9Sstevel@tonic-gate 				if (flags == MDI_SELECT_ONLINE_PATH) {
2018*7c478bd9Sstevel@tonic-gate 					cond = ((MDI_PI(pip)->pi_state ==
2019*7c478bd9Sstevel@tonic-gate 					    MDI_PATHINFO_STATE_ONLINE &&
2020*7c478bd9Sstevel@tonic-gate 						MDI_PI(pip)->pi_preferred ==
2021*7c478bd9Sstevel@tonic-gate 						preferred) ? 1 : 0);
2022*7c478bd9Sstevel@tonic-gate 				} else if (flags == MDI_SELECT_STANDBY_PATH) {
2023*7c478bd9Sstevel@tonic-gate 					cond = ((MDI_PI(pip)->pi_state ==
2024*7c478bd9Sstevel@tonic-gate 					    MDI_PATHINFO_STATE_STANDBY &&
2025*7c478bd9Sstevel@tonic-gate 						MDI_PI(pip)->pi_preferred ==
2026*7c478bd9Sstevel@tonic-gate 						preferred) ? 1 : 0);
2027*7c478bd9Sstevel@tonic-gate 				} else if (flags == (MDI_SELECT_ONLINE_PATH |
2028*7c478bd9Sstevel@tonic-gate 				    MDI_SELECT_STANDBY_PATH)) {
2029*7c478bd9Sstevel@tonic-gate 					cond = (((MDI_PI(pip)->pi_state ==
2030*7c478bd9Sstevel@tonic-gate 					    MDI_PATHINFO_STATE_ONLINE ||
2031*7c478bd9Sstevel@tonic-gate 					    (MDI_PI(pip)->pi_state ==
2032*7c478bd9Sstevel@tonic-gate 					    MDI_PATHINFO_STATE_STANDBY)) &&
2033*7c478bd9Sstevel@tonic-gate 						MDI_PI(pip)->pi_preferred ==
2034*7c478bd9Sstevel@tonic-gate 						preferred) ? 1 : 0);
2035*7c478bd9Sstevel@tonic-gate 				} else {
2036*7c478bd9Sstevel@tonic-gate 					cond = 0;
2037*7c478bd9Sstevel@tonic-gate 				}
2038*7c478bd9Sstevel@tonic-gate 			}
2039*7c478bd9Sstevel@tonic-gate 			/*
2040*7c478bd9Sstevel@tonic-gate 			 * No need to explicitly check if the path is disabled.
2041*7c478bd9Sstevel@tonic-gate 			 * Since we are checking for state == ONLINE and the
2042*7c478bd9Sstevel@tonic-gate 			 * same veriable is used for DISABLE/ENABLE information.
2043*7c478bd9Sstevel@tonic-gate 			 */
2044*7c478bd9Sstevel@tonic-gate 			if (cond) {
2045*7c478bd9Sstevel@tonic-gate 				/*
2046*7c478bd9Sstevel@tonic-gate 				 * Return the path in hold state. Caller should
2047*7c478bd9Sstevel@tonic-gate 				 * release the lock by calling mdi_rele_path()
2048*7c478bd9Sstevel@tonic-gate 				 */
2049*7c478bd9Sstevel@tonic-gate 				MDI_PI_HOLD(pip);
2050*7c478bd9Sstevel@tonic-gate 				MDI_PI_UNLOCK(pip);
2051*7c478bd9Sstevel@tonic-gate 				if (sb)
2052*7c478bd9Sstevel@tonic-gate 					ct->ct_path_last = pip;
2053*7c478bd9Sstevel@tonic-gate 				*ret_pip = pip;
2054*7c478bd9Sstevel@tonic-gate 				MDI_CLIENT_UNLOCK(ct);
2055*7c478bd9Sstevel@tonic-gate 				return (MDI_SUCCESS);
2056*7c478bd9Sstevel@tonic-gate 			}
2057*7c478bd9Sstevel@tonic-gate 			/*
2058*7c478bd9Sstevel@tonic-gate 			 * Path is busy.
2059*7c478bd9Sstevel@tonic-gate 			 */
2060*7c478bd9Sstevel@tonic-gate 			if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) ||
2061*7c478bd9Sstevel@tonic-gate 			    MDI_PI_IS_TRANSIENT(pip))
2062*7c478bd9Sstevel@tonic-gate 				retry = 1;
2063*7c478bd9Sstevel@tonic-gate 
2064*7c478bd9Sstevel@tonic-gate 			/*
2065*7c478bd9Sstevel@tonic-gate 			 * Keep looking for a next available online path
2066*7c478bd9Sstevel@tonic-gate 			 */
2067*7c478bd9Sstevel@tonic-gate do_again:
2068*7c478bd9Sstevel@tonic-gate 			next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
2069*7c478bd9Sstevel@tonic-gate 			if (next == NULL) {
2070*7c478bd9Sstevel@tonic-gate 				if (!sb) {
2071*7c478bd9Sstevel@tonic-gate 					if (preferred == 1) {
2072*7c478bd9Sstevel@tonic-gate 						/*
2073*7c478bd9Sstevel@tonic-gate 						 * Looks like we reached the
2074*7c478bd9Sstevel@tonic-gate 						 * end of the list. Lets enable
2075*7c478bd9Sstevel@tonic-gate 						 * traversal of non preferred
2076*7c478bd9Sstevel@tonic-gate 						 * paths.
2077*7c478bd9Sstevel@tonic-gate 						 */
2078*7c478bd9Sstevel@tonic-gate 						preferred = 0;
2079*7c478bd9Sstevel@tonic-gate 						next = head;
2080*7c478bd9Sstevel@tonic-gate 					} else {
2081*7c478bd9Sstevel@tonic-gate 						/*
2082*7c478bd9Sstevel@tonic-gate 						 * We have done both the passes
2083*7c478bd9Sstevel@tonic-gate 						 * Preferred as well as for
2084*7c478bd9Sstevel@tonic-gate 						 * Non-preferred. Bail out now.
2085*7c478bd9Sstevel@tonic-gate 						 */
2086*7c478bd9Sstevel@tonic-gate 						cont = 0;
2087*7c478bd9Sstevel@tonic-gate 					}
2088*7c478bd9Sstevel@tonic-gate 				} else {
2089*7c478bd9Sstevel@tonic-gate 					/*
2090*7c478bd9Sstevel@tonic-gate 					 * Standard behavior case.
2091*7c478bd9Sstevel@tonic-gate 					 */
2092*7c478bd9Sstevel@tonic-gate 					next = head;
2093*7c478bd9Sstevel@tonic-gate 				}
2094*7c478bd9Sstevel@tonic-gate 			}
2095*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
2096*7c478bd9Sstevel@tonic-gate 			if (cont == 0) {
2097*7c478bd9Sstevel@tonic-gate 				break;
2098*7c478bd9Sstevel@tonic-gate 			}
2099*7c478bd9Sstevel@tonic-gate 			pip = next;
2100*7c478bd9Sstevel@tonic-gate 
2101*7c478bd9Sstevel@tonic-gate 			if (!sb) {
2102*7c478bd9Sstevel@tonic-gate 				/*
2103*7c478bd9Sstevel@tonic-gate 				 * We need to handle the selection of
2104*7c478bd9Sstevel@tonic-gate 				 * non-preferred path in the following
2105*7c478bd9Sstevel@tonic-gate 				 * case:
2106*7c478bd9Sstevel@tonic-gate 				 *
2107*7c478bd9Sstevel@tonic-gate 				 * +------+   +------+   +------+   +-----+
2108*7c478bd9Sstevel@tonic-gate 				 * | A : 1| - | B : 1| - | C : 0| - |NULL |
2109*7c478bd9Sstevel@tonic-gate 				 * +------+   +------+   +------+   +-----+
2110*7c478bd9Sstevel@tonic-gate 				 *
2111*7c478bd9Sstevel@tonic-gate 				 * If we start the search with B, we need to
2112*7c478bd9Sstevel@tonic-gate 				 * skip beyond B to pick C which is non -
2113*7c478bd9Sstevel@tonic-gate 				 * preferred in the second pass. The following
2114*7c478bd9Sstevel@tonic-gate 				 * test, if true, will allow us to skip over
2115*7c478bd9Sstevel@tonic-gate 				 * the 'start'(B in the example) to select
2116*7c478bd9Sstevel@tonic-gate 				 * other non preferred elements.
2117*7c478bd9Sstevel@tonic-gate 				 */
2118*7c478bd9Sstevel@tonic-gate 				if ((start_pip != NULL) && (start_pip == pip) &&
2119*7c478bd9Sstevel@tonic-gate 				    (MDI_PI(start_pip)->pi_preferred
2120*7c478bd9Sstevel@tonic-gate 				    != preferred)) {
2121*7c478bd9Sstevel@tonic-gate 					/*
2122*7c478bd9Sstevel@tonic-gate 					 * try again after going past the start
2123*7c478bd9Sstevel@tonic-gate 					 * pip
2124*7c478bd9Sstevel@tonic-gate 					 */
2125*7c478bd9Sstevel@tonic-gate 					MDI_PI_LOCK(pip);
2126*7c478bd9Sstevel@tonic-gate 					goto do_again;
2127*7c478bd9Sstevel@tonic-gate 				}
2128*7c478bd9Sstevel@tonic-gate 			} else {
2129*7c478bd9Sstevel@tonic-gate 				/*
2130*7c478bd9Sstevel@tonic-gate 				 * Standard behavior case
2131*7c478bd9Sstevel@tonic-gate 				 */
2132*7c478bd9Sstevel@tonic-gate 				if (start == pip && preferred) {
2133*7c478bd9Sstevel@tonic-gate 					/* look for nonpreferred paths */
2134*7c478bd9Sstevel@tonic-gate 					preferred = 0;
2135*7c478bd9Sstevel@tonic-gate 				} else if (start == pip && !preferred) {
2136*7c478bd9Sstevel@tonic-gate 					/*
2137*7c478bd9Sstevel@tonic-gate 					 * Exit condition
2138*7c478bd9Sstevel@tonic-gate 					 */
2139*7c478bd9Sstevel@tonic-gate 					cont = 0;
2140*7c478bd9Sstevel@tonic-gate 				}
2141*7c478bd9Sstevel@tonic-gate 			}
2142*7c478bd9Sstevel@tonic-gate 		} while (cont);
2143*7c478bd9Sstevel@tonic-gate 		break;
2144*7c478bd9Sstevel@tonic-gate 	}
2145*7c478bd9Sstevel@tonic-gate 
2146*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
2147*7c478bd9Sstevel@tonic-gate 	if (retry == 1) {
2148*7c478bd9Sstevel@tonic-gate 		return (MDI_BUSY);
2149*7c478bd9Sstevel@tonic-gate 	} else {
2150*7c478bd9Sstevel@tonic-gate 		return (MDI_NOPATH);
2151*7c478bd9Sstevel@tonic-gate 	}
2152*7c478bd9Sstevel@tonic-gate }
2153*7c478bd9Sstevel@tonic-gate 
2154*7c478bd9Sstevel@tonic-gate /*
2155*7c478bd9Sstevel@tonic-gate  * For a client, return the next available path to any phci
2156*7c478bd9Sstevel@tonic-gate  *
2157*7c478bd9Sstevel@tonic-gate  * Note:
2158*7c478bd9Sstevel@tonic-gate  *		Caller should hold the branch's devinfo node to get a consistent
2159*7c478bd9Sstevel@tonic-gate  *		snap shot of the mdi_pathinfo nodes.
2160*7c478bd9Sstevel@tonic-gate  *
2161*7c478bd9Sstevel@tonic-gate  *		Please note that even the list is stable the mdi_pathinfo
2162*7c478bd9Sstevel@tonic-gate  *		node state and properties are volatile.  The caller should lock
2163*7c478bd9Sstevel@tonic-gate  *		and unlock the nodes by calling mdi_pi_lock() and
2164*7c478bd9Sstevel@tonic-gate  *		mdi_pi_unlock() functions to get a stable properties.
2165*7c478bd9Sstevel@tonic-gate  *
2166*7c478bd9Sstevel@tonic-gate  *		If there is a need to use the nodes beyond the hold of the
2167*7c478bd9Sstevel@tonic-gate  *		devinfo node period (For ex. I/O), then mdi_pathinfo node
2168*7c478bd9Sstevel@tonic-gate  *		need to be held against unexpected removal by calling
2169*7c478bd9Sstevel@tonic-gate  *		mdi_hold_path() and should be released by calling
2170*7c478bd9Sstevel@tonic-gate  *		mdi_rele_path() on completion.
2171*7c478bd9Sstevel@tonic-gate  */
2172*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *
2173*7c478bd9Sstevel@tonic-gate mdi_get_next_phci_path(dev_info_t *ct_dip, mdi_pathinfo_t *pip)
2174*7c478bd9Sstevel@tonic-gate {
2175*7c478bd9Sstevel@tonic-gate 	mdi_client_t *ct;
2176*7c478bd9Sstevel@tonic-gate 
2177*7c478bd9Sstevel@tonic-gate 	if (!MDI_CLIENT(ct_dip))
2178*7c478bd9Sstevel@tonic-gate 		return (NULL);
2179*7c478bd9Sstevel@tonic-gate 
2180*7c478bd9Sstevel@tonic-gate 	/*
2181*7c478bd9Sstevel@tonic-gate 	 * Walk through client link
2182*7c478bd9Sstevel@tonic-gate 	 */
2183*7c478bd9Sstevel@tonic-gate 	ct = (mdi_client_t *)DEVI(ct_dip)->devi_mdi_client;
2184*7c478bd9Sstevel@tonic-gate 	ASSERT(ct != NULL);
2185*7c478bd9Sstevel@tonic-gate 
2186*7c478bd9Sstevel@tonic-gate 	if (pip == NULL)
2187*7c478bd9Sstevel@tonic-gate 		return ((mdi_pathinfo_t *)ct->ct_path_head);
2188*7c478bd9Sstevel@tonic-gate 
2189*7c478bd9Sstevel@tonic-gate 	return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link);
2190*7c478bd9Sstevel@tonic-gate }
2191*7c478bd9Sstevel@tonic-gate 
2192*7c478bd9Sstevel@tonic-gate /*
2193*7c478bd9Sstevel@tonic-gate  * For a phci, return the next available path to any client
2194*7c478bd9Sstevel@tonic-gate  * Note: ditto mdi_get_next_phci_path()
2195*7c478bd9Sstevel@tonic-gate  */
2196*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *
2197*7c478bd9Sstevel@tonic-gate mdi_get_next_client_path(dev_info_t *ph_dip, mdi_pathinfo_t *pip)
2198*7c478bd9Sstevel@tonic-gate {
2199*7c478bd9Sstevel@tonic-gate 	mdi_phci_t *ph;
2200*7c478bd9Sstevel@tonic-gate 
2201*7c478bd9Sstevel@tonic-gate 	if (!MDI_PHCI(ph_dip))
2202*7c478bd9Sstevel@tonic-gate 		return (NULL);
2203*7c478bd9Sstevel@tonic-gate 
2204*7c478bd9Sstevel@tonic-gate 	/*
2205*7c478bd9Sstevel@tonic-gate 	 * Walk through pHCI link
2206*7c478bd9Sstevel@tonic-gate 	 */
2207*7c478bd9Sstevel@tonic-gate 	ph = (mdi_phci_t *)DEVI(ph_dip)->devi_mdi_xhci;
2208*7c478bd9Sstevel@tonic-gate 	ASSERT(ph != NULL);
2209*7c478bd9Sstevel@tonic-gate 
2210*7c478bd9Sstevel@tonic-gate 	if (pip == NULL)
2211*7c478bd9Sstevel@tonic-gate 		return ((mdi_pathinfo_t *)ph->ph_path_head);
2212*7c478bd9Sstevel@tonic-gate 
2213*7c478bd9Sstevel@tonic-gate 	return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link);
2214*7c478bd9Sstevel@tonic-gate }
2215*7c478bd9Sstevel@tonic-gate 
2216*7c478bd9Sstevel@tonic-gate /*
2217*7c478bd9Sstevel@tonic-gate  * mdi_get_nextpath():
2218*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo node walker function.  Get the next node from the
2219*7c478bd9Sstevel@tonic-gate  *		client or pHCI device list.
2220*7c478bd9Sstevel@tonic-gate  *
2221*7c478bd9Sstevel@tonic-gate  * XXX This is wrapper function for compatibility purposes only.
2222*7c478bd9Sstevel@tonic-gate  *
2223*7c478bd9Sstevel@tonic-gate  *	It doesn't work under Multi-level MPxIO, where a dip
2224*7c478bd9Sstevel@tonic-gate  *	is both client and phci (which link should next_path follow?).
2225*7c478bd9Sstevel@tonic-gate  *	Once Leadville is modified to call mdi_get_next_phci/client_path,
2226*7c478bd9Sstevel@tonic-gate  *	this interface should be removed.
2227*7c478bd9Sstevel@tonic-gate  */
2228*7c478bd9Sstevel@tonic-gate void
2229*7c478bd9Sstevel@tonic-gate mdi_get_next_path(dev_info_t *dip, mdi_pathinfo_t *pip,
2230*7c478bd9Sstevel@tonic-gate     mdi_pathinfo_t **ret_pip)
2231*7c478bd9Sstevel@tonic-gate {
2232*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT(dip)) {
2233*7c478bd9Sstevel@tonic-gate 		*ret_pip = mdi_get_next_phci_path(dip, pip);
2234*7c478bd9Sstevel@tonic-gate 	} else if (MDI_PHCI(dip)) {
2235*7c478bd9Sstevel@tonic-gate 		*ret_pip = mdi_get_next_client_path(dip, pip);
2236*7c478bd9Sstevel@tonic-gate 	} else {
2237*7c478bd9Sstevel@tonic-gate 		*ret_pip = NULL;
2238*7c478bd9Sstevel@tonic-gate 	}
2239*7c478bd9Sstevel@tonic-gate }
2240*7c478bd9Sstevel@tonic-gate 
2241*7c478bd9Sstevel@tonic-gate /*
2242*7c478bd9Sstevel@tonic-gate  * mdi_hold_path():
2243*7c478bd9Sstevel@tonic-gate  *		Hold the mdi_pathinfo node against unwanted unexpected free.
2244*7c478bd9Sstevel@tonic-gate  * Return Values:
2245*7c478bd9Sstevel@tonic-gate  *		None
2246*7c478bd9Sstevel@tonic-gate  */
2247*7c478bd9Sstevel@tonic-gate void
2248*7c478bd9Sstevel@tonic-gate mdi_hold_path(mdi_pathinfo_t *pip)
2249*7c478bd9Sstevel@tonic-gate {
2250*7c478bd9Sstevel@tonic-gate 	if (pip) {
2251*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
2252*7c478bd9Sstevel@tonic-gate 		MDI_PI_HOLD(pip);
2253*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
2254*7c478bd9Sstevel@tonic-gate 	}
2255*7c478bd9Sstevel@tonic-gate }
2256*7c478bd9Sstevel@tonic-gate 
2257*7c478bd9Sstevel@tonic-gate 
2258*7c478bd9Sstevel@tonic-gate /*
2259*7c478bd9Sstevel@tonic-gate  * mdi_rele_path():
2260*7c478bd9Sstevel@tonic-gate  *		Release the mdi_pathinfo node which was selected
2261*7c478bd9Sstevel@tonic-gate  *		through mdi_select_path() mechanism or manually held by
2262*7c478bd9Sstevel@tonic-gate  *		calling mdi_hold_path().
2263*7c478bd9Sstevel@tonic-gate  * Return Values:
2264*7c478bd9Sstevel@tonic-gate  *		None
2265*7c478bd9Sstevel@tonic-gate  */
2266*7c478bd9Sstevel@tonic-gate void
2267*7c478bd9Sstevel@tonic-gate mdi_rele_path(mdi_pathinfo_t *pip)
2268*7c478bd9Sstevel@tonic-gate {
2269*7c478bd9Sstevel@tonic-gate 	if (pip) {
2270*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
2271*7c478bd9Sstevel@tonic-gate 		MDI_PI_RELE(pip);
2272*7c478bd9Sstevel@tonic-gate 		if (MDI_PI(pip)->pi_ref_cnt == 0) {
2273*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&MDI_PI(pip)->pi_ref_cv);
2274*7c478bd9Sstevel@tonic-gate 		}
2275*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
2276*7c478bd9Sstevel@tonic-gate 	}
2277*7c478bd9Sstevel@tonic-gate }
2278*7c478bd9Sstevel@tonic-gate 
2279*7c478bd9Sstevel@tonic-gate 
2280*7c478bd9Sstevel@tonic-gate /*
2281*7c478bd9Sstevel@tonic-gate  * mdi_pi_lock():
2282*7c478bd9Sstevel@tonic-gate  * 		Lock the mdi_pathinfo node.
2283*7c478bd9Sstevel@tonic-gate  * Note:
2284*7c478bd9Sstevel@tonic-gate  *		The caller should release the lock by calling mdi_pi_unlock()
2285*7c478bd9Sstevel@tonic-gate  */
2286*7c478bd9Sstevel@tonic-gate void
2287*7c478bd9Sstevel@tonic-gate mdi_pi_lock(mdi_pathinfo_t *pip)
2288*7c478bd9Sstevel@tonic-gate {
2289*7c478bd9Sstevel@tonic-gate 	ASSERT(pip != NULL);
2290*7c478bd9Sstevel@tonic-gate 	if (pip) {
2291*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
2292*7c478bd9Sstevel@tonic-gate 	}
2293*7c478bd9Sstevel@tonic-gate }
2294*7c478bd9Sstevel@tonic-gate 
2295*7c478bd9Sstevel@tonic-gate 
2296*7c478bd9Sstevel@tonic-gate /*
2297*7c478bd9Sstevel@tonic-gate  * mdi_pi_unlock():
2298*7c478bd9Sstevel@tonic-gate  * 		Unlock the mdi_pathinfo node.
2299*7c478bd9Sstevel@tonic-gate  * Note:
2300*7c478bd9Sstevel@tonic-gate  *		The mdi_pathinfo node should have been locked with mdi_pi_lock()
2301*7c478bd9Sstevel@tonic-gate  */
2302*7c478bd9Sstevel@tonic-gate void
2303*7c478bd9Sstevel@tonic-gate mdi_pi_unlock(mdi_pathinfo_t *pip)
2304*7c478bd9Sstevel@tonic-gate {
2305*7c478bd9Sstevel@tonic-gate 	ASSERT(pip != NULL);
2306*7c478bd9Sstevel@tonic-gate 	if (pip) {
2307*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
2308*7c478bd9Sstevel@tonic-gate 	}
2309*7c478bd9Sstevel@tonic-gate }
2310*7c478bd9Sstevel@tonic-gate 
2311*7c478bd9Sstevel@tonic-gate /*
2312*7c478bd9Sstevel@tonic-gate  * mdi_pi_find():
2313*7c478bd9Sstevel@tonic-gate  *		Search the list of mdi_pathinfo nodes attached to the
2314*7c478bd9Sstevel@tonic-gate  *		pHCI/Client device node whose path address matches "paddr".
2315*7c478bd9Sstevel@tonic-gate  *		Returns a pointer to the mdi_pathinfo node if a matching node is
2316*7c478bd9Sstevel@tonic-gate  *		found.
2317*7c478bd9Sstevel@tonic-gate  * Return Values:
2318*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo node handle
2319*7c478bd9Sstevel@tonic-gate  *		NULL
2320*7c478bd9Sstevel@tonic-gate  * Notes:
2321*7c478bd9Sstevel@tonic-gate  *		Caller need not hold any locks to call this function.
2322*7c478bd9Sstevel@tonic-gate  */
2323*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *
2324*7c478bd9Sstevel@tonic-gate mdi_pi_find(dev_info_t *pdip, char *caddr, char *paddr)
2325*7c478bd9Sstevel@tonic-gate {
2326*7c478bd9Sstevel@tonic-gate 	mdi_phci_t		*ph;
2327*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t		*vh;
2328*7c478bd9Sstevel@tonic-gate 	mdi_client_t		*ct;
2329*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t		*pip = NULL;
2330*7c478bd9Sstevel@tonic-gate 
2331*7c478bd9Sstevel@tonic-gate 	if ((pdip == NULL) || (paddr == NULL)) {
2332*7c478bd9Sstevel@tonic-gate 		return (NULL);
2333*7c478bd9Sstevel@tonic-gate 	}
2334*7c478bd9Sstevel@tonic-gate 	ph = i_devi_get_phci(pdip);
2335*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
2336*7c478bd9Sstevel@tonic-gate 		/*
2337*7c478bd9Sstevel@tonic-gate 		 * Invalid pHCI device, Nothing more to do.
2338*7c478bd9Sstevel@tonic-gate 		 */
2339*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_WARN, NULL,
2340*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_find: invalid phci"));
2341*7c478bd9Sstevel@tonic-gate 		return (NULL);
2342*7c478bd9Sstevel@tonic-gate 	}
2343*7c478bd9Sstevel@tonic-gate 
2344*7c478bd9Sstevel@tonic-gate 	vh = ph->ph_vhci;
2345*7c478bd9Sstevel@tonic-gate 	if (vh == NULL) {
2346*7c478bd9Sstevel@tonic-gate 		/*
2347*7c478bd9Sstevel@tonic-gate 		 * Invalid vHCI device, Nothing more to do.
2348*7c478bd9Sstevel@tonic-gate 		 */
2349*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_WARN, NULL,
2350*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_find: invalid phci"));
2351*7c478bd9Sstevel@tonic-gate 		return (NULL);
2352*7c478bd9Sstevel@tonic-gate 	}
2353*7c478bd9Sstevel@tonic-gate 
2354*7c478bd9Sstevel@tonic-gate 	/*
2355*7c478bd9Sstevel@tonic-gate 	 * Look for client device identified by caddr (guid)
2356*7c478bd9Sstevel@tonic-gate 	 */
2357*7c478bd9Sstevel@tonic-gate 	if (caddr == NULL) {
2358*7c478bd9Sstevel@tonic-gate 		/*
2359*7c478bd9Sstevel@tonic-gate 		 * Find a mdi_pathinfo node under pHCI list for a matching
2360*7c478bd9Sstevel@tonic-gate 		 * unit address.
2361*7c478bd9Sstevel@tonic-gate 		 */
2362*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph->ph_mutex);
2363*7c478bd9Sstevel@tonic-gate 		pip = (mdi_pathinfo_t *)ph->ph_path_head;
2364*7c478bd9Sstevel@tonic-gate 
2365*7c478bd9Sstevel@tonic-gate 		while (pip != NULL) {
2366*7c478bd9Sstevel@tonic-gate 			if (strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) {
2367*7c478bd9Sstevel@tonic-gate 				break;
2368*7c478bd9Sstevel@tonic-gate 			}
2369*7c478bd9Sstevel@tonic-gate 			pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
2370*7c478bd9Sstevel@tonic-gate 		}
2371*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph->ph_mutex);
2372*7c478bd9Sstevel@tonic-gate 		return (pip);
2373*7c478bd9Sstevel@tonic-gate 	}
2374*7c478bd9Sstevel@tonic-gate 
2375*7c478bd9Sstevel@tonic-gate 	/*
2376*7c478bd9Sstevel@tonic-gate 	 * Find the client device corresponding to 'caddr'
2377*7c478bd9Sstevel@tonic-gate 	 */
2378*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
2379*7c478bd9Sstevel@tonic-gate 	ct = i_mdi_client_find(vh, caddr);
2380*7c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
2381*7c478bd9Sstevel@tonic-gate 		/*
2382*7c478bd9Sstevel@tonic-gate 		 * Client not found, Obviously mdi_pathinfo node has not been
2383*7c478bd9Sstevel@tonic-gate 		 * created yet.
2384*7c478bd9Sstevel@tonic-gate 		 */
2385*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mdi_mutex);
2386*7c478bd9Sstevel@tonic-gate 		return (pip);
2387*7c478bd9Sstevel@tonic-gate 	}
2388*7c478bd9Sstevel@tonic-gate 
2389*7c478bd9Sstevel@tonic-gate 	/*
2390*7c478bd9Sstevel@tonic-gate 	 * Hold the client lock and look for a mdi_pathinfo node with matching
2391*7c478bd9Sstevel@tonic-gate 	 * pHCI and paddr
2392*7c478bd9Sstevel@tonic-gate 	 */
2393*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
2394*7c478bd9Sstevel@tonic-gate 
2395*7c478bd9Sstevel@tonic-gate 	/*
2396*7c478bd9Sstevel@tonic-gate 	 * Release the global mutex as it is no more needed. Note: We always
2397*7c478bd9Sstevel@tonic-gate 	 * respect the locking order while acquiring.
2398*7c478bd9Sstevel@tonic-gate 	 */
2399*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
2400*7c478bd9Sstevel@tonic-gate 
2401*7c478bd9Sstevel@tonic-gate 	pip = (mdi_pathinfo_t *)ct->ct_path_head;
2402*7c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
2403*7c478bd9Sstevel@tonic-gate 		/*
2404*7c478bd9Sstevel@tonic-gate 		 * Compare the unit address
2405*7c478bd9Sstevel@tonic-gate 		 */
2406*7c478bd9Sstevel@tonic-gate 		if ((MDI_PI(pip)->pi_phci == ph) &&
2407*7c478bd9Sstevel@tonic-gate 		    strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) {
2408*7c478bd9Sstevel@tonic-gate 			break;
2409*7c478bd9Sstevel@tonic-gate 		}
2410*7c478bd9Sstevel@tonic-gate 		pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
2411*7c478bd9Sstevel@tonic-gate 	}
2412*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
2413*7c478bd9Sstevel@tonic-gate 	return (pip);
2414*7c478bd9Sstevel@tonic-gate }
2415*7c478bd9Sstevel@tonic-gate 
2416*7c478bd9Sstevel@tonic-gate /*
2417*7c478bd9Sstevel@tonic-gate  * mdi_pi_alloc():
2418*7c478bd9Sstevel@tonic-gate  *		Allocate and initialize a new instance of a mdi_pathinfo node.
2419*7c478bd9Sstevel@tonic-gate  *		The mdi_pathinfo node returned by this function identifies a
2420*7c478bd9Sstevel@tonic-gate  *		unique device path is capable of having properties attached
2421*7c478bd9Sstevel@tonic-gate  *		and passed to mdi_pi_online() to fully attach and online the
2422*7c478bd9Sstevel@tonic-gate  *		path and client device node.
2423*7c478bd9Sstevel@tonic-gate  *		The mdi_pathinfo node returned by this function must be
2424*7c478bd9Sstevel@tonic-gate  *		destroyed using mdi_pi_free() if the path is no longer
2425*7c478bd9Sstevel@tonic-gate  *		operational or if the caller fails to attach a client device
2426*7c478bd9Sstevel@tonic-gate  *		node when calling mdi_pi_online(). The framework will not free
2427*7c478bd9Sstevel@tonic-gate  *		the resources allocated.
2428*7c478bd9Sstevel@tonic-gate  *		This function can be called from both interrupt and kernel
2429*7c478bd9Sstevel@tonic-gate  *		contexts.  DDI_NOSLEEP flag should be used while calling
2430*7c478bd9Sstevel@tonic-gate  *		from interrupt contexts.
2431*7c478bd9Sstevel@tonic-gate  * Return Values:
2432*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
2433*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
2434*7c478bd9Sstevel@tonic-gate  *		MDI_NOMEM
2435*7c478bd9Sstevel@tonic-gate  */
2436*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2437*7c478bd9Sstevel@tonic-gate int
2438*7c478bd9Sstevel@tonic-gate mdi_pi_alloc_compatible(dev_info_t *pdip, char *cname, char *caddr, char *paddr,
2439*7c478bd9Sstevel@tonic-gate     char **compatible, int ncompatible, int flags, mdi_pathinfo_t **ret_pip)
2440*7c478bd9Sstevel@tonic-gate {
2441*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*vh;
2442*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
2443*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
2444*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*pip = NULL;
2445*7c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip;
2446*7c478bd9Sstevel@tonic-gate 	int		rv = MDI_NOMEM;
2447*7c478bd9Sstevel@tonic-gate 
2448*7c478bd9Sstevel@tonic-gate 	if (pdip == NULL || cname == NULL || caddr == NULL || paddr == NULL ||
2449*7c478bd9Sstevel@tonic-gate 	    ret_pip == NULL) {
2450*7c478bd9Sstevel@tonic-gate 		/* Nothing more to do */
2451*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
2452*7c478bd9Sstevel@tonic-gate 	}
2453*7c478bd9Sstevel@tonic-gate 
2454*7c478bd9Sstevel@tonic-gate 	*ret_pip = NULL;
2455*7c478bd9Sstevel@tonic-gate 	ph = i_devi_get_phci(pdip);
2456*7c478bd9Sstevel@tonic-gate 	ASSERT(ph != NULL);
2457*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
2458*7c478bd9Sstevel@tonic-gate 		/* Invalid pHCI device, return failure */
2459*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
2460*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_alloc: invalid pHCI=%p", pdip));
2461*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
2462*7c478bd9Sstevel@tonic-gate 	}
2463*7c478bd9Sstevel@tonic-gate 
2464*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_LOCK(ph);
2465*7c478bd9Sstevel@tonic-gate 	vh = ph->ph_vhci;
2466*7c478bd9Sstevel@tonic-gate 	if (vh == NULL) {
2467*7c478bd9Sstevel@tonic-gate 		/* Invalid vHCI device, return failure */
2468*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
2469*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_alloc: invalid pHCI=%p", pdip));
2470*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_UNLOCK(ph);
2471*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
2472*7c478bd9Sstevel@tonic-gate 	}
2473*7c478bd9Sstevel@tonic-gate 
2474*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI_IS_READY(ph) == 0) {
2475*7c478bd9Sstevel@tonic-gate 		/*
2476*7c478bd9Sstevel@tonic-gate 		 * Do not allow new node creation when pHCI is in
2477*7c478bd9Sstevel@tonic-gate 		 * offline/suspended states
2478*7c478bd9Sstevel@tonic-gate 		 */
2479*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
2480*7c478bd9Sstevel@tonic-gate 		    "mdi_pi_alloc: pHCI=%p is not ready", ph));
2481*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_UNLOCK(ph);
2482*7c478bd9Sstevel@tonic-gate 		return (MDI_BUSY);
2483*7c478bd9Sstevel@tonic-gate 	}
2484*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNSTABLE(ph);
2485*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNLOCK(ph);
2486*7c478bd9Sstevel@tonic-gate 
2487*7c478bd9Sstevel@tonic-gate 	/*
2488*7c478bd9Sstevel@tonic-gate 	 * Look for a client device with matching guid identified by caddr,
2489*7c478bd9Sstevel@tonic-gate 	 * If not found create one
2490*7c478bd9Sstevel@tonic-gate 	 */
2491*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
2492*7c478bd9Sstevel@tonic-gate 	ct = i_mdi_client_find(vh, caddr);
2493*7c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
2494*7c478bd9Sstevel@tonic-gate 		ct = i_mdi_client_alloc(vh, cname, caddr, flags);
2495*7c478bd9Sstevel@tonic-gate 		if (ct == NULL)
2496*7c478bd9Sstevel@tonic-gate 			goto fail;
2497*7c478bd9Sstevel@tonic-gate 	}
2498*7c478bd9Sstevel@tonic-gate 
2499*7c478bd9Sstevel@tonic-gate 	if (ct->ct_dip == NULL) {
2500*7c478bd9Sstevel@tonic-gate 		/*
2501*7c478bd9Sstevel@tonic-gate 		 * Allocate a devinfo node
2502*7c478bd9Sstevel@tonic-gate 		 */
2503*7c478bd9Sstevel@tonic-gate 		ct->ct_dip = i_mdi_devinfo_create(vh, cname, caddr,
2504*7c478bd9Sstevel@tonic-gate 		    compatible, ncompatible, flags);
2505*7c478bd9Sstevel@tonic-gate 		if (ct->ct_dip == NULL) {
2506*7c478bd9Sstevel@tonic-gate 			(void) i_mdi_client_free(vh, ct);
2507*7c478bd9Sstevel@tonic-gate 			goto fail;
2508*7c478bd9Sstevel@tonic-gate 		}
2509*7c478bd9Sstevel@tonic-gate 	}
2510*7c478bd9Sstevel@tonic-gate 	cdip = ct->ct_dip;
2511*7c478bd9Sstevel@tonic-gate 
2512*7c478bd9Sstevel@tonic-gate 	DEVI(cdip)->devi_mdi_component |= MDI_COMPONENT_CLIENT;
2513*7c478bd9Sstevel@tonic-gate 	DEVI(cdip)->devi_mdi_client = (caddr_t)ct;
2514*7c478bd9Sstevel@tonic-gate 
2515*7c478bd9Sstevel@tonic-gate 	pip = (mdi_pathinfo_t *)ct->ct_path_head;
2516*7c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
2517*7c478bd9Sstevel@tonic-gate 		/*
2518*7c478bd9Sstevel@tonic-gate 		 * Compare the unit address
2519*7c478bd9Sstevel@tonic-gate 		 */
2520*7c478bd9Sstevel@tonic-gate 		if ((MDI_PI(pip)->pi_phci == ph) &&
2521*7c478bd9Sstevel@tonic-gate 		    strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) {
2522*7c478bd9Sstevel@tonic-gate 			break;
2523*7c478bd9Sstevel@tonic-gate 		}
2524*7c478bd9Sstevel@tonic-gate 		pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
2525*7c478bd9Sstevel@tonic-gate 	}
2526*7c478bd9Sstevel@tonic-gate 
2527*7c478bd9Sstevel@tonic-gate 	if (pip == NULL) {
2528*7c478bd9Sstevel@tonic-gate 		/*
2529*7c478bd9Sstevel@tonic-gate 		 * This is a new path for this client device.  Allocate and
2530*7c478bd9Sstevel@tonic-gate 		 * initialize a new pathinfo node
2531*7c478bd9Sstevel@tonic-gate 		 */
2532*7c478bd9Sstevel@tonic-gate 		pip = i_mdi_pi_alloc(ph, paddr, ct, flags);
2533*7c478bd9Sstevel@tonic-gate 		if (pip == NULL) {
2534*7c478bd9Sstevel@tonic-gate 			(void) i_mdi_client_free(vh, ct);
2535*7c478bd9Sstevel@tonic-gate 			goto fail;
2536*7c478bd9Sstevel@tonic-gate 		}
2537*7c478bd9Sstevel@tonic-gate 	}
2538*7c478bd9Sstevel@tonic-gate 	rv = MDI_SUCCESS;
2539*7c478bd9Sstevel@tonic-gate 
2540*7c478bd9Sstevel@tonic-gate fail:
2541*7c478bd9Sstevel@tonic-gate 	/*
2542*7c478bd9Sstevel@tonic-gate 	 * Release the global mutex.
2543*7c478bd9Sstevel@tonic-gate 	 */
2544*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
2545*7c478bd9Sstevel@tonic-gate 
2546*7c478bd9Sstevel@tonic-gate 	/*
2547*7c478bd9Sstevel@tonic-gate 	 * Mark the pHCI as stable
2548*7c478bd9Sstevel@tonic-gate 	 */
2549*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_LOCK(ph);
2550*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_STABLE(ph);
2551*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNLOCK(ph);
2552*7c478bd9Sstevel@tonic-gate 	*ret_pip = pip;
2553*7c478bd9Sstevel@tonic-gate 	return (rv);
2554*7c478bd9Sstevel@tonic-gate }
2555*7c478bd9Sstevel@tonic-gate 
2556*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2557*7c478bd9Sstevel@tonic-gate int
2558*7c478bd9Sstevel@tonic-gate mdi_pi_alloc(dev_info_t *pdip, char *cname, char *caddr, char *paddr,
2559*7c478bd9Sstevel@tonic-gate     int flags, mdi_pathinfo_t **ret_pip)
2560*7c478bd9Sstevel@tonic-gate {
2561*7c478bd9Sstevel@tonic-gate 	return (mdi_pi_alloc_compatible(pdip, cname, caddr, paddr, NULL, 0,
2562*7c478bd9Sstevel@tonic-gate 	    flags, ret_pip));
2563*7c478bd9Sstevel@tonic-gate }
2564*7c478bd9Sstevel@tonic-gate 
2565*7c478bd9Sstevel@tonic-gate /*
2566*7c478bd9Sstevel@tonic-gate  * i_mdi_pi_alloc():
2567*7c478bd9Sstevel@tonic-gate  *		Allocate a mdi_pathinfo node and add to the pHCI path list
2568*7c478bd9Sstevel@tonic-gate  * Return Values:
2569*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo
2570*7c478bd9Sstevel@tonic-gate  */
2571*7c478bd9Sstevel@tonic-gate 
2572*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2573*7c478bd9Sstevel@tonic-gate static mdi_pathinfo_t *
2574*7c478bd9Sstevel@tonic-gate i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct, int flags)
2575*7c478bd9Sstevel@tonic-gate {
2576*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*pip = NULL;
2577*7c478bd9Sstevel@tonic-gate 	char		*pi_addr = NULL;
2578*7c478bd9Sstevel@tonic-gate 	nvlist_t	*pi_prop = NULL;
2579*7c478bd9Sstevel@tonic-gate 
2580*7c478bd9Sstevel@tonic-gate 	int		ct_circular;
2581*7c478bd9Sstevel@tonic-gate 	int		ph_circular;
2582*7c478bd9Sstevel@tonic-gate 
2583*7c478bd9Sstevel@tonic-gate 	pip = kmem_zalloc(sizeof (struct mdi_pathinfo),
2584*7c478bd9Sstevel@tonic-gate 	    (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
2585*7c478bd9Sstevel@tonic-gate 	if (pip == NULL)
2586*7c478bd9Sstevel@tonic-gate 		goto fail;
2587*7c478bd9Sstevel@tonic-gate 	mutex_init(&MDI_PI(pip)->pi_mutex, NULL, MUTEX_DEFAULT, NULL);
2588*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_state = MDI_PATHINFO_STATE_INIT |
2589*7c478bd9Sstevel@tonic-gate 	    MDI_PATHINFO_STATE_TRANSIENT;
2590*7c478bd9Sstevel@tonic-gate 
2591*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI_IS_USER_DISABLED(ph))
2592*7c478bd9Sstevel@tonic-gate 		MDI_PI_SET_USER_DISABLE(pip);
2593*7c478bd9Sstevel@tonic-gate 
2594*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI_IS_DRV_DISABLED_TRANSIENT(ph))
2595*7c478bd9Sstevel@tonic-gate 		MDI_PI_SET_DRV_DISABLE_TRANS(pip);
2596*7c478bd9Sstevel@tonic-gate 
2597*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI_IS_DRV_DISABLED(ph))
2598*7c478bd9Sstevel@tonic-gate 		MDI_PI_SET_DRV_DISABLE(pip);
2599*7c478bd9Sstevel@tonic-gate 
2600*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_old_state = MDI_PATHINFO_STATE_INIT;
2601*7c478bd9Sstevel@tonic-gate 	cv_init(&MDI_PI(pip)->pi_state_cv, NULL, CV_DEFAULT, NULL);
2602*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_client = ct;
2603*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_phci = ph;
2604*7c478bd9Sstevel@tonic-gate 	pi_addr =
2605*7c478bd9Sstevel@tonic-gate 	    MDI_PI(pip)->pi_addr = kmem_alloc(strlen(paddr) + 1,
2606*7c478bd9Sstevel@tonic-gate 	    (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
2607*7c478bd9Sstevel@tonic-gate 	if (pi_addr == NULL)
2608*7c478bd9Sstevel@tonic-gate 		goto fail;
2609*7c478bd9Sstevel@tonic-gate 	(void) strcpy(MDI_PI(pip)->pi_addr, paddr);
2610*7c478bd9Sstevel@tonic-gate 	(void) nvlist_alloc(&pi_prop, NV_UNIQUE_NAME,
2611*7c478bd9Sstevel@tonic-gate 	    (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
2612*7c478bd9Sstevel@tonic-gate 	if (pi_prop == NULL)
2613*7c478bd9Sstevel@tonic-gate 		goto fail;
2614*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_prop = pi_prop;
2615*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_pprivate = NULL;
2616*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_cprivate = NULL;
2617*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_vprivate = NULL;
2618*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_client_link = NULL;
2619*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_phci_link = NULL;
2620*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_ref_cnt = 0;
2621*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_kstats = NULL;
2622*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_preferred = 1;
2623*7c478bd9Sstevel@tonic-gate 	cv_init(&MDI_PI(pip)->pi_ref_cv, NULL, CV_DEFAULT, NULL);
2624*7c478bd9Sstevel@tonic-gate 
2625*7c478bd9Sstevel@tonic-gate 	/*
2626*7c478bd9Sstevel@tonic-gate 	 * Lock both dev_info nodes against changes in parallel.
2627*7c478bd9Sstevel@tonic-gate 	 */
2628*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(ct->ct_dip, &ct_circular);
2629*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(ph->ph_dip, &ph_circular);
2630*7c478bd9Sstevel@tonic-gate 
2631*7c478bd9Sstevel@tonic-gate 	i_mdi_phci_add_path(ph, pip);
2632*7c478bd9Sstevel@tonic-gate 	i_mdi_client_add_path(ct, pip);
2633*7c478bd9Sstevel@tonic-gate 
2634*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(ph->ph_dip, ph_circular);
2635*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(ct->ct_dip, ct_circular);
2636*7c478bd9Sstevel@tonic-gate 
2637*7c478bd9Sstevel@tonic-gate 	return (pip);
2638*7c478bd9Sstevel@tonic-gate 
2639*7c478bd9Sstevel@tonic-gate fail:
2640*7c478bd9Sstevel@tonic-gate 	if (pi_prop)
2641*7c478bd9Sstevel@tonic-gate 		(void) nvlist_free(pi_prop);
2642*7c478bd9Sstevel@tonic-gate 	if (pi_addr)
2643*7c478bd9Sstevel@tonic-gate 		kmem_free(pi_addr, strlen(paddr) + 1);
2644*7c478bd9Sstevel@tonic-gate 	kmem_free(pip, sizeof (struct mdi_pathinfo));
2645*7c478bd9Sstevel@tonic-gate 	return (NULL);
2646*7c478bd9Sstevel@tonic-gate }
2647*7c478bd9Sstevel@tonic-gate 
2648*7c478bd9Sstevel@tonic-gate /*
2649*7c478bd9Sstevel@tonic-gate  * i_mdi_phci_add_path():
2650*7c478bd9Sstevel@tonic-gate  * 		Add a mdi_pathinfo node to pHCI list.
2651*7c478bd9Sstevel@tonic-gate  * Notes:
2652*7c478bd9Sstevel@tonic-gate  *		Caller should per-pHCI mutex
2653*7c478bd9Sstevel@tonic-gate  */
2654*7c478bd9Sstevel@tonic-gate 
2655*7c478bd9Sstevel@tonic-gate static void
2656*7c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(mdi_phci_t *ph, mdi_pathinfo_t *pip)
2657*7c478bd9Sstevel@tonic-gate {
2658*7c478bd9Sstevel@tonic-gate 	ASSERT(DEVI_BUSY_OWNED(ph->ph_dip));
2659*7c478bd9Sstevel@tonic-gate 
2660*7c478bd9Sstevel@tonic-gate 	if (ph->ph_path_head == NULL) {
2661*7c478bd9Sstevel@tonic-gate 		ph->ph_path_head = pip;
2662*7c478bd9Sstevel@tonic-gate 	} else {
2663*7c478bd9Sstevel@tonic-gate 		MDI_PI(ph->ph_path_tail)->pi_phci_link = MDI_PI(pip);
2664*7c478bd9Sstevel@tonic-gate 	}
2665*7c478bd9Sstevel@tonic-gate 	ph->ph_path_tail = pip;
2666*7c478bd9Sstevel@tonic-gate 	ph->ph_path_count++;
2667*7c478bd9Sstevel@tonic-gate }
2668*7c478bd9Sstevel@tonic-gate 
2669*7c478bd9Sstevel@tonic-gate /*
2670*7c478bd9Sstevel@tonic-gate  * i_mdi_client_add_path():
2671*7c478bd9Sstevel@tonic-gate  *		Add mdi_pathinfo node to client list
2672*7c478bd9Sstevel@tonic-gate  */
2673*7c478bd9Sstevel@tonic-gate 
2674*7c478bd9Sstevel@tonic-gate static void
2675*7c478bd9Sstevel@tonic-gate i_mdi_client_add_path(mdi_client_t *ct, mdi_pathinfo_t *pip)
2676*7c478bd9Sstevel@tonic-gate {
2677*7c478bd9Sstevel@tonic-gate 	ASSERT(DEVI_BUSY_OWNED(ct->ct_dip));
2678*7c478bd9Sstevel@tonic-gate 
2679*7c478bd9Sstevel@tonic-gate 	if (ct->ct_path_head == NULL) {
2680*7c478bd9Sstevel@tonic-gate 		ct->ct_path_head = pip;
2681*7c478bd9Sstevel@tonic-gate 	} else {
2682*7c478bd9Sstevel@tonic-gate 		MDI_PI(ct->ct_path_tail)->pi_client_link = MDI_PI(pip);
2683*7c478bd9Sstevel@tonic-gate 	}
2684*7c478bd9Sstevel@tonic-gate 	ct->ct_path_tail = pip;
2685*7c478bd9Sstevel@tonic-gate 	ct->ct_path_count++;
2686*7c478bd9Sstevel@tonic-gate }
2687*7c478bd9Sstevel@tonic-gate 
2688*7c478bd9Sstevel@tonic-gate /*
2689*7c478bd9Sstevel@tonic-gate  * mdi_pi_free():
2690*7c478bd9Sstevel@tonic-gate  *		Free the mdi_pathinfo node and also client device node if this
2691*7c478bd9Sstevel@tonic-gate  *		is the last path to the device
2692*7c478bd9Sstevel@tonic-gate  * Return Values:
2693*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
2694*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
2695*7c478bd9Sstevel@tonic-gate  *		MDI_BUSY
2696*7c478bd9Sstevel@tonic-gate  */
2697*7c478bd9Sstevel@tonic-gate 
2698*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2699*7c478bd9Sstevel@tonic-gate int
2700*7c478bd9Sstevel@tonic-gate mdi_pi_free(mdi_pathinfo_t *pip, int flags)
2701*7c478bd9Sstevel@tonic-gate {
2702*7c478bd9Sstevel@tonic-gate 	int		rv = MDI_SUCCESS;
2703*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*vh;
2704*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
2705*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
2706*7c478bd9Sstevel@tonic-gate 	int		(*f)();
2707*7c478bd9Sstevel@tonic-gate 	int		client_held = 0;
2708*7c478bd9Sstevel@tonic-gate 
2709*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
2710*7c478bd9Sstevel@tonic-gate 	ph = MDI_PI(pip)->pi_phci;
2711*7c478bd9Sstevel@tonic-gate 	ASSERT(ph != NULL);
2712*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
2713*7c478bd9Sstevel@tonic-gate 		/*
2714*7c478bd9Sstevel@tonic-gate 		 * Invalid pHCI device, return failure
2715*7c478bd9Sstevel@tonic-gate 		 */
2716*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
2717*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_free: invalid pHCI"));
2718*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
2719*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
2720*7c478bd9Sstevel@tonic-gate 	}
2721*7c478bd9Sstevel@tonic-gate 
2722*7c478bd9Sstevel@tonic-gate 	vh = ph->ph_vhci;
2723*7c478bd9Sstevel@tonic-gate 	ASSERT(vh != NULL);
2724*7c478bd9Sstevel@tonic-gate 	if (vh == NULL) {
2725*7c478bd9Sstevel@tonic-gate 		/* Invalid pHCI device, return failure */
2726*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
2727*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_free: invalid vHCI"));
2728*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
2729*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
2730*7c478bd9Sstevel@tonic-gate 	}
2731*7c478bd9Sstevel@tonic-gate 
2732*7c478bd9Sstevel@tonic-gate 	ct = MDI_PI(pip)->pi_client;
2733*7c478bd9Sstevel@tonic-gate 	ASSERT(ct != NULL);
2734*7c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
2735*7c478bd9Sstevel@tonic-gate 		/*
2736*7c478bd9Sstevel@tonic-gate 		 * Invalid Client device, return failure
2737*7c478bd9Sstevel@tonic-gate 		 */
2738*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
2739*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_free: invalid client"));
2740*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
2741*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
2742*7c478bd9Sstevel@tonic-gate 	}
2743*7c478bd9Sstevel@tonic-gate 
2744*7c478bd9Sstevel@tonic-gate 	/*
2745*7c478bd9Sstevel@tonic-gate 	 * Check to see for busy condition.  A mdi_pathinfo can only be freed
2746*7c478bd9Sstevel@tonic-gate 	 * if the node state is either offline or init and the reference count
2747*7c478bd9Sstevel@tonic-gate 	 * is zero.
2748*7c478bd9Sstevel@tonic-gate 	 */
2749*7c478bd9Sstevel@tonic-gate 	if (!(MDI_PI_IS_OFFLINE(pip) || MDI_PI_IS_INIT(pip) ||
2750*7c478bd9Sstevel@tonic-gate 	    MDI_PI_IS_INITING(pip))) {
2751*7c478bd9Sstevel@tonic-gate 		/*
2752*7c478bd9Sstevel@tonic-gate 		 * Node is busy
2753*7c478bd9Sstevel@tonic-gate 		 */
2754*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
2755*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_free: pathinfo node is busy pip=%p", pip));
2756*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
2757*7c478bd9Sstevel@tonic-gate 		return (MDI_BUSY);
2758*7c478bd9Sstevel@tonic-gate 	}
2759*7c478bd9Sstevel@tonic-gate 
2760*7c478bd9Sstevel@tonic-gate 	while (MDI_PI(pip)->pi_ref_cnt != 0) {
2761*7c478bd9Sstevel@tonic-gate 		/*
2762*7c478bd9Sstevel@tonic-gate 		 * Give a chance for pending I/Os to complete.
2763*7c478bd9Sstevel@tonic-gate 		 */
2764*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, "!i_mdi_pi_free: "
2765*7c478bd9Sstevel@tonic-gate 		    "%d cmds still pending on path: %p\n",
2766*7c478bd9Sstevel@tonic-gate 		    MDI_PI(pip)->pi_ref_cnt, pip));
2767*7c478bd9Sstevel@tonic-gate 		if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv,
2768*7c478bd9Sstevel@tonic-gate 		    &MDI_PI(pip)->pi_mutex,
2769*7c478bd9Sstevel@tonic-gate 		    ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) {
2770*7c478bd9Sstevel@tonic-gate 			/*
2771*7c478bd9Sstevel@tonic-gate 			 * The timeout time reached without ref_cnt being zero
2772*7c478bd9Sstevel@tonic-gate 			 * being signaled.
2773*7c478bd9Sstevel@tonic-gate 			 */
2774*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip,
2775*7c478bd9Sstevel@tonic-gate 			    "!i_mdi_pi_free: "
2776*7c478bd9Sstevel@tonic-gate 			    "Timeout reached on path %p without the cond\n",
2777*7c478bd9Sstevel@tonic-gate 			    pip));
2778*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip,
2779*7c478bd9Sstevel@tonic-gate 			    "!i_mdi_pi_free: "
2780*7c478bd9Sstevel@tonic-gate 			    "%d cmds still pending on path: %p\n",
2781*7c478bd9Sstevel@tonic-gate 			    MDI_PI(pip)->pi_ref_cnt, pip));
2782*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
2783*7c478bd9Sstevel@tonic-gate 			return (MDI_BUSY);
2784*7c478bd9Sstevel@tonic-gate 		}
2785*7c478bd9Sstevel@tonic-gate 	}
2786*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_pm_held) {
2787*7c478bd9Sstevel@tonic-gate 		client_held = 1;
2788*7c478bd9Sstevel@tonic-gate 	}
2789*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
2790*7c478bd9Sstevel@tonic-gate 
2791*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
2792*7c478bd9Sstevel@tonic-gate 
2793*7c478bd9Sstevel@tonic-gate 	/* Prevent further failovers till mdi_mutex is held */
2794*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_SET_PATH_FREE_IN_PROGRESS(ct);
2795*7c478bd9Sstevel@tonic-gate 
2796*7c478bd9Sstevel@tonic-gate 	/*
2797*7c478bd9Sstevel@tonic-gate 	 * Wait till failover is complete before removing this node.
2798*7c478bd9Sstevel@tonic-gate 	 */
2799*7c478bd9Sstevel@tonic-gate 	while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct))
2800*7c478bd9Sstevel@tonic-gate 		cv_wait(&ct->ct_failover_cv, &ct->ct_mutex);
2801*7c478bd9Sstevel@tonic-gate 
2802*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
2803*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
2804*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
2805*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_CLEAR_PATH_FREE_IN_PROGRESS(ct);
2806*7c478bd9Sstevel@tonic-gate 
2807*7c478bd9Sstevel@tonic-gate 	if (!MDI_PI_IS_INITING(pip)) {
2808*7c478bd9Sstevel@tonic-gate 		f = vh->vh_ops->vo_pi_uninit;
2809*7c478bd9Sstevel@tonic-gate 		if (f != NULL) {
2810*7c478bd9Sstevel@tonic-gate 			rv = (*f)(vh->vh_dip, pip, 0);
2811*7c478bd9Sstevel@tonic-gate 		}
2812*7c478bd9Sstevel@tonic-gate 	}
2813*7c478bd9Sstevel@tonic-gate 	/*
2814*7c478bd9Sstevel@tonic-gate 	 * If vo_pi_uninit() completed successfully.
2815*7c478bd9Sstevel@tonic-gate 	 */
2816*7c478bd9Sstevel@tonic-gate 	if (rv == MDI_SUCCESS) {
2817*7c478bd9Sstevel@tonic-gate 		if (client_held) {
2818*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_free "
2819*7c478bd9Sstevel@tonic-gate 			    "i_mdi_pm_rele_client\n"));
2820*7c478bd9Sstevel@tonic-gate 			i_mdi_pm_rele_client(ct, 1);
2821*7c478bd9Sstevel@tonic-gate 		}
2822*7c478bd9Sstevel@tonic-gate 		i_mdi_pi_free(ph, pip, ct);
2823*7c478bd9Sstevel@tonic-gate 		if (ct->ct_path_count == 0) {
2824*7c478bd9Sstevel@tonic-gate 			/*
2825*7c478bd9Sstevel@tonic-gate 			 * Client lost its last path.
2826*7c478bd9Sstevel@tonic-gate 			 * Clean up the client device
2827*7c478bd9Sstevel@tonic-gate 			 */
2828*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
2829*7c478bd9Sstevel@tonic-gate 			(void) i_mdi_client_free(ct->ct_vhci, ct);
2830*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mdi_mutex);
2831*7c478bd9Sstevel@tonic-gate 			return (rv);
2832*7c478bd9Sstevel@tonic-gate 		}
2833*7c478bd9Sstevel@tonic-gate 	}
2834*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
2835*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
2836*7c478bd9Sstevel@tonic-gate 	return (rv);
2837*7c478bd9Sstevel@tonic-gate }
2838*7c478bd9Sstevel@tonic-gate 
2839*7c478bd9Sstevel@tonic-gate /*
2840*7c478bd9Sstevel@tonic-gate  * i_mdi_pi_free():
2841*7c478bd9Sstevel@tonic-gate  *		Free the mdi_pathinfo node
2842*7c478bd9Sstevel@tonic-gate  */
2843*7c478bd9Sstevel@tonic-gate static void
2844*7c478bd9Sstevel@tonic-gate i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct)
2845*7c478bd9Sstevel@tonic-gate {
2846*7c478bd9Sstevel@tonic-gate 	int	ct_circular;
2847*7c478bd9Sstevel@tonic-gate 	int	ph_circular;
2848*7c478bd9Sstevel@tonic-gate 
2849*7c478bd9Sstevel@tonic-gate 	/*
2850*7c478bd9Sstevel@tonic-gate 	 * remove any per-path kstats
2851*7c478bd9Sstevel@tonic-gate 	 */
2852*7c478bd9Sstevel@tonic-gate 	i_mdi_pi_kstat_destroy(pip);
2853*7c478bd9Sstevel@tonic-gate 
2854*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(ct->ct_dip, &ct_circular);
2855*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(ph->ph_dip, &ph_circular);
2856*7c478bd9Sstevel@tonic-gate 
2857*7c478bd9Sstevel@tonic-gate 	i_mdi_client_remove_path(ct, pip);
2858*7c478bd9Sstevel@tonic-gate 	i_mdi_phci_remove_path(ph, pip);
2859*7c478bd9Sstevel@tonic-gate 
2860*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(ph->ph_dip, ph_circular);
2861*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(ct->ct_dip, ct_circular);
2862*7c478bd9Sstevel@tonic-gate 
2863*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&MDI_PI(pip)->pi_mutex);
2864*7c478bd9Sstevel@tonic-gate 	cv_destroy(&MDI_PI(pip)->pi_state_cv);
2865*7c478bd9Sstevel@tonic-gate 	cv_destroy(&MDI_PI(pip)->pi_ref_cv);
2866*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_addr) {
2867*7c478bd9Sstevel@tonic-gate 		kmem_free(MDI_PI(pip)->pi_addr,
2868*7c478bd9Sstevel@tonic-gate 		    strlen(MDI_PI(pip)->pi_addr) + 1);
2869*7c478bd9Sstevel@tonic-gate 		MDI_PI(pip)->pi_addr = NULL;
2870*7c478bd9Sstevel@tonic-gate 	}
2871*7c478bd9Sstevel@tonic-gate 
2872*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_prop) {
2873*7c478bd9Sstevel@tonic-gate 		(void) nvlist_free(MDI_PI(pip)->pi_prop);
2874*7c478bd9Sstevel@tonic-gate 		MDI_PI(pip)->pi_prop = NULL;
2875*7c478bd9Sstevel@tonic-gate 	}
2876*7c478bd9Sstevel@tonic-gate 	kmem_free(pip, sizeof (struct mdi_pathinfo));
2877*7c478bd9Sstevel@tonic-gate }
2878*7c478bd9Sstevel@tonic-gate 
2879*7c478bd9Sstevel@tonic-gate 
2880*7c478bd9Sstevel@tonic-gate /*
2881*7c478bd9Sstevel@tonic-gate  * i_mdi_phci_remove_path():
2882*7c478bd9Sstevel@tonic-gate  * 		Remove a mdi_pathinfo node from pHCI list.
2883*7c478bd9Sstevel@tonic-gate  * Notes:
2884*7c478bd9Sstevel@tonic-gate  *		Caller should hold per-pHCI mutex
2885*7c478bd9Sstevel@tonic-gate  */
2886*7c478bd9Sstevel@tonic-gate 
2887*7c478bd9Sstevel@tonic-gate static void
2888*7c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(mdi_phci_t *ph, mdi_pathinfo_t *pip)
2889*7c478bd9Sstevel@tonic-gate {
2890*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*prev = NULL;
2891*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*path = NULL;
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 	ASSERT(DEVI_BUSY_OWNED(ph->ph_dip));
2894*7c478bd9Sstevel@tonic-gate 
2895*7c478bd9Sstevel@tonic-gate 	path = ph->ph_path_head;
2896*7c478bd9Sstevel@tonic-gate 	while (path != NULL) {
2897*7c478bd9Sstevel@tonic-gate 		if (path == pip) {
2898*7c478bd9Sstevel@tonic-gate 			break;
2899*7c478bd9Sstevel@tonic-gate 		}
2900*7c478bd9Sstevel@tonic-gate 		prev = path;
2901*7c478bd9Sstevel@tonic-gate 		path = (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link;
2902*7c478bd9Sstevel@tonic-gate 	}
2903*7c478bd9Sstevel@tonic-gate 
2904*7c478bd9Sstevel@tonic-gate 	if (path) {
2905*7c478bd9Sstevel@tonic-gate 		ph->ph_path_count--;
2906*7c478bd9Sstevel@tonic-gate 		if (prev) {
2907*7c478bd9Sstevel@tonic-gate 			MDI_PI(prev)->pi_phci_link = MDI_PI(path)->pi_phci_link;
2908*7c478bd9Sstevel@tonic-gate 		} else {
2909*7c478bd9Sstevel@tonic-gate 			ph->ph_path_head =
2910*7c478bd9Sstevel@tonic-gate 			    (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link;
2911*7c478bd9Sstevel@tonic-gate 		}
2912*7c478bd9Sstevel@tonic-gate 		if (ph->ph_path_tail == path) {
2913*7c478bd9Sstevel@tonic-gate 			ph->ph_path_tail = prev;
2914*7c478bd9Sstevel@tonic-gate 		}
2915*7c478bd9Sstevel@tonic-gate 	}
2916*7c478bd9Sstevel@tonic-gate 
2917*7c478bd9Sstevel@tonic-gate 	/*
2918*7c478bd9Sstevel@tonic-gate 	 * Clear the pHCI link
2919*7c478bd9Sstevel@tonic-gate 	 */
2920*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_phci_link = NULL;
2921*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_phci = NULL;
2922*7c478bd9Sstevel@tonic-gate }
2923*7c478bd9Sstevel@tonic-gate 
2924*7c478bd9Sstevel@tonic-gate /*
2925*7c478bd9Sstevel@tonic-gate  * i_mdi_client_remove_path():
2926*7c478bd9Sstevel@tonic-gate  * 		Remove a mdi_pathinfo node from client path list.
2927*7c478bd9Sstevel@tonic-gate  */
2928*7c478bd9Sstevel@tonic-gate 
2929*7c478bd9Sstevel@tonic-gate static void
2930*7c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(mdi_client_t *ct, mdi_pathinfo_t *pip)
2931*7c478bd9Sstevel@tonic-gate {
2932*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*prev = NULL;
2933*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*path;
2934*7c478bd9Sstevel@tonic-gate 
2935*7c478bd9Sstevel@tonic-gate 	ASSERT(DEVI_BUSY_OWNED(ct->ct_dip));
2936*7c478bd9Sstevel@tonic-gate 
2937*7c478bd9Sstevel@tonic-gate 	path = ct->ct_path_head;
2938*7c478bd9Sstevel@tonic-gate 	while (path != NULL) {
2939*7c478bd9Sstevel@tonic-gate 		if (path == pip) {
2940*7c478bd9Sstevel@tonic-gate 			break;
2941*7c478bd9Sstevel@tonic-gate 		}
2942*7c478bd9Sstevel@tonic-gate 		prev = path;
2943*7c478bd9Sstevel@tonic-gate 		path = (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link;
2944*7c478bd9Sstevel@tonic-gate 	}
2945*7c478bd9Sstevel@tonic-gate 
2946*7c478bd9Sstevel@tonic-gate 	if (path) {
2947*7c478bd9Sstevel@tonic-gate 		ct->ct_path_count--;
2948*7c478bd9Sstevel@tonic-gate 		if (prev) {
2949*7c478bd9Sstevel@tonic-gate 			MDI_PI(prev)->pi_client_link =
2950*7c478bd9Sstevel@tonic-gate 			    MDI_PI(path)->pi_client_link;
2951*7c478bd9Sstevel@tonic-gate 		} else {
2952*7c478bd9Sstevel@tonic-gate 			ct->ct_path_head =
2953*7c478bd9Sstevel@tonic-gate 			    (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link;
2954*7c478bd9Sstevel@tonic-gate 		}
2955*7c478bd9Sstevel@tonic-gate 		if (ct->ct_path_tail == path) {
2956*7c478bd9Sstevel@tonic-gate 			ct->ct_path_tail = prev;
2957*7c478bd9Sstevel@tonic-gate 		}
2958*7c478bd9Sstevel@tonic-gate 		if (ct->ct_path_last == path) {
2959*7c478bd9Sstevel@tonic-gate 			ct->ct_path_last = ct->ct_path_head;
2960*7c478bd9Sstevel@tonic-gate 		}
2961*7c478bd9Sstevel@tonic-gate 	}
2962*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_client_link = NULL;
2963*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_client = NULL;
2964*7c478bd9Sstevel@tonic-gate }
2965*7c478bd9Sstevel@tonic-gate 
2966*7c478bd9Sstevel@tonic-gate /*
2967*7c478bd9Sstevel@tonic-gate  * i_mdi_pi_state_change():
2968*7c478bd9Sstevel@tonic-gate  *		online a mdi_pathinfo node
2969*7c478bd9Sstevel@tonic-gate  *
2970*7c478bd9Sstevel@tonic-gate  * Return Values:
2971*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
2972*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
2973*7c478bd9Sstevel@tonic-gate  */
2974*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2975*7c478bd9Sstevel@tonic-gate static int
2976*7c478bd9Sstevel@tonic-gate i_mdi_pi_state_change(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state, int flag)
2977*7c478bd9Sstevel@tonic-gate {
2978*7c478bd9Sstevel@tonic-gate 	int		rv = MDI_SUCCESS;
2979*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*vh;
2980*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
2981*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
2982*7c478bd9Sstevel@tonic-gate 	int		(*f)();
2983*7c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip;
2984*7c478bd9Sstevel@tonic-gate 
2985*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
2986*7c478bd9Sstevel@tonic-gate 
2987*7c478bd9Sstevel@tonic-gate 	ph = MDI_PI(pip)->pi_phci;
2988*7c478bd9Sstevel@tonic-gate 	ASSERT(ph);
2989*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
2990*7c478bd9Sstevel@tonic-gate 		/*
2991*7c478bd9Sstevel@tonic-gate 		 * Invalid pHCI device, fail the request
2992*7c478bd9Sstevel@tonic-gate 		 */
2993*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
2994*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
2995*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_state_change: invalid phci"));
2996*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
2997*7c478bd9Sstevel@tonic-gate 	}
2998*7c478bd9Sstevel@tonic-gate 
2999*7c478bd9Sstevel@tonic-gate 	vh = ph->ph_vhci;
3000*7c478bd9Sstevel@tonic-gate 	ASSERT(vh);
3001*7c478bd9Sstevel@tonic-gate 	if (vh == NULL) {
3002*7c478bd9Sstevel@tonic-gate 		/*
3003*7c478bd9Sstevel@tonic-gate 		 * Invalid vHCI device, fail the request
3004*7c478bd9Sstevel@tonic-gate 		 */
3005*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3006*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
3007*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_state_change: invalid vhci"));
3008*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
3009*7c478bd9Sstevel@tonic-gate 	}
3010*7c478bd9Sstevel@tonic-gate 
3011*7c478bd9Sstevel@tonic-gate 	ct = MDI_PI(pip)->pi_client;
3012*7c478bd9Sstevel@tonic-gate 	ASSERT(ct != NULL);
3013*7c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
3014*7c478bd9Sstevel@tonic-gate 		/*
3015*7c478bd9Sstevel@tonic-gate 		 * Invalid client device, fail the request
3016*7c478bd9Sstevel@tonic-gate 		 */
3017*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3018*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
3019*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_state_change: invalid client"));
3020*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
3021*7c478bd9Sstevel@tonic-gate 	}
3022*7c478bd9Sstevel@tonic-gate 
3023*7c478bd9Sstevel@tonic-gate 	/*
3024*7c478bd9Sstevel@tonic-gate 	 * If this path has not been initialized yet, Callback vHCI driver's
3025*7c478bd9Sstevel@tonic-gate 	 * pathinfo node initialize entry point
3026*7c478bd9Sstevel@tonic-gate 	 */
3027*7c478bd9Sstevel@tonic-gate 
3028*7c478bd9Sstevel@tonic-gate 	if (MDI_PI_IS_INITING(pip)) {
3029*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3030*7c478bd9Sstevel@tonic-gate 		f = vh->vh_ops->vo_pi_init;
3031*7c478bd9Sstevel@tonic-gate 		if (f != NULL) {
3032*7c478bd9Sstevel@tonic-gate 			rv = (*f)(vh->vh_dip, pip, 0);
3033*7c478bd9Sstevel@tonic-gate 			if (rv != MDI_SUCCESS) {
3034*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(1, (CE_WARN, vh->vh_dip,
3035*7c478bd9Sstevel@tonic-gate 				    "!vo_pi_init: failed vHCI=0x%p, pip=0x%p",
3036*7c478bd9Sstevel@tonic-gate 				    vh, pip));
3037*7c478bd9Sstevel@tonic-gate 				return (MDI_FAILURE);
3038*7c478bd9Sstevel@tonic-gate 			}
3039*7c478bd9Sstevel@tonic-gate 		}
3040*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
3041*7c478bd9Sstevel@tonic-gate 		MDI_PI_CLEAR_TRANSIENT(pip);
3042*7c478bd9Sstevel@tonic-gate 	}
3043*7c478bd9Sstevel@tonic-gate 
3044*7c478bd9Sstevel@tonic-gate 	/*
3045*7c478bd9Sstevel@tonic-gate 	 * Do not allow state transition when pHCI is in offline/suspended
3046*7c478bd9Sstevel@tonic-gate 	 * states
3047*7c478bd9Sstevel@tonic-gate 	 */
3048*7c478bd9Sstevel@tonic-gate 	i_mdi_phci_lock(ph, pip);
3049*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI_IS_READY(ph) == 0) {
3050*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, NULL,
3051*7c478bd9Sstevel@tonic-gate 		    "!mdi_pi_state_change: pHCI not ready, pHCI=%p", ph));
3052*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3053*7c478bd9Sstevel@tonic-gate 		i_mdi_phci_unlock(ph);
3054*7c478bd9Sstevel@tonic-gate 		return (MDI_BUSY);
3055*7c478bd9Sstevel@tonic-gate 	}
3056*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNSTABLE(ph);
3057*7c478bd9Sstevel@tonic-gate 	i_mdi_phci_unlock(ph);
3058*7c478bd9Sstevel@tonic-gate 
3059*7c478bd9Sstevel@tonic-gate 	/*
3060*7c478bd9Sstevel@tonic-gate 	 * Check if mdi_pathinfo state is in transient state.
3061*7c478bd9Sstevel@tonic-gate 	 * If yes, offlining is in progress and wait till transient state is
3062*7c478bd9Sstevel@tonic-gate 	 * cleared.
3063*7c478bd9Sstevel@tonic-gate 	 */
3064*7c478bd9Sstevel@tonic-gate 	if (MDI_PI_IS_TRANSIENT(pip)) {
3065*7c478bd9Sstevel@tonic-gate 		while (MDI_PI_IS_TRANSIENT(pip)) {
3066*7c478bd9Sstevel@tonic-gate 			cv_wait(&MDI_PI(pip)->pi_state_cv,
3067*7c478bd9Sstevel@tonic-gate 			    &MDI_PI(pip)->pi_mutex);
3068*7c478bd9Sstevel@tonic-gate 		}
3069*7c478bd9Sstevel@tonic-gate 	}
3070*7c478bd9Sstevel@tonic-gate 
3071*7c478bd9Sstevel@tonic-gate 	/*
3072*7c478bd9Sstevel@tonic-gate 	 * Grab the client lock in reverse order sequence and release the
3073*7c478bd9Sstevel@tonic-gate 	 * mdi_pathinfo mutex.
3074*7c478bd9Sstevel@tonic-gate 	 */
3075*7c478bd9Sstevel@tonic-gate 	i_mdi_client_lock(ct, pip);
3076*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3077*7c478bd9Sstevel@tonic-gate 
3078*7c478bd9Sstevel@tonic-gate 	/*
3079*7c478bd9Sstevel@tonic-gate 	 * Wait till failover state is cleared
3080*7c478bd9Sstevel@tonic-gate 	 */
3081*7c478bd9Sstevel@tonic-gate 	while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct))
3082*7c478bd9Sstevel@tonic-gate 		cv_wait(&ct->ct_failover_cv, &ct->ct_mutex);
3083*7c478bd9Sstevel@tonic-gate 
3084*7c478bd9Sstevel@tonic-gate 	/*
3085*7c478bd9Sstevel@tonic-gate 	 * Mark the mdi_pathinfo node state as transient
3086*7c478bd9Sstevel@tonic-gate 	 */
3087*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3088*7c478bd9Sstevel@tonic-gate 	switch (state) {
3089*7c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_ONLINE:
3090*7c478bd9Sstevel@tonic-gate 		MDI_PI_SET_ONLINING(pip);
3091*7c478bd9Sstevel@tonic-gate 		break;
3092*7c478bd9Sstevel@tonic-gate 
3093*7c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_STANDBY:
3094*7c478bd9Sstevel@tonic-gate 		MDI_PI_SET_STANDBYING(pip);
3095*7c478bd9Sstevel@tonic-gate 		break;
3096*7c478bd9Sstevel@tonic-gate 
3097*7c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_FAULT:
3098*7c478bd9Sstevel@tonic-gate 		/*
3099*7c478bd9Sstevel@tonic-gate 		 * Mark the pathinfo state as FAULTED
3100*7c478bd9Sstevel@tonic-gate 		 */
3101*7c478bd9Sstevel@tonic-gate 		MDI_PI_SET_FAULTING(pip);
3102*7c478bd9Sstevel@tonic-gate 		MDI_PI_ERRSTAT(pip, MDI_PI_HARDERR);
3103*7c478bd9Sstevel@tonic-gate 		break;
3104*7c478bd9Sstevel@tonic-gate 
3105*7c478bd9Sstevel@tonic-gate 	case MDI_PATHINFO_STATE_OFFLINE:
3106*7c478bd9Sstevel@tonic-gate 		/*
3107*7c478bd9Sstevel@tonic-gate 		 * ndi_devi_offline() cannot hold pip or ct locks.
3108*7c478bd9Sstevel@tonic-gate 		 */
3109*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3110*7c478bd9Sstevel@tonic-gate 		/*
3111*7c478bd9Sstevel@tonic-gate 		 * Do not offline if path will become last path and path
3112*7c478bd9Sstevel@tonic-gate 		 * is busy for user initiated events.
3113*7c478bd9Sstevel@tonic-gate 		 */
3114*7c478bd9Sstevel@tonic-gate 		cdip = ct->ct_dip;
3115*7c478bd9Sstevel@tonic-gate 		if ((flag & NDI_DEVI_REMOVE) &&
3116*7c478bd9Sstevel@tonic-gate 		    (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED)) {
3117*7c478bd9Sstevel@tonic-gate 			i_mdi_client_unlock(ct);
3118*7c478bd9Sstevel@tonic-gate 			rv = ndi_devi_offline(cdip, 0);
3119*7c478bd9Sstevel@tonic-gate 			if (rv != NDI_SUCCESS) {
3120*7c478bd9Sstevel@tonic-gate 				/*
3121*7c478bd9Sstevel@tonic-gate 				 * Convert to MDI error code
3122*7c478bd9Sstevel@tonic-gate 				 */
3123*7c478bd9Sstevel@tonic-gate 				switch (rv) {
3124*7c478bd9Sstevel@tonic-gate 				case NDI_BUSY:
3125*7c478bd9Sstevel@tonic-gate 					rv = MDI_BUSY;
3126*7c478bd9Sstevel@tonic-gate 					break;
3127*7c478bd9Sstevel@tonic-gate 				default:
3128*7c478bd9Sstevel@tonic-gate 					rv = MDI_FAILURE;
3129*7c478bd9Sstevel@tonic-gate 					break;
3130*7c478bd9Sstevel@tonic-gate 				}
3131*7c478bd9Sstevel@tonic-gate 				goto state_change_exit;
3132*7c478bd9Sstevel@tonic-gate 			} else {
3133*7c478bd9Sstevel@tonic-gate 				i_mdi_client_lock(ct, NULL);
3134*7c478bd9Sstevel@tonic-gate 			}
3135*7c478bd9Sstevel@tonic-gate 		}
3136*7c478bd9Sstevel@tonic-gate 		/*
3137*7c478bd9Sstevel@tonic-gate 		 * Mark the mdi_pathinfo node state as transient
3138*7c478bd9Sstevel@tonic-gate 		 */
3139*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
3140*7c478bd9Sstevel@tonic-gate 		MDI_PI_SET_OFFLINING(pip);
3141*7c478bd9Sstevel@tonic-gate 		break;
3142*7c478bd9Sstevel@tonic-gate 	}
3143*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3144*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNSTABLE(ct);
3145*7c478bd9Sstevel@tonic-gate 	i_mdi_client_unlock(ct);
3146*7c478bd9Sstevel@tonic-gate 
3147*7c478bd9Sstevel@tonic-gate 	f = vh->vh_ops->vo_pi_state_change;
3148*7c478bd9Sstevel@tonic-gate 	if (f != NULL) {
3149*7c478bd9Sstevel@tonic-gate 		rv = (*f)(vh->vh_dip, pip, state, 0, flag);
3150*7c478bd9Sstevel@tonic-gate 		if (rv == MDI_NOT_SUPPORTED) {
3151*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_SET_DEV_NOT_SUPPORTED(ct);
3152*7c478bd9Sstevel@tonic-gate 		}
3153*7c478bd9Sstevel@tonic-gate 		if (rv != MDI_SUCCESS) {
3154*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(2, (CE_WARN, vh->vh_dip,
3155*7c478bd9Sstevel@tonic-gate 			    "!vo_pi_state_change: failed rv = %x", rv));
3156*7c478bd9Sstevel@tonic-gate 		}
3157*7c478bd9Sstevel@tonic-gate 	}
3158*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
3159*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3160*7c478bd9Sstevel@tonic-gate 	if (MDI_PI_IS_TRANSIENT(pip)) {
3161*7c478bd9Sstevel@tonic-gate 		if (rv == MDI_SUCCESS) {
3162*7c478bd9Sstevel@tonic-gate 			MDI_PI_CLEAR_TRANSIENT(pip);
3163*7c478bd9Sstevel@tonic-gate 		} else {
3164*7c478bd9Sstevel@tonic-gate 			MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip);
3165*7c478bd9Sstevel@tonic-gate 		}
3166*7c478bd9Sstevel@tonic-gate 	}
3167*7c478bd9Sstevel@tonic-gate 
3168*7c478bd9Sstevel@tonic-gate 	/*
3169*7c478bd9Sstevel@tonic-gate 	 * Wake anyone waiting for this mdi_pathinfo node
3170*7c478bd9Sstevel@tonic-gate 	 */
3171*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&MDI_PI(pip)->pi_state_cv);
3172*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3173*7c478bd9Sstevel@tonic-gate 
3174*7c478bd9Sstevel@tonic-gate 	/*
3175*7c478bd9Sstevel@tonic-gate 	 * Mark the client device as stable
3176*7c478bd9Sstevel@tonic-gate 	 */
3177*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_STABLE(ct);
3178*7c478bd9Sstevel@tonic-gate 	if (rv == MDI_SUCCESS) {
3179*7c478bd9Sstevel@tonic-gate 		if (ct->ct_unstable == 0) {
3180*7c478bd9Sstevel@tonic-gate 			cdip = ct->ct_dip;
3181*7c478bd9Sstevel@tonic-gate 
3182*7c478bd9Sstevel@tonic-gate 			/*
3183*7c478bd9Sstevel@tonic-gate 			 * Onlining the mdi_pathinfo node will impact the
3184*7c478bd9Sstevel@tonic-gate 			 * client state Update the client and dev_info node
3185*7c478bd9Sstevel@tonic-gate 			 * state accordingly
3186*7c478bd9Sstevel@tonic-gate 			 */
3187*7c478bd9Sstevel@tonic-gate 			rv = NDI_SUCCESS;
3188*7c478bd9Sstevel@tonic-gate 			i_mdi_client_update_state(ct);
3189*7c478bd9Sstevel@tonic-gate 			switch (MDI_CLIENT_STATE(ct)) {
3190*7c478bd9Sstevel@tonic-gate 			case MDI_CLIENT_STATE_OPTIMAL:
3191*7c478bd9Sstevel@tonic-gate 			case MDI_CLIENT_STATE_DEGRADED:
3192*7c478bd9Sstevel@tonic-gate 				if (cdip &&
3193*7c478bd9Sstevel@tonic-gate 				    (i_ddi_node_state(cdip) < DS_READY) &&
3194*7c478bd9Sstevel@tonic-gate 				    ((state == MDI_PATHINFO_STATE_ONLINE) ||
3195*7c478bd9Sstevel@tonic-gate 				    (state == MDI_PATHINFO_STATE_STANDBY))) {
3196*7c478bd9Sstevel@tonic-gate 
3197*7c478bd9Sstevel@tonic-gate 					i_mdi_client_unlock(ct);
3198*7c478bd9Sstevel@tonic-gate 					/*
3199*7c478bd9Sstevel@tonic-gate 					 * Must do ndi_devi_online() through
3200*7c478bd9Sstevel@tonic-gate 					 * hotplug thread for deferred
3201*7c478bd9Sstevel@tonic-gate 					 * attach mechanism to work
3202*7c478bd9Sstevel@tonic-gate 					 */
3203*7c478bd9Sstevel@tonic-gate 					rv = ndi_devi_online(cdip, 0);
3204*7c478bd9Sstevel@tonic-gate 					i_mdi_client_lock(ct, NULL);
3205*7c478bd9Sstevel@tonic-gate 					if ((rv != NDI_SUCCESS) &&
3206*7c478bd9Sstevel@tonic-gate 					    (MDI_CLIENT_STATE(ct) ==
3207*7c478bd9Sstevel@tonic-gate 					    MDI_CLIENT_STATE_DEGRADED)) {
3208*7c478bd9Sstevel@tonic-gate 						/*
3209*7c478bd9Sstevel@tonic-gate 						 * ndi_devi_online failed.
3210*7c478bd9Sstevel@tonic-gate 						 * Reset client flags to
3211*7c478bd9Sstevel@tonic-gate 						 * offline.
3212*7c478bd9Sstevel@tonic-gate 						 */
3213*7c478bd9Sstevel@tonic-gate 						MDI_DEBUG(1, (CE_WARN, cdip,
3214*7c478bd9Sstevel@tonic-gate 						    "!ndi_devi_online: failed "
3215*7c478bd9Sstevel@tonic-gate 						    " Error: %x", rv));
3216*7c478bd9Sstevel@tonic-gate 						MDI_CLIENT_SET_OFFLINE(ct);
3217*7c478bd9Sstevel@tonic-gate 					}
3218*7c478bd9Sstevel@tonic-gate 					if (rv != NDI_SUCCESS) {
3219*7c478bd9Sstevel@tonic-gate 						/* Reset the path state */
3220*7c478bd9Sstevel@tonic-gate 						MDI_PI_LOCK(pip);
3221*7c478bd9Sstevel@tonic-gate 						MDI_PI(pip)->pi_state =
3222*7c478bd9Sstevel@tonic-gate 						    MDI_PI_OLD_STATE(pip);
3223*7c478bd9Sstevel@tonic-gate 						MDI_PI_UNLOCK(pip);
3224*7c478bd9Sstevel@tonic-gate 					}
3225*7c478bd9Sstevel@tonic-gate 				}
3226*7c478bd9Sstevel@tonic-gate 				break;
3227*7c478bd9Sstevel@tonic-gate 
3228*7c478bd9Sstevel@tonic-gate 			case MDI_CLIENT_STATE_FAILED:
3229*7c478bd9Sstevel@tonic-gate 				/*
3230*7c478bd9Sstevel@tonic-gate 				 * This is the last path case for
3231*7c478bd9Sstevel@tonic-gate 				 * non-user initiated events.
3232*7c478bd9Sstevel@tonic-gate 				 */
3233*7c478bd9Sstevel@tonic-gate 				if (((flag & NDI_DEVI_REMOVE) == 0) &&
3234*7c478bd9Sstevel@tonic-gate 				    cdip && (i_ddi_node_state(cdip) >=
3235*7c478bd9Sstevel@tonic-gate 				    DS_INITIALIZED)) {
3236*7c478bd9Sstevel@tonic-gate 					i_mdi_client_unlock(ct);
3237*7c478bd9Sstevel@tonic-gate 					rv = ndi_devi_offline(cdip, 0);
3238*7c478bd9Sstevel@tonic-gate 					i_mdi_client_lock(ct, NULL);
3239*7c478bd9Sstevel@tonic-gate 
3240*7c478bd9Sstevel@tonic-gate 					if (rv != NDI_SUCCESS) {
3241*7c478bd9Sstevel@tonic-gate 						/*
3242*7c478bd9Sstevel@tonic-gate 						 * ndi_devi_offline failed.
3243*7c478bd9Sstevel@tonic-gate 						 * Reset client flags to
3244*7c478bd9Sstevel@tonic-gate 						 * online as the path could not
3245*7c478bd9Sstevel@tonic-gate 						 * be offlined.
3246*7c478bd9Sstevel@tonic-gate 						 */
3247*7c478bd9Sstevel@tonic-gate 						MDI_DEBUG(1, (CE_WARN, cdip,
3248*7c478bd9Sstevel@tonic-gate 						    "!ndi_devi_offline: failed "
3249*7c478bd9Sstevel@tonic-gate 						    " Error: %x", rv));
3250*7c478bd9Sstevel@tonic-gate 						MDI_CLIENT_SET_ONLINE(ct);
3251*7c478bd9Sstevel@tonic-gate 					}
3252*7c478bd9Sstevel@tonic-gate 				}
3253*7c478bd9Sstevel@tonic-gate 				break;
3254*7c478bd9Sstevel@tonic-gate 			}
3255*7c478bd9Sstevel@tonic-gate 			/*
3256*7c478bd9Sstevel@tonic-gate 			 * Convert to MDI error code
3257*7c478bd9Sstevel@tonic-gate 			 */
3258*7c478bd9Sstevel@tonic-gate 			switch (rv) {
3259*7c478bd9Sstevel@tonic-gate 			case NDI_SUCCESS:
3260*7c478bd9Sstevel@tonic-gate 				MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct);
3261*7c478bd9Sstevel@tonic-gate 				i_mdi_report_path_state(ct, pip);
3262*7c478bd9Sstevel@tonic-gate 				rv = MDI_SUCCESS;
3263*7c478bd9Sstevel@tonic-gate 				break;
3264*7c478bd9Sstevel@tonic-gate 			case NDI_BUSY:
3265*7c478bd9Sstevel@tonic-gate 				rv = MDI_BUSY;
3266*7c478bd9Sstevel@tonic-gate 				break;
3267*7c478bd9Sstevel@tonic-gate 			default:
3268*7c478bd9Sstevel@tonic-gate 				rv = MDI_FAILURE;
3269*7c478bd9Sstevel@tonic-gate 				break;
3270*7c478bd9Sstevel@tonic-gate 			}
3271*7c478bd9Sstevel@tonic-gate 		}
3272*7c478bd9Sstevel@tonic-gate 	}
3273*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
3274*7c478bd9Sstevel@tonic-gate 
3275*7c478bd9Sstevel@tonic-gate state_change_exit:
3276*7c478bd9Sstevel@tonic-gate 	/*
3277*7c478bd9Sstevel@tonic-gate 	 * Mark the pHCI as stable again.
3278*7c478bd9Sstevel@tonic-gate 	 */
3279*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_LOCK(ph);
3280*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_STABLE(ph);
3281*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNLOCK(ph);
3282*7c478bd9Sstevel@tonic-gate 	return (rv);
3283*7c478bd9Sstevel@tonic-gate }
3284*7c478bd9Sstevel@tonic-gate 
3285*7c478bd9Sstevel@tonic-gate /*
3286*7c478bd9Sstevel@tonic-gate  * mdi_pi_online():
3287*7c478bd9Sstevel@tonic-gate  *		Place the path_info node in the online state.  The path is
3288*7c478bd9Sstevel@tonic-gate  *		now available to be selected by mdi_select_path() for
3289*7c478bd9Sstevel@tonic-gate  *		transporting I/O requests to client devices.
3290*7c478bd9Sstevel@tonic-gate  * Return Values:
3291*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
3292*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
3293*7c478bd9Sstevel@tonic-gate  */
3294*7c478bd9Sstevel@tonic-gate int
3295*7c478bd9Sstevel@tonic-gate mdi_pi_online(mdi_pathinfo_t *pip, int flags)
3296*7c478bd9Sstevel@tonic-gate {
3297*7c478bd9Sstevel@tonic-gate 	mdi_client_t *ct = MDI_PI(pip)->pi_client;
3298*7c478bd9Sstevel@tonic-gate 	dev_info_t *cdip;
3299*7c478bd9Sstevel@tonic-gate 	int		client_held = 0;
3300*7c478bd9Sstevel@tonic-gate 	int rv;
3301*7c478bd9Sstevel@tonic-gate 
3302*7c478bd9Sstevel@tonic-gate 	ASSERT(ct != NULL);
3303*7c478bd9Sstevel@tonic-gate 	rv = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_ONLINE, flags);
3304*7c478bd9Sstevel@tonic-gate 	if (rv != MDI_SUCCESS)
3305*7c478bd9Sstevel@tonic-gate 		return (rv);
3306*7c478bd9Sstevel@tonic-gate 
3307*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3308*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_pm_held == 0) {
3309*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online "
3310*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_hold_pip\n"));
3311*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_hold_pip(pip);
3312*7c478bd9Sstevel@tonic-gate 		client_held = 1;
3313*7c478bd9Sstevel@tonic-gate 	}
3314*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3315*7c478bd9Sstevel@tonic-gate 
3316*7c478bd9Sstevel@tonic-gate 	if (client_held) {
3317*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_LOCK(ct);
3318*7c478bd9Sstevel@tonic-gate 		if (ct->ct_power_cnt == 0) {
3319*7c478bd9Sstevel@tonic-gate 			rv = i_mdi_power_all_phci(ct);
3320*7c478bd9Sstevel@tonic-gate 		}
3321*7c478bd9Sstevel@tonic-gate 
3322*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online "
3323*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_hold_client\n"));
3324*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_hold_client(ct, 1);
3325*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
3326*7c478bd9Sstevel@tonic-gate 	}
3327*7c478bd9Sstevel@tonic-gate 
3328*7c478bd9Sstevel@tonic-gate 	/*
3329*7c478bd9Sstevel@tonic-gate 	 * Create the per-path (pathinfo) IO and error kstats which
3330*7c478bd9Sstevel@tonic-gate 	 * are reported via iostat(1m).
3331*7c478bd9Sstevel@tonic-gate 	 *
3332*7c478bd9Sstevel@tonic-gate 	 * Defer creating the per-path kstats if device is not yet
3333*7c478bd9Sstevel@tonic-gate 	 * attached;  the names of the kstats are constructed in part
3334*7c478bd9Sstevel@tonic-gate 	 * using the devices instance number which is assigned during
3335*7c478bd9Sstevel@tonic-gate 	 * process of attaching the client device.
3336*7c478bd9Sstevel@tonic-gate 	 *
3337*7c478bd9Sstevel@tonic-gate 	 * The framework post_attach handler, mdi_post_attach(), is
3338*7c478bd9Sstevel@tonic-gate 	 * is responsible for initializing the client's pathinfo list
3339*7c478bd9Sstevel@tonic-gate 	 * once successfully attached.
3340*7c478bd9Sstevel@tonic-gate 	 */
3341*7c478bd9Sstevel@tonic-gate 	cdip = ct->ct_dip;
3342*7c478bd9Sstevel@tonic-gate 	ASSERT(cdip);
3343*7c478bd9Sstevel@tonic-gate 	if (cdip == NULL || (i_ddi_node_state(cdip) < DS_ATTACHED))
3344*7c478bd9Sstevel@tonic-gate 		return (rv);
3345*7c478bd9Sstevel@tonic-gate 
3346*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
3347*7c478bd9Sstevel@tonic-gate 	rv = i_mdi_pi_kstat_create(pip);
3348*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
3349*7c478bd9Sstevel@tonic-gate 	return (rv);
3350*7c478bd9Sstevel@tonic-gate }
3351*7c478bd9Sstevel@tonic-gate 
3352*7c478bd9Sstevel@tonic-gate /*
3353*7c478bd9Sstevel@tonic-gate  * mdi_pi_standby():
3354*7c478bd9Sstevel@tonic-gate  *		Place the mdi_pathinfo node in standby state
3355*7c478bd9Sstevel@tonic-gate  *
3356*7c478bd9Sstevel@tonic-gate  * Return Values:
3357*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
3358*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
3359*7c478bd9Sstevel@tonic-gate  */
3360*7c478bd9Sstevel@tonic-gate int
3361*7c478bd9Sstevel@tonic-gate mdi_pi_standby(mdi_pathinfo_t *pip, int flags)
3362*7c478bd9Sstevel@tonic-gate {
3363*7c478bd9Sstevel@tonic-gate 	return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_STANDBY, flags));
3364*7c478bd9Sstevel@tonic-gate }
3365*7c478bd9Sstevel@tonic-gate 
3366*7c478bd9Sstevel@tonic-gate /*
3367*7c478bd9Sstevel@tonic-gate  * mdi_pi_fault():
3368*7c478bd9Sstevel@tonic-gate  *		Place the mdi_pathinfo node in fault'ed state
3369*7c478bd9Sstevel@tonic-gate  * Return Values:
3370*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
3371*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
3372*7c478bd9Sstevel@tonic-gate  */
3373*7c478bd9Sstevel@tonic-gate int
3374*7c478bd9Sstevel@tonic-gate mdi_pi_fault(mdi_pathinfo_t *pip, int flags)
3375*7c478bd9Sstevel@tonic-gate {
3376*7c478bd9Sstevel@tonic-gate 	return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_FAULT, flags));
3377*7c478bd9Sstevel@tonic-gate }
3378*7c478bd9Sstevel@tonic-gate 
3379*7c478bd9Sstevel@tonic-gate /*
3380*7c478bd9Sstevel@tonic-gate  * mdi_pi_offline():
3381*7c478bd9Sstevel@tonic-gate  *		Offline a mdi_pathinfo node.
3382*7c478bd9Sstevel@tonic-gate  * Return Values:
3383*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
3384*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
3385*7c478bd9Sstevel@tonic-gate  */
3386*7c478bd9Sstevel@tonic-gate int
3387*7c478bd9Sstevel@tonic-gate mdi_pi_offline(mdi_pathinfo_t *pip, int flags)
3388*7c478bd9Sstevel@tonic-gate {
3389*7c478bd9Sstevel@tonic-gate 	int	ret, client_held = 0;
3390*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
3391*7c478bd9Sstevel@tonic-gate 
3392*7c478bd9Sstevel@tonic-gate 	ret = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_OFFLINE, flags);
3393*7c478bd9Sstevel@tonic-gate 
3394*7c478bd9Sstevel@tonic-gate 	if (ret == MDI_SUCCESS) {
3395*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
3396*7c478bd9Sstevel@tonic-gate 		if (MDI_PI(pip)->pi_pm_held) {
3397*7c478bd9Sstevel@tonic-gate 			client_held = 1;
3398*7c478bd9Sstevel@tonic-gate 		}
3399*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3400*7c478bd9Sstevel@tonic-gate 
3401*7c478bd9Sstevel@tonic-gate 		if (client_held) {
3402*7c478bd9Sstevel@tonic-gate 			ct = MDI_PI(pip)->pi_client;
3403*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_LOCK(ct);
3404*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, ct->ct_dip,
3405*7c478bd9Sstevel@tonic-gate 			    "mdi_pi_offline i_mdi_pm_rele_client\n"));
3406*7c478bd9Sstevel@tonic-gate 			i_mdi_pm_rele_client(ct, 1);
3407*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
3408*7c478bd9Sstevel@tonic-gate 		}
3409*7c478bd9Sstevel@tonic-gate 	}
3410*7c478bd9Sstevel@tonic-gate 
3411*7c478bd9Sstevel@tonic-gate 	return (ret);
3412*7c478bd9Sstevel@tonic-gate }
3413*7c478bd9Sstevel@tonic-gate 
3414*7c478bd9Sstevel@tonic-gate /*
3415*7c478bd9Sstevel@tonic-gate  * i_mdi_pi_offline():
3416*7c478bd9Sstevel@tonic-gate  *		Offline a mdi_pathinfo node and call the vHCI driver's callback
3417*7c478bd9Sstevel@tonic-gate  */
3418*7c478bd9Sstevel@tonic-gate static int
3419*7c478bd9Sstevel@tonic-gate i_mdi_pi_offline(mdi_pathinfo_t *pip, int flags)
3420*7c478bd9Sstevel@tonic-gate {
3421*7c478bd9Sstevel@tonic-gate 	dev_info_t	*vdip = NULL;
3422*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*vh = NULL;
3423*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct = NULL;
3424*7c478bd9Sstevel@tonic-gate 	int		(*f)();
3425*7c478bd9Sstevel@tonic-gate 	int		rv;
3426*7c478bd9Sstevel@tonic-gate 
3427*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3428*7c478bd9Sstevel@tonic-gate 	ct = MDI_PI(pip)->pi_client;
3429*7c478bd9Sstevel@tonic-gate 	ASSERT(ct != NULL);
3430*7c478bd9Sstevel@tonic-gate 
3431*7c478bd9Sstevel@tonic-gate 	while (MDI_PI(pip)->pi_ref_cnt != 0) {
3432*7c478bd9Sstevel@tonic-gate 		/*
3433*7c478bd9Sstevel@tonic-gate 		 * Give a chance for pending I/Os to complete.
3434*7c478bd9Sstevel@tonic-gate 		 */
3435*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: "
3436*7c478bd9Sstevel@tonic-gate 		    "%d cmds still pending on path: %p\n",
3437*7c478bd9Sstevel@tonic-gate 		    MDI_PI(pip)->pi_ref_cnt, pip));
3438*7c478bd9Sstevel@tonic-gate 		if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv,
3439*7c478bd9Sstevel@tonic-gate 		    &MDI_PI(pip)->pi_mutex,
3440*7c478bd9Sstevel@tonic-gate 		    ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) {
3441*7c478bd9Sstevel@tonic-gate 			/*
3442*7c478bd9Sstevel@tonic-gate 			 * The timeout time reached without ref_cnt being zero
3443*7c478bd9Sstevel@tonic-gate 			 * being signaled.
3444*7c478bd9Sstevel@tonic-gate 			 */
3445*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: "
3446*7c478bd9Sstevel@tonic-gate 			    "Timeout reached on path %p without the cond\n",
3447*7c478bd9Sstevel@tonic-gate 			    pip));
3448*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: "
3449*7c478bd9Sstevel@tonic-gate 			    "%d cmds still pending on path: %p\n",
3450*7c478bd9Sstevel@tonic-gate 			    MDI_PI(pip)->pi_ref_cnt, pip));
3451*7c478bd9Sstevel@tonic-gate 		}
3452*7c478bd9Sstevel@tonic-gate 	}
3453*7c478bd9Sstevel@tonic-gate 	vh = ct->ct_vhci;
3454*7c478bd9Sstevel@tonic-gate 	vdip = vh->vh_dip;
3455*7c478bd9Sstevel@tonic-gate 
3456*7c478bd9Sstevel@tonic-gate 	/*
3457*7c478bd9Sstevel@tonic-gate 	 * Notify vHCI that has registered this event
3458*7c478bd9Sstevel@tonic-gate 	 */
3459*7c478bd9Sstevel@tonic-gate 	ASSERT(vh->vh_ops);
3460*7c478bd9Sstevel@tonic-gate 	f = vh->vh_ops->vo_pi_state_change;
3461*7c478bd9Sstevel@tonic-gate 
3462*7c478bd9Sstevel@tonic-gate 	if (f != NULL) {
3463*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3464*7c478bd9Sstevel@tonic-gate 		if ((rv = (*f)(vdip, pip, MDI_PATHINFO_STATE_OFFLINE, 0,
3465*7c478bd9Sstevel@tonic-gate 		    flags)) != MDI_SUCCESS) {
3466*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_WARN, vdip, "!vo_path_offline failed "
3467*7c478bd9Sstevel@tonic-gate 			    "vdip 0x%x, pip 0x%x", vdip, pip));
3468*7c478bd9Sstevel@tonic-gate 		}
3469*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
3470*7c478bd9Sstevel@tonic-gate 	}
3471*7c478bd9Sstevel@tonic-gate 
3472*7c478bd9Sstevel@tonic-gate 	/*
3473*7c478bd9Sstevel@tonic-gate 	 * Set the mdi_pathinfo node state and clear the transient condition
3474*7c478bd9Sstevel@tonic-gate 	 */
3475*7c478bd9Sstevel@tonic-gate 	MDI_PI_SET_OFFLINE(pip);
3476*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&MDI_PI(pip)->pi_state_cv);
3477*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3478*7c478bd9Sstevel@tonic-gate 
3479*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
3480*7c478bd9Sstevel@tonic-gate 	if (rv == MDI_SUCCESS) {
3481*7c478bd9Sstevel@tonic-gate 		if (ct->ct_unstable == 0) {
3482*7c478bd9Sstevel@tonic-gate 			dev_info_t	*cdip = ct->ct_dip;
3483*7c478bd9Sstevel@tonic-gate 
3484*7c478bd9Sstevel@tonic-gate 			/*
3485*7c478bd9Sstevel@tonic-gate 			 * Onlining the mdi_pathinfo node will impact the
3486*7c478bd9Sstevel@tonic-gate 			 * client state Update the client and dev_info node
3487*7c478bd9Sstevel@tonic-gate 			 * state accordingly
3488*7c478bd9Sstevel@tonic-gate 			 */
3489*7c478bd9Sstevel@tonic-gate 			i_mdi_client_update_state(ct);
3490*7c478bd9Sstevel@tonic-gate 			rv = NDI_SUCCESS;
3491*7c478bd9Sstevel@tonic-gate 			if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) {
3492*7c478bd9Sstevel@tonic-gate 				if (cdip &&
3493*7c478bd9Sstevel@tonic-gate 				    (i_ddi_node_state(cdip) >=
3494*7c478bd9Sstevel@tonic-gate 				    DS_INITIALIZED)) {
3495*7c478bd9Sstevel@tonic-gate 					MDI_CLIENT_UNLOCK(ct);
3496*7c478bd9Sstevel@tonic-gate 					rv = ndi_devi_offline(cdip, 0);
3497*7c478bd9Sstevel@tonic-gate 					MDI_CLIENT_LOCK(ct);
3498*7c478bd9Sstevel@tonic-gate 					if (rv != NDI_SUCCESS) {
3499*7c478bd9Sstevel@tonic-gate 						/*
3500*7c478bd9Sstevel@tonic-gate 						 * ndi_devi_offline failed.
3501*7c478bd9Sstevel@tonic-gate 						 * Reset client flags to
3502*7c478bd9Sstevel@tonic-gate 						 * online.
3503*7c478bd9Sstevel@tonic-gate 						 */
3504*7c478bd9Sstevel@tonic-gate 						MDI_DEBUG(4, (CE_WARN, cdip,
3505*7c478bd9Sstevel@tonic-gate 						    "!ndi_devi_offline: failed "
3506*7c478bd9Sstevel@tonic-gate 						    " Error: %x", rv));
3507*7c478bd9Sstevel@tonic-gate 						MDI_CLIENT_SET_ONLINE(ct);
3508*7c478bd9Sstevel@tonic-gate 					}
3509*7c478bd9Sstevel@tonic-gate 				}
3510*7c478bd9Sstevel@tonic-gate 			}
3511*7c478bd9Sstevel@tonic-gate 			/*
3512*7c478bd9Sstevel@tonic-gate 			 * Convert to MDI error code
3513*7c478bd9Sstevel@tonic-gate 			 */
3514*7c478bd9Sstevel@tonic-gate 			switch (rv) {
3515*7c478bd9Sstevel@tonic-gate 			case NDI_SUCCESS:
3516*7c478bd9Sstevel@tonic-gate 				rv = MDI_SUCCESS;
3517*7c478bd9Sstevel@tonic-gate 				break;
3518*7c478bd9Sstevel@tonic-gate 			case NDI_BUSY:
3519*7c478bd9Sstevel@tonic-gate 				rv = MDI_BUSY;
3520*7c478bd9Sstevel@tonic-gate 				break;
3521*7c478bd9Sstevel@tonic-gate 			default:
3522*7c478bd9Sstevel@tonic-gate 				rv = MDI_FAILURE;
3523*7c478bd9Sstevel@tonic-gate 				break;
3524*7c478bd9Sstevel@tonic-gate 			}
3525*7c478bd9Sstevel@tonic-gate 		}
3526*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct);
3527*7c478bd9Sstevel@tonic-gate 		i_mdi_report_path_state(ct, pip);
3528*7c478bd9Sstevel@tonic-gate 	}
3529*7c478bd9Sstevel@tonic-gate 
3530*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
3531*7c478bd9Sstevel@tonic-gate 
3532*7c478bd9Sstevel@tonic-gate 	/*
3533*7c478bd9Sstevel@tonic-gate 	 * Change in the mdi_pathinfo node state will impact the client state
3534*7c478bd9Sstevel@tonic-gate 	 */
3535*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(2, (CE_NOTE, NULL, "!i_mdi_pi_offline ct = %p pip = %p",
3536*7c478bd9Sstevel@tonic-gate 	    ct, pip));
3537*7c478bd9Sstevel@tonic-gate 	return (rv);
3538*7c478bd9Sstevel@tonic-gate }
3539*7c478bd9Sstevel@tonic-gate 
3540*7c478bd9Sstevel@tonic-gate 
3541*7c478bd9Sstevel@tonic-gate /*
3542*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_addr():
3543*7c478bd9Sstevel@tonic-gate  *		Get the unit address associated with a mdi_pathinfo node
3544*7c478bd9Sstevel@tonic-gate  *
3545*7c478bd9Sstevel@tonic-gate  * Return Values:
3546*7c478bd9Sstevel@tonic-gate  *		char *
3547*7c478bd9Sstevel@tonic-gate  */
3548*7c478bd9Sstevel@tonic-gate char *
3549*7c478bd9Sstevel@tonic-gate mdi_pi_get_addr(mdi_pathinfo_t *pip)
3550*7c478bd9Sstevel@tonic-gate {
3551*7c478bd9Sstevel@tonic-gate 	char *addr;
3552*7c478bd9Sstevel@tonic-gate 
3553*7c478bd9Sstevel@tonic-gate 	if (pip == NULL)
3554*7c478bd9Sstevel@tonic-gate 		return (NULL);
3555*7c478bd9Sstevel@tonic-gate 
3556*7c478bd9Sstevel@tonic-gate 	addr = MDI_PI(pip)->pi_addr;
3557*7c478bd9Sstevel@tonic-gate 
3558*7c478bd9Sstevel@tonic-gate 	/*
3559*7c478bd9Sstevel@tonic-gate 	 * XXX To be removed when libg_fc is updated to
3560*7c478bd9Sstevel@tonic-gate 	 * skip leading 'w' in NWS consolidation.
3561*7c478bd9Sstevel@tonic-gate 	 */
3562*7c478bd9Sstevel@tonic-gate 	if (*addr == 'w')
3563*7c478bd9Sstevel@tonic-gate 		addr += 1;
3564*7c478bd9Sstevel@tonic-gate 
3565*7c478bd9Sstevel@tonic-gate 	return (addr);
3566*7c478bd9Sstevel@tonic-gate }
3567*7c478bd9Sstevel@tonic-gate 
3568*7c478bd9Sstevel@tonic-gate /*
3569*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_client():
3570*7c478bd9Sstevel@tonic-gate  *		Get the client devinfo associated with a mdi_pathinfo node
3571*7c478bd9Sstevel@tonic-gate  *
3572*7c478bd9Sstevel@tonic-gate  * Return Values:
3573*7c478bd9Sstevel@tonic-gate  *		Handle to client device dev_info node
3574*7c478bd9Sstevel@tonic-gate  */
3575*7c478bd9Sstevel@tonic-gate dev_info_t *
3576*7c478bd9Sstevel@tonic-gate mdi_pi_get_client(mdi_pathinfo_t *pip)
3577*7c478bd9Sstevel@tonic-gate {
3578*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = NULL;
3579*7c478bd9Sstevel@tonic-gate 	if (pip) {
3580*7c478bd9Sstevel@tonic-gate 		dip = MDI_PI(pip)->pi_client->ct_dip;
3581*7c478bd9Sstevel@tonic-gate 	}
3582*7c478bd9Sstevel@tonic-gate 	return (dip);
3583*7c478bd9Sstevel@tonic-gate }
3584*7c478bd9Sstevel@tonic-gate 
3585*7c478bd9Sstevel@tonic-gate /*
3586*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_phci():
3587*7c478bd9Sstevel@tonic-gate  *		Get the pHCI devinfo associated with the mdi_pathinfo node
3588*7c478bd9Sstevel@tonic-gate  * Return Values:
3589*7c478bd9Sstevel@tonic-gate  *		Handle to dev_info node
3590*7c478bd9Sstevel@tonic-gate  */
3591*7c478bd9Sstevel@tonic-gate dev_info_t *
3592*7c478bd9Sstevel@tonic-gate mdi_pi_get_phci(mdi_pathinfo_t *pip)
3593*7c478bd9Sstevel@tonic-gate {
3594*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = NULL;
3595*7c478bd9Sstevel@tonic-gate 	if (pip) {
3596*7c478bd9Sstevel@tonic-gate 		dip = MDI_PI(pip)->pi_phci->ph_dip;
3597*7c478bd9Sstevel@tonic-gate 	}
3598*7c478bd9Sstevel@tonic-gate 	return (dip);
3599*7c478bd9Sstevel@tonic-gate }
3600*7c478bd9Sstevel@tonic-gate 
3601*7c478bd9Sstevel@tonic-gate /*
3602*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_client_private():
3603*7c478bd9Sstevel@tonic-gate  *		Get the client private information associated with the
3604*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo node
3605*7c478bd9Sstevel@tonic-gate  */
3606*7c478bd9Sstevel@tonic-gate void *
3607*7c478bd9Sstevel@tonic-gate mdi_pi_get_client_private(mdi_pathinfo_t *pip)
3608*7c478bd9Sstevel@tonic-gate {
3609*7c478bd9Sstevel@tonic-gate 	void *cprivate = NULL;
3610*7c478bd9Sstevel@tonic-gate 	if (pip) {
3611*7c478bd9Sstevel@tonic-gate 		cprivate = MDI_PI(pip)->pi_cprivate;
3612*7c478bd9Sstevel@tonic-gate 	}
3613*7c478bd9Sstevel@tonic-gate 	return (cprivate);
3614*7c478bd9Sstevel@tonic-gate }
3615*7c478bd9Sstevel@tonic-gate 
3616*7c478bd9Sstevel@tonic-gate /*
3617*7c478bd9Sstevel@tonic-gate  * mdi_pi_set_client_private():
3618*7c478bd9Sstevel@tonic-gate  *		Set the client private information in the mdi_pathinfo node
3619*7c478bd9Sstevel@tonic-gate  */
3620*7c478bd9Sstevel@tonic-gate void
3621*7c478bd9Sstevel@tonic-gate mdi_pi_set_client_private(mdi_pathinfo_t *pip, void *priv)
3622*7c478bd9Sstevel@tonic-gate {
3623*7c478bd9Sstevel@tonic-gate 	if (pip) {
3624*7c478bd9Sstevel@tonic-gate 		MDI_PI(pip)->pi_cprivate = priv;
3625*7c478bd9Sstevel@tonic-gate 	}
3626*7c478bd9Sstevel@tonic-gate }
3627*7c478bd9Sstevel@tonic-gate 
3628*7c478bd9Sstevel@tonic-gate /*
3629*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_phci_private():
3630*7c478bd9Sstevel@tonic-gate  *		Get the pHCI private information associated with the
3631*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo node
3632*7c478bd9Sstevel@tonic-gate  */
3633*7c478bd9Sstevel@tonic-gate caddr_t
3634*7c478bd9Sstevel@tonic-gate mdi_pi_get_phci_private(mdi_pathinfo_t *pip)
3635*7c478bd9Sstevel@tonic-gate {
3636*7c478bd9Sstevel@tonic-gate 	caddr_t	pprivate = NULL;
3637*7c478bd9Sstevel@tonic-gate 	if (pip) {
3638*7c478bd9Sstevel@tonic-gate 		pprivate = MDI_PI(pip)->pi_pprivate;
3639*7c478bd9Sstevel@tonic-gate 	}
3640*7c478bd9Sstevel@tonic-gate 	return (pprivate);
3641*7c478bd9Sstevel@tonic-gate }
3642*7c478bd9Sstevel@tonic-gate 
3643*7c478bd9Sstevel@tonic-gate /*
3644*7c478bd9Sstevel@tonic-gate  * mdi_pi_set_phci_private():
3645*7c478bd9Sstevel@tonic-gate  *		Set the pHCI private information in the mdi_pathinfo node
3646*7c478bd9Sstevel@tonic-gate  */
3647*7c478bd9Sstevel@tonic-gate void
3648*7c478bd9Sstevel@tonic-gate mdi_pi_set_phci_private(mdi_pathinfo_t *pip, caddr_t priv)
3649*7c478bd9Sstevel@tonic-gate {
3650*7c478bd9Sstevel@tonic-gate 	if (pip) {
3651*7c478bd9Sstevel@tonic-gate 		MDI_PI(pip)->pi_pprivate = priv;
3652*7c478bd9Sstevel@tonic-gate 	}
3653*7c478bd9Sstevel@tonic-gate }
3654*7c478bd9Sstevel@tonic-gate 
3655*7c478bd9Sstevel@tonic-gate /*
3656*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_state():
3657*7c478bd9Sstevel@tonic-gate  *		Get the mdi_pathinfo node state. Transient states are internal
3658*7c478bd9Sstevel@tonic-gate  *		and not provided to the users
3659*7c478bd9Sstevel@tonic-gate  */
3660*7c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t
3661*7c478bd9Sstevel@tonic-gate mdi_pi_get_state(mdi_pathinfo_t *pip)
3662*7c478bd9Sstevel@tonic-gate {
3663*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_state_t    state = MDI_PATHINFO_STATE_INIT;
3664*7c478bd9Sstevel@tonic-gate 
3665*7c478bd9Sstevel@tonic-gate 	if (pip) {
3666*7c478bd9Sstevel@tonic-gate 		if (MDI_PI_IS_TRANSIENT(pip)) {
3667*7c478bd9Sstevel@tonic-gate 			/*
3668*7c478bd9Sstevel@tonic-gate 			 * mdi_pathinfo is in state transition.  Return the
3669*7c478bd9Sstevel@tonic-gate 			 * last good state.
3670*7c478bd9Sstevel@tonic-gate 			 */
3671*7c478bd9Sstevel@tonic-gate 			state = MDI_PI_OLD_STATE(pip);
3672*7c478bd9Sstevel@tonic-gate 		} else {
3673*7c478bd9Sstevel@tonic-gate 			state = MDI_PI_STATE(pip);
3674*7c478bd9Sstevel@tonic-gate 		}
3675*7c478bd9Sstevel@tonic-gate 	}
3676*7c478bd9Sstevel@tonic-gate 	return (state);
3677*7c478bd9Sstevel@tonic-gate }
3678*7c478bd9Sstevel@tonic-gate 
3679*7c478bd9Sstevel@tonic-gate /*
3680*7c478bd9Sstevel@tonic-gate  * Note that the following function needs to be the new interface for
3681*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_state when mpxio gets integrated to ON.
3682*7c478bd9Sstevel@tonic-gate  */
3683*7c478bd9Sstevel@tonic-gate int
3684*7c478bd9Sstevel@tonic-gate mdi_pi_get_state2(mdi_pathinfo_t *pip, mdi_pathinfo_state_t *state,
3685*7c478bd9Sstevel@tonic-gate 		uint32_t *ext_state)
3686*7c478bd9Sstevel@tonic-gate {
3687*7c478bd9Sstevel@tonic-gate 	*state = MDI_PATHINFO_STATE_INIT;
3688*7c478bd9Sstevel@tonic-gate 
3689*7c478bd9Sstevel@tonic-gate 	if (pip) {
3690*7c478bd9Sstevel@tonic-gate 		if (MDI_PI_IS_TRANSIENT(pip)) {
3691*7c478bd9Sstevel@tonic-gate 			/*
3692*7c478bd9Sstevel@tonic-gate 			 * mdi_pathinfo is in state transition.  Return the
3693*7c478bd9Sstevel@tonic-gate 			 * last good state.
3694*7c478bd9Sstevel@tonic-gate 			 */
3695*7c478bd9Sstevel@tonic-gate 			*state = MDI_PI_OLD_STATE(pip);
3696*7c478bd9Sstevel@tonic-gate 			*ext_state = MDI_PI_OLD_EXT_STATE(pip);
3697*7c478bd9Sstevel@tonic-gate 		} else {
3698*7c478bd9Sstevel@tonic-gate 			*state = MDI_PI_STATE(pip);
3699*7c478bd9Sstevel@tonic-gate 			*ext_state = MDI_PI_EXT_STATE(pip);
3700*7c478bd9Sstevel@tonic-gate 		}
3701*7c478bd9Sstevel@tonic-gate 	}
3702*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
3703*7c478bd9Sstevel@tonic-gate }
3704*7c478bd9Sstevel@tonic-gate 
3705*7c478bd9Sstevel@tonic-gate /*
3706*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_preferred:
3707*7c478bd9Sstevel@tonic-gate  *	Get the preferred path flag
3708*7c478bd9Sstevel@tonic-gate  */
3709*7c478bd9Sstevel@tonic-gate int
3710*7c478bd9Sstevel@tonic-gate mdi_pi_get_preferred(mdi_pathinfo_t *pip)
3711*7c478bd9Sstevel@tonic-gate {
3712*7c478bd9Sstevel@tonic-gate 	if (pip) {
3713*7c478bd9Sstevel@tonic-gate 		return (MDI_PI(pip)->pi_preferred);
3714*7c478bd9Sstevel@tonic-gate 	}
3715*7c478bd9Sstevel@tonic-gate 	return (0);
3716*7c478bd9Sstevel@tonic-gate }
3717*7c478bd9Sstevel@tonic-gate 
3718*7c478bd9Sstevel@tonic-gate /*
3719*7c478bd9Sstevel@tonic-gate  * mdi_pi_set_preferred:
3720*7c478bd9Sstevel@tonic-gate  *	Set the preferred path flag
3721*7c478bd9Sstevel@tonic-gate  */
3722*7c478bd9Sstevel@tonic-gate void
3723*7c478bd9Sstevel@tonic-gate mdi_pi_set_preferred(mdi_pathinfo_t *pip, int preferred)
3724*7c478bd9Sstevel@tonic-gate {
3725*7c478bd9Sstevel@tonic-gate 	if (pip) {
3726*7c478bd9Sstevel@tonic-gate 		MDI_PI(pip)->pi_preferred = preferred;
3727*7c478bd9Sstevel@tonic-gate 	}
3728*7c478bd9Sstevel@tonic-gate }
3729*7c478bd9Sstevel@tonic-gate 
3730*7c478bd9Sstevel@tonic-gate 
3731*7c478bd9Sstevel@tonic-gate /*
3732*7c478bd9Sstevel@tonic-gate  * mdi_pi_set_state():
3733*7c478bd9Sstevel@tonic-gate  *		Set the mdi_pathinfo node state
3734*7c478bd9Sstevel@tonic-gate  */
3735*7c478bd9Sstevel@tonic-gate void
3736*7c478bd9Sstevel@tonic-gate mdi_pi_set_state(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state)
3737*7c478bd9Sstevel@tonic-gate {
3738*7c478bd9Sstevel@tonic-gate 	uint32_t	ext_state;
3739*7c478bd9Sstevel@tonic-gate 
3740*7c478bd9Sstevel@tonic-gate 	if (pip) {
3741*7c478bd9Sstevel@tonic-gate 		ext_state = MDI_PI(pip)->pi_state & MDI_PATHINFO_EXT_STATE_MASK;
3742*7c478bd9Sstevel@tonic-gate 		MDI_PI(pip)->pi_state = state;
3743*7c478bd9Sstevel@tonic-gate 		MDI_PI(pip)->pi_state |= ext_state;
3744*7c478bd9Sstevel@tonic-gate 	}
3745*7c478bd9Sstevel@tonic-gate }
3746*7c478bd9Sstevel@tonic-gate 
3747*7c478bd9Sstevel@tonic-gate /*
3748*7c478bd9Sstevel@tonic-gate  * Property functions:
3749*7c478bd9Sstevel@tonic-gate  */
3750*7c478bd9Sstevel@tonic-gate 
3751*7c478bd9Sstevel@tonic-gate int
3752*7c478bd9Sstevel@tonic-gate i_map_nvlist_error_to_mdi(int val)
3753*7c478bd9Sstevel@tonic-gate {
3754*7c478bd9Sstevel@tonic-gate 	int rv;
3755*7c478bd9Sstevel@tonic-gate 
3756*7c478bd9Sstevel@tonic-gate 	switch (val) {
3757*7c478bd9Sstevel@tonic-gate 	case 0:
3758*7c478bd9Sstevel@tonic-gate 		rv = DDI_PROP_SUCCESS;
3759*7c478bd9Sstevel@tonic-gate 		break;
3760*7c478bd9Sstevel@tonic-gate 	case EINVAL:
3761*7c478bd9Sstevel@tonic-gate 	case ENOTSUP:
3762*7c478bd9Sstevel@tonic-gate 		rv = DDI_PROP_INVAL_ARG;
3763*7c478bd9Sstevel@tonic-gate 		break;
3764*7c478bd9Sstevel@tonic-gate 	case ENOMEM:
3765*7c478bd9Sstevel@tonic-gate 		rv = DDI_PROP_NO_MEMORY;
3766*7c478bd9Sstevel@tonic-gate 		break;
3767*7c478bd9Sstevel@tonic-gate 	default:
3768*7c478bd9Sstevel@tonic-gate 		rv = DDI_PROP_NOT_FOUND;
3769*7c478bd9Sstevel@tonic-gate 		break;
3770*7c478bd9Sstevel@tonic-gate 	}
3771*7c478bd9Sstevel@tonic-gate 	return (rv);
3772*7c478bd9Sstevel@tonic-gate }
3773*7c478bd9Sstevel@tonic-gate 
3774*7c478bd9Sstevel@tonic-gate /*
3775*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_next_prop():
3776*7c478bd9Sstevel@tonic-gate  * 		Property walk function.  The caller should hold mdi_pi_lock()
3777*7c478bd9Sstevel@tonic-gate  *		and release by calling mdi_pi_unlock() at the end of walk to
3778*7c478bd9Sstevel@tonic-gate  *		get a consistent value.
3779*7c478bd9Sstevel@tonic-gate  */
3780*7c478bd9Sstevel@tonic-gate 
3781*7c478bd9Sstevel@tonic-gate nvpair_t *
3782*7c478bd9Sstevel@tonic-gate mdi_pi_get_next_prop(mdi_pathinfo_t *pip, nvpair_t *prev)
3783*7c478bd9Sstevel@tonic-gate {
3784*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
3785*7c478bd9Sstevel@tonic-gate 		return (NULL);
3786*7c478bd9Sstevel@tonic-gate 	}
3787*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
3788*7c478bd9Sstevel@tonic-gate 	return (nvlist_next_nvpair(MDI_PI(pip)->pi_prop, prev));
3789*7c478bd9Sstevel@tonic-gate }
3790*7c478bd9Sstevel@tonic-gate 
3791*7c478bd9Sstevel@tonic-gate /*
3792*7c478bd9Sstevel@tonic-gate  * mdi_prop_remove():
3793*7c478bd9Sstevel@tonic-gate  * 		Remove the named property from the named list.
3794*7c478bd9Sstevel@tonic-gate  */
3795*7c478bd9Sstevel@tonic-gate 
3796*7c478bd9Sstevel@tonic-gate int
3797*7c478bd9Sstevel@tonic-gate mdi_prop_remove(mdi_pathinfo_t *pip, char *name)
3798*7c478bd9Sstevel@tonic-gate {
3799*7c478bd9Sstevel@tonic-gate 	if (pip == NULL) {
3800*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3801*7c478bd9Sstevel@tonic-gate 	}
3802*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
3803*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3804*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_prop == NULL) {
3805*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3806*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3807*7c478bd9Sstevel@tonic-gate 	}
3808*7c478bd9Sstevel@tonic-gate 	if (name) {
3809*7c478bd9Sstevel@tonic-gate 		(void) nvlist_remove_all(MDI_PI(pip)->pi_prop, name);
3810*7c478bd9Sstevel@tonic-gate 	} else {
3811*7c478bd9Sstevel@tonic-gate 		char		nvp_name[MAXNAMELEN];
3812*7c478bd9Sstevel@tonic-gate 		nvpair_t	*nvp;
3813*7c478bd9Sstevel@tonic-gate 		nvp = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, NULL);
3814*7c478bd9Sstevel@tonic-gate 		while (nvp) {
3815*7c478bd9Sstevel@tonic-gate 			nvpair_t	*next;
3816*7c478bd9Sstevel@tonic-gate 			next = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, nvp);
3817*7c478bd9Sstevel@tonic-gate 			(void) snprintf(nvp_name, MAXNAMELEN, "%s",
3818*7c478bd9Sstevel@tonic-gate 			    nvpair_name(nvp));
3819*7c478bd9Sstevel@tonic-gate 			(void) nvlist_remove_all(MDI_PI(pip)->pi_prop,
3820*7c478bd9Sstevel@tonic-gate 			    nvp_name);
3821*7c478bd9Sstevel@tonic-gate 			nvp = next;
3822*7c478bd9Sstevel@tonic-gate 		}
3823*7c478bd9Sstevel@tonic-gate 	}
3824*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3825*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
3826*7c478bd9Sstevel@tonic-gate }
3827*7c478bd9Sstevel@tonic-gate 
3828*7c478bd9Sstevel@tonic-gate /*
3829*7c478bd9Sstevel@tonic-gate  * mdi_prop_size():
3830*7c478bd9Sstevel@tonic-gate  * 		Get buffer size needed to pack the property data.
3831*7c478bd9Sstevel@tonic-gate  * 		Caller should hold the mdi_pathinfo_t lock to get a consistent
3832*7c478bd9Sstevel@tonic-gate  *		buffer size.
3833*7c478bd9Sstevel@tonic-gate  */
3834*7c478bd9Sstevel@tonic-gate 
3835*7c478bd9Sstevel@tonic-gate int
3836*7c478bd9Sstevel@tonic-gate mdi_prop_size(mdi_pathinfo_t *pip, size_t *buflenp)
3837*7c478bd9Sstevel@tonic-gate {
3838*7c478bd9Sstevel@tonic-gate 	int	rv;
3839*7c478bd9Sstevel@tonic-gate 	size_t	bufsize;
3840*7c478bd9Sstevel@tonic-gate 
3841*7c478bd9Sstevel@tonic-gate 	*buflenp = 0;
3842*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
3843*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3844*7c478bd9Sstevel@tonic-gate 	}
3845*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
3846*7c478bd9Sstevel@tonic-gate 	rv = nvlist_size(MDI_PI(pip)->pi_prop,
3847*7c478bd9Sstevel@tonic-gate 	    &bufsize, NV_ENCODE_NATIVE);
3848*7c478bd9Sstevel@tonic-gate 	*buflenp = bufsize;
3849*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
3850*7c478bd9Sstevel@tonic-gate }
3851*7c478bd9Sstevel@tonic-gate 
3852*7c478bd9Sstevel@tonic-gate /*
3853*7c478bd9Sstevel@tonic-gate  * mdi_prop_pack():
3854*7c478bd9Sstevel@tonic-gate  * 		pack the property list.  The caller should hold the
3855*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo_t node to get a consistent data
3856*7c478bd9Sstevel@tonic-gate  */
3857*7c478bd9Sstevel@tonic-gate 
3858*7c478bd9Sstevel@tonic-gate int
3859*7c478bd9Sstevel@tonic-gate mdi_prop_pack(mdi_pathinfo_t *pip, char **bufp, uint_t buflen)
3860*7c478bd9Sstevel@tonic-gate {
3861*7c478bd9Sstevel@tonic-gate 	int	rv;
3862*7c478bd9Sstevel@tonic-gate 	size_t	bufsize;
3863*7c478bd9Sstevel@tonic-gate 
3864*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || MDI_PI(pip)->pi_prop == NULL) {
3865*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3866*7c478bd9Sstevel@tonic-gate 	}
3867*7c478bd9Sstevel@tonic-gate 
3868*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
3869*7c478bd9Sstevel@tonic-gate 
3870*7c478bd9Sstevel@tonic-gate 	bufsize = buflen;
3871*7c478bd9Sstevel@tonic-gate 	rv = nvlist_pack(MDI_PI(pip)->pi_prop, bufp, (size_t *)&bufsize,
3872*7c478bd9Sstevel@tonic-gate 	    NV_ENCODE_NATIVE, KM_SLEEP);
3873*7c478bd9Sstevel@tonic-gate 
3874*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
3875*7c478bd9Sstevel@tonic-gate }
3876*7c478bd9Sstevel@tonic-gate 
3877*7c478bd9Sstevel@tonic-gate /*
3878*7c478bd9Sstevel@tonic-gate  * mdi_prop_update_byte():
3879*7c478bd9Sstevel@tonic-gate  *		Create/Update a byte property
3880*7c478bd9Sstevel@tonic-gate  */
3881*7c478bd9Sstevel@tonic-gate int
3882*7c478bd9Sstevel@tonic-gate mdi_prop_update_byte(mdi_pathinfo_t *pip, char *name, uchar_t data)
3883*7c478bd9Sstevel@tonic-gate {
3884*7c478bd9Sstevel@tonic-gate 	int rv;
3885*7c478bd9Sstevel@tonic-gate 
3886*7c478bd9Sstevel@tonic-gate 	if (pip == NULL) {
3887*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3888*7c478bd9Sstevel@tonic-gate 	}
3889*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
3890*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3891*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_prop == NULL) {
3892*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3893*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3894*7c478bd9Sstevel@tonic-gate 	}
3895*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_byte(MDI_PI(pip)->pi_prop, name, data);
3896*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3897*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
3898*7c478bd9Sstevel@tonic-gate }
3899*7c478bd9Sstevel@tonic-gate 
3900*7c478bd9Sstevel@tonic-gate /*
3901*7c478bd9Sstevel@tonic-gate  * mdi_prop_update_byte_array():
3902*7c478bd9Sstevel@tonic-gate  *		Create/Update a byte array property
3903*7c478bd9Sstevel@tonic-gate  */
3904*7c478bd9Sstevel@tonic-gate int
3905*7c478bd9Sstevel@tonic-gate mdi_prop_update_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t *data,
3906*7c478bd9Sstevel@tonic-gate     uint_t nelements)
3907*7c478bd9Sstevel@tonic-gate {
3908*7c478bd9Sstevel@tonic-gate 	int rv;
3909*7c478bd9Sstevel@tonic-gate 
3910*7c478bd9Sstevel@tonic-gate 	if (pip == NULL) {
3911*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3912*7c478bd9Sstevel@tonic-gate 	}
3913*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
3914*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3915*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_prop == NULL) {
3916*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3917*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3918*7c478bd9Sstevel@tonic-gate 	}
3919*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_byte_array(MDI_PI(pip)->pi_prop, name, data, nelements);
3920*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3921*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
3922*7c478bd9Sstevel@tonic-gate }
3923*7c478bd9Sstevel@tonic-gate 
3924*7c478bd9Sstevel@tonic-gate /*
3925*7c478bd9Sstevel@tonic-gate  * mdi_prop_update_int():
3926*7c478bd9Sstevel@tonic-gate  *		Create/Update a 32 bit integer property
3927*7c478bd9Sstevel@tonic-gate  */
3928*7c478bd9Sstevel@tonic-gate int
3929*7c478bd9Sstevel@tonic-gate mdi_prop_update_int(mdi_pathinfo_t *pip, char *name, int data)
3930*7c478bd9Sstevel@tonic-gate {
3931*7c478bd9Sstevel@tonic-gate 	int rv;
3932*7c478bd9Sstevel@tonic-gate 
3933*7c478bd9Sstevel@tonic-gate 	if (pip == NULL) {
3934*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3935*7c478bd9Sstevel@tonic-gate 	}
3936*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
3937*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3938*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_prop == NULL) {
3939*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3940*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3941*7c478bd9Sstevel@tonic-gate 	}
3942*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_int32(MDI_PI(pip)->pi_prop, name, (int32_t)data);
3943*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3944*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
3945*7c478bd9Sstevel@tonic-gate }
3946*7c478bd9Sstevel@tonic-gate 
3947*7c478bd9Sstevel@tonic-gate /*
3948*7c478bd9Sstevel@tonic-gate  * mdi_prop_update_int64():
3949*7c478bd9Sstevel@tonic-gate  *		Create/Update a 64 bit integer property
3950*7c478bd9Sstevel@tonic-gate  */
3951*7c478bd9Sstevel@tonic-gate int
3952*7c478bd9Sstevel@tonic-gate mdi_prop_update_int64(mdi_pathinfo_t *pip, char *name, int64_t data)
3953*7c478bd9Sstevel@tonic-gate {
3954*7c478bd9Sstevel@tonic-gate 	int rv;
3955*7c478bd9Sstevel@tonic-gate 
3956*7c478bd9Sstevel@tonic-gate 	if (pip == NULL) {
3957*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3958*7c478bd9Sstevel@tonic-gate 	}
3959*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
3960*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3961*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_prop == NULL) {
3962*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3963*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3964*7c478bd9Sstevel@tonic-gate 	}
3965*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_int64(MDI_PI(pip)->pi_prop, name, data);
3966*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3967*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
3968*7c478bd9Sstevel@tonic-gate }
3969*7c478bd9Sstevel@tonic-gate 
3970*7c478bd9Sstevel@tonic-gate /*
3971*7c478bd9Sstevel@tonic-gate  * mdi_prop_update_int_array():
3972*7c478bd9Sstevel@tonic-gate  *		Create/Update a int array property
3973*7c478bd9Sstevel@tonic-gate  */
3974*7c478bd9Sstevel@tonic-gate int
3975*7c478bd9Sstevel@tonic-gate mdi_prop_update_int_array(mdi_pathinfo_t *pip, char *name, int *data,
3976*7c478bd9Sstevel@tonic-gate 	    uint_t nelements)
3977*7c478bd9Sstevel@tonic-gate {
3978*7c478bd9Sstevel@tonic-gate 	int rv;
3979*7c478bd9Sstevel@tonic-gate 
3980*7c478bd9Sstevel@tonic-gate 	if (pip == NULL) {
3981*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3982*7c478bd9Sstevel@tonic-gate 	}
3983*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
3984*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
3985*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_prop == NULL) {
3986*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
3987*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3988*7c478bd9Sstevel@tonic-gate 	}
3989*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_int32_array(MDI_PI(pip)->pi_prop, name, (int32_t *)data,
3990*7c478bd9Sstevel@tonic-gate 	    nelements);
3991*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
3992*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
3993*7c478bd9Sstevel@tonic-gate }
3994*7c478bd9Sstevel@tonic-gate 
3995*7c478bd9Sstevel@tonic-gate /*
3996*7c478bd9Sstevel@tonic-gate  * mdi_prop_update_string():
3997*7c478bd9Sstevel@tonic-gate  *		Create/Update a string property
3998*7c478bd9Sstevel@tonic-gate  */
3999*7c478bd9Sstevel@tonic-gate int
4000*7c478bd9Sstevel@tonic-gate mdi_prop_update_string(mdi_pathinfo_t *pip, char *name, char *data)
4001*7c478bd9Sstevel@tonic-gate {
4002*7c478bd9Sstevel@tonic-gate 	int rv;
4003*7c478bd9Sstevel@tonic-gate 
4004*7c478bd9Sstevel@tonic-gate 	if (pip == NULL) {
4005*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
4006*7c478bd9Sstevel@tonic-gate 	}
4007*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
4008*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
4009*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_prop == NULL) {
4010*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
4011*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4012*7c478bd9Sstevel@tonic-gate 	}
4013*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_string(MDI_PI(pip)->pi_prop, name, data);
4014*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
4015*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
4016*7c478bd9Sstevel@tonic-gate }
4017*7c478bd9Sstevel@tonic-gate 
4018*7c478bd9Sstevel@tonic-gate /*
4019*7c478bd9Sstevel@tonic-gate  * mdi_prop_update_string_array():
4020*7c478bd9Sstevel@tonic-gate  *		Create/Update a string array property
4021*7c478bd9Sstevel@tonic-gate  */
4022*7c478bd9Sstevel@tonic-gate int
4023*7c478bd9Sstevel@tonic-gate mdi_prop_update_string_array(mdi_pathinfo_t *pip, char *name, char **data,
4024*7c478bd9Sstevel@tonic-gate     uint_t nelements)
4025*7c478bd9Sstevel@tonic-gate {
4026*7c478bd9Sstevel@tonic-gate 	int rv;
4027*7c478bd9Sstevel@tonic-gate 
4028*7c478bd9Sstevel@tonic-gate 	if (pip == NULL) {
4029*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
4030*7c478bd9Sstevel@tonic-gate 	}
4031*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
4032*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
4033*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_prop == NULL) {
4034*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
4035*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4036*7c478bd9Sstevel@tonic-gate 	}
4037*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_string_array(MDI_PI(pip)->pi_prop, name, data,
4038*7c478bd9Sstevel@tonic-gate 	    nelements);
4039*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
4040*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
4041*7c478bd9Sstevel@tonic-gate }
4042*7c478bd9Sstevel@tonic-gate 
4043*7c478bd9Sstevel@tonic-gate /*
4044*7c478bd9Sstevel@tonic-gate  * mdi_prop_lookup_byte():
4045*7c478bd9Sstevel@tonic-gate  * 		Look for byte property identified by name.  The data returned
4046*7c478bd9Sstevel@tonic-gate  *		is the actual property and valid as long as mdi_pathinfo_t node
4047*7c478bd9Sstevel@tonic-gate  *		is alive.
4048*7c478bd9Sstevel@tonic-gate  */
4049*7c478bd9Sstevel@tonic-gate int
4050*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte(mdi_pathinfo_t *pip, char *name, uchar_t *data)
4051*7c478bd9Sstevel@tonic-gate {
4052*7c478bd9Sstevel@tonic-gate 	int rv;
4053*7c478bd9Sstevel@tonic-gate 
4054*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4055*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4056*7c478bd9Sstevel@tonic-gate 	}
4057*7c478bd9Sstevel@tonic-gate 	rv = nvlist_lookup_byte(MDI_PI(pip)->pi_prop, name, data);
4058*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
4059*7c478bd9Sstevel@tonic-gate }
4060*7c478bd9Sstevel@tonic-gate 
4061*7c478bd9Sstevel@tonic-gate 
4062*7c478bd9Sstevel@tonic-gate /*
4063*7c478bd9Sstevel@tonic-gate  * mdi_prop_lookup_byte_array():
4064*7c478bd9Sstevel@tonic-gate  * 		Look for byte array property identified by name.  The data
4065*7c478bd9Sstevel@tonic-gate  *		returned is the actual property and valid as long as
4066*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo_t node is alive.
4067*7c478bd9Sstevel@tonic-gate  */
4068*7c478bd9Sstevel@tonic-gate int
4069*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t **data,
4070*7c478bd9Sstevel@tonic-gate     uint_t *nelements)
4071*7c478bd9Sstevel@tonic-gate {
4072*7c478bd9Sstevel@tonic-gate 	int rv;
4073*7c478bd9Sstevel@tonic-gate 
4074*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4075*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4076*7c478bd9Sstevel@tonic-gate 	}
4077*7c478bd9Sstevel@tonic-gate 	rv = nvlist_lookup_byte_array(MDI_PI(pip)->pi_prop, name, data,
4078*7c478bd9Sstevel@tonic-gate 	    nelements);
4079*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
4080*7c478bd9Sstevel@tonic-gate }
4081*7c478bd9Sstevel@tonic-gate 
4082*7c478bd9Sstevel@tonic-gate /*
4083*7c478bd9Sstevel@tonic-gate  * mdi_prop_lookup_int():
4084*7c478bd9Sstevel@tonic-gate  * 		Look for int property identified by name.  The data returned
4085*7c478bd9Sstevel@tonic-gate  *		is the actual property and valid as long as mdi_pathinfo_t
4086*7c478bd9Sstevel@tonic-gate  *		node is alive.
4087*7c478bd9Sstevel@tonic-gate  */
4088*7c478bd9Sstevel@tonic-gate int
4089*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_int(mdi_pathinfo_t *pip, char *name, int *data)
4090*7c478bd9Sstevel@tonic-gate {
4091*7c478bd9Sstevel@tonic-gate 	int rv;
4092*7c478bd9Sstevel@tonic-gate 
4093*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4094*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4095*7c478bd9Sstevel@tonic-gate 	}
4096*7c478bd9Sstevel@tonic-gate 	rv = nvlist_lookup_int32(MDI_PI(pip)->pi_prop, name, (int32_t *)data);
4097*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
4098*7c478bd9Sstevel@tonic-gate }
4099*7c478bd9Sstevel@tonic-gate 
4100*7c478bd9Sstevel@tonic-gate /*
4101*7c478bd9Sstevel@tonic-gate  * mdi_prop_lookup_int64():
4102*7c478bd9Sstevel@tonic-gate  * 		Look for int64 property identified by name.  The data returned
4103*7c478bd9Sstevel@tonic-gate  *		is the actual property and valid as long as mdi_pathinfo_t node
4104*7c478bd9Sstevel@tonic-gate  *		is alive.
4105*7c478bd9Sstevel@tonic-gate  */
4106*7c478bd9Sstevel@tonic-gate int
4107*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_int64(mdi_pathinfo_t *pip, char *name, int64_t *data)
4108*7c478bd9Sstevel@tonic-gate {
4109*7c478bd9Sstevel@tonic-gate 	int rv;
4110*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4111*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4112*7c478bd9Sstevel@tonic-gate 	}
4113*7c478bd9Sstevel@tonic-gate 	rv = nvlist_lookup_int64(MDI_PI(pip)->pi_prop, name, data);
4114*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
4115*7c478bd9Sstevel@tonic-gate }
4116*7c478bd9Sstevel@tonic-gate 
4117*7c478bd9Sstevel@tonic-gate /*
4118*7c478bd9Sstevel@tonic-gate  * mdi_prop_lookup_int_array():
4119*7c478bd9Sstevel@tonic-gate  * 		Look for int array property identified by name.  The data
4120*7c478bd9Sstevel@tonic-gate  *		returned is the actual property and valid as long as
4121*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo_t node is alive.
4122*7c478bd9Sstevel@tonic-gate  */
4123*7c478bd9Sstevel@tonic-gate int
4124*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_int_array(mdi_pathinfo_t *pip, char *name, int **data,
4125*7c478bd9Sstevel@tonic-gate     uint_t *nelements)
4126*7c478bd9Sstevel@tonic-gate {
4127*7c478bd9Sstevel@tonic-gate 	int rv;
4128*7c478bd9Sstevel@tonic-gate 
4129*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4130*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4131*7c478bd9Sstevel@tonic-gate 	}
4132*7c478bd9Sstevel@tonic-gate 	rv = nvlist_lookup_int32_array(MDI_PI(pip)->pi_prop, name,
4133*7c478bd9Sstevel@tonic-gate 	    (int32_t **)data, nelements);
4134*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
4135*7c478bd9Sstevel@tonic-gate }
4136*7c478bd9Sstevel@tonic-gate 
4137*7c478bd9Sstevel@tonic-gate /*
4138*7c478bd9Sstevel@tonic-gate  * mdi_prop_lookup_string():
4139*7c478bd9Sstevel@tonic-gate  * 		Look for string property identified by name.  The data
4140*7c478bd9Sstevel@tonic-gate  *		returned is the actual property and valid as long as
4141*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo_t node is alive.
4142*7c478bd9Sstevel@tonic-gate  */
4143*7c478bd9Sstevel@tonic-gate int
4144*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_string(mdi_pathinfo_t *pip, char *name, char **data)
4145*7c478bd9Sstevel@tonic-gate {
4146*7c478bd9Sstevel@tonic-gate 	int rv;
4147*7c478bd9Sstevel@tonic-gate 
4148*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4149*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4150*7c478bd9Sstevel@tonic-gate 	}
4151*7c478bd9Sstevel@tonic-gate 	rv = nvlist_lookup_string(MDI_PI(pip)->pi_prop, name, data);
4152*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
4153*7c478bd9Sstevel@tonic-gate }
4154*7c478bd9Sstevel@tonic-gate 
4155*7c478bd9Sstevel@tonic-gate /*
4156*7c478bd9Sstevel@tonic-gate  * mdi_prop_lookup_string_array():
4157*7c478bd9Sstevel@tonic-gate  * 		Look for string array property identified by name.  The data
4158*7c478bd9Sstevel@tonic-gate  *		returned is the actual property and valid as long as
4159*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo_t node is alive.
4160*7c478bd9Sstevel@tonic-gate  */
4161*7c478bd9Sstevel@tonic-gate 
4162*7c478bd9Sstevel@tonic-gate int
4163*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_string_array(mdi_pathinfo_t *pip, char *name, char ***data,
4164*7c478bd9Sstevel@tonic-gate     uint_t *nelements)
4165*7c478bd9Sstevel@tonic-gate {
4166*7c478bd9Sstevel@tonic-gate 	int rv;
4167*7c478bd9Sstevel@tonic-gate 
4168*7c478bd9Sstevel@tonic-gate 	if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4169*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4170*7c478bd9Sstevel@tonic-gate 	}
4171*7c478bd9Sstevel@tonic-gate 	rv = nvlist_lookup_string_array(MDI_PI(pip)->pi_prop, name, data,
4172*7c478bd9Sstevel@tonic-gate 	    nelements);
4173*7c478bd9Sstevel@tonic-gate 	return (i_map_nvlist_error_to_mdi(rv));
4174*7c478bd9Sstevel@tonic-gate }
4175*7c478bd9Sstevel@tonic-gate 
4176*7c478bd9Sstevel@tonic-gate /*
4177*7c478bd9Sstevel@tonic-gate  * mdi_prop_free():
4178*7c478bd9Sstevel@tonic-gate  * 		Symmetrical function to ddi_prop_free(). nvlist_lookup_xx()
4179*7c478bd9Sstevel@tonic-gate  *		functions return the pointer to actual property data and not a
4180*7c478bd9Sstevel@tonic-gate  *		copy of it.  So the data returned is valid as long as
4181*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo_t node is valid.
4182*7c478bd9Sstevel@tonic-gate  */
4183*7c478bd9Sstevel@tonic-gate 
4184*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4185*7c478bd9Sstevel@tonic-gate int
4186*7c478bd9Sstevel@tonic-gate mdi_prop_free(void *data)
4187*7c478bd9Sstevel@tonic-gate {
4188*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
4189*7c478bd9Sstevel@tonic-gate }
4190*7c478bd9Sstevel@tonic-gate 
4191*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4192*7c478bd9Sstevel@tonic-gate static void
4193*7c478bd9Sstevel@tonic-gate i_mdi_report_path_state(mdi_client_t *ct, mdi_pathinfo_t *pip)
4194*7c478bd9Sstevel@tonic-gate {
4195*7c478bd9Sstevel@tonic-gate 	char		*phci_path, *ct_path;
4196*7c478bd9Sstevel@tonic-gate 	char		*ct_status;
4197*7c478bd9Sstevel@tonic-gate 	char		*status;
4198*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = ct->ct_dip;
4199*7c478bd9Sstevel@tonic-gate 	char		lb_buf[64];
4200*7c478bd9Sstevel@tonic-gate 
4201*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ct->ct_mutex));
4202*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (ddi_get_instance(dip) == -1) ||
4203*7c478bd9Sstevel@tonic-gate 	    (MDI_CLIENT_IS_REPORT_DEV_NEEDED(ct) == 0)) {
4204*7c478bd9Sstevel@tonic-gate 		return;
4205*7c478bd9Sstevel@tonic-gate 	}
4206*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL) {
4207*7c478bd9Sstevel@tonic-gate 		ct_status = "optimal";
4208*7c478bd9Sstevel@tonic-gate 	} else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) {
4209*7c478bd9Sstevel@tonic-gate 		ct_status = "degraded";
4210*7c478bd9Sstevel@tonic-gate 	} else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) {
4211*7c478bd9Sstevel@tonic-gate 		ct_status = "failed";
4212*7c478bd9Sstevel@tonic-gate 	} else {
4213*7c478bd9Sstevel@tonic-gate 		ct_status = "unknown";
4214*7c478bd9Sstevel@tonic-gate 	}
4215*7c478bd9Sstevel@tonic-gate 
4216*7c478bd9Sstevel@tonic-gate 	if (MDI_PI_IS_OFFLINE(pip)) {
4217*7c478bd9Sstevel@tonic-gate 		status = "offline";
4218*7c478bd9Sstevel@tonic-gate 	} else if (MDI_PI_IS_ONLINE(pip)) {
4219*7c478bd9Sstevel@tonic-gate 		status = "online";
4220*7c478bd9Sstevel@tonic-gate 	} else if (MDI_PI_IS_STANDBY(pip)) {
4221*7c478bd9Sstevel@tonic-gate 		status = "standby";
4222*7c478bd9Sstevel@tonic-gate 	} else if (MDI_PI_IS_FAULT(pip)) {
4223*7c478bd9Sstevel@tonic-gate 		status = "faulted";
4224*7c478bd9Sstevel@tonic-gate 	} else {
4225*7c478bd9Sstevel@tonic-gate 		status = "unknown";
4226*7c478bd9Sstevel@tonic-gate 	}
4227*7c478bd9Sstevel@tonic-gate 
4228*7c478bd9Sstevel@tonic-gate 	if (ct->ct_lb == LOAD_BALANCE_LBA) {
4229*7c478bd9Sstevel@tonic-gate 		(void) snprintf(lb_buf, sizeof (lb_buf),
4230*7c478bd9Sstevel@tonic-gate 		    "%s, region-size: %d", mdi_load_balance_lba,
4231*7c478bd9Sstevel@tonic-gate 			ct->ct_lb_args->region_size);
4232*7c478bd9Sstevel@tonic-gate 	} else if (ct->ct_lb == LOAD_BALANCE_NONE) {
4233*7c478bd9Sstevel@tonic-gate 		(void) snprintf(lb_buf, sizeof (lb_buf),
4234*7c478bd9Sstevel@tonic-gate 		    "%s", mdi_load_balance_none);
4235*7c478bd9Sstevel@tonic-gate 	} else {
4236*7c478bd9Sstevel@tonic-gate 		(void) snprintf(lb_buf, sizeof (lb_buf), "%s",
4237*7c478bd9Sstevel@tonic-gate 		    mdi_load_balance_rr);
4238*7c478bd9Sstevel@tonic-gate 	}
4239*7c478bd9Sstevel@tonic-gate 
4240*7c478bd9Sstevel@tonic-gate 	if (dip) {
4241*7c478bd9Sstevel@tonic-gate 		ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4242*7c478bd9Sstevel@tonic-gate 		phci_path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4243*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s (%s%d) multipath status: %s, "
4244*7c478bd9Sstevel@tonic-gate 		    "path %s (%s%d) to target address: %s is %s"
4245*7c478bd9Sstevel@tonic-gate 		    " Load balancing: %s\n",
4246*7c478bd9Sstevel@tonic-gate 		    ddi_pathname(dip, ct_path), ddi_driver_name(dip),
4247*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(dip), ct_status,
4248*7c478bd9Sstevel@tonic-gate 		    ddi_pathname(MDI_PI(pip)->pi_phci->ph_dip, phci_path),
4249*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(MDI_PI(pip)->pi_phci->ph_dip),
4250*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(MDI_PI(pip)->pi_phci->ph_dip),
4251*7c478bd9Sstevel@tonic-gate 		    MDI_PI(pip)->pi_addr, status, lb_buf);
4252*7c478bd9Sstevel@tonic-gate 		kmem_free(phci_path, MAXPATHLEN);
4253*7c478bd9Sstevel@tonic-gate 		kmem_free(ct_path, MAXPATHLEN);
4254*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct);
4255*7c478bd9Sstevel@tonic-gate 	}
4256*7c478bd9Sstevel@tonic-gate }
4257*7c478bd9Sstevel@tonic-gate 
4258*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
4259*7c478bd9Sstevel@tonic-gate /*
4260*7c478bd9Sstevel@tonic-gate  * i_mdi_log():
4261*7c478bd9Sstevel@tonic-gate  *		Utility function for error message management
4262*7c478bd9Sstevel@tonic-gate  *
4263*7c478bd9Sstevel@tonic-gate  */
4264*7c478bd9Sstevel@tonic-gate 
4265*7c478bd9Sstevel@tonic-gate /*VARARGS3*/
4266*7c478bd9Sstevel@tonic-gate static void
4267*7c478bd9Sstevel@tonic-gate i_mdi_log(int level, dev_info_t *dip, const char *fmt, ...)
4268*7c478bd9Sstevel@tonic-gate {
4269*7c478bd9Sstevel@tonic-gate 	char		buf[MAXNAMELEN];
4270*7c478bd9Sstevel@tonic-gate 	char		name[MAXNAMELEN];
4271*7c478bd9Sstevel@tonic-gate 	va_list		ap;
4272*7c478bd9Sstevel@tonic-gate 	int		log_only = 0;
4273*7c478bd9Sstevel@tonic-gate 	int		boot_only = 0;
4274*7c478bd9Sstevel@tonic-gate 	int		console_only = 0;
4275*7c478bd9Sstevel@tonic-gate 
4276*7c478bd9Sstevel@tonic-gate 	if (dip) {
4277*7c478bd9Sstevel@tonic-gate 		if (level == CE_PANIC || level == CE_WARN || level == CE_NOTE) {
4278*7c478bd9Sstevel@tonic-gate 			(void) snprintf(name, MAXNAMELEN, "%s%d:\n",
4279*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(dip), ddi_get_instance(dip));
4280*7c478bd9Sstevel@tonic-gate 		} else {
4281*7c478bd9Sstevel@tonic-gate 			(void) snprintf(name, MAXNAMELEN, "%s%d:",
4282*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(dip), ddi_get_instance(dip));
4283*7c478bd9Sstevel@tonic-gate 		}
4284*7c478bd9Sstevel@tonic-gate 	} else {
4285*7c478bd9Sstevel@tonic-gate 		name[0] = '\0';
4286*7c478bd9Sstevel@tonic-gate 	}
4287*7c478bd9Sstevel@tonic-gate 
4288*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
4289*7c478bd9Sstevel@tonic-gate 	(void) vsnprintf(buf, MAXNAMELEN, fmt, ap);
4290*7c478bd9Sstevel@tonic-gate 	va_end(ap);
4291*7c478bd9Sstevel@tonic-gate 
4292*7c478bd9Sstevel@tonic-gate 	switch (buf[0]) {
4293*7c478bd9Sstevel@tonic-gate 	case '!':
4294*7c478bd9Sstevel@tonic-gate 		log_only = 1;
4295*7c478bd9Sstevel@tonic-gate 		break;
4296*7c478bd9Sstevel@tonic-gate 	case '?':
4297*7c478bd9Sstevel@tonic-gate 		boot_only = 1;
4298*7c478bd9Sstevel@tonic-gate 		break;
4299*7c478bd9Sstevel@tonic-gate 	case '^':
4300*7c478bd9Sstevel@tonic-gate 		console_only = 1;
4301*7c478bd9Sstevel@tonic-gate 		break;
4302*7c478bd9Sstevel@tonic-gate 	}
4303*7c478bd9Sstevel@tonic-gate 
4304*7c478bd9Sstevel@tonic-gate 	switch (level) {
4305*7c478bd9Sstevel@tonic-gate 	case CE_NOTE:
4306*7c478bd9Sstevel@tonic-gate 		level = CE_CONT;
4307*7c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
4308*7c478bd9Sstevel@tonic-gate 	case CE_CONT:
4309*7c478bd9Sstevel@tonic-gate 	case CE_WARN:
4310*7c478bd9Sstevel@tonic-gate 	case CE_PANIC:
4311*7c478bd9Sstevel@tonic-gate 		if (boot_only) {
4312*7c478bd9Sstevel@tonic-gate 			cmn_err(level, "?%s\t%s", name, &buf[1]);
4313*7c478bd9Sstevel@tonic-gate 		} else if (console_only) {
4314*7c478bd9Sstevel@tonic-gate 			cmn_err(level, "^%s\t%s", name, &buf[1]);
4315*7c478bd9Sstevel@tonic-gate 		} else if (log_only) {
4316*7c478bd9Sstevel@tonic-gate 			cmn_err(level, "!%s\t%s", name, &buf[1]);
4317*7c478bd9Sstevel@tonic-gate 		} else {
4318*7c478bd9Sstevel@tonic-gate 			cmn_err(level, "%s\t%s", name, buf);
4319*7c478bd9Sstevel@tonic-gate 		}
4320*7c478bd9Sstevel@tonic-gate 		break;
4321*7c478bd9Sstevel@tonic-gate 	default:
4322*7c478bd9Sstevel@tonic-gate 		cmn_err(level, "%s\t%s", name, buf);
4323*7c478bd9Sstevel@tonic-gate 		break;
4324*7c478bd9Sstevel@tonic-gate 	}
4325*7c478bd9Sstevel@tonic-gate }
4326*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
4327*7c478bd9Sstevel@tonic-gate 
4328*7c478bd9Sstevel@tonic-gate void
4329*7c478bd9Sstevel@tonic-gate i_mdi_client_online(dev_info_t *ct_dip)
4330*7c478bd9Sstevel@tonic-gate {
4331*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
4332*7c478bd9Sstevel@tonic-gate 
4333*7c478bd9Sstevel@tonic-gate 	/*
4334*7c478bd9Sstevel@tonic-gate 	 * Client online notification. Mark client state as online
4335*7c478bd9Sstevel@tonic-gate 	 * restore our binding with dev_info node
4336*7c478bd9Sstevel@tonic-gate 	 */
4337*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(ct_dip);
4338*7c478bd9Sstevel@tonic-gate 	ASSERT(ct != NULL);
4339*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
4340*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_SET_ONLINE(ct);
4341*7c478bd9Sstevel@tonic-gate 	/* catch for any memory leaks */
4342*7c478bd9Sstevel@tonic-gate 	ASSERT((ct->ct_dip == NULL) || (ct->ct_dip == ct_dip));
4343*7c478bd9Sstevel@tonic-gate 	ct->ct_dip = ct_dip;
4344*7c478bd9Sstevel@tonic-gate 
4345*7c478bd9Sstevel@tonic-gate 	if (ct->ct_power_cnt == 0)
4346*7c478bd9Sstevel@tonic-gate 		(void) i_mdi_power_all_phci(ct);
4347*7c478bd9Sstevel@tonic-gate 
4348*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ct_dip, "i_mdi_client_online "
4349*7c478bd9Sstevel@tonic-gate 	    "i_mdi_pm_hold_client\n"));
4350*7c478bd9Sstevel@tonic-gate 	i_mdi_pm_hold_client(ct, 1);
4351*7c478bd9Sstevel@tonic-gate 
4352*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
4353*7c478bd9Sstevel@tonic-gate }
4354*7c478bd9Sstevel@tonic-gate 
4355*7c478bd9Sstevel@tonic-gate void
4356*7c478bd9Sstevel@tonic-gate i_mdi_phci_online(dev_info_t *ph_dip)
4357*7c478bd9Sstevel@tonic-gate {
4358*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
4359*7c478bd9Sstevel@tonic-gate 
4360*7c478bd9Sstevel@tonic-gate 	/* pHCI online notification. Mark state accordingly */
4361*7c478bd9Sstevel@tonic-gate 	ph = i_devi_get_phci(ph_dip);
4362*7c478bd9Sstevel@tonic-gate 	ASSERT(ph != NULL);
4363*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_LOCK(ph);
4364*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_SET_ONLINE(ph);
4365*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNLOCK(ph);
4366*7c478bd9Sstevel@tonic-gate }
4367*7c478bd9Sstevel@tonic-gate 
4368*7c478bd9Sstevel@tonic-gate /*
4369*7c478bd9Sstevel@tonic-gate  * mdi_devi_online():
4370*7c478bd9Sstevel@tonic-gate  * 		Online notification from NDI framework on pHCI/client
4371*7c478bd9Sstevel@tonic-gate  *		device online.
4372*7c478bd9Sstevel@tonic-gate  * Return Values:
4373*7c478bd9Sstevel@tonic-gate  *		NDI_SUCCESS
4374*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
4375*7c478bd9Sstevel@tonic-gate  */
4376*7c478bd9Sstevel@tonic-gate 
4377*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4378*7c478bd9Sstevel@tonic-gate int
4379*7c478bd9Sstevel@tonic-gate mdi_devi_online(dev_info_t *dip, uint_t flags)
4380*7c478bd9Sstevel@tonic-gate {
4381*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI(dip)) {
4382*7c478bd9Sstevel@tonic-gate 		i_mdi_phci_online(dip);
4383*7c478bd9Sstevel@tonic-gate 	}
4384*7c478bd9Sstevel@tonic-gate 
4385*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT(dip)) {
4386*7c478bd9Sstevel@tonic-gate 		i_mdi_client_online(dip);
4387*7c478bd9Sstevel@tonic-gate 	}
4388*7c478bd9Sstevel@tonic-gate 	return (NDI_SUCCESS);
4389*7c478bd9Sstevel@tonic-gate }
4390*7c478bd9Sstevel@tonic-gate 
4391*7c478bd9Sstevel@tonic-gate /*
4392*7c478bd9Sstevel@tonic-gate  * mdi_devi_offline():
4393*7c478bd9Sstevel@tonic-gate  * 		Offline notification from NDI framework on pHCI/Client device
4394*7c478bd9Sstevel@tonic-gate  *		offline.
4395*7c478bd9Sstevel@tonic-gate  *
4396*7c478bd9Sstevel@tonic-gate  * Return Values:
4397*7c478bd9Sstevel@tonic-gate  *		NDI_SUCCESS
4398*7c478bd9Sstevel@tonic-gate  *		NDI_FAILURE
4399*7c478bd9Sstevel@tonic-gate  */
4400*7c478bd9Sstevel@tonic-gate 
4401*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4402*7c478bd9Sstevel@tonic-gate int
4403*7c478bd9Sstevel@tonic-gate mdi_devi_offline(dev_info_t *dip, uint_t flags)
4404*7c478bd9Sstevel@tonic-gate {
4405*7c478bd9Sstevel@tonic-gate 	int		rv = NDI_SUCCESS;
4406*7c478bd9Sstevel@tonic-gate 
4407*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT(dip)) {
4408*7c478bd9Sstevel@tonic-gate 		rv = i_mdi_client_offline(dip, flags);
4409*7c478bd9Sstevel@tonic-gate 		if (rv != NDI_SUCCESS)
4410*7c478bd9Sstevel@tonic-gate 			return (rv);
4411*7c478bd9Sstevel@tonic-gate 	}
4412*7c478bd9Sstevel@tonic-gate 
4413*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI(dip)) {
4414*7c478bd9Sstevel@tonic-gate 		rv = i_mdi_phci_offline(dip, flags);
4415*7c478bd9Sstevel@tonic-gate 		if ((rv != NDI_SUCCESS) && MDI_CLIENT(dip)) {
4416*7c478bd9Sstevel@tonic-gate 			/* set client back online */
4417*7c478bd9Sstevel@tonic-gate 			i_mdi_client_online(dip);
4418*7c478bd9Sstevel@tonic-gate 		}
4419*7c478bd9Sstevel@tonic-gate 	}
4420*7c478bd9Sstevel@tonic-gate 
4421*7c478bd9Sstevel@tonic-gate 	return (rv);
4422*7c478bd9Sstevel@tonic-gate }
4423*7c478bd9Sstevel@tonic-gate 
4424*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4425*7c478bd9Sstevel@tonic-gate static int
4426*7c478bd9Sstevel@tonic-gate i_mdi_phci_offline(dev_info_t *dip, uint_t flags)
4427*7c478bd9Sstevel@tonic-gate {
4428*7c478bd9Sstevel@tonic-gate 	int		rv = NDI_SUCCESS;
4429*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
4430*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
4431*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*pip;
4432*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*next;
4433*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*failed_pip = NULL;
4434*7c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip;
4435*7c478bd9Sstevel@tonic-gate 
4436*7c478bd9Sstevel@tonic-gate 	/*
4437*7c478bd9Sstevel@tonic-gate 	 * pHCI component offline notification
4438*7c478bd9Sstevel@tonic-gate 	 * Make sure that this pHCI instance is free to be offlined.
4439*7c478bd9Sstevel@tonic-gate 	 * If it is OK to proceed, Offline and remove all the child
4440*7c478bd9Sstevel@tonic-gate 	 * mdi_pathinfo nodes.  This process automatically offlines
4441*7c478bd9Sstevel@tonic-gate 	 * corresponding client devices, for which this pHCI provides
4442*7c478bd9Sstevel@tonic-gate 	 * critical services.
4443*7c478bd9Sstevel@tonic-gate 	 */
4444*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(2, (CE_NOTE, dip, "!mdi_phci_offline called %p\n",
4445*7c478bd9Sstevel@tonic-gate 	    dip));
4446*7c478bd9Sstevel@tonic-gate 
4447*7c478bd9Sstevel@tonic-gate 	ph = i_devi_get_phci(dip);
4448*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
4449*7c478bd9Sstevel@tonic-gate 		return (rv);
4450*7c478bd9Sstevel@tonic-gate 	}
4451*7c478bd9Sstevel@tonic-gate 
4452*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_LOCK(ph);
4453*7c478bd9Sstevel@tonic-gate 
4454*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI_IS_OFFLINE(ph)) {
4455*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, dip, "!pHCI %p already offlined", ph));
4456*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_UNLOCK(ph);
4457*7c478bd9Sstevel@tonic-gate 		return (NDI_SUCCESS);
4458*7c478bd9Sstevel@tonic-gate 	}
4459*7c478bd9Sstevel@tonic-gate 
4460*7c478bd9Sstevel@tonic-gate 	/*
4461*7c478bd9Sstevel@tonic-gate 	 * Check to see if the pHCI can be offlined
4462*7c478bd9Sstevel@tonic-gate 	 */
4463*7c478bd9Sstevel@tonic-gate 	if (ph->ph_unstable) {
4464*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_WARN, dip,
4465*7c478bd9Sstevel@tonic-gate 		    "!One or more target devices are in transient "
4466*7c478bd9Sstevel@tonic-gate 		    "state. This device can not be removed at "
4467*7c478bd9Sstevel@tonic-gate 		    "this moment. Please try again later."));
4468*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_UNLOCK(ph);
4469*7c478bd9Sstevel@tonic-gate 		return (NDI_BUSY);
4470*7c478bd9Sstevel@tonic-gate 	}
4471*7c478bd9Sstevel@tonic-gate 
4472*7c478bd9Sstevel@tonic-gate 	pip = ph->ph_path_head;
4473*7c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
4474*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
4475*7c478bd9Sstevel@tonic-gate 		next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
4476*7c478bd9Sstevel@tonic-gate 		/*
4477*7c478bd9Sstevel@tonic-gate 		 * The mdi_pathinfo state is OK. Check the client state.
4478*7c478bd9Sstevel@tonic-gate 		 * If failover in progress fail the pHCI from offlining
4479*7c478bd9Sstevel@tonic-gate 		 */
4480*7c478bd9Sstevel@tonic-gate 		ct = MDI_PI(pip)->pi_client;
4481*7c478bd9Sstevel@tonic-gate 		i_mdi_client_lock(ct, pip);
4482*7c478bd9Sstevel@tonic-gate 		if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) ||
4483*7c478bd9Sstevel@tonic-gate 		    (ct->ct_unstable)) {
4484*7c478bd9Sstevel@tonic-gate 			/*
4485*7c478bd9Sstevel@tonic-gate 			 * Failover is in progress, Fail the DR
4486*7c478bd9Sstevel@tonic-gate 			 */
4487*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_WARN, dip,
4488*7c478bd9Sstevel@tonic-gate 			    "!pHCI device (%s%d) is Busy. %s",
4489*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
4490*7c478bd9Sstevel@tonic-gate 			    "This device can not be removed at "
4491*7c478bd9Sstevel@tonic-gate 			    "this moment. Please try again later."));
4492*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
4493*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
4494*7c478bd9Sstevel@tonic-gate 			MDI_PHCI_UNLOCK(ph);
4495*7c478bd9Sstevel@tonic-gate 			return (NDI_BUSY);
4496*7c478bd9Sstevel@tonic-gate 		}
4497*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
4498*7c478bd9Sstevel@tonic-gate 
4499*7c478bd9Sstevel@tonic-gate 		/*
4500*7c478bd9Sstevel@tonic-gate 		 * Check to see of we are removing the last path of this
4501*7c478bd9Sstevel@tonic-gate 		 * client device...
4502*7c478bd9Sstevel@tonic-gate 		 */
4503*7c478bd9Sstevel@tonic-gate 		cdip = ct->ct_dip;
4504*7c478bd9Sstevel@tonic-gate 		if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) &&
4505*7c478bd9Sstevel@tonic-gate 		    (i_mdi_client_compute_state(ct, ph) ==
4506*7c478bd9Sstevel@tonic-gate 		    MDI_CLIENT_STATE_FAILED)) {
4507*7c478bd9Sstevel@tonic-gate 			i_mdi_client_unlock(ct);
4508*7c478bd9Sstevel@tonic-gate 			MDI_PHCI_UNLOCK(ph);
4509*7c478bd9Sstevel@tonic-gate 			if (ndi_devi_offline(cdip, 0) != NDI_SUCCESS) {
4510*7c478bd9Sstevel@tonic-gate 				/*
4511*7c478bd9Sstevel@tonic-gate 				 * ndi_devi_offline() failed.
4512*7c478bd9Sstevel@tonic-gate 				 * This pHCI provides the critical path
4513*7c478bd9Sstevel@tonic-gate 				 * to one or more client devices.
4514*7c478bd9Sstevel@tonic-gate 				 * Return busy.
4515*7c478bd9Sstevel@tonic-gate 				 */
4516*7c478bd9Sstevel@tonic-gate 				MDI_PHCI_LOCK(ph);
4517*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(1, (CE_WARN, dip,
4518*7c478bd9Sstevel@tonic-gate 				    "!pHCI device (%s%d) is Busy. %s",
4519*7c478bd9Sstevel@tonic-gate 				    ddi_driver_name(dip), ddi_get_instance(dip),
4520*7c478bd9Sstevel@tonic-gate 				    "This device can not be removed at "
4521*7c478bd9Sstevel@tonic-gate 				    "this moment. Please try again later."));
4522*7c478bd9Sstevel@tonic-gate 				failed_pip = pip;
4523*7c478bd9Sstevel@tonic-gate 				break;
4524*7c478bd9Sstevel@tonic-gate 			} else {
4525*7c478bd9Sstevel@tonic-gate 				MDI_PHCI_LOCK(ph);
4526*7c478bd9Sstevel@tonic-gate 				pip = next;
4527*7c478bd9Sstevel@tonic-gate 			}
4528*7c478bd9Sstevel@tonic-gate 		} else {
4529*7c478bd9Sstevel@tonic-gate 			i_mdi_client_unlock(ct);
4530*7c478bd9Sstevel@tonic-gate 			pip = next;
4531*7c478bd9Sstevel@tonic-gate 		}
4532*7c478bd9Sstevel@tonic-gate 	}
4533*7c478bd9Sstevel@tonic-gate 
4534*7c478bd9Sstevel@tonic-gate 	if (failed_pip) {
4535*7c478bd9Sstevel@tonic-gate 		pip = ph->ph_path_head;
4536*7c478bd9Sstevel@tonic-gate 		while (pip != failed_pip) {
4537*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
4538*7c478bd9Sstevel@tonic-gate 			next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
4539*7c478bd9Sstevel@tonic-gate 			ct = MDI_PI(pip)->pi_client;
4540*7c478bd9Sstevel@tonic-gate 			i_mdi_client_lock(ct, pip);
4541*7c478bd9Sstevel@tonic-gate 			cdip = ct->ct_dip;
4542*7c478bd9Sstevel@tonic-gate 			switch (MDI_CLIENT_STATE(ct)) {
4543*7c478bd9Sstevel@tonic-gate 			case MDI_CLIENT_STATE_OPTIMAL:
4544*7c478bd9Sstevel@tonic-gate 			case MDI_CLIENT_STATE_DEGRADED:
4545*7c478bd9Sstevel@tonic-gate 				if (cdip) {
4546*7c478bd9Sstevel@tonic-gate 					MDI_PI_UNLOCK(pip);
4547*7c478bd9Sstevel@tonic-gate 					i_mdi_client_unlock(ct);
4548*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_UNLOCK(ph);
4549*7c478bd9Sstevel@tonic-gate 					(void) ndi_devi_online(cdip, 0);
4550*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_LOCK(ph);
4551*7c478bd9Sstevel@tonic-gate 					pip = next;
4552*7c478bd9Sstevel@tonic-gate 					continue;
4553*7c478bd9Sstevel@tonic-gate 				}
4554*7c478bd9Sstevel@tonic-gate 				break;
4555*7c478bd9Sstevel@tonic-gate 
4556*7c478bd9Sstevel@tonic-gate 			case MDI_CLIENT_STATE_FAILED:
4557*7c478bd9Sstevel@tonic-gate 				if (cdip) {
4558*7c478bd9Sstevel@tonic-gate 					MDI_PI_UNLOCK(pip);
4559*7c478bd9Sstevel@tonic-gate 					i_mdi_client_unlock(ct);
4560*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_UNLOCK(ph);
4561*7c478bd9Sstevel@tonic-gate 					(void) ndi_devi_offline(cdip, 0);
4562*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_LOCK(ph);
4563*7c478bd9Sstevel@tonic-gate 					pip = next;
4564*7c478bd9Sstevel@tonic-gate 					continue;
4565*7c478bd9Sstevel@tonic-gate 				}
4566*7c478bd9Sstevel@tonic-gate 				break;
4567*7c478bd9Sstevel@tonic-gate 			}
4568*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
4569*7c478bd9Sstevel@tonic-gate 			i_mdi_client_unlock(ct);
4570*7c478bd9Sstevel@tonic-gate 			pip = next;
4571*7c478bd9Sstevel@tonic-gate 		}
4572*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_UNLOCK(ph);
4573*7c478bd9Sstevel@tonic-gate 		return (NDI_BUSY);
4574*7c478bd9Sstevel@tonic-gate 	}
4575*7c478bd9Sstevel@tonic-gate 
4576*7c478bd9Sstevel@tonic-gate 	/*
4577*7c478bd9Sstevel@tonic-gate 	 * Mark the pHCI as offline
4578*7c478bd9Sstevel@tonic-gate 	 */
4579*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_SET_OFFLINE(ph);
4580*7c478bd9Sstevel@tonic-gate 
4581*7c478bd9Sstevel@tonic-gate 	/*
4582*7c478bd9Sstevel@tonic-gate 	 * Mark the child mdi_pathinfo nodes as transient
4583*7c478bd9Sstevel@tonic-gate 	 */
4584*7c478bd9Sstevel@tonic-gate 	pip = ph->ph_path_head;
4585*7c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
4586*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
4587*7c478bd9Sstevel@tonic-gate 		next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
4588*7c478bd9Sstevel@tonic-gate 		MDI_PI_SET_OFFLINING(pip);
4589*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
4590*7c478bd9Sstevel@tonic-gate 		pip = next;
4591*7c478bd9Sstevel@tonic-gate 	}
4592*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNLOCK(ph);
4593*7c478bd9Sstevel@tonic-gate 	/*
4594*7c478bd9Sstevel@tonic-gate 	 * Give a chance for any pending commands to execute
4595*7c478bd9Sstevel@tonic-gate 	 */
4596*7c478bd9Sstevel@tonic-gate 	delay(1);
4597*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_LOCK(ph);
4598*7c478bd9Sstevel@tonic-gate 	pip = ph->ph_path_head;
4599*7c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
4600*7c478bd9Sstevel@tonic-gate 		next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
4601*7c478bd9Sstevel@tonic-gate 		(void) i_mdi_pi_offline(pip, flags);
4602*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
4603*7c478bd9Sstevel@tonic-gate 		ct = MDI_PI(pip)->pi_client;
4604*7c478bd9Sstevel@tonic-gate 		if (!MDI_PI_IS_OFFLINE(pip)) {
4605*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_WARN, dip,
4606*7c478bd9Sstevel@tonic-gate 			    "!pHCI device (%s%d) is Busy. %s",
4607*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
4608*7c478bd9Sstevel@tonic-gate 			    "This device can not be removed at "
4609*7c478bd9Sstevel@tonic-gate 			    "this moment. Please try again later."));
4610*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
4611*7c478bd9Sstevel@tonic-gate 			MDI_PHCI_SET_ONLINE(ph);
4612*7c478bd9Sstevel@tonic-gate 			MDI_PHCI_UNLOCK(ph);
4613*7c478bd9Sstevel@tonic-gate 			return (NDI_BUSY);
4614*7c478bd9Sstevel@tonic-gate 		}
4615*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
4616*7c478bd9Sstevel@tonic-gate 		pip = next;
4617*7c478bd9Sstevel@tonic-gate 	}
4618*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNLOCK(ph);
4619*7c478bd9Sstevel@tonic-gate 
4620*7c478bd9Sstevel@tonic-gate 	return (rv);
4621*7c478bd9Sstevel@tonic-gate }
4622*7c478bd9Sstevel@tonic-gate 
4623*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4624*7c478bd9Sstevel@tonic-gate static int
4625*7c478bd9Sstevel@tonic-gate i_mdi_client_offline(dev_info_t *dip, uint_t flags)
4626*7c478bd9Sstevel@tonic-gate {
4627*7c478bd9Sstevel@tonic-gate 	int		rv = NDI_SUCCESS;
4628*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
4629*7c478bd9Sstevel@tonic-gate 
4630*7c478bd9Sstevel@tonic-gate 	/*
4631*7c478bd9Sstevel@tonic-gate 	 * Client component to go offline.  Make sure that we are
4632*7c478bd9Sstevel@tonic-gate 	 * not in failing over state and update client state
4633*7c478bd9Sstevel@tonic-gate 	 * accordingly
4634*7c478bd9Sstevel@tonic-gate 	 */
4635*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(2, (CE_NOTE, dip, "!i_mdi_client_offline called %p\n",
4636*7c478bd9Sstevel@tonic-gate 	    dip));
4637*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(dip);
4638*7c478bd9Sstevel@tonic-gate 	if (ct != NULL) {
4639*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_LOCK(ct);
4640*7c478bd9Sstevel@tonic-gate 		if (ct->ct_unstable) {
4641*7c478bd9Sstevel@tonic-gate 			/*
4642*7c478bd9Sstevel@tonic-gate 			 * One or more paths are in transient state,
4643*7c478bd9Sstevel@tonic-gate 			 * Dont allow offline of a client device
4644*7c478bd9Sstevel@tonic-gate 			 */
4645*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_WARN, dip,
4646*7c478bd9Sstevel@tonic-gate 			    "!One or more paths to this device is "
4647*7c478bd9Sstevel@tonic-gate 			    "in transient state. This device can not "
4648*7c478bd9Sstevel@tonic-gate 			    "be removed at this moment. "
4649*7c478bd9Sstevel@tonic-gate 			    "Please try again later."));
4650*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
4651*7c478bd9Sstevel@tonic-gate 			return (NDI_BUSY);
4652*7c478bd9Sstevel@tonic-gate 		}
4653*7c478bd9Sstevel@tonic-gate 		if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) {
4654*7c478bd9Sstevel@tonic-gate 			/*
4655*7c478bd9Sstevel@tonic-gate 			 * Failover is in progress, Dont allow DR of
4656*7c478bd9Sstevel@tonic-gate 			 * a client device
4657*7c478bd9Sstevel@tonic-gate 			 */
4658*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_WARN, dip,
4659*7c478bd9Sstevel@tonic-gate 			    "!Client device (%s%d) is Busy. %s",
4660*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip),
4661*7c478bd9Sstevel@tonic-gate 			    "This device can not be removed at "
4662*7c478bd9Sstevel@tonic-gate 			    "this moment. Please try again later."));
4663*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_UNLOCK(ct);
4664*7c478bd9Sstevel@tonic-gate 			return (NDI_BUSY);
4665*7c478bd9Sstevel@tonic-gate 		}
4666*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_SET_OFFLINE(ct);
4667*7c478bd9Sstevel@tonic-gate 
4668*7c478bd9Sstevel@tonic-gate 		/*
4669*7c478bd9Sstevel@tonic-gate 		 * Unbind our relationship with the dev_info node
4670*7c478bd9Sstevel@tonic-gate 		 */
4671*7c478bd9Sstevel@tonic-gate 		if (flags & NDI_DEVI_REMOVE) {
4672*7c478bd9Sstevel@tonic-gate 			ct->ct_dip = NULL;
4673*7c478bd9Sstevel@tonic-gate 		}
4674*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
4675*7c478bd9Sstevel@tonic-gate 	}
4676*7c478bd9Sstevel@tonic-gate 	return (rv);
4677*7c478bd9Sstevel@tonic-gate }
4678*7c478bd9Sstevel@tonic-gate 
4679*7c478bd9Sstevel@tonic-gate /*
4680*7c478bd9Sstevel@tonic-gate  * mdi_pre_attach():
4681*7c478bd9Sstevel@tonic-gate  *		Pre attach() notification handler
4682*7c478bd9Sstevel@tonic-gate  */
4683*7c478bd9Sstevel@tonic-gate 
4684*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4685*7c478bd9Sstevel@tonic-gate int
4686*7c478bd9Sstevel@tonic-gate mdi_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4687*7c478bd9Sstevel@tonic-gate {
4688*7c478bd9Sstevel@tonic-gate 	/* don't support old DDI_PM_RESUME */
4689*7c478bd9Sstevel@tonic-gate 	if ((DEVI(dip)->devi_mdi_component != MDI_COMPONENT_NONE) &&
4690*7c478bd9Sstevel@tonic-gate 	    (cmd == DDI_PM_RESUME))
4691*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4692*7c478bd9Sstevel@tonic-gate 
4693*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4694*7c478bd9Sstevel@tonic-gate }
4695*7c478bd9Sstevel@tonic-gate 
4696*7c478bd9Sstevel@tonic-gate /*
4697*7c478bd9Sstevel@tonic-gate  * mdi_post_attach():
4698*7c478bd9Sstevel@tonic-gate  *		Post attach() notification handler
4699*7c478bd9Sstevel@tonic-gate  */
4700*7c478bd9Sstevel@tonic-gate 
4701*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4702*7c478bd9Sstevel@tonic-gate void
4703*7c478bd9Sstevel@tonic-gate mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error)
4704*7c478bd9Sstevel@tonic-gate {
4705*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
4706*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
4707*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*pip;
4708*7c478bd9Sstevel@tonic-gate 
4709*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI(dip)) {
4710*7c478bd9Sstevel@tonic-gate 		ph = i_devi_get_phci(dip);
4711*7c478bd9Sstevel@tonic-gate 		ASSERT(ph != NULL);
4712*7c478bd9Sstevel@tonic-gate 
4713*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_LOCK(ph);
4714*7c478bd9Sstevel@tonic-gate 		switch (cmd) {
4715*7c478bd9Sstevel@tonic-gate 		case DDI_ATTACH:
4716*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(2, (CE_NOTE, dip,
4717*7c478bd9Sstevel@tonic-gate 			    "!pHCI post_attach: called %p\n", ph));
4718*7c478bd9Sstevel@tonic-gate 			if (error == DDI_SUCCESS) {
4719*7c478bd9Sstevel@tonic-gate 				MDI_PHCI_SET_ATTACH(ph);
4720*7c478bd9Sstevel@tonic-gate 			} else {
4721*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(1, (CE_NOTE, dip,
4722*7c478bd9Sstevel@tonic-gate 				    "!pHCI post_attach: failed error=%d\n",
4723*7c478bd9Sstevel@tonic-gate 				    error));
4724*7c478bd9Sstevel@tonic-gate 				MDI_PHCI_SET_DETACH(ph);
4725*7c478bd9Sstevel@tonic-gate 			}
4726*7c478bd9Sstevel@tonic-gate 			break;
4727*7c478bd9Sstevel@tonic-gate 
4728*7c478bd9Sstevel@tonic-gate 		case DDI_RESUME:
4729*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(2, (CE_NOTE, dip,
4730*7c478bd9Sstevel@tonic-gate 			    "!pHCI post_resume: called %p\n", ph));
4731*7c478bd9Sstevel@tonic-gate 			if (error == DDI_SUCCESS) {
4732*7c478bd9Sstevel@tonic-gate 				MDI_PHCI_SET_RESUME(ph);
4733*7c478bd9Sstevel@tonic-gate 			} else {
4734*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(1, (CE_NOTE, dip,
4735*7c478bd9Sstevel@tonic-gate 				    "!pHCI post_resume: failed error=%d\n",
4736*7c478bd9Sstevel@tonic-gate 				    error));
4737*7c478bd9Sstevel@tonic-gate 				MDI_PHCI_SET_SUSPEND(ph);
4738*7c478bd9Sstevel@tonic-gate 			}
4739*7c478bd9Sstevel@tonic-gate 			break;
4740*7c478bd9Sstevel@tonic-gate 		}
4741*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_UNLOCK(ph);
4742*7c478bd9Sstevel@tonic-gate 	}
4743*7c478bd9Sstevel@tonic-gate 
4744*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT(dip)) {
4745*7c478bd9Sstevel@tonic-gate 		ct = i_devi_get_client(dip);
4746*7c478bd9Sstevel@tonic-gate 		ASSERT(ct != NULL);
4747*7c478bd9Sstevel@tonic-gate 
4748*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_LOCK(ct);
4749*7c478bd9Sstevel@tonic-gate 		switch (cmd) {
4750*7c478bd9Sstevel@tonic-gate 		case DDI_ATTACH:
4751*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(2, (CE_NOTE, dip,
4752*7c478bd9Sstevel@tonic-gate 			    "!Client post_attach: called %p\n", ct));
4753*7c478bd9Sstevel@tonic-gate 			if (error != DDI_SUCCESS) {
4754*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(1, (CE_NOTE, dip,
4755*7c478bd9Sstevel@tonic-gate 				    "!Client post_attach: failed error=%d\n",
4756*7c478bd9Sstevel@tonic-gate 				    error));
4757*7c478bd9Sstevel@tonic-gate 				MDI_CLIENT_SET_DETACH(ct);
4758*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(4, (CE_WARN, dip,
4759*7c478bd9Sstevel@tonic-gate 				    "mdi_post_attach i_mdi_pm_reset_client\n"));
4760*7c478bd9Sstevel@tonic-gate 				i_mdi_pm_reset_client(ct);
4761*7c478bd9Sstevel@tonic-gate 				break;
4762*7c478bd9Sstevel@tonic-gate 			}
4763*7c478bd9Sstevel@tonic-gate 
4764*7c478bd9Sstevel@tonic-gate 			/*
4765*7c478bd9Sstevel@tonic-gate 			 * Client device has successfully attached.
4766*7c478bd9Sstevel@tonic-gate 			 * Create kstats for any pathinfo structures
4767*7c478bd9Sstevel@tonic-gate 			 * initially associated with this client.
4768*7c478bd9Sstevel@tonic-gate 			 */
4769*7c478bd9Sstevel@tonic-gate 			for (pip = ct->ct_path_head; pip != NULL;
4770*7c478bd9Sstevel@tonic-gate 			    pip = (mdi_pathinfo_t *)
4771*7c478bd9Sstevel@tonic-gate 			    MDI_PI(pip)->pi_client_link) {
4772*7c478bd9Sstevel@tonic-gate 				(void) i_mdi_pi_kstat_create(pip);
4773*7c478bd9Sstevel@tonic-gate 				i_mdi_report_path_state(ct, pip);
4774*7c478bd9Sstevel@tonic-gate 			}
4775*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_SET_ATTACH(ct);
4776*7c478bd9Sstevel@tonic-gate 			break;
4777*7c478bd9Sstevel@tonic-gate 
4778*7c478bd9Sstevel@tonic-gate 		case DDI_RESUME:
4779*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(2, (CE_NOTE, dip,
4780*7c478bd9Sstevel@tonic-gate 			    "!Client post_attach: called %p\n", ct));
4781*7c478bd9Sstevel@tonic-gate 			if (error == DDI_SUCCESS) {
4782*7c478bd9Sstevel@tonic-gate 				MDI_CLIENT_SET_RESUME(ct);
4783*7c478bd9Sstevel@tonic-gate 			} else {
4784*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(1, (CE_NOTE, dip,
4785*7c478bd9Sstevel@tonic-gate 				    "!Client post_resume: failed error=%d\n",
4786*7c478bd9Sstevel@tonic-gate 				    error));
4787*7c478bd9Sstevel@tonic-gate 				MDI_CLIENT_SET_SUSPEND(ct);
4788*7c478bd9Sstevel@tonic-gate 			}
4789*7c478bd9Sstevel@tonic-gate 			break;
4790*7c478bd9Sstevel@tonic-gate 		}
4791*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
4792*7c478bd9Sstevel@tonic-gate 	}
4793*7c478bd9Sstevel@tonic-gate }
4794*7c478bd9Sstevel@tonic-gate 
4795*7c478bd9Sstevel@tonic-gate /*
4796*7c478bd9Sstevel@tonic-gate  * mdi_pre_detach():
4797*7c478bd9Sstevel@tonic-gate  *		Pre detach notification handler
4798*7c478bd9Sstevel@tonic-gate  */
4799*7c478bd9Sstevel@tonic-gate 
4800*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4801*7c478bd9Sstevel@tonic-gate int
4802*7c478bd9Sstevel@tonic-gate mdi_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4803*7c478bd9Sstevel@tonic-gate {
4804*7c478bd9Sstevel@tonic-gate 	int rv = DDI_SUCCESS;
4805*7c478bd9Sstevel@tonic-gate 
4806*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT(dip)) {
4807*7c478bd9Sstevel@tonic-gate 		(void) i_mdi_client_pre_detach(dip, cmd);
4808*7c478bd9Sstevel@tonic-gate 	}
4809*7c478bd9Sstevel@tonic-gate 
4810*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI(dip)) {
4811*7c478bd9Sstevel@tonic-gate 		rv = i_mdi_phci_pre_detach(dip, cmd);
4812*7c478bd9Sstevel@tonic-gate 	}
4813*7c478bd9Sstevel@tonic-gate 
4814*7c478bd9Sstevel@tonic-gate 	return (rv);
4815*7c478bd9Sstevel@tonic-gate }
4816*7c478bd9Sstevel@tonic-gate 
4817*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4818*7c478bd9Sstevel@tonic-gate static int
4819*7c478bd9Sstevel@tonic-gate i_mdi_phci_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4820*7c478bd9Sstevel@tonic-gate {
4821*7c478bd9Sstevel@tonic-gate 	int		rv = DDI_SUCCESS;
4822*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
4823*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
4824*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*pip;
4825*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*failed_pip = NULL;
4826*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*next;
4827*7c478bd9Sstevel@tonic-gate 
4828*7c478bd9Sstevel@tonic-gate 	ph = i_devi_get_phci(dip);
4829*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
4830*7c478bd9Sstevel@tonic-gate 		return (rv);
4831*7c478bd9Sstevel@tonic-gate 	}
4832*7c478bd9Sstevel@tonic-gate 
4833*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_LOCK(ph);
4834*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
4835*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
4836*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, dip,
4837*7c478bd9Sstevel@tonic-gate 		    "!pHCI pre_detach: called %p\n", ph));
4838*7c478bd9Sstevel@tonic-gate 		if (!MDI_PHCI_IS_OFFLINE(ph)) {
4839*7c478bd9Sstevel@tonic-gate 			/*
4840*7c478bd9Sstevel@tonic-gate 			 * mdi_pathinfo nodes are still attached to
4841*7c478bd9Sstevel@tonic-gate 			 * this pHCI. Fail the detach for this pHCI.
4842*7c478bd9Sstevel@tonic-gate 			 */
4843*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(2, (CE_WARN, dip,
4844*7c478bd9Sstevel@tonic-gate 			    "!pHCI pre_detach: "
4845*7c478bd9Sstevel@tonic-gate 			    "mdi_pathinfo nodes are still attached "
4846*7c478bd9Sstevel@tonic-gate 			    "%p\n", ph));
4847*7c478bd9Sstevel@tonic-gate 			rv = DDI_FAILURE;
4848*7c478bd9Sstevel@tonic-gate 			break;
4849*7c478bd9Sstevel@tonic-gate 		}
4850*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_SET_DETACH(ph);
4851*7c478bd9Sstevel@tonic-gate 		break;
4852*7c478bd9Sstevel@tonic-gate 
4853*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
4854*7c478bd9Sstevel@tonic-gate 		/*
4855*7c478bd9Sstevel@tonic-gate 		 * pHCI is getting suspended.  Since mpxio client
4856*7c478bd9Sstevel@tonic-gate 		 * devices may not be suspended at this point, to avoid
4857*7c478bd9Sstevel@tonic-gate 		 * a potential stack overflow, it is important to suspend
4858*7c478bd9Sstevel@tonic-gate 		 * client devices before pHCI can be suspended.
4859*7c478bd9Sstevel@tonic-gate 		 */
4860*7c478bd9Sstevel@tonic-gate 
4861*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, dip,
4862*7c478bd9Sstevel@tonic-gate 		    "!pHCI pre_suspend: called %p\n", ph));
4863*7c478bd9Sstevel@tonic-gate 		/*
4864*7c478bd9Sstevel@tonic-gate 		 * Suspend all the client devices accessible through this pHCI
4865*7c478bd9Sstevel@tonic-gate 		 */
4866*7c478bd9Sstevel@tonic-gate 		pip = ph->ph_path_head;
4867*7c478bd9Sstevel@tonic-gate 		while (pip != NULL && rv == DDI_SUCCESS) {
4868*7c478bd9Sstevel@tonic-gate 			dev_info_t *cdip;
4869*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
4870*7c478bd9Sstevel@tonic-gate 			next =
4871*7c478bd9Sstevel@tonic-gate 			    (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
4872*7c478bd9Sstevel@tonic-gate 			ct = MDI_PI(pip)->pi_client;
4873*7c478bd9Sstevel@tonic-gate 			i_mdi_client_lock(ct, pip);
4874*7c478bd9Sstevel@tonic-gate 			cdip = ct->ct_dip;
4875*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
4876*7c478bd9Sstevel@tonic-gate 			if ((MDI_CLIENT_IS_DETACHED(ct) == 0) &&
4877*7c478bd9Sstevel@tonic-gate 			    MDI_CLIENT_IS_SUSPENDED(ct) == 0) {
4878*7c478bd9Sstevel@tonic-gate 				i_mdi_client_unlock(ct);
4879*7c478bd9Sstevel@tonic-gate 				if ((rv = devi_detach(cdip, DDI_SUSPEND)) !=
4880*7c478bd9Sstevel@tonic-gate 				    DDI_SUCCESS) {
4881*7c478bd9Sstevel@tonic-gate 					/*
4882*7c478bd9Sstevel@tonic-gate 					 * Suspend of one of the client
4883*7c478bd9Sstevel@tonic-gate 					 * device has failed.
4884*7c478bd9Sstevel@tonic-gate 					 */
4885*7c478bd9Sstevel@tonic-gate 					MDI_DEBUG(1, (CE_WARN, dip,
4886*7c478bd9Sstevel@tonic-gate 					    "!Suspend of device (%s%d) failed.",
4887*7c478bd9Sstevel@tonic-gate 					    ddi_driver_name(cdip),
4888*7c478bd9Sstevel@tonic-gate 					    ddi_get_instance(cdip)));
4889*7c478bd9Sstevel@tonic-gate 					failed_pip = pip;
4890*7c478bd9Sstevel@tonic-gate 					break;
4891*7c478bd9Sstevel@tonic-gate 				}
4892*7c478bd9Sstevel@tonic-gate 			} else {
4893*7c478bd9Sstevel@tonic-gate 				i_mdi_client_unlock(ct);
4894*7c478bd9Sstevel@tonic-gate 			}
4895*7c478bd9Sstevel@tonic-gate 			pip = next;
4896*7c478bd9Sstevel@tonic-gate 		}
4897*7c478bd9Sstevel@tonic-gate 
4898*7c478bd9Sstevel@tonic-gate 		if (rv == DDI_SUCCESS) {
4899*7c478bd9Sstevel@tonic-gate 			/*
4900*7c478bd9Sstevel@tonic-gate 			 * Suspend of client devices is complete. Proceed
4901*7c478bd9Sstevel@tonic-gate 			 * with pHCI suspend.
4902*7c478bd9Sstevel@tonic-gate 			 */
4903*7c478bd9Sstevel@tonic-gate 			MDI_PHCI_SET_SUSPEND(ph);
4904*7c478bd9Sstevel@tonic-gate 		} else {
4905*7c478bd9Sstevel@tonic-gate 			/*
4906*7c478bd9Sstevel@tonic-gate 			 * Revert back all the suspended client device states
4907*7c478bd9Sstevel@tonic-gate 			 * to converse.
4908*7c478bd9Sstevel@tonic-gate 			 */
4909*7c478bd9Sstevel@tonic-gate 			pip = ph->ph_path_head;
4910*7c478bd9Sstevel@tonic-gate 			while (pip != failed_pip) {
4911*7c478bd9Sstevel@tonic-gate 				dev_info_t *cdip;
4912*7c478bd9Sstevel@tonic-gate 				MDI_PI_LOCK(pip);
4913*7c478bd9Sstevel@tonic-gate 				next =
4914*7c478bd9Sstevel@tonic-gate 				    (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
4915*7c478bd9Sstevel@tonic-gate 				ct = MDI_PI(pip)->pi_client;
4916*7c478bd9Sstevel@tonic-gate 				i_mdi_client_lock(ct, pip);
4917*7c478bd9Sstevel@tonic-gate 				cdip = ct->ct_dip;
4918*7c478bd9Sstevel@tonic-gate 				MDI_PI_UNLOCK(pip);
4919*7c478bd9Sstevel@tonic-gate 				if (MDI_CLIENT_IS_SUSPENDED(ct)) {
4920*7c478bd9Sstevel@tonic-gate 					i_mdi_client_unlock(ct);
4921*7c478bd9Sstevel@tonic-gate 					(void) devi_attach(cdip, DDI_RESUME);
4922*7c478bd9Sstevel@tonic-gate 				} else {
4923*7c478bd9Sstevel@tonic-gate 					i_mdi_client_unlock(ct);
4924*7c478bd9Sstevel@tonic-gate 				}
4925*7c478bd9Sstevel@tonic-gate 				pip = next;
4926*7c478bd9Sstevel@tonic-gate 			}
4927*7c478bd9Sstevel@tonic-gate 		}
4928*7c478bd9Sstevel@tonic-gate 		break;
4929*7c478bd9Sstevel@tonic-gate 
4930*7c478bd9Sstevel@tonic-gate 	default:
4931*7c478bd9Sstevel@tonic-gate 		rv = DDI_FAILURE;
4932*7c478bd9Sstevel@tonic-gate 		break;
4933*7c478bd9Sstevel@tonic-gate 	}
4934*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNLOCK(ph);
4935*7c478bd9Sstevel@tonic-gate 	return (rv);
4936*7c478bd9Sstevel@tonic-gate }
4937*7c478bd9Sstevel@tonic-gate 
4938*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4939*7c478bd9Sstevel@tonic-gate static int
4940*7c478bd9Sstevel@tonic-gate i_mdi_client_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4941*7c478bd9Sstevel@tonic-gate {
4942*7c478bd9Sstevel@tonic-gate 	int		rv = DDI_SUCCESS;
4943*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
4944*7c478bd9Sstevel@tonic-gate 
4945*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(dip);
4946*7c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
4947*7c478bd9Sstevel@tonic-gate 		return (rv);
4948*7c478bd9Sstevel@tonic-gate 	}
4949*7c478bd9Sstevel@tonic-gate 
4950*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
4951*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
4952*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
4953*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, dip,
4954*7c478bd9Sstevel@tonic-gate 		    "!Client pre_detach: called %p\n", ct));
4955*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_SET_DETACH(ct);
4956*7c478bd9Sstevel@tonic-gate 		break;
4957*7c478bd9Sstevel@tonic-gate 
4958*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
4959*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, dip,
4960*7c478bd9Sstevel@tonic-gate 		    "!Client pre_suspend: called %p\n", ct));
4961*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_SET_SUSPEND(ct);
4962*7c478bd9Sstevel@tonic-gate 		break;
4963*7c478bd9Sstevel@tonic-gate 
4964*7c478bd9Sstevel@tonic-gate 	default:
4965*7c478bd9Sstevel@tonic-gate 		rv = DDI_FAILURE;
4966*7c478bd9Sstevel@tonic-gate 		break;
4967*7c478bd9Sstevel@tonic-gate 	}
4968*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
4969*7c478bd9Sstevel@tonic-gate 	return (rv);
4970*7c478bd9Sstevel@tonic-gate }
4971*7c478bd9Sstevel@tonic-gate 
4972*7c478bd9Sstevel@tonic-gate /*
4973*7c478bd9Sstevel@tonic-gate  * mdi_post_detach():
4974*7c478bd9Sstevel@tonic-gate  *		Post detach notification handler
4975*7c478bd9Sstevel@tonic-gate  */
4976*7c478bd9Sstevel@tonic-gate 
4977*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4978*7c478bd9Sstevel@tonic-gate void
4979*7c478bd9Sstevel@tonic-gate mdi_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error)
4980*7c478bd9Sstevel@tonic-gate {
4981*7c478bd9Sstevel@tonic-gate 	/*
4982*7c478bd9Sstevel@tonic-gate 	 * Detach/Suspend of mpxio component failed. Update our state
4983*7c478bd9Sstevel@tonic-gate 	 * too
4984*7c478bd9Sstevel@tonic-gate 	 */
4985*7c478bd9Sstevel@tonic-gate 	if (MDI_PHCI(dip))
4986*7c478bd9Sstevel@tonic-gate 		i_mdi_phci_post_detach(dip, cmd, error);
4987*7c478bd9Sstevel@tonic-gate 
4988*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT(dip))
4989*7c478bd9Sstevel@tonic-gate 		i_mdi_client_post_detach(dip, cmd, error);
4990*7c478bd9Sstevel@tonic-gate }
4991*7c478bd9Sstevel@tonic-gate 
4992*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4993*7c478bd9Sstevel@tonic-gate static void
4994*7c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error)
4995*7c478bd9Sstevel@tonic-gate {
4996*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
4997*7c478bd9Sstevel@tonic-gate 
4998*7c478bd9Sstevel@tonic-gate 	/*
4999*7c478bd9Sstevel@tonic-gate 	 * Detach/Suspend of phci component failed. Update our state
5000*7c478bd9Sstevel@tonic-gate 	 * too
5001*7c478bd9Sstevel@tonic-gate 	 */
5002*7c478bd9Sstevel@tonic-gate 	ph = i_devi_get_phci(dip);
5003*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
5004*7c478bd9Sstevel@tonic-gate 		return;
5005*7c478bd9Sstevel@tonic-gate 	}
5006*7c478bd9Sstevel@tonic-gate 
5007*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_LOCK(ph);
5008*7c478bd9Sstevel@tonic-gate 	/*
5009*7c478bd9Sstevel@tonic-gate 	 * Detach of pHCI failed. Restore back converse
5010*7c478bd9Sstevel@tonic-gate 	 * state
5011*7c478bd9Sstevel@tonic-gate 	 */
5012*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
5013*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
5014*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, dip,
5015*7c478bd9Sstevel@tonic-gate 		    "!pHCI post_detach: called %p\n", ph));
5016*7c478bd9Sstevel@tonic-gate 		if (error != DDI_SUCCESS)
5017*7c478bd9Sstevel@tonic-gate 			MDI_PHCI_SET_ATTACH(ph);
5018*7c478bd9Sstevel@tonic-gate 		break;
5019*7c478bd9Sstevel@tonic-gate 
5020*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
5021*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, dip,
5022*7c478bd9Sstevel@tonic-gate 		    "!pHCI post_suspend: called %p\n", ph));
5023*7c478bd9Sstevel@tonic-gate 		if (error != DDI_SUCCESS)
5024*7c478bd9Sstevel@tonic-gate 			MDI_PHCI_SET_RESUME(ph);
5025*7c478bd9Sstevel@tonic-gate 		break;
5026*7c478bd9Sstevel@tonic-gate 	}
5027*7c478bd9Sstevel@tonic-gate 	MDI_PHCI_UNLOCK(ph);
5028*7c478bd9Sstevel@tonic-gate }
5029*7c478bd9Sstevel@tonic-gate 
5030*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5031*7c478bd9Sstevel@tonic-gate static void
5032*7c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error)
5033*7c478bd9Sstevel@tonic-gate {
5034*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
5035*7c478bd9Sstevel@tonic-gate 
5036*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(dip);
5037*7c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
5038*7c478bd9Sstevel@tonic-gate 		return;
5039*7c478bd9Sstevel@tonic-gate 	}
5040*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
5041*7c478bd9Sstevel@tonic-gate 	/*
5042*7c478bd9Sstevel@tonic-gate 	 * Detach of Client failed. Restore back converse
5043*7c478bd9Sstevel@tonic-gate 	 * state
5044*7c478bd9Sstevel@tonic-gate 	 */
5045*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
5046*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
5047*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, dip,
5048*7c478bd9Sstevel@tonic-gate 		    "!Client post_detach: called %p\n", ct));
5049*7c478bd9Sstevel@tonic-gate 		if (DEVI_IS_ATTACHING(ct->ct_dip)) {
5050*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach "
5051*7c478bd9Sstevel@tonic-gate 			    "i_mdi_pm_rele_client\n"));
5052*7c478bd9Sstevel@tonic-gate 			i_mdi_pm_rele_client(ct, ct->ct_path_count);
5053*7c478bd9Sstevel@tonic-gate 		} else {
5054*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach "
5055*7c478bd9Sstevel@tonic-gate 			    "i_mdi_pm_reset_client\n"));
5056*7c478bd9Sstevel@tonic-gate 			i_mdi_pm_reset_client(ct);
5057*7c478bd9Sstevel@tonic-gate 		}
5058*7c478bd9Sstevel@tonic-gate 		if (error != DDI_SUCCESS)
5059*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_SET_ATTACH(ct);
5060*7c478bd9Sstevel@tonic-gate 		break;
5061*7c478bd9Sstevel@tonic-gate 
5062*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
5063*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, dip,
5064*7c478bd9Sstevel@tonic-gate 		    "!Client post_suspend: called %p\n", ct));
5065*7c478bd9Sstevel@tonic-gate 		if (error != DDI_SUCCESS)
5066*7c478bd9Sstevel@tonic-gate 			MDI_CLIENT_SET_RESUME(ct);
5067*7c478bd9Sstevel@tonic-gate 		break;
5068*7c478bd9Sstevel@tonic-gate 	}
5069*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
5070*7c478bd9Sstevel@tonic-gate }
5071*7c478bd9Sstevel@tonic-gate 
5072*7c478bd9Sstevel@tonic-gate /*
5073*7c478bd9Sstevel@tonic-gate  * create and install per-path (client - pHCI) statistics
5074*7c478bd9Sstevel@tonic-gate  * I/O stats supported: nread, nwritten, reads, and writes
5075*7c478bd9Sstevel@tonic-gate  * Error stats - hard errors, soft errors, & transport errors
5076*7c478bd9Sstevel@tonic-gate  */
5077*7c478bd9Sstevel@tonic-gate static int
5078*7c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_create(mdi_pathinfo_t *pip)
5079*7c478bd9Sstevel@tonic-gate {
5080*7c478bd9Sstevel@tonic-gate 
5081*7c478bd9Sstevel@tonic-gate 	dev_info_t *client = MDI_PI(pip)->pi_client->ct_dip;
5082*7c478bd9Sstevel@tonic-gate 	dev_info_t *ppath = MDI_PI(pip)->pi_phci->ph_dip;
5083*7c478bd9Sstevel@tonic-gate 	char ksname[KSTAT_STRLEN];
5084*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t *cpip;
5085*7c478bd9Sstevel@tonic-gate 	const char *err_postfix = ",err";
5086*7c478bd9Sstevel@tonic-gate 	kstat_t	*kiosp, *kerrsp;
5087*7c478bd9Sstevel@tonic-gate 	struct pi_errs	*nsp;
5088*7c478bd9Sstevel@tonic-gate 	struct mdi_pi_kstats *mdi_statp;
5089*7c478bd9Sstevel@tonic-gate 
5090*7c478bd9Sstevel@tonic-gate 	ASSERT(client != NULL && ppath != NULL);
5091*7c478bd9Sstevel@tonic-gate 
5092*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&(MDI_PI(pip)->pi_client->ct_mutex)));
5093*7c478bd9Sstevel@tonic-gate 
5094*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_kstats != NULL)
5095*7c478bd9Sstevel@tonic-gate 		return (MDI_SUCCESS);
5096*7c478bd9Sstevel@tonic-gate 
5097*7c478bd9Sstevel@tonic-gate 	for (cpip = MDI_PI(pip)->pi_client->ct_path_head; cpip != NULL;
5098*7c478bd9Sstevel@tonic-gate 	    cpip = (mdi_pathinfo_t *)(MDI_PI(cpip)->pi_client_link)) {
5099*7c478bd9Sstevel@tonic-gate 		if (cpip == pip)
5100*7c478bd9Sstevel@tonic-gate 			continue;
5101*7c478bd9Sstevel@tonic-gate 		/*
5102*7c478bd9Sstevel@tonic-gate 		 * We have found a different path with same parent
5103*7c478bd9Sstevel@tonic-gate 		 * kstats for a given client-pHCI are common
5104*7c478bd9Sstevel@tonic-gate 		 */
5105*7c478bd9Sstevel@tonic-gate 		if ((MDI_PI(cpip)->pi_phci->ph_dip == ppath) &&
5106*7c478bd9Sstevel@tonic-gate 		    (MDI_PI(cpip)->pi_kstats != NULL)) {
5107*7c478bd9Sstevel@tonic-gate 			MDI_PI(cpip)->pi_kstats->pi_kstat_ref++;
5108*7c478bd9Sstevel@tonic-gate 			MDI_PI(pip)->pi_kstats = MDI_PI(cpip)->pi_kstats;
5109*7c478bd9Sstevel@tonic-gate 			return (MDI_SUCCESS);
5110*7c478bd9Sstevel@tonic-gate 		}
5111*7c478bd9Sstevel@tonic-gate 	}
5112*7c478bd9Sstevel@tonic-gate 
5113*7c478bd9Sstevel@tonic-gate 	/*
5114*7c478bd9Sstevel@tonic-gate 	 * stats are named as follows: TGTx.HBAy, e.g. "ssd0.fp0"
5115*7c478bd9Sstevel@tonic-gate 	 * clamp length of name against max length of error kstat name
5116*7c478bd9Sstevel@tonic-gate 	 */
5117*7c478bd9Sstevel@tonic-gate 	if (snprintf(ksname, KSTAT_STRLEN, "%s%d.%s%d",
5118*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(client), ddi_get_instance(client),
5119*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(ppath), ddi_get_instance(ppath)) >
5120*7c478bd9Sstevel@tonic-gate 	    (KSTAT_STRLEN - strlen(err_postfix))) {
5121*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5122*7c478bd9Sstevel@tonic-gate 	}
5123*7c478bd9Sstevel@tonic-gate 	if ((kiosp = kstat_create("mdi", 0, ksname, "iopath",
5124*7c478bd9Sstevel@tonic-gate 	    KSTAT_TYPE_IO, 1, 0)) == NULL) {
5125*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5126*7c478bd9Sstevel@tonic-gate 	}
5127*7c478bd9Sstevel@tonic-gate 
5128*7c478bd9Sstevel@tonic-gate 	(void) strcat(ksname, err_postfix);
5129*7c478bd9Sstevel@tonic-gate 	kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors",
5130*7c478bd9Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED,
5131*7c478bd9Sstevel@tonic-gate 	    sizeof (struct pi_errs) / sizeof (kstat_named_t), 0);
5132*7c478bd9Sstevel@tonic-gate 
5133*7c478bd9Sstevel@tonic-gate 	if (kerrsp == NULL) {
5134*7c478bd9Sstevel@tonic-gate 		kstat_delete(kiosp);
5135*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5136*7c478bd9Sstevel@tonic-gate 	}
5137*7c478bd9Sstevel@tonic-gate 
5138*7c478bd9Sstevel@tonic-gate 	nsp = (struct pi_errs *)kerrsp->ks_data;
5139*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32);
5140*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32);
5141*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_transerrs, "Transport Errors",
5142*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
5143*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy",
5144*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
5145*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors",
5146*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
5147*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources",
5148*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
5149*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors",
5150*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
5151*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State",
5152*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
5153*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_failedfrom, "Failed From",
5154*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
5155*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32);
5156*7c478bd9Sstevel@tonic-gate 
5157*7c478bd9Sstevel@tonic-gate 	mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP);
5158*7c478bd9Sstevel@tonic-gate 	mdi_statp->pi_kstat_ref = 1;
5159*7c478bd9Sstevel@tonic-gate 	mdi_statp->pi_kstat_iostats = kiosp;
5160*7c478bd9Sstevel@tonic-gate 	mdi_statp->pi_kstat_errstats = kerrsp;
5161*7c478bd9Sstevel@tonic-gate 	kstat_install(kiosp);
5162*7c478bd9Sstevel@tonic-gate 	kstat_install(kerrsp);
5163*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_kstats = mdi_statp;
5164*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
5165*7c478bd9Sstevel@tonic-gate }
5166*7c478bd9Sstevel@tonic-gate 
5167*7c478bd9Sstevel@tonic-gate /*
5168*7c478bd9Sstevel@tonic-gate  * destroy per-path properties
5169*7c478bd9Sstevel@tonic-gate  */
5170*7c478bd9Sstevel@tonic-gate static void
5171*7c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip)
5172*7c478bd9Sstevel@tonic-gate {
5173*7c478bd9Sstevel@tonic-gate 
5174*7c478bd9Sstevel@tonic-gate 	struct mdi_pi_kstats *mdi_statp;
5175*7c478bd9Sstevel@tonic-gate 
5176*7c478bd9Sstevel@tonic-gate 	if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL)
5177*7c478bd9Sstevel@tonic-gate 		return;
5178*7c478bd9Sstevel@tonic-gate 
5179*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_kstats = NULL;
5180*7c478bd9Sstevel@tonic-gate 
5181*7c478bd9Sstevel@tonic-gate 	/*
5182*7c478bd9Sstevel@tonic-gate 	 * the kstat may be shared between multiple pathinfo nodes
5183*7c478bd9Sstevel@tonic-gate 	 * decrement this pathinfo's usage, removing the kstats
5184*7c478bd9Sstevel@tonic-gate 	 * themselves when the last pathinfo reference is removed.
5185*7c478bd9Sstevel@tonic-gate 	 */
5186*7c478bd9Sstevel@tonic-gate 	ASSERT(mdi_statp->pi_kstat_ref > 0);
5187*7c478bd9Sstevel@tonic-gate 	if (--mdi_statp->pi_kstat_ref != 0)
5188*7c478bd9Sstevel@tonic-gate 		return;
5189*7c478bd9Sstevel@tonic-gate 
5190*7c478bd9Sstevel@tonic-gate 	kstat_delete(mdi_statp->pi_kstat_iostats);
5191*7c478bd9Sstevel@tonic-gate 	kstat_delete(mdi_statp->pi_kstat_errstats);
5192*7c478bd9Sstevel@tonic-gate 	kmem_free(mdi_statp, sizeof (*mdi_statp));
5193*7c478bd9Sstevel@tonic-gate }
5194*7c478bd9Sstevel@tonic-gate 
5195*7c478bd9Sstevel@tonic-gate /*
5196*7c478bd9Sstevel@tonic-gate  * update I/O paths KSTATS
5197*7c478bd9Sstevel@tonic-gate  */
5198*7c478bd9Sstevel@tonic-gate void
5199*7c478bd9Sstevel@tonic-gate mdi_pi_kstat_iosupdate(mdi_pathinfo_t *pip, struct buf *bp)
5200*7c478bd9Sstevel@tonic-gate {
5201*7c478bd9Sstevel@tonic-gate 	kstat_t *iostatp;
5202*7c478bd9Sstevel@tonic-gate 	size_t xfer_cnt;
5203*7c478bd9Sstevel@tonic-gate 
5204*7c478bd9Sstevel@tonic-gate 	ASSERT(pip != NULL);
5205*7c478bd9Sstevel@tonic-gate 
5206*7c478bd9Sstevel@tonic-gate 	/*
5207*7c478bd9Sstevel@tonic-gate 	 * I/O can be driven across a path prior to having path
5208*7c478bd9Sstevel@tonic-gate 	 * statistics available, i.e. probe(9e).
5209*7c478bd9Sstevel@tonic-gate 	 */
5210*7c478bd9Sstevel@tonic-gate 	if (bp != NULL && MDI_PI(pip)->pi_kstats != NULL) {
5211*7c478bd9Sstevel@tonic-gate 		iostatp = MDI_PI(pip)->pi_kstats->pi_kstat_iostats;
5212*7c478bd9Sstevel@tonic-gate 		xfer_cnt = bp->b_bcount - bp->b_resid;
5213*7c478bd9Sstevel@tonic-gate 		if (bp->b_flags & B_READ) {
5214*7c478bd9Sstevel@tonic-gate 			KSTAT_IO_PTR(iostatp)->reads++;
5215*7c478bd9Sstevel@tonic-gate 			KSTAT_IO_PTR(iostatp)->nread += xfer_cnt;
5216*7c478bd9Sstevel@tonic-gate 		} else {
5217*7c478bd9Sstevel@tonic-gate 			KSTAT_IO_PTR(iostatp)->writes++;
5218*7c478bd9Sstevel@tonic-gate 			KSTAT_IO_PTR(iostatp)->nwritten += xfer_cnt;
5219*7c478bd9Sstevel@tonic-gate 		}
5220*7c478bd9Sstevel@tonic-gate 	}
5221*7c478bd9Sstevel@tonic-gate }
5222*7c478bd9Sstevel@tonic-gate 
5223*7c478bd9Sstevel@tonic-gate /*
5224*7c478bd9Sstevel@tonic-gate  * disable the path to a particular pHCI (pHCI specified in the phci_path
5225*7c478bd9Sstevel@tonic-gate  * argument) for a particular client (specified in the client_path argument).
5226*7c478bd9Sstevel@tonic-gate  * Disabling a path means that MPxIO will not select the disabled path for
5227*7c478bd9Sstevel@tonic-gate  * routing any new I/O requests.
5228*7c478bd9Sstevel@tonic-gate  */
5229*7c478bd9Sstevel@tonic-gate int
5230*7c478bd9Sstevel@tonic-gate mdi_pi_disable(dev_info_t *cdip, dev_info_t *pdip, int flags)
5231*7c478bd9Sstevel@tonic-gate {
5232*7c478bd9Sstevel@tonic-gate 	return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_DISABLE_OP));
5233*7c478bd9Sstevel@tonic-gate }
5234*7c478bd9Sstevel@tonic-gate 
5235*7c478bd9Sstevel@tonic-gate /*
5236*7c478bd9Sstevel@tonic-gate  * Enable the path to a particular pHCI (pHCI specified in the phci_path
5237*7c478bd9Sstevel@tonic-gate  * argument) for a particular client (specified in the client_path argument).
5238*7c478bd9Sstevel@tonic-gate  * Enabling a path means that MPxIO may select the enabled path for routing
5239*7c478bd9Sstevel@tonic-gate  * future I/O requests, subject to other path state constraints.
5240*7c478bd9Sstevel@tonic-gate  */
5241*7c478bd9Sstevel@tonic-gate 
5242*7c478bd9Sstevel@tonic-gate int
5243*7c478bd9Sstevel@tonic-gate mdi_pi_enable(dev_info_t *cdip, dev_info_t *pdip, int flags)
5244*7c478bd9Sstevel@tonic-gate {
5245*7c478bd9Sstevel@tonic-gate 	return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_ENABLE_OP));
5246*7c478bd9Sstevel@tonic-gate }
5247*7c478bd9Sstevel@tonic-gate 
5248*7c478bd9Sstevel@tonic-gate 
5249*7c478bd9Sstevel@tonic-gate /*
5250*7c478bd9Sstevel@tonic-gate  * Common routine for doing enable/disable.
5251*7c478bd9Sstevel@tonic-gate  */
5252*7c478bd9Sstevel@tonic-gate int
5253*7c478bd9Sstevel@tonic-gate i_mdi_pi_enable_disable(dev_info_t *cdip, dev_info_t *pdip, int flags, int op)
5254*7c478bd9Sstevel@tonic-gate {
5255*7c478bd9Sstevel@tonic-gate 
5256*7c478bd9Sstevel@tonic-gate 	mdi_phci_t	*ph;
5257*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t	*vh = NULL;
5258*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
5259*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t	*next, *pip;
5260*7c478bd9Sstevel@tonic-gate 	int		found_it;
5261*7c478bd9Sstevel@tonic-gate 	int		(*f)() = NULL;
5262*7c478bd9Sstevel@tonic-gate 	int		rv;
5263*7c478bd9Sstevel@tonic-gate 	int		sync_flag = 0;
5264*7c478bd9Sstevel@tonic-gate 
5265*7c478bd9Sstevel@tonic-gate 	ph = i_devi_get_phci(pdip);
5266*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:"
5267*7c478bd9Sstevel@tonic-gate 		" Operation = %d pdip = %p cdip = %p\n", op, pdip, cdip));
5268*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
5269*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:"
5270*7c478bd9Sstevel@tonic-gate 			" failed. ph = NULL operation = %d\n", op));
5271*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5272*7c478bd9Sstevel@tonic-gate 	}
5273*7c478bd9Sstevel@tonic-gate 
5274*7c478bd9Sstevel@tonic-gate 	if ((op != MDI_ENABLE_OP) && (op != MDI_DISABLE_OP)) {
5275*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:"
5276*7c478bd9Sstevel@tonic-gate 			" Invalid operation = %d\n", op));
5277*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5278*7c478bd9Sstevel@tonic-gate 	}
5279*7c478bd9Sstevel@tonic-gate 
5280*7c478bd9Sstevel@tonic-gate 	sync_flag = (flags << 8) & 0xf00;
5281*7c478bd9Sstevel@tonic-gate 
5282*7c478bd9Sstevel@tonic-gate 	vh = ph->ph_vhci;
5283*7c478bd9Sstevel@tonic-gate 	f = vh->vh_ops->vo_pi_state_change;
5284*7c478bd9Sstevel@tonic-gate 
5285*7c478bd9Sstevel@tonic-gate 	if (cdip == NULL) {
5286*7c478bd9Sstevel@tonic-gate 		/*
5287*7c478bd9Sstevel@tonic-gate 		 * Need to mark the Phci as enabled/disabled.
5288*7c478bd9Sstevel@tonic-gate 		 */
5289*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(3, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:"
5290*7c478bd9Sstevel@tonic-gate 		"Operation %d for the phci\n", op));
5291*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_LOCK(ph);
5292*7c478bd9Sstevel@tonic-gate 		switch (flags) {
5293*7c478bd9Sstevel@tonic-gate 			case USER_DISABLE:
5294*7c478bd9Sstevel@tonic-gate 				if (op == MDI_DISABLE_OP)
5295*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_SET_USER_DISABLE(ph);
5296*7c478bd9Sstevel@tonic-gate 				else
5297*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_SET_USER_ENABLE(ph);
5298*7c478bd9Sstevel@tonic-gate 				break;
5299*7c478bd9Sstevel@tonic-gate 			case DRIVER_DISABLE:
5300*7c478bd9Sstevel@tonic-gate 				if (op == MDI_DISABLE_OP)
5301*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_SET_DRV_DISABLE(ph);
5302*7c478bd9Sstevel@tonic-gate 				else
5303*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_SET_DRV_ENABLE(ph);
5304*7c478bd9Sstevel@tonic-gate 				break;
5305*7c478bd9Sstevel@tonic-gate 			case DRIVER_DISABLE_TRANSIENT:
5306*7c478bd9Sstevel@tonic-gate 				if (op == MDI_DISABLE_OP)
5307*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_SET_DRV_DISABLE_TRANSIENT(ph);
5308*7c478bd9Sstevel@tonic-gate 				else
5309*7c478bd9Sstevel@tonic-gate 					MDI_PHCI_SET_DRV_ENABLE_TRANSIENT(ph);
5310*7c478bd9Sstevel@tonic-gate 				break;
5311*7c478bd9Sstevel@tonic-gate 			default:
5312*7c478bd9Sstevel@tonic-gate 				MDI_PHCI_UNLOCK(ph);
5313*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(1, (CE_NOTE, NULL,
5314*7c478bd9Sstevel@tonic-gate 				"!i_mdi_pi_enable_disable:"
5315*7c478bd9Sstevel@tonic-gate 				" Invalid flag argument= %d\n", flags));
5316*7c478bd9Sstevel@tonic-gate 		}
5317*7c478bd9Sstevel@tonic-gate 
5318*7c478bd9Sstevel@tonic-gate 		/*
5319*7c478bd9Sstevel@tonic-gate 		 * Phci has been disabled. Now try to enable/disable
5320*7c478bd9Sstevel@tonic-gate 		 * path info's to each client.
5321*7c478bd9Sstevel@tonic-gate 		 */
5322*7c478bd9Sstevel@tonic-gate 		pip = ph->ph_path_head;
5323*7c478bd9Sstevel@tonic-gate 		while (pip != NULL) {
5324*7c478bd9Sstevel@tonic-gate 			/*
5325*7c478bd9Sstevel@tonic-gate 			 * Do a callback into the mdi consumer to let it
5326*7c478bd9Sstevel@tonic-gate 			 * know that path is about to be enabled/disabled.
5327*7c478bd9Sstevel@tonic-gate 			 */
5328*7c478bd9Sstevel@tonic-gate 			if (f != NULL) {
5329*7c478bd9Sstevel@tonic-gate 				rv = (*f)(vh->vh_dip, pip, 0,
5330*7c478bd9Sstevel@tonic-gate 					MDI_PI_EXT_STATE(pip),
5331*7c478bd9Sstevel@tonic-gate 					MDI_EXT_STATE_CHANGE | sync_flag |
5332*7c478bd9Sstevel@tonic-gate 					op | MDI_BEFORE_STATE_CHANGE);
5333*7c478bd9Sstevel@tonic-gate 				if (rv != MDI_SUCCESS) {
5334*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(2, (CE_WARN, vh->vh_dip,
5335*7c478bd9Sstevel@tonic-gate 				"!vo_pi_state_change: failed rv = %x", rv));
5336*7c478bd9Sstevel@tonic-gate 				}
5337*7c478bd9Sstevel@tonic-gate 			}
5338*7c478bd9Sstevel@tonic-gate 
5339*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
5340*7c478bd9Sstevel@tonic-gate 			next =
5341*7c478bd9Sstevel@tonic-gate 				(mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5342*7c478bd9Sstevel@tonic-gate 			switch (flags) {
5343*7c478bd9Sstevel@tonic-gate 			case USER_DISABLE:
5344*7c478bd9Sstevel@tonic-gate 				if (op == MDI_DISABLE_OP)
5345*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_USER_DISABLE(pip);
5346*7c478bd9Sstevel@tonic-gate 				else
5347*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_USER_ENABLE(pip);
5348*7c478bd9Sstevel@tonic-gate 				break;
5349*7c478bd9Sstevel@tonic-gate 			case DRIVER_DISABLE:
5350*7c478bd9Sstevel@tonic-gate 				if (op == MDI_DISABLE_OP)
5351*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_DRV_DISABLE(pip);
5352*7c478bd9Sstevel@tonic-gate 				else
5353*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_DRV_ENABLE(pip);
5354*7c478bd9Sstevel@tonic-gate 				break;
5355*7c478bd9Sstevel@tonic-gate 			case DRIVER_DISABLE_TRANSIENT:
5356*7c478bd9Sstevel@tonic-gate 				if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS)
5357*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_DRV_DISABLE_TRANS(pip);
5358*7c478bd9Sstevel@tonic-gate 				else
5359*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_DRV_ENABLE_TRANS(pip);
5360*7c478bd9Sstevel@tonic-gate 				break;
5361*7c478bd9Sstevel@tonic-gate 			}
5362*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
5363*7c478bd9Sstevel@tonic-gate 			/*
5364*7c478bd9Sstevel@tonic-gate 			 * Do a callback into the mdi consumer to let it
5365*7c478bd9Sstevel@tonic-gate 			 * know that path is now enabled/disabled.
5366*7c478bd9Sstevel@tonic-gate 			 */
5367*7c478bd9Sstevel@tonic-gate 			if (f != NULL) {
5368*7c478bd9Sstevel@tonic-gate 				rv = (*f)(vh->vh_dip, pip, 0,
5369*7c478bd9Sstevel@tonic-gate 					MDI_PI_EXT_STATE(pip),
5370*7c478bd9Sstevel@tonic-gate 					MDI_EXT_STATE_CHANGE | sync_flag |
5371*7c478bd9Sstevel@tonic-gate 					op | MDI_AFTER_STATE_CHANGE);
5372*7c478bd9Sstevel@tonic-gate 				if (rv != MDI_SUCCESS) {
5373*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(2, (CE_WARN, vh->vh_dip,
5374*7c478bd9Sstevel@tonic-gate 				"!vo_pi_state_change: failed rv = %x", rv));
5375*7c478bd9Sstevel@tonic-gate 				}
5376*7c478bd9Sstevel@tonic-gate 			}
5377*7c478bd9Sstevel@tonic-gate 			pip = next;
5378*7c478bd9Sstevel@tonic-gate 		}
5379*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_UNLOCK(ph);
5380*7c478bd9Sstevel@tonic-gate 	} else {
5381*7c478bd9Sstevel@tonic-gate 
5382*7c478bd9Sstevel@tonic-gate 		/*
5383*7c478bd9Sstevel@tonic-gate 		 * Disable a specific client.
5384*7c478bd9Sstevel@tonic-gate 		 */
5385*7c478bd9Sstevel@tonic-gate 		ct = i_devi_get_client(cdip);
5386*7c478bd9Sstevel@tonic-gate 		if (ct == NULL) {
5387*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_NOTE, NULL,
5388*7c478bd9Sstevel@tonic-gate 			"!i_mdi_pi_enable_disable:"
5389*7c478bd9Sstevel@tonic-gate 			" failed. ct = NULL operation = %d\n", op));
5390*7c478bd9Sstevel@tonic-gate 			return (MDI_FAILURE);
5391*7c478bd9Sstevel@tonic-gate 		}
5392*7c478bd9Sstevel@tonic-gate 
5393*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_LOCK(ct);
5394*7c478bd9Sstevel@tonic-gate 		pip = ct->ct_path_head;
5395*7c478bd9Sstevel@tonic-gate 		found_it = 0;
5396*7c478bd9Sstevel@tonic-gate 		while (pip != NULL) {
5397*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
5398*7c478bd9Sstevel@tonic-gate 			next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
5399*7c478bd9Sstevel@tonic-gate 			if (MDI_PI(pip)->pi_phci == ph) {
5400*7c478bd9Sstevel@tonic-gate 				MDI_PI_UNLOCK(pip);
5401*7c478bd9Sstevel@tonic-gate 				found_it = 1;
5402*7c478bd9Sstevel@tonic-gate 				break;
5403*7c478bd9Sstevel@tonic-gate 			}
5404*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
5405*7c478bd9Sstevel@tonic-gate 			pip = next;
5406*7c478bd9Sstevel@tonic-gate 		}
5407*7c478bd9Sstevel@tonic-gate 
5408*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
5409*7c478bd9Sstevel@tonic-gate 		if (found_it == 0) {
5410*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(1, (CE_NOTE, NULL,
5411*7c478bd9Sstevel@tonic-gate 			"!i_mdi_pi_enable_disable:"
5412*7c478bd9Sstevel@tonic-gate 			" failed. Could not find corresponding pip\n"));
5413*7c478bd9Sstevel@tonic-gate 			return (MDI_FAILURE);
5414*7c478bd9Sstevel@tonic-gate 		}
5415*7c478bd9Sstevel@tonic-gate 		/*
5416*7c478bd9Sstevel@tonic-gate 		 * Do a callback into the mdi consumer to let it
5417*7c478bd9Sstevel@tonic-gate 		 * know that path is about to get enabled/disabled.
5418*7c478bd9Sstevel@tonic-gate 		 */
5419*7c478bd9Sstevel@tonic-gate 		if (f != NULL) {
5420*7c478bd9Sstevel@tonic-gate 			rv = (*f)(vh->vh_dip, pip, 0,
5421*7c478bd9Sstevel@tonic-gate 				MDI_PI_EXT_STATE(pip),
5422*7c478bd9Sstevel@tonic-gate 				MDI_EXT_STATE_CHANGE | sync_flag |
5423*7c478bd9Sstevel@tonic-gate 				op | MDI_BEFORE_STATE_CHANGE);
5424*7c478bd9Sstevel@tonic-gate 			if (rv != MDI_SUCCESS) {
5425*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(2, (CE_WARN, vh->vh_dip,
5426*7c478bd9Sstevel@tonic-gate 				"!vo_pi_state_change: failed rv = %x", rv));
5427*7c478bd9Sstevel@tonic-gate 			}
5428*7c478bd9Sstevel@tonic-gate 		}
5429*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
5430*7c478bd9Sstevel@tonic-gate 		switch (flags) {
5431*7c478bd9Sstevel@tonic-gate 			case USER_DISABLE:
5432*7c478bd9Sstevel@tonic-gate 				if (op == MDI_DISABLE_OP)
5433*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_USER_DISABLE(pip);
5434*7c478bd9Sstevel@tonic-gate 				else
5435*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_USER_ENABLE(pip);
5436*7c478bd9Sstevel@tonic-gate 				break;
5437*7c478bd9Sstevel@tonic-gate 			case DRIVER_DISABLE:
5438*7c478bd9Sstevel@tonic-gate 				if (op == MDI_DISABLE_OP)
5439*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_DRV_DISABLE(pip);
5440*7c478bd9Sstevel@tonic-gate 				else
5441*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_DRV_ENABLE(pip);
5442*7c478bd9Sstevel@tonic-gate 				break;
5443*7c478bd9Sstevel@tonic-gate 			case DRIVER_DISABLE_TRANSIENT:
5444*7c478bd9Sstevel@tonic-gate 				if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS)
5445*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_DRV_DISABLE_TRANS(pip);
5446*7c478bd9Sstevel@tonic-gate 				else
5447*7c478bd9Sstevel@tonic-gate 					MDI_PI_SET_DRV_ENABLE_TRANS(pip);
5448*7c478bd9Sstevel@tonic-gate 				break;
5449*7c478bd9Sstevel@tonic-gate 		}
5450*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
5451*7c478bd9Sstevel@tonic-gate 		/*
5452*7c478bd9Sstevel@tonic-gate 		 * Do a callback into the mdi consumer to let it
5453*7c478bd9Sstevel@tonic-gate 		 * know that path is now enabled/disabled.
5454*7c478bd9Sstevel@tonic-gate 		 */
5455*7c478bd9Sstevel@tonic-gate 		if (f != NULL) {
5456*7c478bd9Sstevel@tonic-gate 			rv = (*f)(vh->vh_dip, pip, 0,
5457*7c478bd9Sstevel@tonic-gate 				MDI_PI_EXT_STATE(pip),
5458*7c478bd9Sstevel@tonic-gate 				MDI_EXT_STATE_CHANGE | sync_flag |
5459*7c478bd9Sstevel@tonic-gate 				op | MDI_AFTER_STATE_CHANGE);
5460*7c478bd9Sstevel@tonic-gate 			if (rv != MDI_SUCCESS) {
5461*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(2, (CE_WARN, vh->vh_dip,
5462*7c478bd9Sstevel@tonic-gate 				"!vo_pi_state_change: failed rv = %x", rv));
5463*7c478bd9Sstevel@tonic-gate 			}
5464*7c478bd9Sstevel@tonic-gate 		}
5465*7c478bd9Sstevel@tonic-gate 	}
5466*7c478bd9Sstevel@tonic-gate 
5467*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:"
5468*7c478bd9Sstevel@tonic-gate 		" Returning success pdip = %p cdip = %p\n", op, pdip, cdip));
5469*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
5470*7c478bd9Sstevel@tonic-gate }
5471*7c478bd9Sstevel@tonic-gate 
5472*7c478bd9Sstevel@tonic-gate /*ARGSUSED3*/
5473*7c478bd9Sstevel@tonic-gate int
5474*7c478bd9Sstevel@tonic-gate mdi_devi_config_one(dev_info_t *pdip, char *devnm, dev_info_t **cdipp,
5475*7c478bd9Sstevel@tonic-gate     int flags, clock_t timeout)
5476*7c478bd9Sstevel@tonic-gate {
5477*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t *pip;
5478*7c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
5479*7c478bd9Sstevel@tonic-gate 	clock_t interval = drv_usectohz(100000);	/* 0.1 sec */
5480*7c478bd9Sstevel@tonic-gate 	char *paddr;
5481*7c478bd9Sstevel@tonic-gate 
5482*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(2, (CE_NOTE, NULL, "configure device %s", devnm));
5483*7c478bd9Sstevel@tonic-gate 
5484*7c478bd9Sstevel@tonic-gate 	if (!MDI_PHCI(pdip))
5485*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5486*7c478bd9Sstevel@tonic-gate 
5487*7c478bd9Sstevel@tonic-gate 	paddr = strchr(devnm, '@');
5488*7c478bd9Sstevel@tonic-gate 	if (paddr == NULL)
5489*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5490*7c478bd9Sstevel@tonic-gate 
5491*7c478bd9Sstevel@tonic-gate 	paddr++;	/* skip '@' */
5492*7c478bd9Sstevel@tonic-gate 	pip = mdi_pi_find(pdip, NULL, paddr);
5493*7c478bd9Sstevel@tonic-gate 	while (pip == NULL && timeout > 0) {
5494*7c478bd9Sstevel@tonic-gate 		if (interval > timeout)
5495*7c478bd9Sstevel@tonic-gate 			interval = timeout;
5496*7c478bd9Sstevel@tonic-gate 		if (flags & NDI_DEVI_DEBUG) {
5497*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: %s timeout %ld %ld\n",
5498*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(pdip), ddi_get_instance(pdip),
5499*7c478bd9Sstevel@tonic-gate 			    paddr, interval, timeout);
5500*7c478bd9Sstevel@tonic-gate 		}
5501*7c478bd9Sstevel@tonic-gate 		delay(interval);
5502*7c478bd9Sstevel@tonic-gate 		timeout -= interval;
5503*7c478bd9Sstevel@tonic-gate 		interval += interval;
5504*7c478bd9Sstevel@tonic-gate 		pip = mdi_pi_find(pdip, NULL, paddr);
5505*7c478bd9Sstevel@tonic-gate 	}
5506*7c478bd9Sstevel@tonic-gate 
5507*7c478bd9Sstevel@tonic-gate 	if (pip == NULL)
5508*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5509*7c478bd9Sstevel@tonic-gate 	dip = mdi_pi_get_client(pip);
5510*7c478bd9Sstevel@tonic-gate 	if (ndi_devi_online(dip, flags) != NDI_SUCCESS)
5511*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5512*7c478bd9Sstevel@tonic-gate 	*cdipp = dip;
5513*7c478bd9Sstevel@tonic-gate 
5514*7c478bd9Sstevel@tonic-gate 	/* TODO: holding should happen inside search functions */
5515*7c478bd9Sstevel@tonic-gate 	ndi_hold_devi(dip);
5516*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
5517*7c478bd9Sstevel@tonic-gate }
5518*7c478bd9Sstevel@tonic-gate 
5519*7c478bd9Sstevel@tonic-gate /*
5520*7c478bd9Sstevel@tonic-gate  * Ensure phci powered up
5521*7c478bd9Sstevel@tonic-gate  */
5522*7c478bd9Sstevel@tonic-gate static void
5523*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(mdi_pathinfo_t *pip)
5524*7c478bd9Sstevel@tonic-gate {
5525*7c478bd9Sstevel@tonic-gate 	dev_info_t	*ph_dip;
5526*7c478bd9Sstevel@tonic-gate 
5527*7c478bd9Sstevel@tonic-gate 	ASSERT(pip != NULL);
5528*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
5529*7c478bd9Sstevel@tonic-gate 
5530*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_pm_held) {
5531*7c478bd9Sstevel@tonic-gate 		return;
5532*7c478bd9Sstevel@tonic-gate 	}
5533*7c478bd9Sstevel@tonic-gate 
5534*7c478bd9Sstevel@tonic-gate 	ph_dip = mdi_pi_get_phci(pip);
5535*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_hold_pip for %s%d\n",
5536*7c478bd9Sstevel@tonic-gate 	    ddi_get_name(ph_dip), ddi_get_instance(ph_dip)));
5537*7c478bd9Sstevel@tonic-gate 	if (ph_dip == NULL) {
5538*7c478bd9Sstevel@tonic-gate 		return;
5539*7c478bd9Sstevel@tonic-gate 	}
5540*7c478bd9Sstevel@tonic-gate 
5541*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
5542*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n",
5543*7c478bd9Sstevel@tonic-gate 	    DEVI(ph_dip)->devi_pm_kidsupcnt));
5544*7c478bd9Sstevel@tonic-gate 	pm_hold_power(ph_dip);
5545*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n",
5546*7c478bd9Sstevel@tonic-gate 	    DEVI(ph_dip)->devi_pm_kidsupcnt));
5547*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
5548*7c478bd9Sstevel@tonic-gate 
5549*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_pm_held = 1;
5550*7c478bd9Sstevel@tonic-gate }
5551*7c478bd9Sstevel@tonic-gate 
5552*7c478bd9Sstevel@tonic-gate /*
5553*7c478bd9Sstevel@tonic-gate  * Allow phci powered down
5554*7c478bd9Sstevel@tonic-gate  */
5555*7c478bd9Sstevel@tonic-gate static void
5556*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(mdi_pathinfo_t *pip)
5557*7c478bd9Sstevel@tonic-gate {
5558*7c478bd9Sstevel@tonic-gate 	dev_info_t	*ph_dip = NULL;
5559*7c478bd9Sstevel@tonic-gate 
5560*7c478bd9Sstevel@tonic-gate 	ASSERT(pip != NULL);
5561*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex));
5562*7c478bd9Sstevel@tonic-gate 
5563*7c478bd9Sstevel@tonic-gate 	if (MDI_PI(pip)->pi_pm_held == 0) {
5564*7c478bd9Sstevel@tonic-gate 		return;
5565*7c478bd9Sstevel@tonic-gate 	}
5566*7c478bd9Sstevel@tonic-gate 
5567*7c478bd9Sstevel@tonic-gate 	ph_dip = mdi_pi_get_phci(pip);
5568*7c478bd9Sstevel@tonic-gate 	ASSERT(ph_dip != NULL);
5569*7c478bd9Sstevel@tonic-gate 
5570*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
5571*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_rele_pip for %s%d\n",
5572*7c478bd9Sstevel@tonic-gate 	    ddi_get_name(ph_dip), ddi_get_instance(ph_dip)));
5573*7c478bd9Sstevel@tonic-gate 
5574*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n",
5575*7c478bd9Sstevel@tonic-gate 	    DEVI(ph_dip)->devi_pm_kidsupcnt));
5576*7c478bd9Sstevel@tonic-gate 	pm_rele_power(ph_dip);
5577*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n",
5578*7c478bd9Sstevel@tonic-gate 	    DEVI(ph_dip)->devi_pm_kidsupcnt));
5579*7c478bd9Sstevel@tonic-gate 
5580*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
5581*7c478bd9Sstevel@tonic-gate 	MDI_PI(pip)->pi_pm_held = 0;
5582*7c478bd9Sstevel@tonic-gate }
5583*7c478bd9Sstevel@tonic-gate 
5584*7c478bd9Sstevel@tonic-gate static void
5585*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(mdi_client_t *ct, int incr)
5586*7c478bd9Sstevel@tonic-gate {
5587*7c478bd9Sstevel@tonic-gate 	ASSERT(ct);
5588*7c478bd9Sstevel@tonic-gate 
5589*7c478bd9Sstevel@tonic-gate 	ct->ct_power_cnt += incr;
5590*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_hold_client "
5591*7c478bd9Sstevel@tonic-gate 	    "ct_power_cnt = %d incr = %d\n", ct->ct_power_cnt, incr));
5592*7c478bd9Sstevel@tonic-gate 	ASSERT(ct->ct_power_cnt >= 0);
5593*7c478bd9Sstevel@tonic-gate }
5594*7c478bd9Sstevel@tonic-gate 
5595*7c478bd9Sstevel@tonic-gate static void
5596*7c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(mdi_client_t *ct)
5597*7c478bd9Sstevel@tonic-gate {
5598*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t  *pip;
5599*7c478bd9Sstevel@tonic-gate 
5600*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ct->ct_mutex));
5601*7c478bd9Sstevel@tonic-gate 	pip = (mdi_pathinfo_t *)ct->ct_path_head;
5602*7c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
5603*7c478bd9Sstevel@tonic-gate 		mdi_hold_path(pip);
5604*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
5605*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_rele_pip(pip);
5606*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
5607*7c478bd9Sstevel@tonic-gate 		mdi_rele_path(pip);
5608*7c478bd9Sstevel@tonic-gate 		pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
5609*7c478bd9Sstevel@tonic-gate 	}
5610*7c478bd9Sstevel@tonic-gate }
5611*7c478bd9Sstevel@tonic-gate 
5612*7c478bd9Sstevel@tonic-gate static void
5613*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(mdi_client_t *ct, int decr)
5614*7c478bd9Sstevel@tonic-gate {
5615*7c478bd9Sstevel@tonic-gate 	ASSERT(ct);
5616*7c478bd9Sstevel@tonic-gate 
5617*7c478bd9Sstevel@tonic-gate 	if (i_ddi_node_state(ct->ct_dip) >= DS_READY) {
5618*7c478bd9Sstevel@tonic-gate 		ct->ct_power_cnt -= decr;
5619*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_rele_client "
5620*7c478bd9Sstevel@tonic-gate 		    "ct_power_cnt = %d decr = %d\n", ct->ct_power_cnt, decr));
5621*7c478bd9Sstevel@tonic-gate 	}
5622*7c478bd9Sstevel@tonic-gate 
5623*7c478bd9Sstevel@tonic-gate 	ASSERT(ct->ct_power_cnt >= 0);
5624*7c478bd9Sstevel@tonic-gate 	if (ct->ct_power_cnt == 0) {
5625*7c478bd9Sstevel@tonic-gate 		i_mdi_rele_all_phci(ct);
5626*7c478bd9Sstevel@tonic-gate 		return;
5627*7c478bd9Sstevel@tonic-gate 	}
5628*7c478bd9Sstevel@tonic-gate }
5629*7c478bd9Sstevel@tonic-gate 
5630*7c478bd9Sstevel@tonic-gate static void
5631*7c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(mdi_client_t *ct)
5632*7c478bd9Sstevel@tonic-gate {
5633*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_reset_client "
5634*7c478bd9Sstevel@tonic-gate 	    "ct_power_cnt = %d\n", ct->ct_power_cnt));
5635*7c478bd9Sstevel@tonic-gate 	ct->ct_power_cnt = 0;
5636*7c478bd9Sstevel@tonic-gate 	i_mdi_rele_all_phci(ct);
5637*7c478bd9Sstevel@tonic-gate 	ct->ct_powercnt_reset = 1;
5638*7c478bd9Sstevel@tonic-gate 	ct->ct_powercnt_held = 0;
5639*7c478bd9Sstevel@tonic-gate }
5640*7c478bd9Sstevel@tonic-gate 
5641*7c478bd9Sstevel@tonic-gate static void
5642*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_all_phci(mdi_client_t *ct)
5643*7c478bd9Sstevel@tonic-gate {
5644*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t  *pip;
5645*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ct->ct_mutex));
5646*7c478bd9Sstevel@tonic-gate 
5647*7c478bd9Sstevel@tonic-gate 	pip = (mdi_pathinfo_t *)ct->ct_path_head;
5648*7c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
5649*7c478bd9Sstevel@tonic-gate 		mdi_hold_path(pip);
5650*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
5651*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_hold_pip(pip);
5652*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
5653*7c478bd9Sstevel@tonic-gate 		mdi_rele_path(pip);
5654*7c478bd9Sstevel@tonic-gate 		pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
5655*7c478bd9Sstevel@tonic-gate 	}
5656*7c478bd9Sstevel@tonic-gate }
5657*7c478bd9Sstevel@tonic-gate 
5658*7c478bd9Sstevel@tonic-gate static int
5659*7c478bd9Sstevel@tonic-gate i_mdi_power_one_phci(mdi_pathinfo_t *pip)
5660*7c478bd9Sstevel@tonic-gate {
5661*7c478bd9Sstevel@tonic-gate 	int		ret;
5662*7c478bd9Sstevel@tonic-gate 	dev_info_t	*ph_dip;
5663*7c478bd9Sstevel@tonic-gate 
5664*7c478bd9Sstevel@tonic-gate 	MDI_PI_LOCK(pip);
5665*7c478bd9Sstevel@tonic-gate 	i_mdi_pm_hold_pip(pip);
5666*7c478bd9Sstevel@tonic-gate 
5667*7c478bd9Sstevel@tonic-gate 	ph_dip = mdi_pi_get_phci(pip);
5668*7c478bd9Sstevel@tonic-gate 	MDI_PI_UNLOCK(pip);
5669*7c478bd9Sstevel@tonic-gate 
5670*7c478bd9Sstevel@tonic-gate 	/* bring all components of phci to full power */
5671*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci "
5672*7c478bd9Sstevel@tonic-gate 	    "pm_powerup for %s%d\n", ddi_get_name(ph_dip),
5673*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(ph_dip)));
5674*7c478bd9Sstevel@tonic-gate 
5675*7c478bd9Sstevel@tonic-gate 	ret = pm_powerup(ph_dip);
5676*7c478bd9Sstevel@tonic-gate 
5677*7c478bd9Sstevel@tonic-gate 	if (ret == DDI_FAILURE) {
5678*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci "
5679*7c478bd9Sstevel@tonic-gate 		    "pm_powerup FAILED for %s%d\n",
5680*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(ph_dip), ddi_get_instance(ph_dip)));
5681*7c478bd9Sstevel@tonic-gate 
5682*7c478bd9Sstevel@tonic-gate 		MDI_PI_LOCK(pip);
5683*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_rele_pip(pip);
5684*7c478bd9Sstevel@tonic-gate 		MDI_PI_UNLOCK(pip);
5685*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5686*7c478bd9Sstevel@tonic-gate 	}
5687*7c478bd9Sstevel@tonic-gate 
5688*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
5689*7c478bd9Sstevel@tonic-gate }
5690*7c478bd9Sstevel@tonic-gate 
5691*7c478bd9Sstevel@tonic-gate static int
5692*7c478bd9Sstevel@tonic-gate i_mdi_power_all_phci(mdi_client_t *ct)
5693*7c478bd9Sstevel@tonic-gate {
5694*7c478bd9Sstevel@tonic-gate 	mdi_pathinfo_t  *pip;
5695*7c478bd9Sstevel@tonic-gate 	int		succeeded = 0;
5696*7c478bd9Sstevel@tonic-gate 
5697*7c478bd9Sstevel@tonic-gate 	pip = (mdi_pathinfo_t *)ct->ct_path_head;
5698*7c478bd9Sstevel@tonic-gate 	while (pip != NULL) {
5699*7c478bd9Sstevel@tonic-gate 		mdi_hold_path(pip);
5700*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
5701*7c478bd9Sstevel@tonic-gate 		if (i_mdi_power_one_phci(pip) == MDI_SUCCESS)
5702*7c478bd9Sstevel@tonic-gate 			succeeded = 1;
5703*7c478bd9Sstevel@tonic-gate 
5704*7c478bd9Sstevel@tonic-gate 		ASSERT(ct == MDI_PI(pip)->pi_client);
5705*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_LOCK(ct);
5706*7c478bd9Sstevel@tonic-gate 		mdi_rele_path(pip);
5707*7c478bd9Sstevel@tonic-gate 		pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
5708*7c478bd9Sstevel@tonic-gate 	}
5709*7c478bd9Sstevel@tonic-gate 
5710*7c478bd9Sstevel@tonic-gate 	return (succeeded ? MDI_SUCCESS : MDI_FAILURE);
5711*7c478bd9Sstevel@tonic-gate }
5712*7c478bd9Sstevel@tonic-gate 
5713*7c478bd9Sstevel@tonic-gate /*
5714*7c478bd9Sstevel@tonic-gate  * mdi_bus_power():
5715*7c478bd9Sstevel@tonic-gate  *		1. Place the phci(s) into powered up state so that
5716*7c478bd9Sstevel@tonic-gate  *		   client can do power management
5717*7c478bd9Sstevel@tonic-gate  *		2. Ensure phci powered up as client power managing
5718*7c478bd9Sstevel@tonic-gate  * Return Values:
5719*7c478bd9Sstevel@tonic-gate  *		MDI_SUCCESS
5720*7c478bd9Sstevel@tonic-gate  *		MDI_FAILURE
5721*7c478bd9Sstevel@tonic-gate  */
5722*7c478bd9Sstevel@tonic-gate int
5723*7c478bd9Sstevel@tonic-gate mdi_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op,
5724*7c478bd9Sstevel@tonic-gate     void *arg, void *result)
5725*7c478bd9Sstevel@tonic-gate {
5726*7c478bd9Sstevel@tonic-gate 	int			ret = MDI_SUCCESS;
5727*7c478bd9Sstevel@tonic-gate 	pm_bp_child_pwrchg_t	*bpc;
5728*7c478bd9Sstevel@tonic-gate 	mdi_client_t		*ct;
5729*7c478bd9Sstevel@tonic-gate 	dev_info_t		*cdip;
5730*7c478bd9Sstevel@tonic-gate 	pm_bp_has_changed_t	*bphc;
5731*7c478bd9Sstevel@tonic-gate 
5732*7c478bd9Sstevel@tonic-gate 	/*
5733*7c478bd9Sstevel@tonic-gate 	 * BUS_POWER_NOINVOL not supported
5734*7c478bd9Sstevel@tonic-gate 	 */
5735*7c478bd9Sstevel@tonic-gate 	if (op == BUS_POWER_NOINVOL)
5736*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5737*7c478bd9Sstevel@tonic-gate 
5738*7c478bd9Sstevel@tonic-gate 	/*
5739*7c478bd9Sstevel@tonic-gate 	 * ignore other OPs.
5740*7c478bd9Sstevel@tonic-gate 	 * return quickly to save cou cycles on the ct processing
5741*7c478bd9Sstevel@tonic-gate 	 */
5742*7c478bd9Sstevel@tonic-gate 	switch (op) {
5743*7c478bd9Sstevel@tonic-gate 	case BUS_POWER_PRE_NOTIFICATION:
5744*7c478bd9Sstevel@tonic-gate 	case BUS_POWER_POST_NOTIFICATION:
5745*7c478bd9Sstevel@tonic-gate 		bpc = (pm_bp_child_pwrchg_t *)arg;
5746*7c478bd9Sstevel@tonic-gate 		cdip = bpc->bpc_dip;
5747*7c478bd9Sstevel@tonic-gate 		break;
5748*7c478bd9Sstevel@tonic-gate 	case BUS_POWER_HAS_CHANGED:
5749*7c478bd9Sstevel@tonic-gate 		bphc = (pm_bp_has_changed_t *)arg;
5750*7c478bd9Sstevel@tonic-gate 		cdip = bphc->bphc_dip;
5751*7c478bd9Sstevel@tonic-gate 		break;
5752*7c478bd9Sstevel@tonic-gate 	default:
5753*7c478bd9Sstevel@tonic-gate 		return (pm_busop_bus_power(parent, impl_arg, op, arg, result));
5754*7c478bd9Sstevel@tonic-gate 	}
5755*7c478bd9Sstevel@tonic-gate 
5756*7c478bd9Sstevel@tonic-gate 	ASSERT(MDI_CLIENT(cdip));
5757*7c478bd9Sstevel@tonic-gate 
5758*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(cdip);
5759*7c478bd9Sstevel@tonic-gate 	if (ct == NULL)
5760*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5761*7c478bd9Sstevel@tonic-gate 
5762*7c478bd9Sstevel@tonic-gate 	/*
5763*7c478bd9Sstevel@tonic-gate 	 * wait till the mdi_pathinfo node state change are processed
5764*7c478bd9Sstevel@tonic-gate 	 */
5765*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
5766*7c478bd9Sstevel@tonic-gate 	switch (op) {
5767*7c478bd9Sstevel@tonic-gate 	case BUS_POWER_PRE_NOTIFICATION:
5768*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power "
5769*7c478bd9Sstevel@tonic-gate 		    "BUS_POWER_PRE_NOTIFICATION:"
5770*7c478bd9Sstevel@tonic-gate 		    "%s@%s, olevel=%d, nlevel=%d, comp=%d\n",
5771*7c478bd9Sstevel@tonic-gate 		    PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip),
5772*7c478bd9Sstevel@tonic-gate 		    bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp));
5773*7c478bd9Sstevel@tonic-gate 
5774*7c478bd9Sstevel@tonic-gate 		/* serialize power level change per client */
5775*7c478bd9Sstevel@tonic-gate 		while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
5776*7c478bd9Sstevel@tonic-gate 			cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
5777*7c478bd9Sstevel@tonic-gate 
5778*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_SET_POWER_TRANSITION(ct);
5779*7c478bd9Sstevel@tonic-gate 
5780*7c478bd9Sstevel@tonic-gate 		if (ct->ct_power_cnt == 0) {
5781*7c478bd9Sstevel@tonic-gate 			ret = i_mdi_power_all_phci(ct);
5782*7c478bd9Sstevel@tonic-gate 		}
5783*7c478bd9Sstevel@tonic-gate 
5784*7c478bd9Sstevel@tonic-gate 		/*
5785*7c478bd9Sstevel@tonic-gate 		 * if new_level > 0:
5786*7c478bd9Sstevel@tonic-gate 		 *	- hold phci(s)
5787*7c478bd9Sstevel@tonic-gate 		 *	- power up phci(s) if not already
5788*7c478bd9Sstevel@tonic-gate 		 * ignore power down
5789*7c478bd9Sstevel@tonic-gate 		 */
5790*7c478bd9Sstevel@tonic-gate 		if (bpc->bpc_nlevel > 0) {
5791*7c478bd9Sstevel@tonic-gate 			if (!DEVI_IS_ATTACHING(ct->ct_dip)) {
5792*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip,
5793*7c478bd9Sstevel@tonic-gate 				    "mdi_bus_power i_mdi_pm_hold_client\n"));
5794*7c478bd9Sstevel@tonic-gate 				i_mdi_pm_hold_client(ct, ct->ct_path_count);
5795*7c478bd9Sstevel@tonic-gate 			}
5796*7c478bd9Sstevel@tonic-gate 		}
5797*7c478bd9Sstevel@tonic-gate 		break;
5798*7c478bd9Sstevel@tonic-gate 	case BUS_POWER_POST_NOTIFICATION:
5799*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power "
5800*7c478bd9Sstevel@tonic-gate 		    "BUS_POWER_POST_NOTIFICATION:"
5801*7c478bd9Sstevel@tonic-gate 		    "%s@%s, olevel=%d, nlevel=%d, comp=%d result=%d\n",
5802*7c478bd9Sstevel@tonic-gate 		    PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip),
5803*7c478bd9Sstevel@tonic-gate 		    bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp,
5804*7c478bd9Sstevel@tonic-gate 		    *(int *)result));
5805*7c478bd9Sstevel@tonic-gate 
5806*7c478bd9Sstevel@tonic-gate 		if (*(int *)result == DDI_SUCCESS) {
5807*7c478bd9Sstevel@tonic-gate 			if (bpc->bpc_nlevel > 0) {
5808*7c478bd9Sstevel@tonic-gate 				MDI_CLIENT_SET_POWER_UP(ct);
5809*7c478bd9Sstevel@tonic-gate 			} else {
5810*7c478bd9Sstevel@tonic-gate 				MDI_CLIENT_SET_POWER_DOWN(ct);
5811*7c478bd9Sstevel@tonic-gate 			}
5812*7c478bd9Sstevel@tonic-gate 		}
5813*7c478bd9Sstevel@tonic-gate 
5814*7c478bd9Sstevel@tonic-gate 		/* release the hold we did in pre-notification */
5815*7c478bd9Sstevel@tonic-gate 		if (bpc->bpc_nlevel > 0 && (*(int *)result != DDI_SUCCESS) &&
5816*7c478bd9Sstevel@tonic-gate 		    !DEVI_IS_ATTACHING(ct->ct_dip)) {
5817*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip,
5818*7c478bd9Sstevel@tonic-gate 			    "mdi_bus_power i_mdi_pm_rele_client\n"));
5819*7c478bd9Sstevel@tonic-gate 			i_mdi_pm_rele_client(ct, ct->ct_path_count);
5820*7c478bd9Sstevel@tonic-gate 		}
5821*7c478bd9Sstevel@tonic-gate 
5822*7c478bd9Sstevel@tonic-gate 		if (bpc->bpc_nlevel == 0 && (*(int *)result == DDI_SUCCESS)) {
5823*7c478bd9Sstevel@tonic-gate 			/* another thread might started attaching */
5824*7c478bd9Sstevel@tonic-gate 			if (DEVI_IS_ATTACHING(ct->ct_dip)) {
5825*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip,
5826*7c478bd9Sstevel@tonic-gate 				    "mdi_bus_power i_mdi_pm_rele_client\n"));
5827*7c478bd9Sstevel@tonic-gate 				i_mdi_pm_rele_client(ct, ct->ct_path_count);
5828*7c478bd9Sstevel@tonic-gate 			/* detaching has been taken care in pm_post_unconfig */
5829*7c478bd9Sstevel@tonic-gate 			} else if (!DEVI_IS_DETACHING(ct->ct_dip)) {
5830*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip,
5831*7c478bd9Sstevel@tonic-gate 				    "mdi_bus_power i_mdi_pm_reset_client\n"));
5832*7c478bd9Sstevel@tonic-gate 				i_mdi_pm_reset_client(ct);
5833*7c478bd9Sstevel@tonic-gate 			}
5834*7c478bd9Sstevel@tonic-gate 		}
5835*7c478bd9Sstevel@tonic-gate 
5836*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_CLEAR_POWER_TRANSITION(ct);
5837*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&ct->ct_powerchange_cv);
5838*7c478bd9Sstevel@tonic-gate 
5839*7c478bd9Sstevel@tonic-gate 		break;
5840*7c478bd9Sstevel@tonic-gate 
5841*7c478bd9Sstevel@tonic-gate 	/* need to do more */
5842*7c478bd9Sstevel@tonic-gate 	case BUS_POWER_HAS_CHANGED:
5843*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, "mdi_bus_power "
5844*7c478bd9Sstevel@tonic-gate 		    "BUS_POWER_HAS_CHANGED:"
5845*7c478bd9Sstevel@tonic-gate 		    "%s@%s, olevel=%d, nlevel=%d, comp=%d\n",
5846*7c478bd9Sstevel@tonic-gate 		    PM_NAME(bphc->bphc_dip), PM_ADDR(bphc->bphc_dip),
5847*7c478bd9Sstevel@tonic-gate 		    bphc->bphc_olevel, bphc->bphc_nlevel, bphc->bphc_comp));
5848*7c478bd9Sstevel@tonic-gate 
5849*7c478bd9Sstevel@tonic-gate 		if (bphc->bphc_nlevel > 0 &&
5850*7c478bd9Sstevel@tonic-gate 		    bphc->bphc_nlevel > bphc->bphc_olevel) {
5851*7c478bd9Sstevel@tonic-gate 			if (ct->ct_power_cnt == 0) {
5852*7c478bd9Sstevel@tonic-gate 				ret = i_mdi_power_all_phci(ct);
5853*7c478bd9Sstevel@tonic-gate 			}
5854*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip,
5855*7c478bd9Sstevel@tonic-gate 			    "mdi_bus_power i_mdi_pm_hold_client\n"));
5856*7c478bd9Sstevel@tonic-gate 			i_mdi_pm_hold_client(ct, ct->ct_path_count);
5857*7c478bd9Sstevel@tonic-gate 		}
5858*7c478bd9Sstevel@tonic-gate 
5859*7c478bd9Sstevel@tonic-gate 		if (bphc->bphc_nlevel == 0 && bphc->bphc_olevel != -1) {
5860*7c478bd9Sstevel@tonic-gate 			MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip,
5861*7c478bd9Sstevel@tonic-gate 			    "mdi_bus_power i_mdi_pm_rele_client\n"));
5862*7c478bd9Sstevel@tonic-gate 			i_mdi_pm_rele_client(ct, ct->ct_path_count);
5863*7c478bd9Sstevel@tonic-gate 		}
5864*7c478bd9Sstevel@tonic-gate 		break;
5865*7c478bd9Sstevel@tonic-gate 	}
5866*7c478bd9Sstevel@tonic-gate 
5867*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
5868*7c478bd9Sstevel@tonic-gate 	return (ret);
5869*7c478bd9Sstevel@tonic-gate }
5870*7c478bd9Sstevel@tonic-gate 
5871*7c478bd9Sstevel@tonic-gate static int
5872*7c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config_one(dev_info_t *child)
5873*7c478bd9Sstevel@tonic-gate {
5874*7c478bd9Sstevel@tonic-gate 	int		ret = MDI_SUCCESS;
5875*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
5876*7c478bd9Sstevel@tonic-gate 
5877*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(child);
5878*7c478bd9Sstevel@tonic-gate 	if (ct == NULL)
5879*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5880*7c478bd9Sstevel@tonic-gate 
5881*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
5882*7c478bd9Sstevel@tonic-gate 	while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
5883*7c478bd9Sstevel@tonic-gate 		cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
5884*7c478bd9Sstevel@tonic-gate 
5885*7c478bd9Sstevel@tonic-gate 	if (!MDI_CLIENT_IS_FAILED(ct)) {
5886*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
5887*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
5888*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_pre_config_one already configured\n"));
5889*7c478bd9Sstevel@tonic-gate 		return (MDI_SUCCESS);
5890*7c478bd9Sstevel@tonic-gate 	}
5891*7c478bd9Sstevel@tonic-gate 
5892*7c478bd9Sstevel@tonic-gate 	if (ct->ct_powercnt_held) {
5893*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
5894*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
5895*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_pre_config_one ALREADY held\n"));
5896*7c478bd9Sstevel@tonic-gate 		return (MDI_SUCCESS);
5897*7c478bd9Sstevel@tonic-gate 	}
5898*7c478bd9Sstevel@tonic-gate 
5899*7c478bd9Sstevel@tonic-gate 	if (ct->ct_power_cnt == 0) {
5900*7c478bd9Sstevel@tonic-gate 		ret = i_mdi_power_all_phci(ct);
5901*7c478bd9Sstevel@tonic-gate 	}
5902*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, child,
5903*7c478bd9Sstevel@tonic-gate 	    "i_mdi_pm_pre_config_one i_mdi_pm_hold_client\n"));
5904*7c478bd9Sstevel@tonic-gate 	i_mdi_pm_hold_client(ct, ct->ct_path_count);
5905*7c478bd9Sstevel@tonic-gate 	ct->ct_powercnt_held = 1;
5906*7c478bd9Sstevel@tonic-gate 	ct->ct_powercnt_reset = 0;
5907*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
5908*7c478bd9Sstevel@tonic-gate 	return (ret);
5909*7c478bd9Sstevel@tonic-gate }
5910*7c478bd9Sstevel@tonic-gate 
5911*7c478bd9Sstevel@tonic-gate static int
5912*7c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config(dev_info_t *parent, dev_info_t *child)
5913*7c478bd9Sstevel@tonic-gate {
5914*7c478bd9Sstevel@tonic-gate 	int			ret = MDI_SUCCESS;
5915*7c478bd9Sstevel@tonic-gate 	dev_info_t		*cdip;
5916*7c478bd9Sstevel@tonic-gate 	int			circ;
5917*7c478bd9Sstevel@tonic-gate 
5918*7c478bd9Sstevel@tonic-gate 	ASSERT(MDI_VHCI(parent));
5919*7c478bd9Sstevel@tonic-gate 
5920*7c478bd9Sstevel@tonic-gate 	/* ndi_devi_config_one */
5921*7c478bd9Sstevel@tonic-gate 	if (child) {
5922*7c478bd9Sstevel@tonic-gate 		return (i_mdi_pm_pre_config_one(child));
5923*7c478bd9Sstevel@tonic-gate 	}
5924*7c478bd9Sstevel@tonic-gate 
5925*7c478bd9Sstevel@tonic-gate 	/* devi_config_common */
5926*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(parent, &circ);
5927*7c478bd9Sstevel@tonic-gate 	cdip = ddi_get_child(parent);
5928*7c478bd9Sstevel@tonic-gate 	while (cdip) {
5929*7c478bd9Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
5930*7c478bd9Sstevel@tonic-gate 
5931*7c478bd9Sstevel@tonic-gate 		ret = i_mdi_pm_pre_config_one(cdip);
5932*7c478bd9Sstevel@tonic-gate 		if (ret != MDI_SUCCESS)
5933*7c478bd9Sstevel@tonic-gate 			break;
5934*7c478bd9Sstevel@tonic-gate 		cdip = next;
5935*7c478bd9Sstevel@tonic-gate 	}
5936*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(parent, circ);
5937*7c478bd9Sstevel@tonic-gate 	return (ret);
5938*7c478bd9Sstevel@tonic-gate }
5939*7c478bd9Sstevel@tonic-gate 
5940*7c478bd9Sstevel@tonic-gate static int
5941*7c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig_one(dev_info_t *child, int *held, int flags)
5942*7c478bd9Sstevel@tonic-gate {
5943*7c478bd9Sstevel@tonic-gate 	int		ret = MDI_SUCCESS;
5944*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
5945*7c478bd9Sstevel@tonic-gate 
5946*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(child);
5947*7c478bd9Sstevel@tonic-gate 	if (ct == NULL)
5948*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5949*7c478bd9Sstevel@tonic-gate 
5950*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
5951*7c478bd9Sstevel@tonic-gate 	while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
5952*7c478bd9Sstevel@tonic-gate 		cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
5953*7c478bd9Sstevel@tonic-gate 
5954*7c478bd9Sstevel@tonic-gate 	if (i_ddi_node_state(ct->ct_dip) < DS_READY) {
5955*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
5956*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_pre_unconfig node detached already\n"));
5957*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
5958*7c478bd9Sstevel@tonic-gate 		return (MDI_SUCCESS);
5959*7c478bd9Sstevel@tonic-gate 	}
5960*7c478bd9Sstevel@tonic-gate 
5961*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT_IS_POWERED_DOWN(ct) &&
5962*7c478bd9Sstevel@tonic-gate 	    (flags & NDI_AUTODETACH)) {
5963*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
5964*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_pre_unconfig auto-modunload\n"));
5965*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
5966*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
5967*7c478bd9Sstevel@tonic-gate 	}
5968*7c478bd9Sstevel@tonic-gate 
5969*7c478bd9Sstevel@tonic-gate 	if (ct->ct_powercnt_held) {
5970*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
5971*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_pre_unconfig ct_powercnt_held\n"));
5972*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
5973*7c478bd9Sstevel@tonic-gate 		*held = 1;
5974*7c478bd9Sstevel@tonic-gate 		return (MDI_SUCCESS);
5975*7c478bd9Sstevel@tonic-gate 	}
5976*7c478bd9Sstevel@tonic-gate 
5977*7c478bd9Sstevel@tonic-gate 	if (ct->ct_power_cnt == 0) {
5978*7c478bd9Sstevel@tonic-gate 		ret = i_mdi_power_all_phci(ct);
5979*7c478bd9Sstevel@tonic-gate 	}
5980*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, child,
5981*7c478bd9Sstevel@tonic-gate 	    "i_mdi_pm_pre_unconfig i_mdi_pm_hold_client\n"));
5982*7c478bd9Sstevel@tonic-gate 	i_mdi_pm_hold_client(ct, ct->ct_path_count);
5983*7c478bd9Sstevel@tonic-gate 	ct->ct_powercnt_held = 1;
5984*7c478bd9Sstevel@tonic-gate 	ct->ct_powercnt_reset = 0;
5985*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
5986*7c478bd9Sstevel@tonic-gate 	if (ret == MDI_SUCCESS)
5987*7c478bd9Sstevel@tonic-gate 		*held = 1;
5988*7c478bd9Sstevel@tonic-gate 	return (ret);
5989*7c478bd9Sstevel@tonic-gate }
5990*7c478bd9Sstevel@tonic-gate 
5991*7c478bd9Sstevel@tonic-gate static int
5992*7c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig(dev_info_t *parent, dev_info_t *child, int *held,
5993*7c478bd9Sstevel@tonic-gate     int flags)
5994*7c478bd9Sstevel@tonic-gate {
5995*7c478bd9Sstevel@tonic-gate 	int			ret = MDI_SUCCESS;
5996*7c478bd9Sstevel@tonic-gate 	dev_info_t		*cdip;
5997*7c478bd9Sstevel@tonic-gate 	int			circ;
5998*7c478bd9Sstevel@tonic-gate 
5999*7c478bd9Sstevel@tonic-gate 	ASSERT(MDI_VHCI(parent));
6000*7c478bd9Sstevel@tonic-gate 	*held = 0;
6001*7c478bd9Sstevel@tonic-gate 
6002*7c478bd9Sstevel@tonic-gate 	/* ndi_devi_unconfig_one */
6003*7c478bd9Sstevel@tonic-gate 	if (child) {
6004*7c478bd9Sstevel@tonic-gate 		return (i_mdi_pm_pre_unconfig_one(child, held, flags));
6005*7c478bd9Sstevel@tonic-gate 	}
6006*7c478bd9Sstevel@tonic-gate 
6007*7c478bd9Sstevel@tonic-gate 	/* devi_unconfig_common */
6008*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(parent, &circ);
6009*7c478bd9Sstevel@tonic-gate 	cdip = ddi_get_child(parent);
6010*7c478bd9Sstevel@tonic-gate 	while (cdip) {
6011*7c478bd9Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
6012*7c478bd9Sstevel@tonic-gate 
6013*7c478bd9Sstevel@tonic-gate 		ret = i_mdi_pm_pre_unconfig_one(cdip, held, flags);
6014*7c478bd9Sstevel@tonic-gate 		cdip = next;
6015*7c478bd9Sstevel@tonic-gate 	}
6016*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(parent, circ);
6017*7c478bd9Sstevel@tonic-gate 
6018*7c478bd9Sstevel@tonic-gate 	if (*held)
6019*7c478bd9Sstevel@tonic-gate 		ret = MDI_SUCCESS;
6020*7c478bd9Sstevel@tonic-gate 
6021*7c478bd9Sstevel@tonic-gate 	return (ret);
6022*7c478bd9Sstevel@tonic-gate }
6023*7c478bd9Sstevel@tonic-gate 
6024*7c478bd9Sstevel@tonic-gate static void
6025*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(dev_info_t *child)
6026*7c478bd9Sstevel@tonic-gate {
6027*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
6028*7c478bd9Sstevel@tonic-gate 
6029*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(child);
6030*7c478bd9Sstevel@tonic-gate 	if (ct == NULL)
6031*7c478bd9Sstevel@tonic-gate 		return;
6032*7c478bd9Sstevel@tonic-gate 
6033*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
6034*7c478bd9Sstevel@tonic-gate 	while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
6035*7c478bd9Sstevel@tonic-gate 		cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
6036*7c478bd9Sstevel@tonic-gate 
6037*7c478bd9Sstevel@tonic-gate 	if (ct->ct_powercnt_reset || !ct->ct_powercnt_held) {
6038*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
6039*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_post_config_one NOT held\n"));
6040*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
6041*7c478bd9Sstevel@tonic-gate 		return;
6042*7c478bd9Sstevel@tonic-gate 	}
6043*7c478bd9Sstevel@tonic-gate 
6044*7c478bd9Sstevel@tonic-gate 	/* client has not been updated */
6045*7c478bd9Sstevel@tonic-gate 	if (MDI_CLIENT_IS_FAILED(ct)) {
6046*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
6047*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_post_config_one NOT configured\n"));
6048*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
6049*7c478bd9Sstevel@tonic-gate 		return;
6050*7c478bd9Sstevel@tonic-gate 	}
6051*7c478bd9Sstevel@tonic-gate 
6052*7c478bd9Sstevel@tonic-gate 	/* another thread might have powered it down or detached it */
6053*7c478bd9Sstevel@tonic-gate 	if ((MDI_CLIENT_IS_POWERED_DOWN(ct) &&
6054*7c478bd9Sstevel@tonic-gate 	    !DEVI_IS_ATTACHING(ct->ct_dip)) ||
6055*7c478bd9Sstevel@tonic-gate 	    (i_ddi_node_state(ct->ct_dip) < DS_READY &&
6056*7c478bd9Sstevel@tonic-gate 	    !DEVI_IS_ATTACHING(ct->ct_dip))) {
6057*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
6058*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_post_config i_mdi_pm_reset_client\n"));
6059*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_reset_client(ct);
6060*7c478bd9Sstevel@tonic-gate 	} else {
6061*7c478bd9Sstevel@tonic-gate 		mdi_pathinfo_t	*pip, *next;
6062*7c478bd9Sstevel@tonic-gate 		int	valid_path_count = 0;
6063*7c478bd9Sstevel@tonic-gate 
6064*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
6065*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_post_config i_mdi_pm_rele_client\n"));
6066*7c478bd9Sstevel@tonic-gate 		pip = ct->ct_path_head;
6067*7c478bd9Sstevel@tonic-gate 		while (pip != NULL) {
6068*7c478bd9Sstevel@tonic-gate 			MDI_PI_LOCK(pip);
6069*7c478bd9Sstevel@tonic-gate 			next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
6070*7c478bd9Sstevel@tonic-gate 			if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK)
6071*7c478bd9Sstevel@tonic-gate 				== MDI_PATHINFO_STATE_ONLINE ||
6072*7c478bd9Sstevel@tonic-gate 			    (MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK)
6073*7c478bd9Sstevel@tonic-gate 				== MDI_PATHINFO_STATE_STANDBY)
6074*7c478bd9Sstevel@tonic-gate 				valid_path_count ++;
6075*7c478bd9Sstevel@tonic-gate 			MDI_PI_UNLOCK(pip);
6076*7c478bd9Sstevel@tonic-gate 			pip = next;
6077*7c478bd9Sstevel@tonic-gate 		}
6078*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_rele_client(ct, valid_path_count);
6079*7c478bd9Sstevel@tonic-gate 	}
6080*7c478bd9Sstevel@tonic-gate 	ct->ct_powercnt_held = 0;
6081*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
6082*7c478bd9Sstevel@tonic-gate }
6083*7c478bd9Sstevel@tonic-gate 
6084*7c478bd9Sstevel@tonic-gate static void
6085*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(dev_info_t *parent, dev_info_t *child)
6086*7c478bd9Sstevel@tonic-gate {
6087*7c478bd9Sstevel@tonic-gate 	int		circ;
6088*7c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip;
6089*7c478bd9Sstevel@tonic-gate 	ASSERT(MDI_VHCI(parent));
6090*7c478bd9Sstevel@tonic-gate 
6091*7c478bd9Sstevel@tonic-gate 	/* ndi_devi_config_one */
6092*7c478bd9Sstevel@tonic-gate 	if (child) {
6093*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_post_config_one(child);
6094*7c478bd9Sstevel@tonic-gate 		return;
6095*7c478bd9Sstevel@tonic-gate 	}
6096*7c478bd9Sstevel@tonic-gate 
6097*7c478bd9Sstevel@tonic-gate 	/* devi_config_common */
6098*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(parent, &circ);
6099*7c478bd9Sstevel@tonic-gate 	cdip = ddi_get_child(parent);
6100*7c478bd9Sstevel@tonic-gate 	while (cdip) {
6101*7c478bd9Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
6102*7c478bd9Sstevel@tonic-gate 
6103*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_post_config_one(cdip);
6104*7c478bd9Sstevel@tonic-gate 		cdip = next;
6105*7c478bd9Sstevel@tonic-gate 	}
6106*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(parent, circ);
6107*7c478bd9Sstevel@tonic-gate }
6108*7c478bd9Sstevel@tonic-gate 
6109*7c478bd9Sstevel@tonic-gate static void
6110*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(dev_info_t *child)
6111*7c478bd9Sstevel@tonic-gate {
6112*7c478bd9Sstevel@tonic-gate 	mdi_client_t	*ct;
6113*7c478bd9Sstevel@tonic-gate 
6114*7c478bd9Sstevel@tonic-gate 	ct = i_devi_get_client(child);
6115*7c478bd9Sstevel@tonic-gate 	if (ct == NULL)
6116*7c478bd9Sstevel@tonic-gate 		return;
6117*7c478bd9Sstevel@tonic-gate 
6118*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_LOCK(ct);
6119*7c478bd9Sstevel@tonic-gate 	while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
6120*7c478bd9Sstevel@tonic-gate 		cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
6121*7c478bd9Sstevel@tonic-gate 
6122*7c478bd9Sstevel@tonic-gate 	if (!ct->ct_powercnt_held) {
6123*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
6124*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_post_unconfig NOT held\n"));
6125*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
6126*7c478bd9Sstevel@tonic-gate 		return;
6127*7c478bd9Sstevel@tonic-gate 	}
6128*7c478bd9Sstevel@tonic-gate 
6129*7c478bd9Sstevel@tonic-gate 	/* failure detaching or another thread just attached it */
6130*7c478bd9Sstevel@tonic-gate 	if ((MDI_CLIENT_IS_POWERED_DOWN(ct) &&
6131*7c478bd9Sstevel@tonic-gate 	    i_ddi_node_state(ct->ct_dip) == DS_READY) ||
6132*7c478bd9Sstevel@tonic-gate 	    (i_ddi_node_state(ct->ct_dip) != DS_READY &&
6133*7c478bd9Sstevel@tonic-gate 	    !DEVI_IS_ATTACHING(ct->ct_dip))) {
6134*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, child,
6135*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_post_unconfig i_mdi_pm_reset_client\n"));
6136*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_reset_client(ct);
6137*7c478bd9Sstevel@tonic-gate 	}
6138*7c478bd9Sstevel@tonic-gate 
6139*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, child,
6140*7c478bd9Sstevel@tonic-gate 	    "i_mdi_pm_post_unconfig not changed\n"));
6141*7c478bd9Sstevel@tonic-gate 	MDI_CLIENT_UNLOCK(ct);
6142*7c478bd9Sstevel@tonic-gate }
6143*7c478bd9Sstevel@tonic-gate 
6144*7c478bd9Sstevel@tonic-gate static void
6145*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(dev_info_t *parent, dev_info_t *child, int held)
6146*7c478bd9Sstevel@tonic-gate {
6147*7c478bd9Sstevel@tonic-gate 	int			circ;
6148*7c478bd9Sstevel@tonic-gate 	dev_info_t		*cdip;
6149*7c478bd9Sstevel@tonic-gate 
6150*7c478bd9Sstevel@tonic-gate 	ASSERT(MDI_VHCI(parent));
6151*7c478bd9Sstevel@tonic-gate 
6152*7c478bd9Sstevel@tonic-gate 	if (!held) {
6153*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(4, (CE_NOTE, parent,
6154*7c478bd9Sstevel@tonic-gate 		    "i_mdi_pm_post_unconfig held = %d\n", held));
6155*7c478bd9Sstevel@tonic-gate 		return;
6156*7c478bd9Sstevel@tonic-gate 	}
6157*7c478bd9Sstevel@tonic-gate 
6158*7c478bd9Sstevel@tonic-gate 	if (child) {
6159*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_post_unconfig_one(child);
6160*7c478bd9Sstevel@tonic-gate 		return;
6161*7c478bd9Sstevel@tonic-gate 	}
6162*7c478bd9Sstevel@tonic-gate 
6163*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(parent, &circ);
6164*7c478bd9Sstevel@tonic-gate 	cdip = ddi_get_child(parent);
6165*7c478bd9Sstevel@tonic-gate 	while (cdip) {
6166*7c478bd9Sstevel@tonic-gate 		dev_info_t *next = ddi_get_next_sibling(cdip);
6167*7c478bd9Sstevel@tonic-gate 
6168*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_post_unconfig_one(cdip);
6169*7c478bd9Sstevel@tonic-gate 		cdip = next;
6170*7c478bd9Sstevel@tonic-gate 	}
6171*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(parent, circ);
6172*7c478bd9Sstevel@tonic-gate }
6173*7c478bd9Sstevel@tonic-gate 
6174*7c478bd9Sstevel@tonic-gate int
6175*7c478bd9Sstevel@tonic-gate mdi_power(dev_info_t *vdip, mdi_pm_op_t op, void *args, char *devnm, int flags)
6176*7c478bd9Sstevel@tonic-gate {
6177*7c478bd9Sstevel@tonic-gate 	int			circ, ret = MDI_SUCCESS;
6178*7c478bd9Sstevel@tonic-gate 	dev_info_t		*client_dip = NULL;
6179*7c478bd9Sstevel@tonic-gate 	mdi_client_t		*ct;
6180*7c478bd9Sstevel@tonic-gate 
6181*7c478bd9Sstevel@tonic-gate 	/*
6182*7c478bd9Sstevel@tonic-gate 	 * Handling ndi_devi_config_one and ndi_devi_unconfig_one.
6183*7c478bd9Sstevel@tonic-gate 	 * Power up pHCI for the named client device.
6184*7c478bd9Sstevel@tonic-gate 	 * Note: Before the client is enumerated under vhci by phci,
6185*7c478bd9Sstevel@tonic-gate 	 * client_dip can be NULL. Then proceed to power up all the
6186*7c478bd9Sstevel@tonic-gate 	 * pHCIs.
6187*7c478bd9Sstevel@tonic-gate 	 */
6188*7c478bd9Sstevel@tonic-gate 	if (devnm != NULL) {
6189*7c478bd9Sstevel@tonic-gate 		ndi_devi_enter(vdip, &circ);
6190*7c478bd9Sstevel@tonic-gate 		client_dip = ndi_devi_findchild(vdip, devnm);
6191*7c478bd9Sstevel@tonic-gate 		ndi_devi_exit(vdip, circ);
6192*7c478bd9Sstevel@tonic-gate 	}
6193*7c478bd9Sstevel@tonic-gate 
6194*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(4, (CE_NOTE, vdip, "mdi_power op = %d\n", op));
6195*7c478bd9Sstevel@tonic-gate 
6196*7c478bd9Sstevel@tonic-gate 	switch (op) {
6197*7c478bd9Sstevel@tonic-gate 	case MDI_PM_PRE_CONFIG:
6198*7c478bd9Sstevel@tonic-gate 		ret = i_mdi_pm_pre_config(vdip, client_dip);
6199*7c478bd9Sstevel@tonic-gate 
6200*7c478bd9Sstevel@tonic-gate 		break;
6201*7c478bd9Sstevel@tonic-gate 	case MDI_PM_PRE_UNCONFIG:
6202*7c478bd9Sstevel@tonic-gate 		ret = i_mdi_pm_pre_unconfig(vdip, client_dip, (int *)args,
6203*7c478bd9Sstevel@tonic-gate 		    flags);
6204*7c478bd9Sstevel@tonic-gate 
6205*7c478bd9Sstevel@tonic-gate 		break;
6206*7c478bd9Sstevel@tonic-gate 	case MDI_PM_POST_CONFIG:
6207*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_post_config(vdip, client_dip);
6208*7c478bd9Sstevel@tonic-gate 
6209*7c478bd9Sstevel@tonic-gate 		break;
6210*7c478bd9Sstevel@tonic-gate 	case MDI_PM_POST_UNCONFIG:
6211*7c478bd9Sstevel@tonic-gate 		i_mdi_pm_post_unconfig(vdip, client_dip, *(int *)args);
6212*7c478bd9Sstevel@tonic-gate 
6213*7c478bd9Sstevel@tonic-gate 		break;
6214*7c478bd9Sstevel@tonic-gate 	case MDI_PM_HOLD_POWER:
6215*7c478bd9Sstevel@tonic-gate 	case MDI_PM_RELE_POWER:
6216*7c478bd9Sstevel@tonic-gate 		ASSERT(args);
6217*7c478bd9Sstevel@tonic-gate 
6218*7c478bd9Sstevel@tonic-gate 		client_dip = (dev_info_t *)args;
6219*7c478bd9Sstevel@tonic-gate 		ASSERT(MDI_CLIENT(client_dip));
6220*7c478bd9Sstevel@tonic-gate 
6221*7c478bd9Sstevel@tonic-gate 		ct = i_devi_get_client(client_dip);
6222*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_LOCK(ct);
6223*7c478bd9Sstevel@tonic-gate 
6224*7c478bd9Sstevel@tonic-gate 		if (op == MDI_PM_HOLD_POWER) {
6225*7c478bd9Sstevel@tonic-gate 			if (ct->ct_power_cnt == 0) {
6226*7c478bd9Sstevel@tonic-gate 				(void) i_mdi_power_all_phci(ct);
6227*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(4, (CE_NOTE, client_dip,
6228*7c478bd9Sstevel@tonic-gate 				    "mdi_power i_mdi_pm_hold_client\n"));
6229*7c478bd9Sstevel@tonic-gate 				i_mdi_pm_hold_client(ct, ct->ct_path_count);
6230*7c478bd9Sstevel@tonic-gate 			}
6231*7c478bd9Sstevel@tonic-gate 		} else {
6232*7c478bd9Sstevel@tonic-gate 			if (DEVI_IS_ATTACHING(ct->ct_dip)) {
6233*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(4, (CE_NOTE, client_dip,
6234*7c478bd9Sstevel@tonic-gate 				    "mdi_power i_mdi_pm_rele_client\n"));
6235*7c478bd9Sstevel@tonic-gate 				i_mdi_pm_rele_client(ct, ct->ct_path_count);
6236*7c478bd9Sstevel@tonic-gate 			} else {
6237*7c478bd9Sstevel@tonic-gate 				MDI_DEBUG(4, (CE_NOTE, client_dip,
6238*7c478bd9Sstevel@tonic-gate 				    "mdi_power i_mdi_pm_reset_client\n"));
6239*7c478bd9Sstevel@tonic-gate 				i_mdi_pm_reset_client(ct);
6240*7c478bd9Sstevel@tonic-gate 			}
6241*7c478bd9Sstevel@tonic-gate 		}
6242*7c478bd9Sstevel@tonic-gate 
6243*7c478bd9Sstevel@tonic-gate 		MDI_CLIENT_UNLOCK(ct);
6244*7c478bd9Sstevel@tonic-gate 		break;
6245*7c478bd9Sstevel@tonic-gate 	default:
6246*7c478bd9Sstevel@tonic-gate 		break;
6247*7c478bd9Sstevel@tonic-gate 	}
6248*7c478bd9Sstevel@tonic-gate 
6249*7c478bd9Sstevel@tonic-gate 	return (ret);
6250*7c478bd9Sstevel@tonic-gate }
6251*7c478bd9Sstevel@tonic-gate 
6252*7c478bd9Sstevel@tonic-gate int
6253*7c478bd9Sstevel@tonic-gate mdi_component_is_vhci(dev_info_t *dip, const char **mdi_class)
6254*7c478bd9Sstevel@tonic-gate {
6255*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t *vhci;
6256*7c478bd9Sstevel@tonic-gate 
6257*7c478bd9Sstevel@tonic-gate 	if (!MDI_VHCI(dip))
6258*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
6259*7c478bd9Sstevel@tonic-gate 
6260*7c478bd9Sstevel@tonic-gate 	if (mdi_class) {
6261*7c478bd9Sstevel@tonic-gate 		vhci = DEVI(dip)->devi_mdi_xhci;
6262*7c478bd9Sstevel@tonic-gate 		ASSERT(vhci);
6263*7c478bd9Sstevel@tonic-gate 		*mdi_class = vhci->vh_class;
6264*7c478bd9Sstevel@tonic-gate 	}
6265*7c478bd9Sstevel@tonic-gate 
6266*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
6267*7c478bd9Sstevel@tonic-gate }
6268*7c478bd9Sstevel@tonic-gate 
6269*7c478bd9Sstevel@tonic-gate int
6270*7c478bd9Sstevel@tonic-gate mdi_component_is_phci(dev_info_t *dip, const char **mdi_class)
6271*7c478bd9Sstevel@tonic-gate {
6272*7c478bd9Sstevel@tonic-gate 	mdi_phci_t *phci;
6273*7c478bd9Sstevel@tonic-gate 
6274*7c478bd9Sstevel@tonic-gate 	if (!MDI_PHCI(dip))
6275*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
6276*7c478bd9Sstevel@tonic-gate 
6277*7c478bd9Sstevel@tonic-gate 	if (mdi_class) {
6278*7c478bd9Sstevel@tonic-gate 		phci = DEVI(dip)->devi_mdi_xhci;
6279*7c478bd9Sstevel@tonic-gate 		ASSERT(phci);
6280*7c478bd9Sstevel@tonic-gate 		*mdi_class = phci->ph_vhci->vh_class;
6281*7c478bd9Sstevel@tonic-gate 	}
6282*7c478bd9Sstevel@tonic-gate 
6283*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
6284*7c478bd9Sstevel@tonic-gate }
6285*7c478bd9Sstevel@tonic-gate 
6286*7c478bd9Sstevel@tonic-gate int
6287*7c478bd9Sstevel@tonic-gate mdi_component_is_client(dev_info_t *dip, const char **mdi_class)
6288*7c478bd9Sstevel@tonic-gate {
6289*7c478bd9Sstevel@tonic-gate 	mdi_client_t *client;
6290*7c478bd9Sstevel@tonic-gate 
6291*7c478bd9Sstevel@tonic-gate 	if (!MDI_CLIENT(dip))
6292*7c478bd9Sstevel@tonic-gate 		return (MDI_FAILURE);
6293*7c478bd9Sstevel@tonic-gate 
6294*7c478bd9Sstevel@tonic-gate 	if (mdi_class) {
6295*7c478bd9Sstevel@tonic-gate 		client = DEVI(dip)->devi_mdi_client;
6296*7c478bd9Sstevel@tonic-gate 		ASSERT(client);
6297*7c478bd9Sstevel@tonic-gate 		*mdi_class = client->ct_vhci->vh_class;
6298*7c478bd9Sstevel@tonic-gate 	}
6299*7c478bd9Sstevel@tonic-gate 
6300*7c478bd9Sstevel@tonic-gate 	return (MDI_SUCCESS);
6301*7c478bd9Sstevel@tonic-gate }
6302*7c478bd9Sstevel@tonic-gate 
6303*7c478bd9Sstevel@tonic-gate /*
6304*7c478bd9Sstevel@tonic-gate  * XXX This list should include all phci drivers needed during boot time
6305*7c478bd9Sstevel@tonic-gate  * though it currently contains "fp" only.
6306*7c478bd9Sstevel@tonic-gate  * Hopefully, the mechanism provided here will be replaced with a better
6307*7c478bd9Sstevel@tonic-gate  * mechanism by vhci driven enumeration project.
6308*7c478bd9Sstevel@tonic-gate  */
6309*7c478bd9Sstevel@tonic-gate static char *phci_driver_list[] = { "fp" };
6310*7c478bd9Sstevel@tonic-gate #define	N_PHCI_DRIVERS	(sizeof (phci_driver_list) / sizeof (char *))
6311*7c478bd9Sstevel@tonic-gate 
6312*7c478bd9Sstevel@tonic-gate static void
6313*7c478bd9Sstevel@tonic-gate i_mdi_attach_phci_drivers()
6314*7c478bd9Sstevel@tonic-gate {
6315*7c478bd9Sstevel@tonic-gate 	int  i;
6316*7c478bd9Sstevel@tonic-gate 	major_t m;
6317*7c478bd9Sstevel@tonic-gate 
6318*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_PHCI_DRIVERS; i++) {
6319*7c478bd9Sstevel@tonic-gate 		m = ddi_name_to_major(phci_driver_list[i]);
6320*7c478bd9Sstevel@tonic-gate 		if (m != (major_t)-1) {
6321*7c478bd9Sstevel@tonic-gate 			if (ddi_hold_installed_driver(m) != NULL)
6322*7c478bd9Sstevel@tonic-gate 				ddi_rele_driver(m);
6323*7c478bd9Sstevel@tonic-gate 		}
6324*7c478bd9Sstevel@tonic-gate 	}
6325*7c478bd9Sstevel@tonic-gate }
6326*7c478bd9Sstevel@tonic-gate 
6327*7c478bd9Sstevel@tonic-gate /* bus config the specified phci */
6328*7c478bd9Sstevel@tonic-gate static void
6329*7c478bd9Sstevel@tonic-gate i_mdi_phci_bus_config(void *arg)
6330*7c478bd9Sstevel@tonic-gate {
6331*7c478bd9Sstevel@tonic-gate 	mdi_phci_config_t *phc = (mdi_phci_config_t *)arg;
6332*7c478bd9Sstevel@tonic-gate 	mdi_vhci_config_t *vhc;
6333*7c478bd9Sstevel@tonic-gate 	dev_info_t	*ph_dip;
6334*7c478bd9Sstevel@tonic-gate 	int		rv;
6335*7c478bd9Sstevel@tonic-gate 
6336*7c478bd9Sstevel@tonic-gate 	ASSERT(phc);
6337*7c478bd9Sstevel@tonic-gate 	vhc = phc->phc_vhc;
6338*7c478bd9Sstevel@tonic-gate 	ASSERT(vhc->vhc_op == BUS_CONFIG_ALL ||
6339*7c478bd9Sstevel@tonic-gate 	    vhc->vhc_op == BUS_CONFIG_DRIVER);
6340*7c478bd9Sstevel@tonic-gate 
6341*7c478bd9Sstevel@tonic-gate 	/*
6342*7c478bd9Sstevel@tonic-gate 	 * Must have already held the phci parent in
6343*7c478bd9Sstevel@tonic-gate 	 * i_mdi_bus_config_all_phcis().
6344*7c478bd9Sstevel@tonic-gate 	 * First configure the phci itself.
6345*7c478bd9Sstevel@tonic-gate 	 */
6346*7c478bd9Sstevel@tonic-gate 	rv = ndi_devi_config_one(phc->phc_parent_dip, phc->phc_devnm + 1,
6347*7c478bd9Sstevel@tonic-gate 	    &ph_dip, vhc->vhc_flags);
6348*7c478bd9Sstevel@tonic-gate 
6349*7c478bd9Sstevel@tonic-gate 	/* release the hold that i_mdi_bus_config_all_phcis() placed */
6350*7c478bd9Sstevel@tonic-gate 	ndi_rele_devi(phc->phc_parent_dip);
6351*7c478bd9Sstevel@tonic-gate 
6352*7c478bd9Sstevel@tonic-gate 	if (rv == NDI_SUCCESS) {
6353*7c478bd9Sstevel@tonic-gate 		/* now bus config the phci */
6354*7c478bd9Sstevel@tonic-gate 		if (vhc->vhc_op == BUS_CONFIG_DRIVER) {
6355*7c478bd9Sstevel@tonic-gate 			(void) ndi_devi_config_driver(ph_dip, vhc->vhc_flags,
6356*7c478bd9Sstevel@tonic-gate 				vhc->vhc_major);
6357*7c478bd9Sstevel@tonic-gate 		} else
6358*7c478bd9Sstevel@tonic-gate 			(void) ndi_devi_config(ph_dip, vhc->vhc_flags);
6359*7c478bd9Sstevel@tonic-gate 
6360*7c478bd9Sstevel@tonic-gate 		/* release the hold that ndi_devi_config_one() placed */
6361*7c478bd9Sstevel@tonic-gate 		ndi_rele_devi(ph_dip);
6362*7c478bd9Sstevel@tonic-gate 	}
6363*7c478bd9Sstevel@tonic-gate }
6364*7c478bd9Sstevel@tonic-gate 
6365*7c478bd9Sstevel@tonic-gate /*
6366*7c478bd9Sstevel@tonic-gate  * Bus config all registered phcis associated with the vhci in parallel.
6367*7c478bd9Sstevel@tonic-gate  * This process guarantees that the child nodes are enumerated under the vhci,
6368*7c478bd9Sstevel@tonic-gate  * but not necessarily attached.
6369*7c478bd9Sstevel@tonic-gate  * op must be BUS_CONFIG_DRIVER or BUS_CONFIG_ALL.
6370*7c478bd9Sstevel@tonic-gate  */
6371*7c478bd9Sstevel@tonic-gate static int
6372*7c478bd9Sstevel@tonic-gate i_mdi_bus_config_all_phcis(dev_info_t *vdip, uint_t flags,
6373*7c478bd9Sstevel@tonic-gate     ddi_bus_config_op_t op, major_t maj, int optimize)
6374*7c478bd9Sstevel@tonic-gate {
6375*7c478bd9Sstevel@tonic-gate 	mdi_vhci_t		*vh;
6376*7c478bd9Sstevel@tonic-gate 	mdi_phci_t		*ph;
6377*7c478bd9Sstevel@tonic-gate 	mdi_phci_config_t	*phc;
6378*7c478bd9Sstevel@tonic-gate 	int64_t			req_time;
6379*7c478bd9Sstevel@tonic-gate 	int			phci_count, rv;
6380*7c478bd9Sstevel@tonic-gate 	static int		first_time = 1;
6381*7c478bd9Sstevel@tonic-gate 
6382*7c478bd9Sstevel@tonic-gate 	ASSERT(op == BUS_CONFIG_ALL || op == BUS_CONFIG_DRIVER);
6383*7c478bd9Sstevel@tonic-gate 	ASSERT(!DEVI_BUSY_OWNED(vdip));
6384*7c478bd9Sstevel@tonic-gate 
6385*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(2, (CE_NOTE, vdip,
6386*7c478bd9Sstevel@tonic-gate 	    "!MDI: %s on all phcis: major = %d, flags = 0x%x, optimize = %d\n",
6387*7c478bd9Sstevel@tonic-gate 	    (op == BUS_CONFIG_DRIVER) ? "BUS_CONFIG_DRIVER" : "BUS_CONFIG_ALL",
6388*7c478bd9Sstevel@tonic-gate 	    (int)maj, flags, optimize));
6389*7c478bd9Sstevel@tonic-gate 
6390*7c478bd9Sstevel@tonic-gate 	vh = i_devi_get_vhci(vdip);
6391*7c478bd9Sstevel@tonic-gate 	ASSERT(vh);
6392*7c478bd9Sstevel@tonic-gate 
6393*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
6394*7c478bd9Sstevel@tonic-gate 
6395*7c478bd9Sstevel@tonic-gate 	req_time = lbolt64;
6396*7c478bd9Sstevel@tonic-gate 
6397*7c478bd9Sstevel@tonic-gate 	/*
6398*7c478bd9Sstevel@tonic-gate 	 * Reduce unnecessary BUS_CONFIG_ALLs when opening stale
6399*7c478bd9Sstevel@tonic-gate 	 * /dev/[r]dsk links.
6400*7c478bd9Sstevel@tonic-gate 	 */
6401*7c478bd9Sstevel@tonic-gate 	if (optimize && (req_time < vh->vh_bus_config.vhc_cutoff_time)) {
6402*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mdi_mutex);
6403*7c478bd9Sstevel@tonic-gate 		return (MDI_SUCCESS);
6404*7c478bd9Sstevel@tonic-gate 	}
6405*7c478bd9Sstevel@tonic-gate 
6406*7c478bd9Sstevel@tonic-gate 	/*
6407*7c478bd9Sstevel@tonic-gate 	 * To initiate bus configs on all phcis in parallel, create a taskq
6408*7c478bd9Sstevel@tonic-gate 	 * with multiple threads. Since creation of a taskq is a heavy weight
6409*7c478bd9Sstevel@tonic-gate 	 * operation, taskq is created once per vhci and destroyed only when
6410*7c478bd9Sstevel@tonic-gate 	 * vhci unregisters with mdi.
6411*7c478bd9Sstevel@tonic-gate 	 *
6412*7c478bd9Sstevel@tonic-gate 	 * If multiple bus config requests arrive at a time, bus configs on
6413*7c478bd9Sstevel@tonic-gate 	 * phcis are initiated on behalf of one of the requests. Other requests
6414*7c478bd9Sstevel@tonic-gate 	 * wait until the bus configs on phcis is done.
6415*7c478bd9Sstevel@tonic-gate 	 *
6416*7c478bd9Sstevel@tonic-gate 	 * When a BUS_CONFIG_ALL on phcis completes, the following is done
6417*7c478bd9Sstevel@tonic-gate 	 * to avoid more of unnecessary bus configs.
6418*7c478bd9Sstevel@tonic-gate 	 *
6419*7c478bd9Sstevel@tonic-gate 	 *	o all BUS_CONFIG_ALL requests currently waiting with optimize
6420*7c478bd9Sstevel@tonic-gate 	 *	flag set are returned, i.e., no new BUS_CONFIG_ALL is initiated
6421*7c478bd9Sstevel@tonic-gate 	 *	on phcis on behalf of these requests.
6422*7c478bd9Sstevel@tonic-gate 	 *
6423*7c478bd9Sstevel@tonic-gate 	 *	o all BUS_CONFIG_ALL or BUS_CONFIG_DRIVER requests currently
6424*7c478bd9Sstevel@tonic-gate 	 *	waiting but have arrived prior to initiating BUS_CONFIG_ALL on
6425*7c478bd9Sstevel@tonic-gate 	 *	phcis are also returned.
6426*7c478bd9Sstevel@tonic-gate 	 *
6427*7c478bd9Sstevel@tonic-gate 	 * In other cases a new BUS_CONFIG_ALL or BUS_CONFIG_DRIVER is
6428*7c478bd9Sstevel@tonic-gate 	 * initiated on phcis on behalf of a new request.
6429*7c478bd9Sstevel@tonic-gate 	 */
6430*7c478bd9Sstevel@tonic-gate 
6431*7c478bd9Sstevel@tonic-gate 	/* check if a bus config on phcis is in progress */
6432*7c478bd9Sstevel@tonic-gate 	while (vh->vh_bus_config.vhc_start_time != 0) {
6433*7c478bd9Sstevel@tonic-gate 		ddi_bus_config_op_t current_op;
6434*7c478bd9Sstevel@tonic-gate 		int64_t start_time;
6435*7c478bd9Sstevel@tonic-gate 
6436*7c478bd9Sstevel@tonic-gate 		current_op = vh->vh_bus_config.vhc_op;
6437*7c478bd9Sstevel@tonic-gate 		start_time = vh->vh_bus_config.vhc_start_time;
6438*7c478bd9Sstevel@tonic-gate 
6439*7c478bd9Sstevel@tonic-gate 		/* wait until the current bus configs on phcis are done */
6440*7c478bd9Sstevel@tonic-gate 		while (vh->vh_bus_config.vhc_start_time == start_time)
6441*7c478bd9Sstevel@tonic-gate 			cv_wait(&vh->vh_bus_config.vhc_cv, &mdi_mutex);
6442*7c478bd9Sstevel@tonic-gate 
6443*7c478bd9Sstevel@tonic-gate 		if (current_op == BUS_CONFIG_ALL &&
6444*7c478bd9Sstevel@tonic-gate 		    vh->vh_bus_config.vhc_cutoff_time > 0 && (optimize ||
6445*7c478bd9Sstevel@tonic-gate 		    req_time < start_time)) {
6446*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mdi_mutex);
6447*7c478bd9Sstevel@tonic-gate 			return (MDI_SUCCESS);
6448*7c478bd9Sstevel@tonic-gate 		}
6449*7c478bd9Sstevel@tonic-gate 	}
6450*7c478bd9Sstevel@tonic-gate 
6451*7c478bd9Sstevel@tonic-gate 	/*
6452*7c478bd9Sstevel@tonic-gate 	 * At this point we are single threaded until vh_bus_config.start_time
6453*7c478bd9Sstevel@tonic-gate 	 * is reset to 0 at the end of this function.
6454*7c478bd9Sstevel@tonic-gate 	 */
6455*7c478bd9Sstevel@tonic-gate 
6456*7c478bd9Sstevel@tonic-gate 	vh->vh_bus_config.vhc_op = op;
6457*7c478bd9Sstevel@tonic-gate 	vh->vh_bus_config.vhc_major = maj;
6458*7c478bd9Sstevel@tonic-gate 	vh->vh_bus_config.vhc_flags = flags;
6459*7c478bd9Sstevel@tonic-gate 	vh->vh_bus_config.vhc_start_time = lbolt64;
6460*7c478bd9Sstevel@tonic-gate 
6461*7c478bd9Sstevel@tonic-gate 	if (first_time && strcmp(vh->vh_class, MDI_HCI_CLASS_SCSI) == 0) {
6462*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mdi_mutex);
6463*7c478bd9Sstevel@tonic-gate 		i_mdi_attach_phci_drivers();
6464*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mdi_mutex);
6465*7c478bd9Sstevel@tonic-gate 		first_time = 0;
6466*7c478bd9Sstevel@tonic-gate 	}
6467*7c478bd9Sstevel@tonic-gate 
6468*7c478bd9Sstevel@tonic-gate 	ASSERT(vh->vh_phci_count >= 0);
6469*7c478bd9Sstevel@tonic-gate 	if (vh->vh_phci_count == 0) {
6470*7c478bd9Sstevel@tonic-gate 		rv = MDI_SUCCESS;
6471*7c478bd9Sstevel@tonic-gate 		goto out1;
6472*7c478bd9Sstevel@tonic-gate 	}
6473*7c478bd9Sstevel@tonic-gate 
6474*7c478bd9Sstevel@tonic-gate 	/*
6475*7c478bd9Sstevel@tonic-gate 	 * Create a taskq to initiate bus configs in parallel on phcis.
6476*7c478bd9Sstevel@tonic-gate 	 * Taskq allocation can be done in mdi_vhci_register() routine
6477*7c478bd9Sstevel@tonic-gate 	 * instead of here. For most systems, doing it here on demand saves
6478*7c478bd9Sstevel@tonic-gate 	 * resources as this code path is never called most of the times.
6479*7c478bd9Sstevel@tonic-gate 	 */
6480*7c478bd9Sstevel@tonic-gate 	if (vh->vh_bus_config.vhc_taskq == NULL) {
6481*7c478bd9Sstevel@tonic-gate 		/*
6482*7c478bd9Sstevel@tonic-gate 		 * it is ok even if vh->vh_phci_count changes after we release
6483*7c478bd9Sstevel@tonic-gate 		 * the mdi_mutex as phci_count is used just as an
6484*7c478bd9Sstevel@tonic-gate 		 * advisory number to taskq_create.
6485*7c478bd9Sstevel@tonic-gate 		 */
6486*7c478bd9Sstevel@tonic-gate 		phci_count = vh->vh_phci_count;
6487*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mdi_mutex);
6488*7c478bd9Sstevel@tonic-gate 
6489*7c478bd9Sstevel@tonic-gate 		/*
6490*7c478bd9Sstevel@tonic-gate 		 * As we are single threaded, it is ok to access the
6491*7c478bd9Sstevel@tonic-gate 		 * vh_bus_config.taskq member of vh outside of mdi_mutex
6492*7c478bd9Sstevel@tonic-gate 		 */
6493*7c478bd9Sstevel@tonic-gate 		if ((vh->vh_bus_config.vhc_taskq = taskq_create(
6494*7c478bd9Sstevel@tonic-gate 		    "mdi_bus_config_taskq", mdi_max_bus_config_threads,
6495*7c478bd9Sstevel@tonic-gate 		    MDI_TASKQ_PRI, phci_count, INT_MAX,
6496*7c478bd9Sstevel@tonic-gate 		    TASKQ_PREPOPULATE | TASKQ_DYNAMIC)) == NULL) {
6497*7c478bd9Sstevel@tonic-gate 			rv = MDI_FAILURE;
6498*7c478bd9Sstevel@tonic-gate 			goto out;
6499*7c478bd9Sstevel@tonic-gate 		}
6500*7c478bd9Sstevel@tonic-gate 
6501*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mdi_mutex);
6502*7c478bd9Sstevel@tonic-gate 	}
6503*7c478bd9Sstevel@tonic-gate 
6504*7c478bd9Sstevel@tonic-gate 	/* allocate at least vh->vh_phci_count phci bus config structures */
6505*7c478bd9Sstevel@tonic-gate 	while (vh->vh_bus_config.vhc_phc_cnt < vh->vh_phci_count) {
6506*7c478bd9Sstevel@tonic-gate 		int count;
6507*7c478bd9Sstevel@tonic-gate 
6508*7c478bd9Sstevel@tonic-gate 		count = vh->vh_phci_count - vh->vh_bus_config.vhc_phc_cnt;
6509*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mdi_mutex);
6510*7c478bd9Sstevel@tonic-gate 		while (count--) {
6511*7c478bd9Sstevel@tonic-gate 			phc = kmem_alloc(sizeof (*phc), KM_SLEEP);
6512*7c478bd9Sstevel@tonic-gate 			phc->phc_vhc = &vh->vh_bus_config;
6513*7c478bd9Sstevel@tonic-gate 			/*
6514*7c478bd9Sstevel@tonic-gate 			 * there is no need to hold a lock here as we
6515*7c478bd9Sstevel@tonic-gate 			 * are single threaded and no one else manipulates
6516*7c478bd9Sstevel@tonic-gate 			 * the list while we are here.
6517*7c478bd9Sstevel@tonic-gate 			 */
6518*7c478bd9Sstevel@tonic-gate 			phc->phc_next = vh->vh_bus_config.vhc_phc;
6519*7c478bd9Sstevel@tonic-gate 			vh->vh_bus_config.vhc_phc = phc;
6520*7c478bd9Sstevel@tonic-gate 			vh->vh_bus_config.vhc_phc_cnt++;
6521*7c478bd9Sstevel@tonic-gate 		}
6522*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mdi_mutex);
6523*7c478bd9Sstevel@tonic-gate 		/*
6524*7c478bd9Sstevel@tonic-gate 		 * as new phcis could register with mdi after we dropped
6525*7c478bd9Sstevel@tonic-gate 		 * the mdi_mutex, we need to recheck the vh->vh_phci_count.
6526*7c478bd9Sstevel@tonic-gate 		 * Hence the while loop.
6527*7c478bd9Sstevel@tonic-gate 		 */
6528*7c478bd9Sstevel@tonic-gate 	}
6529*7c478bd9Sstevel@tonic-gate 
6530*7c478bd9Sstevel@tonic-gate 	for (ph = vh->vh_phci_head, phc = vh->vh_bus_config.vhc_phc;
6531*7c478bd9Sstevel@tonic-gate 	    ph != NULL; ph = ph->ph_next, phc = phc->phc_next) {
6532*7c478bd9Sstevel@tonic-gate 
6533*7c478bd9Sstevel@tonic-gate 		ASSERT(phc != NULL);
6534*7c478bd9Sstevel@tonic-gate 
6535*7c478bd9Sstevel@tonic-gate 		/* build a phci config handle to be passed to a taskq thread */
6536*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_LOCK(ph);
6537*7c478bd9Sstevel@tonic-gate 		ASSERT(ph->ph_dip);
6538*7c478bd9Sstevel@tonic-gate 
6539*7c478bd9Sstevel@tonic-gate 		/*
6540*7c478bd9Sstevel@tonic-gate 		 * We need to hold the phci dip before bus configuring the phci.
6541*7c478bd9Sstevel@tonic-gate 		 * But placing a hold on the phci dip is not safe here due to
6542*7c478bd9Sstevel@tonic-gate 		 * the race with phci detach. To get around this race,
6543*7c478bd9Sstevel@tonic-gate 		 * we place a hold on the phci dip's parent and note down
6544*7c478bd9Sstevel@tonic-gate 		 * the phci's name@addr. Later, in i_mdi_phci_bus_config(),
6545*7c478bd9Sstevel@tonic-gate 		 * we'll first configure the phci itself before bus
6546*7c478bd9Sstevel@tonic-gate 		 * configuring the phci.
6547*7c478bd9Sstevel@tonic-gate 		 */
6548*7c478bd9Sstevel@tonic-gate 		phc->phc_parent_dip = ddi_get_parent(ph->ph_dip);
6549*7c478bd9Sstevel@tonic-gate 		ndi_hold_devi(phc->phc_parent_dip);
6550*7c478bd9Sstevel@tonic-gate 		(void) ddi_deviname(ph->ph_dip, phc->phc_devnm);
6551*7c478bd9Sstevel@tonic-gate 		MDI_PHCI_UNLOCK(ph);
6552*7c478bd9Sstevel@tonic-gate 	}
6553*7c478bd9Sstevel@tonic-gate 
6554*7c478bd9Sstevel@tonic-gate 	phci_count = vh->vh_phci_count;
6555*7c478bd9Sstevel@tonic-gate 	if (vh->vh_bus_config.vhc_cutoff_time == -1)
6556*7c478bd9Sstevel@tonic-gate 		vh->vh_bus_config.vhc_cutoff_time = 0;
6557*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
6558*7c478bd9Sstevel@tonic-gate 
6559*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(2, (CE_NOTE, vdip,
6560*7c478bd9Sstevel@tonic-gate 	    "!MDI: initiating %s on all phcis, major = %d, flags = 0x%x\n",
6561*7c478bd9Sstevel@tonic-gate 	    (op == BUS_CONFIG_DRIVER) ? "BUS_CONFIG_DRIVER" : "BUS_CONFIG_ALL",
6562*7c478bd9Sstevel@tonic-gate 	    (int)maj, flags));
6563*7c478bd9Sstevel@tonic-gate 
6564*7c478bd9Sstevel@tonic-gate 	/*
6565*7c478bd9Sstevel@tonic-gate 	 * again, no need to hold a lock here as we are single threaded and
6566*7c478bd9Sstevel@tonic-gate 	 * no one else manipulates the list while we are here.
6567*7c478bd9Sstevel@tonic-gate 	 */
6568*7c478bd9Sstevel@tonic-gate 	for (phc = vh->vh_bus_config.vhc_phc; phci_count--;
6569*7c478bd9Sstevel@tonic-gate 	    phc = phc->phc_next) {
6570*7c478bd9Sstevel@tonic-gate 		(void) taskq_dispatch(vh->vh_bus_config.vhc_taskq,
6571*7c478bd9Sstevel@tonic-gate 		    i_mdi_phci_bus_config, phc, TQ_SLEEP);
6572*7c478bd9Sstevel@tonic-gate 	}
6573*7c478bd9Sstevel@tonic-gate 
6574*7c478bd9Sstevel@tonic-gate 	/* wait until all phci bus configs are done */
6575*7c478bd9Sstevel@tonic-gate 	taskq_wait(vh->vh_bus_config.vhc_taskq);
6576*7c478bd9Sstevel@tonic-gate 	rv = MDI_SUCCESS;
6577*7c478bd9Sstevel@tonic-gate 
6578*7c478bd9Sstevel@tonic-gate out:
6579*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mdi_mutex);
6580*7c478bd9Sstevel@tonic-gate out1:
6581*7c478bd9Sstevel@tonic-gate 	vh->vh_bus_config.vhc_start_time = 0;
6582*7c478bd9Sstevel@tonic-gate 	if (op == BUS_CONFIG_ALL && vh->vh_bus_config.vhc_cutoff_time != -1) {
6583*7c478bd9Sstevel@tonic-gate 		vh->vh_bus_config.vhc_cutoff_time = lbolt64 +
6584*7c478bd9Sstevel@tonic-gate 		    (int64_t)drv_usectohz(mdi_bus_config_timeout * 1000000);
6585*7c478bd9Sstevel@tonic-gate 	}
6586*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&vh->vh_bus_config.vhc_cv);
6587*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mdi_mutex);
6588*7c478bd9Sstevel@tonic-gate 
6589*7c478bd9Sstevel@tonic-gate 	MDI_DEBUG(2, (CE_NOTE, vdip, "!MDI: %s on all phcis %s\n",
6590*7c478bd9Sstevel@tonic-gate 	    (op == BUS_CONFIG_DRIVER) ? "BUS_CONFIG_DRIVER" : "BUS_CONFIG_ALL",
6591*7c478bd9Sstevel@tonic-gate 	    (rv == MDI_SUCCESS) ? "successful" : "failed"));
6592*7c478bd9Sstevel@tonic-gate 
6593*7c478bd9Sstevel@tonic-gate 	return (rv);
6594*7c478bd9Sstevel@tonic-gate }
6595*7c478bd9Sstevel@tonic-gate 
6596*7c478bd9Sstevel@tonic-gate /*
6597*7c478bd9Sstevel@tonic-gate  * A simple bus config implementation for vhcis with the assumption that all
6598*7c478bd9Sstevel@tonic-gate  * phcis are always registered with MDI.
6599*7c478bd9Sstevel@tonic-gate  *
6600*7c478bd9Sstevel@tonic-gate  * BUS_CONFIG_ALL
6601*7c478bd9Sstevel@tonic-gate  *
6602*7c478bd9Sstevel@tonic-gate  * 	Do BUS_CONFIG_ALL on all phcis associated with the vhci.
6603*7c478bd9Sstevel@tonic-gate  *
6604*7c478bd9Sstevel@tonic-gate  * BUS_CONFIG_DRIVER
6605*7c478bd9Sstevel@tonic-gate  *
6606*7c478bd9Sstevel@tonic-gate  * 	Do BUS_CONFIG_DRIVER on all phcis associated with the vhci.
6607*7c478bd9Sstevel@tonic-gate  *
6608*7c478bd9Sstevel@tonic-gate  * BUS_CONFIG_ONE
6609*7c478bd9Sstevel@tonic-gate  *
6610*7c478bd9Sstevel@tonic-gate  *	If the requested child has already been enumerated under the vhci
6611*7c478bd9Sstevel@tonic-gate  *	configure the child and return. Otherwise do BUS_CONFIG_ALL on all
6612*7c478bd9Sstevel@tonic-gate  *	phcis associated with the vhci.
6613*7c478bd9Sstevel@tonic-gate  */
6614*7c478bd9Sstevel@tonic-gate int
6615*7c478bd9Sstevel@tonic-gate mdi_vhci_bus_config(dev_info_t *vdip, uint_t flags, ddi_bus_config_op_t op,
6616*7c478bd9Sstevel@tonic-gate     void *arg, dev_info_t **child)
6617*7c478bd9Sstevel@tonic-gate {
6618*7c478bd9Sstevel@tonic-gate 	int rv = MDI_SUCCESS;
6619*7c478bd9Sstevel@tonic-gate 
6620*7c478bd9Sstevel@tonic-gate 	/*
6621*7c478bd9Sstevel@tonic-gate 	 * While bus configuring phcis, the phci driver interactions with MDI
6622*7c478bd9Sstevel@tonic-gate 	 * cause child nodes to be enumerated under the vhci node for which
6623*7c478bd9Sstevel@tonic-gate 	 * they need to ndi_devi_enter the vhci node.
6624*7c478bd9Sstevel@tonic-gate 	 *
6625*7c478bd9Sstevel@tonic-gate 	 * Unfortunately, to avoid the deadlock, we ourself can not wait for
6626*7c478bd9Sstevel@tonic-gate 	 * for the bus config operations on phcis to finish while holding the
6627*7c478bd9Sstevel@tonic-gate 	 * ndi_devi_enter lock. To avoid this deadlock, skip bus configs on
6628*7c478bd9Sstevel@tonic-gate 	 * phcis and call the default framework provided bus config function
6629*7c478bd9Sstevel@tonic-gate 	 * if we are called with ndi_devi_enter lock held.
6630*7c478bd9Sstevel@tonic-gate 	 */
6631*7c478bd9Sstevel@tonic-gate 	if (DEVI_BUSY_OWNED(vdip)) {
6632*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, vdip,
6633*7c478bd9Sstevel@tonic-gate 		    "!MDI: vhci bus config: vhci dip is busy owned\n"));
6634*7c478bd9Sstevel@tonic-gate 		goto default_bus_config;
6635*7c478bd9Sstevel@tonic-gate 	}
6636*7c478bd9Sstevel@tonic-gate 
6637*7c478bd9Sstevel@tonic-gate 	switch (op) {
6638*7c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_ONE:
6639*7c478bd9Sstevel@tonic-gate 		/*
6640*7c478bd9Sstevel@tonic-gate 		 * First try to directly configure the requested child.
6641*7c478bd9Sstevel@tonic-gate 		 * This will work only if the requested child has already
6642*7c478bd9Sstevel@tonic-gate 		 * been enumerated under vhci, which is usually the most common
6643*7c478bd9Sstevel@tonic-gate 		 * case.
6644*7c478bd9Sstevel@tonic-gate 		 */
6645*7c478bd9Sstevel@tonic-gate 		if (ndi_busop_bus_config(vdip, flags, op, arg, child, 0) ==
6646*7c478bd9Sstevel@tonic-gate 		    NDI_SUCCESS) {
6647*7c478bd9Sstevel@tonic-gate 			return (MDI_SUCCESS);
6648*7c478bd9Sstevel@tonic-gate 		}
6649*7c478bd9Sstevel@tonic-gate 
6650*7c478bd9Sstevel@tonic-gate 		MDI_DEBUG(2, (CE_NOTE, vdip, "!MDI: BUS_CONFIG_ONE on %s: "
6651*7c478bd9Sstevel@tonic-gate 		    "will do BUS_CONFIG_ALL on all phcis\n", (char *)arg));
6652*7c478bd9Sstevel@tonic-gate 
6653*7c478bd9Sstevel@tonic-gate 		/* now do BUS_CONFIG_ALL on all phcis */
6654*7c478bd9Sstevel@tonic-gate 		rv = i_mdi_bus_config_all_phcis(vdip, flags,
6655*7c478bd9Sstevel@tonic-gate 		    BUS_CONFIG_ALL, -1, 1);
6656*7c478bd9Sstevel@tonic-gate 		break;
6657*7c478bd9Sstevel@tonic-gate 
6658*7c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_DRIVER:
6659*7c478bd9Sstevel@tonic-gate 		rv = i_mdi_bus_config_all_phcis(vdip, flags, op,
6660*7c478bd9Sstevel@tonic-gate 		    (major_t)(uintptr_t)arg, 0);
6661*7c478bd9Sstevel@tonic-gate 		break;
6662*7c478bd9Sstevel@tonic-gate 
6663*7c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_ALL:
6664*7c478bd9Sstevel@tonic-gate 		rv = i_mdi_bus_config_all_phcis(vdip, flags, op, -1, 0);
6665*7c478bd9Sstevel@tonic-gate 		break;
6666*7c478bd9Sstevel@tonic-gate 
6667*7c478bd9Sstevel@tonic-gate 	default:
6668*7c478bd9Sstevel@tonic-gate 		break;
6669*7c478bd9Sstevel@tonic-gate 	}
6670*7c478bd9Sstevel@tonic-gate 
6671*7c478bd9Sstevel@tonic-gate default_bus_config:
6672*7c478bd9Sstevel@tonic-gate 	/*
6673*7c478bd9Sstevel@tonic-gate 	 * i_mdi_bus_config_all_phcis() guarantees that child nodes are
6674*7c478bd9Sstevel@tonic-gate 	 * enumerated under the vhci, but not necessarily attached.
6675*7c478bd9Sstevel@tonic-gate 	 * Now configure the appropriate child nodes.
6676*7c478bd9Sstevel@tonic-gate 	 */
6677*7c478bd9Sstevel@tonic-gate 	if (rv == MDI_SUCCESS &&
6678*7c478bd9Sstevel@tonic-gate 	    ndi_busop_bus_config(vdip, flags, op, arg, child, 0) ==
6679*7c478bd9Sstevel@tonic-gate 	    NDI_SUCCESS) {
6680*7c478bd9Sstevel@tonic-gate 		return (MDI_SUCCESS);
6681*7c478bd9Sstevel@tonic-gate 	}
6682*7c478bd9Sstevel@tonic-gate 
6683*7c478bd9Sstevel@tonic-gate 	return (MDI_FAILURE);
6684*7c478bd9Sstevel@tonic-gate }
6685*7c478bd9Sstevel@tonic-gate 
6686*7c478bd9Sstevel@tonic-gate 
6687*7c478bd9Sstevel@tonic-gate void *
6688*7c478bd9Sstevel@tonic-gate mdi_client_get_vhci_private(dev_info_t *dip)
6689*7c478bd9Sstevel@tonic-gate {
6690*7c478bd9Sstevel@tonic-gate 	ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS);
6691*7c478bd9Sstevel@tonic-gate 	if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) {
6692*7c478bd9Sstevel@tonic-gate 		mdi_client_t	*ct;
6693*7c478bd9Sstevel@tonic-gate 		ct = i_devi_get_client(dip);
6694*7c478bd9Sstevel@tonic-gate 		return (ct->ct_vprivate);
6695*7c478bd9Sstevel@tonic-gate 	}
6696*7c478bd9Sstevel@tonic-gate 	return (NULL);
6697*7c478bd9Sstevel@tonic-gate }
6698*7c478bd9Sstevel@tonic-gate 
6699*7c478bd9Sstevel@tonic-gate void
6700*7c478bd9Sstevel@tonic-gate mdi_client_set_vhci_private(dev_info_t *dip, void *data)
6701*7c478bd9Sstevel@tonic-gate {
6702*7c478bd9Sstevel@tonic-gate 	ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS);
6703*7c478bd9Sstevel@tonic-gate 	if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) {
6704*7c478bd9Sstevel@tonic-gate 		mdi_client_t	*ct;
6705*7c478bd9Sstevel@tonic-gate 		ct = i_devi_get_client(dip);
6706*7c478bd9Sstevel@tonic-gate 		ct->ct_vprivate = data;
6707*7c478bd9Sstevel@tonic-gate 	}
6708*7c478bd9Sstevel@tonic-gate }
6709*7c478bd9Sstevel@tonic-gate /*
6710*7c478bd9Sstevel@tonic-gate  * mdi_pi_get_vhci_private():
6711*7c478bd9Sstevel@tonic-gate  *		Get the vhci private information associated with the
6712*7c478bd9Sstevel@tonic-gate  *		mdi_pathinfo node
6713*7c478bd9Sstevel@tonic-gate  */
6714*7c478bd9Sstevel@tonic-gate void *
6715*7c478bd9Sstevel@tonic-gate mdi_pi_get_vhci_private(mdi_pathinfo_t *pip)
6716*7c478bd9Sstevel@tonic-gate {
6717*7c478bd9Sstevel@tonic-gate 	caddr_t	vprivate = NULL;
6718*7c478bd9Sstevel@tonic-gate 	if (pip) {
6719*7c478bd9Sstevel@tonic-gate 		vprivate = MDI_PI(pip)->pi_vprivate;
6720*7c478bd9Sstevel@tonic-gate 	}
6721*7c478bd9Sstevel@tonic-gate 	return (vprivate);
6722*7c478bd9Sstevel@tonic-gate }
6723*7c478bd9Sstevel@tonic-gate 
6724*7c478bd9Sstevel@tonic-gate /*
6725*7c478bd9Sstevel@tonic-gate  * mdi_pi_set_vhci_private():
6726*7c478bd9Sstevel@tonic-gate  *		Set the vhci private information in the mdi_pathinfo node
6727*7c478bd9Sstevel@tonic-gate  */
6728*7c478bd9Sstevel@tonic-gate void
6729*7c478bd9Sstevel@tonic-gate mdi_pi_set_vhci_private(mdi_pathinfo_t *pip, void *priv)
6730*7c478bd9Sstevel@tonic-gate {
6731*7c478bd9Sstevel@tonic-gate 	if (pip) {
6732*7c478bd9Sstevel@tonic-gate 		MDI_PI(pip)->pi_vprivate = priv;
6733*7c478bd9Sstevel@tonic-gate 	}
6734*7c478bd9Sstevel@tonic-gate }
6735*7c478bd9Sstevel@tonic-gate 
6736*7c478bd9Sstevel@tonic-gate /*
6737*7c478bd9Sstevel@tonic-gate  * mdi_phci_get_vhci_private():
6738*7c478bd9Sstevel@tonic-gate  *		Get the vhci private information associated with the
6739*7c478bd9Sstevel@tonic-gate  *		mdi_phci node
6740*7c478bd9Sstevel@tonic-gate  */
6741*7c478bd9Sstevel@tonic-gate void *
6742*7c478bd9Sstevel@tonic-gate mdi_phci_get_vhci_private(dev_info_t *dip)
6743*7c478bd9Sstevel@tonic-gate {
6744*7c478bd9Sstevel@tonic-gate 	ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS);
6745*7c478bd9Sstevel@tonic-gate 	if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) {
6746*7c478bd9Sstevel@tonic-gate 		mdi_phci_t	*ph;
6747*7c478bd9Sstevel@tonic-gate 		ph = i_devi_get_phci(dip);
6748*7c478bd9Sstevel@tonic-gate 		return (ph->ph_vprivate);
6749*7c478bd9Sstevel@tonic-gate 	}
6750*7c478bd9Sstevel@tonic-gate 	return (NULL);
6751*7c478bd9Sstevel@tonic-gate }
6752*7c478bd9Sstevel@tonic-gate 
6753*7c478bd9Sstevel@tonic-gate /*
6754*7c478bd9Sstevel@tonic-gate  * mdi_phci_set_vhci_private():
6755*7c478bd9Sstevel@tonic-gate  *		Set the vhci private information in the mdi_phci node
6756*7c478bd9Sstevel@tonic-gate  */
6757*7c478bd9Sstevel@tonic-gate void
6758*7c478bd9Sstevel@tonic-gate mdi_phci_set_vhci_private(dev_info_t *dip, void *priv)
6759*7c478bd9Sstevel@tonic-gate {
6760*7c478bd9Sstevel@tonic-gate 	ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS);
6761*7c478bd9Sstevel@tonic-gate 	if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) {
6762*7c478bd9Sstevel@tonic-gate 		mdi_phci_t	*ph;
6763*7c478bd9Sstevel@tonic-gate 		ph = i_devi_get_phci(dip);
6764*7c478bd9Sstevel@tonic-gate 		ph->ph_vprivate = priv;
6765*7c478bd9Sstevel@tonic-gate 	}
6766*7c478bd9Sstevel@tonic-gate }
6767