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