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