Print this page
9702 HBA drivers don't need the redundant devfs_clean step
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/os/sunmdi.c
+++ new/usr/src/uts/common/os/sunmdi.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 +
21 22 /*
22 23 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23 24 * Copyright (c) 2014 Nexenta Systems Inc. All rights reserved.
24 25 */
25 26
26 27 /*
27 28 * Multipath driver interface (MDI) implementation; see mdi_impldefs.h for a
28 29 * more detailed discussion of the overall mpxio architecture.
29 - *
30 - * Default locking order:
31 - *
32 - * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_phci_mutex);
33 - * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_client_mutex);
34 - * _NOTE(LOCK_ORDER(mdi_vhci:vh_phci_mutex, mdi_phci::ph_mutex);
35 - * _NOTE(LOCK_ORDER(mdi_vhci:vh_client_mutex, mdi_client::ct_mutex);
36 - * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex))
37 - * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex))
38 - * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex))
39 30 */
40 31
41 32 #include <sys/note.h>
42 33 #include <sys/types.h>
43 34 #include <sys/varargs.h>
44 35 #include <sys/param.h>
45 36 #include <sys/errno.h>
46 37 #include <sys/uio.h>
47 38 #include <sys/buf.h>
48 39 #include <sys/modctl.h>
49 40 #include <sys/open.h>
50 41 #include <sys/kmem.h>
51 42 #include <sys/poll.h>
52 43 #include <sys/conf.h>
53 44 #include <sys/bootconf.h>
54 45 #include <sys/cmn_err.h>
55 46 #include <sys/stat.h>
56 47 #include <sys/ddi.h>
57 48 #include <sys/sunddi.h>
58 49 #include <sys/ddipropdefs.h>
59 50 #include <sys/sunndi.h>
60 51 #include <sys/ndi_impldefs.h>
61 52 #include <sys/promif.h>
62 53 #include <sys/sunmdi.h>
63 54 #include <sys/mdi_impldefs.h>
64 55 #include <sys/taskq.h>
65 56 #include <sys/epm.h>
66 57 #include <sys/sunpm.h>
67 58 #include <sys/modhash.h>
68 59 #include <sys/disp.h>
69 60 #include <sys/autoconf.h>
70 61 #include <sys/sysmacros.h>
71 62
72 63 #ifdef DEBUG
73 64 #include <sys/debug.h>
74 65 int mdi_debug = 1;
75 66 int mdi_debug_logonly = 0;
76 67 #define MDI_DEBUG(dbglevel, pargs) if (mdi_debug >= (dbglevel)) i_mdi_log pargs
77 68 #define MDI_WARN CE_WARN, __func__
78 69 #define MDI_NOTE CE_NOTE, __func__
79 70 #define MDI_CONT CE_CONT, __func__
80 71 static void i_mdi_log(int, const char *, dev_info_t *, const char *, ...);
81 72 #else /* !DEBUG */
82 73 #define MDI_DEBUG(dbglevel, pargs)
83 74 #endif /* DEBUG */
84 75 int mdi_debug_consoleonly = 0;
85 76 int mdi_delay = 3;
86 77
87 78 extern pri_t minclsyspri;
88 79 extern int modrootloaded;
89 80
90 81 /*
91 82 * Global mutex:
92 83 * Protects vHCI list and structure members.
93 84 */
94 85 kmutex_t mdi_mutex;
95 86
96 87 /*
97 88 * Registered vHCI class driver lists
98 89 */
99 90 int mdi_vhci_count;
100 91 mdi_vhci_t *mdi_vhci_head;
101 92 mdi_vhci_t *mdi_vhci_tail;
102 93
103 94 /*
104 95 * Client Hash Table size
105 96 */
106 97 static int mdi_client_table_size = CLIENT_HASH_TABLE_SIZE;
107 98
108 99 /*
109 100 * taskq interface definitions
110 101 */
111 102 #define MDI_TASKQ_N_THREADS 8
112 103 #define MDI_TASKQ_PRI minclsyspri
113 104 #define MDI_TASKQ_MINALLOC (4*mdi_taskq_n_threads)
114 105 #define MDI_TASKQ_MAXALLOC (500*mdi_taskq_n_threads)
115 106
116 107 taskq_t *mdi_taskq;
117 108 static uint_t mdi_taskq_n_threads = MDI_TASKQ_N_THREADS;
118 109
119 110 #define TICKS_PER_SECOND (drv_usectohz(1000000))
120 111
121 112 /*
122 113 * The data should be "quiet" for this interval (in seconds) before the
123 114 * vhci cached data is flushed to the disk.
124 115 */
125 116 static int mdi_vhcache_flush_delay = 10;
126 117
127 118 /* number of seconds the vhcache flush daemon will sleep idle before exiting */
128 119 static int mdi_vhcache_flush_daemon_idle_time = 60;
129 120
130 121 /*
131 122 * MDI falls back to discovery of all paths when a bus_config_one fails.
132 123 * The following parameters can be used to tune this operation.
133 124 *
134 125 * mdi_path_discovery_boot
135 126 * Number of times path discovery will be attempted during early boot.
136 127 * Probably there is no reason to ever set this value to greater than one.
137 128 *
138 129 * mdi_path_discovery_postboot
139 130 * Number of times path discovery will be attempted after early boot.
140 131 * Set it to a minimum of two to allow for discovery of iscsi paths which
141 132 * may happen very late during booting.
142 133 *
143 134 * mdi_path_discovery_interval
144 135 * Minimum number of seconds MDI will wait between successive discovery
145 136 * of all paths. Set it to -1 to disable discovery of all paths.
146 137 */
147 138 static int mdi_path_discovery_boot = 1;
148 139 static int mdi_path_discovery_postboot = 2;
149 140 static int mdi_path_discovery_interval = 10;
150 141
151 142 /*
152 143 * number of seconds the asynchronous configuration thread will sleep idle
153 144 * before exiting.
154 145 */
155 146 static int mdi_async_config_idle_time = 600;
156 147
157 148 static int mdi_bus_config_cache_hash_size = 256;
158 149
159 150 /* turns off multithreaded configuration for certain operations */
160 151 static int mdi_mtc_off = 0;
161 152
162 153 /*
163 154 * The "path" to a pathinfo node is identical to the /devices path to a
164 155 * devinfo node had the device been enumerated under a pHCI instead of
165 156 * a vHCI. This pathinfo "path" is associated with a 'path_instance'.
166 157 * This association persists across create/delete of the pathinfo nodes,
167 158 * but not across reboot.
168 159 */
169 160 static uint_t mdi_pathmap_instance = 1; /* 0 -> any path */
170 161 static int mdi_pathmap_hash_size = 256;
171 162 static kmutex_t mdi_pathmap_mutex;
172 163 static mod_hash_t *mdi_pathmap_bypath; /* "path"->instance */
173 164 static mod_hash_t *mdi_pathmap_byinstance; /* instance->"path" */
174 165 static mod_hash_t *mdi_pathmap_sbyinstance; /* inst->shortpath */
175 166
176 167 /*
177 168 * MDI component property name/value string definitions
178 169 */
179 170 const char *mdi_component_prop = "mpxio-component";
180 171 const char *mdi_component_prop_vhci = "vhci";
181 172 const char *mdi_component_prop_phci = "phci";
182 173 const char *mdi_component_prop_client = "client";
183 174
184 175 /*
185 176 * MDI client global unique identifier property name
186 177 */
187 178 const char *mdi_client_guid_prop = "client-guid";
188 179
189 180 /*
190 181 * MDI client load balancing property name/value string definitions
191 182 */
192 183 const char *mdi_load_balance = "load-balance";
193 184 const char *mdi_load_balance_none = "none";
194 185 const char *mdi_load_balance_rr = "round-robin";
195 186 const char *mdi_load_balance_lba = "logical-block";
196 187
197 188 /*
198 189 * Obsolete vHCI class definition; to be removed after Leadville update
199 190 */
200 191 const char *mdi_vhci_class_scsi = MDI_HCI_CLASS_SCSI;
201 192
202 193 static char vhci_greeting[] =
203 194 "\tThere already exists one vHCI driver for class %s\n"
204 195 "\tOnly one vHCI driver for each class is allowed\n";
205 196
206 197 /*
207 198 * Static function prototypes
208 199 */
209 200 static int i_mdi_phci_offline(dev_info_t *, uint_t);
210 201 static int i_mdi_client_offline(dev_info_t *, uint_t);
211 202 static int i_mdi_phci_pre_detach(dev_info_t *, ddi_detach_cmd_t);
212 203 static void i_mdi_phci_post_detach(dev_info_t *,
213 204 ddi_detach_cmd_t, int);
214 205 static int i_mdi_client_pre_detach(dev_info_t *,
215 206 ddi_detach_cmd_t);
216 207 static void i_mdi_client_post_detach(dev_info_t *,
217 208 ddi_detach_cmd_t, int);
218 209 static void i_mdi_pm_hold_pip(mdi_pathinfo_t *);
219 210 static void i_mdi_pm_rele_pip(mdi_pathinfo_t *);
220 211 static int i_mdi_lba_lb(mdi_client_t *ct,
221 212 mdi_pathinfo_t **ret_pip, struct buf *buf);
222 213 static void i_mdi_pm_hold_client(mdi_client_t *, int);
223 214 static void i_mdi_pm_rele_client(mdi_client_t *, int);
224 215 static void i_mdi_pm_reset_client(mdi_client_t *);
225 216 static int i_mdi_power_all_phci(mdi_client_t *);
226 217 static void i_mdi_log_sysevent(dev_info_t *, char *, char *);
227 218
228 219
229 220 /*
230 221 * Internal mdi_pathinfo node functions
231 222 */
232 223 static void i_mdi_pi_kstat_destroy(mdi_pathinfo_t *);
233 224
234 225 static mdi_vhci_t *i_mdi_vhci_class2vhci(char *);
235 226 static mdi_vhci_t *i_devi_get_vhci(dev_info_t *);
236 227 static mdi_phci_t *i_devi_get_phci(dev_info_t *);
237 228 static void i_mdi_phci_lock(mdi_phci_t *, mdi_pathinfo_t *);
238 229 static void i_mdi_phci_unlock(mdi_phci_t *);
239 230 static mdi_pathinfo_t *i_mdi_pi_alloc(mdi_phci_t *, char *, mdi_client_t *);
240 231 static void i_mdi_phci_add_path(mdi_phci_t *, mdi_pathinfo_t *);
241 232 static void i_mdi_client_add_path(mdi_client_t *, mdi_pathinfo_t *);
242 233 static void i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *,
243 234 mdi_client_t *);
244 235 static void i_mdi_phci_remove_path(mdi_phci_t *, mdi_pathinfo_t *);
245 236 static void i_mdi_client_remove_path(mdi_client_t *,
246 237 mdi_pathinfo_t *);
247 238
248 239 static int i_mdi_pi_state_change(mdi_pathinfo_t *,
249 240 mdi_pathinfo_state_t, int);
250 241 static int i_mdi_pi_offline(mdi_pathinfo_t *, int);
251 242 static dev_info_t *i_mdi_devinfo_create(mdi_vhci_t *, char *, char *,
252 243 char **, int);
253 244 static dev_info_t *i_mdi_devinfo_find(mdi_vhci_t *, char *, char *);
254 245 static int i_mdi_devinfo_remove(dev_info_t *, dev_info_t *, int);
255 246 static int i_mdi_is_child_present(dev_info_t *, dev_info_t *);
256 247 static mdi_client_t *i_mdi_client_alloc(mdi_vhci_t *, char *, char *);
257 248 static void i_mdi_client_enlist_table(mdi_vhci_t *, mdi_client_t *);
258 249 static void i_mdi_client_delist_table(mdi_vhci_t *, mdi_client_t *);
259 250 static mdi_client_t *i_mdi_client_find(mdi_vhci_t *, char *, char *);
260 251 static void i_mdi_client_update_state(mdi_client_t *);
261 252 static int i_mdi_client_compute_state(mdi_client_t *,
262 253 mdi_phci_t *);
263 254 static void i_mdi_client_lock(mdi_client_t *, mdi_pathinfo_t *);
264 255 static void i_mdi_client_unlock(mdi_client_t *);
265 256 static int i_mdi_client_free(mdi_vhci_t *, mdi_client_t *);
266 257 static mdi_client_t *i_devi_get_client(dev_info_t *);
267 258 /*
268 259 * NOTE: this will be removed once the NWS files are changed to use the new
269 260 * mdi_{enable,disable}_path interfaces
270 261 */
271 262 static int i_mdi_pi_enable_disable(dev_info_t *, dev_info_t *,
272 263 int, int);
273 264 static mdi_pathinfo_t *i_mdi_enable_disable_path(mdi_pathinfo_t *pip,
274 265 mdi_vhci_t *vh, int flags, int op);
275 266 /*
276 267 * Failover related function prototypes
277 268 */
278 269 static int i_mdi_failover(void *);
279 270
280 271 /*
281 272 * misc internal functions
282 273 */
283 274 static int i_mdi_get_hash_key(char *);
284 275 static int i_map_nvlist_error_to_mdi(int);
285 276 static void i_mdi_report_path_state(mdi_client_t *,
286 277 mdi_pathinfo_t *);
287 278
288 279 static void setup_vhci_cache(mdi_vhci_t *);
289 280 static int destroy_vhci_cache(mdi_vhci_t *);
290 281 static int stop_vhcache_async_threads(mdi_vhci_config_t *);
291 282 static boolean_t stop_vhcache_flush_thread(void *, int);
292 283 static void free_string_array(char **, int);
293 284 static void free_vhcache_phci(mdi_vhcache_phci_t *);
294 285 static void free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *);
295 286 static void free_vhcache_client(mdi_vhcache_client_t *);
296 287 static int mainnvl_to_vhcache(mdi_vhci_cache_t *, nvlist_t *);
297 288 static nvlist_t *vhcache_to_mainnvl(mdi_vhci_cache_t *);
298 289 static void vhcache_phci_add(mdi_vhci_config_t *, mdi_phci_t *);
299 290 static void vhcache_phci_remove(mdi_vhci_config_t *, mdi_phci_t *);
300 291 static void vhcache_pi_add(mdi_vhci_config_t *,
301 292 struct mdi_pathinfo *);
302 293 static void vhcache_pi_remove(mdi_vhci_config_t *,
303 294 struct mdi_pathinfo *);
304 295 static void free_phclient_path_list(mdi_phys_path_t *);
305 296 static void sort_vhcache_paths(mdi_vhcache_client_t *);
306 297 static int flush_vhcache(mdi_vhci_config_t *, int);
307 298 static void vhcache_dirty(mdi_vhci_config_t *);
308 299 static void free_async_client_config(mdi_async_client_config_t *);
309 300 static void single_threaded_vhconfig_enter(mdi_vhci_config_t *);
310 301 static void single_threaded_vhconfig_exit(mdi_vhci_config_t *);
311 302 static nvlist_t *read_on_disk_vhci_cache(char *);
312 303 extern int fread_nvlist(char *, nvlist_t **);
313 304 extern int fwrite_nvlist(char *, nvlist_t *);
314 305
315 306 /* called once when first vhci registers with mdi */
316 307 static void
317 308 i_mdi_init()
318 309 {
319 310 static int initialized = 0;
320 311
321 312 if (initialized)
322 313 return;
323 314 initialized = 1;
324 315
325 316 mutex_init(&mdi_mutex, NULL, MUTEX_DEFAULT, NULL);
326 317
327 318 /* Create our taskq resources */
328 319 mdi_taskq = taskq_create("mdi_taskq", mdi_taskq_n_threads,
329 320 MDI_TASKQ_PRI, MDI_TASKQ_MINALLOC, MDI_TASKQ_MAXALLOC,
330 321 TASKQ_PREPOPULATE | TASKQ_CPR_SAFE);
331 322 ASSERT(mdi_taskq != NULL); /* taskq_create never fails */
332 323
333 324 /* Allocate ['path_instance' <-> "path"] maps */
334 325 mutex_init(&mdi_pathmap_mutex, NULL, MUTEX_DRIVER, NULL);
335 326 mdi_pathmap_bypath = mod_hash_create_strhash(
336 327 "mdi_pathmap_bypath", mdi_pathmap_hash_size,
337 328 mod_hash_null_valdtor);
338 329 mdi_pathmap_byinstance = mod_hash_create_idhash(
339 330 "mdi_pathmap_byinstance", mdi_pathmap_hash_size,
340 331 mod_hash_null_valdtor);
341 332 mdi_pathmap_sbyinstance = mod_hash_create_idhash(
342 333 "mdi_pathmap_sbyinstance", mdi_pathmap_hash_size,
343 334 mod_hash_null_valdtor);
344 335 }
345 336
346 337 /*
347 338 * mdi_get_component_type():
348 339 * Return mpxio component type
349 340 * Return Values:
350 341 * MDI_COMPONENT_NONE
351 342 * MDI_COMPONENT_VHCI
352 343 * MDI_COMPONENT_PHCI
353 344 * MDI_COMPONENT_CLIENT
354 345 * XXX This doesn't work under multi-level MPxIO and should be
355 346 * removed when clients migrate mdi_component_is_*() interfaces.
356 347 */
357 348 int
358 349 mdi_get_component_type(dev_info_t *dip)
359 350 {
360 351 return (DEVI(dip)->devi_mdi_component);
361 352 }
362 353
363 354 /*
364 355 * mdi_vhci_register():
365 356 * Register a vHCI module with the mpxio framework
366 357 * mdi_vhci_register() is called by vHCI drivers to register the
367 358 * 'class_driver' vHCI driver and its MDI entrypoints with the
368 359 * mpxio framework. The vHCI driver must call this interface as
369 360 * part of its attach(9e) handler.
370 361 * Competing threads may try to attach mdi_vhci_register() as
371 362 * the vHCI drivers are loaded and attached as a result of pHCI
372 363 * driver instance registration (mdi_phci_register()) with the
373 364 * framework.
374 365 * Return Values:
375 366 * MDI_SUCCESS
376 367 * MDI_FAILURE
377 368 */
378 369 /*ARGSUSED*/
379 370 int
380 371 mdi_vhci_register(char *class, dev_info_t *vdip, mdi_vhci_ops_t *vops,
381 372 int flags)
382 373 {
383 374 mdi_vhci_t *vh = NULL;
384 375
385 376 /* Registrant can't be older */
386 377 ASSERT(vops->vo_revision <= MDI_VHCI_OPS_REV);
387 378
388 379 #ifdef DEBUG
389 380 /*
390 381 * IB nexus driver is loaded only when IB hardware is present.
391 382 * In order to be able to do this there is a need to drive the loading
392 383 * and attaching of the IB nexus driver (especially when an IB hardware
393 384 * is dynamically plugged in) when an IB HCA driver (PHCI)
394 385 * is being attached. Unfortunately this gets into the limitations
395 386 * of devfs as there seems to be no clean way to drive configuration
396 387 * of a subtree from another subtree of a devfs. Hence, do not ASSERT
397 388 * for IB.
398 389 */
399 390 if (strcmp(class, MDI_HCI_CLASS_IB) != 0)
400 391 ASSERT(DEVI_BUSY_OWNED(ddi_get_parent(vdip)));
401 392 #endif
402 393
403 394 i_mdi_init();
404 395
405 396 mutex_enter(&mdi_mutex);
406 397 /*
407 398 * Scan for already registered vhci
408 399 */
409 400 for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) {
410 401 if (strcmp(vh->vh_class, class) == 0) {
411 402 /*
412 403 * vHCI has already been created. Check for valid
413 404 * vHCI ops registration. We only support one vHCI
414 405 * module per class
415 406 */
416 407 if (vh->vh_ops != NULL) {
417 408 mutex_exit(&mdi_mutex);
418 409 cmn_err(CE_NOTE, vhci_greeting, class);
419 410 return (MDI_FAILURE);
420 411 }
421 412 break;
422 413 }
423 414 }
424 415
425 416 /*
426 417 * if not yet created, create the vHCI component
427 418 */
428 419 if (vh == NULL) {
429 420 struct client_hash *hash = NULL;
430 421 char *load_balance;
431 422
432 423 /*
433 424 * Allocate and initialize the mdi extensions
434 425 */
435 426 vh = kmem_zalloc(sizeof (mdi_vhci_t), KM_SLEEP);
436 427 hash = kmem_zalloc(mdi_client_table_size * sizeof (*hash),
437 428 KM_SLEEP);
438 429 vh->vh_client_table = hash;
439 430 vh->vh_class = kmem_zalloc(strlen(class) + 1, KM_SLEEP);
440 431 (void) strcpy(vh->vh_class, class);
441 432 vh->vh_lb = LOAD_BALANCE_RR;
442 433 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vdip,
443 434 0, LOAD_BALANCE_PROP, &load_balance) == DDI_SUCCESS) {
444 435 if (strcmp(load_balance, LOAD_BALANCE_PROP_NONE) == 0) {
445 436 vh->vh_lb = LOAD_BALANCE_NONE;
446 437 } else if (strcmp(load_balance, LOAD_BALANCE_PROP_LBA)
447 438 == 0) {
448 439 vh->vh_lb = LOAD_BALANCE_LBA;
449 440 }
450 441 ddi_prop_free(load_balance);
451 442 }
452 443
453 444 mutex_init(&vh->vh_phci_mutex, NULL, MUTEX_DEFAULT, NULL);
454 445 mutex_init(&vh->vh_client_mutex, NULL, MUTEX_DEFAULT, NULL);
455 446
456 447 /*
457 448 * Store the vHCI ops vectors
458 449 */
459 450 vh->vh_dip = vdip;
460 451 vh->vh_ops = vops;
461 452
462 453 setup_vhci_cache(vh);
463 454
464 455 if (mdi_vhci_head == NULL) {
465 456 mdi_vhci_head = vh;
466 457 }
467 458 if (mdi_vhci_tail) {
468 459 mdi_vhci_tail->vh_next = vh;
469 460 }
470 461 mdi_vhci_tail = vh;
471 462 mdi_vhci_count++;
472 463 }
473 464
474 465 /*
475 466 * Claim the devfs node as a vhci component
476 467 */
477 468 DEVI(vdip)->devi_mdi_component |= MDI_COMPONENT_VHCI;
478 469
479 470 /*
480 471 * Initialize our back reference from dev_info node
481 472 */
482 473 DEVI(vdip)->devi_mdi_xhci = (caddr_t)vh;
483 474 mutex_exit(&mdi_mutex);
484 475 return (MDI_SUCCESS);
485 476 }
486 477
487 478 /*
488 479 * mdi_vhci_unregister():
489 480 * Unregister a vHCI module from mpxio framework
490 481 * mdi_vhci_unregister() is called from the detach(9E) entrypoint
491 482 * of a vhci to unregister it from the framework.
492 483 * Return Values:
493 484 * MDI_SUCCESS
494 485 * MDI_FAILURE
495 486 */
496 487 /*ARGSUSED*/
497 488 int
498 489 mdi_vhci_unregister(dev_info_t *vdip, int flags)
499 490 {
500 491 mdi_vhci_t *found, *vh, *prev = NULL;
501 492
502 493 ASSERT(DEVI_BUSY_OWNED(ddi_get_parent(vdip)));
503 494
504 495 /*
505 496 * Check for invalid VHCI
506 497 */
507 498 if ((vh = i_devi_get_vhci(vdip)) == NULL)
508 499 return (MDI_FAILURE);
509 500
510 501 /*
511 502 * Scan the list of registered vHCIs for a match
512 503 */
513 504 mutex_enter(&mdi_mutex);
514 505 for (found = mdi_vhci_head; found != NULL; found = found->vh_next) {
515 506 if (found == vh)
516 507 break;
517 508 prev = found;
518 509 }
519 510
520 511 if (found == NULL) {
521 512 mutex_exit(&mdi_mutex);
522 513 return (MDI_FAILURE);
523 514 }
524 515
525 516 /*
526 517 * Check the vHCI, pHCI and client count. All the pHCIs and clients
527 518 * should have been unregistered, before a vHCI can be
528 519 * unregistered.
529 520 */
530 521 MDI_VHCI_PHCI_LOCK(vh);
531 522 if (vh->vh_refcnt || vh->vh_phci_count || vh->vh_client_count) {
532 523 MDI_VHCI_PHCI_UNLOCK(vh);
533 524 mutex_exit(&mdi_mutex);
534 525 return (MDI_FAILURE);
535 526 }
536 527 MDI_VHCI_PHCI_UNLOCK(vh);
537 528
538 529 if (destroy_vhci_cache(vh) != MDI_SUCCESS) {
539 530 mutex_exit(&mdi_mutex);
540 531 return (MDI_FAILURE);
541 532 }
542 533
543 534 /*
544 535 * Remove the vHCI from the global list
545 536 */
546 537 if (vh == mdi_vhci_head) {
547 538 mdi_vhci_head = vh->vh_next;
548 539 } else {
549 540 prev->vh_next = vh->vh_next;
550 541 }
551 542 if (vh == mdi_vhci_tail) {
552 543 mdi_vhci_tail = prev;
553 544 }
554 545 mdi_vhci_count--;
555 546 mutex_exit(&mdi_mutex);
556 547
557 548 vh->vh_ops = NULL;
558 549 DEVI(vdip)->devi_mdi_component &= ~MDI_COMPONENT_VHCI;
559 550 DEVI(vdip)->devi_mdi_xhci = NULL;
560 551 kmem_free(vh->vh_class, strlen(vh->vh_class)+1);
561 552 kmem_free(vh->vh_client_table,
562 553 mdi_client_table_size * sizeof (struct client_hash));
563 554 mutex_destroy(&vh->vh_phci_mutex);
564 555 mutex_destroy(&vh->vh_client_mutex);
565 556
566 557 kmem_free(vh, sizeof (mdi_vhci_t));
567 558 return (MDI_SUCCESS);
568 559 }
569 560
570 561 /*
571 562 * i_mdi_vhci_class2vhci():
572 563 * Look for a matching vHCI module given a vHCI class name
573 564 * Return Values:
574 565 * Handle to a vHCI component
575 566 * NULL
576 567 */
577 568 static mdi_vhci_t *
578 569 i_mdi_vhci_class2vhci(char *class)
579 570 {
580 571 mdi_vhci_t *vh = NULL;
581 572
582 573 ASSERT(!MUTEX_HELD(&mdi_mutex));
583 574
584 575 mutex_enter(&mdi_mutex);
585 576 for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) {
586 577 if (strcmp(vh->vh_class, class) == 0) {
587 578 break;
588 579 }
589 580 }
590 581 mutex_exit(&mdi_mutex);
591 582 return (vh);
592 583 }
593 584
594 585 /*
595 586 * i_devi_get_vhci():
596 587 * Utility function to get the handle to a vHCI component
597 588 * Return Values:
598 589 * Handle to a vHCI component
599 590 * NULL
600 591 */
601 592 mdi_vhci_t *
602 593 i_devi_get_vhci(dev_info_t *vdip)
603 594 {
604 595 mdi_vhci_t *vh = NULL;
605 596 if (MDI_VHCI(vdip)) {
606 597 vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci;
607 598 }
608 599 return (vh);
609 600 }
610 601
611 602 /*
612 603 * mdi_phci_register():
613 604 * Register a pHCI module with mpxio framework
614 605 * mdi_phci_register() is called by pHCI drivers to register with
615 606 * the mpxio framework and a specific 'class_driver' vHCI. The
616 607 * pHCI driver must call this interface as part of its attach(9e)
617 608 * handler.
618 609 * Return Values:
619 610 * MDI_SUCCESS
620 611 * MDI_FAILURE
621 612 */
622 613 /*ARGSUSED*/
623 614 int
624 615 mdi_phci_register(char *class, dev_info_t *pdip, int flags)
625 616 {
626 617 mdi_phci_t *ph;
627 618 mdi_vhci_t *vh;
628 619 char *data;
629 620
630 621 /*
631 622 * Some subsystems, like fcp, perform pHCI registration from a
632 623 * different thread than the one doing the pHCI attach(9E) - the
633 624 * driver attach code is waiting for this other thread to complete.
634 625 * This means we can only ASSERT DEVI_BUSY_CHANGING of parent
635 626 * (indicating that some thread has done an ndi_devi_enter of parent)
636 627 * not DEVI_BUSY_OWNED (which would indicate that we did the enter).
637 628 */
638 629 ASSERT(DEVI_BUSY_CHANGING(ddi_get_parent(pdip)));
639 630
640 631 /*
641 632 * Check for mpxio-disable property. Enable mpxio if the property is
642 633 * missing or not set to "yes".
643 634 * If the property is set to "yes" then emit a brief message.
644 635 */
645 636 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0, "mpxio-disable",
646 637 &data) == DDI_SUCCESS)) {
647 638 if (strcmp(data, "yes") == 0) {
648 639 MDI_DEBUG(1, (MDI_CONT, pdip,
649 640 "?multipath capabilities disabled via %s.conf.",
650 641 ddi_driver_name(pdip)));
651 642 ddi_prop_free(data);
652 643 return (MDI_FAILURE);
653 644 }
654 645 ddi_prop_free(data);
655 646 }
656 647
657 648 /*
658 649 * Search for a matching vHCI
659 650 */
660 651 vh = (mdi_vhci_t *)i_mdi_vhci_class2vhci(class);
661 652 if (vh == NULL) {
662 653 return (MDI_FAILURE);
663 654 }
664 655
665 656 ph = kmem_zalloc(sizeof (mdi_phci_t), KM_SLEEP);
666 657 mutex_init(&ph->ph_mutex, NULL, MUTEX_DEFAULT, NULL);
667 658 ph->ph_dip = pdip;
668 659 ph->ph_vhci = vh;
669 660 ph->ph_next = NULL;
670 661 ph->ph_unstable = 0;
671 662 ph->ph_vprivate = 0;
672 663 cv_init(&ph->ph_unstable_cv, NULL, CV_DRIVER, NULL);
673 664
674 665 MDI_PHCI_LOCK(ph);
675 666 MDI_PHCI_SET_POWER_UP(ph);
676 667 MDI_PHCI_UNLOCK(ph);
677 668 DEVI(pdip)->devi_mdi_component |= MDI_COMPONENT_PHCI;
678 669 DEVI(pdip)->devi_mdi_xhci = (caddr_t)ph;
679 670
680 671 vhcache_phci_add(vh->vh_config, ph);
681 672
682 673 MDI_VHCI_PHCI_LOCK(vh);
683 674 if (vh->vh_phci_head == NULL) {
684 675 vh->vh_phci_head = ph;
685 676 }
686 677 if (vh->vh_phci_tail) {
687 678 vh->vh_phci_tail->ph_next = ph;
688 679 }
689 680 vh->vh_phci_tail = ph;
690 681 vh->vh_phci_count++;
691 682 MDI_VHCI_PHCI_UNLOCK(vh);
692 683
693 684 i_mdi_log_sysevent(pdip, class, ESC_DDI_INITIATOR_REGISTER);
694 685 return (MDI_SUCCESS);
695 686 }
696 687
697 688 /*
698 689 * mdi_phci_unregister():
699 690 * Unregister a pHCI module from mpxio framework
700 691 * mdi_phci_unregister() is called by the pHCI drivers from their
701 692 * detach(9E) handler to unregister their instances from the
702 693 * framework.
703 694 * Return Values:
704 695 * MDI_SUCCESS
705 696 * MDI_FAILURE
706 697 */
707 698 /*ARGSUSED*/
708 699 int
709 700 mdi_phci_unregister(dev_info_t *pdip, int flags)
710 701 {
711 702 mdi_vhci_t *vh;
712 703 mdi_phci_t *ph;
713 704 mdi_phci_t *tmp;
714 705 mdi_phci_t *prev = NULL;
715 706 mdi_pathinfo_t *pip;
716 707
717 708 ASSERT(DEVI_BUSY_CHANGING(ddi_get_parent(pdip)));
718 709
719 710 ph = i_devi_get_phci(pdip);
720 711 if (ph == NULL) {
721 712 MDI_DEBUG(1, (MDI_WARN, pdip, "!not a valid pHCI"));
722 713 return (MDI_FAILURE);
723 714 }
724 715
725 716 vh = ph->ph_vhci;
726 717 ASSERT(vh != NULL);
727 718 if (vh == NULL) {
728 719 MDI_DEBUG(1, (MDI_WARN, pdip, "!not a valid vHCI"));
729 720 return (MDI_FAILURE);
730 721 }
731 722
732 723 MDI_VHCI_PHCI_LOCK(vh);
733 724 tmp = vh->vh_phci_head;
734 725 while (tmp) {
735 726 if (tmp == ph) {
736 727 break;
737 728 }
738 729 prev = tmp;
739 730 tmp = tmp->ph_next;
740 731 }
741 732
742 733 if (ph == vh->vh_phci_head) {
743 734 vh->vh_phci_head = ph->ph_next;
744 735 } else {
745 736 prev->ph_next = ph->ph_next;
746 737 }
747 738
748 739 if (ph == vh->vh_phci_tail) {
749 740 vh->vh_phci_tail = prev;
750 741 }
751 742
752 743 vh->vh_phci_count--;
753 744 MDI_VHCI_PHCI_UNLOCK(vh);
754 745
755 746 /* Walk remaining pathinfo nodes and disassociate them from pHCI */
756 747 MDI_PHCI_LOCK(ph);
757 748 for (pip = (mdi_pathinfo_t *)ph->ph_path_head; pip;
758 749 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link)
759 750 MDI_PI(pip)->pi_phci = NULL;
760 751 MDI_PHCI_UNLOCK(ph);
761 752
762 753 i_mdi_log_sysevent(pdip, ph->ph_vhci->vh_class,
763 754 ESC_DDI_INITIATOR_UNREGISTER);
764 755 vhcache_phci_remove(vh->vh_config, ph);
765 756 cv_destroy(&ph->ph_unstable_cv);
766 757 mutex_destroy(&ph->ph_mutex);
767 758 kmem_free(ph, sizeof (mdi_phci_t));
768 759 DEVI(pdip)->devi_mdi_component &= ~MDI_COMPONENT_PHCI;
769 760 DEVI(pdip)->devi_mdi_xhci = NULL;
770 761 return (MDI_SUCCESS);
771 762 }
772 763
773 764 /*
774 765 * i_devi_get_phci():
775 766 * Utility function to return the phci extensions.
776 767 */
777 768 static mdi_phci_t *
778 769 i_devi_get_phci(dev_info_t *pdip)
779 770 {
780 771 mdi_phci_t *ph = NULL;
781 772
782 773 if (MDI_PHCI(pdip)) {
783 774 ph = (mdi_phci_t *)DEVI(pdip)->devi_mdi_xhci;
784 775 }
785 776 return (ph);
786 777 }
787 778
788 779 /*
789 780 * Single thread mdi entry into devinfo node for modifying its children.
790 781 * If necessary we perform an ndi_devi_enter of the vHCI before doing
791 782 * an ndi_devi_enter of 'dip'. We maintain circular in two parts: one
792 783 * for the vHCI and one for the pHCI.
793 784 */
794 785 void
795 786 mdi_devi_enter(dev_info_t *phci_dip, int *circular)
796 787 {
797 788 dev_info_t *vdip;
798 789 int vcircular, pcircular;
799 790
800 791 /* Verify calling context */
801 792 ASSERT(MDI_PHCI(phci_dip));
802 793 vdip = mdi_devi_get_vdip(phci_dip);
803 794 ASSERT(vdip); /* A pHCI always has a vHCI */
804 795
805 796 /*
806 797 * If pHCI is detaching then the framework has already entered the
807 798 * vHCI on a threads that went down the code path leading to
808 799 * detach_node(). This framework enter of the vHCI during pHCI
809 800 * detach is done to avoid deadlock with vHCI power management
810 801 * operations which enter the vHCI and the enter down the path
811 802 * to the pHCI. If pHCI is detaching then we piggyback this calls
812 803 * enter of the vHCI on frameworks vHCI enter that has already
813 804 * occurred - this is OK because we know that the framework thread
814 805 * doing detach is waiting for our completion.
815 806 *
816 807 * We should DEVI_IS_DETACHING under an enter of the parent to avoid
817 808 * race with detach - but we can't do that because the framework has
818 809 * already entered the parent, so we have some complexity instead.
819 810 */
820 811 for (;;) {
821 812 if (ndi_devi_tryenter(vdip, &vcircular)) {
822 813 ASSERT(vcircular != -1);
823 814 if (DEVI_IS_DETACHING(phci_dip)) {
824 815 ndi_devi_exit(vdip, vcircular);
825 816 vcircular = -1;
826 817 }
827 818 break;
828 819 } else if (DEVI_IS_DETACHING(phci_dip)) {
829 820 vcircular = -1;
830 821 break;
831 822 } else if (servicing_interrupt()) {
832 823 /*
833 824 * Don't delay an interrupt (and ensure adaptive
834 825 * mutex inversion support).
835 826 */
836 827 ndi_devi_enter(vdip, &vcircular);
837 828 break;
838 829 } else {
839 830 delay_random(mdi_delay);
840 831 }
841 832 }
842 833
843 834 ndi_devi_enter(phci_dip, &pcircular);
844 835 *circular = (vcircular << 16) | (pcircular & 0xFFFF);
845 836 }
846 837
847 838 /*
848 839 * Attempt to mdi_devi_enter.
849 840 */
850 841 int
851 842 mdi_devi_tryenter(dev_info_t *phci_dip, int *circular)
852 843 {
853 844 dev_info_t *vdip;
854 845 int vcircular, pcircular;
855 846
856 847 /* Verify calling context */
857 848 ASSERT(MDI_PHCI(phci_dip));
858 849 vdip = mdi_devi_get_vdip(phci_dip);
859 850 ASSERT(vdip); /* A pHCI always has a vHCI */
860 851
861 852 if (ndi_devi_tryenter(vdip, &vcircular)) {
862 853 if (ndi_devi_tryenter(phci_dip, &pcircular)) {
863 854 *circular = (vcircular << 16) | (pcircular & 0xFFFF);
864 855 return (1); /* locked */
865 856 }
866 857 ndi_devi_exit(vdip, vcircular);
867 858 }
868 859 return (0); /* busy */
869 860 }
870 861
871 862 /*
872 863 * Release mdi_devi_enter or successful mdi_devi_tryenter.
873 864 */
874 865 void
875 866 mdi_devi_exit(dev_info_t *phci_dip, int circular)
876 867 {
877 868 dev_info_t *vdip;
878 869 int vcircular, pcircular;
879 870
880 871 /* Verify calling context */
881 872 ASSERT(MDI_PHCI(phci_dip));
882 873 vdip = mdi_devi_get_vdip(phci_dip);
883 874 ASSERT(vdip); /* A pHCI always has a vHCI */
884 875
885 876 /* extract two circular recursion values from single int */
886 877 pcircular = (short)(circular & 0xFFFF);
887 878 vcircular = (short)((circular >> 16) & 0xFFFF);
888 879
889 880 ndi_devi_exit(phci_dip, pcircular);
890 881 if (vcircular != -1)
891 882 ndi_devi_exit(vdip, vcircular);
892 883 }
893 884
894 885 /*
895 886 * The functions mdi_devi_exit_phci() and mdi_devi_enter_phci() are used
896 887 * around a pHCI drivers calls to mdi_pi_online/offline, after holding
897 888 * the pathinfo node via mdi_hold_path/mdi_rele_path, to avoid deadlock
898 889 * with vHCI power management code during path online/offline. Each
899 890 * mdi_devi_exit_phci must have a matching mdi_devi_enter_phci, and both must
900 891 * occur within the scope of an active mdi_devi_enter that establishes the
901 892 * circular value.
902 893 */
903 894 void
904 895 mdi_devi_exit_phci(dev_info_t *phci_dip, int circular)
905 896 {
906 897 int pcircular;
907 898
908 899 /* Verify calling context */
909 900 ASSERT(MDI_PHCI(phci_dip));
910 901
911 902 /* Keep hold on pHCI until we reenter in mdi_devi_enter_phci */
912 903 ndi_hold_devi(phci_dip);
913 904
914 905 pcircular = (short)(circular & 0xFFFF);
915 906 ndi_devi_exit(phci_dip, pcircular);
916 907 }
917 908
918 909 void
919 910 mdi_devi_enter_phci(dev_info_t *phci_dip, int *circular)
920 911 {
921 912 int pcircular;
922 913
923 914 /* Verify calling context */
924 915 ASSERT(MDI_PHCI(phci_dip));
925 916
926 917 ndi_devi_enter(phci_dip, &pcircular);
927 918
928 919 /* Drop hold from mdi_devi_exit_phci. */
929 920 ndi_rele_devi(phci_dip);
930 921
931 922 /* verify matching mdi_devi_exit_phci/mdi_devi_enter_phci use */
932 923 ASSERT(pcircular == ((short)(*circular & 0xFFFF)));
933 924 }
934 925
935 926 /*
936 927 * mdi_devi_get_vdip():
937 928 * given a pHCI dip return vHCI dip
938 929 */
939 930 dev_info_t *
940 931 mdi_devi_get_vdip(dev_info_t *pdip)
941 932 {
942 933 mdi_phci_t *ph;
943 934
944 935 ph = i_devi_get_phci(pdip);
945 936 if (ph && ph->ph_vhci)
946 937 return (ph->ph_vhci->vh_dip);
947 938 return (NULL);
948 939 }
949 940
950 941 /*
951 942 * mdi_devi_pdip_entered():
952 943 * Return 1 if we are vHCI and have done an ndi_devi_enter
953 944 * of a pHCI
954 945 */
955 946 int
956 947 mdi_devi_pdip_entered(dev_info_t *vdip)
957 948 {
958 949 mdi_vhci_t *vh;
959 950 mdi_phci_t *ph;
960 951
961 952 vh = i_devi_get_vhci(vdip);
962 953 if (vh == NULL)
963 954 return (0);
964 955
965 956 MDI_VHCI_PHCI_LOCK(vh);
966 957 ph = vh->vh_phci_head;
967 958 while (ph) {
968 959 if (ph->ph_dip && DEVI_BUSY_OWNED(ph->ph_dip)) {
969 960 MDI_VHCI_PHCI_UNLOCK(vh);
970 961 return (1);
971 962 }
972 963 ph = ph->ph_next;
973 964 }
974 965 MDI_VHCI_PHCI_UNLOCK(vh);
975 966 return (0);
976 967 }
977 968
978 969 /*
979 970 * mdi_phci_path2devinfo():
980 971 * Utility function to search for a valid phci device given
981 972 * the devfs pathname.
982 973 */
983 974 dev_info_t *
984 975 mdi_phci_path2devinfo(dev_info_t *vdip, caddr_t pathname)
985 976 {
986 977 char *temp_pathname;
987 978 mdi_vhci_t *vh;
988 979 mdi_phci_t *ph;
989 980 dev_info_t *pdip = NULL;
990 981
991 982 vh = i_devi_get_vhci(vdip);
992 983 ASSERT(vh != NULL);
993 984
994 985 if (vh == NULL) {
995 986 /*
996 987 * Invalid vHCI component, return failure
997 988 */
998 989 return (NULL);
999 990 }
1000 991
1001 992 temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1002 993 MDI_VHCI_PHCI_LOCK(vh);
1003 994 ph = vh->vh_phci_head;
1004 995 while (ph != NULL) {
1005 996 pdip = ph->ph_dip;
1006 997 ASSERT(pdip != NULL);
1007 998 *temp_pathname = '\0';
1008 999 (void) ddi_pathname(pdip, temp_pathname);
1009 1000 if (strcmp(temp_pathname, pathname) == 0) {
1010 1001 break;
1011 1002 }
1012 1003 ph = ph->ph_next;
1013 1004 }
1014 1005 if (ph == NULL) {
1015 1006 pdip = NULL;
1016 1007 }
1017 1008 MDI_VHCI_PHCI_UNLOCK(vh);
1018 1009 kmem_free(temp_pathname, MAXPATHLEN);
1019 1010 return (pdip);
1020 1011 }
1021 1012
1022 1013 /*
1023 1014 * mdi_phci_get_path_count():
1024 1015 * get number of path information nodes associated with a given
1025 1016 * pHCI device.
1026 1017 */
1027 1018 int
1028 1019 mdi_phci_get_path_count(dev_info_t *pdip)
1029 1020 {
1030 1021 mdi_phci_t *ph;
1031 1022 int count = 0;
1032 1023
1033 1024 ph = i_devi_get_phci(pdip);
1034 1025 if (ph != NULL) {
1035 1026 count = ph->ph_path_count;
1036 1027 }
1037 1028 return (count);
1038 1029 }
1039 1030
1040 1031 /*
1041 1032 * i_mdi_phci_lock():
1042 1033 * Lock a pHCI device
1043 1034 * Return Values:
1044 1035 * None
1045 1036 * Note:
1046 1037 * The default locking order is:
1047 1038 * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex))
1048 1039 * But there are number of situations where locks need to be
1049 1040 * grabbed in reverse order. This routine implements try and lock
1050 1041 * mechanism depending on the requested parameter option.
1051 1042 */
1052 1043 static void
1053 1044 i_mdi_phci_lock(mdi_phci_t *ph, mdi_pathinfo_t *pip)
1054 1045 {
1055 1046 if (pip) {
1056 1047 /* Reverse locking is requested. */
1057 1048 while (MDI_PHCI_TRYLOCK(ph) == 0) {
1058 1049 if (servicing_interrupt()) {
1059 1050 MDI_PI_HOLD(pip);
1060 1051 MDI_PI_UNLOCK(pip);
1061 1052 MDI_PHCI_LOCK(ph);
1062 1053 MDI_PI_LOCK(pip);
1063 1054 MDI_PI_RELE(pip);
1064 1055 break;
1065 1056 } else {
1066 1057 /*
1067 1058 * tryenter failed. Try to grab again
1068 1059 * after a small delay
1069 1060 */
1070 1061 MDI_PI_HOLD(pip);
1071 1062 MDI_PI_UNLOCK(pip);
1072 1063 delay_random(mdi_delay);
1073 1064 MDI_PI_LOCK(pip);
1074 1065 MDI_PI_RELE(pip);
1075 1066 }
1076 1067 }
1077 1068 } else {
1078 1069 MDI_PHCI_LOCK(ph);
1079 1070 }
1080 1071 }
1081 1072
1082 1073 /*
1083 1074 * i_mdi_phci_unlock():
1084 1075 * Unlock the pHCI component
1085 1076 */
1086 1077 static void
1087 1078 i_mdi_phci_unlock(mdi_phci_t *ph)
1088 1079 {
1089 1080 MDI_PHCI_UNLOCK(ph);
1090 1081 }
1091 1082
1092 1083 /*
1093 1084 * i_mdi_devinfo_create():
1094 1085 * create client device's devinfo node
1095 1086 * Return Values:
1096 1087 * dev_info
1097 1088 * NULL
1098 1089 * Notes:
1099 1090 */
1100 1091 static dev_info_t *
1101 1092 i_mdi_devinfo_create(mdi_vhci_t *vh, char *name, char *guid,
1102 1093 char **compatible, int ncompatible)
1103 1094 {
1104 1095 dev_info_t *cdip = NULL;
1105 1096
1106 1097 ASSERT(MDI_VHCI_CLIENT_LOCKED(vh));
1107 1098
1108 1099 /* Verify for duplicate entry */
1109 1100 cdip = i_mdi_devinfo_find(vh, name, guid);
1110 1101 ASSERT(cdip == NULL);
1111 1102 if (cdip) {
1112 1103 cmn_err(CE_WARN,
1113 1104 "i_mdi_devinfo_create: client %s@%s already exists",
1114 1105 name ? name : "", guid ? guid : "");
1115 1106 }
1116 1107
1117 1108 ndi_devi_alloc_sleep(vh->vh_dip, name, DEVI_SID_NODEID, &cdip);
1118 1109 if (cdip == NULL)
1119 1110 goto fail;
1120 1111
1121 1112 /*
1122 1113 * Create component type and Global unique identifier
1123 1114 * properties
1124 1115 */
1125 1116 if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip,
1126 1117 MDI_CLIENT_GUID_PROP, guid) != DDI_PROP_SUCCESS) {
1127 1118 goto fail;
1128 1119 }
1129 1120
1130 1121 /* Decorate the node with compatible property */
1131 1122 if (compatible &&
1132 1123 (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
1133 1124 "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS)) {
1134 1125 goto fail;
1135 1126 }
1136 1127
1137 1128 return (cdip);
1138 1129
1139 1130 fail:
1140 1131 if (cdip) {
1141 1132 (void) ndi_prop_remove_all(cdip);
1142 1133 (void) ndi_devi_free(cdip);
1143 1134 }
1144 1135 return (NULL);
1145 1136 }
1146 1137
1147 1138 /*
1148 1139 * i_mdi_devinfo_find():
1149 1140 * Find a matching devinfo node for given client node name
1150 1141 * and its guid.
1151 1142 * Return Values:
1152 1143 * Handle to a dev_info node or NULL
1153 1144 */
1154 1145 static dev_info_t *
1155 1146 i_mdi_devinfo_find(mdi_vhci_t *vh, caddr_t name, char *guid)
1156 1147 {
1157 1148 char *data;
1158 1149 dev_info_t *cdip = NULL;
1159 1150 dev_info_t *ndip = NULL;
1160 1151 int circular;
1161 1152
1162 1153 ndi_devi_enter(vh->vh_dip, &circular);
1163 1154 ndip = (dev_info_t *)DEVI(vh->vh_dip)->devi_child;
1164 1155 while ((cdip = ndip) != NULL) {
1165 1156 ndip = (dev_info_t *)DEVI(cdip)->devi_sibling;
1166 1157
1167 1158 if (strcmp(DEVI(cdip)->devi_node_name, name)) {
1168 1159 continue;
1169 1160 }
1170 1161
1171 1162 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip,
1172 1163 DDI_PROP_DONTPASS, MDI_CLIENT_GUID_PROP,
1173 1164 &data) != DDI_PROP_SUCCESS) {
1174 1165 continue;
1175 1166 }
1176 1167
1177 1168 if (strcmp(data, guid) != 0) {
1178 1169 ddi_prop_free(data);
1179 1170 continue;
1180 1171 }
1181 1172 ddi_prop_free(data);
1182 1173 break;
1183 1174 }
1184 1175 ndi_devi_exit(vh->vh_dip, circular);
1185 1176 return (cdip);
1186 1177 }
1187 1178
1188 1179 /*
1189 1180 * i_mdi_devinfo_remove():
1190 1181 * Remove a client device node
1191 1182 */
1192 1183 static int
1193 1184 i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags)
1194 1185 {
1195 1186 int rv = MDI_SUCCESS;
1196 1187
1197 1188 if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS ||
1198 1189 (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) {
1199 1190 rv = ndi_devi_offline(cdip, NDI_DEVFS_CLEAN | NDI_DEVI_REMOVE);
1200 1191 if (rv != NDI_SUCCESS) {
1201 1192 MDI_DEBUG(1, (MDI_NOTE, cdip,
1202 1193 "!failed: cdip %p", (void *)cdip));
1203 1194 }
1204 1195 /*
1205 1196 * Convert to MDI error code
1206 1197 */
1207 1198 switch (rv) {
1208 1199 case NDI_SUCCESS:
1209 1200 rv = MDI_SUCCESS;
1210 1201 break;
1211 1202 case NDI_BUSY:
1212 1203 rv = MDI_BUSY;
1213 1204 break;
1214 1205 default:
1215 1206 rv = MDI_FAILURE;
1216 1207 break;
1217 1208 }
1218 1209 }
1219 1210 return (rv);
1220 1211 }
1221 1212
1222 1213 /*
1223 1214 * i_devi_get_client()
1224 1215 * Utility function to get mpxio component extensions
1225 1216 */
1226 1217 static mdi_client_t *
1227 1218 i_devi_get_client(dev_info_t *cdip)
1228 1219 {
1229 1220 mdi_client_t *ct = NULL;
1230 1221
1231 1222 if (MDI_CLIENT(cdip)) {
1232 1223 ct = (mdi_client_t *)DEVI(cdip)->devi_mdi_client;
1233 1224 }
1234 1225 return (ct);
1235 1226 }
1236 1227
1237 1228 /*
1238 1229 * i_mdi_is_child_present():
1239 1230 * Search for the presence of client device dev_info node
1240 1231 */
1241 1232 static int
1242 1233 i_mdi_is_child_present(dev_info_t *vdip, dev_info_t *cdip)
1243 1234 {
1244 1235 int rv = MDI_FAILURE;
1245 1236 struct dev_info *dip;
1246 1237 int circular;
1247 1238
1248 1239 ndi_devi_enter(vdip, &circular);
1249 1240 dip = DEVI(vdip)->devi_child;
1250 1241 while (dip) {
1251 1242 if (dip == DEVI(cdip)) {
1252 1243 rv = MDI_SUCCESS;
1253 1244 break;
1254 1245 }
1255 1246 dip = dip->devi_sibling;
1256 1247 }
1257 1248 ndi_devi_exit(vdip, circular);
1258 1249 return (rv);
1259 1250 }
1260 1251
1261 1252
1262 1253 /*
1263 1254 * i_mdi_client_lock():
1264 1255 * Grab client component lock
1265 1256 * Return Values:
1266 1257 * None
1267 1258 * Note:
1268 1259 * The default locking order is:
1269 1260 * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex))
1270 1261 * But there are number of situations where locks need to be
1271 1262 * grabbed in reverse order. This routine implements try and lock
1272 1263 * mechanism depending on the requested parameter option.
1273 1264 */
1274 1265 static void
1275 1266 i_mdi_client_lock(mdi_client_t *ct, mdi_pathinfo_t *pip)
1276 1267 {
1277 1268 if (pip) {
1278 1269 /*
1279 1270 * Reverse locking is requested.
1280 1271 */
1281 1272 while (MDI_CLIENT_TRYLOCK(ct) == 0) {
1282 1273 if (servicing_interrupt()) {
1283 1274 MDI_PI_HOLD(pip);
1284 1275 MDI_PI_UNLOCK(pip);
1285 1276 MDI_CLIENT_LOCK(ct);
1286 1277 MDI_PI_LOCK(pip);
1287 1278 MDI_PI_RELE(pip);
1288 1279 break;
1289 1280 } else {
1290 1281 /*
1291 1282 * tryenter failed. Try to grab again
1292 1283 * after a small delay
1293 1284 */
1294 1285 MDI_PI_HOLD(pip);
1295 1286 MDI_PI_UNLOCK(pip);
1296 1287 delay_random(mdi_delay);
1297 1288 MDI_PI_LOCK(pip);
1298 1289 MDI_PI_RELE(pip);
1299 1290 }
1300 1291 }
1301 1292 } else {
1302 1293 MDI_CLIENT_LOCK(ct);
1303 1294 }
1304 1295 }
1305 1296
1306 1297 /*
1307 1298 * i_mdi_client_unlock():
1308 1299 * Unlock a client component
1309 1300 */
1310 1301 static void
1311 1302 i_mdi_client_unlock(mdi_client_t *ct)
1312 1303 {
1313 1304 MDI_CLIENT_UNLOCK(ct);
1314 1305 }
1315 1306
1316 1307 /*
1317 1308 * i_mdi_client_alloc():
1318 1309 * Allocate and initialize a client structure. Caller should
1319 1310 * hold the vhci client lock.
1320 1311 * Return Values:
1321 1312 * Handle to a client component
1322 1313 */
1323 1314 /*ARGSUSED*/
1324 1315 static mdi_client_t *
1325 1316 i_mdi_client_alloc(mdi_vhci_t *vh, char *name, char *lguid)
1326 1317 {
1327 1318 mdi_client_t *ct;
1328 1319
1329 1320 ASSERT(MDI_VHCI_CLIENT_LOCKED(vh));
1330 1321
1331 1322 /*
1332 1323 * Allocate and initialize a component structure.
1333 1324 */
1334 1325 ct = kmem_zalloc(sizeof (*ct), KM_SLEEP);
1335 1326 mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL);
1336 1327 ct->ct_hnext = NULL;
1337 1328 ct->ct_hprev = NULL;
1338 1329 ct->ct_dip = NULL;
1339 1330 ct->ct_vhci = vh;
1340 1331 ct->ct_drvname = kmem_alloc(strlen(name) + 1, KM_SLEEP);
1341 1332 (void) strcpy(ct->ct_drvname, name);
1342 1333 ct->ct_guid = kmem_alloc(strlen(lguid) + 1, KM_SLEEP);
1343 1334 (void) strcpy(ct->ct_guid, lguid);
1344 1335 ct->ct_cprivate = NULL;
1345 1336 ct->ct_vprivate = NULL;
1346 1337 ct->ct_flags = 0;
1347 1338 ct->ct_state = MDI_CLIENT_STATE_FAILED;
1348 1339 MDI_CLIENT_LOCK(ct);
1349 1340 MDI_CLIENT_SET_OFFLINE(ct);
1350 1341 MDI_CLIENT_SET_DETACH(ct);
1351 1342 MDI_CLIENT_SET_POWER_UP(ct);
1352 1343 MDI_CLIENT_UNLOCK(ct);
1353 1344 ct->ct_failover_flags = 0;
1354 1345 ct->ct_failover_status = 0;
1355 1346 cv_init(&ct->ct_failover_cv, NULL, CV_DRIVER, NULL);
1356 1347 ct->ct_unstable = 0;
1357 1348 cv_init(&ct->ct_unstable_cv, NULL, CV_DRIVER, NULL);
1358 1349 cv_init(&ct->ct_powerchange_cv, NULL, CV_DRIVER, NULL);
1359 1350 ct->ct_lb = vh->vh_lb;
1360 1351 ct->ct_lb_args = kmem_zalloc(sizeof (client_lb_args_t), KM_SLEEP);
1361 1352 ct->ct_lb_args->region_size = LOAD_BALANCE_DEFAULT_REGION_SIZE;
1362 1353 ct->ct_path_count = 0;
1363 1354 ct->ct_path_head = NULL;
1364 1355 ct->ct_path_tail = NULL;
1365 1356 ct->ct_path_last = NULL;
1366 1357
1367 1358 /*
1368 1359 * Add this client component to our client hash queue
1369 1360 */
1370 1361 i_mdi_client_enlist_table(vh, ct);
1371 1362 return (ct);
1372 1363 }
1373 1364
1374 1365 /*
1375 1366 * i_mdi_client_enlist_table():
1376 1367 * Attach the client device to the client hash table. Caller
1377 1368 * should hold the vhci client lock.
1378 1369 */
1379 1370 static void
1380 1371 i_mdi_client_enlist_table(mdi_vhci_t *vh, mdi_client_t *ct)
1381 1372 {
1382 1373 int index;
1383 1374 struct client_hash *head;
1384 1375
1385 1376 ASSERT(MDI_VHCI_CLIENT_LOCKED(vh));
1386 1377
1387 1378 index = i_mdi_get_hash_key(ct->ct_guid);
1388 1379 head = &vh->vh_client_table[index];
1389 1380 ct->ct_hnext = (mdi_client_t *)head->ct_hash_head;
1390 1381 head->ct_hash_head = ct;
1391 1382 head->ct_hash_count++;
1392 1383 vh->vh_client_count++;
1393 1384 }
1394 1385
1395 1386 /*
1396 1387 * i_mdi_client_delist_table():
1397 1388 * Attach the client device to the client hash table.
1398 1389 * Caller should hold the vhci client lock.
1399 1390 */
1400 1391 static void
1401 1392 i_mdi_client_delist_table(mdi_vhci_t *vh, mdi_client_t *ct)
1402 1393 {
1403 1394 int index;
1404 1395 char *guid;
1405 1396 struct client_hash *head;
1406 1397 mdi_client_t *next;
1407 1398 mdi_client_t *last;
1408 1399
1409 1400 ASSERT(MDI_VHCI_CLIENT_LOCKED(vh));
1410 1401
1411 1402 guid = ct->ct_guid;
1412 1403 index = i_mdi_get_hash_key(guid);
1413 1404 head = &vh->vh_client_table[index];
1414 1405
1415 1406 last = NULL;
1416 1407 next = (mdi_client_t *)head->ct_hash_head;
1417 1408 while (next != NULL) {
1418 1409 if (next == ct) {
1419 1410 break;
1420 1411 }
1421 1412 last = next;
1422 1413 next = next->ct_hnext;
1423 1414 }
1424 1415
1425 1416 if (next) {
1426 1417 head->ct_hash_count--;
1427 1418 if (last == NULL) {
1428 1419 head->ct_hash_head = ct->ct_hnext;
1429 1420 } else {
1430 1421 last->ct_hnext = ct->ct_hnext;
1431 1422 }
1432 1423 ct->ct_hnext = NULL;
1433 1424 vh->vh_client_count--;
1434 1425 }
1435 1426 }
1436 1427
1437 1428
1438 1429 /*
1439 1430 * i_mdi_client_free():
1440 1431 * Free a client component
1441 1432 */
1442 1433 static int
1443 1434 i_mdi_client_free(mdi_vhci_t *vh, mdi_client_t *ct)
1444 1435 {
1445 1436 int rv = MDI_SUCCESS;
1446 1437 int flags = ct->ct_flags;
1447 1438 dev_info_t *cdip;
1448 1439 dev_info_t *vdip;
1449 1440
1450 1441 ASSERT(MDI_VHCI_CLIENT_LOCKED(vh));
1451 1442
1452 1443 vdip = vh->vh_dip;
1453 1444 cdip = ct->ct_dip;
1454 1445
1455 1446 (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, MDI_CLIENT_GUID_PROP);
1456 1447 DEVI(cdip)->devi_mdi_component &= ~MDI_COMPONENT_CLIENT;
1457 1448 DEVI(cdip)->devi_mdi_client = NULL;
1458 1449
1459 1450 /*
1460 1451 * Clear out back ref. to dev_info_t node
1461 1452 */
1462 1453 ct->ct_dip = NULL;
1463 1454
1464 1455 /*
1465 1456 * Remove this client from our hash queue
1466 1457 */
1467 1458 i_mdi_client_delist_table(vh, ct);
1468 1459
1469 1460 /*
1470 1461 * Uninitialize and free the component
1471 1462 */
1472 1463 kmem_free(ct->ct_drvname, strlen(ct->ct_drvname) + 1);
1473 1464 kmem_free(ct->ct_guid, strlen(ct->ct_guid) + 1);
1474 1465 kmem_free(ct->ct_lb_args, sizeof (client_lb_args_t));
1475 1466 cv_destroy(&ct->ct_failover_cv);
1476 1467 cv_destroy(&ct->ct_unstable_cv);
1477 1468 cv_destroy(&ct->ct_powerchange_cv);
1478 1469 mutex_destroy(&ct->ct_mutex);
1479 1470 kmem_free(ct, sizeof (*ct));
1480 1471
1481 1472 if (cdip != NULL) {
1482 1473 MDI_VHCI_CLIENT_UNLOCK(vh);
1483 1474 (void) i_mdi_devinfo_remove(vdip, cdip, flags);
1484 1475 MDI_VHCI_CLIENT_LOCK(vh);
1485 1476 }
1486 1477 return (rv);
1487 1478 }
1488 1479
1489 1480 /*
1490 1481 * i_mdi_client_find():
1491 1482 * Find the client structure corresponding to a given guid
1492 1483 * Caller should hold the vhci client lock.
1493 1484 */
1494 1485 static mdi_client_t *
1495 1486 i_mdi_client_find(mdi_vhci_t *vh, char *cname, char *guid)
1496 1487 {
1497 1488 int index;
1498 1489 struct client_hash *head;
1499 1490 mdi_client_t *ct;
1500 1491
1501 1492 ASSERT(MDI_VHCI_CLIENT_LOCKED(vh));
1502 1493
1503 1494 index = i_mdi_get_hash_key(guid);
1504 1495 head = &vh->vh_client_table[index];
1505 1496
1506 1497 ct = head->ct_hash_head;
1507 1498 while (ct != NULL) {
1508 1499 if (strcmp(ct->ct_guid, guid) == 0 &&
1509 1500 (cname == NULL || strcmp(ct->ct_drvname, cname) == 0)) {
1510 1501 break;
1511 1502 }
1512 1503 ct = ct->ct_hnext;
1513 1504 }
1514 1505 return (ct);
1515 1506 }
1516 1507
1517 1508 /*
1518 1509 * i_mdi_client_update_state():
1519 1510 * Compute and update client device state
1520 1511 * Notes:
1521 1512 * A client device can be in any of three possible states:
1522 1513 *
1523 1514 * MDI_CLIENT_STATE_OPTIMAL - Client in optimal state with more
1524 1515 * one online/standby paths. Can tolerate failures.
1525 1516 * MDI_CLIENT_STATE_DEGRADED - Client device in degraded state with
1526 1517 * no alternate paths available as standby. A failure on the online
1527 1518 * would result in loss of access to device data.
1528 1519 * MDI_CLIENT_STATE_FAILED - Client device in failed state with
1529 1520 * no paths available to access the device.
1530 1521 */
1531 1522 static void
1532 1523 i_mdi_client_update_state(mdi_client_t *ct)
1533 1524 {
1534 1525 int state;
1535 1526
1536 1527 ASSERT(MDI_CLIENT_LOCKED(ct));
1537 1528 state = i_mdi_client_compute_state(ct, NULL);
1538 1529 MDI_CLIENT_SET_STATE(ct, state);
1539 1530 }
1540 1531
1541 1532 /*
1542 1533 * i_mdi_client_compute_state():
1543 1534 * Compute client device state
1544 1535 *
1545 1536 * mdi_phci_t * Pointer to pHCI structure which should
1546 1537 * while computing the new value. Used by
1547 1538 * i_mdi_phci_offline() to find the new
1548 1539 * client state after DR of a pHCI.
1549 1540 */
1550 1541 static int
1551 1542 i_mdi_client_compute_state(mdi_client_t *ct, mdi_phci_t *ph)
1552 1543 {
1553 1544 int state;
1554 1545 int online_count = 0;
1555 1546 int standby_count = 0;
1556 1547 mdi_pathinfo_t *pip, *next;
1557 1548
1558 1549 ASSERT(MDI_CLIENT_LOCKED(ct));
1559 1550 pip = ct->ct_path_head;
1560 1551 while (pip != NULL) {
1561 1552 MDI_PI_LOCK(pip);
1562 1553 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
1563 1554 if (MDI_PI(pip)->pi_phci == ph) {
1564 1555 MDI_PI_UNLOCK(pip);
1565 1556 pip = next;
1566 1557 continue;
1567 1558 }
1568 1559
1569 1560 if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK)
1570 1561 == MDI_PATHINFO_STATE_ONLINE)
1571 1562 online_count++;
1572 1563 else if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK)
1573 1564 == MDI_PATHINFO_STATE_STANDBY)
1574 1565 standby_count++;
1575 1566 MDI_PI_UNLOCK(pip);
1576 1567 pip = next;
1577 1568 }
1578 1569
1579 1570 if (online_count == 0) {
1580 1571 if (standby_count == 0) {
1581 1572 state = MDI_CLIENT_STATE_FAILED;
1582 1573 MDI_DEBUG(2, (MDI_NOTE, ct->ct_dip,
1583 1574 "client state failed: ct = %p", (void *)ct));
1584 1575 } else if (standby_count == 1) {
1585 1576 state = MDI_CLIENT_STATE_DEGRADED;
1586 1577 } else {
1587 1578 state = MDI_CLIENT_STATE_OPTIMAL;
1588 1579 }
1589 1580 } else if (online_count == 1) {
1590 1581 if (standby_count == 0) {
1591 1582 state = MDI_CLIENT_STATE_DEGRADED;
1592 1583 } else {
1593 1584 state = MDI_CLIENT_STATE_OPTIMAL;
1594 1585 }
1595 1586 } else {
1596 1587 state = MDI_CLIENT_STATE_OPTIMAL;
1597 1588 }
1598 1589 return (state);
1599 1590 }
1600 1591
1601 1592 /*
1602 1593 * i_mdi_client2devinfo():
1603 1594 * Utility function
1604 1595 */
1605 1596 dev_info_t *
1606 1597 i_mdi_client2devinfo(mdi_client_t *ct)
1607 1598 {
1608 1599 return (ct->ct_dip);
1609 1600 }
1610 1601
1611 1602 /*
1612 1603 * mdi_client_path2_devinfo():
1613 1604 * Given the parent devinfo and child devfs pathname, search for
1614 1605 * a valid devfs node handle.
1615 1606 */
1616 1607 dev_info_t *
1617 1608 mdi_client_path2devinfo(dev_info_t *vdip, char *pathname)
1618 1609 {
1619 1610 dev_info_t *cdip = NULL;
1620 1611 dev_info_t *ndip = NULL;
1621 1612 char *temp_pathname;
1622 1613 int circular;
1623 1614
1624 1615 /*
1625 1616 * Allocate temp buffer
1626 1617 */
1627 1618 temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1628 1619
1629 1620 /*
1630 1621 * Lock parent against changes
1631 1622 */
1632 1623 ndi_devi_enter(vdip, &circular);
1633 1624 ndip = (dev_info_t *)DEVI(vdip)->devi_child;
1634 1625 while ((cdip = ndip) != NULL) {
1635 1626 ndip = (dev_info_t *)DEVI(cdip)->devi_sibling;
1636 1627
1637 1628 *temp_pathname = '\0';
1638 1629 (void) ddi_pathname(cdip, temp_pathname);
1639 1630 if (strcmp(temp_pathname, pathname) == 0) {
1640 1631 break;
1641 1632 }
1642 1633 }
1643 1634 /*
1644 1635 * Release devinfo lock
1645 1636 */
1646 1637 ndi_devi_exit(vdip, circular);
1647 1638
1648 1639 /*
1649 1640 * Free the temp buffer
1650 1641 */
1651 1642 kmem_free(temp_pathname, MAXPATHLEN);
1652 1643 return (cdip);
1653 1644 }
1654 1645
1655 1646 /*
1656 1647 * mdi_client_get_path_count():
1657 1648 * Utility function to get number of path information nodes
1658 1649 * associated with a given client device.
1659 1650 */
1660 1651 int
1661 1652 mdi_client_get_path_count(dev_info_t *cdip)
1662 1653 {
1663 1654 mdi_client_t *ct;
1664 1655 int count = 0;
1665 1656
1666 1657 ct = i_devi_get_client(cdip);
1667 1658 if (ct != NULL) {
1668 1659 count = ct->ct_path_count;
1669 1660 }
1670 1661 return (count);
1671 1662 }
1672 1663
1673 1664
1674 1665 /*
1675 1666 * i_mdi_get_hash_key():
1676 1667 * Create a hash using strings as keys
1677 1668 *
1678 1669 */
1679 1670 static int
1680 1671 i_mdi_get_hash_key(char *str)
1681 1672 {
1682 1673 uint32_t g, hash = 0;
1683 1674 char *p;
1684 1675
1685 1676 for (p = str; *p != '\0'; p++) {
1686 1677 g = *p;
1687 1678 hash += g;
1688 1679 }
1689 1680 return (hash % (CLIENT_HASH_TABLE_SIZE - 1));
1690 1681 }
1691 1682
1692 1683 /*
1693 1684 * mdi_get_lb_policy():
1694 1685 * Get current load balancing policy for a given client device
1695 1686 */
1696 1687 client_lb_t
1697 1688 mdi_get_lb_policy(dev_info_t *cdip)
1698 1689 {
1699 1690 client_lb_t lb = LOAD_BALANCE_NONE;
1700 1691 mdi_client_t *ct;
1701 1692
1702 1693 ct = i_devi_get_client(cdip);
1703 1694 if (ct != NULL) {
1704 1695 lb = ct->ct_lb;
1705 1696 }
1706 1697 return (lb);
1707 1698 }
1708 1699
1709 1700 /*
1710 1701 * mdi_set_lb_region_size():
1711 1702 * Set current region size for the load-balance
1712 1703 */
1713 1704 int
1714 1705 mdi_set_lb_region_size(dev_info_t *cdip, int region_size)
1715 1706 {
1716 1707 mdi_client_t *ct;
1717 1708 int rv = MDI_FAILURE;
1718 1709
1719 1710 ct = i_devi_get_client(cdip);
1720 1711 if (ct != NULL && ct->ct_lb_args != NULL) {
1721 1712 ct->ct_lb_args->region_size = region_size;
1722 1713 rv = MDI_SUCCESS;
1723 1714 }
1724 1715 return (rv);
1725 1716 }
1726 1717
1727 1718 /*
1728 1719 * mdi_Set_lb_policy():
1729 1720 * Set current load balancing policy for a given client device
1730 1721 */
1731 1722 int
1732 1723 mdi_set_lb_policy(dev_info_t *cdip, client_lb_t lb)
1733 1724 {
1734 1725 mdi_client_t *ct;
1735 1726 int rv = MDI_FAILURE;
1736 1727
1737 1728 ct = i_devi_get_client(cdip);
1738 1729 if (ct != NULL) {
1739 1730 ct->ct_lb = lb;
1740 1731 rv = MDI_SUCCESS;
1741 1732 }
1742 1733 return (rv);
1743 1734 }
1744 1735
1745 1736 /*
1746 1737 * mdi_failover():
1747 1738 * failover function called by the vHCI drivers to initiate
1748 1739 * a failover operation. This is typically due to non-availability
1749 1740 * of online paths to route I/O requests. Failover can be
1750 1741 * triggered through user application also.
1751 1742 *
1752 1743 * The vHCI driver calls mdi_failover() to initiate a failover
1753 1744 * operation. mdi_failover() calls back into the vHCI driver's
1754 1745 * vo_failover() entry point to perform the actual failover
1755 1746 * operation. The reason for requiring the vHCI driver to
1756 1747 * initiate failover by calling mdi_failover(), instead of directly
1757 1748 * executing vo_failover() itself, is to ensure that the mdi
1758 1749 * framework can keep track of the client state properly.
1759 1750 * Additionally, mdi_failover() provides as a convenience the
1760 1751 * option of performing the failover operation synchronously or
1761 1752 * asynchronously
1762 1753 *
1763 1754 * Upon successful completion of the failover operation, the
1764 1755 * paths that were previously ONLINE will be in the STANDBY state,
1765 1756 * and the newly activated paths will be in the ONLINE state.
1766 1757 *
1767 1758 * The flags modifier determines whether the activation is done
1768 1759 * synchronously: MDI_FAILOVER_SYNC
1769 1760 * Return Values:
1770 1761 * MDI_SUCCESS
1771 1762 * MDI_FAILURE
1772 1763 * MDI_BUSY
1773 1764 */
1774 1765 /*ARGSUSED*/
1775 1766 int
1776 1767 mdi_failover(dev_info_t *vdip, dev_info_t *cdip, int flags)
1777 1768 {
1778 1769 int rv;
1779 1770 mdi_client_t *ct;
1780 1771
1781 1772 ct = i_devi_get_client(cdip);
1782 1773 ASSERT(ct != NULL);
1783 1774 if (ct == NULL) {
1784 1775 /* cdip is not a valid client device. Nothing more to do. */
1785 1776 return (MDI_FAILURE);
1786 1777 }
1787 1778
1788 1779 MDI_CLIENT_LOCK(ct);
1789 1780
1790 1781 if (MDI_CLIENT_IS_PATH_FREE_IN_PROGRESS(ct)) {
1791 1782 /* A path to the client is being freed */
1792 1783 MDI_CLIENT_UNLOCK(ct);
1793 1784 return (MDI_BUSY);
1794 1785 }
1795 1786
1796 1787
1797 1788 if (MDI_CLIENT_IS_FAILED(ct)) {
1798 1789 /*
1799 1790 * Client is in failed state. Nothing more to do.
1800 1791 */
1801 1792 MDI_CLIENT_UNLOCK(ct);
1802 1793 return (MDI_FAILURE);
1803 1794 }
1804 1795
1805 1796 if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) {
1806 1797 /*
1807 1798 * Failover is already in progress; return BUSY
1808 1799 */
1809 1800 MDI_CLIENT_UNLOCK(ct);
1810 1801 return (MDI_BUSY);
1811 1802 }
1812 1803 /*
1813 1804 * Make sure that mdi_pathinfo node state changes are processed.
1814 1805 * We do not allow failovers to progress while client path state
1815 1806 * changes are in progress
1816 1807 */
1817 1808 if (ct->ct_unstable) {
1818 1809 if (flags == MDI_FAILOVER_ASYNC) {
1819 1810 MDI_CLIENT_UNLOCK(ct);
1820 1811 return (MDI_BUSY);
1821 1812 } else {
1822 1813 while (ct->ct_unstable)
1823 1814 cv_wait(&ct->ct_unstable_cv, &ct->ct_mutex);
1824 1815 }
1825 1816 }
1826 1817
1827 1818 /*
1828 1819 * Client device is in stable state. Before proceeding, perform sanity
1829 1820 * checks again.
1830 1821 */
1831 1822 if ((MDI_CLIENT_IS_DETACHED(ct)) || (MDI_CLIENT_IS_FAILED(ct)) ||
1832 1823 (!i_ddi_devi_attached(cdip))) {
1833 1824 /*
1834 1825 * Client is in failed state. Nothing more to do.
1835 1826 */
1836 1827 MDI_CLIENT_UNLOCK(ct);
1837 1828 return (MDI_FAILURE);
1838 1829 }
1839 1830
1840 1831 /*
1841 1832 * Set the client state as failover in progress.
1842 1833 */
1843 1834 MDI_CLIENT_SET_FAILOVER_IN_PROGRESS(ct);
1844 1835 ct->ct_failover_flags = flags;
1845 1836 MDI_CLIENT_UNLOCK(ct);
1846 1837
1847 1838 if (flags == MDI_FAILOVER_ASYNC) {
1848 1839 /*
1849 1840 * Submit the initiate failover request via CPR safe
1850 1841 * taskq threads.
1851 1842 */
1852 1843 (void) taskq_dispatch(mdi_taskq, (task_func_t *)i_mdi_failover,
1853 1844 ct, KM_SLEEP);
1854 1845 return (MDI_ACCEPT);
1855 1846 } else {
1856 1847 /*
1857 1848 * Synchronous failover mode. Typically invoked from the user
1858 1849 * land.
1859 1850 */
1860 1851 rv = i_mdi_failover(ct);
1861 1852 }
1862 1853 return (rv);
1863 1854 }
1864 1855
1865 1856 /*
1866 1857 * i_mdi_failover():
1867 1858 * internal failover function. Invokes vHCI drivers failover
1868 1859 * callback function and process the failover status
1869 1860 * Return Values:
1870 1861 * None
1871 1862 *
1872 1863 * Note: A client device in failover state can not be detached or freed.
1873 1864 */
1874 1865 static int
1875 1866 i_mdi_failover(void *arg)
1876 1867 {
1877 1868 int rv = MDI_SUCCESS;
1878 1869 mdi_client_t *ct = (mdi_client_t *)arg;
1879 1870 mdi_vhci_t *vh = ct->ct_vhci;
1880 1871
1881 1872 ASSERT(!MDI_CLIENT_LOCKED(ct));
1882 1873
1883 1874 if (vh->vh_ops->vo_failover != NULL) {
1884 1875 /*
1885 1876 * Call vHCI drivers callback routine
1886 1877 */
1887 1878 rv = (*vh->vh_ops->vo_failover)(vh->vh_dip, ct->ct_dip,
1888 1879 ct->ct_failover_flags);
1889 1880 }
1890 1881
1891 1882 MDI_CLIENT_LOCK(ct);
1892 1883 MDI_CLIENT_CLEAR_FAILOVER_IN_PROGRESS(ct);
1893 1884
1894 1885 /*
1895 1886 * Save the failover return status
1896 1887 */
1897 1888 ct->ct_failover_status = rv;
1898 1889
1899 1890 /*
1900 1891 * As a result of failover, client status would have been changed.
1901 1892 * Update the client state and wake up anyone waiting on this client
1902 1893 * device.
1903 1894 */
1904 1895 i_mdi_client_update_state(ct);
1905 1896
1906 1897 cv_broadcast(&ct->ct_failover_cv);
1907 1898 MDI_CLIENT_UNLOCK(ct);
1908 1899 return (rv);
1909 1900 }
1910 1901
1911 1902 /*
1912 1903 * Load balancing is logical block.
1913 1904 * IOs within the range described by region_size
1914 1905 * would go on the same path. This would improve the
1915 1906 * performance by cache-hit on some of the RAID devices.
1916 1907 * Search only for online paths(At some point we
1917 1908 * may want to balance across target ports).
1918 1909 * If no paths are found then default to round-robin.
1919 1910 */
1920 1911 static int
1921 1912 i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp)
1922 1913 {
1923 1914 int path_index = -1;
1924 1915 int online_path_count = 0;
1925 1916 int online_nonpref_path_count = 0;
1926 1917 int region_size = ct->ct_lb_args->region_size;
1927 1918 mdi_pathinfo_t *pip;
1928 1919 mdi_pathinfo_t *next;
1929 1920 int preferred, path_cnt;
1930 1921
1931 1922 pip = ct->ct_path_head;
1932 1923 while (pip) {
1933 1924 MDI_PI_LOCK(pip);
1934 1925 if (MDI_PI(pip)->pi_state ==
1935 1926 MDI_PATHINFO_STATE_ONLINE && MDI_PI(pip)->pi_preferred) {
1936 1927 online_path_count++;
1937 1928 } else if (MDI_PI(pip)->pi_state ==
1938 1929 MDI_PATHINFO_STATE_ONLINE && !MDI_PI(pip)->pi_preferred) {
1939 1930 online_nonpref_path_count++;
1940 1931 }
1941 1932 next = (mdi_pathinfo_t *)
1942 1933 MDI_PI(pip)->pi_client_link;
1943 1934 MDI_PI_UNLOCK(pip);
1944 1935 pip = next;
1945 1936 }
1946 1937 /* if found any online/preferred then use this type */
1947 1938 if (online_path_count > 0) {
1948 1939 path_cnt = online_path_count;
1949 1940 preferred = 1;
1950 1941 } else if (online_nonpref_path_count > 0) {
1951 1942 path_cnt = online_nonpref_path_count;
1952 1943 preferred = 0;
1953 1944 } else {
1954 1945 path_cnt = 0;
1955 1946 }
1956 1947 if (path_cnt) {
1957 1948 path_index = (bp->b_blkno >> region_size) % path_cnt;
1958 1949 pip = ct->ct_path_head;
1959 1950 while (pip && path_index != -1) {
1960 1951 MDI_PI_LOCK(pip);
1961 1952 if (path_index == 0 &&
1962 1953 (MDI_PI(pip)->pi_state ==
1963 1954 MDI_PATHINFO_STATE_ONLINE) &&
1964 1955 MDI_PI(pip)->pi_preferred == preferred) {
1965 1956 MDI_PI_HOLD(pip);
1966 1957 MDI_PI_UNLOCK(pip);
1967 1958 *ret_pip = pip;
1968 1959 return (MDI_SUCCESS);
1969 1960 }
1970 1961 path_index --;
1971 1962 next = (mdi_pathinfo_t *)
1972 1963 MDI_PI(pip)->pi_client_link;
1973 1964 MDI_PI_UNLOCK(pip);
1974 1965 pip = next;
1975 1966 }
1976 1967 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
1977 1968 "lba %llx: path %s %p",
1978 1969 bp->b_lblkno, mdi_pi_spathname(pip), (void *)pip));
1979 1970 }
1980 1971 return (MDI_FAILURE);
1981 1972 }
1982 1973
1983 1974 /*
1984 1975 * mdi_select_path():
1985 1976 * select a path to access a client device.
1986 1977 *
1987 1978 * mdi_select_path() function is called by the vHCI drivers to
1988 1979 * select a path to route the I/O request to. The caller passes
1989 1980 * the block I/O data transfer structure ("buf") as one of the
1990 1981 * parameters. The mpxio framework uses the buf structure
1991 1982 * contents to maintain per path statistics (total I/O size /
1992 1983 * count pending). If more than one online paths are available to
1993 1984 * select, the framework automatically selects a suitable path
1994 1985 * for routing I/O request. If a failover operation is active for
1995 1986 * this client device the call shall be failed with MDI_BUSY error
1996 1987 * code.
1997 1988 *
1998 1989 * By default this function returns a suitable path in online
1999 1990 * state based on the current load balancing policy. Currently
2000 1991 * we support LOAD_BALANCE_NONE (Previously selected online path
2001 1992 * will continue to be used till the path is usable) and
2002 1993 * LOAD_BALANCE_RR (Online paths will be selected in a round
2003 1994 * robin fashion), LOAD_BALANCE_LB(Online paths will be selected
2004 1995 * based on the logical block). The load balancing
2005 1996 * through vHCI drivers configuration file (driver.conf).
2006 1997 *
2007 1998 * vHCI drivers may override this default behavior by specifying
2008 1999 * appropriate flags. The meaning of the thrid argument depends
2009 2000 * on the flags specified. If MDI_SELECT_PATH_INSTANCE is set
2010 2001 * then the argument is the "path instance" of the path to select.
2011 2002 * If MDI_SELECT_PATH_INSTANCE is not set then the argument is
2012 2003 * "start_pip". A non NULL "start_pip" is the starting point to
2013 2004 * walk and find the next appropriate path. The following values
2014 2005 * are currently defined: MDI_SELECT_ONLINE_PATH (to select an
2015 2006 * ONLINE path) and/or MDI_SELECT_STANDBY_PATH (to select an
2016 2007 * STANDBY path).
2017 2008 *
2018 2009 * The non-standard behavior is used by the scsi_vhci driver,
2019 2010 * whenever it has to use a STANDBY/FAULTED path. Eg. during
2020 2011 * attach of client devices (to avoid an unnecessary failover
2021 2012 * when the STANDBY path comes up first), during failover
2022 2013 * (to activate a STANDBY path as ONLINE).
2023 2014 *
2024 2015 * The selected path is returned in a a mdi_hold_path() state
2025 2016 * (pi_ref_cnt). Caller should release the hold by calling
2026 2017 * mdi_rele_path().
2027 2018 *
2028 2019 * Return Values:
2029 2020 * MDI_SUCCESS - Completed successfully
2030 2021 * MDI_BUSY - Client device is busy failing over
2031 2022 * MDI_NOPATH - Client device is online, but no valid path are
2032 2023 * available to access this client device
2033 2024 * MDI_FAILURE - Invalid client device or state
2034 2025 * MDI_DEVI_ONLINING
2035 2026 * - Client device (struct dev_info state) is in
2036 2027 * onlining state.
2037 2028 */
2038 2029
2039 2030 /*ARGSUSED*/
2040 2031 int
2041 2032 mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags,
2042 2033 void *arg, mdi_pathinfo_t **ret_pip)
2043 2034 {
2044 2035 mdi_client_t *ct;
2045 2036 mdi_pathinfo_t *pip;
2046 2037 mdi_pathinfo_t *next;
2047 2038 mdi_pathinfo_t *head;
2048 2039 mdi_pathinfo_t *start;
2049 2040 client_lb_t lbp; /* load balancing policy */
2050 2041 int sb = 1; /* standard behavior */
2051 2042 int preferred = 1; /* preferred path */
2052 2043 int cond, cont = 1;
2053 2044 int retry = 0;
2054 2045 mdi_pathinfo_t *start_pip; /* request starting pathinfo */
2055 2046 int path_instance; /* request specific path instance */
2056 2047
2057 2048 /* determine type of arg based on flags */
2058 2049 if (flags & MDI_SELECT_PATH_INSTANCE) {
2059 2050 path_instance = (int)(intptr_t)arg;
2060 2051 start_pip = NULL;
2061 2052 } else {
2062 2053 path_instance = 0;
2063 2054 start_pip = (mdi_pathinfo_t *)arg;
2064 2055 }
2065 2056
2066 2057 if (flags != 0) {
2067 2058 /*
2068 2059 * disable default behavior
2069 2060 */
2070 2061 sb = 0;
2071 2062 }
2072 2063
2073 2064 *ret_pip = NULL;
2074 2065 ct = i_devi_get_client(cdip);
2075 2066 if (ct == NULL) {
2076 2067 /* mdi extensions are NULL, Nothing more to do */
2077 2068 return (MDI_FAILURE);
2078 2069 }
2079 2070
2080 2071 MDI_CLIENT_LOCK(ct);
2081 2072
2082 2073 if (sb) {
2083 2074 if (MDI_CLIENT_IS_FAILED(ct)) {
2084 2075 /*
2085 2076 * Client is not ready to accept any I/O requests.
2086 2077 * Fail this request.
2087 2078 */
2088 2079 MDI_DEBUG(2, (MDI_NOTE, cdip,
2089 2080 "client state offline ct = %p", (void *)ct));
2090 2081 MDI_CLIENT_UNLOCK(ct);
2091 2082 return (MDI_FAILURE);
2092 2083 }
2093 2084
2094 2085 if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) {
2095 2086 /*
2096 2087 * Check for Failover is in progress. If so tell the
2097 2088 * caller that this device is busy.
2098 2089 */
2099 2090 MDI_DEBUG(2, (MDI_NOTE, cdip,
2100 2091 "client failover in progress ct = %p",
2101 2092 (void *)ct));
2102 2093 MDI_CLIENT_UNLOCK(ct);
2103 2094 return (MDI_BUSY);
2104 2095 }
2105 2096
2106 2097 /*
2107 2098 * Check to see whether the client device is attached.
2108 2099 * If not so, let the vHCI driver manually select a path
2109 2100 * (standby) and let the probe/attach process to continue.
2110 2101 */
2111 2102 if (MDI_CLIENT_IS_DETACHED(ct) || !i_ddi_devi_attached(cdip)) {
2112 2103 MDI_DEBUG(4, (MDI_NOTE, cdip,
2113 2104 "devi is onlining ct = %p", (void *)ct));
2114 2105 MDI_CLIENT_UNLOCK(ct);
2115 2106 return (MDI_DEVI_ONLINING);
2116 2107 }
2117 2108 }
2118 2109
2119 2110 /*
2120 2111 * Cache in the client list head. If head of the list is NULL
2121 2112 * return MDI_NOPATH
2122 2113 */
2123 2114 head = ct->ct_path_head;
2124 2115 if (head == NULL) {
2125 2116 MDI_CLIENT_UNLOCK(ct);
2126 2117 return (MDI_NOPATH);
2127 2118 }
2128 2119
2129 2120 /* Caller is specifying a specific pathinfo path by path_instance */
2130 2121 if (path_instance) {
2131 2122 /* search for pathinfo with correct path_instance */
2132 2123 for (pip = head;
2133 2124 pip && (mdi_pi_get_path_instance(pip) != path_instance);
2134 2125 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link)
2135 2126 ;
2136 2127
2137 2128 /* If path can't be selected then MDI_NOPATH is returned. */
2138 2129 if (pip == NULL) {
2139 2130 MDI_CLIENT_UNLOCK(ct);
2140 2131 return (MDI_NOPATH);
2141 2132 }
2142 2133
2143 2134 /*
2144 2135 * Verify state of path. When asked to select a specific
2145 2136 * path_instance, we select the requested path in any
2146 2137 * state (ONLINE, OFFLINE, STANDBY, FAULT) other than INIT.
2147 2138 * We don't however select paths where the pHCI has detached.
2148 2139 * NOTE: last pathinfo node of an opened client device may
2149 2140 * exist in an OFFLINE state after the pHCI associated with
2150 2141 * that path has detached (but pi_phci will be NULL if that
2151 2142 * has occurred).
2152 2143 */
2153 2144 MDI_PI_LOCK(pip);
2154 2145 if ((MDI_PI(pip)->pi_state == MDI_PATHINFO_STATE_INIT) ||
2155 2146 (MDI_PI(pip)->pi_phci == NULL)) {
2156 2147 MDI_PI_UNLOCK(pip);
2157 2148 MDI_CLIENT_UNLOCK(ct);
2158 2149 return (MDI_FAILURE);
2159 2150 }
2160 2151
2161 2152 /* Return MDI_BUSY if we have a transient condition */
2162 2153 if (MDI_PI_IS_TRANSIENT(pip)) {
2163 2154 MDI_PI_UNLOCK(pip);
2164 2155 MDI_CLIENT_UNLOCK(ct);
2165 2156 return (MDI_BUSY);
2166 2157 }
2167 2158
2168 2159 /*
2169 2160 * Return the path in hold state. Caller should release the
2170 2161 * lock by calling mdi_rele_path()
2171 2162 */
2172 2163 MDI_PI_HOLD(pip);
2173 2164 MDI_PI_UNLOCK(pip);
2174 2165 *ret_pip = pip;
2175 2166 MDI_CLIENT_UNLOCK(ct);
2176 2167 return (MDI_SUCCESS);
2177 2168 }
2178 2169
2179 2170 /*
2180 2171 * for non default behavior, bypass current
2181 2172 * load balancing policy and always use LOAD_BALANCE_RR
2182 2173 * except that the start point will be adjusted based
2183 2174 * on the provided start_pip
2184 2175 */
2185 2176 lbp = sb ? ct->ct_lb : LOAD_BALANCE_RR;
2186 2177
2187 2178 switch (lbp) {
2188 2179 case LOAD_BALANCE_NONE:
2189 2180 /*
2190 2181 * Load balancing is None or Alternate path mode
2191 2182 * Start looking for a online mdi_pathinfo node starting from
2192 2183 * last known selected path
2193 2184 */
2194 2185 preferred = 1;
2195 2186 pip = (mdi_pathinfo_t *)ct->ct_path_last;
2196 2187 if (pip == NULL) {
2197 2188 pip = head;
2198 2189 }
2199 2190 start = pip;
2200 2191 do {
2201 2192 MDI_PI_LOCK(pip);
2202 2193 /*
2203 2194 * No need to explicitly check if the path is disabled.
2204 2195 * Since we are checking for state == ONLINE and the
2205 2196 * same variable is used for DISABLE/ENABLE information.
2206 2197 */
2207 2198 if ((MDI_PI(pip)->pi_state ==
2208 2199 MDI_PATHINFO_STATE_ONLINE) &&
2209 2200 preferred == MDI_PI(pip)->pi_preferred) {
2210 2201 /*
2211 2202 * Return the path in hold state. Caller should
2212 2203 * release the lock by calling mdi_rele_path()
2213 2204 */
2214 2205 MDI_PI_HOLD(pip);
2215 2206 MDI_PI_UNLOCK(pip);
2216 2207 ct->ct_path_last = pip;
2217 2208 *ret_pip = pip;
2218 2209 MDI_CLIENT_UNLOCK(ct);
2219 2210 return (MDI_SUCCESS);
2220 2211 }
2221 2212
2222 2213 /*
2223 2214 * Path is busy.
2224 2215 */
2225 2216 if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) ||
2226 2217 MDI_PI_IS_TRANSIENT(pip))
2227 2218 retry = 1;
2228 2219 /*
2229 2220 * Keep looking for a next available online path
2230 2221 */
2231 2222 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
2232 2223 if (next == NULL) {
2233 2224 next = head;
2234 2225 }
2235 2226 MDI_PI_UNLOCK(pip);
2236 2227 pip = next;
2237 2228 if (start == pip && preferred) {
2238 2229 preferred = 0;
2239 2230 } else if (start == pip && !preferred) {
2240 2231 cont = 0;
2241 2232 }
2242 2233 } while (cont);
2243 2234 break;
2244 2235
2245 2236 case LOAD_BALANCE_LBA:
2246 2237 /*
2247 2238 * Make sure we are looking
2248 2239 * for an online path. Otherwise, if it is for a STANDBY
2249 2240 * path request, it will go through and fetch an ONLINE
2250 2241 * path which is not desirable.
2251 2242 */
2252 2243 if ((ct->ct_lb_args != NULL) &&
2253 2244 (ct->ct_lb_args->region_size) && bp &&
2254 2245 (sb || (flags == MDI_SELECT_ONLINE_PATH))) {
2255 2246 if (i_mdi_lba_lb(ct, ret_pip, bp)
2256 2247 == MDI_SUCCESS) {
2257 2248 MDI_CLIENT_UNLOCK(ct);
2258 2249 return (MDI_SUCCESS);
2259 2250 }
2260 2251 }
2261 2252 /* FALLTHROUGH */
2262 2253 case LOAD_BALANCE_RR:
2263 2254 /*
2264 2255 * Load balancing is Round Robin. Start looking for a online
2265 2256 * mdi_pathinfo node starting from last known selected path
2266 2257 * as the start point. If override flags are specified,
2267 2258 * process accordingly.
2268 2259 * If the search is already in effect(start_pip not null),
2269 2260 * then lets just use the same path preference to continue the
2270 2261 * traversal.
2271 2262 */
2272 2263
2273 2264 if (start_pip != NULL) {
2274 2265 preferred = MDI_PI(start_pip)->pi_preferred;
2275 2266 } else {
2276 2267 preferred = 1;
2277 2268 }
2278 2269
2279 2270 start = sb ? (mdi_pathinfo_t *)ct->ct_path_last : start_pip;
2280 2271 if (start == NULL) {
2281 2272 pip = head;
2282 2273 } else {
2283 2274 pip = (mdi_pathinfo_t *)MDI_PI(start)->pi_client_link;
2284 2275 if (pip == NULL) {
2285 2276 if ( flags & MDI_SELECT_NO_PREFERRED) {
2286 2277 /*
2287 2278 * Return since we hit the end of list
2288 2279 */
2289 2280 MDI_CLIENT_UNLOCK(ct);
2290 2281 return (MDI_NOPATH);
2291 2282 }
2292 2283
2293 2284 if (!sb) {
2294 2285 if (preferred == 0) {
2295 2286 /*
2296 2287 * Looks like we have completed
2297 2288 * the traversal as preferred
2298 2289 * value is 0. Time to bail out.
2299 2290 */
2300 2291 *ret_pip = NULL;
2301 2292 MDI_CLIENT_UNLOCK(ct);
2302 2293 return (MDI_NOPATH);
2303 2294 } else {
2304 2295 /*
2305 2296 * Looks like we reached the
2306 2297 * end of the list. Lets enable
2307 2298 * traversal of non preferred
2308 2299 * paths.
2309 2300 */
2310 2301 preferred = 0;
2311 2302 }
2312 2303 }
2313 2304 pip = head;
2314 2305 }
2315 2306 }
2316 2307 start = pip;
2317 2308 do {
2318 2309 MDI_PI_LOCK(pip);
2319 2310 if (sb) {
2320 2311 cond = ((MDI_PI(pip)->pi_state ==
2321 2312 MDI_PATHINFO_STATE_ONLINE &&
2322 2313 MDI_PI(pip)->pi_preferred ==
2323 2314 preferred) ? 1 : 0);
2324 2315 } else {
2325 2316 if (flags == MDI_SELECT_ONLINE_PATH) {
2326 2317 cond = ((MDI_PI(pip)->pi_state ==
2327 2318 MDI_PATHINFO_STATE_ONLINE &&
2328 2319 MDI_PI(pip)->pi_preferred ==
2329 2320 preferred) ? 1 : 0);
2330 2321 } else if (flags == MDI_SELECT_STANDBY_PATH) {
2331 2322 cond = ((MDI_PI(pip)->pi_state ==
2332 2323 MDI_PATHINFO_STATE_STANDBY &&
2333 2324 MDI_PI(pip)->pi_preferred ==
2334 2325 preferred) ? 1 : 0);
2335 2326 } else if (flags == (MDI_SELECT_ONLINE_PATH |
2336 2327 MDI_SELECT_STANDBY_PATH)) {
2337 2328 cond = (((MDI_PI(pip)->pi_state ==
2338 2329 MDI_PATHINFO_STATE_ONLINE ||
2339 2330 (MDI_PI(pip)->pi_state ==
2340 2331 MDI_PATHINFO_STATE_STANDBY)) &&
2341 2332 MDI_PI(pip)->pi_preferred ==
2342 2333 preferred) ? 1 : 0);
2343 2334 } else if (flags ==
2344 2335 (MDI_SELECT_STANDBY_PATH |
2345 2336 MDI_SELECT_ONLINE_PATH |
2346 2337 MDI_SELECT_USER_DISABLE_PATH)) {
2347 2338 cond = (((MDI_PI(pip)->pi_state ==
2348 2339 MDI_PATHINFO_STATE_ONLINE ||
2349 2340 (MDI_PI(pip)->pi_state ==
2350 2341 MDI_PATHINFO_STATE_STANDBY) ||
2351 2342 (MDI_PI(pip)->pi_state ==
2352 2343 (MDI_PATHINFO_STATE_ONLINE|
2353 2344 MDI_PATHINFO_STATE_USER_DISABLE)) ||
2354 2345 (MDI_PI(pip)->pi_state ==
2355 2346 (MDI_PATHINFO_STATE_STANDBY |
2356 2347 MDI_PATHINFO_STATE_USER_DISABLE)))&&
2357 2348 MDI_PI(pip)->pi_preferred ==
2358 2349 preferred) ? 1 : 0);
2359 2350 } else if (flags ==
2360 2351 (MDI_SELECT_STANDBY_PATH |
2361 2352 MDI_SELECT_ONLINE_PATH |
2362 2353 MDI_SELECT_NO_PREFERRED)) {
2363 2354 cond = (((MDI_PI(pip)->pi_state ==
2364 2355 MDI_PATHINFO_STATE_ONLINE) ||
2365 2356 (MDI_PI(pip)->pi_state ==
2366 2357 MDI_PATHINFO_STATE_STANDBY))
2367 2358 ? 1 : 0);
2368 2359 } else {
2369 2360 cond = 0;
2370 2361 }
2371 2362 }
2372 2363 /*
2373 2364 * No need to explicitly check if the path is disabled.
2374 2365 * Since we are checking for state == ONLINE and the
2375 2366 * same variable is used for DISABLE/ENABLE information.
2376 2367 */
2377 2368 if (cond) {
2378 2369 /*
2379 2370 * Return the path in hold state. Caller should
2380 2371 * release the lock by calling mdi_rele_path()
2381 2372 */
2382 2373 MDI_PI_HOLD(pip);
2383 2374 MDI_PI_UNLOCK(pip);
2384 2375 if (sb)
2385 2376 ct->ct_path_last = pip;
2386 2377 *ret_pip = pip;
2387 2378 MDI_CLIENT_UNLOCK(ct);
2388 2379 return (MDI_SUCCESS);
2389 2380 }
2390 2381 /*
2391 2382 * Path is busy.
2392 2383 */
2393 2384 if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) ||
2394 2385 MDI_PI_IS_TRANSIENT(pip))
2395 2386 retry = 1;
2396 2387
2397 2388 /*
2398 2389 * Keep looking for a next available online path
2399 2390 */
2400 2391 do_again:
2401 2392 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
2402 2393 if (next == NULL) {
2403 2394 if ( flags & MDI_SELECT_NO_PREFERRED) {
2404 2395 /*
2405 2396 * Bail out since we hit the end of list
2406 2397 */
2407 2398 MDI_PI_UNLOCK(pip);
2408 2399 break;
2409 2400 }
2410 2401
2411 2402 if (!sb) {
2412 2403 if (preferred == 1) {
2413 2404 /*
2414 2405 * Looks like we reached the
2415 2406 * end of the list. Lets enable
2416 2407 * traversal of non preferred
2417 2408 * paths.
2418 2409 */
2419 2410 preferred = 0;
2420 2411 next = head;
2421 2412 } else {
2422 2413 /*
2423 2414 * We have done both the passes
2424 2415 * Preferred as well as for
2425 2416 * Non-preferred. Bail out now.
2426 2417 */
2427 2418 cont = 0;
2428 2419 }
2429 2420 } else {
2430 2421 /*
2431 2422 * Standard behavior case.
2432 2423 */
2433 2424 next = head;
2434 2425 }
2435 2426 }
2436 2427 MDI_PI_UNLOCK(pip);
2437 2428 if (cont == 0) {
2438 2429 break;
2439 2430 }
2440 2431 pip = next;
2441 2432
2442 2433 if (!sb) {
2443 2434 /*
2444 2435 * We need to handle the selection of
2445 2436 * non-preferred path in the following
2446 2437 * case:
2447 2438 *
2448 2439 * +------+ +------+ +------+ +-----+
2449 2440 * | A : 1| - | B : 1| - | C : 0| - |NULL |
2450 2441 * +------+ +------+ +------+ +-----+
2451 2442 *
2452 2443 * If we start the search with B, we need to
2453 2444 * skip beyond B to pick C which is non -
2454 2445 * preferred in the second pass. The following
2455 2446 * test, if true, will allow us to skip over
2456 2447 * the 'start'(B in the example) to select
2457 2448 * other non preferred elements.
2458 2449 */
2459 2450 if ((start_pip != NULL) && (start_pip == pip) &&
2460 2451 (MDI_PI(start_pip)->pi_preferred
2461 2452 != preferred)) {
2462 2453 /*
2463 2454 * try again after going past the start
2464 2455 * pip
2465 2456 */
2466 2457 MDI_PI_LOCK(pip);
2467 2458 goto do_again;
2468 2459 }
2469 2460 } else {
2470 2461 /*
2471 2462 * Standard behavior case
2472 2463 */
2473 2464 if (start == pip && preferred) {
2474 2465 /* look for nonpreferred paths */
2475 2466 preferred = 0;
2476 2467 } else if (start == pip && !preferred) {
2477 2468 /*
2478 2469 * Exit condition
2479 2470 */
2480 2471 cont = 0;
2481 2472 }
2482 2473 }
2483 2474 } while (cont);
2484 2475 break;
2485 2476 }
2486 2477
2487 2478 MDI_CLIENT_UNLOCK(ct);
2488 2479 if (retry == 1) {
2489 2480 return (MDI_BUSY);
2490 2481 } else {
2491 2482 return (MDI_NOPATH);
2492 2483 }
2493 2484 }
2494 2485
2495 2486 /*
2496 2487 * For a client, return the next available path to any phci
2497 2488 *
2498 2489 * Note:
2499 2490 * Caller should hold the branch's devinfo node to get a consistent
2500 2491 * snap shot of the mdi_pathinfo nodes.
2501 2492 *
2502 2493 * Please note that even the list is stable the mdi_pathinfo
2503 2494 * node state and properties are volatile. The caller should lock
2504 2495 * and unlock the nodes by calling mdi_pi_lock() and
2505 2496 * mdi_pi_unlock() functions to get a stable properties.
2506 2497 *
2507 2498 * If there is a need to use the nodes beyond the hold of the
2508 2499 * devinfo node period (For ex. I/O), then mdi_pathinfo node
2509 2500 * need to be held against unexpected removal by calling
2510 2501 * mdi_hold_path() and should be released by calling
2511 2502 * mdi_rele_path() on completion.
2512 2503 */
2513 2504 mdi_pathinfo_t *
2514 2505 mdi_get_next_phci_path(dev_info_t *ct_dip, mdi_pathinfo_t *pip)
2515 2506 {
2516 2507 mdi_client_t *ct;
2517 2508
2518 2509 if (!MDI_CLIENT(ct_dip))
2519 2510 return (NULL);
2520 2511
2521 2512 /*
2522 2513 * Walk through client link
2523 2514 */
2524 2515 ct = (mdi_client_t *)DEVI(ct_dip)->devi_mdi_client;
2525 2516 ASSERT(ct != NULL);
2526 2517
2527 2518 if (pip == NULL)
2528 2519 return ((mdi_pathinfo_t *)ct->ct_path_head);
2529 2520
2530 2521 return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link);
2531 2522 }
2532 2523
2533 2524 /*
2534 2525 * For a phci, return the next available path to any client
2535 2526 * Note: ditto mdi_get_next_phci_path()
2536 2527 */
2537 2528 mdi_pathinfo_t *
2538 2529 mdi_get_next_client_path(dev_info_t *ph_dip, mdi_pathinfo_t *pip)
2539 2530 {
2540 2531 mdi_phci_t *ph;
2541 2532
2542 2533 if (!MDI_PHCI(ph_dip))
2543 2534 return (NULL);
2544 2535
2545 2536 /*
2546 2537 * Walk through pHCI link
2547 2538 */
2548 2539 ph = (mdi_phci_t *)DEVI(ph_dip)->devi_mdi_xhci;
2549 2540 ASSERT(ph != NULL);
2550 2541
2551 2542 if (pip == NULL)
2552 2543 return ((mdi_pathinfo_t *)ph->ph_path_head);
2553 2544
2554 2545 return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link);
2555 2546 }
2556 2547
2557 2548 /*
2558 2549 * mdi_hold_path():
2559 2550 * Hold the mdi_pathinfo node against unwanted unexpected free.
2560 2551 * Return Values:
2561 2552 * None
2562 2553 */
2563 2554 void
2564 2555 mdi_hold_path(mdi_pathinfo_t *pip)
2565 2556 {
2566 2557 if (pip) {
2567 2558 MDI_PI_LOCK(pip);
2568 2559 MDI_PI_HOLD(pip);
2569 2560 MDI_PI_UNLOCK(pip);
2570 2561 }
2571 2562 }
2572 2563
2573 2564
2574 2565 /*
2575 2566 * mdi_rele_path():
2576 2567 * Release the mdi_pathinfo node which was selected
2577 2568 * through mdi_select_path() mechanism or manually held by
2578 2569 * calling mdi_hold_path().
2579 2570 * Return Values:
2580 2571 * None
2581 2572 */
2582 2573 void
2583 2574 mdi_rele_path(mdi_pathinfo_t *pip)
2584 2575 {
2585 2576 if (pip) {
2586 2577 MDI_PI_LOCK(pip);
2587 2578 MDI_PI_RELE(pip);
2588 2579 if (MDI_PI(pip)->pi_ref_cnt == 0) {
2589 2580 cv_broadcast(&MDI_PI(pip)->pi_ref_cv);
2590 2581 }
2591 2582 MDI_PI_UNLOCK(pip);
2592 2583 }
2593 2584 }
2594 2585
2595 2586 /*
2596 2587 * mdi_pi_lock():
2597 2588 * Lock the mdi_pathinfo node.
2598 2589 * Note:
2599 2590 * The caller should release the lock by calling mdi_pi_unlock()
2600 2591 */
2601 2592 void
2602 2593 mdi_pi_lock(mdi_pathinfo_t *pip)
2603 2594 {
2604 2595 ASSERT(pip != NULL);
2605 2596 if (pip) {
2606 2597 MDI_PI_LOCK(pip);
2607 2598 }
2608 2599 }
2609 2600
2610 2601
2611 2602 /*
2612 2603 * mdi_pi_unlock():
2613 2604 * Unlock the mdi_pathinfo node.
2614 2605 * Note:
2615 2606 * The mdi_pathinfo node should have been locked with mdi_pi_lock()
2616 2607 */
2617 2608 void
2618 2609 mdi_pi_unlock(mdi_pathinfo_t *pip)
2619 2610 {
2620 2611 ASSERT(pip != NULL);
2621 2612 if (pip) {
2622 2613 MDI_PI_UNLOCK(pip);
2623 2614 }
2624 2615 }
2625 2616
2626 2617 /*
2627 2618 * mdi_pi_find():
2628 2619 * Search the list of mdi_pathinfo nodes attached to the
2629 2620 * pHCI/Client device node whose path address matches "paddr".
2630 2621 * Returns a pointer to the mdi_pathinfo node if a matching node is
2631 2622 * found.
2632 2623 * Return Values:
2633 2624 * mdi_pathinfo node handle
2634 2625 * NULL
2635 2626 * Notes:
2636 2627 * Caller need not hold any locks to call this function.
2637 2628 */
2638 2629 mdi_pathinfo_t *
2639 2630 mdi_pi_find(dev_info_t *pdip, char *caddr, char *paddr)
2640 2631 {
2641 2632 mdi_phci_t *ph;
2642 2633 mdi_vhci_t *vh;
2643 2634 mdi_client_t *ct;
2644 2635 mdi_pathinfo_t *pip = NULL;
2645 2636
2646 2637 MDI_DEBUG(2, (MDI_NOTE, pdip,
2647 2638 "caddr@%s paddr@%s", caddr ? caddr : "", paddr ? paddr : ""));
2648 2639 if ((pdip == NULL) || (paddr == NULL)) {
2649 2640 return (NULL);
2650 2641 }
2651 2642 ph = i_devi_get_phci(pdip);
2652 2643 if (ph == NULL) {
2653 2644 /*
2654 2645 * Invalid pHCI device, Nothing more to do.
2655 2646 */
2656 2647 MDI_DEBUG(2, (MDI_WARN, pdip, "invalid phci"));
2657 2648 return (NULL);
2658 2649 }
2659 2650
2660 2651 vh = ph->ph_vhci;
2661 2652 if (vh == NULL) {
2662 2653 /*
2663 2654 * Invalid vHCI device, Nothing more to do.
2664 2655 */
2665 2656 MDI_DEBUG(2, (MDI_WARN, pdip, "invalid vhci"));
2666 2657 return (NULL);
2667 2658 }
2668 2659
2669 2660 /*
2670 2661 * Look for pathinfo node identified by paddr.
2671 2662 */
2672 2663 if (caddr == NULL) {
2673 2664 /*
2674 2665 * Find a mdi_pathinfo node under pHCI list for a matching
2675 2666 * unit address.
2676 2667 */
2677 2668 MDI_PHCI_LOCK(ph);
2678 2669 if (MDI_PHCI_IS_OFFLINE(ph)) {
2679 2670 MDI_DEBUG(2, (MDI_WARN, pdip,
2680 2671 "offline phci %p", (void *)ph));
2681 2672 MDI_PHCI_UNLOCK(ph);
2682 2673 return (NULL);
2683 2674 }
2684 2675 pip = (mdi_pathinfo_t *)ph->ph_path_head;
2685 2676
2686 2677 while (pip != NULL) {
2687 2678 if (strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) {
2688 2679 break;
2689 2680 }
2690 2681 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
2691 2682 }
2692 2683 MDI_PHCI_UNLOCK(ph);
2693 2684 MDI_DEBUG(2, (MDI_NOTE, pdip,
2694 2685 "found %s %p", mdi_pi_spathname(pip), (void *)pip));
2695 2686 return (pip);
2696 2687 }
2697 2688
2698 2689 /*
2699 2690 * XXX - Is the rest of the code in this function really necessary?
2700 2691 * The consumers of mdi_pi_find() can search for the desired pathinfo
2701 2692 * node by calling mdi_pi_find(pdip, NULL, paddr). Irrespective of
2702 2693 * whether the search is based on the pathinfo nodes attached to
2703 2694 * the pHCI or the client node, the result will be the same.
2704 2695 */
2705 2696
2706 2697 /*
2707 2698 * Find the client device corresponding to 'caddr'
2708 2699 */
2709 2700 MDI_VHCI_CLIENT_LOCK(vh);
2710 2701
2711 2702 /*
2712 2703 * XXX - Passing NULL to the following function works as long as the
2713 2704 * the client addresses (caddr) are unique per vhci basis.
2714 2705 */
2715 2706 ct = i_mdi_client_find(vh, NULL, caddr);
2716 2707 if (ct == NULL) {
2717 2708 /*
2718 2709 * Client not found, Obviously mdi_pathinfo node has not been
2719 2710 * created yet.
2720 2711 */
2721 2712 MDI_VHCI_CLIENT_UNLOCK(vh);
2722 2713 MDI_DEBUG(2, (MDI_NOTE, pdip,
2723 2714 "client not found for caddr @%s", caddr ? caddr : ""));
2724 2715 return (NULL);
2725 2716 }
2726 2717
2727 2718 /*
2728 2719 * Hold the client lock and look for a mdi_pathinfo node with matching
2729 2720 * pHCI and paddr
2730 2721 */
2731 2722 MDI_CLIENT_LOCK(ct);
2732 2723
2733 2724 /*
2734 2725 * Release the global mutex as it is no more needed. Note: We always
2735 2726 * respect the locking order while acquiring.
2736 2727 */
2737 2728 MDI_VHCI_CLIENT_UNLOCK(vh);
2738 2729
2739 2730 pip = (mdi_pathinfo_t *)ct->ct_path_head;
2740 2731 while (pip != NULL) {
2741 2732 /*
2742 2733 * Compare the unit address
2743 2734 */
2744 2735 if ((MDI_PI(pip)->pi_phci == ph) &&
2745 2736 strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) {
2746 2737 break;
2747 2738 }
2748 2739 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
2749 2740 }
2750 2741 MDI_CLIENT_UNLOCK(ct);
2751 2742 MDI_DEBUG(2, (MDI_NOTE, pdip,
2752 2743 "found: %s %p", mdi_pi_spathname(pip), (void *)pip));
2753 2744 return (pip);
2754 2745 }
2755 2746
2756 2747 /*
2757 2748 * mdi_pi_alloc():
2758 2749 * Allocate and initialize a new instance of a mdi_pathinfo node.
2759 2750 * The mdi_pathinfo node returned by this function identifies a
2760 2751 * unique device path is capable of having properties attached
2761 2752 * and passed to mdi_pi_online() to fully attach and online the
2762 2753 * path and client device node.
2763 2754 * The mdi_pathinfo node returned by this function must be
2764 2755 * destroyed using mdi_pi_free() if the path is no longer
2765 2756 * operational or if the caller fails to attach a client device
2766 2757 * node when calling mdi_pi_online(). The framework will not free
2767 2758 * the resources allocated.
2768 2759 * This function can be called from both interrupt and kernel
2769 2760 * contexts. DDI_NOSLEEP flag should be used while calling
2770 2761 * from interrupt contexts.
2771 2762 * Return Values:
2772 2763 * MDI_SUCCESS
2773 2764 * MDI_FAILURE
2774 2765 * MDI_NOMEM
2775 2766 */
2776 2767 /*ARGSUSED*/
2777 2768 int
2778 2769 mdi_pi_alloc_compatible(dev_info_t *pdip, char *cname, char *caddr, char *paddr,
2779 2770 char **compatible, int ncompatible, int flags, mdi_pathinfo_t **ret_pip)
2780 2771 {
2781 2772 mdi_vhci_t *vh;
2782 2773 mdi_phci_t *ph;
2783 2774 mdi_client_t *ct;
2784 2775 mdi_pathinfo_t *pip = NULL;
2785 2776 dev_info_t *cdip;
2786 2777 int rv = MDI_NOMEM;
2787 2778 int path_allocated = 0;
2788 2779
2789 2780 MDI_DEBUG(2, (MDI_NOTE, pdip,
2790 2781 "cname %s: caddr@%s paddr@%s",
2791 2782 cname ? cname : "", caddr ? caddr : "", paddr ? paddr : ""));
2792 2783
2793 2784 if (pdip == NULL || cname == NULL || caddr == NULL || paddr == NULL ||
2794 2785 ret_pip == NULL) {
2795 2786 /* Nothing more to do */
2796 2787 return (MDI_FAILURE);
2797 2788 }
2798 2789
2799 2790 *ret_pip = NULL;
2800 2791
2801 2792 /* No allocations on detaching pHCI */
2802 2793 if (DEVI_IS_DETACHING(pdip)) {
2803 2794 /* Invalid pHCI device, return failure */
2804 2795 MDI_DEBUG(1, (MDI_WARN, pdip,
2805 2796 "!detaching pHCI=%p", (void *)pdip));
2806 2797 return (MDI_FAILURE);
2807 2798 }
2808 2799
2809 2800 ph = i_devi_get_phci(pdip);
2810 2801 ASSERT(ph != NULL);
2811 2802 if (ph == NULL) {
2812 2803 /* Invalid pHCI device, return failure */
2813 2804 MDI_DEBUG(1, (MDI_WARN, pdip,
2814 2805 "!invalid pHCI=%p", (void *)pdip));
2815 2806 return (MDI_FAILURE);
2816 2807 }
2817 2808
2818 2809 MDI_PHCI_LOCK(ph);
2819 2810 vh = ph->ph_vhci;
2820 2811 if (vh == NULL) {
2821 2812 /* Invalid vHCI device, return failure */
2822 2813 MDI_DEBUG(1, (MDI_WARN, pdip,
2823 2814 "!invalid vHCI=%p", (void *)pdip));
2824 2815 MDI_PHCI_UNLOCK(ph);
2825 2816 return (MDI_FAILURE);
2826 2817 }
2827 2818
2828 2819 if (MDI_PHCI_IS_READY(ph) == 0) {
2829 2820 /*
2830 2821 * Do not allow new node creation when pHCI is in
2831 2822 * offline/suspended states
2832 2823 */
2833 2824 MDI_DEBUG(1, (MDI_WARN, pdip,
2834 2825 "pHCI=%p is not ready", (void *)ph));
2835 2826 MDI_PHCI_UNLOCK(ph);
2836 2827 return (MDI_BUSY);
2837 2828 }
2838 2829 MDI_PHCI_UNSTABLE(ph);
2839 2830 MDI_PHCI_UNLOCK(ph);
2840 2831
2841 2832 /* look for a matching client, create one if not found */
2842 2833 MDI_VHCI_CLIENT_LOCK(vh);
2843 2834 ct = i_mdi_client_find(vh, cname, caddr);
2844 2835 if (ct == NULL) {
2845 2836 ct = i_mdi_client_alloc(vh, cname, caddr);
2846 2837 ASSERT(ct != NULL);
2847 2838 }
2848 2839
2849 2840 if (ct->ct_dip == NULL) {
2850 2841 /*
2851 2842 * Allocate a devinfo node
2852 2843 */
2853 2844 ct->ct_dip = i_mdi_devinfo_create(vh, cname, caddr,
2854 2845 compatible, ncompatible);
2855 2846 if (ct->ct_dip == NULL) {
2856 2847 (void) i_mdi_client_free(vh, ct);
2857 2848 goto fail;
2858 2849 }
2859 2850 }
2860 2851 cdip = ct->ct_dip;
2861 2852
2862 2853 DEVI(cdip)->devi_mdi_component |= MDI_COMPONENT_CLIENT;
2863 2854 DEVI(cdip)->devi_mdi_client = (caddr_t)ct;
2864 2855
2865 2856 MDI_CLIENT_LOCK(ct);
2866 2857 pip = (mdi_pathinfo_t *)ct->ct_path_head;
2867 2858 while (pip != NULL) {
2868 2859 /*
2869 2860 * Compare the unit address
2870 2861 */
2871 2862 if ((MDI_PI(pip)->pi_phci == ph) &&
2872 2863 strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) {
2873 2864 break;
2874 2865 }
2875 2866 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
2876 2867 }
2877 2868 MDI_CLIENT_UNLOCK(ct);
2878 2869
2879 2870 if (pip == NULL) {
2880 2871 /*
2881 2872 * This is a new path for this client device. Allocate and
2882 2873 * initialize a new pathinfo node
2883 2874 */
2884 2875 pip = i_mdi_pi_alloc(ph, paddr, ct);
2885 2876 ASSERT(pip != NULL);
2886 2877 path_allocated = 1;
2887 2878 }
2888 2879 rv = MDI_SUCCESS;
2889 2880
2890 2881 fail:
2891 2882 /*
2892 2883 * Release the global mutex.
2893 2884 */
2894 2885 MDI_VHCI_CLIENT_UNLOCK(vh);
2895 2886
2896 2887 /*
2897 2888 * Mark the pHCI as stable
2898 2889 */
2899 2890 MDI_PHCI_LOCK(ph);
2900 2891 MDI_PHCI_STABLE(ph);
2901 2892 MDI_PHCI_UNLOCK(ph);
2902 2893 *ret_pip = pip;
2903 2894
2904 2895 MDI_DEBUG(2, (MDI_NOTE, pdip,
2905 2896 "alloc %s %p", mdi_pi_spathname(pip), (void *)pip));
2906 2897
2907 2898 if (path_allocated)
2908 2899 vhcache_pi_add(vh->vh_config, MDI_PI(pip));
2909 2900
2910 2901 return (rv);
2911 2902 }
2912 2903
2913 2904 /*ARGSUSED*/
2914 2905 int
2915 2906 mdi_pi_alloc(dev_info_t *pdip, char *cname, char *caddr, char *paddr,
2916 2907 int flags, mdi_pathinfo_t **ret_pip)
2917 2908 {
2918 2909 return (mdi_pi_alloc_compatible(pdip, cname, caddr, paddr, NULL, 0,
2919 2910 flags, ret_pip));
2920 2911 }
2921 2912
2922 2913 /*
2923 2914 * i_mdi_pi_alloc():
2924 2915 * Allocate a mdi_pathinfo node and add to the pHCI path list
2925 2916 * Return Values:
2926 2917 * mdi_pathinfo
2927 2918 */
2928 2919 /*ARGSUSED*/
2929 2920 static mdi_pathinfo_t *
2930 2921 i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct)
2931 2922 {
2932 2923 mdi_pathinfo_t *pip;
2933 2924 int ct_circular;
2934 2925 int ph_circular;
2935 2926 static char path[MAXPATHLEN]; /* mdi_pathmap_mutex protects */
2936 2927 char *path_persistent;
2937 2928 int path_instance;
2938 2929 mod_hash_val_t hv;
2939 2930
2940 2931 ASSERT(MDI_VHCI_CLIENT_LOCKED(ph->ph_vhci));
2941 2932
2942 2933 pip = kmem_zalloc(sizeof (struct mdi_pathinfo), KM_SLEEP);
2943 2934 mutex_init(&MDI_PI(pip)->pi_mutex, NULL, MUTEX_DEFAULT, NULL);
2944 2935 MDI_PI(pip)->pi_state = MDI_PATHINFO_STATE_INIT |
2945 2936 MDI_PATHINFO_STATE_TRANSIENT;
2946 2937
2947 2938 if (MDI_PHCI_IS_USER_DISABLED(ph))
2948 2939 MDI_PI_SET_USER_DISABLE(pip);
2949 2940
2950 2941 if (MDI_PHCI_IS_DRV_DISABLED_TRANSIENT(ph))
2951 2942 MDI_PI_SET_DRV_DISABLE_TRANS(pip);
2952 2943
2953 2944 if (MDI_PHCI_IS_DRV_DISABLED(ph))
2954 2945 MDI_PI_SET_DRV_DISABLE(pip);
2955 2946
2956 2947 MDI_PI(pip)->pi_old_state = MDI_PATHINFO_STATE_INIT;
2957 2948 cv_init(&MDI_PI(pip)->pi_state_cv, NULL, CV_DEFAULT, NULL);
2958 2949 MDI_PI(pip)->pi_client = ct;
2959 2950 MDI_PI(pip)->pi_phci = ph;
2960 2951 MDI_PI(pip)->pi_addr = kmem_alloc(strlen(paddr) + 1, KM_SLEEP);
2961 2952 (void) strcpy(MDI_PI(pip)->pi_addr, paddr);
2962 2953
2963 2954 /*
2964 2955 * We form the "path" to the pathinfo node, and see if we have
2965 2956 * already allocated a 'path_instance' for that "path". If so,
2966 2957 * we use the already allocated 'path_instance'. If not, we
2967 2958 * allocate a new 'path_instance' and associate it with a copy of
2968 2959 * the "path" string (which is never freed). The association
2969 2960 * between a 'path_instance' this "path" string persists until
2970 2961 * reboot.
2971 2962 */
2972 2963 mutex_enter(&mdi_pathmap_mutex);
2973 2964 (void) ddi_pathname(ph->ph_dip, path);
2974 2965 (void) sprintf(path + strlen(path), "/%s@%s",
2975 2966 mdi_pi_get_node_name(pip), mdi_pi_get_addr(pip));
2976 2967 if (mod_hash_find(mdi_pathmap_bypath, (mod_hash_key_t)path, &hv) == 0) {
2977 2968 path_instance = (uint_t)(intptr_t)hv;
2978 2969 } else {
2979 2970 /* allocate a new 'path_instance' and persistent "path" */
2980 2971 path_instance = mdi_pathmap_instance++;
2981 2972 path_persistent = i_ddi_strdup(path, KM_SLEEP);
2982 2973 (void) mod_hash_insert(mdi_pathmap_bypath,
2983 2974 (mod_hash_key_t)path_persistent,
2984 2975 (mod_hash_val_t)(intptr_t)path_instance);
2985 2976 (void) mod_hash_insert(mdi_pathmap_byinstance,
2986 2977 (mod_hash_key_t)(intptr_t)path_instance,
2987 2978 (mod_hash_val_t)path_persistent);
2988 2979
2989 2980 /* create shortpath name */
2990 2981 (void) snprintf(path, sizeof(path), "%s%d/%s@%s",
2991 2982 ddi_driver_name(ph->ph_dip), ddi_get_instance(ph->ph_dip),
2992 2983 mdi_pi_get_node_name(pip), mdi_pi_get_addr(pip));
2993 2984 path_persistent = i_ddi_strdup(path, KM_SLEEP);
2994 2985 (void) mod_hash_insert(mdi_pathmap_sbyinstance,
2995 2986 (mod_hash_key_t)(intptr_t)path_instance,
2996 2987 (mod_hash_val_t)path_persistent);
2997 2988 }
2998 2989 mutex_exit(&mdi_pathmap_mutex);
2999 2990 MDI_PI(pip)->pi_path_instance = path_instance;
3000 2991
3001 2992 (void) nvlist_alloc(&MDI_PI(pip)->pi_prop, NV_UNIQUE_NAME, KM_SLEEP);
3002 2993 ASSERT(MDI_PI(pip)->pi_prop != NULL);
3003 2994 MDI_PI(pip)->pi_pprivate = NULL;
3004 2995 MDI_PI(pip)->pi_cprivate = NULL;
3005 2996 MDI_PI(pip)->pi_vprivate = NULL;
3006 2997 MDI_PI(pip)->pi_client_link = NULL;
3007 2998 MDI_PI(pip)->pi_phci_link = NULL;
3008 2999 MDI_PI(pip)->pi_ref_cnt = 0;
3009 3000 MDI_PI(pip)->pi_kstats = NULL;
3010 3001 MDI_PI(pip)->pi_preferred = 1;
3011 3002 cv_init(&MDI_PI(pip)->pi_ref_cv, NULL, CV_DEFAULT, NULL);
3012 3003
3013 3004 /*
3014 3005 * Lock both dev_info nodes against changes in parallel.
3015 3006 *
3016 3007 * The ndi_devi_enter(Client), is atypical since the client is a leaf.
3017 3008 * This atypical operation is done to synchronize pathinfo nodes
3018 3009 * during devinfo snapshot (see di_register_pip) by 'pretending' that
3019 3010 * the pathinfo nodes are children of the Client.
3020 3011 */
3021 3012 ndi_devi_enter(ct->ct_dip, &ct_circular);
3022 3013 ndi_devi_enter(ph->ph_dip, &ph_circular);
3023 3014
3024 3015 i_mdi_phci_add_path(ph, pip);
3025 3016 i_mdi_client_add_path(ct, pip);
3026 3017
3027 3018 ndi_devi_exit(ph->ph_dip, ph_circular);
3028 3019 ndi_devi_exit(ct->ct_dip, ct_circular);
3029 3020
3030 3021 return (pip);
3031 3022 }
3032 3023
3033 3024 /*
3034 3025 * mdi_pi_pathname_by_instance():
3035 3026 * Lookup of "path" by 'path_instance'. Return "path".
3036 3027 * NOTE: returned "path" remains valid forever (until reboot).
3037 3028 */
3038 3029 char *
3039 3030 mdi_pi_pathname_by_instance(int path_instance)
3040 3031 {
3041 3032 char *path;
3042 3033 mod_hash_val_t hv;
3043 3034
3044 3035 /* mdi_pathmap lookup of "path" by 'path_instance' */
3045 3036 mutex_enter(&mdi_pathmap_mutex);
3046 3037 if (mod_hash_find(mdi_pathmap_byinstance,
3047 3038 (mod_hash_key_t)(intptr_t)path_instance, &hv) == 0)
3048 3039 path = (char *)hv;
3049 3040 else
3050 3041 path = NULL;
3051 3042 mutex_exit(&mdi_pathmap_mutex);
3052 3043 return (path);
3053 3044 }
3054 3045
3055 3046 /*
3056 3047 * mdi_pi_spathname_by_instance():
3057 3048 * Lookup of "shortpath" by 'path_instance'. Return "shortpath".
3058 3049 * NOTE: returned "shortpath" remains valid forever (until reboot).
3059 3050 */
3060 3051 char *
3061 3052 mdi_pi_spathname_by_instance(int path_instance)
3062 3053 {
3063 3054 char *path;
3064 3055 mod_hash_val_t hv;
3065 3056
3066 3057 /* mdi_pathmap lookup of "path" by 'path_instance' */
3067 3058 mutex_enter(&mdi_pathmap_mutex);
3068 3059 if (mod_hash_find(mdi_pathmap_sbyinstance,
3069 3060 (mod_hash_key_t)(intptr_t)path_instance, &hv) == 0)
3070 3061 path = (char *)hv;
3071 3062 else
3072 3063 path = NULL;
3073 3064 mutex_exit(&mdi_pathmap_mutex);
3074 3065 return (path);
3075 3066 }
3076 3067
3077 3068
3078 3069 /*
3079 3070 * i_mdi_phci_add_path():
3080 3071 * Add a mdi_pathinfo node to pHCI list.
3081 3072 * Notes:
3082 3073 * Caller should per-pHCI mutex
3083 3074 */
3084 3075 static void
3085 3076 i_mdi_phci_add_path(mdi_phci_t *ph, mdi_pathinfo_t *pip)
3086 3077 {
3087 3078 ASSERT(DEVI_BUSY_OWNED(ph->ph_dip));
3088 3079
3089 3080 MDI_PHCI_LOCK(ph);
3090 3081 if (ph->ph_path_head == NULL) {
3091 3082 ph->ph_path_head = pip;
3092 3083 } else {
3093 3084 MDI_PI(ph->ph_path_tail)->pi_phci_link = MDI_PI(pip);
3094 3085 }
3095 3086 ph->ph_path_tail = pip;
3096 3087 ph->ph_path_count++;
3097 3088 MDI_PHCI_UNLOCK(ph);
3098 3089 }
3099 3090
3100 3091 /*
3101 3092 * i_mdi_client_add_path():
3102 3093 * Add mdi_pathinfo node to client list
3103 3094 */
3104 3095 static void
3105 3096 i_mdi_client_add_path(mdi_client_t *ct, mdi_pathinfo_t *pip)
3106 3097 {
3107 3098 ASSERT(DEVI_BUSY_OWNED(ct->ct_dip));
3108 3099
3109 3100 MDI_CLIENT_LOCK(ct);
3110 3101 if (ct->ct_path_head == NULL) {
3111 3102 ct->ct_path_head = pip;
3112 3103 } else {
3113 3104 MDI_PI(ct->ct_path_tail)->pi_client_link = MDI_PI(pip);
3114 3105 }
3115 3106 ct->ct_path_tail = pip;
3116 3107 ct->ct_path_count++;
3117 3108 MDI_CLIENT_UNLOCK(ct);
3118 3109 }
3119 3110
3120 3111 /*
3121 3112 * mdi_pi_free():
3122 3113 * Free the mdi_pathinfo node and also client device node if this
3123 3114 * is the last path to the device
3124 3115 * Return Values:
3125 3116 * MDI_SUCCESS
3126 3117 * MDI_FAILURE
3127 3118 * MDI_BUSY
3128 3119 */
3129 3120 /*ARGSUSED*/
3130 3121 int
3131 3122 mdi_pi_free(mdi_pathinfo_t *pip, int flags)
3132 3123 {
3133 3124 int rv;
3134 3125 mdi_vhci_t *vh;
3135 3126 mdi_phci_t *ph;
3136 3127 mdi_client_t *ct;
3137 3128 int (*f)();
3138 3129 int client_held = 0;
3139 3130
3140 3131 MDI_PI_LOCK(pip);
3141 3132 ph = MDI_PI(pip)->pi_phci;
3142 3133 ASSERT(ph != NULL);
3143 3134 if (ph == NULL) {
3144 3135 /*
3145 3136 * Invalid pHCI device, return failure
3146 3137 */
3147 3138 MDI_DEBUG(1, (MDI_WARN, NULL,
3148 3139 "!invalid pHCI: pip %s %p",
3149 3140 mdi_pi_spathname(pip), (void *)pip));
3150 3141 MDI_PI_UNLOCK(pip);
3151 3142 return (MDI_FAILURE);
3152 3143 }
3153 3144
3154 3145 vh = ph->ph_vhci;
3155 3146 ASSERT(vh != NULL);
3156 3147 if (vh == NULL) {
3157 3148 /* Invalid pHCI device, return failure */
3158 3149 MDI_DEBUG(1, (MDI_WARN, ph->ph_dip,
3159 3150 "!invalid vHCI: pip %s %p",
3160 3151 mdi_pi_spathname(pip), (void *)pip));
3161 3152 MDI_PI_UNLOCK(pip);
3162 3153 return (MDI_FAILURE);
3163 3154 }
3164 3155
3165 3156 ct = MDI_PI(pip)->pi_client;
3166 3157 ASSERT(ct != NULL);
3167 3158 if (ct == NULL) {
3168 3159 /*
3169 3160 * Invalid Client device, return failure
3170 3161 */
3171 3162 MDI_DEBUG(1, (MDI_WARN, ph->ph_dip,
3172 3163 "!invalid client: pip %s %p",
3173 3164 mdi_pi_spathname(pip), (void *)pip));
3174 3165 MDI_PI_UNLOCK(pip);
3175 3166 return (MDI_FAILURE);
3176 3167 }
3177 3168
3178 3169 /*
3179 3170 * Check to see for busy condition. A mdi_pathinfo can only be freed
3180 3171 * if the node state is either offline or init and the reference count
3181 3172 * is zero.
3182 3173 */
3183 3174 if (!(MDI_PI_IS_OFFLINE(pip) || MDI_PI_IS_INIT(pip) ||
3184 3175 MDI_PI_IS_INITING(pip))) {
3185 3176 /*
3186 3177 * Node is busy
3187 3178 */
3188 3179 MDI_DEBUG(1, (MDI_WARN, ct->ct_dip,
3189 3180 "!busy: pip %s %p", mdi_pi_spathname(pip), (void *)pip));
3190 3181 MDI_PI_UNLOCK(pip);
3191 3182 return (MDI_BUSY);
3192 3183 }
3193 3184
3194 3185 while (MDI_PI(pip)->pi_ref_cnt != 0) {
3195 3186 /*
3196 3187 * Give a chance for pending I/Os to complete.
3197 3188 */
3198 3189 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip,
3199 3190 "!%d cmds still pending on path: %s %p",
3200 3191 MDI_PI(pip)->pi_ref_cnt,
3201 3192 mdi_pi_spathname(pip), (void *)pip));
3202 3193 if (cv_reltimedwait(&MDI_PI(pip)->pi_ref_cv,
3203 3194 &MDI_PI(pip)->pi_mutex, drv_usectohz(60 * 1000000),
3204 3195 TR_CLOCK_TICK) == -1) {
3205 3196 /*
3206 3197 * The timeout time reached without ref_cnt being zero
3207 3198 * being signaled.
3208 3199 */
3209 3200 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip,
3210 3201 "!Timeout reached on path %s %p without the cond",
3211 3202 mdi_pi_spathname(pip), (void *)pip));
3212 3203 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip,
3213 3204 "!%d cmds still pending on path %s %p",
3214 3205 MDI_PI(pip)->pi_ref_cnt,
3215 3206 mdi_pi_spathname(pip), (void *)pip));
3216 3207 MDI_PI_UNLOCK(pip);
3217 3208 return (MDI_BUSY);
3218 3209 }
3219 3210 }
3220 3211 if (MDI_PI(pip)->pi_pm_held) {
3221 3212 client_held = 1;
3222 3213 }
3223 3214 MDI_PI_UNLOCK(pip);
3224 3215
3225 3216 vhcache_pi_remove(vh->vh_config, MDI_PI(pip));
3226 3217
3227 3218 MDI_CLIENT_LOCK(ct);
3228 3219
3229 3220 /* Prevent further failovers till MDI_VHCI_CLIENT_LOCK is held */
3230 3221 MDI_CLIENT_SET_PATH_FREE_IN_PROGRESS(ct);
3231 3222
3232 3223 /*
3233 3224 * Wait till failover is complete before removing this node.
3234 3225 */
3235 3226 while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct))
3236 3227 cv_wait(&ct->ct_failover_cv, &ct->ct_mutex);
3237 3228
3238 3229 MDI_CLIENT_UNLOCK(ct);
3239 3230 MDI_VHCI_CLIENT_LOCK(vh);
3240 3231 MDI_CLIENT_LOCK(ct);
3241 3232 MDI_CLIENT_CLEAR_PATH_FREE_IN_PROGRESS(ct);
3242 3233
3243 3234 if (!MDI_PI_IS_INITING(pip)) {
3244 3235 f = vh->vh_ops->vo_pi_uninit;
3245 3236 if (f != NULL) {
3246 3237 rv = (*f)(vh->vh_dip, pip, 0);
3247 3238 }
3248 3239 } else
3249 3240 rv = MDI_SUCCESS;
3250 3241
3251 3242 /*
3252 3243 * If vo_pi_uninit() completed successfully.
3253 3244 */
3254 3245 if (rv == MDI_SUCCESS) {
3255 3246 if (client_held) {
3256 3247 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
3257 3248 "i_mdi_pm_rele_client\n"));
3258 3249 i_mdi_pm_rele_client(ct, 1);
3259 3250 }
3260 3251 i_mdi_pi_free(ph, pip, ct);
3261 3252 if (ct->ct_path_count == 0) {
3262 3253 /*
3263 3254 * Client lost its last path.
3264 3255 * Clean up the client device
3265 3256 */
3266 3257 MDI_CLIENT_UNLOCK(ct);
3267 3258 (void) i_mdi_client_free(ct->ct_vhci, ct);
3268 3259 MDI_VHCI_CLIENT_UNLOCK(vh);
3269 3260 return (rv);
3270 3261 }
3271 3262 }
3272 3263 MDI_CLIENT_UNLOCK(ct);
3273 3264 MDI_VHCI_CLIENT_UNLOCK(vh);
3274 3265
3275 3266 if (rv == MDI_FAILURE)
3276 3267 vhcache_pi_add(vh->vh_config, MDI_PI(pip));
3277 3268
3278 3269 return (rv);
3279 3270 }
3280 3271
3281 3272 /*
3282 3273 * i_mdi_pi_free():
3283 3274 * Free the mdi_pathinfo node
3284 3275 */
3285 3276 static void
3286 3277 i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct)
3287 3278 {
3288 3279 int ct_circular;
3289 3280 int ph_circular;
3290 3281
3291 3282 ASSERT(MDI_CLIENT_LOCKED(ct));
3292 3283
3293 3284 /*
3294 3285 * remove any per-path kstats
3295 3286 */
3296 3287 i_mdi_pi_kstat_destroy(pip);
3297 3288
3298 3289 /* See comments in i_mdi_pi_alloc() */
3299 3290 ndi_devi_enter(ct->ct_dip, &ct_circular);
3300 3291 ndi_devi_enter(ph->ph_dip, &ph_circular);
3301 3292
3302 3293 i_mdi_client_remove_path(ct, pip);
3303 3294 i_mdi_phci_remove_path(ph, pip);
3304 3295
3305 3296 ndi_devi_exit(ph->ph_dip, ph_circular);
3306 3297 ndi_devi_exit(ct->ct_dip, ct_circular);
3307 3298
3308 3299 mutex_destroy(&MDI_PI(pip)->pi_mutex);
3309 3300 cv_destroy(&MDI_PI(pip)->pi_state_cv);
3310 3301 cv_destroy(&MDI_PI(pip)->pi_ref_cv);
3311 3302 if (MDI_PI(pip)->pi_addr) {
3312 3303 kmem_free(MDI_PI(pip)->pi_addr,
3313 3304 strlen(MDI_PI(pip)->pi_addr) + 1);
3314 3305 MDI_PI(pip)->pi_addr = NULL;
3315 3306 }
3316 3307
3317 3308 if (MDI_PI(pip)->pi_prop) {
3318 3309 (void) nvlist_free(MDI_PI(pip)->pi_prop);
3319 3310 MDI_PI(pip)->pi_prop = NULL;
3320 3311 }
3321 3312 kmem_free(pip, sizeof (struct mdi_pathinfo));
3322 3313 }
3323 3314
3324 3315
3325 3316 /*
3326 3317 * i_mdi_phci_remove_path():
3327 3318 * Remove a mdi_pathinfo node from pHCI list.
3328 3319 * Notes:
3329 3320 * Caller should hold per-pHCI mutex
3330 3321 */
3331 3322 static void
3332 3323 i_mdi_phci_remove_path(mdi_phci_t *ph, mdi_pathinfo_t *pip)
3333 3324 {
3334 3325 mdi_pathinfo_t *prev = NULL;
3335 3326 mdi_pathinfo_t *path = NULL;
3336 3327
3337 3328 ASSERT(DEVI_BUSY_OWNED(ph->ph_dip));
3338 3329
3339 3330 MDI_PHCI_LOCK(ph);
3340 3331 path = ph->ph_path_head;
3341 3332 while (path != NULL) {
3342 3333 if (path == pip) {
3343 3334 break;
3344 3335 }
3345 3336 prev = path;
3346 3337 path = (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link;
3347 3338 }
3348 3339
3349 3340 if (path) {
3350 3341 ph->ph_path_count--;
3351 3342 if (prev) {
3352 3343 MDI_PI(prev)->pi_phci_link = MDI_PI(path)->pi_phci_link;
3353 3344 } else {
3354 3345 ph->ph_path_head =
3355 3346 (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link;
3356 3347 }
3357 3348 if (ph->ph_path_tail == path) {
3358 3349 ph->ph_path_tail = prev;
3359 3350 }
3360 3351 }
3361 3352
3362 3353 /*
3363 3354 * Clear the pHCI link
3364 3355 */
3365 3356 MDI_PI(pip)->pi_phci_link = NULL;
3366 3357 MDI_PI(pip)->pi_phci = NULL;
3367 3358 MDI_PHCI_UNLOCK(ph);
3368 3359 }
3369 3360
3370 3361 /*
3371 3362 * i_mdi_client_remove_path():
3372 3363 * Remove a mdi_pathinfo node from client path list.
3373 3364 */
3374 3365 static void
3375 3366 i_mdi_client_remove_path(mdi_client_t *ct, mdi_pathinfo_t *pip)
3376 3367 {
3377 3368 mdi_pathinfo_t *prev = NULL;
3378 3369 mdi_pathinfo_t *path;
3379 3370
3380 3371 ASSERT(DEVI_BUSY_OWNED(ct->ct_dip));
3381 3372
3382 3373 ASSERT(MDI_CLIENT_LOCKED(ct));
3383 3374 path = ct->ct_path_head;
3384 3375 while (path != NULL) {
3385 3376 if (path == pip) {
3386 3377 break;
3387 3378 }
3388 3379 prev = path;
3389 3380 path = (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link;
3390 3381 }
3391 3382
3392 3383 if (path) {
3393 3384 ct->ct_path_count--;
3394 3385 if (prev) {
3395 3386 MDI_PI(prev)->pi_client_link =
3396 3387 MDI_PI(path)->pi_client_link;
3397 3388 } else {
3398 3389 ct->ct_path_head =
3399 3390 (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link;
3400 3391 }
3401 3392 if (ct->ct_path_tail == path) {
3402 3393 ct->ct_path_tail = prev;
3403 3394 }
3404 3395 if (ct->ct_path_last == path) {
3405 3396 ct->ct_path_last = ct->ct_path_head;
3406 3397 }
3407 3398 }
3408 3399 MDI_PI(pip)->pi_client_link = NULL;
3409 3400 MDI_PI(pip)->pi_client = NULL;
3410 3401 }
3411 3402
3412 3403 /*
3413 3404 * i_mdi_pi_state_change():
3414 3405 * online a mdi_pathinfo node
3415 3406 *
3416 3407 * Return Values:
3417 3408 * MDI_SUCCESS
3418 3409 * MDI_FAILURE
3419 3410 */
3420 3411 /*ARGSUSED*/
3421 3412 static int
3422 3413 i_mdi_pi_state_change(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state, int flag)
3423 3414 {
3424 3415 int rv = MDI_SUCCESS;
3425 3416 mdi_vhci_t *vh;
3426 3417 mdi_phci_t *ph;
3427 3418 mdi_client_t *ct;
3428 3419 int (*f)();
3429 3420 dev_info_t *cdip;
3430 3421
3431 3422 MDI_PI_LOCK(pip);
3432 3423
3433 3424 ph = MDI_PI(pip)->pi_phci;
3434 3425 ASSERT(ph);
3435 3426 if (ph == NULL) {
3436 3427 /*
3437 3428 * Invalid pHCI device, fail the request
3438 3429 */
3439 3430 MDI_PI_UNLOCK(pip);
3440 3431 MDI_DEBUG(1, (MDI_WARN, NULL,
3441 3432 "!invalid phci: pip %s %p",
3442 3433 mdi_pi_spathname(pip), (void *)pip));
3443 3434 return (MDI_FAILURE);
3444 3435 }
3445 3436
3446 3437 vh = ph->ph_vhci;
3447 3438 ASSERT(vh);
3448 3439 if (vh == NULL) {
3449 3440 /*
3450 3441 * Invalid vHCI device, fail the request
3451 3442 */
3452 3443 MDI_PI_UNLOCK(pip);
3453 3444 MDI_DEBUG(1, (MDI_WARN, ph->ph_dip,
3454 3445 "!invalid vhci: pip %s %p",
3455 3446 mdi_pi_spathname(pip), (void *)pip));
3456 3447 return (MDI_FAILURE);
3457 3448 }
3458 3449
3459 3450 ct = MDI_PI(pip)->pi_client;
3460 3451 ASSERT(ct != NULL);
3461 3452 if (ct == NULL) {
3462 3453 /*
3463 3454 * Invalid client device, fail the request
3464 3455 */
3465 3456 MDI_PI_UNLOCK(pip);
3466 3457 MDI_DEBUG(1, (MDI_WARN, ph->ph_dip,
3467 3458 "!invalid client: pip %s %p",
3468 3459 mdi_pi_spathname(pip), (void *)pip));
3469 3460 return (MDI_FAILURE);
3470 3461 }
3471 3462
3472 3463 /*
3473 3464 * If this path has not been initialized yet, Callback vHCI driver's
3474 3465 * pathinfo node initialize entry point
3475 3466 */
3476 3467
3477 3468 if (MDI_PI_IS_INITING(pip)) {
3478 3469 MDI_PI_UNLOCK(pip);
3479 3470 f = vh->vh_ops->vo_pi_init;
3480 3471 if (f != NULL) {
3481 3472 rv = (*f)(vh->vh_dip, pip, 0);
3482 3473 if (rv != MDI_SUCCESS) {
3483 3474 MDI_DEBUG(1, (MDI_WARN, ct->ct_dip,
3484 3475 "!vo_pi_init failed: vHCI %p, pip %s %p",
3485 3476 (void *)vh, mdi_pi_spathname(pip),
3486 3477 (void *)pip));
3487 3478 return (MDI_FAILURE);
3488 3479 }
3489 3480 }
3490 3481 MDI_PI_LOCK(pip);
3491 3482 MDI_PI_CLEAR_TRANSIENT(pip);
3492 3483 }
3493 3484
3494 3485 /*
3495 3486 * Do not allow state transition when pHCI is in offline/suspended
3496 3487 * states
3497 3488 */
3498 3489 i_mdi_phci_lock(ph, pip);
3499 3490 if (MDI_PHCI_IS_READY(ph) == 0) {
3500 3491 MDI_DEBUG(1, (MDI_WARN, ct->ct_dip,
3501 3492 "!pHCI not ready, pHCI=%p", (void *)ph));
3502 3493 MDI_PI_UNLOCK(pip);
3503 3494 i_mdi_phci_unlock(ph);
3504 3495 return (MDI_BUSY);
3505 3496 }
3506 3497 MDI_PHCI_UNSTABLE(ph);
3507 3498 i_mdi_phci_unlock(ph);
3508 3499
3509 3500 /*
3510 3501 * Check if mdi_pathinfo state is in transient state.
3511 3502 * If yes, offlining is in progress and wait till transient state is
3512 3503 * cleared.
3513 3504 */
3514 3505 if (MDI_PI_IS_TRANSIENT(pip)) {
3515 3506 while (MDI_PI_IS_TRANSIENT(pip)) {
3516 3507 cv_wait(&MDI_PI(pip)->pi_state_cv,
3517 3508 &MDI_PI(pip)->pi_mutex);
3518 3509 }
3519 3510 }
3520 3511
3521 3512 /*
3522 3513 * Grab the client lock in reverse order sequence and release the
3523 3514 * mdi_pathinfo mutex.
3524 3515 */
3525 3516 i_mdi_client_lock(ct, pip);
3526 3517 MDI_PI_UNLOCK(pip);
3527 3518
3528 3519 /*
3529 3520 * Wait till failover state is cleared
3530 3521 */
3531 3522 while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct))
3532 3523 cv_wait(&ct->ct_failover_cv, &ct->ct_mutex);
3533 3524
3534 3525 /*
3535 3526 * Mark the mdi_pathinfo node state as transient
3536 3527 */
3537 3528 MDI_PI_LOCK(pip);
3538 3529 switch (state) {
3539 3530 case MDI_PATHINFO_STATE_ONLINE:
3540 3531 MDI_PI_SET_ONLINING(pip);
3541 3532 break;
3542 3533
3543 3534 case MDI_PATHINFO_STATE_STANDBY:
3544 3535 MDI_PI_SET_STANDBYING(pip);
3545 3536 break;
3546 3537
3547 3538 case MDI_PATHINFO_STATE_FAULT:
3548 3539 /*
3549 3540 * Mark the pathinfo state as FAULTED
3550 3541 */
3551 3542 MDI_PI_SET_FAULTING(pip);
3552 3543 MDI_PI_ERRSTAT(pip, MDI_PI_HARDERR);
3553 3544 break;
3554 3545
3555 3546 case MDI_PATHINFO_STATE_OFFLINE:
3556 3547 /*
3557 3548 * ndi_devi_offline() cannot hold pip or ct locks.
3558 3549 */
3559 3550 MDI_PI_UNLOCK(pip);
3560 3551
3561 3552 /*
3562 3553 * If this is a user initiated path online->offline operation
3563 3554 * who's success would transition a client from DEGRADED to
3564 3555 * FAILED then only proceed if we can offline the client first.
3565 3556 */
3566 3557 cdip = ct->ct_dip;
3567 3558 if ((flag & NDI_USER_REQ) &&
3568 3559 MDI_PI_IS_ONLINE(pip) &&
3569 3560 (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED)) {
3570 3561 i_mdi_client_unlock(ct);
3571 3562 rv = ndi_devi_offline(cdip, NDI_DEVFS_CLEAN);
3572 3563 if (rv != NDI_SUCCESS) {
3573 3564 /*
3574 3565 * Convert to MDI error code
3575 3566 */
3576 3567 switch (rv) {
3577 3568 case NDI_BUSY:
3578 3569 rv = MDI_BUSY;
3579 3570 break;
3580 3571 default:
3581 3572 rv = MDI_FAILURE;
3582 3573 break;
3583 3574 }
3584 3575 goto state_change_exit;
3585 3576 } else {
3586 3577 i_mdi_client_lock(ct, NULL);
3587 3578 }
3588 3579 }
3589 3580 /*
3590 3581 * Mark the mdi_pathinfo node state as transient
3591 3582 */
3592 3583 MDI_PI_LOCK(pip);
3593 3584 MDI_PI_SET_OFFLINING(pip);
3594 3585 break;
3595 3586 }
3596 3587 MDI_PI_UNLOCK(pip);
3597 3588 MDI_CLIENT_UNSTABLE(ct);
3598 3589 i_mdi_client_unlock(ct);
3599 3590
3600 3591 f = vh->vh_ops->vo_pi_state_change;
3601 3592 if (f != NULL)
3602 3593 rv = (*f)(vh->vh_dip, pip, state, 0, flag);
3603 3594
3604 3595 MDI_CLIENT_LOCK(ct);
3605 3596 MDI_PI_LOCK(pip);
3606 3597 if (rv == MDI_NOT_SUPPORTED) {
3607 3598 MDI_CLIENT_SET_DEV_NOT_SUPPORTED(ct);
3608 3599 }
3609 3600 if (rv != MDI_SUCCESS) {
3610 3601 MDI_DEBUG(2, (MDI_WARN, ct->ct_dip,
3611 3602 "vo_pi_state_change failed: rv %x", rv));
3612 3603 }
3613 3604 if (MDI_PI_IS_TRANSIENT(pip)) {
3614 3605 if (rv == MDI_SUCCESS) {
3615 3606 MDI_PI_CLEAR_TRANSIENT(pip);
3616 3607 } else {
3617 3608 MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip);
3618 3609 }
3619 3610 }
3620 3611
3621 3612 /*
3622 3613 * Wake anyone waiting for this mdi_pathinfo node
3623 3614 */
3624 3615 cv_broadcast(&MDI_PI(pip)->pi_state_cv);
3625 3616 MDI_PI_UNLOCK(pip);
3626 3617
3627 3618 /*
3628 3619 * Mark the client device as stable
3629 3620 */
3630 3621 MDI_CLIENT_STABLE(ct);
3631 3622 if (rv == MDI_SUCCESS) {
3632 3623 if (ct->ct_unstable == 0) {
3633 3624 cdip = ct->ct_dip;
3634 3625
3635 3626 /*
3636 3627 * Onlining the mdi_pathinfo node will impact the
3637 3628 * client state Update the client and dev_info node
3638 3629 * state accordingly
3639 3630 */
3640 3631 rv = NDI_SUCCESS;
3641 3632 i_mdi_client_update_state(ct);
3642 3633 switch (MDI_CLIENT_STATE(ct)) {
3643 3634 case MDI_CLIENT_STATE_OPTIMAL:
3644 3635 case MDI_CLIENT_STATE_DEGRADED:
3645 3636 if (cdip && !i_ddi_devi_attached(cdip) &&
3646 3637 ((state == MDI_PATHINFO_STATE_ONLINE) ||
3647 3638 (state == MDI_PATHINFO_STATE_STANDBY))) {
3648 3639
3649 3640 /*
3650 3641 * Must do ndi_devi_online() through
3651 3642 * hotplug thread for deferred
3652 3643 * attach mechanism to work
3653 3644 */
3654 3645 MDI_CLIENT_UNLOCK(ct);
3655 3646 rv = ndi_devi_online(cdip, 0);
3656 3647 MDI_CLIENT_LOCK(ct);
3657 3648 if ((rv != NDI_SUCCESS) &&
3658 3649 (MDI_CLIENT_STATE(ct) ==
3659 3650 MDI_CLIENT_STATE_DEGRADED)) {
3660 3651 MDI_DEBUG(1, (MDI_WARN, cdip,
3661 3652 "!ndi_devi_online failed "
3662 3653 "error %x", rv));
↓ open down ↓ |
3614 lines elided |
↑ open up ↑ |
3663 3654 }
3664 3655 rv = NDI_SUCCESS;
3665 3656 }
3666 3657 break;
3667 3658
3668 3659 case MDI_CLIENT_STATE_FAILED:
3669 3660 /*
3670 3661 * This is the last path case for
3671 3662 * non-user initiated events.
3672 3663 */
3673 - if (((flag & NDI_USER_REQ) == 0) &&
3674 - cdip && (i_ddi_node_state(cdip) >=
3675 - DS_INITIALIZED)) {
3676 - MDI_CLIENT_UNLOCK(ct);
3677 - rv = ndi_devi_offline(cdip,
3678 - NDI_DEVFS_CLEAN);
3679 - MDI_CLIENT_LOCK(ct);
3664 + if ((flag & NDI_USER_REQ) ||
3665 + cdip == NULL || i_ddi_node_state(cdip) <
3666 + DS_INITIALIZED)
3667 + break;
3680 3668
3681 - if (rv != NDI_SUCCESS) {
3682 - /*
3683 - * ndi_devi_offline failed.
3684 - * Reset client flags to
3685 - * online as the path could not
3686 - * be offlined.
3687 - */
3688 - MDI_DEBUG(1, (MDI_WARN, cdip,
3689 - "!ndi_devi_offline failed: "
3690 - "error %x", rv));
3691 - MDI_CLIENT_SET_ONLINE(ct);
3692 - }
3669 + MDI_CLIENT_UNLOCK(ct);
3670 + rv = ndi_devi_offline(cdip, NDI_DEVFS_CLEAN);
3671 + MDI_CLIENT_LOCK(ct);
3672 +
3673 + if (rv != NDI_SUCCESS) {
3674 + /*
3675 + * Reset client flags to online as the
3676 + * path could not be offlined.
3677 + */
3678 + MDI_DEBUG(1, (MDI_WARN, cdip,
3679 + "!ndi_devi_offline failed: %d",
3680 + rv));
3681 + MDI_CLIENT_SET_ONLINE(ct);
3693 3682 }
3694 3683 break;
3695 3684 }
3696 3685 /*
3697 3686 * Convert to MDI error code
3698 3687 */
3699 3688 switch (rv) {
3700 3689 case NDI_SUCCESS:
3701 3690 MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct);
3702 3691 i_mdi_report_path_state(ct, pip);
3703 3692 rv = MDI_SUCCESS;
3704 3693 break;
3705 3694 case NDI_BUSY:
3706 3695 rv = MDI_BUSY;
3707 3696 break;
3708 3697 default:
3709 3698 rv = MDI_FAILURE;
3710 3699 break;
3711 3700 }
3712 3701 }
3713 3702 }
3714 3703 MDI_CLIENT_UNLOCK(ct);
3715 3704
3716 3705 state_change_exit:
3717 3706 /*
3718 3707 * Mark the pHCI as stable again.
3719 3708 */
3720 3709 MDI_PHCI_LOCK(ph);
3721 3710 MDI_PHCI_STABLE(ph);
3722 3711 MDI_PHCI_UNLOCK(ph);
3723 3712 return (rv);
3724 3713 }
3725 3714
3726 3715 /*
3727 3716 * mdi_pi_online():
3728 3717 * Place the path_info node in the online state. The path is
3729 3718 * now available to be selected by mdi_select_path() for
3730 3719 * transporting I/O requests to client devices.
3731 3720 * Return Values:
3732 3721 * MDI_SUCCESS
3733 3722 * MDI_FAILURE
3734 3723 */
3735 3724 int
3736 3725 mdi_pi_online(mdi_pathinfo_t *pip, int flags)
3737 3726 {
3738 3727 mdi_client_t *ct = MDI_PI(pip)->pi_client;
3739 3728 int client_held = 0;
3740 3729 int rv;
3741 3730
3742 3731 ASSERT(ct != NULL);
3743 3732 rv = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_ONLINE, flags);
3744 3733 if (rv != MDI_SUCCESS)
3745 3734 return (rv);
3746 3735
3747 3736 MDI_PI_LOCK(pip);
3748 3737 if (MDI_PI(pip)->pi_pm_held == 0) {
3749 3738 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
3750 3739 "i_mdi_pm_hold_pip %p", (void *)pip));
3751 3740 i_mdi_pm_hold_pip(pip);
3752 3741 client_held = 1;
3753 3742 }
3754 3743 MDI_PI_UNLOCK(pip);
3755 3744
3756 3745 if (client_held) {
3757 3746 MDI_CLIENT_LOCK(ct);
3758 3747 if (ct->ct_power_cnt == 0) {
3759 3748 rv = i_mdi_power_all_phci(ct);
3760 3749 }
3761 3750
3762 3751 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
3763 3752 "i_mdi_pm_hold_client %p", (void *)ct));
3764 3753 i_mdi_pm_hold_client(ct, 1);
3765 3754 MDI_CLIENT_UNLOCK(ct);
3766 3755 }
3767 3756
3768 3757 return (rv);
3769 3758 }
3770 3759
3771 3760 /*
3772 3761 * mdi_pi_standby():
3773 3762 * Place the mdi_pathinfo node in standby state
3774 3763 *
3775 3764 * Return Values:
3776 3765 * MDI_SUCCESS
3777 3766 * MDI_FAILURE
3778 3767 */
3779 3768 int
3780 3769 mdi_pi_standby(mdi_pathinfo_t *pip, int flags)
3781 3770 {
3782 3771 return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_STANDBY, flags));
3783 3772 }
3784 3773
3785 3774 /*
3786 3775 * mdi_pi_fault():
3787 3776 * Place the mdi_pathinfo node in fault'ed state
3788 3777 * Return Values:
3789 3778 * MDI_SUCCESS
3790 3779 * MDI_FAILURE
3791 3780 */
3792 3781 int
3793 3782 mdi_pi_fault(mdi_pathinfo_t *pip, int flags)
3794 3783 {
3795 3784 return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_FAULT, flags));
3796 3785 }
3797 3786
3798 3787 /*
3799 3788 * mdi_pi_offline():
3800 3789 * Offline a mdi_pathinfo node.
3801 3790 * Return Values:
3802 3791 * MDI_SUCCESS
3803 3792 * MDI_FAILURE
3804 3793 */
3805 3794 int
3806 3795 mdi_pi_offline(mdi_pathinfo_t *pip, int flags)
3807 3796 {
3808 3797 int ret, client_held = 0;
3809 3798 mdi_client_t *ct;
3810 3799
3811 3800 /*
3812 3801 * Original code overloaded NDI_DEVI_REMOVE to this interface, and
3813 3802 * used it to mean "user initiated operation" (i.e. devctl). Callers
3814 3803 * should now just use NDI_USER_REQ.
3815 3804 */
3816 3805 if (flags & NDI_DEVI_REMOVE) {
3817 3806 flags &= ~NDI_DEVI_REMOVE;
3818 3807 flags |= NDI_USER_REQ;
3819 3808 }
3820 3809
3821 3810 ret = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_OFFLINE, flags);
3822 3811
3823 3812 if (ret == MDI_SUCCESS) {
3824 3813 MDI_PI_LOCK(pip);
3825 3814 if (MDI_PI(pip)->pi_pm_held) {
3826 3815 client_held = 1;
3827 3816 }
3828 3817 MDI_PI_UNLOCK(pip);
3829 3818
3830 3819 if (client_held) {
3831 3820 ct = MDI_PI(pip)->pi_client;
3832 3821 MDI_CLIENT_LOCK(ct);
3833 3822 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
3834 3823 "i_mdi_pm_rele_client\n"));
3835 3824 i_mdi_pm_rele_client(ct, 1);
3836 3825 MDI_CLIENT_UNLOCK(ct);
3837 3826 }
3838 3827 }
3839 3828
3840 3829 return (ret);
3841 3830 }
3842 3831
3843 3832 /*
3844 3833 * i_mdi_pi_offline():
3845 3834 * Offline a mdi_pathinfo node and call the vHCI driver's callback
3846 3835 */
3847 3836 static int
3848 3837 i_mdi_pi_offline(mdi_pathinfo_t *pip, int flags)
3849 3838 {
3850 3839 dev_info_t *vdip = NULL;
3851 3840 mdi_vhci_t *vh = NULL;
3852 3841 mdi_client_t *ct = NULL;
3853 3842 int (*f)();
3854 3843 int rv;
3855 3844
3856 3845 MDI_PI_LOCK(pip);
3857 3846 ct = MDI_PI(pip)->pi_client;
3858 3847 ASSERT(ct != NULL);
3859 3848
3860 3849 while (MDI_PI(pip)->pi_ref_cnt != 0) {
3861 3850 /*
3862 3851 * Give a chance for pending I/Os to complete.
3863 3852 */
3864 3853 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip,
3865 3854 "!%d cmds still pending on path %s %p",
3866 3855 MDI_PI(pip)->pi_ref_cnt, mdi_pi_spathname(pip),
3867 3856 (void *)pip));
3868 3857 if (cv_reltimedwait(&MDI_PI(pip)->pi_ref_cv,
3869 3858 &MDI_PI(pip)->pi_mutex, drv_usectohz(60 * 1000000),
3870 3859 TR_CLOCK_TICK) == -1) {
3871 3860 /*
3872 3861 * The timeout time reached without ref_cnt being zero
3873 3862 * being signaled.
3874 3863 */
3875 3864 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip,
3876 3865 "!Timeout reached on path %s %p without the cond",
3877 3866 mdi_pi_spathname(pip), (void *)pip));
3878 3867 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip,
3879 3868 "!%d cmds still pending on path %s %p",
3880 3869 MDI_PI(pip)->pi_ref_cnt,
3881 3870 mdi_pi_spathname(pip), (void *)pip));
3882 3871 }
3883 3872 }
3884 3873 vh = ct->ct_vhci;
3885 3874 vdip = vh->vh_dip;
3886 3875
3887 3876 /*
3888 3877 * Notify vHCI that has registered this event
3889 3878 */
3890 3879 ASSERT(vh->vh_ops);
3891 3880 f = vh->vh_ops->vo_pi_state_change;
3892 3881
3893 3882 if (f != NULL) {
3894 3883 MDI_PI_UNLOCK(pip);
3895 3884 if ((rv = (*f)(vdip, pip, MDI_PATHINFO_STATE_OFFLINE, 0,
3896 3885 flags)) != MDI_SUCCESS) {
3897 3886 MDI_DEBUG(1, (MDI_WARN, ct->ct_dip,
3898 3887 "!vo_path_offline failed: vdip %s%d %p: path %s %p",
3899 3888 ddi_driver_name(vdip), ddi_get_instance(vdip),
3900 3889 (void *)vdip, mdi_pi_spathname(pip), (void *)pip));
3901 3890 }
3902 3891 MDI_PI_LOCK(pip);
3903 3892 }
3904 3893
3905 3894 /*
3906 3895 * Set the mdi_pathinfo node state and clear the transient condition
3907 3896 */
3908 3897 MDI_PI_SET_OFFLINE(pip);
3909 3898 cv_broadcast(&MDI_PI(pip)->pi_state_cv);
3910 3899 MDI_PI_UNLOCK(pip);
3911 3900
3912 3901 MDI_CLIENT_LOCK(ct);
3913 3902 if (rv == MDI_SUCCESS) {
3914 3903 if (ct->ct_unstable == 0) {
3915 3904 dev_info_t *cdip = ct->ct_dip;
3916 3905
3917 3906 /*
3918 3907 * Onlining the mdi_pathinfo node will impact the
3919 3908 * client state Update the client and dev_info node
3920 3909 * state accordingly
3921 3910 */
3922 3911 i_mdi_client_update_state(ct);
3923 3912 rv = NDI_SUCCESS;
3924 3913 if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) {
3925 3914 if (cdip &&
3926 3915 (i_ddi_node_state(cdip) >=
3927 3916 DS_INITIALIZED)) {
3928 3917 MDI_CLIENT_UNLOCK(ct);
3929 3918 rv = ndi_devi_offline(cdip,
3930 3919 NDI_DEVFS_CLEAN);
3931 3920 MDI_CLIENT_LOCK(ct);
3932 3921 if (rv != NDI_SUCCESS) {
3933 3922 /*
3934 3923 * ndi_devi_offline failed.
3935 3924 * Reset client flags to
3936 3925 * online.
3937 3926 */
3938 3927 MDI_DEBUG(4, (MDI_WARN, cdip,
3939 3928 "ndi_devi_offline failed: "
3940 3929 "error %x", rv));
3941 3930 MDI_CLIENT_SET_ONLINE(ct);
3942 3931 }
3943 3932 }
3944 3933 }
3945 3934 /*
3946 3935 * Convert to MDI error code
3947 3936 */
3948 3937 switch (rv) {
3949 3938 case NDI_SUCCESS:
3950 3939 rv = MDI_SUCCESS;
3951 3940 break;
3952 3941 case NDI_BUSY:
3953 3942 rv = MDI_BUSY;
3954 3943 break;
3955 3944 default:
3956 3945 rv = MDI_FAILURE;
3957 3946 break;
3958 3947 }
3959 3948 }
3960 3949 MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct);
3961 3950 i_mdi_report_path_state(ct, pip);
3962 3951 }
3963 3952
3964 3953 MDI_CLIENT_UNLOCK(ct);
3965 3954
3966 3955 /*
3967 3956 * Change in the mdi_pathinfo node state will impact the client state
3968 3957 */
3969 3958 MDI_DEBUG(2, (MDI_NOTE, ct->ct_dip,
3970 3959 "ct = %p pip = %p", (void *)ct, (void *)pip));
3971 3960 return (rv);
3972 3961 }
3973 3962
3974 3963 /*
3975 3964 * i_mdi_pi_online():
3976 3965 * Online a mdi_pathinfo node and call the vHCI driver's callback
3977 3966 */
3978 3967 static int
3979 3968 i_mdi_pi_online(mdi_pathinfo_t *pip, int flags)
3980 3969 {
3981 3970 mdi_vhci_t *vh = NULL;
3982 3971 mdi_client_t *ct = NULL;
3983 3972 mdi_phci_t *ph;
3984 3973 int (*f)();
3985 3974 int rv;
3986 3975
3987 3976 MDI_PI_LOCK(pip);
3988 3977 ph = MDI_PI(pip)->pi_phci;
3989 3978 vh = ph->ph_vhci;
3990 3979 ct = MDI_PI(pip)->pi_client;
3991 3980 MDI_PI_SET_ONLINING(pip)
3992 3981 MDI_PI_UNLOCK(pip);
3993 3982 f = vh->vh_ops->vo_pi_state_change;
3994 3983 if (f != NULL)
3995 3984 rv = (*f)(vh->vh_dip, pip, MDI_PATHINFO_STATE_ONLINE, 0,
3996 3985 flags);
3997 3986 MDI_CLIENT_LOCK(ct);
3998 3987 MDI_PI_LOCK(pip);
3999 3988 cv_broadcast(&MDI_PI(pip)->pi_state_cv);
4000 3989 MDI_PI_UNLOCK(pip);
4001 3990 if (rv == MDI_SUCCESS) {
4002 3991 dev_info_t *cdip = ct->ct_dip;
4003 3992
4004 3993 rv = MDI_SUCCESS;
4005 3994 i_mdi_client_update_state(ct);
4006 3995 if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL ||
4007 3996 MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) {
4008 3997 if (cdip && !i_ddi_devi_attached(cdip)) {
4009 3998 MDI_CLIENT_UNLOCK(ct);
4010 3999 rv = ndi_devi_online(cdip, 0);
4011 4000 MDI_CLIENT_LOCK(ct);
4012 4001 if ((rv != NDI_SUCCESS) &&
4013 4002 (MDI_CLIENT_STATE(ct) ==
4014 4003 MDI_CLIENT_STATE_DEGRADED)) {
4015 4004 MDI_CLIENT_SET_OFFLINE(ct);
4016 4005 }
4017 4006 if (rv != NDI_SUCCESS) {
4018 4007 /* Reset the path state */
4019 4008 MDI_PI_LOCK(pip);
4020 4009 MDI_PI(pip)->pi_state =
4021 4010 MDI_PI_OLD_STATE(pip);
4022 4011 MDI_PI_UNLOCK(pip);
4023 4012 }
4024 4013 }
4025 4014 }
4026 4015 switch (rv) {
4027 4016 case NDI_SUCCESS:
4028 4017 MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct);
4029 4018 i_mdi_report_path_state(ct, pip);
4030 4019 rv = MDI_SUCCESS;
4031 4020 break;
4032 4021 case NDI_BUSY:
4033 4022 rv = MDI_BUSY;
4034 4023 break;
4035 4024 default:
4036 4025 rv = MDI_FAILURE;
4037 4026 break;
4038 4027 }
4039 4028 } else {
4040 4029 /* Reset the path state */
4041 4030 MDI_PI_LOCK(pip);
4042 4031 MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip);
4043 4032 MDI_PI_UNLOCK(pip);
4044 4033 }
4045 4034 MDI_CLIENT_UNLOCK(ct);
4046 4035 return (rv);
4047 4036 }
4048 4037
4049 4038 /*
4050 4039 * mdi_pi_get_node_name():
4051 4040 * Get the name associated with a mdi_pathinfo node.
4052 4041 * Since pathinfo nodes are not directly named, we
4053 4042 * return the node_name of the client.
4054 4043 *
4055 4044 * Return Values:
4056 4045 * char *
4057 4046 */
4058 4047 char *
4059 4048 mdi_pi_get_node_name(mdi_pathinfo_t *pip)
4060 4049 {
4061 4050 mdi_client_t *ct;
4062 4051
4063 4052 if (pip == NULL)
4064 4053 return (NULL);
4065 4054 ct = MDI_PI(pip)->pi_client;
4066 4055 if ((ct == NULL) || (ct->ct_dip == NULL))
4067 4056 return (NULL);
4068 4057 return (ddi_node_name(ct->ct_dip));
4069 4058 }
4070 4059
4071 4060 /*
4072 4061 * mdi_pi_get_addr():
4073 4062 * Get the unit address associated with a mdi_pathinfo node
4074 4063 *
4075 4064 * Return Values:
4076 4065 * char *
4077 4066 */
4078 4067 char *
4079 4068 mdi_pi_get_addr(mdi_pathinfo_t *pip)
4080 4069 {
4081 4070 if (pip == NULL)
4082 4071 return (NULL);
4083 4072
4084 4073 return (MDI_PI(pip)->pi_addr);
4085 4074 }
4086 4075
4087 4076 /*
4088 4077 * mdi_pi_get_path_instance():
4089 4078 * Get the 'path_instance' of a mdi_pathinfo node
4090 4079 *
4091 4080 * Return Values:
4092 4081 * path_instance
4093 4082 */
4094 4083 int
4095 4084 mdi_pi_get_path_instance(mdi_pathinfo_t *pip)
4096 4085 {
4097 4086 if (pip == NULL)
4098 4087 return (0);
4099 4088
4100 4089 return (MDI_PI(pip)->pi_path_instance);
4101 4090 }
4102 4091
4103 4092 /*
4104 4093 * mdi_pi_pathname():
4105 4094 * Return pointer to path to pathinfo node.
4106 4095 */
4107 4096 char *
4108 4097 mdi_pi_pathname(mdi_pathinfo_t *pip)
4109 4098 {
4110 4099 if (pip == NULL)
4111 4100 return (NULL);
4112 4101 return (mdi_pi_pathname_by_instance(mdi_pi_get_path_instance(pip)));
4113 4102 }
4114 4103
4115 4104 /*
4116 4105 * mdi_pi_spathname():
4117 4106 * Return pointer to shortpath to pathinfo node. Used for debug
4118 4107 * messages, so return "" instead of NULL when unknown.
4119 4108 */
4120 4109 char *
4121 4110 mdi_pi_spathname(mdi_pathinfo_t *pip)
4122 4111 {
4123 4112 char *spath = "";
4124 4113
4125 4114 if (pip) {
4126 4115 spath = mdi_pi_spathname_by_instance(
4127 4116 mdi_pi_get_path_instance(pip));
4128 4117 if (spath == NULL)
4129 4118 spath = "";
4130 4119 }
4131 4120 return (spath);
4132 4121 }
4133 4122
4134 4123 char *
4135 4124 mdi_pi_pathname_obp(mdi_pathinfo_t *pip, char *path)
4136 4125 {
4137 4126 char *obp_path = NULL;
4138 4127 if ((pip == NULL) || (path == NULL))
4139 4128 return (NULL);
4140 4129
4141 4130 if (mdi_prop_lookup_string(pip, "obp-path", &obp_path) == MDI_SUCCESS) {
4142 4131 (void) strcpy(path, obp_path);
4143 4132 (void) mdi_prop_free(obp_path);
4144 4133 } else {
4145 4134 path = NULL;
4146 4135 }
4147 4136 return (path);
4148 4137 }
4149 4138
4150 4139 int
4151 4140 mdi_pi_pathname_obp_set(mdi_pathinfo_t *pip, char *component)
4152 4141 {
4153 4142 dev_info_t *pdip;
4154 4143 char *obp_path = NULL;
4155 4144 int rc = MDI_FAILURE;
4156 4145
4157 4146 if (pip == NULL)
4158 4147 return (MDI_FAILURE);
4159 4148
4160 4149 pdip = mdi_pi_get_phci(pip);
4161 4150 if (pdip == NULL)
4162 4151 return (MDI_FAILURE);
4163 4152
4164 4153 obp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
4165 4154
4166 4155 if (ddi_pathname_obp(pdip, obp_path) == NULL) {
4167 4156 (void) ddi_pathname(pdip, obp_path);
4168 4157 }
4169 4158
4170 4159 if (component) {
4171 4160 (void) strncat(obp_path, "/", MAXPATHLEN);
4172 4161 (void) strncat(obp_path, component, MAXPATHLEN);
4173 4162 }
4174 4163 rc = mdi_prop_update_string(pip, "obp-path", obp_path);
4175 4164
4176 4165 if (obp_path)
4177 4166 kmem_free(obp_path, MAXPATHLEN);
4178 4167 return (rc);
4179 4168 }
4180 4169
4181 4170 /*
4182 4171 * mdi_pi_get_client():
4183 4172 * Get the client devinfo associated with a mdi_pathinfo node
4184 4173 *
4185 4174 * Return Values:
4186 4175 * Handle to client device dev_info node
4187 4176 */
4188 4177 dev_info_t *
4189 4178 mdi_pi_get_client(mdi_pathinfo_t *pip)
4190 4179 {
4191 4180 dev_info_t *dip = NULL;
4192 4181 if (pip) {
4193 4182 dip = MDI_PI(pip)->pi_client->ct_dip;
4194 4183 }
4195 4184 return (dip);
4196 4185 }
4197 4186
4198 4187 /*
4199 4188 * mdi_pi_get_phci():
4200 4189 * Get the pHCI devinfo associated with the mdi_pathinfo node
4201 4190 * Return Values:
4202 4191 * Handle to dev_info node
4203 4192 */
4204 4193 dev_info_t *
4205 4194 mdi_pi_get_phci(mdi_pathinfo_t *pip)
4206 4195 {
4207 4196 dev_info_t *dip = NULL;
4208 4197 mdi_phci_t *ph;
4209 4198
4210 4199 if (pip) {
4211 4200 ph = MDI_PI(pip)->pi_phci;
4212 4201 if (ph)
4213 4202 dip = ph->ph_dip;
4214 4203 }
4215 4204 return (dip);
4216 4205 }
4217 4206
4218 4207 /*
4219 4208 * mdi_pi_get_client_private():
4220 4209 * Get the client private information associated with the
4221 4210 * mdi_pathinfo node
4222 4211 */
4223 4212 void *
4224 4213 mdi_pi_get_client_private(mdi_pathinfo_t *pip)
4225 4214 {
4226 4215 void *cprivate = NULL;
4227 4216 if (pip) {
4228 4217 cprivate = MDI_PI(pip)->pi_cprivate;
4229 4218 }
4230 4219 return (cprivate);
4231 4220 }
4232 4221
4233 4222 /*
4234 4223 * mdi_pi_set_client_private():
4235 4224 * Set the client private information in the mdi_pathinfo node
4236 4225 */
4237 4226 void
4238 4227 mdi_pi_set_client_private(mdi_pathinfo_t *pip, void *priv)
4239 4228 {
4240 4229 if (pip) {
4241 4230 MDI_PI(pip)->pi_cprivate = priv;
4242 4231 }
4243 4232 }
4244 4233
4245 4234 /*
4246 4235 * mdi_pi_get_phci_private():
4247 4236 * Get the pHCI private information associated with the
4248 4237 * mdi_pathinfo node
4249 4238 */
4250 4239 caddr_t
4251 4240 mdi_pi_get_phci_private(mdi_pathinfo_t *pip)
4252 4241 {
4253 4242 caddr_t pprivate = NULL;
4254 4243
4255 4244 if (pip) {
4256 4245 pprivate = MDI_PI(pip)->pi_pprivate;
4257 4246 }
4258 4247 return (pprivate);
4259 4248 }
4260 4249
4261 4250 /*
4262 4251 * mdi_pi_set_phci_private():
4263 4252 * Set the pHCI private information in the mdi_pathinfo node
4264 4253 */
4265 4254 void
4266 4255 mdi_pi_set_phci_private(mdi_pathinfo_t *pip, caddr_t priv)
4267 4256 {
4268 4257 if (pip) {
4269 4258 MDI_PI(pip)->pi_pprivate = priv;
4270 4259 }
4271 4260 }
4272 4261
4273 4262 /*
4274 4263 * mdi_pi_get_state():
4275 4264 * Get the mdi_pathinfo node state. Transient states are internal
4276 4265 * and not provided to the users
4277 4266 */
4278 4267 mdi_pathinfo_state_t
4279 4268 mdi_pi_get_state(mdi_pathinfo_t *pip)
4280 4269 {
4281 4270 mdi_pathinfo_state_t state = MDI_PATHINFO_STATE_INIT;
4282 4271
4283 4272 if (pip) {
4284 4273 if (MDI_PI_IS_TRANSIENT(pip)) {
4285 4274 /*
4286 4275 * mdi_pathinfo is in state transition. Return the
4287 4276 * last good state.
4288 4277 */
4289 4278 state = MDI_PI_OLD_STATE(pip);
4290 4279 } else {
4291 4280 state = MDI_PI_STATE(pip);
4292 4281 }
4293 4282 }
4294 4283 return (state);
4295 4284 }
4296 4285
4297 4286 /*
4298 4287 * mdi_pi_get_flags():
4299 4288 * Get the mdi_pathinfo node flags.
4300 4289 */
4301 4290 uint_t
4302 4291 mdi_pi_get_flags(mdi_pathinfo_t *pip)
4303 4292 {
4304 4293 return (pip ? MDI_PI(pip)->pi_flags : 0);
4305 4294 }
4306 4295
4307 4296 /*
4308 4297 * Note that the following function needs to be the new interface for
4309 4298 * mdi_pi_get_state when mpxio gets integrated to ON.
4310 4299 */
4311 4300 int
4312 4301 mdi_pi_get_state2(mdi_pathinfo_t *pip, mdi_pathinfo_state_t *state,
4313 4302 uint32_t *ext_state)
4314 4303 {
4315 4304 *state = MDI_PATHINFO_STATE_INIT;
4316 4305
4317 4306 if (pip) {
4318 4307 if (MDI_PI_IS_TRANSIENT(pip)) {
4319 4308 /*
4320 4309 * mdi_pathinfo is in state transition. Return the
4321 4310 * last good state.
4322 4311 */
4323 4312 *state = MDI_PI_OLD_STATE(pip);
4324 4313 *ext_state = MDI_PI_OLD_EXT_STATE(pip);
4325 4314 } else {
4326 4315 *state = MDI_PI_STATE(pip);
4327 4316 *ext_state = MDI_PI_EXT_STATE(pip);
4328 4317 }
4329 4318 }
4330 4319 return (MDI_SUCCESS);
4331 4320 }
4332 4321
4333 4322 /*
4334 4323 * mdi_pi_get_preferred:
4335 4324 * Get the preferred path flag
4336 4325 */
4337 4326 int
4338 4327 mdi_pi_get_preferred(mdi_pathinfo_t *pip)
4339 4328 {
4340 4329 if (pip) {
4341 4330 return (MDI_PI(pip)->pi_preferred);
4342 4331 }
4343 4332 return (0);
4344 4333 }
4345 4334
4346 4335 /*
4347 4336 * mdi_pi_set_preferred:
4348 4337 * Set the preferred path flag
4349 4338 */
4350 4339 void
4351 4340 mdi_pi_set_preferred(mdi_pathinfo_t *pip, int preferred)
4352 4341 {
4353 4342 if (pip) {
4354 4343 MDI_PI(pip)->pi_preferred = preferred;
4355 4344 }
4356 4345 }
4357 4346
4358 4347 /*
4359 4348 * mdi_pi_set_state():
4360 4349 * Set the mdi_pathinfo node state
4361 4350 */
4362 4351 void
4363 4352 mdi_pi_set_state(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state)
4364 4353 {
4365 4354 uint32_t ext_state;
4366 4355
4367 4356 if (pip) {
4368 4357 ext_state = MDI_PI(pip)->pi_state & MDI_PATHINFO_EXT_STATE_MASK;
4369 4358 MDI_PI(pip)->pi_state = state;
4370 4359 MDI_PI(pip)->pi_state |= ext_state;
4371 4360
4372 4361 /* Path has changed state, invalidate DINFOCACHE snap shot. */
4373 4362 i_ddi_di_cache_invalidate();
4374 4363 }
4375 4364 }
4376 4365
4377 4366 /*
4378 4367 * Property functions:
4379 4368 */
4380 4369 int
4381 4370 i_map_nvlist_error_to_mdi(int val)
4382 4371 {
4383 4372 int rv;
4384 4373
4385 4374 switch (val) {
4386 4375 case 0:
4387 4376 rv = DDI_PROP_SUCCESS;
4388 4377 break;
4389 4378 case EINVAL:
4390 4379 case ENOTSUP:
4391 4380 rv = DDI_PROP_INVAL_ARG;
4392 4381 break;
4393 4382 case ENOMEM:
4394 4383 rv = DDI_PROP_NO_MEMORY;
4395 4384 break;
4396 4385 default:
4397 4386 rv = DDI_PROP_NOT_FOUND;
4398 4387 break;
4399 4388 }
4400 4389 return (rv);
4401 4390 }
4402 4391
4403 4392 /*
4404 4393 * mdi_pi_get_next_prop():
4405 4394 * Property walk function. The caller should hold mdi_pi_lock()
4406 4395 * and release by calling mdi_pi_unlock() at the end of walk to
4407 4396 * get a consistent value.
4408 4397 */
4409 4398 nvpair_t *
4410 4399 mdi_pi_get_next_prop(mdi_pathinfo_t *pip, nvpair_t *prev)
4411 4400 {
4412 4401 if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4413 4402 return (NULL);
4414 4403 }
4415 4404 ASSERT(MDI_PI_LOCKED(pip));
4416 4405 return (nvlist_next_nvpair(MDI_PI(pip)->pi_prop, prev));
4417 4406 }
4418 4407
4419 4408 /*
4420 4409 * mdi_prop_remove():
4421 4410 * Remove the named property from the named list.
4422 4411 */
4423 4412 int
4424 4413 mdi_prop_remove(mdi_pathinfo_t *pip, char *name)
4425 4414 {
4426 4415 if (pip == NULL) {
4427 4416 return (DDI_PROP_NOT_FOUND);
4428 4417 }
4429 4418 ASSERT(!MDI_PI_LOCKED(pip));
4430 4419 MDI_PI_LOCK(pip);
4431 4420 if (MDI_PI(pip)->pi_prop == NULL) {
4432 4421 MDI_PI_UNLOCK(pip);
4433 4422 return (DDI_PROP_NOT_FOUND);
4434 4423 }
4435 4424 if (name) {
4436 4425 (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, name);
4437 4426 } else {
4438 4427 char nvp_name[MAXNAMELEN];
4439 4428 nvpair_t *nvp;
4440 4429 nvp = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, NULL);
4441 4430 while (nvp) {
4442 4431 nvpair_t *next;
4443 4432 next = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, nvp);
4444 4433 (void) snprintf(nvp_name, sizeof(nvp_name), "%s",
4445 4434 nvpair_name(nvp));
4446 4435 (void) nvlist_remove_all(MDI_PI(pip)->pi_prop,
4447 4436 nvp_name);
4448 4437 nvp = next;
4449 4438 }
4450 4439 }
4451 4440 MDI_PI_UNLOCK(pip);
4452 4441 return (DDI_PROP_SUCCESS);
4453 4442 }
4454 4443
4455 4444 /*
4456 4445 * mdi_prop_size():
4457 4446 * Get buffer size needed to pack the property data.
4458 4447 * Caller should hold the mdi_pathinfo_t lock to get a consistent
4459 4448 * buffer size.
4460 4449 */
4461 4450 int
4462 4451 mdi_prop_size(mdi_pathinfo_t *pip, size_t *buflenp)
4463 4452 {
4464 4453 int rv;
4465 4454 size_t bufsize;
4466 4455
4467 4456 *buflenp = 0;
4468 4457 if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4469 4458 return (DDI_PROP_NOT_FOUND);
4470 4459 }
4471 4460 ASSERT(MDI_PI_LOCKED(pip));
4472 4461 rv = nvlist_size(MDI_PI(pip)->pi_prop,
4473 4462 &bufsize, NV_ENCODE_NATIVE);
4474 4463 *buflenp = bufsize;
4475 4464 return (i_map_nvlist_error_to_mdi(rv));
4476 4465 }
4477 4466
4478 4467 /*
4479 4468 * mdi_prop_pack():
4480 4469 * pack the property list. The caller should hold the
4481 4470 * mdi_pathinfo_t node to get a consistent data
4482 4471 */
4483 4472 int
4484 4473 mdi_prop_pack(mdi_pathinfo_t *pip, char **bufp, uint_t buflen)
4485 4474 {
4486 4475 int rv;
4487 4476 size_t bufsize;
4488 4477
4489 4478 if ((pip == NULL) || MDI_PI(pip)->pi_prop == NULL) {
4490 4479 return (DDI_PROP_NOT_FOUND);
4491 4480 }
4492 4481
4493 4482 ASSERT(MDI_PI_LOCKED(pip));
4494 4483
4495 4484 bufsize = buflen;
4496 4485 rv = nvlist_pack(MDI_PI(pip)->pi_prop, bufp, (size_t *)&bufsize,
4497 4486 NV_ENCODE_NATIVE, KM_SLEEP);
4498 4487
4499 4488 return (i_map_nvlist_error_to_mdi(rv));
4500 4489 }
4501 4490
4502 4491 /*
4503 4492 * mdi_prop_update_byte():
4504 4493 * Create/Update a byte property
4505 4494 */
4506 4495 int
4507 4496 mdi_prop_update_byte(mdi_pathinfo_t *pip, char *name, uchar_t data)
4508 4497 {
4509 4498 int rv;
4510 4499
4511 4500 if (pip == NULL) {
4512 4501 return (DDI_PROP_INVAL_ARG);
4513 4502 }
4514 4503 ASSERT(!MDI_PI_LOCKED(pip));
4515 4504 MDI_PI_LOCK(pip);
4516 4505 if (MDI_PI(pip)->pi_prop == NULL) {
4517 4506 MDI_PI_UNLOCK(pip);
4518 4507 return (DDI_PROP_NOT_FOUND);
4519 4508 }
4520 4509 rv = nvlist_add_byte(MDI_PI(pip)->pi_prop, name, data);
4521 4510 MDI_PI_UNLOCK(pip);
4522 4511 return (i_map_nvlist_error_to_mdi(rv));
4523 4512 }
4524 4513
4525 4514 /*
4526 4515 * mdi_prop_update_byte_array():
4527 4516 * Create/Update a byte array property
4528 4517 */
4529 4518 int
4530 4519 mdi_prop_update_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t *data,
4531 4520 uint_t nelements)
4532 4521 {
4533 4522 int rv;
4534 4523
4535 4524 if (pip == NULL) {
4536 4525 return (DDI_PROP_INVAL_ARG);
4537 4526 }
4538 4527 ASSERT(!MDI_PI_LOCKED(pip));
4539 4528 MDI_PI_LOCK(pip);
4540 4529 if (MDI_PI(pip)->pi_prop == NULL) {
4541 4530 MDI_PI_UNLOCK(pip);
4542 4531 return (DDI_PROP_NOT_FOUND);
4543 4532 }
4544 4533 rv = nvlist_add_byte_array(MDI_PI(pip)->pi_prop, name, data, nelements);
4545 4534 MDI_PI_UNLOCK(pip);
4546 4535 return (i_map_nvlist_error_to_mdi(rv));
4547 4536 }
4548 4537
4549 4538 /*
4550 4539 * mdi_prop_update_int():
4551 4540 * Create/Update a 32 bit integer property
4552 4541 */
4553 4542 int
4554 4543 mdi_prop_update_int(mdi_pathinfo_t *pip, char *name, int data)
4555 4544 {
4556 4545 int rv;
4557 4546
4558 4547 if (pip == NULL) {
4559 4548 return (DDI_PROP_INVAL_ARG);
4560 4549 }
4561 4550 ASSERT(!MDI_PI_LOCKED(pip));
4562 4551 MDI_PI_LOCK(pip);
4563 4552 if (MDI_PI(pip)->pi_prop == NULL) {
4564 4553 MDI_PI_UNLOCK(pip);
4565 4554 return (DDI_PROP_NOT_FOUND);
4566 4555 }
4567 4556 rv = nvlist_add_int32(MDI_PI(pip)->pi_prop, name, (int32_t)data);
4568 4557 MDI_PI_UNLOCK(pip);
4569 4558 return (i_map_nvlist_error_to_mdi(rv));
4570 4559 }
4571 4560
4572 4561 /*
4573 4562 * mdi_prop_update_int64():
4574 4563 * Create/Update a 64 bit integer property
4575 4564 */
4576 4565 int
4577 4566 mdi_prop_update_int64(mdi_pathinfo_t *pip, char *name, int64_t data)
4578 4567 {
4579 4568 int rv;
4580 4569
4581 4570 if (pip == NULL) {
4582 4571 return (DDI_PROP_INVAL_ARG);
4583 4572 }
4584 4573 ASSERT(!MDI_PI_LOCKED(pip));
4585 4574 MDI_PI_LOCK(pip);
4586 4575 if (MDI_PI(pip)->pi_prop == NULL) {
4587 4576 MDI_PI_UNLOCK(pip);
4588 4577 return (DDI_PROP_NOT_FOUND);
4589 4578 }
4590 4579 rv = nvlist_add_int64(MDI_PI(pip)->pi_prop, name, data);
4591 4580 MDI_PI_UNLOCK(pip);
4592 4581 return (i_map_nvlist_error_to_mdi(rv));
4593 4582 }
4594 4583
4595 4584 /*
4596 4585 * mdi_prop_update_int_array():
4597 4586 * Create/Update a int array property
4598 4587 */
4599 4588 int
4600 4589 mdi_prop_update_int_array(mdi_pathinfo_t *pip, char *name, int *data,
4601 4590 uint_t nelements)
4602 4591 {
4603 4592 int rv;
4604 4593
4605 4594 if (pip == NULL) {
4606 4595 return (DDI_PROP_INVAL_ARG);
4607 4596 }
4608 4597 ASSERT(!MDI_PI_LOCKED(pip));
4609 4598 MDI_PI_LOCK(pip);
4610 4599 if (MDI_PI(pip)->pi_prop == NULL) {
4611 4600 MDI_PI_UNLOCK(pip);
4612 4601 return (DDI_PROP_NOT_FOUND);
4613 4602 }
4614 4603 rv = nvlist_add_int32_array(MDI_PI(pip)->pi_prop, name, (int32_t *)data,
4615 4604 nelements);
4616 4605 MDI_PI_UNLOCK(pip);
4617 4606 return (i_map_nvlist_error_to_mdi(rv));
4618 4607 }
4619 4608
4620 4609 /*
4621 4610 * mdi_prop_update_string():
4622 4611 * Create/Update a string property
4623 4612 */
4624 4613 int
4625 4614 mdi_prop_update_string(mdi_pathinfo_t *pip, char *name, char *data)
4626 4615 {
4627 4616 int rv;
4628 4617
4629 4618 if (pip == NULL) {
4630 4619 return (DDI_PROP_INVAL_ARG);
4631 4620 }
4632 4621 ASSERT(!MDI_PI_LOCKED(pip));
4633 4622 MDI_PI_LOCK(pip);
4634 4623 if (MDI_PI(pip)->pi_prop == NULL) {
4635 4624 MDI_PI_UNLOCK(pip);
4636 4625 return (DDI_PROP_NOT_FOUND);
4637 4626 }
4638 4627 rv = nvlist_add_string(MDI_PI(pip)->pi_prop, name, data);
4639 4628 MDI_PI_UNLOCK(pip);
4640 4629 return (i_map_nvlist_error_to_mdi(rv));
4641 4630 }
4642 4631
4643 4632 /*
4644 4633 * mdi_prop_update_string_array():
4645 4634 * Create/Update a string array property
4646 4635 */
4647 4636 int
4648 4637 mdi_prop_update_string_array(mdi_pathinfo_t *pip, char *name, char **data,
4649 4638 uint_t nelements)
4650 4639 {
4651 4640 int rv;
4652 4641
4653 4642 if (pip == NULL) {
4654 4643 return (DDI_PROP_INVAL_ARG);
4655 4644 }
4656 4645 ASSERT(!MDI_PI_LOCKED(pip));
4657 4646 MDI_PI_LOCK(pip);
4658 4647 if (MDI_PI(pip)->pi_prop == NULL) {
4659 4648 MDI_PI_UNLOCK(pip);
4660 4649 return (DDI_PROP_NOT_FOUND);
4661 4650 }
4662 4651 rv = nvlist_add_string_array(MDI_PI(pip)->pi_prop, name, data,
4663 4652 nelements);
4664 4653 MDI_PI_UNLOCK(pip);
4665 4654 return (i_map_nvlist_error_to_mdi(rv));
4666 4655 }
4667 4656
4668 4657 /*
4669 4658 * mdi_prop_lookup_byte():
4670 4659 * Look for byte property identified by name. The data returned
4671 4660 * is the actual property and valid as long as mdi_pathinfo_t node
4672 4661 * is alive.
4673 4662 */
4674 4663 int
4675 4664 mdi_prop_lookup_byte(mdi_pathinfo_t *pip, char *name, uchar_t *data)
4676 4665 {
4677 4666 int rv;
4678 4667
4679 4668 if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4680 4669 return (DDI_PROP_NOT_FOUND);
4681 4670 }
4682 4671 rv = nvlist_lookup_byte(MDI_PI(pip)->pi_prop, name, data);
4683 4672 return (i_map_nvlist_error_to_mdi(rv));
4684 4673 }
4685 4674
4686 4675
4687 4676 /*
4688 4677 * mdi_prop_lookup_byte_array():
4689 4678 * Look for byte array property identified by name. The data
4690 4679 * returned is the actual property and valid as long as
4691 4680 * mdi_pathinfo_t node is alive.
4692 4681 */
4693 4682 int
4694 4683 mdi_prop_lookup_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t **data,
4695 4684 uint_t *nelements)
4696 4685 {
4697 4686 int rv;
4698 4687
4699 4688 if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4700 4689 return (DDI_PROP_NOT_FOUND);
4701 4690 }
4702 4691 rv = nvlist_lookup_byte_array(MDI_PI(pip)->pi_prop, name, data,
4703 4692 nelements);
4704 4693 return (i_map_nvlist_error_to_mdi(rv));
4705 4694 }
4706 4695
4707 4696 /*
4708 4697 * mdi_prop_lookup_int():
4709 4698 * Look for int property identified by name. The data returned
4710 4699 * is the actual property and valid as long as mdi_pathinfo_t
4711 4700 * node is alive.
4712 4701 */
4713 4702 int
4714 4703 mdi_prop_lookup_int(mdi_pathinfo_t *pip, char *name, int *data)
4715 4704 {
4716 4705 int rv;
4717 4706
4718 4707 if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4719 4708 return (DDI_PROP_NOT_FOUND);
4720 4709 }
4721 4710 rv = nvlist_lookup_int32(MDI_PI(pip)->pi_prop, name, (int32_t *)data);
4722 4711 return (i_map_nvlist_error_to_mdi(rv));
4723 4712 }
4724 4713
4725 4714 /*
4726 4715 * mdi_prop_lookup_int64():
4727 4716 * Look for int64 property identified by name. The data returned
4728 4717 * is the actual property and valid as long as mdi_pathinfo_t node
4729 4718 * is alive.
4730 4719 */
4731 4720 int
4732 4721 mdi_prop_lookup_int64(mdi_pathinfo_t *pip, char *name, int64_t *data)
4733 4722 {
4734 4723 int rv;
4735 4724 if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4736 4725 return (DDI_PROP_NOT_FOUND);
4737 4726 }
4738 4727 rv = nvlist_lookup_int64(MDI_PI(pip)->pi_prop, name, data);
4739 4728 return (i_map_nvlist_error_to_mdi(rv));
4740 4729 }
4741 4730
4742 4731 /*
4743 4732 * mdi_prop_lookup_int_array():
4744 4733 * Look for int array property identified by name. The data
4745 4734 * returned is the actual property and valid as long as
4746 4735 * mdi_pathinfo_t node is alive.
4747 4736 */
4748 4737 int
4749 4738 mdi_prop_lookup_int_array(mdi_pathinfo_t *pip, char *name, int **data,
4750 4739 uint_t *nelements)
4751 4740 {
4752 4741 int rv;
4753 4742
4754 4743 if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4755 4744 return (DDI_PROP_NOT_FOUND);
4756 4745 }
4757 4746 rv = nvlist_lookup_int32_array(MDI_PI(pip)->pi_prop, name,
4758 4747 (int32_t **)data, nelements);
4759 4748 return (i_map_nvlist_error_to_mdi(rv));
4760 4749 }
4761 4750
4762 4751 /*
4763 4752 * mdi_prop_lookup_string():
4764 4753 * Look for string property identified by name. The data
4765 4754 * returned is the actual property and valid as long as
4766 4755 * mdi_pathinfo_t node is alive.
4767 4756 */
4768 4757 int
4769 4758 mdi_prop_lookup_string(mdi_pathinfo_t *pip, char *name, char **data)
4770 4759 {
4771 4760 int rv;
4772 4761
4773 4762 if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4774 4763 return (DDI_PROP_NOT_FOUND);
4775 4764 }
4776 4765 rv = nvlist_lookup_string(MDI_PI(pip)->pi_prop, name, data);
4777 4766 return (i_map_nvlist_error_to_mdi(rv));
4778 4767 }
4779 4768
4780 4769 /*
4781 4770 * mdi_prop_lookup_string_array():
4782 4771 * Look for string array property identified by name. The data
4783 4772 * returned is the actual property and valid as long as
4784 4773 * mdi_pathinfo_t node is alive.
4785 4774 */
4786 4775 int
4787 4776 mdi_prop_lookup_string_array(mdi_pathinfo_t *pip, char *name, char ***data,
4788 4777 uint_t *nelements)
4789 4778 {
4790 4779 int rv;
4791 4780
4792 4781 if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) {
4793 4782 return (DDI_PROP_NOT_FOUND);
4794 4783 }
4795 4784 rv = nvlist_lookup_string_array(MDI_PI(pip)->pi_prop, name, data,
4796 4785 nelements);
4797 4786 return (i_map_nvlist_error_to_mdi(rv));
4798 4787 }
4799 4788
4800 4789 /*
4801 4790 * mdi_prop_free():
4802 4791 * Symmetrical function to ddi_prop_free(). nvlist_lookup_xx()
4803 4792 * functions return the pointer to actual property data and not a
4804 4793 * copy of it. So the data returned is valid as long as
4805 4794 * mdi_pathinfo_t node is valid.
4806 4795 */
4807 4796 /*ARGSUSED*/
4808 4797 int
4809 4798 mdi_prop_free(void *data)
4810 4799 {
4811 4800 return (DDI_PROP_SUCCESS);
4812 4801 }
4813 4802
4814 4803 /*ARGSUSED*/
4815 4804 static void
4816 4805 i_mdi_report_path_state(mdi_client_t *ct, mdi_pathinfo_t *pip)
4817 4806 {
4818 4807 char *ct_path;
4819 4808 char *ct_status;
4820 4809 char *status;
4821 4810 dev_info_t *cdip = ct->ct_dip;
4822 4811 char lb_buf[64];
4823 4812 int report_lb_c = 0, report_lb_p = 0;
4824 4813
4825 4814 ASSERT(MDI_CLIENT_LOCKED(ct));
4826 4815 if ((cdip == NULL) || (ddi_get_instance(cdip) == -1) ||
4827 4816 (MDI_CLIENT_IS_REPORT_DEV_NEEDED(ct) == 0)) {
4828 4817 return;
4829 4818 }
4830 4819 if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL) {
4831 4820 ct_status = "optimal";
4832 4821 report_lb_c = 1;
4833 4822 } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) {
4834 4823 ct_status = "degraded";
4835 4824 } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) {
4836 4825 ct_status = "failed";
4837 4826 } else {
4838 4827 ct_status = "unknown";
4839 4828 }
4840 4829
4841 4830 lb_buf[0] = 0; /* not interested in load balancing config */
4842 4831
4843 4832 if (MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip)) {
4844 4833 status = "removed";
4845 4834 } else if (MDI_PI_IS_OFFLINE(pip)) {
4846 4835 status = "offline";
4847 4836 } else if (MDI_PI_IS_ONLINE(pip)) {
4848 4837 status = "online";
4849 4838 report_lb_p = 1;
4850 4839 } else if (MDI_PI_IS_STANDBY(pip)) {
4851 4840 status = "standby";
4852 4841 } else if (MDI_PI_IS_FAULT(pip)) {
4853 4842 status = "faulted";
4854 4843 } else {
4855 4844 status = "unknown";
4856 4845 }
4857 4846
4858 4847 if (cdip) {
4859 4848 ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4860 4849
4861 4850 /*
4862 4851 * NOTE: Keeping "multipath status: %s" and
4863 4852 * "Load balancing: %s" format unchanged in case someone
4864 4853 * scrubs /var/adm/messages looking for these messages.
4865 4854 */
4866 4855 if (report_lb_c && report_lb_p) {
4867 4856 if (ct->ct_lb == LOAD_BALANCE_LBA) {
4868 4857 (void) snprintf(lb_buf, sizeof (lb_buf),
4869 4858 "%s, region-size: %d", mdi_load_balance_lba,
4870 4859 ct->ct_lb_args->region_size);
4871 4860 } else if (ct->ct_lb == LOAD_BALANCE_NONE) {
4872 4861 (void) snprintf(lb_buf, sizeof (lb_buf),
4873 4862 "%s", mdi_load_balance_none);
4874 4863 } else {
4875 4864 (void) snprintf(lb_buf, sizeof (lb_buf), "%s",
4876 4865 mdi_load_balance_rr);
4877 4866 }
4878 4867
4879 4868 cmn_err(mdi_debug_consoleonly ? CE_NOTE : CE_CONT,
4880 4869 "?%s (%s%d) multipath status: %s: "
4881 4870 "path %d %s is %s: Load balancing: %s\n",
4882 4871 ddi_pathname(cdip, ct_path), ddi_driver_name(cdip),
4883 4872 ddi_get_instance(cdip), ct_status,
4884 4873 mdi_pi_get_path_instance(pip),
4885 4874 mdi_pi_spathname(pip), status, lb_buf);
4886 4875 } else {
4887 4876 cmn_err(mdi_debug_consoleonly ? CE_NOTE : CE_CONT,
4888 4877 "?%s (%s%d) multipath status: %s: "
4889 4878 "path %d %s is %s\n",
4890 4879 ddi_pathname(cdip, ct_path), ddi_driver_name(cdip),
4891 4880 ddi_get_instance(cdip), ct_status,
4892 4881 mdi_pi_get_path_instance(pip),
4893 4882 mdi_pi_spathname(pip), status);
4894 4883 }
4895 4884
4896 4885 kmem_free(ct_path, MAXPATHLEN);
4897 4886 MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct);
4898 4887 }
4899 4888 }
4900 4889
4901 4890 #ifdef DEBUG
4902 4891 /*
4903 4892 * i_mdi_log():
4904 4893 * Utility function for error message management
4905 4894 *
4906 4895 * NOTE: Implementation takes care of trailing \n for cmn_err,
4907 4896 * MDI_DEBUG should not terminate fmt strings with \n.
4908 4897 *
4909 4898 * NOTE: If the level is >= 2, and there is no leading !?^
4910 4899 * then a leading ! is implied (but can be overriden via
4911 4900 * mdi_debug_consoleonly). If you are using kmdb on the console,
4912 4901 * consider setting mdi_debug_consoleonly to 1 as an aid.
4913 4902 */
4914 4903 /*PRINTFLIKE4*/
4915 4904 static void
4916 4905 i_mdi_log(int level, const char *func, dev_info_t *dip, const char *fmt, ...)
4917 4906 {
4918 4907 char name[MAXNAMELEN];
4919 4908 char buf[512];
4920 4909 char *bp;
4921 4910 va_list ap;
4922 4911 int log_only = 0;
4923 4912 int boot_only = 0;
4924 4913 int console_only = 0;
4925 4914
4926 4915 if (dip) {
4927 4916 (void) snprintf(name, sizeof(name), "%s%d: ",
4928 4917 ddi_driver_name(dip), ddi_get_instance(dip));
4929 4918 } else {
4930 4919 name[0] = 0;
4931 4920 }
4932 4921
4933 4922 va_start(ap, fmt);
4934 4923 (void) vsnprintf(buf, sizeof(buf), fmt, ap);
4935 4924 va_end(ap);
4936 4925
4937 4926 switch (buf[0]) {
4938 4927 case '!':
4939 4928 bp = &buf[1];
4940 4929 log_only = 1;
4941 4930 break;
4942 4931 case '?':
4943 4932 bp = &buf[1];
4944 4933 boot_only = 1;
4945 4934 break;
4946 4935 case '^':
4947 4936 bp = &buf[1];
4948 4937 console_only = 1;
4949 4938 break;
4950 4939 default:
4951 4940 if (level >= 2)
4952 4941 log_only = 1; /* ! implied */
4953 4942 bp = buf;
4954 4943 break;
4955 4944 }
4956 4945 if (mdi_debug_logonly) {
4957 4946 log_only = 1;
4958 4947 boot_only = 0;
4959 4948 console_only = 0;
4960 4949 }
4961 4950 if (mdi_debug_consoleonly) {
4962 4951 log_only = 0;
4963 4952 boot_only = 0;
4964 4953 console_only = 1;
4965 4954 level = CE_NOTE;
4966 4955 goto console;
4967 4956 }
4968 4957
4969 4958 switch (level) {
4970 4959 case CE_NOTE:
4971 4960 level = CE_CONT;
4972 4961 /* FALLTHROUGH */
4973 4962 case CE_CONT:
4974 4963 if (boot_only) {
4975 4964 cmn_err(level, "?mdi: %s%s: %s\n", name, func, bp);
4976 4965 } else if (console_only) {
4977 4966 cmn_err(level, "^mdi: %s%s: %s\n", name, func, bp);
4978 4967 } else if (log_only) {
4979 4968 cmn_err(level, "!mdi: %s%s: %s\n", name, func, bp);
4980 4969 } else {
4981 4970 cmn_err(level, "mdi: %s%s: %s\n", name, func, bp);
4982 4971 }
4983 4972 break;
4984 4973
4985 4974 case CE_WARN:
4986 4975 case CE_PANIC:
4987 4976 console:
4988 4977 if (boot_only) {
4989 4978 cmn_err(level, "?mdi: %s%s: %s", name, func, bp);
4990 4979 } else if (console_only) {
4991 4980 cmn_err(level, "^mdi: %s%s: %s", name, func, bp);
4992 4981 } else if (log_only) {
4993 4982 cmn_err(level, "!mdi: %s%s: %s", name, func, bp);
4994 4983 } else {
4995 4984 cmn_err(level, "mdi: %s%s: %s", name, func, bp);
4996 4985 }
4997 4986 break;
4998 4987 default:
4999 4988 cmn_err(level, "mdi: %s%s", name, bp);
5000 4989 break;
5001 4990 }
5002 4991 }
5003 4992 #endif /* DEBUG */
5004 4993
5005 4994 void
5006 4995 i_mdi_client_online(dev_info_t *ct_dip)
5007 4996 {
5008 4997 mdi_client_t *ct;
5009 4998
5010 4999 /*
5011 5000 * Client online notification. Mark client state as online
5012 5001 * restore our binding with dev_info node
5013 5002 */
5014 5003 ct = i_devi_get_client(ct_dip);
5015 5004 ASSERT(ct != NULL);
5016 5005 MDI_CLIENT_LOCK(ct);
5017 5006 MDI_CLIENT_SET_ONLINE(ct);
5018 5007 /* catch for any memory leaks */
5019 5008 ASSERT((ct->ct_dip == NULL) || (ct->ct_dip == ct_dip));
5020 5009 ct->ct_dip = ct_dip;
5021 5010
5022 5011 if (ct->ct_power_cnt == 0)
5023 5012 (void) i_mdi_power_all_phci(ct);
5024 5013
5025 5014 MDI_DEBUG(4, (MDI_NOTE, ct_dip,
5026 5015 "i_mdi_pm_hold_client %p", (void *)ct));
5027 5016 i_mdi_pm_hold_client(ct, 1);
5028 5017
5029 5018 MDI_CLIENT_UNLOCK(ct);
5030 5019 }
5031 5020
5032 5021 void
5033 5022 i_mdi_phci_online(dev_info_t *ph_dip)
5034 5023 {
5035 5024 mdi_phci_t *ph;
5036 5025
5037 5026 /* pHCI online notification. Mark state accordingly */
5038 5027 ph = i_devi_get_phci(ph_dip);
5039 5028 ASSERT(ph != NULL);
5040 5029 MDI_PHCI_LOCK(ph);
5041 5030 MDI_PHCI_SET_ONLINE(ph);
5042 5031 MDI_PHCI_UNLOCK(ph);
5043 5032 }
5044 5033
5045 5034 /*
5046 5035 * mdi_devi_online():
5047 5036 * Online notification from NDI framework on pHCI/client
5048 5037 * device online.
5049 5038 * Return Values:
5050 5039 * NDI_SUCCESS
5051 5040 * MDI_FAILURE
5052 5041 */
5053 5042 /*ARGSUSED*/
5054 5043 int
5055 5044 mdi_devi_online(dev_info_t *dip, uint_t flags)
5056 5045 {
5057 5046 if (MDI_PHCI(dip)) {
5058 5047 i_mdi_phci_online(dip);
5059 5048 }
5060 5049
5061 5050 if (MDI_CLIENT(dip)) {
5062 5051 i_mdi_client_online(dip);
5063 5052 }
5064 5053 return (NDI_SUCCESS);
5065 5054 }
5066 5055
5067 5056 /*
5068 5057 * mdi_devi_offline():
5069 5058 * Offline notification from NDI framework on pHCI/Client device
5070 5059 * offline.
5071 5060 *
5072 5061 * Return Values:
5073 5062 * NDI_SUCCESS
5074 5063 * NDI_FAILURE
5075 5064 */
5076 5065 /*ARGSUSED*/
5077 5066 int
5078 5067 mdi_devi_offline(dev_info_t *dip, uint_t flags)
5079 5068 {
5080 5069 int rv = NDI_SUCCESS;
5081 5070
5082 5071 if (MDI_CLIENT(dip)) {
5083 5072 rv = i_mdi_client_offline(dip, flags);
5084 5073 if (rv != NDI_SUCCESS)
5085 5074 return (rv);
5086 5075 }
5087 5076
5088 5077 if (MDI_PHCI(dip)) {
5089 5078 rv = i_mdi_phci_offline(dip, flags);
5090 5079
5091 5080 if ((rv != NDI_SUCCESS) && MDI_CLIENT(dip)) {
5092 5081 /* set client back online */
5093 5082 i_mdi_client_online(dip);
5094 5083 }
5095 5084 }
5096 5085
5097 5086 return (rv);
5098 5087 }
5099 5088
5100 5089 /*ARGSUSED*/
5101 5090 static int
5102 5091 i_mdi_phci_offline(dev_info_t *dip, uint_t flags)
5103 5092 {
5104 5093 int rv = NDI_SUCCESS;
5105 5094 mdi_phci_t *ph;
5106 5095 mdi_client_t *ct;
5107 5096 mdi_pathinfo_t *pip;
5108 5097 mdi_pathinfo_t *next;
5109 5098 mdi_pathinfo_t *failed_pip = NULL;
5110 5099 dev_info_t *cdip;
5111 5100
5112 5101 /*
5113 5102 * pHCI component offline notification
5114 5103 * Make sure that this pHCI instance is free to be offlined.
5115 5104 * If it is OK to proceed, Offline and remove all the child
5116 5105 * mdi_pathinfo nodes. This process automatically offlines
5117 5106 * corresponding client devices, for which this pHCI provides
5118 5107 * critical services.
5119 5108 */
5120 5109 ph = i_devi_get_phci(dip);
5121 5110 MDI_DEBUG(2, (MDI_NOTE, dip,
5122 5111 "called %p %p", (void *)dip, (void *)ph));
5123 5112 if (ph == NULL) {
5124 5113 return (rv);
5125 5114 }
5126 5115
5127 5116 MDI_PHCI_LOCK(ph);
5128 5117
5129 5118 if (MDI_PHCI_IS_OFFLINE(ph)) {
5130 5119 MDI_DEBUG(1, (MDI_WARN, dip,
5131 5120 "!pHCI already offlined: %p", (void *)dip));
5132 5121 MDI_PHCI_UNLOCK(ph);
5133 5122 return (NDI_SUCCESS);
5134 5123 }
5135 5124
5136 5125 /*
5137 5126 * Check to see if the pHCI can be offlined
5138 5127 */
5139 5128 if (ph->ph_unstable) {
5140 5129 MDI_DEBUG(1, (MDI_WARN, dip,
5141 5130 "!One or more target devices are in transient state. "
5142 5131 "This device can not be removed at this moment. "
5143 5132 "Please try again later."));
5144 5133 MDI_PHCI_UNLOCK(ph);
5145 5134 return (NDI_BUSY);
5146 5135 }
5147 5136
5148 5137 pip = ph->ph_path_head;
5149 5138 while (pip != NULL) {
5150 5139 MDI_PI_LOCK(pip);
5151 5140 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5152 5141
5153 5142 /*
5154 5143 * The mdi_pathinfo state is OK. Check the client state.
5155 5144 * If failover in progress fail the pHCI from offlining
5156 5145 */
5157 5146 ct = MDI_PI(pip)->pi_client;
5158 5147 i_mdi_client_lock(ct, pip);
5159 5148 if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) ||
5160 5149 (ct->ct_unstable)) {
5161 5150 /*
5162 5151 * Failover is in progress, Fail the DR
5163 5152 */
5164 5153 MDI_DEBUG(1, (MDI_WARN, dip,
5165 5154 "!pHCI device is busy. "
5166 5155 "This device can not be removed at this moment. "
5167 5156 "Please try again later."));
5168 5157 MDI_PI_UNLOCK(pip);
5169 5158 i_mdi_client_unlock(ct);
5170 5159 MDI_PHCI_UNLOCK(ph);
5171 5160 return (NDI_BUSY);
5172 5161 }
5173 5162 MDI_PI_UNLOCK(pip);
5174 5163
5175 5164 /*
5176 5165 * Check to see of we are removing the last path of this
5177 5166 * client device...
5178 5167 */
5179 5168 cdip = ct->ct_dip;
5180 5169 if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) &&
5181 5170 (i_mdi_client_compute_state(ct, ph) ==
5182 5171 MDI_CLIENT_STATE_FAILED)) {
5183 5172 i_mdi_client_unlock(ct);
5184 5173 MDI_PHCI_UNLOCK(ph);
5185 5174 if (ndi_devi_offline(cdip,
5186 5175 NDI_DEVFS_CLEAN) != NDI_SUCCESS) {
5187 5176 /*
5188 5177 * ndi_devi_offline() failed.
5189 5178 * This pHCI provides the critical path
5190 5179 * to one or more client devices.
5191 5180 * Return busy.
5192 5181 */
5193 5182 MDI_PHCI_LOCK(ph);
5194 5183 MDI_DEBUG(1, (MDI_WARN, dip,
5195 5184 "!pHCI device is busy. "
5196 5185 "This device can not be removed at this "
5197 5186 "moment. Please try again later."));
5198 5187 failed_pip = pip;
5199 5188 break;
5200 5189 } else {
5201 5190 MDI_PHCI_LOCK(ph);
5202 5191 pip = next;
5203 5192 }
5204 5193 } else {
5205 5194 i_mdi_client_unlock(ct);
5206 5195 pip = next;
5207 5196 }
5208 5197 }
5209 5198
5210 5199 if (failed_pip) {
5211 5200 pip = ph->ph_path_head;
5212 5201 while (pip != failed_pip) {
5213 5202 MDI_PI_LOCK(pip);
5214 5203 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5215 5204 ct = MDI_PI(pip)->pi_client;
5216 5205 i_mdi_client_lock(ct, pip);
5217 5206 cdip = ct->ct_dip;
5218 5207 switch (MDI_CLIENT_STATE(ct)) {
5219 5208 case MDI_CLIENT_STATE_OPTIMAL:
5220 5209 case MDI_CLIENT_STATE_DEGRADED:
5221 5210 if (cdip) {
5222 5211 MDI_PI_UNLOCK(pip);
5223 5212 i_mdi_client_unlock(ct);
5224 5213 MDI_PHCI_UNLOCK(ph);
5225 5214 (void) ndi_devi_online(cdip, 0);
5226 5215 MDI_PHCI_LOCK(ph);
5227 5216 pip = next;
5228 5217 continue;
5229 5218 }
5230 5219 break;
5231 5220
5232 5221 case MDI_CLIENT_STATE_FAILED:
5233 5222 if (cdip) {
5234 5223 MDI_PI_UNLOCK(pip);
5235 5224 i_mdi_client_unlock(ct);
5236 5225 MDI_PHCI_UNLOCK(ph);
5237 5226 (void) ndi_devi_offline(cdip,
5238 5227 NDI_DEVFS_CLEAN);
5239 5228 MDI_PHCI_LOCK(ph);
5240 5229 pip = next;
5241 5230 continue;
5242 5231 }
5243 5232 break;
5244 5233 }
5245 5234 MDI_PI_UNLOCK(pip);
5246 5235 i_mdi_client_unlock(ct);
5247 5236 pip = next;
5248 5237 }
5249 5238 MDI_PHCI_UNLOCK(ph);
5250 5239 return (NDI_BUSY);
5251 5240 }
5252 5241
5253 5242 /*
5254 5243 * Mark the pHCI as offline
5255 5244 */
5256 5245 MDI_PHCI_SET_OFFLINE(ph);
5257 5246
5258 5247 /*
5259 5248 * Mark the child mdi_pathinfo nodes as transient
5260 5249 */
5261 5250 pip = ph->ph_path_head;
5262 5251 while (pip != NULL) {
5263 5252 MDI_PI_LOCK(pip);
5264 5253 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5265 5254 MDI_PI_SET_OFFLINING(pip);
5266 5255 MDI_PI_UNLOCK(pip);
5267 5256 pip = next;
5268 5257 }
5269 5258 MDI_PHCI_UNLOCK(ph);
5270 5259 /*
5271 5260 * Give a chance for any pending commands to execute
5272 5261 */
5273 5262 delay_random(mdi_delay);
5274 5263 MDI_PHCI_LOCK(ph);
5275 5264 pip = ph->ph_path_head;
5276 5265 while (pip != NULL) {
5277 5266 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5278 5267 (void) i_mdi_pi_offline(pip, flags);
5279 5268 MDI_PI_LOCK(pip);
5280 5269 ct = MDI_PI(pip)->pi_client;
5281 5270 if (!MDI_PI_IS_OFFLINE(pip)) {
5282 5271 MDI_DEBUG(1, (MDI_WARN, dip,
5283 5272 "!pHCI device is busy. "
5284 5273 "This device can not be removed at this moment. "
5285 5274 "Please try again later."));
5286 5275 MDI_PI_UNLOCK(pip);
5287 5276 MDI_PHCI_SET_ONLINE(ph);
5288 5277 MDI_PHCI_UNLOCK(ph);
5289 5278 return (NDI_BUSY);
5290 5279 }
5291 5280 MDI_PI_UNLOCK(pip);
5292 5281 pip = next;
5293 5282 }
5294 5283 MDI_PHCI_UNLOCK(ph);
5295 5284
5296 5285 return (rv);
5297 5286 }
5298 5287
5299 5288 void
5300 5289 mdi_phci_mark_retiring(dev_info_t *dip, char **cons_array)
5301 5290 {
5302 5291 mdi_phci_t *ph;
5303 5292 mdi_client_t *ct;
5304 5293 mdi_pathinfo_t *pip;
5305 5294 mdi_pathinfo_t *next;
5306 5295 dev_info_t *cdip;
5307 5296
5308 5297 if (!MDI_PHCI(dip))
5309 5298 return;
5310 5299
5311 5300 ph = i_devi_get_phci(dip);
5312 5301 if (ph == NULL) {
5313 5302 return;
5314 5303 }
5315 5304
5316 5305 MDI_PHCI_LOCK(ph);
5317 5306
5318 5307 if (MDI_PHCI_IS_OFFLINE(ph)) {
5319 5308 /* has no last path */
5320 5309 MDI_PHCI_UNLOCK(ph);
5321 5310 return;
5322 5311 }
5323 5312
5324 5313 pip = ph->ph_path_head;
5325 5314 while (pip != NULL) {
5326 5315 MDI_PI_LOCK(pip);
5327 5316 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5328 5317
5329 5318 ct = MDI_PI(pip)->pi_client;
5330 5319 i_mdi_client_lock(ct, pip);
5331 5320 MDI_PI_UNLOCK(pip);
5332 5321
5333 5322 cdip = ct->ct_dip;
5334 5323 if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) &&
5335 5324 (i_mdi_client_compute_state(ct, ph) ==
5336 5325 MDI_CLIENT_STATE_FAILED)) {
5337 5326 /* Last path. Mark client dip as retiring */
5338 5327 i_mdi_client_unlock(ct);
5339 5328 MDI_PHCI_UNLOCK(ph);
5340 5329 (void) e_ddi_mark_retiring(cdip, cons_array);
5341 5330 MDI_PHCI_LOCK(ph);
5342 5331 pip = next;
5343 5332 } else {
5344 5333 i_mdi_client_unlock(ct);
5345 5334 pip = next;
5346 5335 }
5347 5336 }
5348 5337
5349 5338 MDI_PHCI_UNLOCK(ph);
5350 5339
5351 5340 return;
5352 5341 }
5353 5342
5354 5343 void
5355 5344 mdi_phci_retire_notify(dev_info_t *dip, int *constraint)
5356 5345 {
5357 5346 mdi_phci_t *ph;
5358 5347 mdi_client_t *ct;
5359 5348 mdi_pathinfo_t *pip;
5360 5349 mdi_pathinfo_t *next;
5361 5350 dev_info_t *cdip;
5362 5351
5363 5352 if (!MDI_PHCI(dip))
5364 5353 return;
5365 5354
5366 5355 ph = i_devi_get_phci(dip);
5367 5356 if (ph == NULL)
5368 5357 return;
5369 5358
5370 5359 MDI_PHCI_LOCK(ph);
5371 5360
5372 5361 if (MDI_PHCI_IS_OFFLINE(ph)) {
5373 5362 MDI_PHCI_UNLOCK(ph);
5374 5363 /* not last path */
5375 5364 return;
5376 5365 }
5377 5366
5378 5367 if (ph->ph_unstable) {
5379 5368 MDI_PHCI_UNLOCK(ph);
5380 5369 /* can't check for constraints */
5381 5370 *constraint = 0;
5382 5371 return;
5383 5372 }
5384 5373
5385 5374 pip = ph->ph_path_head;
5386 5375 while (pip != NULL) {
5387 5376 MDI_PI_LOCK(pip);
5388 5377 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5389 5378
5390 5379 /*
5391 5380 * The mdi_pathinfo state is OK. Check the client state.
5392 5381 * If failover in progress fail the pHCI from offlining
5393 5382 */
5394 5383 ct = MDI_PI(pip)->pi_client;
5395 5384 i_mdi_client_lock(ct, pip);
5396 5385 if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) ||
5397 5386 (ct->ct_unstable)) {
5398 5387 /*
5399 5388 * Failover is in progress, can't check for constraints
5400 5389 */
5401 5390 MDI_PI_UNLOCK(pip);
5402 5391 i_mdi_client_unlock(ct);
5403 5392 MDI_PHCI_UNLOCK(ph);
5404 5393 *constraint = 0;
5405 5394 return;
5406 5395 }
5407 5396 MDI_PI_UNLOCK(pip);
5408 5397
5409 5398 /*
5410 5399 * Check to see of we are retiring the last path of this
5411 5400 * client device...
5412 5401 */
5413 5402 cdip = ct->ct_dip;
5414 5403 if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) &&
5415 5404 (i_mdi_client_compute_state(ct, ph) ==
5416 5405 MDI_CLIENT_STATE_FAILED)) {
5417 5406 i_mdi_client_unlock(ct);
5418 5407 MDI_PHCI_UNLOCK(ph);
5419 5408 (void) e_ddi_retire_notify(cdip, constraint);
5420 5409 MDI_PHCI_LOCK(ph);
5421 5410 pip = next;
5422 5411 } else {
5423 5412 i_mdi_client_unlock(ct);
5424 5413 pip = next;
5425 5414 }
5426 5415 }
5427 5416
5428 5417 MDI_PHCI_UNLOCK(ph);
5429 5418
5430 5419 return;
5431 5420 }
5432 5421
5433 5422 /*
5434 5423 * offline the path(s) hanging off the pHCI. If the
5435 5424 * last path to any client, check that constraints
5436 5425 * have been applied.
5437 5426 *
5438 5427 * If constraint is 0, we aren't going to retire the
5439 5428 * pHCI. However we still need to go through the paths
5440 5429 * calling e_ddi_retire_finalize() to clear their
5441 5430 * contract barriers.
5442 5431 */
5443 5432 void
5444 5433 mdi_phci_retire_finalize(dev_info_t *dip, int phci_only, void *constraint)
5445 5434 {
5446 5435 mdi_phci_t *ph;
5447 5436 mdi_client_t *ct;
5448 5437 mdi_pathinfo_t *pip;
5449 5438 mdi_pathinfo_t *next;
5450 5439 dev_info_t *cdip;
5451 5440 int unstable = 0;
5452 5441 int tmp_constraint;
5453 5442
5454 5443 if (!MDI_PHCI(dip))
5455 5444 return;
5456 5445
5457 5446 ph = i_devi_get_phci(dip);
5458 5447 if (ph == NULL) {
5459 5448 /* no last path and no pips */
5460 5449 return;
5461 5450 }
5462 5451
5463 5452 MDI_PHCI_LOCK(ph);
5464 5453
5465 5454 if (MDI_PHCI_IS_OFFLINE(ph)) {
5466 5455 MDI_PHCI_UNLOCK(ph);
5467 5456 /* no last path and no pips */
5468 5457 return;
5469 5458 }
5470 5459
5471 5460 /*
5472 5461 * Check to see if the pHCI can be offlined
5473 5462 */
5474 5463 if (ph->ph_unstable) {
5475 5464 unstable = 1;
5476 5465 }
5477 5466
5478 5467 pip = ph->ph_path_head;
5479 5468 while (pip != NULL) {
5480 5469 MDI_PI_LOCK(pip);
5481 5470 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5482 5471
5483 5472 /*
5484 5473 * if failover in progress fail the pHCI from offlining
5485 5474 */
5486 5475 ct = MDI_PI(pip)->pi_client;
5487 5476 i_mdi_client_lock(ct, pip);
5488 5477 if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) ||
5489 5478 (ct->ct_unstable)) {
5490 5479 unstable = 1;
5491 5480 }
5492 5481 MDI_PI_UNLOCK(pip);
5493 5482
5494 5483 /*
5495 5484 * Check to see of we are removing the last path of this
5496 5485 * client device...
5497 5486 */
5498 5487 cdip = ct->ct_dip;
5499 5488 if (!phci_only && cdip &&
5500 5489 (i_ddi_node_state(cdip) >= DS_INITIALIZED) &&
5501 5490 (i_mdi_client_compute_state(ct, ph) ==
5502 5491 MDI_CLIENT_STATE_FAILED)) {
5503 5492 i_mdi_client_unlock(ct);
5504 5493 MDI_PHCI_UNLOCK(ph);
5505 5494 /*
5506 5495 * This is the last path to this client.
5507 5496 *
5508 5497 * Constraint will only be set to 1 if this client can
5509 5498 * be retired (as already determined by
5510 5499 * mdi_phci_retire_notify). However we don't actually
5511 5500 * need to retire the client (we just retire the last
5512 5501 * path - MPXIO will then fail all I/Os to the client).
5513 5502 * But we still need to call e_ddi_retire_finalize so
5514 5503 * the contract barriers can be cleared. Therefore we
5515 5504 * temporarily set constraint = 0 so that the client
5516 5505 * dip is not retired.
5517 5506 */
5518 5507 tmp_constraint = 0;
5519 5508 (void) e_ddi_retire_finalize(cdip, &tmp_constraint);
5520 5509 MDI_PHCI_LOCK(ph);
5521 5510 pip = next;
5522 5511 } else {
5523 5512 i_mdi_client_unlock(ct);
5524 5513 pip = next;
5525 5514 }
5526 5515 }
5527 5516
5528 5517 if (!phci_only && *((int *)constraint) == 0) {
5529 5518 MDI_PHCI_UNLOCK(ph);
5530 5519 return;
5531 5520 }
5532 5521
5533 5522 /*
5534 5523 * Cannot offline pip(s)
5535 5524 */
5536 5525 if (unstable) {
5537 5526 cmn_err(CE_WARN, "%s%d: mdi_phci_retire_finalize: "
5538 5527 "pHCI in transient state, cannot retire",
5539 5528 ddi_driver_name(dip), ddi_get_instance(dip));
5540 5529 MDI_PHCI_UNLOCK(ph);
5541 5530 return;
5542 5531 }
5543 5532
5544 5533 /*
5545 5534 * Mark the pHCI as offline
5546 5535 */
5547 5536 MDI_PHCI_SET_OFFLINE(ph);
5548 5537
5549 5538 /*
5550 5539 * Mark the child mdi_pathinfo nodes as transient
5551 5540 */
5552 5541 pip = ph->ph_path_head;
5553 5542 while (pip != NULL) {
5554 5543 MDI_PI_LOCK(pip);
5555 5544 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5556 5545 MDI_PI_SET_OFFLINING(pip);
5557 5546 MDI_PI_UNLOCK(pip);
5558 5547 pip = next;
5559 5548 }
5560 5549 MDI_PHCI_UNLOCK(ph);
5561 5550 /*
5562 5551 * Give a chance for any pending commands to execute
5563 5552 */
5564 5553 delay_random(mdi_delay);
5565 5554 MDI_PHCI_LOCK(ph);
5566 5555 pip = ph->ph_path_head;
5567 5556 while (pip != NULL) {
5568 5557 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5569 5558 (void) i_mdi_pi_offline(pip, 0);
5570 5559 MDI_PI_LOCK(pip);
5571 5560 ct = MDI_PI(pip)->pi_client;
5572 5561 if (!MDI_PI_IS_OFFLINE(pip)) {
5573 5562 cmn_err(CE_WARN, "mdi_phci_retire_finalize: "
5574 5563 "path %d %s busy, cannot offline",
5575 5564 mdi_pi_get_path_instance(pip),
5576 5565 mdi_pi_spathname(pip));
5577 5566 MDI_PI_UNLOCK(pip);
5578 5567 MDI_PHCI_SET_ONLINE(ph);
5579 5568 MDI_PHCI_UNLOCK(ph);
5580 5569 return;
5581 5570 }
5582 5571 MDI_PI_UNLOCK(pip);
5583 5572 pip = next;
5584 5573 }
5585 5574 MDI_PHCI_UNLOCK(ph);
5586 5575
5587 5576 return;
5588 5577 }
5589 5578
5590 5579 void
5591 5580 mdi_phci_unretire(dev_info_t *dip)
5592 5581 {
5593 5582 mdi_phci_t *ph;
5594 5583 mdi_pathinfo_t *pip;
5595 5584 mdi_pathinfo_t *next;
5596 5585
5597 5586 ASSERT(MDI_PHCI(dip));
5598 5587
5599 5588 /*
5600 5589 * Online the phci
5601 5590 */
5602 5591 i_mdi_phci_online(dip);
5603 5592
5604 5593 ph = i_devi_get_phci(dip);
5605 5594 MDI_PHCI_LOCK(ph);
5606 5595 pip = ph->ph_path_head;
5607 5596 while (pip != NULL) {
5608 5597 MDI_PI_LOCK(pip);
5609 5598 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5610 5599 MDI_PI_UNLOCK(pip);
5611 5600 (void) i_mdi_pi_online(pip, 0);
5612 5601 pip = next;
5613 5602 }
5614 5603 MDI_PHCI_UNLOCK(ph);
5615 5604 }
5616 5605
5617 5606 /*ARGSUSED*/
5618 5607 static int
5619 5608 i_mdi_client_offline(dev_info_t *dip, uint_t flags)
5620 5609 {
5621 5610 int rv = NDI_SUCCESS;
5622 5611 mdi_client_t *ct;
5623 5612
5624 5613 /*
5625 5614 * Client component to go offline. Make sure that we are
5626 5615 * not in failing over state and update client state
5627 5616 * accordingly
5628 5617 */
5629 5618 ct = i_devi_get_client(dip);
5630 5619 MDI_DEBUG(2, (MDI_NOTE, dip,
5631 5620 "called %p %p", (void *)dip, (void *)ct));
5632 5621 if (ct != NULL) {
5633 5622 MDI_CLIENT_LOCK(ct);
5634 5623 if (ct->ct_unstable) {
5635 5624 /*
5636 5625 * One or more paths are in transient state,
5637 5626 * Dont allow offline of a client device
5638 5627 */
5639 5628 MDI_DEBUG(1, (MDI_WARN, dip,
5640 5629 "!One or more paths to "
5641 5630 "this device are in transient state. "
5642 5631 "This device can not be removed at this moment. "
5643 5632 "Please try again later."));
5644 5633 MDI_CLIENT_UNLOCK(ct);
5645 5634 return (NDI_BUSY);
5646 5635 }
5647 5636 if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) {
5648 5637 /*
5649 5638 * Failover is in progress, Dont allow DR of
5650 5639 * a client device
5651 5640 */
5652 5641 MDI_DEBUG(1, (MDI_WARN, dip,
5653 5642 "!Client device is Busy. "
5654 5643 "This device can not be removed at this moment. "
5655 5644 "Please try again later."));
5656 5645 MDI_CLIENT_UNLOCK(ct);
5657 5646 return (NDI_BUSY);
5658 5647 }
5659 5648 MDI_CLIENT_SET_OFFLINE(ct);
5660 5649
5661 5650 /*
5662 5651 * Unbind our relationship with the dev_info node
5663 5652 */
5664 5653 if (flags & NDI_DEVI_REMOVE) {
5665 5654 ct->ct_dip = NULL;
5666 5655 }
5667 5656 MDI_CLIENT_UNLOCK(ct);
5668 5657 }
5669 5658 return (rv);
5670 5659 }
5671 5660
5672 5661 /*
5673 5662 * mdi_pre_attach():
5674 5663 * Pre attach() notification handler
5675 5664 */
5676 5665 /*ARGSUSED*/
5677 5666 int
5678 5667 mdi_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5679 5668 {
5680 5669 /* don't support old DDI_PM_RESUME */
5681 5670 if ((DEVI(dip)->devi_mdi_component != MDI_COMPONENT_NONE) &&
5682 5671 (cmd == DDI_PM_RESUME))
5683 5672 return (DDI_FAILURE);
5684 5673
5685 5674 return (DDI_SUCCESS);
5686 5675 }
5687 5676
5688 5677 /*
5689 5678 * mdi_post_attach():
5690 5679 * Post attach() notification handler
5691 5680 */
5692 5681 /*ARGSUSED*/
5693 5682 void
5694 5683 mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error)
5695 5684 {
5696 5685 mdi_phci_t *ph;
5697 5686 mdi_client_t *ct;
5698 5687 mdi_vhci_t *vh;
5699 5688
5700 5689 if (MDI_PHCI(dip)) {
5701 5690 ph = i_devi_get_phci(dip);
5702 5691 ASSERT(ph != NULL);
5703 5692
5704 5693 MDI_PHCI_LOCK(ph);
5705 5694 switch (cmd) {
5706 5695 case DDI_ATTACH:
5707 5696 MDI_DEBUG(2, (MDI_NOTE, dip,
5708 5697 "phci post_attach called %p", (void *)ph));
5709 5698 if (error == DDI_SUCCESS) {
5710 5699 MDI_PHCI_SET_ATTACH(ph);
5711 5700 } else {
5712 5701 MDI_DEBUG(1, (MDI_NOTE, dip,
5713 5702 "!pHCI post_attach failed: error %d",
5714 5703 error));
5715 5704 MDI_PHCI_SET_DETACH(ph);
5716 5705 }
5717 5706 break;
5718 5707
5719 5708 case DDI_RESUME:
5720 5709 MDI_DEBUG(2, (MDI_NOTE, dip,
5721 5710 "pHCI post_resume: called %p", (void *)ph));
5722 5711 if (error == DDI_SUCCESS) {
5723 5712 MDI_PHCI_SET_RESUME(ph);
5724 5713 } else {
5725 5714 MDI_DEBUG(1, (MDI_NOTE, dip,
5726 5715 "!pHCI post_resume failed: error %d",
5727 5716 error));
5728 5717 MDI_PHCI_SET_SUSPEND(ph);
5729 5718 }
5730 5719 break;
5731 5720 }
5732 5721 MDI_PHCI_UNLOCK(ph);
5733 5722 }
5734 5723
5735 5724 if (MDI_CLIENT(dip)) {
5736 5725 ct = i_devi_get_client(dip);
5737 5726 ASSERT(ct != NULL);
5738 5727
5739 5728 MDI_CLIENT_LOCK(ct);
5740 5729 switch (cmd) {
5741 5730 case DDI_ATTACH:
5742 5731 MDI_DEBUG(2, (MDI_NOTE, dip,
5743 5732 "client post_attach called %p", (void *)ct));
5744 5733 if (error != DDI_SUCCESS) {
5745 5734 MDI_DEBUG(1, (MDI_NOTE, dip,
5746 5735 "!client post_attach failed: error %d",
5747 5736 error));
5748 5737 MDI_CLIENT_SET_DETACH(ct);
5749 5738 MDI_DEBUG(4, (MDI_WARN, dip,
5750 5739 "i_mdi_pm_reset_client"));
5751 5740 i_mdi_pm_reset_client(ct);
5752 5741 break;
5753 5742 }
5754 5743
5755 5744 /*
5756 5745 * Client device has successfully attached, inform
5757 5746 * the vhci.
5758 5747 */
5759 5748 vh = ct->ct_vhci;
5760 5749 if (vh->vh_ops->vo_client_attached)
5761 5750 (*vh->vh_ops->vo_client_attached)(dip);
5762 5751
5763 5752 MDI_CLIENT_SET_ATTACH(ct);
5764 5753 break;
5765 5754
5766 5755 case DDI_RESUME:
5767 5756 MDI_DEBUG(2, (MDI_NOTE, dip,
5768 5757 "client post_attach: called %p", (void *)ct));
5769 5758 if (error == DDI_SUCCESS) {
5770 5759 MDI_CLIENT_SET_RESUME(ct);
5771 5760 } else {
5772 5761 MDI_DEBUG(1, (MDI_NOTE, dip,
5773 5762 "!client post_resume failed: error %d",
5774 5763 error));
5775 5764 MDI_CLIENT_SET_SUSPEND(ct);
5776 5765 }
5777 5766 break;
5778 5767 }
5779 5768 MDI_CLIENT_UNLOCK(ct);
5780 5769 }
5781 5770 }
5782 5771
5783 5772 /*
5784 5773 * mdi_pre_detach():
5785 5774 * Pre detach notification handler
5786 5775 */
5787 5776 /*ARGSUSED*/
5788 5777 int
5789 5778 mdi_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5790 5779 {
5791 5780 int rv = DDI_SUCCESS;
5792 5781
5793 5782 if (MDI_CLIENT(dip)) {
5794 5783 (void) i_mdi_client_pre_detach(dip, cmd);
5795 5784 }
5796 5785
5797 5786 if (MDI_PHCI(dip)) {
5798 5787 rv = i_mdi_phci_pre_detach(dip, cmd);
5799 5788 }
5800 5789
5801 5790 return (rv);
5802 5791 }
5803 5792
5804 5793 /*ARGSUSED*/
5805 5794 static int
5806 5795 i_mdi_phci_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5807 5796 {
5808 5797 int rv = DDI_SUCCESS;
5809 5798 mdi_phci_t *ph;
5810 5799 mdi_client_t *ct;
5811 5800 mdi_pathinfo_t *pip;
5812 5801 mdi_pathinfo_t *failed_pip = NULL;
5813 5802 mdi_pathinfo_t *next;
5814 5803
5815 5804 ph = i_devi_get_phci(dip);
5816 5805 if (ph == NULL) {
5817 5806 return (rv);
5818 5807 }
5819 5808
5820 5809 MDI_PHCI_LOCK(ph);
5821 5810 switch (cmd) {
5822 5811 case DDI_DETACH:
5823 5812 MDI_DEBUG(2, (MDI_NOTE, dip,
5824 5813 "pHCI pre_detach: called %p", (void *)ph));
5825 5814 if (!MDI_PHCI_IS_OFFLINE(ph)) {
5826 5815 /*
5827 5816 * mdi_pathinfo nodes are still attached to
5828 5817 * this pHCI. Fail the detach for this pHCI.
5829 5818 */
5830 5819 MDI_DEBUG(2, (MDI_WARN, dip,
5831 5820 "pHCI pre_detach: paths are still attached %p",
5832 5821 (void *)ph));
5833 5822 rv = DDI_FAILURE;
5834 5823 break;
5835 5824 }
5836 5825 MDI_PHCI_SET_DETACH(ph);
5837 5826 break;
5838 5827
5839 5828 case DDI_SUSPEND:
5840 5829 /*
5841 5830 * pHCI is getting suspended. Since mpxio client
5842 5831 * devices may not be suspended at this point, to avoid
5843 5832 * a potential stack overflow, it is important to suspend
5844 5833 * client devices before pHCI can be suspended.
5845 5834 */
5846 5835
5847 5836 MDI_DEBUG(2, (MDI_NOTE, dip,
5848 5837 "pHCI pre_suspend: called %p", (void *)ph));
5849 5838 /*
5850 5839 * Suspend all the client devices accessible through this pHCI
5851 5840 */
5852 5841 pip = ph->ph_path_head;
5853 5842 while (pip != NULL && rv == DDI_SUCCESS) {
5854 5843 dev_info_t *cdip;
5855 5844 MDI_PI_LOCK(pip);
5856 5845 next =
5857 5846 (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5858 5847 ct = MDI_PI(pip)->pi_client;
5859 5848 i_mdi_client_lock(ct, pip);
5860 5849 cdip = ct->ct_dip;
5861 5850 MDI_PI_UNLOCK(pip);
5862 5851 if ((MDI_CLIENT_IS_DETACHED(ct) == 0) &&
5863 5852 MDI_CLIENT_IS_SUSPENDED(ct) == 0) {
5864 5853 i_mdi_client_unlock(ct);
5865 5854 if ((rv = devi_detach(cdip, DDI_SUSPEND)) !=
5866 5855 DDI_SUCCESS) {
5867 5856 /*
5868 5857 * Suspend of one of the client
5869 5858 * device has failed.
5870 5859 */
5871 5860 MDI_DEBUG(1, (MDI_WARN, dip,
5872 5861 "!suspend of device (%s%d) failed.",
5873 5862 ddi_driver_name(cdip),
5874 5863 ddi_get_instance(cdip)));
5875 5864 failed_pip = pip;
5876 5865 break;
5877 5866 }
5878 5867 } else {
5879 5868 i_mdi_client_unlock(ct);
5880 5869 }
5881 5870 pip = next;
5882 5871 }
5883 5872
5884 5873 if (rv == DDI_SUCCESS) {
5885 5874 /*
5886 5875 * Suspend of client devices is complete. Proceed
5887 5876 * with pHCI suspend.
5888 5877 */
5889 5878 MDI_PHCI_SET_SUSPEND(ph);
5890 5879 } else {
5891 5880 /*
5892 5881 * Revert back all the suspended client device states
5893 5882 * to converse.
5894 5883 */
5895 5884 pip = ph->ph_path_head;
5896 5885 while (pip != failed_pip) {
5897 5886 dev_info_t *cdip;
5898 5887 MDI_PI_LOCK(pip);
5899 5888 next =
5900 5889 (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
5901 5890 ct = MDI_PI(pip)->pi_client;
5902 5891 i_mdi_client_lock(ct, pip);
5903 5892 cdip = ct->ct_dip;
5904 5893 MDI_PI_UNLOCK(pip);
5905 5894 if (MDI_CLIENT_IS_SUSPENDED(ct)) {
5906 5895 i_mdi_client_unlock(ct);
5907 5896 (void) devi_attach(cdip, DDI_RESUME);
5908 5897 } else {
5909 5898 i_mdi_client_unlock(ct);
5910 5899 }
5911 5900 pip = next;
5912 5901 }
5913 5902 }
5914 5903 break;
5915 5904
5916 5905 default:
5917 5906 rv = DDI_FAILURE;
5918 5907 break;
5919 5908 }
5920 5909 MDI_PHCI_UNLOCK(ph);
5921 5910 return (rv);
5922 5911 }
5923 5912
5924 5913 /*ARGSUSED*/
5925 5914 static int
5926 5915 i_mdi_client_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5927 5916 {
5928 5917 int rv = DDI_SUCCESS;
5929 5918 mdi_client_t *ct;
5930 5919
5931 5920 ct = i_devi_get_client(dip);
5932 5921 if (ct == NULL) {
5933 5922 return (rv);
5934 5923 }
5935 5924
5936 5925 MDI_CLIENT_LOCK(ct);
5937 5926 switch (cmd) {
5938 5927 case DDI_DETACH:
5939 5928 MDI_DEBUG(2, (MDI_NOTE, dip,
5940 5929 "client pre_detach: called %p",
5941 5930 (void *)ct));
5942 5931 MDI_CLIENT_SET_DETACH(ct);
5943 5932 break;
5944 5933
5945 5934 case DDI_SUSPEND:
5946 5935 MDI_DEBUG(2, (MDI_NOTE, dip,
5947 5936 "client pre_suspend: called %p",
5948 5937 (void *)ct));
5949 5938 MDI_CLIENT_SET_SUSPEND(ct);
5950 5939 break;
5951 5940
5952 5941 default:
5953 5942 rv = DDI_FAILURE;
5954 5943 break;
5955 5944 }
5956 5945 MDI_CLIENT_UNLOCK(ct);
5957 5946 return (rv);
5958 5947 }
5959 5948
5960 5949 /*
5961 5950 * mdi_post_detach():
5962 5951 * Post detach notification handler
5963 5952 */
5964 5953 /*ARGSUSED*/
5965 5954 void
5966 5955 mdi_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error)
5967 5956 {
5968 5957 /*
5969 5958 * Detach/Suspend of mpxio component failed. Update our state
5970 5959 * too
5971 5960 */
5972 5961 if (MDI_PHCI(dip))
5973 5962 i_mdi_phci_post_detach(dip, cmd, error);
5974 5963
5975 5964 if (MDI_CLIENT(dip))
5976 5965 i_mdi_client_post_detach(dip, cmd, error);
5977 5966 }
5978 5967
5979 5968 /*ARGSUSED*/
5980 5969 static void
5981 5970 i_mdi_phci_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error)
5982 5971 {
5983 5972 mdi_phci_t *ph;
5984 5973
5985 5974 /*
5986 5975 * Detach/Suspend of phci component failed. Update our state
5987 5976 * too
5988 5977 */
5989 5978 ph = i_devi_get_phci(dip);
5990 5979 if (ph == NULL) {
5991 5980 return;
5992 5981 }
5993 5982
5994 5983 MDI_PHCI_LOCK(ph);
5995 5984 /*
5996 5985 * Detach of pHCI failed. Restore back converse
5997 5986 * state
5998 5987 */
5999 5988 switch (cmd) {
6000 5989 case DDI_DETACH:
6001 5990 MDI_DEBUG(2, (MDI_NOTE, dip,
6002 5991 "pHCI post_detach: called %p",
6003 5992 (void *)ph));
6004 5993 if (error != DDI_SUCCESS)
6005 5994 MDI_PHCI_SET_ATTACH(ph);
6006 5995 break;
6007 5996
6008 5997 case DDI_SUSPEND:
6009 5998 MDI_DEBUG(2, (MDI_NOTE, dip,
6010 5999 "pHCI post_suspend: called %p",
6011 6000 (void *)ph));
6012 6001 if (error != DDI_SUCCESS)
6013 6002 MDI_PHCI_SET_RESUME(ph);
6014 6003 break;
6015 6004 }
6016 6005 MDI_PHCI_UNLOCK(ph);
6017 6006 }
6018 6007
6019 6008 /*ARGSUSED*/
6020 6009 static void
6021 6010 i_mdi_client_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error)
6022 6011 {
6023 6012 mdi_client_t *ct;
6024 6013
6025 6014 ct = i_devi_get_client(dip);
6026 6015 if (ct == NULL) {
6027 6016 return;
6028 6017 }
6029 6018 MDI_CLIENT_LOCK(ct);
6030 6019 /*
6031 6020 * Detach of Client failed. Restore back converse
6032 6021 * state
6033 6022 */
6034 6023 switch (cmd) {
6035 6024 case DDI_DETACH:
6036 6025 MDI_DEBUG(2, (MDI_NOTE, dip,
6037 6026 "client post_detach: called %p", (void *)ct));
6038 6027 if (DEVI_IS_ATTACHING(dip)) {
6039 6028 MDI_DEBUG(4, (MDI_NOTE, dip,
6040 6029 "i_mdi_pm_rele_client\n"));
6041 6030 i_mdi_pm_rele_client(ct, ct->ct_path_count);
6042 6031 } else {
6043 6032 MDI_DEBUG(4, (MDI_NOTE, dip,
6044 6033 "i_mdi_pm_reset_client\n"));
6045 6034 i_mdi_pm_reset_client(ct);
6046 6035 }
6047 6036 if (error != DDI_SUCCESS)
6048 6037 MDI_CLIENT_SET_ATTACH(ct);
6049 6038 break;
6050 6039
6051 6040 case DDI_SUSPEND:
6052 6041 MDI_DEBUG(2, (MDI_NOTE, dip,
6053 6042 "called %p", (void *)ct));
6054 6043 if (error != DDI_SUCCESS)
6055 6044 MDI_CLIENT_SET_RESUME(ct);
6056 6045 break;
6057 6046 }
6058 6047 MDI_CLIENT_UNLOCK(ct);
6059 6048 }
6060 6049
6061 6050 int
6062 6051 mdi_pi_kstat_exists(mdi_pathinfo_t *pip)
6063 6052 {
6064 6053 return (MDI_PI(pip)->pi_kstats ? 1 : 0);
6065 6054 }
6066 6055
6067 6056 /*
6068 6057 * create and install per-path (client - pHCI) statistics
6069 6058 * I/O stats supported: nread, nwritten, reads, and writes
6070 6059 * Error stats - hard errors, soft errors, & transport errors
6071 6060 */
6072 6061 int
6073 6062 mdi_pi_kstat_create(mdi_pathinfo_t *pip, char *ksname)
6074 6063 {
6075 6064 kstat_t *kiosp, *kerrsp;
6076 6065 struct pi_errs *nsp;
6077 6066 struct mdi_pi_kstats *mdi_statp;
6078 6067
6079 6068 if (MDI_PI(pip)->pi_kstats != NULL)
6080 6069 return (MDI_SUCCESS);
6081 6070
6082 6071 if ((kiosp = kstat_create("mdi", 0, ksname, "iopath",
6083 6072 KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT)) == NULL) {
6084 6073 return (MDI_FAILURE);
6085 6074 }
6086 6075
6087 6076 (void) strcat(ksname, ",err");
6088 6077 kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors",
6089 6078 KSTAT_TYPE_NAMED,
6090 6079 sizeof (struct pi_errs) / sizeof (kstat_named_t), 0);
6091 6080 if (kerrsp == NULL) {
6092 6081 kstat_delete(kiosp);
6093 6082 return (MDI_FAILURE);
6094 6083 }
6095 6084
6096 6085 nsp = (struct pi_errs *)kerrsp->ks_data;
6097 6086 kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32);
6098 6087 kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32);
6099 6088 kstat_named_init(&nsp->pi_transerrs, "Transport Errors",
6100 6089 KSTAT_DATA_UINT32);
6101 6090 kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy",
6102 6091 KSTAT_DATA_UINT32);
6103 6092 kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors",
6104 6093 KSTAT_DATA_UINT32);
6105 6094 kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources",
6106 6095 KSTAT_DATA_UINT32);
6107 6096 kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors",
6108 6097 KSTAT_DATA_UINT32);
6109 6098 kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State",
6110 6099 KSTAT_DATA_UINT32);
6111 6100 kstat_named_init(&nsp->pi_failedfrom, "Failed From",
6112 6101 KSTAT_DATA_UINT32);
6113 6102 kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32);
6114 6103
6115 6104 mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP);
6116 6105 mdi_statp->pi_kstat_ref = 1;
6117 6106 mdi_statp->pi_kstat_iostats = kiosp;
6118 6107 mdi_statp->pi_kstat_errstats = kerrsp;
6119 6108 kstat_install(kiosp);
6120 6109 kstat_install(kerrsp);
6121 6110 MDI_PI(pip)->pi_kstats = mdi_statp;
6122 6111 return (MDI_SUCCESS);
6123 6112 }
6124 6113
6125 6114 /*
6126 6115 * destroy per-path properties
6127 6116 */
6128 6117 static void
6129 6118 i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip)
6130 6119 {
6131 6120
6132 6121 struct mdi_pi_kstats *mdi_statp;
6133 6122
6134 6123 if (MDI_PI(pip)->pi_kstats == NULL)
6135 6124 return;
6136 6125 if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL)
6137 6126 return;
6138 6127
6139 6128 MDI_PI(pip)->pi_kstats = NULL;
6140 6129
6141 6130 /*
6142 6131 * the kstat may be shared between multiple pathinfo nodes
6143 6132 * decrement this pathinfo's usage, removing the kstats
6144 6133 * themselves when the last pathinfo reference is removed.
6145 6134 */
6146 6135 ASSERT(mdi_statp->pi_kstat_ref > 0);
6147 6136 if (--mdi_statp->pi_kstat_ref != 0)
6148 6137 return;
6149 6138
6150 6139 kstat_delete(mdi_statp->pi_kstat_iostats);
6151 6140 kstat_delete(mdi_statp->pi_kstat_errstats);
6152 6141 kmem_free(mdi_statp, sizeof (*mdi_statp));
6153 6142 }
6154 6143
6155 6144 /*
6156 6145 * update I/O paths KSTATS
6157 6146 */
6158 6147 void
6159 6148 mdi_pi_kstat_iosupdate(mdi_pathinfo_t *pip, struct buf *bp)
6160 6149 {
6161 6150 kstat_t *iostatp;
6162 6151 size_t xfer_cnt;
6163 6152
6164 6153 ASSERT(pip != NULL);
6165 6154
6166 6155 /*
6167 6156 * I/O can be driven across a path prior to having path
6168 6157 * statistics available, i.e. probe(9e).
6169 6158 */
6170 6159 if (bp != NULL && MDI_PI(pip)->pi_kstats != NULL) {
6171 6160 iostatp = MDI_PI(pip)->pi_kstats->pi_kstat_iostats;
6172 6161 xfer_cnt = bp->b_bcount - bp->b_resid;
6173 6162 if (bp->b_flags & B_READ) {
6174 6163 KSTAT_IO_PTR(iostatp)->reads++;
6175 6164 KSTAT_IO_PTR(iostatp)->nread += xfer_cnt;
6176 6165 } else {
6177 6166 KSTAT_IO_PTR(iostatp)->writes++;
6178 6167 KSTAT_IO_PTR(iostatp)->nwritten += xfer_cnt;
6179 6168 }
6180 6169 }
6181 6170 }
6182 6171
6183 6172 /*
6184 6173 * Enable the path(specific client/target/initiator)
6185 6174 * Enabling a path means that MPxIO may select the enabled path for routing
6186 6175 * future I/O requests, subject to other path state constraints.
6187 6176 */
6188 6177 int
6189 6178 mdi_pi_enable_path(mdi_pathinfo_t *pip, int flags)
6190 6179 {
6191 6180 mdi_phci_t *ph;
6192 6181
6193 6182 ph = MDI_PI(pip)->pi_phci;
6194 6183 if (ph == NULL) {
6195 6184 MDI_DEBUG(1, (MDI_NOTE, mdi_pi_get_phci(pip),
6196 6185 "!failed: path %s %p: NULL ph",
6197 6186 mdi_pi_spathname(pip), (void *)pip));
6198 6187 return (MDI_FAILURE);
6199 6188 }
6200 6189
6201 6190 (void) i_mdi_enable_disable_path(pip, ph->ph_vhci, flags,
6202 6191 MDI_ENABLE_OP);
6203 6192 MDI_DEBUG(5, (MDI_NOTE, ph->ph_dip,
6204 6193 "!returning success pip = %p. ph = %p",
6205 6194 (void *)pip, (void *)ph));
6206 6195 return (MDI_SUCCESS);
6207 6196
6208 6197 }
6209 6198
6210 6199 /*
6211 6200 * Disable the path (specific client/target/initiator)
6212 6201 * Disabling a path means that MPxIO will not select the disabled path for
6213 6202 * routing any new I/O requests.
6214 6203 */
6215 6204 int
6216 6205 mdi_pi_disable_path(mdi_pathinfo_t *pip, int flags)
6217 6206 {
6218 6207 mdi_phci_t *ph;
6219 6208
6220 6209 ph = MDI_PI(pip)->pi_phci;
6221 6210 if (ph == NULL) {
6222 6211 MDI_DEBUG(1, (MDI_NOTE, mdi_pi_get_phci(pip),
6223 6212 "!failed: path %s %p: NULL ph",
6224 6213 mdi_pi_spathname(pip), (void *)pip));
6225 6214 return (MDI_FAILURE);
6226 6215 }
6227 6216
6228 6217 (void) i_mdi_enable_disable_path(pip,
6229 6218 ph->ph_vhci, flags, MDI_DISABLE_OP);
6230 6219 MDI_DEBUG(5, (MDI_NOTE, ph->ph_dip,
6231 6220 "!returning success pip = %p. ph = %p",
6232 6221 (void *)pip, (void *)ph));
6233 6222 return (MDI_SUCCESS);
6234 6223 }
6235 6224
6236 6225 /*
6237 6226 * disable the path to a particular pHCI (pHCI specified in the phci_path
6238 6227 * argument) for a particular client (specified in the client_path argument).
6239 6228 * Disabling a path means that MPxIO will not select the disabled path for
6240 6229 * routing any new I/O requests.
6241 6230 * NOTE: this will be removed once the NWS files are changed to use the new
6242 6231 * mdi_{enable,disable}_path interfaces
6243 6232 */
6244 6233 int
6245 6234 mdi_pi_disable(dev_info_t *cdip, dev_info_t *pdip, int flags)
6246 6235 {
6247 6236 return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_DISABLE_OP));
6248 6237 }
6249 6238
6250 6239 /*
6251 6240 * Enable the path to a particular pHCI (pHCI specified in the phci_path
6252 6241 * argument) for a particular client (specified in the client_path argument).
6253 6242 * Enabling a path means that MPxIO may select the enabled path for routing
6254 6243 * future I/O requests, subject to other path state constraints.
6255 6244 * NOTE: this will be removed once the NWS files are changed to use the new
6256 6245 * mdi_{enable,disable}_path interfaces
6257 6246 */
6258 6247
6259 6248 int
6260 6249 mdi_pi_enable(dev_info_t *cdip, dev_info_t *pdip, int flags)
6261 6250 {
6262 6251 return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_ENABLE_OP));
6263 6252 }
6264 6253
6265 6254 /*
6266 6255 * Common routine for doing enable/disable.
6267 6256 */
6268 6257 static mdi_pathinfo_t *
6269 6258 i_mdi_enable_disable_path(mdi_pathinfo_t *pip, mdi_vhci_t *vh, int flags,
6270 6259 int op)
6271 6260 {
6272 6261 int sync_flag = 0;
6273 6262 int rv;
6274 6263 mdi_pathinfo_t *next;
6275 6264 int (*f)() = NULL;
6276 6265
6277 6266 /*
6278 6267 * Check to make sure the path is not already in the
6279 6268 * requested state. If it is just return the next path
6280 6269 * as we have nothing to do here.
6281 6270 */
6282 6271 if ((MDI_PI_IS_DISABLE(pip) && op == MDI_DISABLE_OP) ||
6283 6272 (!MDI_PI_IS_DISABLE(pip) && op == MDI_ENABLE_OP)) {
6284 6273 MDI_PI_LOCK(pip);
6285 6274 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
6286 6275 MDI_PI_UNLOCK(pip);
6287 6276 return (next);
6288 6277 }
6289 6278
6290 6279 f = vh->vh_ops->vo_pi_state_change;
6291 6280
6292 6281 sync_flag = (flags << 8) & 0xf00;
6293 6282
6294 6283 /*
6295 6284 * Do a callback into the mdi consumer to let it
6296 6285 * know that path is about to get enabled/disabled.
6297 6286 */
6298 6287 if (f != NULL) {
6299 6288 rv = (*f)(vh->vh_dip, pip, 0,
6300 6289 MDI_PI_EXT_STATE(pip),
6301 6290 MDI_EXT_STATE_CHANGE | sync_flag |
6302 6291 op | MDI_BEFORE_STATE_CHANGE);
6303 6292 if (rv != MDI_SUCCESS) {
6304 6293 MDI_DEBUG(2, (MDI_WARN, vh->vh_dip,
6305 6294 "vo_pi_state_change: failed rv = %x", rv));
6306 6295 }
6307 6296 }
6308 6297 MDI_PI_LOCK(pip);
6309 6298 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link;
6310 6299
6311 6300 switch (flags) {
6312 6301 case USER_DISABLE:
6313 6302 if (op == MDI_DISABLE_OP) {
6314 6303 MDI_PI_SET_USER_DISABLE(pip);
6315 6304 } else {
6316 6305 MDI_PI_SET_USER_ENABLE(pip);
6317 6306 }
6318 6307 break;
6319 6308 case DRIVER_DISABLE:
6320 6309 if (op == MDI_DISABLE_OP) {
6321 6310 MDI_PI_SET_DRV_DISABLE(pip);
6322 6311 } else {
6323 6312 MDI_PI_SET_DRV_ENABLE(pip);
6324 6313 }
6325 6314 break;
6326 6315 case DRIVER_DISABLE_TRANSIENT:
6327 6316 if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) {
6328 6317 MDI_PI_SET_DRV_DISABLE_TRANS(pip);
6329 6318 } else {
6330 6319 MDI_PI_SET_DRV_ENABLE_TRANS(pip);
6331 6320 }
6332 6321 break;
6333 6322 }
6334 6323 MDI_PI_UNLOCK(pip);
6335 6324 /*
6336 6325 * Do a callback into the mdi consumer to let it
6337 6326 * know that path is now enabled/disabled.
6338 6327 */
6339 6328 if (f != NULL) {
6340 6329 rv = (*f)(vh->vh_dip, pip, 0,
6341 6330 MDI_PI_EXT_STATE(pip),
6342 6331 MDI_EXT_STATE_CHANGE | sync_flag |
6343 6332 op | MDI_AFTER_STATE_CHANGE);
6344 6333 if (rv != MDI_SUCCESS) {
6345 6334 MDI_DEBUG(2, (MDI_WARN, vh->vh_dip,
6346 6335 "vo_pi_state_change failed: rv = %x", rv));
6347 6336 }
6348 6337 }
6349 6338 return (next);
6350 6339 }
6351 6340
6352 6341 /*
6353 6342 * Common routine for doing enable/disable.
6354 6343 * NOTE: this will be removed once the NWS files are changed to use the new
6355 6344 * mdi_{enable,disable}_path has been putback
6356 6345 */
6357 6346 int
6358 6347 i_mdi_pi_enable_disable(dev_info_t *cdip, dev_info_t *pdip, int flags, int op)
6359 6348 {
6360 6349
6361 6350 mdi_phci_t *ph;
6362 6351 mdi_vhci_t *vh = NULL;
6363 6352 mdi_client_t *ct;
6364 6353 mdi_pathinfo_t *next, *pip;
6365 6354 int found_it;
6366 6355
6367 6356 ph = i_devi_get_phci(pdip);
6368 6357 MDI_DEBUG(5, (MDI_NOTE, cdip ? cdip : pdip,
6369 6358 "!op = %d pdip = %p cdip = %p", op, (void *)pdip,
6370 6359 (void *)cdip));
6371 6360 if (ph == NULL) {
6372 6361 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip,
6373 6362 "!failed: operation %d: NULL ph", op));
6374 6363 return (MDI_FAILURE);
6375 6364 }
6376 6365
6377 6366 if ((op != MDI_ENABLE_OP) && (op != MDI_DISABLE_OP)) {
6378 6367 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip,
6379 6368 "!failed: invalid operation %d", op));
6380 6369 return (MDI_FAILURE);
6381 6370 }
6382 6371
6383 6372 vh = ph->ph_vhci;
6384 6373
6385 6374 if (cdip == NULL) {
6386 6375 /*
6387 6376 * Need to mark the Phci as enabled/disabled.
6388 6377 */
6389 6378 MDI_DEBUG(4, (MDI_NOTE, cdip ? cdip : pdip,
6390 6379 "op %d for the phci", op));
6391 6380 MDI_PHCI_LOCK(ph);
6392 6381 switch (flags) {
6393 6382 case USER_DISABLE:
6394 6383 if (op == MDI_DISABLE_OP) {
6395 6384 MDI_PHCI_SET_USER_DISABLE(ph);
6396 6385 } else {
6397 6386 MDI_PHCI_SET_USER_ENABLE(ph);
6398 6387 }
6399 6388 break;
6400 6389 case DRIVER_DISABLE:
6401 6390 if (op == MDI_DISABLE_OP) {
6402 6391 MDI_PHCI_SET_DRV_DISABLE(ph);
6403 6392 } else {
6404 6393 MDI_PHCI_SET_DRV_ENABLE(ph);
6405 6394 }
6406 6395 break;
6407 6396 case DRIVER_DISABLE_TRANSIENT:
6408 6397 if (op == MDI_DISABLE_OP) {
6409 6398 MDI_PHCI_SET_DRV_DISABLE_TRANSIENT(ph);
6410 6399 } else {
6411 6400 MDI_PHCI_SET_DRV_ENABLE_TRANSIENT(ph);
6412 6401 }
6413 6402 break;
6414 6403 default:
6415 6404 MDI_PHCI_UNLOCK(ph);
6416 6405 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip,
6417 6406 "!invalid flag argument= %d", flags));
6418 6407 }
6419 6408
6420 6409 /*
6421 6410 * Phci has been disabled. Now try to enable/disable
6422 6411 * path info's to each client.
6423 6412 */
6424 6413 pip = ph->ph_path_head;
6425 6414 while (pip != NULL) {
6426 6415 pip = i_mdi_enable_disable_path(pip, vh, flags, op);
6427 6416 }
6428 6417 MDI_PHCI_UNLOCK(ph);
6429 6418 } else {
6430 6419
6431 6420 /*
6432 6421 * Disable a specific client.
6433 6422 */
6434 6423 ct = i_devi_get_client(cdip);
6435 6424 if (ct == NULL) {
6436 6425 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip,
6437 6426 "!failed: operation = %d: NULL ct", op));
6438 6427 return (MDI_FAILURE);
6439 6428 }
6440 6429
6441 6430 MDI_CLIENT_LOCK(ct);
6442 6431 pip = ct->ct_path_head;
6443 6432 found_it = 0;
6444 6433 while (pip != NULL) {
6445 6434 MDI_PI_LOCK(pip);
6446 6435 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
6447 6436 if (MDI_PI(pip)->pi_phci == ph) {
6448 6437 MDI_PI_UNLOCK(pip);
6449 6438 found_it = 1;
6450 6439 break;
6451 6440 }
6452 6441 MDI_PI_UNLOCK(pip);
6453 6442 pip = next;
6454 6443 }
6455 6444
6456 6445
6457 6446 MDI_CLIENT_UNLOCK(ct);
6458 6447 if (found_it == 0) {
6459 6448 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip,
6460 6449 "!failed. Could not find corresponding pip\n"));
6461 6450 return (MDI_FAILURE);
6462 6451 }
6463 6452
6464 6453 (void) i_mdi_enable_disable_path(pip, vh, flags, op);
6465 6454 }
6466 6455
6467 6456 MDI_DEBUG(5, (MDI_NOTE, cdip ? cdip : pdip,
6468 6457 "!op %d returning success pdip = %p cdip = %p",
6469 6458 op, (void *)pdip, (void *)cdip));
6470 6459 return (MDI_SUCCESS);
6471 6460 }
6472 6461
6473 6462 /*
6474 6463 * Ensure phci powered up
6475 6464 */
6476 6465 static void
6477 6466 i_mdi_pm_hold_pip(mdi_pathinfo_t *pip)
6478 6467 {
6479 6468 dev_info_t *ph_dip;
6480 6469
6481 6470 ASSERT(pip != NULL);
6482 6471 ASSERT(MDI_PI_LOCKED(pip));
6483 6472
6484 6473 if (MDI_PI(pip)->pi_pm_held) {
6485 6474 return;
6486 6475 }
6487 6476
6488 6477 ph_dip = mdi_pi_get_phci(pip);
6489 6478 MDI_DEBUG(4, (MDI_NOTE, ph_dip,
6490 6479 "%s %p", mdi_pi_spathname(pip), (void *)pip));
6491 6480 if (ph_dip == NULL) {
6492 6481 return;
6493 6482 }
6494 6483
6495 6484 MDI_PI_UNLOCK(pip);
6496 6485 MDI_DEBUG(4, (MDI_NOTE, ph_dip, "kidsupcnt was %d",
6497 6486 DEVI(ph_dip)->devi_pm_kidsupcnt));
6498 6487 pm_hold_power(ph_dip);
6499 6488 MDI_DEBUG(4, (MDI_NOTE, ph_dip, "kidsupcnt is %d",
6500 6489 DEVI(ph_dip)->devi_pm_kidsupcnt));
6501 6490 MDI_PI_LOCK(pip);
6502 6491
6503 6492 /* If PM_GET_PM_INFO is NULL the pm_hold_power above was a noop */
6504 6493 if (DEVI(ph_dip)->devi_pm_info)
6505 6494 MDI_PI(pip)->pi_pm_held = 1;
6506 6495 }
6507 6496
6508 6497 /*
6509 6498 * Allow phci powered down
6510 6499 */
6511 6500 static void
6512 6501 i_mdi_pm_rele_pip(mdi_pathinfo_t *pip)
6513 6502 {
6514 6503 dev_info_t *ph_dip = NULL;
6515 6504
6516 6505 ASSERT(pip != NULL);
6517 6506 ASSERT(MDI_PI_LOCKED(pip));
6518 6507
6519 6508 if (MDI_PI(pip)->pi_pm_held == 0) {
6520 6509 return;
6521 6510 }
6522 6511
6523 6512 ph_dip = mdi_pi_get_phci(pip);
6524 6513 ASSERT(ph_dip != NULL);
6525 6514
6526 6515 MDI_DEBUG(4, (MDI_NOTE, ph_dip,
6527 6516 "%s %p", mdi_pi_spathname(pip), (void *)pip));
6528 6517
6529 6518 MDI_PI_UNLOCK(pip);
6530 6519 MDI_DEBUG(4, (MDI_NOTE, ph_dip,
6531 6520 "kidsupcnt was %d", DEVI(ph_dip)->devi_pm_kidsupcnt));
6532 6521 pm_rele_power(ph_dip);
6533 6522 MDI_DEBUG(4, (MDI_NOTE, ph_dip,
6534 6523 "kidsupcnt is %d", DEVI(ph_dip)->devi_pm_kidsupcnt));
6535 6524 MDI_PI_LOCK(pip);
6536 6525
6537 6526 MDI_PI(pip)->pi_pm_held = 0;
6538 6527 }
6539 6528
6540 6529 static void
6541 6530 i_mdi_pm_hold_client(mdi_client_t *ct, int incr)
6542 6531 {
6543 6532 ASSERT(MDI_CLIENT_LOCKED(ct));
6544 6533
6545 6534 ct->ct_power_cnt += incr;
6546 6535 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
6547 6536 "%p ct_power_cnt = %d incr = %d",
6548 6537 (void *)ct, ct->ct_power_cnt, incr));
6549 6538 ASSERT(ct->ct_power_cnt >= 0);
6550 6539 }
6551 6540
6552 6541 static void
6553 6542 i_mdi_rele_all_phci(mdi_client_t *ct)
6554 6543 {
6555 6544 mdi_pathinfo_t *pip;
6556 6545
6557 6546 ASSERT(MDI_CLIENT_LOCKED(ct));
6558 6547 pip = (mdi_pathinfo_t *)ct->ct_path_head;
6559 6548 while (pip != NULL) {
6560 6549 mdi_hold_path(pip);
6561 6550 MDI_PI_LOCK(pip);
6562 6551 i_mdi_pm_rele_pip(pip);
6563 6552 MDI_PI_UNLOCK(pip);
6564 6553 mdi_rele_path(pip);
6565 6554 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
6566 6555 }
6567 6556 }
6568 6557
6569 6558 static void
6570 6559 i_mdi_pm_rele_client(mdi_client_t *ct, int decr)
6571 6560 {
6572 6561 ASSERT(MDI_CLIENT_LOCKED(ct));
6573 6562
6574 6563 if (i_ddi_devi_attached(ct->ct_dip)) {
6575 6564 ct->ct_power_cnt -= decr;
6576 6565 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
6577 6566 "%p ct_power_cnt = %d decr = %d",
6578 6567 (void *)ct, ct->ct_power_cnt, decr));
6579 6568 }
6580 6569
6581 6570 ASSERT(ct->ct_power_cnt >= 0);
6582 6571 if (ct->ct_power_cnt == 0) {
6583 6572 i_mdi_rele_all_phci(ct);
6584 6573 return;
6585 6574 }
6586 6575 }
6587 6576
6588 6577 static void
6589 6578 i_mdi_pm_reset_client(mdi_client_t *ct)
6590 6579 {
6591 6580 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip,
6592 6581 "%p ct_power_cnt = %d", (void *)ct, ct->ct_power_cnt));
6593 6582 ASSERT(MDI_CLIENT_LOCKED(ct));
6594 6583 ct->ct_power_cnt = 0;
6595 6584 i_mdi_rele_all_phci(ct);
6596 6585 ct->ct_powercnt_config = 0;
6597 6586 ct->ct_powercnt_unconfig = 0;
6598 6587 ct->ct_powercnt_reset = 1;
6599 6588 }
6600 6589
6601 6590 static int
6602 6591 i_mdi_power_one_phci(mdi_pathinfo_t *pip)
6603 6592 {
6604 6593 int ret;
6605 6594 dev_info_t *ph_dip;
6606 6595
6607 6596 MDI_PI_LOCK(pip);
6608 6597 i_mdi_pm_hold_pip(pip);
6609 6598
6610 6599 ph_dip = mdi_pi_get_phci(pip);
6611 6600 MDI_PI_UNLOCK(pip);
6612 6601
6613 6602 /* bring all components of phci to full power */
6614 6603 MDI_DEBUG(4, (MDI_NOTE, ph_dip,
6615 6604 "pm_powerup for %s%d %p", ddi_driver_name(ph_dip),
6616 6605 ddi_get_instance(ph_dip), (void *)pip));
6617 6606
6618 6607 ret = pm_powerup(ph_dip);
6619 6608
6620 6609 if (ret == DDI_FAILURE) {
6621 6610 MDI_DEBUG(4, (MDI_NOTE, ph_dip,
6622 6611 "pm_powerup FAILED for %s%d %p",
6623 6612 ddi_driver_name(ph_dip), ddi_get_instance(ph_dip),
6624 6613 (void *)pip));
6625 6614
6626 6615 MDI_PI_LOCK(pip);
6627 6616 i_mdi_pm_rele_pip(pip);
6628 6617 MDI_PI_UNLOCK(pip);
6629 6618 return (MDI_FAILURE);
6630 6619 }
6631 6620
6632 6621 return (MDI_SUCCESS);
6633 6622 }
6634 6623
6635 6624 static int
6636 6625 i_mdi_power_all_phci(mdi_client_t *ct)
6637 6626 {
6638 6627 mdi_pathinfo_t *pip;
6639 6628 int succeeded = 0;
6640 6629
6641 6630 ASSERT(MDI_CLIENT_LOCKED(ct));
6642 6631 pip = (mdi_pathinfo_t *)ct->ct_path_head;
6643 6632 while (pip != NULL) {
6644 6633 /*
6645 6634 * Don't power if MDI_PATHINFO_STATE_FAULT
6646 6635 * or MDI_PATHINFO_STATE_OFFLINE.
6647 6636 */
6648 6637 if (MDI_PI_IS_INIT(pip) ||
6649 6638 MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip)) {
6650 6639 mdi_hold_path(pip);
6651 6640 MDI_CLIENT_UNLOCK(ct);
6652 6641 if (i_mdi_power_one_phci(pip) == MDI_SUCCESS)
6653 6642 succeeded = 1;
6654 6643
6655 6644 ASSERT(ct == MDI_PI(pip)->pi_client);
6656 6645 MDI_CLIENT_LOCK(ct);
6657 6646 mdi_rele_path(pip);
6658 6647 }
6659 6648 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
6660 6649 }
6661 6650
6662 6651 return (succeeded ? MDI_SUCCESS : MDI_FAILURE);
6663 6652 }
6664 6653
6665 6654 /*
6666 6655 * mdi_bus_power():
6667 6656 * 1. Place the phci(s) into powered up state so that
6668 6657 * client can do power management
6669 6658 * 2. Ensure phci powered up as client power managing
6670 6659 * Return Values:
6671 6660 * MDI_SUCCESS
6672 6661 * MDI_FAILURE
6673 6662 */
6674 6663 int
6675 6664 mdi_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op,
6676 6665 void *arg, void *result)
6677 6666 {
6678 6667 int ret = MDI_SUCCESS;
6679 6668 pm_bp_child_pwrchg_t *bpc;
6680 6669 mdi_client_t *ct;
6681 6670 dev_info_t *cdip;
6682 6671 pm_bp_has_changed_t *bphc;
6683 6672
6684 6673 /*
6685 6674 * BUS_POWER_NOINVOL not supported
6686 6675 */
6687 6676 if (op == BUS_POWER_NOINVOL)
6688 6677 return (MDI_FAILURE);
6689 6678
6690 6679 /*
6691 6680 * ignore other OPs.
6692 6681 * return quickly to save cou cycles on the ct processing
6693 6682 */
6694 6683 switch (op) {
6695 6684 case BUS_POWER_PRE_NOTIFICATION:
6696 6685 case BUS_POWER_POST_NOTIFICATION:
6697 6686 bpc = (pm_bp_child_pwrchg_t *)arg;
6698 6687 cdip = bpc->bpc_dip;
6699 6688 break;
6700 6689 case BUS_POWER_HAS_CHANGED:
6701 6690 bphc = (pm_bp_has_changed_t *)arg;
6702 6691 cdip = bphc->bphc_dip;
6703 6692 break;
6704 6693 default:
6705 6694 return (pm_busop_bus_power(parent, impl_arg, op, arg, result));
6706 6695 }
6707 6696
6708 6697 ASSERT(MDI_CLIENT(cdip));
6709 6698
6710 6699 ct = i_devi_get_client(cdip);
6711 6700 if (ct == NULL)
6712 6701 return (MDI_FAILURE);
6713 6702
6714 6703 /*
6715 6704 * wait till the mdi_pathinfo node state change are processed
6716 6705 */
6717 6706 MDI_CLIENT_LOCK(ct);
6718 6707 switch (op) {
6719 6708 case BUS_POWER_PRE_NOTIFICATION:
6720 6709 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip,
6721 6710 "BUS_POWER_PRE_NOTIFICATION:"
6722 6711 "%s@%s, olevel=%d, nlevel=%d, comp=%d",
6723 6712 ddi_node_name(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip),
6724 6713 bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp));
6725 6714
6726 6715 /* serialize power level change per client */
6727 6716 while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
6728 6717 cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
6729 6718
6730 6719 MDI_CLIENT_SET_POWER_TRANSITION(ct);
6731 6720
6732 6721 if (ct->ct_power_cnt == 0) {
6733 6722 ret = i_mdi_power_all_phci(ct);
6734 6723 }
6735 6724
6736 6725 /*
6737 6726 * if new_level > 0:
6738 6727 * - hold phci(s)
6739 6728 * - power up phci(s) if not already
6740 6729 * ignore power down
6741 6730 */
6742 6731 if (bpc->bpc_nlevel > 0) {
6743 6732 if (!DEVI_IS_ATTACHING(ct->ct_dip)) {
6744 6733 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip,
6745 6734 "i_mdi_pm_hold_client\n"));
6746 6735 i_mdi_pm_hold_client(ct, ct->ct_path_count);
6747 6736 }
6748 6737 }
6749 6738 break;
6750 6739 case BUS_POWER_POST_NOTIFICATION:
6751 6740 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip,
6752 6741 "BUS_POWER_POST_NOTIFICATION:"
6753 6742 "%s@%s, olevel=%d, nlevel=%d, comp=%d result=%d",
6754 6743 ddi_node_name(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip),
6755 6744 bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp,
6756 6745 *(int *)result));
6757 6746
6758 6747 if (*(int *)result == DDI_SUCCESS) {
6759 6748 if (bpc->bpc_nlevel > 0) {
6760 6749 MDI_CLIENT_SET_POWER_UP(ct);
6761 6750 } else {
6762 6751 MDI_CLIENT_SET_POWER_DOWN(ct);
6763 6752 }
6764 6753 }
6765 6754
6766 6755 /* release the hold we did in pre-notification */
6767 6756 if (bpc->bpc_nlevel > 0 && (*(int *)result != DDI_SUCCESS) &&
6768 6757 !DEVI_IS_ATTACHING(ct->ct_dip)) {
6769 6758 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip,
6770 6759 "i_mdi_pm_rele_client\n"));
6771 6760 i_mdi_pm_rele_client(ct, ct->ct_path_count);
6772 6761 }
6773 6762
6774 6763 if (bpc->bpc_nlevel == 0 && (*(int *)result == DDI_SUCCESS)) {
6775 6764 /* another thread might started attaching */
6776 6765 if (DEVI_IS_ATTACHING(ct->ct_dip)) {
6777 6766 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip,
6778 6767 "i_mdi_pm_rele_client\n"));
6779 6768 i_mdi_pm_rele_client(ct, ct->ct_path_count);
6780 6769 /* detaching has been taken care in pm_post_unconfig */
6781 6770 } else if (!DEVI_IS_DETACHING(ct->ct_dip)) {
6782 6771 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip,
6783 6772 "i_mdi_pm_reset_client\n"));
6784 6773 i_mdi_pm_reset_client(ct);
6785 6774 }
6786 6775 }
6787 6776
6788 6777 MDI_CLIENT_CLEAR_POWER_TRANSITION(ct);
6789 6778 cv_broadcast(&ct->ct_powerchange_cv);
6790 6779
6791 6780 break;
6792 6781
6793 6782 /* need to do more */
6794 6783 case BUS_POWER_HAS_CHANGED:
6795 6784 MDI_DEBUG(4, (MDI_NOTE, bphc->bphc_dip,
6796 6785 "BUS_POWER_HAS_CHANGED:"
6797 6786 "%s@%s, olevel=%d, nlevel=%d, comp=%d",
6798 6787 ddi_node_name(bphc->bphc_dip), PM_ADDR(bphc->bphc_dip),
6799 6788 bphc->bphc_olevel, bphc->bphc_nlevel, bphc->bphc_comp));
6800 6789
6801 6790 if (bphc->bphc_nlevel > 0 &&
6802 6791 bphc->bphc_nlevel > bphc->bphc_olevel) {
6803 6792 if (ct->ct_power_cnt == 0) {
6804 6793 ret = i_mdi_power_all_phci(ct);
6805 6794 }
6806 6795 MDI_DEBUG(4, (MDI_NOTE, bphc->bphc_dip,
6807 6796 "i_mdi_pm_hold_client\n"));
6808 6797 i_mdi_pm_hold_client(ct, ct->ct_path_count);
6809 6798 }
6810 6799
6811 6800 if (bphc->bphc_nlevel == 0 && bphc->bphc_olevel != -1) {
6812 6801 MDI_DEBUG(4, (MDI_NOTE, bphc->bphc_dip,
6813 6802 "i_mdi_pm_rele_client\n"));
6814 6803 i_mdi_pm_rele_client(ct, ct->ct_path_count);
6815 6804 }
6816 6805 break;
6817 6806 }
6818 6807
6819 6808 MDI_CLIENT_UNLOCK(ct);
6820 6809 return (ret);
6821 6810 }
6822 6811
6823 6812 static int
6824 6813 i_mdi_pm_pre_config_one(dev_info_t *child)
6825 6814 {
6826 6815 int ret = MDI_SUCCESS;
6827 6816 mdi_client_t *ct;
6828 6817
6829 6818 ct = i_devi_get_client(child);
6830 6819 if (ct == NULL)
6831 6820 return (MDI_FAILURE);
6832 6821
6833 6822 MDI_CLIENT_LOCK(ct);
6834 6823 while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
6835 6824 cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
6836 6825
6837 6826 if (!MDI_CLIENT_IS_FAILED(ct)) {
6838 6827 MDI_CLIENT_UNLOCK(ct);
6839 6828 MDI_DEBUG(4, (MDI_NOTE, child, "already configured\n"));
6840 6829 return (MDI_SUCCESS);
6841 6830 }
6842 6831
6843 6832 if (ct->ct_powercnt_config) {
6844 6833 MDI_CLIENT_UNLOCK(ct);
6845 6834 MDI_DEBUG(4, (MDI_NOTE, child, "already held\n"));
6846 6835 return (MDI_SUCCESS);
6847 6836 }
6848 6837
6849 6838 if (ct->ct_power_cnt == 0) {
6850 6839 ret = i_mdi_power_all_phci(ct);
6851 6840 }
6852 6841 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_hold_client\n"));
6853 6842 i_mdi_pm_hold_client(ct, ct->ct_path_count);
6854 6843 ct->ct_powercnt_config = 1;
6855 6844 ct->ct_powercnt_reset = 0;
6856 6845 MDI_CLIENT_UNLOCK(ct);
6857 6846 return (ret);
6858 6847 }
6859 6848
6860 6849 static int
6861 6850 i_mdi_pm_pre_config(dev_info_t *vdip, dev_info_t *child)
6862 6851 {
6863 6852 int ret = MDI_SUCCESS;
6864 6853 dev_info_t *cdip;
6865 6854 int circ;
6866 6855
6867 6856 ASSERT(MDI_VHCI(vdip));
6868 6857
6869 6858 /* ndi_devi_config_one */
6870 6859 if (child) {
6871 6860 ASSERT(DEVI_BUSY_OWNED(vdip));
6872 6861 return (i_mdi_pm_pre_config_one(child));
6873 6862 }
6874 6863
6875 6864 /* devi_config_common */
6876 6865 ndi_devi_enter(vdip, &circ);
6877 6866 cdip = ddi_get_child(vdip);
6878 6867 while (cdip) {
6879 6868 dev_info_t *next = ddi_get_next_sibling(cdip);
6880 6869
6881 6870 ret = i_mdi_pm_pre_config_one(cdip);
6882 6871 if (ret != MDI_SUCCESS)
6883 6872 break;
6884 6873 cdip = next;
6885 6874 }
6886 6875 ndi_devi_exit(vdip, circ);
6887 6876 return (ret);
6888 6877 }
6889 6878
6890 6879 static int
6891 6880 i_mdi_pm_pre_unconfig_one(dev_info_t *child, int *held, int flags)
6892 6881 {
6893 6882 int ret = MDI_SUCCESS;
6894 6883 mdi_client_t *ct;
6895 6884
6896 6885 ct = i_devi_get_client(child);
6897 6886 if (ct == NULL)
6898 6887 return (MDI_FAILURE);
6899 6888
6900 6889 MDI_CLIENT_LOCK(ct);
6901 6890 while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
6902 6891 cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
6903 6892
6904 6893 if (!i_ddi_devi_attached(child)) {
6905 6894 MDI_DEBUG(4, (MDI_NOTE, child, "node detached already\n"));
6906 6895 MDI_CLIENT_UNLOCK(ct);
6907 6896 return (MDI_SUCCESS);
6908 6897 }
6909 6898
6910 6899 if (MDI_CLIENT_IS_POWERED_DOWN(ct) &&
6911 6900 (flags & NDI_AUTODETACH)) {
6912 6901 MDI_DEBUG(4, (MDI_NOTE, child, "auto-modunload\n"));
6913 6902 MDI_CLIENT_UNLOCK(ct);
6914 6903 return (MDI_FAILURE);
6915 6904 }
6916 6905
6917 6906 if (ct->ct_powercnt_unconfig) {
6918 6907 MDI_DEBUG(4, (MDI_NOTE, child, "ct_powercnt_held\n"));
6919 6908 MDI_CLIENT_UNLOCK(ct);
6920 6909 *held = 1;
6921 6910 return (MDI_SUCCESS);
6922 6911 }
6923 6912
6924 6913 if (ct->ct_power_cnt == 0) {
6925 6914 ret = i_mdi_power_all_phci(ct);
6926 6915 }
6927 6916 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_hold_client\n"));
6928 6917 i_mdi_pm_hold_client(ct, ct->ct_path_count);
6929 6918 ct->ct_powercnt_unconfig = 1;
6930 6919 ct->ct_powercnt_reset = 0;
6931 6920 MDI_CLIENT_UNLOCK(ct);
6932 6921 if (ret == MDI_SUCCESS)
6933 6922 *held = 1;
6934 6923 return (ret);
6935 6924 }
6936 6925
6937 6926 static int
6938 6927 i_mdi_pm_pre_unconfig(dev_info_t *vdip, dev_info_t *child, int *held,
6939 6928 int flags)
6940 6929 {
6941 6930 int ret = MDI_SUCCESS;
6942 6931 dev_info_t *cdip;
6943 6932 int circ;
6944 6933
6945 6934 ASSERT(MDI_VHCI(vdip));
6946 6935 *held = 0;
6947 6936
6948 6937 /* ndi_devi_unconfig_one */
6949 6938 if (child) {
6950 6939 ASSERT(DEVI_BUSY_OWNED(vdip));
6951 6940 return (i_mdi_pm_pre_unconfig_one(child, held, flags));
6952 6941 }
6953 6942
6954 6943 /* devi_unconfig_common */
6955 6944 ndi_devi_enter(vdip, &circ);
6956 6945 cdip = ddi_get_child(vdip);
6957 6946 while (cdip) {
6958 6947 dev_info_t *next = ddi_get_next_sibling(cdip);
6959 6948
6960 6949 ret = i_mdi_pm_pre_unconfig_one(cdip, held, flags);
6961 6950 cdip = next;
6962 6951 }
6963 6952 ndi_devi_exit(vdip, circ);
6964 6953
6965 6954 if (*held)
6966 6955 ret = MDI_SUCCESS;
6967 6956
6968 6957 return (ret);
6969 6958 }
6970 6959
6971 6960 static void
6972 6961 i_mdi_pm_post_config_one(dev_info_t *child)
6973 6962 {
6974 6963 mdi_client_t *ct;
6975 6964
6976 6965 ct = i_devi_get_client(child);
6977 6966 if (ct == NULL)
6978 6967 return;
6979 6968
6980 6969 MDI_CLIENT_LOCK(ct);
6981 6970 while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
6982 6971 cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
6983 6972
6984 6973 if (ct->ct_powercnt_reset || !ct->ct_powercnt_config) {
6985 6974 MDI_DEBUG(4, (MDI_NOTE, child, "not configured\n"));
6986 6975 MDI_CLIENT_UNLOCK(ct);
6987 6976 return;
6988 6977 }
6989 6978
6990 6979 /* client has not been updated */
6991 6980 if (MDI_CLIENT_IS_FAILED(ct)) {
6992 6981 MDI_DEBUG(4, (MDI_NOTE, child, "client failed\n"));
6993 6982 MDI_CLIENT_UNLOCK(ct);
6994 6983 return;
6995 6984 }
6996 6985
6997 6986 /* another thread might have powered it down or detached it */
6998 6987 if ((MDI_CLIENT_IS_POWERED_DOWN(ct) &&
6999 6988 !DEVI_IS_ATTACHING(child)) ||
7000 6989 (!i_ddi_devi_attached(child) &&
7001 6990 !DEVI_IS_ATTACHING(child))) {
7002 6991 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_reset_client\n"));
7003 6992 i_mdi_pm_reset_client(ct);
7004 6993 } else {
7005 6994 mdi_pathinfo_t *pip, *next;
7006 6995 int valid_path_count = 0;
7007 6996
7008 6997 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_rele_client\n"));
7009 6998 pip = ct->ct_path_head;
7010 6999 while (pip != NULL) {
7011 7000 MDI_PI_LOCK(pip);
7012 7001 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
7013 7002 if (MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip))
7014 7003 valid_path_count ++;
7015 7004 MDI_PI_UNLOCK(pip);
7016 7005 pip = next;
7017 7006 }
7018 7007 i_mdi_pm_rele_client(ct, valid_path_count);
7019 7008 }
7020 7009 ct->ct_powercnt_config = 0;
7021 7010 MDI_CLIENT_UNLOCK(ct);
7022 7011 }
7023 7012
7024 7013 static void
7025 7014 i_mdi_pm_post_config(dev_info_t *vdip, dev_info_t *child)
7026 7015 {
7027 7016 int circ;
7028 7017 dev_info_t *cdip;
7029 7018
7030 7019 ASSERT(MDI_VHCI(vdip));
7031 7020
7032 7021 /* ndi_devi_config_one */
7033 7022 if (child) {
7034 7023 ASSERT(DEVI_BUSY_OWNED(vdip));
7035 7024 i_mdi_pm_post_config_one(child);
7036 7025 return;
7037 7026 }
7038 7027
7039 7028 /* devi_config_common */
7040 7029 ndi_devi_enter(vdip, &circ);
7041 7030 cdip = ddi_get_child(vdip);
7042 7031 while (cdip) {
7043 7032 dev_info_t *next = ddi_get_next_sibling(cdip);
7044 7033
7045 7034 i_mdi_pm_post_config_one(cdip);
7046 7035 cdip = next;
7047 7036 }
7048 7037 ndi_devi_exit(vdip, circ);
7049 7038 }
7050 7039
7051 7040 static void
7052 7041 i_mdi_pm_post_unconfig_one(dev_info_t *child)
7053 7042 {
7054 7043 mdi_client_t *ct;
7055 7044
7056 7045 ct = i_devi_get_client(child);
7057 7046 if (ct == NULL)
7058 7047 return;
7059 7048
7060 7049 MDI_CLIENT_LOCK(ct);
7061 7050 while (MDI_CLIENT_IS_POWER_TRANSITION(ct))
7062 7051 cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex);
7063 7052
7064 7053 if (!ct->ct_powercnt_unconfig || ct->ct_powercnt_reset) {
7065 7054 MDI_DEBUG(4, (MDI_NOTE, child, "not held\n"));
7066 7055 MDI_CLIENT_UNLOCK(ct);
7067 7056 return;
7068 7057 }
7069 7058
7070 7059 /* failure detaching or another thread just attached it */
7071 7060 if ((MDI_CLIENT_IS_POWERED_DOWN(ct) &&
7072 7061 i_ddi_devi_attached(child)) ||
7073 7062 (!i_ddi_devi_attached(child) &&
7074 7063 !DEVI_IS_ATTACHING(child))) {
7075 7064 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_reset_client\n"));
7076 7065 i_mdi_pm_reset_client(ct);
7077 7066 } else {
7078 7067 mdi_pathinfo_t *pip, *next;
7079 7068 int valid_path_count = 0;
7080 7069
7081 7070 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_rele_client\n"));
7082 7071 pip = ct->ct_path_head;
7083 7072 while (pip != NULL) {
7084 7073 MDI_PI_LOCK(pip);
7085 7074 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link;
7086 7075 if (MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip))
7087 7076 valid_path_count ++;
7088 7077 MDI_PI_UNLOCK(pip);
7089 7078 pip = next;
7090 7079 }
7091 7080 i_mdi_pm_rele_client(ct, valid_path_count);
7092 7081 ct->ct_powercnt_unconfig = 0;
7093 7082 }
7094 7083
7095 7084 MDI_CLIENT_UNLOCK(ct);
7096 7085 }
7097 7086
7098 7087 static void
7099 7088 i_mdi_pm_post_unconfig(dev_info_t *vdip, dev_info_t *child, int held)
7100 7089 {
7101 7090 int circ;
7102 7091 dev_info_t *cdip;
7103 7092
7104 7093 ASSERT(MDI_VHCI(vdip));
7105 7094
7106 7095 if (!held) {
7107 7096 MDI_DEBUG(4, (MDI_NOTE, vdip, "held = %d", held));
7108 7097 return;
7109 7098 }
7110 7099
7111 7100 if (child) {
7112 7101 ASSERT(DEVI_BUSY_OWNED(vdip));
7113 7102 i_mdi_pm_post_unconfig_one(child);
7114 7103 return;
7115 7104 }
7116 7105
7117 7106 ndi_devi_enter(vdip, &circ);
7118 7107 cdip = ddi_get_child(vdip);
7119 7108 while (cdip) {
7120 7109 dev_info_t *next = ddi_get_next_sibling(cdip);
7121 7110
7122 7111 i_mdi_pm_post_unconfig_one(cdip);
7123 7112 cdip = next;
7124 7113 }
7125 7114 ndi_devi_exit(vdip, circ);
7126 7115 }
7127 7116
7128 7117 int
7129 7118 mdi_power(dev_info_t *vdip, mdi_pm_op_t op, void *args, char *devnm, int flags)
7130 7119 {
7131 7120 int circ, ret = MDI_SUCCESS;
7132 7121 dev_info_t *client_dip = NULL;
7133 7122 mdi_client_t *ct;
7134 7123
7135 7124 /*
7136 7125 * Handling ndi_devi_config_one and ndi_devi_unconfig_one.
7137 7126 * Power up pHCI for the named client device.
7138 7127 * Note: Before the client is enumerated under vhci by phci,
7139 7128 * client_dip can be NULL. Then proceed to power up all the
7140 7129 * pHCIs.
7141 7130 */
7142 7131 if (devnm != NULL) {
7143 7132 ndi_devi_enter(vdip, &circ);
7144 7133 client_dip = ndi_devi_findchild(vdip, devnm);
7145 7134 }
7146 7135
7147 7136 MDI_DEBUG(4, (MDI_NOTE, vdip,
7148 7137 "op = %d %s %p", op, devnm ? devnm : "", (void *)client_dip));
7149 7138
7150 7139 switch (op) {
7151 7140 case MDI_PM_PRE_CONFIG:
7152 7141 ret = i_mdi_pm_pre_config(vdip, client_dip);
7153 7142 break;
7154 7143
7155 7144 case MDI_PM_PRE_UNCONFIG:
7156 7145 ret = i_mdi_pm_pre_unconfig(vdip, client_dip, (int *)args,
7157 7146 flags);
7158 7147 break;
7159 7148
7160 7149 case MDI_PM_POST_CONFIG:
7161 7150 i_mdi_pm_post_config(vdip, client_dip);
7162 7151 break;
7163 7152
7164 7153 case MDI_PM_POST_UNCONFIG:
7165 7154 i_mdi_pm_post_unconfig(vdip, client_dip, *(int *)args);
7166 7155 break;
7167 7156
7168 7157 case MDI_PM_HOLD_POWER:
7169 7158 case MDI_PM_RELE_POWER:
7170 7159 ASSERT(args);
7171 7160
7172 7161 client_dip = (dev_info_t *)args;
7173 7162 ASSERT(MDI_CLIENT(client_dip));
7174 7163
7175 7164 ct = i_devi_get_client(client_dip);
7176 7165 MDI_CLIENT_LOCK(ct);
7177 7166
7178 7167 if (op == MDI_PM_HOLD_POWER) {
7179 7168 if (ct->ct_power_cnt == 0) {
7180 7169 (void) i_mdi_power_all_phci(ct);
7181 7170 MDI_DEBUG(4, (MDI_NOTE, client_dip,
7182 7171 "i_mdi_pm_hold_client\n"));
7183 7172 i_mdi_pm_hold_client(ct, ct->ct_path_count);
7184 7173 }
7185 7174 } else {
7186 7175 if (DEVI_IS_ATTACHING(client_dip)) {
7187 7176 MDI_DEBUG(4, (MDI_NOTE, client_dip,
7188 7177 "i_mdi_pm_rele_client\n"));
7189 7178 i_mdi_pm_rele_client(ct, ct->ct_path_count);
7190 7179 } else {
7191 7180 MDI_DEBUG(4, (MDI_NOTE, client_dip,
7192 7181 "i_mdi_pm_reset_client\n"));
7193 7182 i_mdi_pm_reset_client(ct);
7194 7183 }
7195 7184 }
7196 7185
7197 7186 MDI_CLIENT_UNLOCK(ct);
7198 7187 break;
7199 7188
7200 7189 default:
7201 7190 break;
7202 7191 }
7203 7192
7204 7193 if (devnm)
7205 7194 ndi_devi_exit(vdip, circ);
7206 7195
7207 7196 return (ret);
7208 7197 }
7209 7198
7210 7199 int
7211 7200 mdi_component_is_vhci(dev_info_t *dip, const char **mdi_class)
7212 7201 {
7213 7202 mdi_vhci_t *vhci;
7214 7203
7215 7204 if (!MDI_VHCI(dip))
7216 7205 return (MDI_FAILURE);
7217 7206
7218 7207 if (mdi_class) {
7219 7208 vhci = DEVI(dip)->devi_mdi_xhci;
7220 7209 ASSERT(vhci);
7221 7210 *mdi_class = vhci->vh_class;
7222 7211 }
7223 7212
7224 7213 return (MDI_SUCCESS);
7225 7214 }
7226 7215
7227 7216 int
7228 7217 mdi_component_is_phci(dev_info_t *dip, const char **mdi_class)
7229 7218 {
7230 7219 mdi_phci_t *phci;
7231 7220
7232 7221 if (!MDI_PHCI(dip))
7233 7222 return (MDI_FAILURE);
7234 7223
7235 7224 if (mdi_class) {
7236 7225 phci = DEVI(dip)->devi_mdi_xhci;
7237 7226 ASSERT(phci);
7238 7227 *mdi_class = phci->ph_vhci->vh_class;
7239 7228 }
7240 7229
7241 7230 return (MDI_SUCCESS);
7242 7231 }
7243 7232
7244 7233 int
7245 7234 mdi_component_is_client(dev_info_t *dip, const char **mdi_class)
7246 7235 {
7247 7236 mdi_client_t *client;
7248 7237
7249 7238 if (!MDI_CLIENT(dip))
7250 7239 return (MDI_FAILURE);
7251 7240
7252 7241 if (mdi_class) {
7253 7242 client = DEVI(dip)->devi_mdi_client;
7254 7243 ASSERT(client);
7255 7244 *mdi_class = client->ct_vhci->vh_class;
7256 7245 }
7257 7246
7258 7247 return (MDI_SUCCESS);
7259 7248 }
7260 7249
7261 7250 void *
7262 7251 mdi_client_get_vhci_private(dev_info_t *dip)
7263 7252 {
7264 7253 ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS);
7265 7254 if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) {
7266 7255 mdi_client_t *ct;
7267 7256 ct = i_devi_get_client(dip);
7268 7257 return (ct->ct_vprivate);
7269 7258 }
7270 7259 return (NULL);
7271 7260 }
7272 7261
7273 7262 void
7274 7263 mdi_client_set_vhci_private(dev_info_t *dip, void *data)
7275 7264 {
7276 7265 ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS);
7277 7266 if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) {
7278 7267 mdi_client_t *ct;
7279 7268 ct = i_devi_get_client(dip);
7280 7269 ct->ct_vprivate = data;
7281 7270 }
7282 7271 }
7283 7272 /*
7284 7273 * mdi_pi_get_vhci_private():
7285 7274 * Get the vhci private information associated with the
7286 7275 * mdi_pathinfo node
7287 7276 */
7288 7277 void *
7289 7278 mdi_pi_get_vhci_private(mdi_pathinfo_t *pip)
7290 7279 {
7291 7280 caddr_t vprivate = NULL;
7292 7281 if (pip) {
7293 7282 vprivate = MDI_PI(pip)->pi_vprivate;
7294 7283 }
7295 7284 return (vprivate);
7296 7285 }
7297 7286
7298 7287 /*
7299 7288 * mdi_pi_set_vhci_private():
7300 7289 * Set the vhci private information in the mdi_pathinfo node
7301 7290 */
7302 7291 void
7303 7292 mdi_pi_set_vhci_private(mdi_pathinfo_t *pip, void *priv)
7304 7293 {
7305 7294 if (pip) {
7306 7295 MDI_PI(pip)->pi_vprivate = priv;
7307 7296 }
7308 7297 }
7309 7298
7310 7299 /*
7311 7300 * mdi_phci_get_vhci_private():
7312 7301 * Get the vhci private information associated with the
7313 7302 * mdi_phci node
7314 7303 */
7315 7304 void *
7316 7305 mdi_phci_get_vhci_private(dev_info_t *dip)
7317 7306 {
7318 7307 ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS);
7319 7308 if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) {
7320 7309 mdi_phci_t *ph;
7321 7310 ph = i_devi_get_phci(dip);
7322 7311 return (ph->ph_vprivate);
7323 7312 }
7324 7313 return (NULL);
7325 7314 }
7326 7315
7327 7316 /*
7328 7317 * mdi_phci_set_vhci_private():
7329 7318 * Set the vhci private information in the mdi_phci node
7330 7319 */
7331 7320 void
7332 7321 mdi_phci_set_vhci_private(dev_info_t *dip, void *priv)
7333 7322 {
7334 7323 ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS);
7335 7324 if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) {
7336 7325 mdi_phci_t *ph;
7337 7326 ph = i_devi_get_phci(dip);
7338 7327 ph->ph_vprivate = priv;
7339 7328 }
7340 7329 }
7341 7330
7342 7331 int
7343 7332 mdi_pi_ishidden(mdi_pathinfo_t *pip)
7344 7333 {
7345 7334 return (MDI_PI_FLAGS_IS_HIDDEN(pip));
7346 7335 }
7347 7336
7348 7337 int
7349 7338 mdi_pi_device_isremoved(mdi_pathinfo_t *pip)
7350 7339 {
7351 7340 return (MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip));
7352 7341 }
7353 7342
7354 7343 /* Return 1 if all client paths are device_removed */
7355 7344 static int
7356 7345 i_mdi_client_all_devices_removed(mdi_client_t *ct)
7357 7346 {
7358 7347 mdi_pathinfo_t *pip;
7359 7348 int all_devices_removed = 1;
7360 7349
7361 7350 MDI_CLIENT_LOCK(ct);
7362 7351 for (pip = ct->ct_path_head; pip;
7363 7352 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link) {
7364 7353 if (!mdi_pi_device_isremoved(pip)) {
7365 7354 all_devices_removed = 0;
7366 7355 break;
7367 7356 }
7368 7357 }
7369 7358 MDI_CLIENT_UNLOCK(ct);
7370 7359 return (all_devices_removed);
7371 7360 }
7372 7361
7373 7362 /*
7374 7363 * When processing path hotunplug, represent device removal.
7375 7364 */
7376 7365 int
7377 7366 mdi_pi_device_remove(mdi_pathinfo_t *pip)
7378 7367 {
7379 7368 mdi_client_t *ct;
7380 7369
7381 7370 MDI_PI_LOCK(pip);
7382 7371 if (mdi_pi_device_isremoved(pip)) {
7383 7372 MDI_PI_UNLOCK(pip);
7384 7373 return (0);
7385 7374 }
7386 7375 MDI_PI_FLAGS_SET_DEVICE_REMOVED(pip);
7387 7376 MDI_PI_FLAGS_SET_HIDDEN(pip);
7388 7377 MDI_PI_UNLOCK(pip);
7389 7378
7390 7379 /*
7391 7380 * If all paths associated with the client are now DEVICE_REMOVED,
7392 7381 * reflect DEVICE_REMOVED in the client.
7393 7382 */
7394 7383 ct = MDI_PI(pip)->pi_client;
7395 7384 if (ct && ct->ct_dip && i_mdi_client_all_devices_removed(ct))
7396 7385 (void) ndi_devi_device_remove(ct->ct_dip);
7397 7386 else
7398 7387 i_ddi_di_cache_invalidate();
7399 7388
7400 7389 return (1);
7401 7390 }
7402 7391
7403 7392 /*
7404 7393 * When processing hotplug, if a path marked mdi_pi_device_isremoved()
7405 7394 * is now accessible then this interfaces is used to represent device insertion.
7406 7395 */
7407 7396 int
7408 7397 mdi_pi_device_insert(mdi_pathinfo_t *pip)
7409 7398 {
7410 7399 MDI_PI_LOCK(pip);
7411 7400 if (!mdi_pi_device_isremoved(pip)) {
7412 7401 MDI_PI_UNLOCK(pip);
7413 7402 return (0);
7414 7403 }
7415 7404 MDI_PI_FLAGS_CLR_DEVICE_REMOVED(pip);
7416 7405 MDI_PI_FLAGS_CLR_HIDDEN(pip);
7417 7406 MDI_PI_UNLOCK(pip);
7418 7407
7419 7408 i_ddi_di_cache_invalidate();
7420 7409
7421 7410 return (1);
7422 7411 }
7423 7412
7424 7413 /*
7425 7414 * List of vhci class names:
7426 7415 * A vhci class name must be in this list only if the corresponding vhci
7427 7416 * driver intends to use the mdi provided bus config implementation
7428 7417 * (i.e., mdi_vhci_bus_config()).
7429 7418 */
7430 7419 static char *vhci_class_list[] = { MDI_HCI_CLASS_SCSI, MDI_HCI_CLASS_IB };
7431 7420 #define N_VHCI_CLASSES (sizeof (vhci_class_list) / sizeof (char *))
7432 7421
7433 7422 /*
7434 7423 * During boot time, the on-disk vhci cache for every vhci class is read
7435 7424 * in the form of an nvlist and stored here.
7436 7425 */
7437 7426 static nvlist_t *vhcache_nvl[N_VHCI_CLASSES];
7438 7427
7439 7428 /* nvpair names in vhci cache nvlist */
7440 7429 #define MDI_VHCI_CACHE_VERSION 1
7441 7430 #define MDI_NVPNAME_VERSION "version"
7442 7431 #define MDI_NVPNAME_PHCIS "phcis"
7443 7432 #define MDI_NVPNAME_CTADDRMAP "clientaddrmap"
7444 7433
7445 7434 /*
7446 7435 * Given vhci class name, return its on-disk vhci cache filename.
7447 7436 * Memory for the returned filename which includes the full path is allocated
7448 7437 * by this function.
7449 7438 */
7450 7439 static char *
7451 7440 vhclass2vhcache_filename(char *vhclass)
7452 7441 {
7453 7442 char *filename;
7454 7443 int len;
7455 7444 static char *fmt = "/etc/devices/mdi_%s_cache";
7456 7445
7457 7446 /*
7458 7447 * fmt contains the on-disk vhci cache file name format;
7459 7448 * for scsi_vhci the filename is "/etc/devices/mdi_scsi_vhci_cache".
7460 7449 */
7461 7450
7462 7451 /* the -1 below is to account for "%s" in the format string */
7463 7452 len = strlen(fmt) + strlen(vhclass) - 1;
7464 7453 filename = kmem_alloc(len, KM_SLEEP);
7465 7454 (void) snprintf(filename, len, fmt, vhclass);
7466 7455 ASSERT(len == (strlen(filename) + 1));
7467 7456 return (filename);
7468 7457 }
7469 7458
7470 7459 /*
7471 7460 * initialize the vhci cache related data structures and read the on-disk
7472 7461 * vhci cached data into memory.
7473 7462 */
7474 7463 static void
7475 7464 setup_vhci_cache(mdi_vhci_t *vh)
7476 7465 {
7477 7466 mdi_vhci_config_t *vhc;
7478 7467 mdi_vhci_cache_t *vhcache;
7479 7468 int i;
7480 7469 nvlist_t *nvl = NULL;
7481 7470
7482 7471 vhc = kmem_zalloc(sizeof (mdi_vhci_config_t), KM_SLEEP);
7483 7472 vh->vh_config = vhc;
7484 7473 vhcache = &vhc->vhc_vhcache;
7485 7474
7486 7475 vhc->vhc_vhcache_filename = vhclass2vhcache_filename(vh->vh_class);
7487 7476
7488 7477 mutex_init(&vhc->vhc_lock, NULL, MUTEX_DEFAULT, NULL);
7489 7478 cv_init(&vhc->vhc_cv, NULL, CV_DRIVER, NULL);
7490 7479
7491 7480 rw_init(&vhcache->vhcache_lock, NULL, RW_DRIVER, NULL);
7492 7481
7493 7482 /*
7494 7483 * Create string hash; same as mod_hash_create_strhash() except that
7495 7484 * we use NULL key destructor.
7496 7485 */
7497 7486 vhcache->vhcache_client_hash = mod_hash_create_extended(vh->vh_class,
7498 7487 mdi_bus_config_cache_hash_size,
7499 7488 mod_hash_null_keydtor, mod_hash_null_valdtor,
7500 7489 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
7501 7490
7502 7491 /*
7503 7492 * The on-disk vhci cache is read during booting prior to the
7504 7493 * lights-out period by mdi_read_devices_files().
7505 7494 */
7506 7495 for (i = 0; i < N_VHCI_CLASSES; i++) {
7507 7496 if (strcmp(vhci_class_list[i], vh->vh_class) == 0) {
7508 7497 nvl = vhcache_nvl[i];
7509 7498 vhcache_nvl[i] = NULL;
7510 7499 break;
7511 7500 }
7512 7501 }
7513 7502
7514 7503 /*
7515 7504 * this is to cover the case of some one manually causing unloading
7516 7505 * (or detaching) and reloading (or attaching) of a vhci driver.
7517 7506 */
7518 7507 if (nvl == NULL && modrootloaded)
7519 7508 nvl = read_on_disk_vhci_cache(vh->vh_class);
7520 7509
7521 7510 if (nvl != NULL) {
7522 7511 rw_enter(&vhcache->vhcache_lock, RW_WRITER);
7523 7512 if (mainnvl_to_vhcache(vhcache, nvl) == MDI_SUCCESS)
7524 7513 vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE;
7525 7514 else {
7526 7515 cmn_err(CE_WARN,
7527 7516 "%s: data file corrupted, will recreate",
7528 7517 vhc->vhc_vhcache_filename);
7529 7518 }
7530 7519 rw_exit(&vhcache->vhcache_lock);
7531 7520 nvlist_free(nvl);
7532 7521 }
7533 7522
7534 7523 vhc->vhc_cbid = callb_add(stop_vhcache_flush_thread, vhc,
7535 7524 CB_CL_UADMIN_PRE_VFS, "mdi_vhcache_flush");
7536 7525
7537 7526 vhc->vhc_path_discovery_boot = mdi_path_discovery_boot;
7538 7527 vhc->vhc_path_discovery_postboot = mdi_path_discovery_postboot;
7539 7528 }
7540 7529
7541 7530 /*
7542 7531 * free all vhci cache related resources
7543 7532 */
7544 7533 static int
7545 7534 destroy_vhci_cache(mdi_vhci_t *vh)
7546 7535 {
7547 7536 mdi_vhci_config_t *vhc = vh->vh_config;
7548 7537 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
7549 7538 mdi_vhcache_phci_t *cphci, *cphci_next;
7550 7539 mdi_vhcache_client_t *cct, *cct_next;
7551 7540 mdi_vhcache_pathinfo_t *cpi, *cpi_next;
7552 7541
7553 7542 if (stop_vhcache_async_threads(vhc) != MDI_SUCCESS)
7554 7543 return (MDI_FAILURE);
7555 7544
7556 7545 kmem_free(vhc->vhc_vhcache_filename,
7557 7546 strlen(vhc->vhc_vhcache_filename) + 1);
7558 7547
7559 7548 mod_hash_destroy_strhash(vhcache->vhcache_client_hash);
7560 7549
7561 7550 for (cphci = vhcache->vhcache_phci_head; cphci != NULL;
7562 7551 cphci = cphci_next) {
7563 7552 cphci_next = cphci->cphci_next;
7564 7553 free_vhcache_phci(cphci);
7565 7554 }
7566 7555
7567 7556 for (cct = vhcache->vhcache_client_head; cct != NULL; cct = cct_next) {
7568 7557 cct_next = cct->cct_next;
7569 7558 for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi_next) {
7570 7559 cpi_next = cpi->cpi_next;
7571 7560 free_vhcache_pathinfo(cpi);
7572 7561 }
7573 7562 free_vhcache_client(cct);
7574 7563 }
7575 7564
7576 7565 rw_destroy(&vhcache->vhcache_lock);
7577 7566
7578 7567 mutex_destroy(&vhc->vhc_lock);
7579 7568 cv_destroy(&vhc->vhc_cv);
7580 7569 kmem_free(vhc, sizeof (mdi_vhci_config_t));
7581 7570 return (MDI_SUCCESS);
7582 7571 }
7583 7572
7584 7573 /*
7585 7574 * Stop all vhci cache related async threads and free their resources.
7586 7575 */
7587 7576 static int
7588 7577 stop_vhcache_async_threads(mdi_vhci_config_t *vhc)
7589 7578 {
7590 7579 mdi_async_client_config_t *acc, *acc_next;
7591 7580
7592 7581 mutex_enter(&vhc->vhc_lock);
7593 7582 vhc->vhc_flags |= MDI_VHC_EXIT;
7594 7583 ASSERT(vhc->vhc_acc_thrcount >= 0);
7595 7584 cv_broadcast(&vhc->vhc_cv);
7596 7585
7597 7586 while ((vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) ||
7598 7587 vhc->vhc_acc_thrcount != 0) {
7599 7588 mutex_exit(&vhc->vhc_lock);
7600 7589 delay_random(mdi_delay);
7601 7590 mutex_enter(&vhc->vhc_lock);
7602 7591 }
7603 7592
7604 7593 vhc->vhc_flags &= ~MDI_VHC_EXIT;
7605 7594
7606 7595 for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc_next) {
7607 7596 acc_next = acc->acc_next;
7608 7597 free_async_client_config(acc);
7609 7598 }
7610 7599 vhc->vhc_acc_list_head = NULL;
7611 7600 vhc->vhc_acc_list_tail = NULL;
7612 7601 vhc->vhc_acc_count = 0;
7613 7602
7614 7603 if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) {
7615 7604 vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY;
7616 7605 mutex_exit(&vhc->vhc_lock);
7617 7606 if (flush_vhcache(vhc, 0) != MDI_SUCCESS) {
7618 7607 vhcache_dirty(vhc);
7619 7608 return (MDI_FAILURE);
7620 7609 }
7621 7610 } else
7622 7611 mutex_exit(&vhc->vhc_lock);
7623 7612
7624 7613 if (callb_delete(vhc->vhc_cbid) != 0)
7625 7614 return (MDI_FAILURE);
7626 7615
7627 7616 return (MDI_SUCCESS);
7628 7617 }
7629 7618
7630 7619 /*
7631 7620 * Stop vhci cache flush thread
7632 7621 */
7633 7622 /* ARGSUSED */
7634 7623 static boolean_t
7635 7624 stop_vhcache_flush_thread(void *arg, int code)
7636 7625 {
7637 7626 mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg;
7638 7627
7639 7628 mutex_enter(&vhc->vhc_lock);
7640 7629 vhc->vhc_flags |= MDI_VHC_EXIT;
7641 7630 cv_broadcast(&vhc->vhc_cv);
7642 7631
7643 7632 while (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) {
7644 7633 mutex_exit(&vhc->vhc_lock);
7645 7634 delay_random(mdi_delay);
7646 7635 mutex_enter(&vhc->vhc_lock);
7647 7636 }
7648 7637
7649 7638 if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) {
7650 7639 vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY;
7651 7640 mutex_exit(&vhc->vhc_lock);
7652 7641 (void) flush_vhcache(vhc, 1);
7653 7642 } else
7654 7643 mutex_exit(&vhc->vhc_lock);
7655 7644
7656 7645 return (B_TRUE);
7657 7646 }
7658 7647
7659 7648 /*
7660 7649 * Enqueue the vhcache phci (cphci) at the tail of the list
7661 7650 */
7662 7651 static void
7663 7652 enqueue_vhcache_phci(mdi_vhci_cache_t *vhcache, mdi_vhcache_phci_t *cphci)
7664 7653 {
7665 7654 cphci->cphci_next = NULL;
7666 7655 if (vhcache->vhcache_phci_head == NULL)
7667 7656 vhcache->vhcache_phci_head = cphci;
7668 7657 else
7669 7658 vhcache->vhcache_phci_tail->cphci_next = cphci;
7670 7659 vhcache->vhcache_phci_tail = cphci;
7671 7660 }
7672 7661
7673 7662 /*
7674 7663 * Enqueue the vhcache pathinfo (cpi) at the tail of the list
7675 7664 */
7676 7665 static void
7677 7666 enqueue_tail_vhcache_pathinfo(mdi_vhcache_client_t *cct,
7678 7667 mdi_vhcache_pathinfo_t *cpi)
7679 7668 {
7680 7669 cpi->cpi_next = NULL;
7681 7670 if (cct->cct_cpi_head == NULL)
7682 7671 cct->cct_cpi_head = cpi;
7683 7672 else
7684 7673 cct->cct_cpi_tail->cpi_next = cpi;
7685 7674 cct->cct_cpi_tail = cpi;
7686 7675 }
7687 7676
7688 7677 /*
7689 7678 * Enqueue the vhcache pathinfo (cpi) at the correct location in the
7690 7679 * ordered list. All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST
7691 7680 * flag set come at the beginning of the list. All cpis which have this
7692 7681 * flag set come at the end of the list.
7693 7682 */
7694 7683 static void
7695 7684 enqueue_vhcache_pathinfo(mdi_vhcache_client_t *cct,
7696 7685 mdi_vhcache_pathinfo_t *newcpi)
7697 7686 {
7698 7687 mdi_vhcache_pathinfo_t *cpi, *prev_cpi;
7699 7688
7700 7689 if (cct->cct_cpi_head == NULL ||
7701 7690 (newcpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST))
7702 7691 enqueue_tail_vhcache_pathinfo(cct, newcpi);
7703 7692 else {
7704 7693 for (cpi = cct->cct_cpi_head, prev_cpi = NULL; cpi != NULL &&
7705 7694 !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST);
7706 7695 prev_cpi = cpi, cpi = cpi->cpi_next)
7707 7696 ;
7708 7697
7709 7698 if (prev_cpi == NULL)
7710 7699 cct->cct_cpi_head = newcpi;
7711 7700 else
7712 7701 prev_cpi->cpi_next = newcpi;
7713 7702
7714 7703 newcpi->cpi_next = cpi;
7715 7704
7716 7705 if (cpi == NULL)
7717 7706 cct->cct_cpi_tail = newcpi;
7718 7707 }
7719 7708 }
7720 7709
7721 7710 /*
7722 7711 * Enqueue the vhcache client (cct) at the tail of the list
7723 7712 */
7724 7713 static void
7725 7714 enqueue_vhcache_client(mdi_vhci_cache_t *vhcache,
7726 7715 mdi_vhcache_client_t *cct)
7727 7716 {
7728 7717 cct->cct_next = NULL;
7729 7718 if (vhcache->vhcache_client_head == NULL)
7730 7719 vhcache->vhcache_client_head = cct;
7731 7720 else
7732 7721 vhcache->vhcache_client_tail->cct_next = cct;
7733 7722 vhcache->vhcache_client_tail = cct;
7734 7723 }
7735 7724
7736 7725 static void
7737 7726 free_string_array(char **str, int nelem)
7738 7727 {
7739 7728 int i;
7740 7729
7741 7730 if (str) {
7742 7731 for (i = 0; i < nelem; i++) {
7743 7732 if (str[i])
7744 7733 kmem_free(str[i], strlen(str[i]) + 1);
7745 7734 }
7746 7735 kmem_free(str, sizeof (char *) * nelem);
7747 7736 }
7748 7737 }
7749 7738
7750 7739 static void
7751 7740 free_vhcache_phci(mdi_vhcache_phci_t *cphci)
7752 7741 {
7753 7742 kmem_free(cphci->cphci_path, strlen(cphci->cphci_path) + 1);
7754 7743 kmem_free(cphci, sizeof (*cphci));
7755 7744 }
7756 7745
7757 7746 static void
7758 7747 free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *cpi)
7759 7748 {
7760 7749 kmem_free(cpi->cpi_addr, strlen(cpi->cpi_addr) + 1);
7761 7750 kmem_free(cpi, sizeof (*cpi));
7762 7751 }
7763 7752
7764 7753 static void
7765 7754 free_vhcache_client(mdi_vhcache_client_t *cct)
7766 7755 {
7767 7756 kmem_free(cct->cct_name_addr, strlen(cct->cct_name_addr) + 1);
7768 7757 kmem_free(cct, sizeof (*cct));
7769 7758 }
7770 7759
7771 7760 static char *
7772 7761 vhcache_mknameaddr(char *ct_name, char *ct_addr, int *ret_len)
7773 7762 {
7774 7763 char *name_addr;
7775 7764 int len;
7776 7765
7777 7766 len = strlen(ct_name) + strlen(ct_addr) + 2;
7778 7767 name_addr = kmem_alloc(len, KM_SLEEP);
7779 7768 (void) snprintf(name_addr, len, "%s@%s", ct_name, ct_addr);
7780 7769
7781 7770 if (ret_len)
7782 7771 *ret_len = len;
7783 7772 return (name_addr);
7784 7773 }
7785 7774
7786 7775 /*
7787 7776 * Copy the contents of paddrnvl to vhci cache.
7788 7777 * paddrnvl nvlist contains path information for a vhci client.
7789 7778 * See the comment in mainnvl_to_vhcache() for the format of this nvlist.
7790 7779 */
7791 7780 static void
7792 7781 paddrnvl_to_vhcache(nvlist_t *nvl, mdi_vhcache_phci_t *cphci_list[],
7793 7782 mdi_vhcache_client_t *cct)
7794 7783 {
7795 7784 nvpair_t *nvp = NULL;
7796 7785 mdi_vhcache_pathinfo_t *cpi;
7797 7786 uint_t nelem;
7798 7787 uint32_t *val;
7799 7788
7800 7789 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
7801 7790 ASSERT(nvpair_type(nvp) == DATA_TYPE_UINT32_ARRAY);
7802 7791 cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP);
7803 7792 cpi->cpi_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP);
7804 7793 (void) nvpair_value_uint32_array(nvp, &val, &nelem);
7805 7794 ASSERT(nelem == 2);
7806 7795 cpi->cpi_cphci = cphci_list[val[0]];
7807 7796 cpi->cpi_flags = val[1];
7808 7797 enqueue_tail_vhcache_pathinfo(cct, cpi);
7809 7798 }
7810 7799 }
7811 7800
7812 7801 /*
7813 7802 * Copy the contents of caddrmapnvl to vhci cache.
7814 7803 * caddrmapnvl nvlist contains vhci client address to phci client address
7815 7804 * mappings. See the comment in mainnvl_to_vhcache() for the format of
7816 7805 * this nvlist.
7817 7806 */
7818 7807 static void
7819 7808 caddrmapnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl,
7820 7809 mdi_vhcache_phci_t *cphci_list[])
7821 7810 {
7822 7811 nvpair_t *nvp = NULL;
7823 7812 nvlist_t *paddrnvl;
7824 7813 mdi_vhcache_client_t *cct;
7825 7814
7826 7815 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
7827 7816 ASSERT(nvpair_type(nvp) == DATA_TYPE_NVLIST);
7828 7817 cct = kmem_zalloc(sizeof (*cct), KM_SLEEP);
7829 7818 cct->cct_name_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP);
7830 7819 (void) nvpair_value_nvlist(nvp, &paddrnvl);
7831 7820 paddrnvl_to_vhcache(paddrnvl, cphci_list, cct);
7832 7821 /* the client must contain at least one path */
7833 7822 ASSERT(cct->cct_cpi_head != NULL);
7834 7823
7835 7824 enqueue_vhcache_client(vhcache, cct);
7836 7825 (void) mod_hash_insert(vhcache->vhcache_client_hash,
7837 7826 (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct);
7838 7827 }
7839 7828 }
7840 7829
7841 7830 /*
7842 7831 * Copy the contents of the main nvlist to vhci cache.
7843 7832 *
7844 7833 * VHCI busconfig cached data is stored in the form of a nvlist on the disk.
7845 7834 * The nvlist contains the mappings between the vhci client addresses and
7846 7835 * their corresponding phci client addresses.
7847 7836 *
7848 7837 * The structure of the nvlist is as follows:
7849 7838 *
7850 7839 * Main nvlist:
7851 7840 * NAME TYPE DATA
7852 7841 * version int32 version number
7853 7842 * phcis string array array of phci paths
7854 7843 * clientaddrmap nvlist_t c2paddrs_nvl (see below)
7855 7844 *
7856 7845 * structure of c2paddrs_nvl:
7857 7846 * NAME TYPE DATA
7858 7847 * caddr1 nvlist_t paddrs_nvl1
7859 7848 * caddr2 nvlist_t paddrs_nvl2
7860 7849 * ...
7861 7850 * where caddr1, caddr2, ... are vhci client name and addresses in the
7862 7851 * form of "<clientname>@<clientaddress>".
7863 7852 * (for example: "ssd@2000002037cd9f72");
7864 7853 * paddrs_nvl1, paddrs_nvl2, .. are nvlists that contain path information.
7865 7854 *
7866 7855 * structure of paddrs_nvl:
7867 7856 * NAME TYPE DATA
7868 7857 * pi_addr1 uint32_array (phci-id, cpi_flags)
7869 7858 * pi_addr2 uint32_array (phci-id, cpi_flags)
7870 7859 * ...
7871 7860 * where pi_addr1, pi_addr2, ... are bus specific addresses of pathinfo nodes
7872 7861 * (so called pi_addrs, for example: "w2100002037cd9f72,0");
7873 7862 * phci-ids are integers that identify pHCIs to which the
7874 7863 * the bus specific address belongs to. These integers are used as an index
7875 7864 * into to the phcis string array in the main nvlist to get the pHCI path.
7876 7865 */
7877 7866 static int
7878 7867 mainnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl)
7879 7868 {
7880 7869 char **phcis, **phci_namep;
7881 7870 uint_t nphcis;
7882 7871 mdi_vhcache_phci_t *cphci, **cphci_list;
7883 7872 nvlist_t *caddrmapnvl;
7884 7873 int32_t ver;
7885 7874 int i;
7886 7875 size_t cphci_list_size;
7887 7876
7888 7877 ASSERT(RW_WRITE_HELD(&vhcache->vhcache_lock));
7889 7878
7890 7879 if (nvlist_lookup_int32(nvl, MDI_NVPNAME_VERSION, &ver) != 0 ||
7891 7880 ver != MDI_VHCI_CACHE_VERSION)
7892 7881 return (MDI_FAILURE);
7893 7882
7894 7883 if (nvlist_lookup_string_array(nvl, MDI_NVPNAME_PHCIS, &phcis,
7895 7884 &nphcis) != 0)
7896 7885 return (MDI_SUCCESS);
7897 7886
7898 7887 ASSERT(nphcis > 0);
7899 7888
7900 7889 cphci_list_size = sizeof (mdi_vhcache_phci_t *) * nphcis;
7901 7890 cphci_list = kmem_alloc(cphci_list_size, KM_SLEEP);
7902 7891 for (i = 0, phci_namep = phcis; i < nphcis; i++, phci_namep++) {
7903 7892 cphci = kmem_zalloc(sizeof (mdi_vhcache_phci_t), KM_SLEEP);
7904 7893 cphci->cphci_path = i_ddi_strdup(*phci_namep, KM_SLEEP);
7905 7894 enqueue_vhcache_phci(vhcache, cphci);
7906 7895 cphci_list[i] = cphci;
7907 7896 }
7908 7897
7909 7898 ASSERT(vhcache->vhcache_phci_head != NULL);
7910 7899
7911 7900 if (nvlist_lookup_nvlist(nvl, MDI_NVPNAME_CTADDRMAP, &caddrmapnvl) == 0)
7912 7901 caddrmapnvl_to_vhcache(vhcache, caddrmapnvl, cphci_list);
7913 7902
7914 7903 kmem_free(cphci_list, cphci_list_size);
7915 7904 return (MDI_SUCCESS);
7916 7905 }
7917 7906
7918 7907 /*
7919 7908 * Build paddrnvl for the specified client using the information in the
7920 7909 * vhci cache and add it to the caddrmapnnvl.
7921 7910 * Returns 0 on success, errno on failure.
7922 7911 */
7923 7912 static int
7924 7913 vhcache_to_paddrnvl(mdi_vhci_cache_t *vhcache, mdi_vhcache_client_t *cct,
7925 7914 nvlist_t *caddrmapnvl)
7926 7915 {
7927 7916 mdi_vhcache_pathinfo_t *cpi;
7928 7917 nvlist_t *nvl;
7929 7918 int err;
7930 7919 uint32_t val[2];
7931 7920
7932 7921 ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock));
7933 7922
7934 7923 if ((err = nvlist_alloc(&nvl, 0, KM_SLEEP)) != 0)
7935 7924 return (err);
7936 7925
7937 7926 for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) {
7938 7927 val[0] = cpi->cpi_cphci->cphci_id;
7939 7928 val[1] = cpi->cpi_flags;
7940 7929 if ((err = nvlist_add_uint32_array(nvl, cpi->cpi_addr, val, 2))
7941 7930 != 0)
7942 7931 goto out;
7943 7932 }
7944 7933
7945 7934 err = nvlist_add_nvlist(caddrmapnvl, cct->cct_name_addr, nvl);
7946 7935 out:
7947 7936 nvlist_free(nvl);
7948 7937 return (err);
7949 7938 }
7950 7939
7951 7940 /*
7952 7941 * Build caddrmapnvl using the information in the vhci cache
7953 7942 * and add it to the mainnvl.
7954 7943 * Returns 0 on success, errno on failure.
7955 7944 */
7956 7945 static int
7957 7946 vhcache_to_caddrmapnvl(mdi_vhci_cache_t *vhcache, nvlist_t *mainnvl)
7958 7947 {
7959 7948 mdi_vhcache_client_t *cct;
7960 7949 nvlist_t *nvl;
7961 7950 int err;
7962 7951
7963 7952 ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock));
7964 7953
7965 7954 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0)
7966 7955 return (err);
7967 7956
7968 7957 for (cct = vhcache->vhcache_client_head; cct != NULL;
7969 7958 cct = cct->cct_next) {
7970 7959 if ((err = vhcache_to_paddrnvl(vhcache, cct, nvl)) != 0)
7971 7960 goto out;
7972 7961 }
7973 7962
7974 7963 err = nvlist_add_nvlist(mainnvl, MDI_NVPNAME_CTADDRMAP, nvl);
7975 7964 out:
7976 7965 nvlist_free(nvl);
7977 7966 return (err);
7978 7967 }
7979 7968
7980 7969 /*
7981 7970 * Build nvlist using the information in the vhci cache.
7982 7971 * See the comment in mainnvl_to_vhcache() for the format of the nvlist.
7983 7972 * Returns nvl on success, NULL on failure.
7984 7973 */
7985 7974 static nvlist_t *
7986 7975 vhcache_to_mainnvl(mdi_vhci_cache_t *vhcache)
7987 7976 {
7988 7977 mdi_vhcache_phci_t *cphci;
7989 7978 uint_t phci_count;
7990 7979 char **phcis;
7991 7980 nvlist_t *nvl;
7992 7981 int err, i;
7993 7982
7994 7983 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0) {
7995 7984 nvl = NULL;
7996 7985 goto out;
7997 7986 }
7998 7987
7999 7988 if ((err = nvlist_add_int32(nvl, MDI_NVPNAME_VERSION,
8000 7989 MDI_VHCI_CACHE_VERSION)) != 0)
8001 7990 goto out;
8002 7991
8003 7992 rw_enter(&vhcache->vhcache_lock, RW_READER);
8004 7993 if (vhcache->vhcache_phci_head == NULL) {
8005 7994 rw_exit(&vhcache->vhcache_lock);
8006 7995 return (nvl);
8007 7996 }
8008 7997
8009 7998 phci_count = 0;
8010 7999 for (cphci = vhcache->vhcache_phci_head; cphci != NULL;
8011 8000 cphci = cphci->cphci_next)
8012 8001 cphci->cphci_id = phci_count++;
8013 8002
8014 8003 /* build phci pathname list */
8015 8004 phcis = kmem_alloc(sizeof (char *) * phci_count, KM_SLEEP);
8016 8005 for (cphci = vhcache->vhcache_phci_head, i = 0; cphci != NULL;
8017 8006 cphci = cphci->cphci_next, i++)
8018 8007 phcis[i] = i_ddi_strdup(cphci->cphci_path, KM_SLEEP);
8019 8008
8020 8009 err = nvlist_add_string_array(nvl, MDI_NVPNAME_PHCIS, phcis,
8021 8010 phci_count);
8022 8011 free_string_array(phcis, phci_count);
8023 8012
8024 8013 if (err == 0 &&
8025 8014 (err = vhcache_to_caddrmapnvl(vhcache, nvl)) == 0) {
8026 8015 rw_exit(&vhcache->vhcache_lock);
8027 8016 return (nvl);
8028 8017 }
8029 8018
8030 8019 rw_exit(&vhcache->vhcache_lock);
8031 8020 out:
8032 8021 nvlist_free(nvl);
8033 8022 return (NULL);
8034 8023 }
8035 8024
8036 8025 /*
8037 8026 * Lookup vhcache phci structure for the specified phci path.
8038 8027 */
8039 8028 static mdi_vhcache_phci_t *
8040 8029 lookup_vhcache_phci_by_name(mdi_vhci_cache_t *vhcache, char *phci_path)
8041 8030 {
8042 8031 mdi_vhcache_phci_t *cphci;
8043 8032
8044 8033 ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock));
8045 8034
8046 8035 for (cphci = vhcache->vhcache_phci_head; cphci != NULL;
8047 8036 cphci = cphci->cphci_next) {
8048 8037 if (strcmp(cphci->cphci_path, phci_path) == 0)
8049 8038 return (cphci);
8050 8039 }
8051 8040
8052 8041 return (NULL);
8053 8042 }
8054 8043
8055 8044 /*
8056 8045 * Lookup vhcache phci structure for the specified phci.
8057 8046 */
8058 8047 static mdi_vhcache_phci_t *
8059 8048 lookup_vhcache_phci_by_addr(mdi_vhci_cache_t *vhcache, mdi_phci_t *ph)
8060 8049 {
8061 8050 mdi_vhcache_phci_t *cphci;
8062 8051
8063 8052 ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock));
8064 8053
8065 8054 for (cphci = vhcache->vhcache_phci_head; cphci != NULL;
8066 8055 cphci = cphci->cphci_next) {
8067 8056 if (cphci->cphci_phci == ph)
8068 8057 return (cphci);
8069 8058 }
8070 8059
8071 8060 return (NULL);
8072 8061 }
8073 8062
8074 8063 /*
8075 8064 * Add the specified phci to the vhci cache if not already present.
8076 8065 */
8077 8066 static void
8078 8067 vhcache_phci_add(mdi_vhci_config_t *vhc, mdi_phci_t *ph)
8079 8068 {
8080 8069 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
8081 8070 mdi_vhcache_phci_t *cphci;
8082 8071 char *pathname;
8083 8072 int cache_updated;
8084 8073
8085 8074 rw_enter(&vhcache->vhcache_lock, RW_WRITER);
8086 8075
8087 8076 pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
8088 8077 (void) ddi_pathname(ph->ph_dip, pathname);
8089 8078 if ((cphci = lookup_vhcache_phci_by_name(vhcache, pathname))
8090 8079 != NULL) {
8091 8080 cphci->cphci_phci = ph;
8092 8081 cache_updated = 0;
8093 8082 } else {
8094 8083 cphci = kmem_zalloc(sizeof (*cphci), KM_SLEEP);
8095 8084 cphci->cphci_path = i_ddi_strdup(pathname, KM_SLEEP);
8096 8085 cphci->cphci_phci = ph;
8097 8086 enqueue_vhcache_phci(vhcache, cphci);
8098 8087 cache_updated = 1;
8099 8088 }
8100 8089
8101 8090 rw_exit(&vhcache->vhcache_lock);
8102 8091
8103 8092 /*
8104 8093 * Since a new phci has been added, reset
8105 8094 * vhc_path_discovery_cutoff_time to allow for discovery of paths
8106 8095 * during next vhcache_discover_paths().
8107 8096 */
8108 8097 mutex_enter(&vhc->vhc_lock);
8109 8098 vhc->vhc_path_discovery_cutoff_time = 0;
8110 8099 mutex_exit(&vhc->vhc_lock);
8111 8100
8112 8101 kmem_free(pathname, MAXPATHLEN);
8113 8102 if (cache_updated)
8114 8103 vhcache_dirty(vhc);
8115 8104 }
8116 8105
8117 8106 /*
8118 8107 * Remove the reference to the specified phci from the vhci cache.
8119 8108 */
8120 8109 static void
8121 8110 vhcache_phci_remove(mdi_vhci_config_t *vhc, mdi_phci_t *ph)
8122 8111 {
8123 8112 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
8124 8113 mdi_vhcache_phci_t *cphci;
8125 8114
8126 8115 rw_enter(&vhcache->vhcache_lock, RW_WRITER);
8127 8116 if ((cphci = lookup_vhcache_phci_by_addr(vhcache, ph)) != NULL) {
8128 8117 /* do not remove the actual mdi_vhcache_phci structure */
8129 8118 cphci->cphci_phci = NULL;
8130 8119 }
8131 8120 rw_exit(&vhcache->vhcache_lock);
8132 8121 }
8133 8122
8134 8123 static void
8135 8124 init_vhcache_lookup_token(mdi_vhcache_lookup_token_t *dst,
8136 8125 mdi_vhcache_lookup_token_t *src)
8137 8126 {
8138 8127 if (src == NULL) {
8139 8128 dst->lt_cct = NULL;
8140 8129 dst->lt_cct_lookup_time = 0;
8141 8130 } else {
8142 8131 dst->lt_cct = src->lt_cct;
8143 8132 dst->lt_cct_lookup_time = src->lt_cct_lookup_time;
8144 8133 }
8145 8134 }
8146 8135
8147 8136 /*
8148 8137 * Look up vhcache client for the specified client.
8149 8138 */
8150 8139 static mdi_vhcache_client_t *
8151 8140 lookup_vhcache_client(mdi_vhci_cache_t *vhcache, char *ct_name, char *ct_addr,
8152 8141 mdi_vhcache_lookup_token_t *token)
8153 8142 {
8154 8143 mod_hash_val_t hv;
8155 8144 char *name_addr;
8156 8145 int len;
8157 8146
8158 8147 ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock));
8159 8148
8160 8149 /*
8161 8150 * If no vhcache clean occurred since the last lookup, we can
8162 8151 * simply return the cct from the last lookup operation.
8163 8152 * It works because ccts are never freed except during the vhcache
8164 8153 * cleanup operation.
8165 8154 */
8166 8155 if (token != NULL &&
8167 8156 vhcache->vhcache_clean_time < token->lt_cct_lookup_time)
8168 8157 return (token->lt_cct);
8169 8158
8170 8159 name_addr = vhcache_mknameaddr(ct_name, ct_addr, &len);
8171 8160 if (mod_hash_find(vhcache->vhcache_client_hash,
8172 8161 (mod_hash_key_t)name_addr, &hv) == 0) {
8173 8162 if (token) {
8174 8163 token->lt_cct = (mdi_vhcache_client_t *)hv;
8175 8164 token->lt_cct_lookup_time = ddi_get_lbolt64();
8176 8165 }
8177 8166 } else {
8178 8167 if (token) {
8179 8168 token->lt_cct = NULL;
8180 8169 token->lt_cct_lookup_time = 0;
8181 8170 }
8182 8171 hv = NULL;
8183 8172 }
8184 8173 kmem_free(name_addr, len);
8185 8174 return ((mdi_vhcache_client_t *)hv);
8186 8175 }
8187 8176
8188 8177 /*
8189 8178 * Add the specified path to the vhci cache if not already present.
8190 8179 * Also add the vhcache client for the client corresponding to this path
8191 8180 * if it doesn't already exist.
8192 8181 */
8193 8182 static void
8194 8183 vhcache_pi_add(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip)
8195 8184 {
8196 8185 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
8197 8186 mdi_vhcache_client_t *cct;
8198 8187 mdi_vhcache_pathinfo_t *cpi;
8199 8188 mdi_phci_t *ph = pip->pi_phci;
8200 8189 mdi_client_t *ct = pip->pi_client;
8201 8190 int cache_updated = 0;
8202 8191
8203 8192 rw_enter(&vhcache->vhcache_lock, RW_WRITER);
8204 8193
8205 8194 /* if vhcache client for this pip doesn't already exist, add it */
8206 8195 if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid,
8207 8196 NULL)) == NULL) {
8208 8197 cct = kmem_zalloc(sizeof (*cct), KM_SLEEP);
8209 8198 cct->cct_name_addr = vhcache_mknameaddr(ct->ct_drvname,
8210 8199 ct->ct_guid, NULL);
8211 8200 enqueue_vhcache_client(vhcache, cct);
8212 8201 (void) mod_hash_insert(vhcache->vhcache_client_hash,
8213 8202 (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct);
8214 8203 cache_updated = 1;
8215 8204 }
8216 8205
8217 8206 for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) {
8218 8207 if (cpi->cpi_cphci->cphci_phci == ph &&
8219 8208 strcmp(cpi->cpi_addr, pip->pi_addr) == 0) {
8220 8209 cpi->cpi_pip = pip;
8221 8210 if (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST) {
8222 8211 cpi->cpi_flags &=
8223 8212 ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST;
8224 8213 sort_vhcache_paths(cct);
8225 8214 cache_updated = 1;
8226 8215 }
8227 8216 break;
8228 8217 }
8229 8218 }
8230 8219
8231 8220 if (cpi == NULL) {
8232 8221 cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP);
8233 8222 cpi->cpi_addr = i_ddi_strdup(pip->pi_addr, KM_SLEEP);
8234 8223 cpi->cpi_cphci = lookup_vhcache_phci_by_addr(vhcache, ph);
8235 8224 ASSERT(cpi->cpi_cphci != NULL);
8236 8225 cpi->cpi_pip = pip;
8237 8226 enqueue_vhcache_pathinfo(cct, cpi);
8238 8227 cache_updated = 1;
8239 8228 }
8240 8229
8241 8230 rw_exit(&vhcache->vhcache_lock);
8242 8231
8243 8232 if (cache_updated)
8244 8233 vhcache_dirty(vhc);
8245 8234 }
8246 8235
8247 8236 /*
8248 8237 * Remove the reference to the specified path from the vhci cache.
8249 8238 */
8250 8239 static void
8251 8240 vhcache_pi_remove(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip)
8252 8241 {
8253 8242 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
8254 8243 mdi_client_t *ct = pip->pi_client;
8255 8244 mdi_vhcache_client_t *cct;
8256 8245 mdi_vhcache_pathinfo_t *cpi;
8257 8246
8258 8247 rw_enter(&vhcache->vhcache_lock, RW_WRITER);
8259 8248 if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid,
8260 8249 NULL)) != NULL) {
8261 8250 for (cpi = cct->cct_cpi_head; cpi != NULL;
8262 8251 cpi = cpi->cpi_next) {
8263 8252 if (cpi->cpi_pip == pip) {
8264 8253 cpi->cpi_pip = NULL;
8265 8254 break;
8266 8255 }
8267 8256 }
8268 8257 }
8269 8258 rw_exit(&vhcache->vhcache_lock);
8270 8259 }
8271 8260
8272 8261 /*
8273 8262 * Flush the vhci cache to disk.
8274 8263 * Returns MDI_SUCCESS on success, MDI_FAILURE on failure.
8275 8264 */
8276 8265 static int
8277 8266 flush_vhcache(mdi_vhci_config_t *vhc, int force_flag)
8278 8267 {
8279 8268 nvlist_t *nvl;
8280 8269 int err;
8281 8270 int rv;
8282 8271
8283 8272 /*
8284 8273 * It is possible that the system may shutdown before
8285 8274 * i_ddi_io_initialized (during stmsboot for example). To allow for
8286 8275 * flushing the cache in this case do not check for
8287 8276 * i_ddi_io_initialized when force flag is set.
8288 8277 */
8289 8278 if (force_flag == 0 && !i_ddi_io_initialized())
8290 8279 return (MDI_FAILURE);
8291 8280
8292 8281 if ((nvl = vhcache_to_mainnvl(&vhc->vhc_vhcache)) != NULL) {
8293 8282 err = fwrite_nvlist(vhc->vhc_vhcache_filename, nvl);
8294 8283 nvlist_free(nvl);
8295 8284 } else
8296 8285 err = EFAULT;
8297 8286
8298 8287 rv = MDI_SUCCESS;
8299 8288 mutex_enter(&vhc->vhc_lock);
8300 8289 if (err != 0) {
8301 8290 if (err == EROFS) {
8302 8291 vhc->vhc_flags |= MDI_VHC_READONLY_FS;
8303 8292 vhc->vhc_flags &= ~(MDI_VHC_VHCACHE_FLUSH_ERROR |
8304 8293 MDI_VHC_VHCACHE_DIRTY);
8305 8294 } else {
8306 8295 if (!(vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR)) {
8307 8296 cmn_err(CE_CONT, "%s: update failed\n",
8308 8297 vhc->vhc_vhcache_filename);
8309 8298 vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_ERROR;
8310 8299 }
8311 8300 rv = MDI_FAILURE;
8312 8301 }
8313 8302 } else if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR) {
8314 8303 cmn_err(CE_CONT,
8315 8304 "%s: update now ok\n", vhc->vhc_vhcache_filename);
8316 8305 vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_ERROR;
8317 8306 }
8318 8307 mutex_exit(&vhc->vhc_lock);
8319 8308
8320 8309 return (rv);
8321 8310 }
8322 8311
8323 8312 /*
8324 8313 * Call flush_vhcache() to flush the vhci cache at the scheduled time.
8325 8314 * Exits itself if left idle for the idle timeout period.
8326 8315 */
8327 8316 static void
8328 8317 vhcache_flush_thread(void *arg)
8329 8318 {
8330 8319 mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg;
8331 8320 clock_t idle_time, quit_at_ticks;
8332 8321 callb_cpr_t cprinfo;
8333 8322
8334 8323 /* number of seconds to sleep idle before exiting */
8335 8324 idle_time = mdi_vhcache_flush_daemon_idle_time * TICKS_PER_SECOND;
8336 8325
8337 8326 CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr,
8338 8327 "mdi_vhcache_flush");
8339 8328 mutex_enter(&vhc->vhc_lock);
8340 8329 for (; ; ) {
8341 8330 while (!(vhc->vhc_flags & MDI_VHC_EXIT) &&
8342 8331 (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY)) {
8343 8332 if (ddi_get_lbolt() < vhc->vhc_flush_at_ticks) {
8344 8333 CALLB_CPR_SAFE_BEGIN(&cprinfo);
8345 8334 (void) cv_timedwait(&vhc->vhc_cv,
8346 8335 &vhc->vhc_lock, vhc->vhc_flush_at_ticks);
8347 8336 CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock);
8348 8337 } else {
8349 8338 vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY;
8350 8339 mutex_exit(&vhc->vhc_lock);
8351 8340
8352 8341 if (flush_vhcache(vhc, 0) != MDI_SUCCESS)
8353 8342 vhcache_dirty(vhc);
8354 8343
8355 8344 mutex_enter(&vhc->vhc_lock);
8356 8345 }
8357 8346 }
8358 8347
8359 8348 quit_at_ticks = ddi_get_lbolt() + idle_time;
8360 8349
8361 8350 while (!(vhc->vhc_flags & MDI_VHC_EXIT) &&
8362 8351 !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) &&
8363 8352 ddi_get_lbolt() < quit_at_ticks) {
8364 8353 CALLB_CPR_SAFE_BEGIN(&cprinfo);
8365 8354 (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock,
8366 8355 quit_at_ticks);
8367 8356 CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock);
8368 8357 }
8369 8358
8370 8359 if ((vhc->vhc_flags & MDI_VHC_EXIT) ||
8371 8360 !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY))
8372 8361 goto out;
8373 8362 }
8374 8363
8375 8364 out:
8376 8365 vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_THREAD;
8377 8366 /* CALLB_CPR_EXIT releases the vhc->vhc_lock */
8378 8367 CALLB_CPR_EXIT(&cprinfo);
8379 8368 }
8380 8369
8381 8370 /*
8382 8371 * Make vhci cache dirty and schedule flushing by vhcache flush thread.
8383 8372 */
8384 8373 static void
8385 8374 vhcache_dirty(mdi_vhci_config_t *vhc)
8386 8375 {
8387 8376 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
8388 8377 int create_thread;
8389 8378
8390 8379 rw_enter(&vhcache->vhcache_lock, RW_READER);
8391 8380 /* do not flush cache until the cache is fully built */
8392 8381 if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) {
8393 8382 rw_exit(&vhcache->vhcache_lock);
8394 8383 return;
8395 8384 }
8396 8385 rw_exit(&vhcache->vhcache_lock);
8397 8386
8398 8387 mutex_enter(&vhc->vhc_lock);
8399 8388 if (vhc->vhc_flags & MDI_VHC_READONLY_FS) {
8400 8389 mutex_exit(&vhc->vhc_lock);
8401 8390 return;
8402 8391 }
8403 8392
8404 8393 vhc->vhc_flags |= MDI_VHC_VHCACHE_DIRTY;
8405 8394 vhc->vhc_flush_at_ticks = ddi_get_lbolt() +
8406 8395 mdi_vhcache_flush_delay * TICKS_PER_SECOND;
8407 8396 if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) {
8408 8397 cv_broadcast(&vhc->vhc_cv);
8409 8398 create_thread = 0;
8410 8399 } else {
8411 8400 vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_THREAD;
8412 8401 create_thread = 1;
8413 8402 }
8414 8403 mutex_exit(&vhc->vhc_lock);
8415 8404
8416 8405 if (create_thread)
8417 8406 (void) thread_create(NULL, 0, vhcache_flush_thread, vhc,
8418 8407 0, &p0, TS_RUN, minclsyspri);
8419 8408 }
8420 8409
8421 8410 /*
8422 8411 * phci bus config structure - one for for each phci bus config operation that
8423 8412 * we initiate on behalf of a vhci.
8424 8413 */
8425 8414 typedef struct mdi_phci_bus_config_s {
8426 8415 char *phbc_phci_path;
8427 8416 struct mdi_vhci_bus_config_s *phbc_vhbusconfig; /* vhci bus config */
8428 8417 struct mdi_phci_bus_config_s *phbc_next;
8429 8418 } mdi_phci_bus_config_t;
8430 8419
8431 8420 /* vhci bus config structure - one for each vhci bus config operation */
8432 8421 typedef struct mdi_vhci_bus_config_s {
8433 8422 ddi_bus_config_op_t vhbc_op; /* bus config op */
8434 8423 major_t vhbc_op_major; /* bus config op major */
8435 8424 uint_t vhbc_op_flags; /* bus config op flags */
8436 8425 kmutex_t vhbc_lock;
8437 8426 kcondvar_t vhbc_cv;
8438 8427 int vhbc_thr_count;
8439 8428 } mdi_vhci_bus_config_t;
8440 8429
8441 8430 /*
8442 8431 * bus config the specified phci
8443 8432 */
8444 8433 static void
8445 8434 bus_config_phci(void *arg)
8446 8435 {
8447 8436 mdi_phci_bus_config_t *phbc = (mdi_phci_bus_config_t *)arg;
8448 8437 mdi_vhci_bus_config_t *vhbc = phbc->phbc_vhbusconfig;
8449 8438 dev_info_t *ph_dip;
8450 8439
8451 8440 /*
8452 8441 * first configure all path components upto phci and then configure
8453 8442 * the phci children.
8454 8443 */
8455 8444 if ((ph_dip = e_ddi_hold_devi_by_path(phbc->phbc_phci_path, 0))
8456 8445 != NULL) {
8457 8446 if (vhbc->vhbc_op == BUS_CONFIG_DRIVER ||
8458 8447 vhbc->vhbc_op == BUS_UNCONFIG_DRIVER) {
8459 8448 (void) ndi_devi_config_driver(ph_dip,
8460 8449 vhbc->vhbc_op_flags,
8461 8450 vhbc->vhbc_op_major);
8462 8451 } else
8463 8452 (void) ndi_devi_config(ph_dip,
8464 8453 vhbc->vhbc_op_flags);
8465 8454
8466 8455 /* release the hold that e_ddi_hold_devi_by_path() placed */
8467 8456 ndi_rele_devi(ph_dip);
8468 8457 }
8469 8458
8470 8459 kmem_free(phbc->phbc_phci_path, strlen(phbc->phbc_phci_path) + 1);
8471 8460 kmem_free(phbc, sizeof (*phbc));
8472 8461
8473 8462 mutex_enter(&vhbc->vhbc_lock);
8474 8463 vhbc->vhbc_thr_count--;
8475 8464 if (vhbc->vhbc_thr_count == 0)
8476 8465 cv_broadcast(&vhbc->vhbc_cv);
8477 8466 mutex_exit(&vhbc->vhbc_lock);
8478 8467 }
8479 8468
8480 8469 /*
8481 8470 * Bus config all phcis associated with the vhci in parallel.
8482 8471 * op must be BUS_CONFIG_DRIVER or BUS_CONFIG_ALL.
8483 8472 */
8484 8473 static void
8485 8474 bus_config_all_phcis(mdi_vhci_cache_t *vhcache, uint_t flags,
8486 8475 ddi_bus_config_op_t op, major_t maj)
8487 8476 {
8488 8477 mdi_phci_bus_config_t *phbc_head = NULL, *phbc, *phbc_next;
8489 8478 mdi_vhci_bus_config_t *vhbc;
8490 8479 mdi_vhcache_phci_t *cphci;
8491 8480
8492 8481 rw_enter(&vhcache->vhcache_lock, RW_READER);
8493 8482 if (vhcache->vhcache_phci_head == NULL) {
8494 8483 rw_exit(&vhcache->vhcache_lock);
8495 8484 return;
8496 8485 }
8497 8486
8498 8487 vhbc = kmem_zalloc(sizeof (*vhbc), KM_SLEEP);
8499 8488
8500 8489 for (cphci = vhcache->vhcache_phci_head; cphci != NULL;
8501 8490 cphci = cphci->cphci_next) {
8502 8491 /* skip phcis that haven't attached before root is available */
8503 8492 if (!modrootloaded && (cphci->cphci_phci == NULL))
8504 8493 continue;
8505 8494 phbc = kmem_zalloc(sizeof (*phbc), KM_SLEEP);
8506 8495 phbc->phbc_phci_path = i_ddi_strdup(cphci->cphci_path,
8507 8496 KM_SLEEP);
8508 8497 phbc->phbc_vhbusconfig = vhbc;
8509 8498 phbc->phbc_next = phbc_head;
8510 8499 phbc_head = phbc;
8511 8500 vhbc->vhbc_thr_count++;
8512 8501 }
8513 8502 rw_exit(&vhcache->vhcache_lock);
8514 8503
8515 8504 vhbc->vhbc_op = op;
8516 8505 vhbc->vhbc_op_major = maj;
8517 8506 vhbc->vhbc_op_flags = NDI_NO_EVENT |
8518 8507 (flags & (NDI_CONFIG_REPROBE | NDI_DRV_CONF_REPROBE));
8519 8508 mutex_init(&vhbc->vhbc_lock, NULL, MUTEX_DEFAULT, NULL);
8520 8509 cv_init(&vhbc->vhbc_cv, NULL, CV_DRIVER, NULL);
8521 8510
8522 8511 /* now create threads to initiate bus config on all phcis in parallel */
8523 8512 for (phbc = phbc_head; phbc != NULL; phbc = phbc_next) {
8524 8513 phbc_next = phbc->phbc_next;
8525 8514 if (mdi_mtc_off)
8526 8515 bus_config_phci((void *)phbc);
8527 8516 else
8528 8517 (void) thread_create(NULL, 0, bus_config_phci, phbc,
8529 8518 0, &p0, TS_RUN, minclsyspri);
8530 8519 }
8531 8520
8532 8521 mutex_enter(&vhbc->vhbc_lock);
8533 8522 /* wait until all threads exit */
8534 8523 while (vhbc->vhbc_thr_count > 0)
8535 8524 cv_wait(&vhbc->vhbc_cv, &vhbc->vhbc_lock);
8536 8525 mutex_exit(&vhbc->vhbc_lock);
8537 8526
8538 8527 mutex_destroy(&vhbc->vhbc_lock);
8539 8528 cv_destroy(&vhbc->vhbc_cv);
8540 8529 kmem_free(vhbc, sizeof (*vhbc));
8541 8530 }
8542 8531
8543 8532 /*
8544 8533 * Single threaded version of bus_config_all_phcis()
8545 8534 */
8546 8535 static void
8547 8536 st_bus_config_all_phcis(mdi_vhci_config_t *vhc, uint_t flags,
8548 8537 ddi_bus_config_op_t op, major_t maj)
8549 8538 {
8550 8539 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
8551 8540
8552 8541 single_threaded_vhconfig_enter(vhc);
8553 8542 bus_config_all_phcis(vhcache, flags, op, maj);
8554 8543 single_threaded_vhconfig_exit(vhc);
8555 8544 }
8556 8545
8557 8546 /*
8558 8547 * Perform BUS_CONFIG_ONE on the specified child of the phci.
8559 8548 * The path includes the child component in addition to the phci path.
8560 8549 */
8561 8550 static int
8562 8551 bus_config_one_phci_child(char *path)
8563 8552 {
8564 8553 dev_info_t *ph_dip, *child;
8565 8554 char *devnm;
8566 8555 int rv = MDI_FAILURE;
8567 8556
8568 8557 /* extract the child component of the phci */
8569 8558 devnm = strrchr(path, '/');
8570 8559 *devnm++ = '\0';
8571 8560
8572 8561 /*
8573 8562 * first configure all path components upto phci and then
8574 8563 * configure the phci child.
8575 8564 */
8576 8565 if ((ph_dip = e_ddi_hold_devi_by_path(path, 0)) != NULL) {
8577 8566 if (ndi_devi_config_one(ph_dip, devnm, &child, NDI_NO_EVENT) ==
8578 8567 NDI_SUCCESS) {
8579 8568 /*
8580 8569 * release the hold that ndi_devi_config_one() placed
8581 8570 */
8582 8571 ndi_rele_devi(child);
8583 8572 rv = MDI_SUCCESS;
8584 8573 }
8585 8574
8586 8575 /* release the hold that e_ddi_hold_devi_by_path() placed */
8587 8576 ndi_rele_devi(ph_dip);
8588 8577 }
8589 8578
8590 8579 devnm--;
8591 8580 *devnm = '/';
8592 8581 return (rv);
8593 8582 }
8594 8583
8595 8584 /*
8596 8585 * Build a list of phci client paths for the specified vhci client.
8597 8586 * The list includes only those phci client paths which aren't configured yet.
8598 8587 */
8599 8588 static mdi_phys_path_t *
8600 8589 build_phclient_path_list(mdi_vhcache_client_t *cct, char *ct_name)
8601 8590 {
8602 8591 mdi_vhcache_pathinfo_t *cpi;
8603 8592 mdi_phys_path_t *pp_head = NULL, *pp_tail = NULL, *pp;
8604 8593 int config_path, len;
8605 8594
8606 8595 for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) {
8607 8596 /*
8608 8597 * include only those paths that aren't configured.
8609 8598 */
8610 8599 config_path = 0;
8611 8600 if (cpi->cpi_pip == NULL)
8612 8601 config_path = 1;
8613 8602 else {
8614 8603 MDI_PI_LOCK(cpi->cpi_pip);
8615 8604 if (MDI_PI_IS_INIT(cpi->cpi_pip))
8616 8605 config_path = 1;
8617 8606 MDI_PI_UNLOCK(cpi->cpi_pip);
8618 8607 }
8619 8608
8620 8609 if (config_path) {
8621 8610 pp = kmem_alloc(sizeof (*pp), KM_SLEEP);
8622 8611 len = strlen(cpi->cpi_cphci->cphci_path) +
8623 8612 strlen(ct_name) + strlen(cpi->cpi_addr) + 3;
8624 8613 pp->phys_path = kmem_alloc(len, KM_SLEEP);
8625 8614 (void) snprintf(pp->phys_path, len, "%s/%s@%s",
8626 8615 cpi->cpi_cphci->cphci_path, ct_name,
8627 8616 cpi->cpi_addr);
8628 8617 pp->phys_path_next = NULL;
8629 8618
8630 8619 if (pp_head == NULL)
8631 8620 pp_head = pp;
8632 8621 else
8633 8622 pp_tail->phys_path_next = pp;
8634 8623 pp_tail = pp;
8635 8624 }
8636 8625 }
8637 8626
8638 8627 return (pp_head);
8639 8628 }
8640 8629
8641 8630 /*
8642 8631 * Free the memory allocated for phci client path list.
8643 8632 */
8644 8633 static void
8645 8634 free_phclient_path_list(mdi_phys_path_t *pp_head)
8646 8635 {
8647 8636 mdi_phys_path_t *pp, *pp_next;
8648 8637
8649 8638 for (pp = pp_head; pp != NULL; pp = pp_next) {
8650 8639 pp_next = pp->phys_path_next;
8651 8640 kmem_free(pp->phys_path, strlen(pp->phys_path) + 1);
8652 8641 kmem_free(pp, sizeof (*pp));
8653 8642 }
8654 8643 }
8655 8644
8656 8645 /*
8657 8646 * Allocated async client structure and initialize with the specified values.
8658 8647 */
8659 8648 static mdi_async_client_config_t *
8660 8649 alloc_async_client_config(char *ct_name, char *ct_addr,
8661 8650 mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok)
8662 8651 {
8663 8652 mdi_async_client_config_t *acc;
8664 8653
8665 8654 acc = kmem_alloc(sizeof (*acc), KM_SLEEP);
8666 8655 acc->acc_ct_name = i_ddi_strdup(ct_name, KM_SLEEP);
8667 8656 acc->acc_ct_addr = i_ddi_strdup(ct_addr, KM_SLEEP);
8668 8657 acc->acc_phclient_path_list_head = pp_head;
8669 8658 init_vhcache_lookup_token(&acc->acc_token, tok);
8670 8659 acc->acc_next = NULL;
8671 8660 return (acc);
8672 8661 }
8673 8662
8674 8663 /*
8675 8664 * Free the memory allocated for the async client structure and their members.
8676 8665 */
8677 8666 static void
8678 8667 free_async_client_config(mdi_async_client_config_t *acc)
8679 8668 {
8680 8669 if (acc->acc_phclient_path_list_head)
8681 8670 free_phclient_path_list(acc->acc_phclient_path_list_head);
8682 8671 kmem_free(acc->acc_ct_name, strlen(acc->acc_ct_name) + 1);
8683 8672 kmem_free(acc->acc_ct_addr, strlen(acc->acc_ct_addr) + 1);
8684 8673 kmem_free(acc, sizeof (*acc));
8685 8674 }
8686 8675
8687 8676 /*
8688 8677 * Sort vhcache pathinfos (cpis) of the specified client.
8689 8678 * All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST
8690 8679 * flag set come at the beginning of the list. All cpis which have this
8691 8680 * flag set come at the end of the list.
8692 8681 */
8693 8682 static void
8694 8683 sort_vhcache_paths(mdi_vhcache_client_t *cct)
8695 8684 {
8696 8685 mdi_vhcache_pathinfo_t *cpi, *cpi_next, *cpi_head;
8697 8686
8698 8687 cpi_head = cct->cct_cpi_head;
8699 8688 cct->cct_cpi_head = cct->cct_cpi_tail = NULL;
8700 8689 for (cpi = cpi_head; cpi != NULL; cpi = cpi_next) {
8701 8690 cpi_next = cpi->cpi_next;
8702 8691 enqueue_vhcache_pathinfo(cct, cpi);
8703 8692 }
8704 8693 }
8705 8694
8706 8695 /*
8707 8696 * Verify whether MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag setting is correct for
8708 8697 * every vhcache pathinfo of the specified client. If not adjust the flag
8709 8698 * setting appropriately.
8710 8699 *
8711 8700 * Note that MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag is persisted in the
8712 8701 * on-disk vhci cache. So every time this flag is updated the cache must be
8713 8702 * flushed.
8714 8703 */
8715 8704 static void
8716 8705 adjust_sort_vhcache_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr,
8717 8706 mdi_vhcache_lookup_token_t *tok)
8718 8707 {
8719 8708 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
8720 8709 mdi_vhcache_client_t *cct;
8721 8710 mdi_vhcache_pathinfo_t *cpi;
8722 8711
8723 8712 rw_enter(&vhcache->vhcache_lock, RW_READER);
8724 8713 if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, tok))
8725 8714 == NULL) {
8726 8715 rw_exit(&vhcache->vhcache_lock);
8727 8716 return;
8728 8717 }
8729 8718
8730 8719 /*
8731 8720 * to avoid unnecessary on-disk cache updates, first check if an
8732 8721 * update is really needed. If no update is needed simply return.
8733 8722 */
8734 8723 for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) {
8735 8724 if ((cpi->cpi_pip != NULL &&
8736 8725 (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST)) ||
8737 8726 (cpi->cpi_pip == NULL &&
8738 8727 !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST))) {
8739 8728 break;
8740 8729 }
8741 8730 }
8742 8731 if (cpi == NULL) {
8743 8732 rw_exit(&vhcache->vhcache_lock);
8744 8733 return;
8745 8734 }
8746 8735
8747 8736 if (rw_tryupgrade(&vhcache->vhcache_lock) == 0) {
8748 8737 rw_exit(&vhcache->vhcache_lock);
8749 8738 rw_enter(&vhcache->vhcache_lock, RW_WRITER);
8750 8739 if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr,
8751 8740 tok)) == NULL) {
8752 8741 rw_exit(&vhcache->vhcache_lock);
8753 8742 return;
8754 8743 }
8755 8744 }
8756 8745
8757 8746 for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) {
8758 8747 if (cpi->cpi_pip != NULL)
8759 8748 cpi->cpi_flags &= ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST;
8760 8749 else
8761 8750 cpi->cpi_flags |= MDI_CPI_HINT_PATH_DOES_NOT_EXIST;
8762 8751 }
8763 8752 sort_vhcache_paths(cct);
8764 8753
8765 8754 rw_exit(&vhcache->vhcache_lock);
8766 8755 vhcache_dirty(vhc);
8767 8756 }
8768 8757
8769 8758 /*
8770 8759 * Configure all specified paths of the client.
8771 8760 */
8772 8761 static void
8773 8762 config_client_paths_sync(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr,
8774 8763 mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok)
8775 8764 {
8776 8765 mdi_phys_path_t *pp;
8777 8766
8778 8767 for (pp = pp_head; pp != NULL; pp = pp->phys_path_next)
8779 8768 (void) bus_config_one_phci_child(pp->phys_path);
8780 8769 adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, tok);
8781 8770 }
8782 8771
8783 8772 /*
8784 8773 * Dequeue elements from vhci async client config list and bus configure
8785 8774 * their corresponding phci clients.
8786 8775 */
8787 8776 static void
8788 8777 config_client_paths_thread(void *arg)
8789 8778 {
8790 8779 mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg;
8791 8780 mdi_async_client_config_t *acc;
8792 8781 clock_t quit_at_ticks;
8793 8782 clock_t idle_time = mdi_async_config_idle_time * TICKS_PER_SECOND;
8794 8783 callb_cpr_t cprinfo;
8795 8784
8796 8785 CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr,
8797 8786 "mdi_config_client_paths");
8798 8787
8799 8788 for (; ; ) {
8800 8789 quit_at_ticks = ddi_get_lbolt() + idle_time;
8801 8790
8802 8791 mutex_enter(&vhc->vhc_lock);
8803 8792 while (!(vhc->vhc_flags & MDI_VHC_EXIT) &&
8804 8793 vhc->vhc_acc_list_head == NULL &&
8805 8794 ddi_get_lbolt() < quit_at_ticks) {
8806 8795 CALLB_CPR_SAFE_BEGIN(&cprinfo);
8807 8796 (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock,
8808 8797 quit_at_ticks);
8809 8798 CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock);
8810 8799 }
8811 8800
8812 8801 if ((vhc->vhc_flags & MDI_VHC_EXIT) ||
8813 8802 vhc->vhc_acc_list_head == NULL)
8814 8803 goto out;
8815 8804
8816 8805 acc = vhc->vhc_acc_list_head;
8817 8806 vhc->vhc_acc_list_head = acc->acc_next;
8818 8807 if (vhc->vhc_acc_list_head == NULL)
8819 8808 vhc->vhc_acc_list_tail = NULL;
8820 8809 vhc->vhc_acc_count--;
8821 8810 mutex_exit(&vhc->vhc_lock);
8822 8811
8823 8812 config_client_paths_sync(vhc, acc->acc_ct_name,
8824 8813 acc->acc_ct_addr, acc->acc_phclient_path_list_head,
8825 8814 &acc->acc_token);
8826 8815
8827 8816 free_async_client_config(acc);
8828 8817 }
8829 8818
8830 8819 out:
8831 8820 vhc->vhc_acc_thrcount--;
8832 8821 /* CALLB_CPR_EXIT releases the vhc->vhc_lock */
8833 8822 CALLB_CPR_EXIT(&cprinfo);
8834 8823 }
8835 8824
8836 8825 /*
8837 8826 * Arrange for all the phci client paths (pp_head) for the specified client
8838 8827 * to be bus configured asynchronously by a thread.
8839 8828 */
8840 8829 static void
8841 8830 config_client_paths_async(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr,
8842 8831 mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok)
8843 8832 {
8844 8833 mdi_async_client_config_t *acc, *newacc;
8845 8834 int create_thread;
8846 8835
8847 8836 if (pp_head == NULL)
8848 8837 return;
8849 8838
8850 8839 if (mdi_mtc_off) {
8851 8840 config_client_paths_sync(vhc, ct_name, ct_addr, pp_head, tok);
8852 8841 free_phclient_path_list(pp_head);
8853 8842 return;
8854 8843 }
8855 8844
8856 8845 newacc = alloc_async_client_config(ct_name, ct_addr, pp_head, tok);
8857 8846 ASSERT(newacc);
8858 8847
8859 8848 mutex_enter(&vhc->vhc_lock);
8860 8849 for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc->acc_next) {
8861 8850 if (strcmp(ct_name, acc->acc_ct_name) == 0 &&
8862 8851 strcmp(ct_addr, acc->acc_ct_addr) == 0) {
8863 8852 free_async_client_config(newacc);
8864 8853 mutex_exit(&vhc->vhc_lock);
8865 8854 return;
8866 8855 }
8867 8856 }
8868 8857
8869 8858 if (vhc->vhc_acc_list_head == NULL)
8870 8859 vhc->vhc_acc_list_head = newacc;
8871 8860 else
8872 8861 vhc->vhc_acc_list_tail->acc_next = newacc;
8873 8862 vhc->vhc_acc_list_tail = newacc;
8874 8863 vhc->vhc_acc_count++;
8875 8864 if (vhc->vhc_acc_count <= vhc->vhc_acc_thrcount) {
8876 8865 cv_broadcast(&vhc->vhc_cv);
8877 8866 create_thread = 0;
8878 8867 } else {
8879 8868 vhc->vhc_acc_thrcount++;
8880 8869 create_thread = 1;
8881 8870 }
8882 8871 mutex_exit(&vhc->vhc_lock);
8883 8872
8884 8873 if (create_thread)
8885 8874 (void) thread_create(NULL, 0, config_client_paths_thread, vhc,
8886 8875 0, &p0, TS_RUN, minclsyspri);
8887 8876 }
8888 8877
8889 8878 /*
8890 8879 * Return number of online paths for the specified client.
8891 8880 */
8892 8881 static int
8893 8882 nonline_paths(mdi_vhcache_client_t *cct)
8894 8883 {
8895 8884 mdi_vhcache_pathinfo_t *cpi;
8896 8885 int online_count = 0;
8897 8886
8898 8887 for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) {
8899 8888 if (cpi->cpi_pip != NULL) {
8900 8889 MDI_PI_LOCK(cpi->cpi_pip);
8901 8890 if (cpi->cpi_pip->pi_state == MDI_PATHINFO_STATE_ONLINE)
8902 8891 online_count++;
8903 8892 MDI_PI_UNLOCK(cpi->cpi_pip);
8904 8893 }
8905 8894 }
8906 8895
8907 8896 return (online_count);
8908 8897 }
8909 8898
8910 8899 /*
8911 8900 * Bus configure all paths for the specified vhci client.
8912 8901 * If at least one path for the client is already online, the remaining paths
8913 8902 * will be configured asynchronously. Otherwise, it synchronously configures
8914 8903 * the paths until at least one path is online and then rest of the paths
8915 8904 * will be configured asynchronously.
8916 8905 */
8917 8906 static void
8918 8907 config_client_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr)
8919 8908 {
8920 8909 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
8921 8910 mdi_phys_path_t *pp_head, *pp;
8922 8911 mdi_vhcache_client_t *cct;
8923 8912 mdi_vhcache_lookup_token_t tok;
8924 8913
8925 8914 ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock));
8926 8915
8927 8916 init_vhcache_lookup_token(&tok, NULL);
8928 8917
8929 8918 if (ct_name == NULL || ct_addr == NULL ||
8930 8919 (cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, &tok))
8931 8920 == NULL ||
8932 8921 (pp_head = build_phclient_path_list(cct, ct_name)) == NULL) {
8933 8922 rw_exit(&vhcache->vhcache_lock);
8934 8923 return;
8935 8924 }
8936 8925
8937 8926 /* if at least one path is online, configure the rest asynchronously */
8938 8927 if (nonline_paths(cct) > 0) {
8939 8928 rw_exit(&vhcache->vhcache_lock);
8940 8929 config_client_paths_async(vhc, ct_name, ct_addr, pp_head, &tok);
8941 8930 return;
8942 8931 }
8943 8932
8944 8933 rw_exit(&vhcache->vhcache_lock);
8945 8934
8946 8935 for (pp = pp_head; pp != NULL; pp = pp->phys_path_next) {
8947 8936 if (bus_config_one_phci_child(pp->phys_path) == MDI_SUCCESS) {
8948 8937 rw_enter(&vhcache->vhcache_lock, RW_READER);
8949 8938
8950 8939 if ((cct = lookup_vhcache_client(vhcache, ct_name,
8951 8940 ct_addr, &tok)) == NULL) {
8952 8941 rw_exit(&vhcache->vhcache_lock);
8953 8942 goto out;
8954 8943 }
8955 8944
8956 8945 if (nonline_paths(cct) > 0 &&
8957 8946 pp->phys_path_next != NULL) {
8958 8947 rw_exit(&vhcache->vhcache_lock);
8959 8948 config_client_paths_async(vhc, ct_name, ct_addr,
8960 8949 pp->phys_path_next, &tok);
8961 8950 pp->phys_path_next = NULL;
8962 8951 goto out;
8963 8952 }
8964 8953
8965 8954 rw_exit(&vhcache->vhcache_lock);
8966 8955 }
8967 8956 }
8968 8957
8969 8958 adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, &tok);
8970 8959 out:
8971 8960 free_phclient_path_list(pp_head);
8972 8961 }
8973 8962
8974 8963 static void
8975 8964 single_threaded_vhconfig_enter(mdi_vhci_config_t *vhc)
8976 8965 {
8977 8966 mutex_enter(&vhc->vhc_lock);
8978 8967 while (vhc->vhc_flags & MDI_VHC_SINGLE_THREADED)
8979 8968 cv_wait(&vhc->vhc_cv, &vhc->vhc_lock);
8980 8969 vhc->vhc_flags |= MDI_VHC_SINGLE_THREADED;
8981 8970 mutex_exit(&vhc->vhc_lock);
8982 8971 }
8983 8972
8984 8973 static void
8985 8974 single_threaded_vhconfig_exit(mdi_vhci_config_t *vhc)
8986 8975 {
8987 8976 mutex_enter(&vhc->vhc_lock);
8988 8977 vhc->vhc_flags &= ~MDI_VHC_SINGLE_THREADED;
8989 8978 cv_broadcast(&vhc->vhc_cv);
8990 8979 mutex_exit(&vhc->vhc_lock);
8991 8980 }
8992 8981
8993 8982 typedef struct mdi_phci_driver_info {
8994 8983 char *phdriver_name; /* name of the phci driver */
8995 8984
8996 8985 /* set to non zero if the phci driver supports root device */
8997 8986 int phdriver_root_support;
8998 8987 } mdi_phci_driver_info_t;
8999 8988
9000 8989 /*
9001 8990 * vhci class and root support capability of a phci driver can be
9002 8991 * specified using ddi-vhci-class and ddi-no-root-support properties in the
9003 8992 * phci driver.conf file. The built-in tables below contain this information
9004 8993 * for those phci drivers whose driver.conf files don't yet contain this info.
9005 8994 *
9006 8995 * All phci drivers expect iscsi have root device support.
9007 8996 */
9008 8997 static mdi_phci_driver_info_t scsi_phci_driver_list[] = {
9009 8998 { "fp", 1 },
9010 8999 { "iscsi", 0 },
9011 9000 { "ibsrp", 1 }
9012 9001 };
9013 9002
9014 9003 static mdi_phci_driver_info_t ib_phci_driver_list[] = { "tavor", 1 };
9015 9004
9016 9005 static void *
9017 9006 mdi_realloc(void *old_ptr, size_t old_size, size_t new_size)
9018 9007 {
9019 9008 void *new_ptr;
9020 9009
9021 9010 new_ptr = kmem_zalloc(new_size, KM_SLEEP);
9022 9011 if (old_ptr) {
9023 9012 bcopy(old_ptr, new_ptr, MIN(old_size, new_size));
9024 9013 kmem_free(old_ptr, old_size);
9025 9014 }
9026 9015 return (new_ptr);
9027 9016 }
9028 9017
9029 9018 static void
9030 9019 add_to_phci_list(char ***driver_list, int **root_support_list,
9031 9020 int *cur_elements, int *max_elements, char *driver_name, int root_support)
9032 9021 {
9033 9022 ASSERT(*cur_elements <= *max_elements);
9034 9023 if (*cur_elements == *max_elements) {
9035 9024 *max_elements += 10;
9036 9025 *driver_list = mdi_realloc(*driver_list,
9037 9026 sizeof (char *) * (*cur_elements),
9038 9027 sizeof (char *) * (*max_elements));
9039 9028 *root_support_list = mdi_realloc(*root_support_list,
9040 9029 sizeof (int) * (*cur_elements),
9041 9030 sizeof (int) * (*max_elements));
9042 9031 }
9043 9032 (*driver_list)[*cur_elements] = i_ddi_strdup(driver_name, KM_SLEEP);
9044 9033 (*root_support_list)[*cur_elements] = root_support;
9045 9034 (*cur_elements)++;
9046 9035 }
9047 9036
9048 9037 static void
9049 9038 get_phci_driver_list(char *vhci_class, char ***driver_list,
9050 9039 int **root_support_list, int *cur_elements, int *max_elements)
9051 9040 {
9052 9041 mdi_phci_driver_info_t *st_driver_list, *p;
9053 9042 int st_ndrivers, root_support, i, j, driver_conf_count;
9054 9043 major_t m;
9055 9044 struct devnames *dnp;
9056 9045 ddi_prop_t *propp;
9057 9046
9058 9047 *driver_list = NULL;
9059 9048 *root_support_list = NULL;
9060 9049 *cur_elements = 0;
9061 9050 *max_elements = 0;
9062 9051
9063 9052 /* add the phci drivers derived from the phci driver.conf files */
9064 9053 for (m = 0; m < devcnt; m++) {
9065 9054 dnp = &devnamesp[m];
9066 9055
9067 9056 if (dnp->dn_flags & DN_PHCI_DRIVER) {
9068 9057 LOCK_DEV_OPS(&dnp->dn_lock);
9069 9058 if (dnp->dn_global_prop_ptr != NULL &&
9070 9059 (propp = i_ddi_prop_search(DDI_DEV_T_ANY,
9071 9060 DDI_VHCI_CLASS, DDI_PROP_TYPE_STRING,
9072 9061 &dnp->dn_global_prop_ptr->prop_list)) != NULL &&
9073 9062 strcmp(propp->prop_val, vhci_class) == 0) {
9074 9063
9075 9064 root_support = (i_ddi_prop_search(DDI_DEV_T_ANY,
9076 9065 DDI_NO_ROOT_SUPPORT, DDI_PROP_TYPE_INT,
9077 9066 &dnp->dn_global_prop_ptr->prop_list)
9078 9067 == NULL) ? 1 : 0;
9079 9068
9080 9069 add_to_phci_list(driver_list, root_support_list,
9081 9070 cur_elements, max_elements, dnp->dn_name,
9082 9071 root_support);
9083 9072
9084 9073 UNLOCK_DEV_OPS(&dnp->dn_lock);
9085 9074 } else
9086 9075 UNLOCK_DEV_OPS(&dnp->dn_lock);
9087 9076 }
9088 9077 }
9089 9078
9090 9079 driver_conf_count = *cur_elements;
9091 9080
9092 9081 /* add the phci drivers specified in the built-in tables */
9093 9082 if (strcmp(vhci_class, MDI_HCI_CLASS_SCSI) == 0) {
9094 9083 st_driver_list = scsi_phci_driver_list;
9095 9084 st_ndrivers = sizeof (scsi_phci_driver_list) /
9096 9085 sizeof (mdi_phci_driver_info_t);
9097 9086 } else if (strcmp(vhci_class, MDI_HCI_CLASS_IB) == 0) {
9098 9087 st_driver_list = ib_phci_driver_list;
9099 9088 st_ndrivers = sizeof (ib_phci_driver_list) /
9100 9089 sizeof (mdi_phci_driver_info_t);
9101 9090 } else {
9102 9091 st_driver_list = NULL;
9103 9092 st_ndrivers = 0;
9104 9093 }
9105 9094
9106 9095 for (i = 0, p = st_driver_list; i < st_ndrivers; i++, p++) {
9107 9096 /* add this phci driver if not already added before */
9108 9097 for (j = 0; j < driver_conf_count; j++) {
9109 9098 if (strcmp((*driver_list)[j], p->phdriver_name) == 0)
9110 9099 break;
9111 9100 }
9112 9101 if (j == driver_conf_count) {
9113 9102 add_to_phci_list(driver_list, root_support_list,
9114 9103 cur_elements, max_elements, p->phdriver_name,
9115 9104 p->phdriver_root_support);
9116 9105 }
9117 9106 }
9118 9107 }
9119 9108
9120 9109 /*
9121 9110 * Attach the phci driver instances associated with the specified vhci class.
9122 9111 * If root is mounted attach all phci driver instances.
9123 9112 * If root is not mounted, attach the instances of only those phci
9124 9113 * drivers that have the root support.
9125 9114 */
9126 9115 static void
9127 9116 attach_phci_drivers(char *vhci_class)
9128 9117 {
9129 9118 char **driver_list, **p;
9130 9119 int *root_support_list;
9131 9120 int cur_elements, max_elements, i;
9132 9121 major_t m;
9133 9122
9134 9123 get_phci_driver_list(vhci_class, &driver_list, &root_support_list,
9135 9124 &cur_elements, &max_elements);
9136 9125
9137 9126 for (i = 0; i < cur_elements; i++) {
9138 9127 if (modrootloaded || root_support_list[i]) {
9139 9128 m = ddi_name_to_major(driver_list[i]);
9140 9129 if (m != DDI_MAJOR_T_NONE &&
9141 9130 ddi_hold_installed_driver(m))
9142 9131 ddi_rele_driver(m);
9143 9132 }
9144 9133 }
9145 9134
9146 9135 if (driver_list) {
9147 9136 for (i = 0, p = driver_list; i < cur_elements; i++, p++)
9148 9137 kmem_free(*p, strlen(*p) + 1);
9149 9138 kmem_free(driver_list, sizeof (char *) * max_elements);
9150 9139 kmem_free(root_support_list, sizeof (int) * max_elements);
9151 9140 }
9152 9141 }
9153 9142
9154 9143 /*
9155 9144 * Build vhci cache:
9156 9145 *
9157 9146 * Attach phci driver instances and then drive BUS_CONFIG_ALL on
9158 9147 * the phci driver instances. During this process the cache gets built.
9159 9148 *
9160 9149 * Cache is built fully if the root is mounted.
9161 9150 * If the root is not mounted, phci drivers that do not have root support
9162 9151 * are not attached. As a result the cache is built partially. The entries
9163 9152 * in the cache reflect only those phci drivers that have root support.
9164 9153 */
9165 9154 static int
9166 9155 build_vhci_cache(mdi_vhci_t *vh)
9167 9156 {
9168 9157 mdi_vhci_config_t *vhc = vh->vh_config;
9169 9158 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
9170 9159
9171 9160 single_threaded_vhconfig_enter(vhc);
9172 9161
9173 9162 rw_enter(&vhcache->vhcache_lock, RW_READER);
9174 9163 if (vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE) {
9175 9164 rw_exit(&vhcache->vhcache_lock);
9176 9165 single_threaded_vhconfig_exit(vhc);
9177 9166 return (0);
9178 9167 }
9179 9168 rw_exit(&vhcache->vhcache_lock);
9180 9169
9181 9170 attach_phci_drivers(vh->vh_class);
9182 9171 bus_config_all_phcis(vhcache, NDI_DRV_CONF_REPROBE | NDI_NO_EVENT,
9183 9172 BUS_CONFIG_ALL, DDI_MAJOR_T_NONE);
9184 9173
9185 9174 rw_enter(&vhcache->vhcache_lock, RW_WRITER);
9186 9175 vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE;
9187 9176 rw_exit(&vhcache->vhcache_lock);
9188 9177
9189 9178 single_threaded_vhconfig_exit(vhc);
9190 9179 vhcache_dirty(vhc);
9191 9180 return (1);
9192 9181 }
9193 9182
9194 9183 /*
9195 9184 * Determine if discovery of paths is needed.
9196 9185 */
9197 9186 static int
9198 9187 vhcache_do_discovery(mdi_vhci_config_t *vhc)
9199 9188 {
9200 9189 int rv = 1;
9201 9190
9202 9191 mutex_enter(&vhc->vhc_lock);
9203 9192 if (i_ddi_io_initialized() == 0) {
9204 9193 if (vhc->vhc_path_discovery_boot > 0) {
9205 9194 vhc->vhc_path_discovery_boot--;
9206 9195 goto out;
9207 9196 }
9208 9197 } else {
9209 9198 if (vhc->vhc_path_discovery_postboot > 0) {
9210 9199 vhc->vhc_path_discovery_postboot--;
9211 9200 goto out;
9212 9201 }
9213 9202 }
9214 9203
9215 9204 /*
9216 9205 * Do full path discovery at most once per mdi_path_discovery_interval.
9217 9206 * This is to avoid a series of full path discoveries when opening
9218 9207 * stale /dev/[r]dsk links.
9219 9208 */
9220 9209 if (mdi_path_discovery_interval != -1 &&
9221 9210 ddi_get_lbolt64() >= vhc->vhc_path_discovery_cutoff_time)
9222 9211 goto out;
9223 9212
9224 9213 rv = 0;
9225 9214 out:
9226 9215 mutex_exit(&vhc->vhc_lock);
9227 9216 return (rv);
9228 9217 }
9229 9218
9230 9219 /*
9231 9220 * Discover all paths:
9232 9221 *
9233 9222 * Attach phci driver instances and then drive BUS_CONFIG_ALL on all the phci
9234 9223 * driver instances. During this process all paths will be discovered.
9235 9224 */
9236 9225 static int
9237 9226 vhcache_discover_paths(mdi_vhci_t *vh)
9238 9227 {
9239 9228 mdi_vhci_config_t *vhc = vh->vh_config;
9240 9229 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
9241 9230 int rv = 0;
9242 9231
9243 9232 single_threaded_vhconfig_enter(vhc);
9244 9233
9245 9234 if (vhcache_do_discovery(vhc)) {
9246 9235 attach_phci_drivers(vh->vh_class);
9247 9236 bus_config_all_phcis(vhcache, NDI_DRV_CONF_REPROBE |
9248 9237 NDI_NO_EVENT, BUS_CONFIG_ALL, DDI_MAJOR_T_NONE);
9249 9238
9250 9239 mutex_enter(&vhc->vhc_lock);
9251 9240 vhc->vhc_path_discovery_cutoff_time = ddi_get_lbolt64() +
9252 9241 mdi_path_discovery_interval * TICKS_PER_SECOND;
9253 9242 mutex_exit(&vhc->vhc_lock);
9254 9243 rv = 1;
9255 9244 }
9256 9245
9257 9246 single_threaded_vhconfig_exit(vhc);
9258 9247 return (rv);
9259 9248 }
9260 9249
9261 9250 /*
9262 9251 * Generic vhci bus config implementation:
9263 9252 *
9264 9253 * Parameters
9265 9254 * vdip vhci dip
9266 9255 * flags bus config flags
9267 9256 * op bus config operation
9268 9257 * The remaining parameters are bus config operation specific
9269 9258 *
9270 9259 * for BUS_CONFIG_ONE
9271 9260 * arg pointer to name@addr
9272 9261 * child upon successful return from this function, *child will be
9273 9262 * set to the configured and held devinfo child node of vdip.
9274 9263 * ct_addr pointer to client address (i.e. GUID)
9275 9264 *
9276 9265 * for BUS_CONFIG_DRIVER
9277 9266 * arg major number of the driver
9278 9267 * child and ct_addr parameters are ignored
9279 9268 *
9280 9269 * for BUS_CONFIG_ALL
9281 9270 * arg, child, and ct_addr parameters are ignored
9282 9271 *
9283 9272 * Note that for the rest of the bus config operations, this function simply
9284 9273 * calls the framework provided default bus config routine.
9285 9274 */
9286 9275 int
9287 9276 mdi_vhci_bus_config(dev_info_t *vdip, uint_t flags, ddi_bus_config_op_t op,
9288 9277 void *arg, dev_info_t **child, char *ct_addr)
9289 9278 {
9290 9279 mdi_vhci_t *vh = i_devi_get_vhci(vdip);
9291 9280 mdi_vhci_config_t *vhc = vh->vh_config;
9292 9281 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
9293 9282 int rv = 0;
9294 9283 int params_valid = 0;
9295 9284 char *cp;
9296 9285
9297 9286 /*
9298 9287 * To bus config vhcis we relay operation, possibly using another
9299 9288 * thread, to phcis. The phci driver then interacts with MDI to cause
9300 9289 * vhci child nodes to be enumerated under the vhci node. Adding a
9301 9290 * vhci child requires an ndi_devi_enter of the vhci. Since another
9302 9291 * thread may be adding the child, to avoid deadlock we can't wait
9303 9292 * for the relayed operations to complete if we have already entered
9304 9293 * the vhci node.
9305 9294 */
9306 9295 if (DEVI_BUSY_OWNED(vdip)) {
9307 9296 MDI_DEBUG(2, (MDI_NOTE, vdip,
9308 9297 "vhci dip is busy owned %p", (void *)vdip));
9309 9298 goto default_bus_config;
9310 9299 }
9311 9300
9312 9301 rw_enter(&vhcache->vhcache_lock, RW_READER);
9313 9302 if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) {
9314 9303 rw_exit(&vhcache->vhcache_lock);
9315 9304 rv = build_vhci_cache(vh);
9316 9305 rw_enter(&vhcache->vhcache_lock, RW_READER);
9317 9306 }
9318 9307
9319 9308 switch (op) {
9320 9309 case BUS_CONFIG_ONE:
9321 9310 if (arg != NULL && ct_addr != NULL) {
9322 9311 /* extract node name */
9323 9312 cp = (char *)arg;
9324 9313 while (*cp != '\0' && *cp != '@')
9325 9314 cp++;
9326 9315 if (*cp == '@') {
9327 9316 params_valid = 1;
9328 9317 *cp = '\0';
9329 9318 config_client_paths(vhc, (char *)arg, ct_addr);
9330 9319 /* config_client_paths() releases cache_lock */
9331 9320 *cp = '@';
9332 9321 break;
9333 9322 }
9334 9323 }
9335 9324
9336 9325 rw_exit(&vhcache->vhcache_lock);
9337 9326 break;
9338 9327
9339 9328 case BUS_CONFIG_DRIVER:
9340 9329 rw_exit(&vhcache->vhcache_lock);
9341 9330 if (rv == 0)
9342 9331 st_bus_config_all_phcis(vhc, flags, op,
9343 9332 (major_t)(uintptr_t)arg);
9344 9333 break;
9345 9334
9346 9335 case BUS_CONFIG_ALL:
9347 9336 rw_exit(&vhcache->vhcache_lock);
9348 9337 if (rv == 0)
9349 9338 st_bus_config_all_phcis(vhc, flags, op, -1);
9350 9339 break;
9351 9340
9352 9341 default:
9353 9342 rw_exit(&vhcache->vhcache_lock);
9354 9343 break;
9355 9344 }
9356 9345
9357 9346
9358 9347 default_bus_config:
9359 9348 /*
9360 9349 * All requested child nodes are enumerated under the vhci.
9361 9350 * Now configure them.
9362 9351 */
9363 9352 if (ndi_busop_bus_config(vdip, flags, op, arg, child, 0) ==
9364 9353 NDI_SUCCESS) {
9365 9354 return (MDI_SUCCESS);
9366 9355 } else if (op == BUS_CONFIG_ONE && rv == 0 && params_valid) {
9367 9356 /* discover all paths and try configuring again */
9368 9357 if (vhcache_discover_paths(vh) &&
9369 9358 ndi_busop_bus_config(vdip, flags, op, arg, child, 0) ==
9370 9359 NDI_SUCCESS)
9371 9360 return (MDI_SUCCESS);
9372 9361 }
9373 9362
9374 9363 return (MDI_FAILURE);
9375 9364 }
9376 9365
9377 9366 /*
9378 9367 * Read the on-disk vhci cache into an nvlist for the specified vhci class.
9379 9368 */
9380 9369 static nvlist_t *
9381 9370 read_on_disk_vhci_cache(char *vhci_class)
9382 9371 {
9383 9372 nvlist_t *nvl;
9384 9373 int err;
9385 9374 char *filename;
9386 9375
9387 9376 filename = vhclass2vhcache_filename(vhci_class);
9388 9377
9389 9378 if ((err = fread_nvlist(filename, &nvl)) == 0) {
9390 9379 kmem_free(filename, strlen(filename) + 1);
9391 9380 return (nvl);
9392 9381 } else if (err == EIO)
9393 9382 cmn_err(CE_WARN, "%s: I/O error, will recreate", filename);
9394 9383 else if (err == EINVAL)
9395 9384 cmn_err(CE_WARN,
9396 9385 "%s: data file corrupted, will recreate", filename);
9397 9386
9398 9387 kmem_free(filename, strlen(filename) + 1);
9399 9388 return (NULL);
9400 9389 }
9401 9390
9402 9391 /*
9403 9392 * Read on-disk vhci cache into nvlists for all vhci classes.
9404 9393 * Called during booting by i_ddi_read_devices_files().
9405 9394 */
9406 9395 void
9407 9396 mdi_read_devices_files(void)
9408 9397 {
9409 9398 int i;
9410 9399
9411 9400 for (i = 0; i < N_VHCI_CLASSES; i++)
9412 9401 vhcache_nvl[i] = read_on_disk_vhci_cache(vhci_class_list[i]);
9413 9402 }
9414 9403
9415 9404 /*
9416 9405 * Remove all stale entries from vhci cache.
9417 9406 */
9418 9407 static void
9419 9408 clean_vhcache(mdi_vhci_config_t *vhc)
9420 9409 {
9421 9410 mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache;
9422 9411 mdi_vhcache_phci_t *phci, *nxt_phci;
9423 9412 mdi_vhcache_client_t *client, *nxt_client;
9424 9413 mdi_vhcache_pathinfo_t *path, *nxt_path;
9425 9414
9426 9415 rw_enter(&vhcache->vhcache_lock, RW_WRITER);
9427 9416
9428 9417 client = vhcache->vhcache_client_head;
9429 9418 vhcache->vhcache_client_head = vhcache->vhcache_client_tail = NULL;
9430 9419 for ( ; client != NULL; client = nxt_client) {
9431 9420 nxt_client = client->cct_next;
9432 9421
9433 9422 path = client->cct_cpi_head;
9434 9423 client->cct_cpi_head = client->cct_cpi_tail = NULL;
9435 9424 for ( ; path != NULL; path = nxt_path) {
9436 9425 nxt_path = path->cpi_next;
9437 9426 if ((path->cpi_cphci->cphci_phci != NULL) &&
9438 9427 (path->cpi_pip != NULL)) {
9439 9428 enqueue_tail_vhcache_pathinfo(client, path);
9440 9429 } else if (path->cpi_pip != NULL) {
9441 9430 /* Not valid to have a path without a phci. */
9442 9431 free_vhcache_pathinfo(path);
9443 9432 }
9444 9433 }
9445 9434
9446 9435 if (client->cct_cpi_head != NULL)
9447 9436 enqueue_vhcache_client(vhcache, client);
9448 9437 else {
9449 9438 (void) mod_hash_destroy(vhcache->vhcache_client_hash,
9450 9439 (mod_hash_key_t)client->cct_name_addr);
9451 9440 free_vhcache_client(client);
9452 9441 }
9453 9442 }
9454 9443
9455 9444 phci = vhcache->vhcache_phci_head;
9456 9445 vhcache->vhcache_phci_head = vhcache->vhcache_phci_tail = NULL;
9457 9446 for ( ; phci != NULL; phci = nxt_phci) {
9458 9447
9459 9448 nxt_phci = phci->cphci_next;
9460 9449 if (phci->cphci_phci != NULL)
9461 9450 enqueue_vhcache_phci(vhcache, phci);
9462 9451 else
9463 9452 free_vhcache_phci(phci);
9464 9453 }
9465 9454
9466 9455 vhcache->vhcache_clean_time = ddi_get_lbolt64();
9467 9456 rw_exit(&vhcache->vhcache_lock);
9468 9457 vhcache_dirty(vhc);
9469 9458 }
9470 9459
9471 9460 /*
9472 9461 * Remove all stale entries from vhci cache.
9473 9462 * Called by i_ddi_clean_devices_files() during the execution of devfsadm -C
9474 9463 */
9475 9464 void
9476 9465 mdi_clean_vhcache(void)
9477 9466 {
9478 9467 mdi_vhci_t *vh;
9479 9468
9480 9469 mutex_enter(&mdi_mutex);
9481 9470 for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) {
9482 9471 vh->vh_refcnt++;
9483 9472 mutex_exit(&mdi_mutex);
9484 9473 clean_vhcache(vh->vh_config);
9485 9474 mutex_enter(&mdi_mutex);
9486 9475 vh->vh_refcnt--;
9487 9476 }
9488 9477 mutex_exit(&mdi_mutex);
9489 9478 }
9490 9479
9491 9480 /*
9492 9481 * mdi_vhci_walk_clients():
9493 9482 * Walker routine to traverse client dev_info nodes
9494 9483 * ddi_walk_devs(ddi_get_child(vdip), f, arg) returns the entire tree
9495 9484 * below the client, including nexus devices, which we dont want.
9496 9485 * So we just traverse the immediate siblings, starting from 1st client.
9497 9486 */
9498 9487 void
9499 9488 mdi_vhci_walk_clients(dev_info_t *vdip,
9500 9489 int (*f)(dev_info_t *, void *), void *arg)
9501 9490 {
9502 9491 mdi_vhci_t *vh = i_devi_get_vhci(vdip);
9503 9492 dev_info_t *cdip;
9504 9493 mdi_client_t *ct;
9505 9494
9506 9495 MDI_VHCI_CLIENT_LOCK(vh);
9507 9496 cdip = ddi_get_child(vdip);
9508 9497 while (cdip) {
9509 9498 ct = i_devi_get_client(cdip);
9510 9499 MDI_CLIENT_LOCK(ct);
9511 9500
9512 9501 if (((*f)(cdip, arg)) == DDI_WALK_CONTINUE)
9513 9502 cdip = ddi_get_next_sibling(cdip);
9514 9503 else
9515 9504 cdip = NULL;
9516 9505
9517 9506 MDI_CLIENT_UNLOCK(ct);
9518 9507 }
9519 9508 MDI_VHCI_CLIENT_UNLOCK(vh);
9520 9509 }
9521 9510
9522 9511 /*
9523 9512 * mdi_vhci_walk_phcis():
9524 9513 * Walker routine to traverse phci dev_info nodes
9525 9514 */
9526 9515 void
9527 9516 mdi_vhci_walk_phcis(dev_info_t *vdip,
9528 9517 int (*f)(dev_info_t *, void *), void *arg)
9529 9518 {
9530 9519 mdi_vhci_t *vh = i_devi_get_vhci(vdip);
9531 9520 mdi_phci_t *ph, *next;
9532 9521
9533 9522 MDI_VHCI_PHCI_LOCK(vh);
9534 9523 ph = vh->vh_phci_head;
9535 9524 while (ph) {
9536 9525 MDI_PHCI_LOCK(ph);
9537 9526
9538 9527 if (((*f)(ph->ph_dip, arg)) == DDI_WALK_CONTINUE)
9539 9528 next = ph->ph_next;
9540 9529 else
9541 9530 next = NULL;
9542 9531
9543 9532 MDI_PHCI_UNLOCK(ph);
9544 9533 ph = next;
9545 9534 }
9546 9535 MDI_VHCI_PHCI_UNLOCK(vh);
9547 9536 }
9548 9537
9549 9538
9550 9539 /*
9551 9540 * mdi_walk_vhcis():
9552 9541 * Walker routine to traverse vhci dev_info nodes
9553 9542 */
9554 9543 void
9555 9544 mdi_walk_vhcis(int (*f)(dev_info_t *, void *), void *arg)
9556 9545 {
9557 9546 mdi_vhci_t *vh = NULL;
9558 9547
9559 9548 mutex_enter(&mdi_mutex);
9560 9549 /*
9561 9550 * Scan for already registered vhci
9562 9551 */
9563 9552 for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) {
9564 9553 vh->vh_refcnt++;
9565 9554 mutex_exit(&mdi_mutex);
9566 9555 if (((*f)(vh->vh_dip, arg)) != DDI_WALK_CONTINUE) {
9567 9556 mutex_enter(&mdi_mutex);
9568 9557 vh->vh_refcnt--;
9569 9558 break;
9570 9559 } else {
9571 9560 mutex_enter(&mdi_mutex);
9572 9561 vh->vh_refcnt--;
9573 9562 }
9574 9563 }
9575 9564
9576 9565 mutex_exit(&mdi_mutex);
9577 9566 }
9578 9567
9579 9568 /*
9580 9569 * i_mdi_log_sysevent():
9581 9570 * Logs events for pickup by syseventd
9582 9571 */
9583 9572 static void
9584 9573 i_mdi_log_sysevent(dev_info_t *dip, char *ph_vh_class, char *subclass)
9585 9574 {
9586 9575 char *path_name;
9587 9576 nvlist_t *attr_list;
9588 9577
9589 9578 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
9590 9579 KM_SLEEP) != DDI_SUCCESS) {
9591 9580 goto alloc_failed;
9592 9581 }
9593 9582
9594 9583 path_name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
9595 9584 (void) ddi_pathname(dip, path_name);
9596 9585
9597 9586 if (nvlist_add_string(attr_list, DDI_DRIVER_NAME,
9598 9587 ddi_driver_name(dip)) != DDI_SUCCESS) {
9599 9588 goto error;
9600 9589 }
9601 9590
9602 9591 if (nvlist_add_int32(attr_list, DDI_DRIVER_MAJOR,
9603 9592 (int32_t)ddi_driver_major(dip)) != DDI_SUCCESS) {
9604 9593 goto error;
9605 9594 }
9606 9595
9607 9596 if (nvlist_add_int32(attr_list, DDI_INSTANCE,
9608 9597 (int32_t)ddi_get_instance(dip)) != DDI_SUCCESS) {
9609 9598 goto error;
9610 9599 }
9611 9600
9612 9601 if (nvlist_add_string(attr_list, DDI_PATHNAME,
9613 9602 path_name) != DDI_SUCCESS) {
9614 9603 goto error;
9615 9604 }
9616 9605
9617 9606 if (nvlist_add_string(attr_list, DDI_CLASS,
9618 9607 ph_vh_class) != DDI_SUCCESS) {
9619 9608 goto error;
9620 9609 }
9621 9610
9622 9611 (void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_DDI, subclass,
9623 9612 attr_list, NULL, DDI_SLEEP);
9624 9613
9625 9614 error:
9626 9615 kmem_free(path_name, MAXPATHLEN);
9627 9616 nvlist_free(attr_list);
9628 9617 return;
9629 9618
9630 9619 alloc_failed:
9631 9620 MDI_DEBUG(1, (MDI_WARN, dip, "!unable to send sysevent"));
9632 9621 }
9633 9622
9634 9623 char **
9635 9624 mdi_get_phci_driver_list(char *vhci_class, int *ndrivers)
9636 9625 {
9637 9626 char **driver_list, **ret_driver_list = NULL;
9638 9627 int *root_support_list;
9639 9628 int cur_elements, max_elements;
9640 9629
9641 9630 get_phci_driver_list(vhci_class, &driver_list, &root_support_list,
9642 9631 &cur_elements, &max_elements);
9643 9632
9644 9633
9645 9634 if (driver_list) {
9646 9635 kmem_free(root_support_list, sizeof (int) * max_elements);
9647 9636 ret_driver_list = mdi_realloc(driver_list, sizeof (char *)
9648 9637 * max_elements, sizeof (char *) * cur_elements);
9649 9638 }
9650 9639 *ndrivers = cur_elements;
9651 9640
9652 9641 return (ret_driver_list);
9653 9642
9654 9643 }
9655 9644
9656 9645 void
9657 9646 mdi_free_phci_driver_list(char **driver_list, int ndrivers)
9658 9647 {
9659 9648 char **p;
9660 9649 int i;
9661 9650
9662 9651 if (driver_list) {
9663 9652 for (i = 0, p = driver_list; i < ndrivers; i++, p++)
9664 9653 kmem_free(*p, strlen(*p) + 1);
9665 9654 kmem_free(driver_list, sizeof (char *) * ndrivers);
9666 9655 }
9667 9656 }
9668 9657
9669 9658 /*
9670 9659 * mdi_is_dev_supported():
9671 9660 * function called by pHCI bus config operation to determine if a
9672 9661 * device should be represented as a child of the vHCI or the
9673 9662 * pHCI. This decision is made by the vHCI, using cinfo idenity
9674 9663 * information passed by the pHCI - specifics of the cinfo
9675 9664 * representation are by agreement between the pHCI and vHCI.
9676 9665 * Return Values:
9677 9666 * MDI_SUCCESS
9678 9667 * MDI_FAILURE
9679 9668 */
9680 9669 int
9681 9670 mdi_is_dev_supported(char *class, dev_info_t *pdip, void *cinfo)
9682 9671 {
9683 9672 mdi_vhci_t *vh;
9684 9673
9685 9674 ASSERT(class && pdip);
9686 9675
9687 9676 /*
9688 9677 * For dev_supported, mdi_phci_register() must have established pdip as
9689 9678 * a pHCI.
9690 9679 *
9691 9680 * NOTE: mdi_phci_register() does "mpxio-disable" processing, and
9692 9681 * MDI_PHCI(pdip) will return false if mpxio is disabled.
9693 9682 */
9694 9683 if (!MDI_PHCI(pdip))
9695 9684 return (MDI_FAILURE);
9696 9685
9697 9686 /* Return MDI_FAILURE if vHCI does not support asking the question. */
9698 9687 vh = (mdi_vhci_t *)i_mdi_vhci_class2vhci(class);
9699 9688 if ((vh == NULL) || (vh->vh_ops->vo_is_dev_supported == NULL)) {
9700 9689 return (MDI_FAILURE);
9701 9690 }
9702 9691
9703 9692 /* Return vHCI answer */
9704 9693 return (vh->vh_ops->vo_is_dev_supported(vh->vh_dip, pdip, cinfo));
9705 9694 }
9706 9695
9707 9696 int
9708 9697 mdi_dc_return_dev_state(mdi_pathinfo_t *pip, struct devctl_iocdata *dcp)
9709 9698 {
9710 9699 uint_t devstate = 0;
9711 9700 dev_info_t *cdip;
9712 9701
9713 9702 if ((pip == NULL) || (dcp == NULL))
9714 9703 return (MDI_FAILURE);
9715 9704
9716 9705 cdip = mdi_pi_get_client(pip);
9717 9706
9718 9707 switch (mdi_pi_get_state(pip)) {
9719 9708 case MDI_PATHINFO_STATE_INIT:
9720 9709 devstate = DEVICE_DOWN;
9721 9710 break;
9722 9711 case MDI_PATHINFO_STATE_ONLINE:
9723 9712 devstate = DEVICE_ONLINE;
9724 9713 if ((cdip) && (devi_stillreferenced(cdip) == DEVI_REFERENCED))
9725 9714 devstate |= DEVICE_BUSY;
9726 9715 break;
9727 9716 case MDI_PATHINFO_STATE_STANDBY:
9728 9717 devstate = DEVICE_ONLINE;
9729 9718 break;
9730 9719 case MDI_PATHINFO_STATE_FAULT:
9731 9720 devstate = DEVICE_DOWN;
9732 9721 break;
9733 9722 case MDI_PATHINFO_STATE_OFFLINE:
9734 9723 devstate = DEVICE_OFFLINE;
9735 9724 break;
9736 9725 default:
9737 9726 ASSERT(MDI_PI(pip)->pi_state);
9738 9727 }
9739 9728
9740 9729 if (copyout(&devstate, dcp->cpyout_buf, sizeof (uint_t)) != 0)
9741 9730 return (MDI_FAILURE);
9742 9731
9743 9732 return (MDI_SUCCESS);
9744 9733 }
↓ open down ↓ |
6042 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX