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