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