17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Multipath driver interface (MDI) implementation; see mdi_impl.h for a more 307c478bd9Sstevel@tonic-gate * detailed discussion of the overall mpxio architecture. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * Default locking order: 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_mutex, mdi_phci::ph_mutex)) 357c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_mutex, mdi_client::ct_mutex)) 367c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 377c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex)) 387c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <sys/note.h> 427c478bd9Sstevel@tonic-gate #include <sys/types.h> 437c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 447c478bd9Sstevel@tonic-gate #include <sys/param.h> 457c478bd9Sstevel@tonic-gate #include <sys/errno.h> 467c478bd9Sstevel@tonic-gate #include <sys/uio.h> 477c478bd9Sstevel@tonic-gate #include <sys/buf.h> 487c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 497c478bd9Sstevel@tonic-gate #include <sys/open.h> 507c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 517c478bd9Sstevel@tonic-gate #include <sys/poll.h> 527c478bd9Sstevel@tonic-gate #include <sys/conf.h> 537c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 557c478bd9Sstevel@tonic-gate #include <sys/stat.h> 567c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 577c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 587c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h> 597c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 607c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 617c478bd9Sstevel@tonic-gate #include <sys/promif.h> 627c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h> 637c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h> 647c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 657c478bd9Sstevel@tonic-gate #include <sys/epm.h> 667c478bd9Sstevel@tonic-gate #include <sys/sunpm.h> 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #ifdef DEBUG 697c478bd9Sstevel@tonic-gate #include <sys/debug.h> 707c478bd9Sstevel@tonic-gate int mdi_debug = 1; 717c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) \ 727c478bd9Sstevel@tonic-gate if (mdi_debug >= (level)) i_mdi_log stmnt 737c478bd9Sstevel@tonic-gate static void i_mdi_log(int, dev_info_t *, const char *fmt, ...); 747c478bd9Sstevel@tonic-gate #else /* !DEBUG */ 757c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) 767c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; 797c478bd9Sstevel@tonic-gate extern int modrootloaded; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * Global mutex: 837c478bd9Sstevel@tonic-gate * Protects vHCI list and structure members, pHCI and Client lists. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate kmutex_t mdi_mutex; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * Registered vHCI class driver lists 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate int mdi_vhci_count; 917c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_head; 927c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_tail; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate /* 957c478bd9Sstevel@tonic-gate * Client Hash Table size 967c478bd9Sstevel@tonic-gate */ 977c478bd9Sstevel@tonic-gate static int mdi_client_table_size = CLIENT_HASH_TABLE_SIZE; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate /* 1007c478bd9Sstevel@tonic-gate * taskq interface definitions 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate #define MDI_TASKQ_N_THREADS 8 1037c478bd9Sstevel@tonic-gate #define MDI_TASKQ_PRI minclsyspri 1047c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MINALLOC (4*mdi_taskq_n_threads) 1057c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MAXALLOC (500*mdi_taskq_n_threads) 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate taskq_t *mdi_taskq; 1087c478bd9Sstevel@tonic-gate static uint_t mdi_taskq_n_threads = MDI_TASKQ_N_THREADS; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static int mdi_max_bus_config_threads = 100; 1117c478bd9Sstevel@tonic-gate /* 1127c478bd9Sstevel@tonic-gate * To reduce unnecessary BUS_CONFIG_ALLs, do not BUS_CONFIG_ALL phcis in the 1137c478bd9Sstevel@tonic-gate * context of a BUS_CONFIG_ONE if a BUS_CONFIG_ALL has already been performed 1147c478bd9Sstevel@tonic-gate * in the last mdi_bus_config_timeout seconds. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate static int mdi_bus_config_timeout = 60; /* in seconds */ 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * MDI component property name/value string definitions 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate const char *mdi_component_prop = "mpxio-component"; 1227c478bd9Sstevel@tonic-gate const char *mdi_component_prop_vhci = "vhci"; 1237c478bd9Sstevel@tonic-gate const char *mdi_component_prop_phci = "phci"; 1247c478bd9Sstevel@tonic-gate const char *mdi_component_prop_client = "client"; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* 1277c478bd9Sstevel@tonic-gate * MDI client global unique identifier property name 1287c478bd9Sstevel@tonic-gate */ 1297c478bd9Sstevel@tonic-gate const char *mdi_client_guid_prop = "client-guid"; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * MDI client load balancing property name/value string definitions 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate const char *mdi_load_balance = "load-balance"; 1357c478bd9Sstevel@tonic-gate const char *mdi_load_balance_none = "none"; 1367c478bd9Sstevel@tonic-gate const char *mdi_load_balance_rr = "round-robin"; 1377c478bd9Sstevel@tonic-gate const char *mdi_load_balance_lba = "logical-block"; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Obsolete vHCI class definition; to be removed after Leadville update 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate const char *mdi_vhci_class_scsi = MDI_HCI_CLASS_SCSI; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate static char vhci_greeting[] = 1457c478bd9Sstevel@tonic-gate "\tThere already exists one vHCI driver for class %s\n" 1467c478bd9Sstevel@tonic-gate "\tOnly one vHCI driver for each class is allowed\n"; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Static function prototypes 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate static int i_mdi_phci_offline(dev_info_t *, uint_t); 1527c478bd9Sstevel@tonic-gate static int i_mdi_client_offline(dev_info_t *, uint_t); 1537c478bd9Sstevel@tonic-gate static int i_mdi_phci_pre_detach(dev_info_t *, ddi_detach_cmd_t); 1547c478bd9Sstevel@tonic-gate static void i_mdi_phci_post_detach(dev_info_t *, 1557c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 1567c478bd9Sstevel@tonic-gate static int i_mdi_client_pre_detach(dev_info_t *, 1577c478bd9Sstevel@tonic-gate ddi_detach_cmd_t); 1587c478bd9Sstevel@tonic-gate static void i_mdi_client_post_detach(dev_info_t *, 1597c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 1607c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_pip(mdi_pathinfo_t *); 1617c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_pip(mdi_pathinfo_t *); 1627c478bd9Sstevel@tonic-gate static int i_mdi_lba_lb(mdi_client_t *ct, 1637c478bd9Sstevel@tonic-gate mdi_pathinfo_t **ret_pip, struct buf *buf); 1647c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_client(mdi_client_t *, int); 1657c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_client(mdi_client_t *, int); 1667c478bd9Sstevel@tonic-gate static void i_mdi_pm_reset_client(mdi_client_t *); 1677c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_all_phci(mdi_client_t *); 1687c478bd9Sstevel@tonic-gate static int i_mdi_power_all_phci(mdi_client_t *); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * Internal mdi_pathinfo node functions 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static int i_mdi_pi_kstat_create(mdi_pathinfo_t *); 1757c478bd9Sstevel@tonic-gate static void i_mdi_pi_kstat_destroy(mdi_pathinfo_t *); 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_mdi_vhci_class2vhci(char *); 1787c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_devi_get_vhci(dev_info_t *); 1797c478bd9Sstevel@tonic-gate static mdi_phci_t *i_devi_get_phci(dev_info_t *); 1807c478bd9Sstevel@tonic-gate static void i_mdi_phci_lock(mdi_phci_t *, mdi_pathinfo_t *); 1817c478bd9Sstevel@tonic-gate static void i_mdi_phci_get_client_lock(mdi_phci_t *, 1827c478bd9Sstevel@tonic-gate mdi_client_t *); 1837c478bd9Sstevel@tonic-gate static void i_mdi_phci_unlock(mdi_phci_t *); 1847c478bd9Sstevel@tonic-gate static mdi_pathinfo_t *i_mdi_pi_alloc(mdi_phci_t *, char *, 1857c478bd9Sstevel@tonic-gate mdi_client_t *, int); 1867c478bd9Sstevel@tonic-gate static void i_mdi_phci_add_path(mdi_phci_t *, mdi_pathinfo_t *); 1877c478bd9Sstevel@tonic-gate static void i_mdi_client_add_path(mdi_client_t *, mdi_pathinfo_t *); 1887c478bd9Sstevel@tonic-gate static void i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *, 1897c478bd9Sstevel@tonic-gate mdi_client_t *); 1907c478bd9Sstevel@tonic-gate static void i_mdi_phci_remove_path(mdi_phci_t *, mdi_pathinfo_t *); 1917c478bd9Sstevel@tonic-gate static void i_mdi_client_remove_path(mdi_client_t *, 1927c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate static int i_mdi_pi_state_change(mdi_pathinfo_t *, 1957c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t, int); 1967c478bd9Sstevel@tonic-gate static int i_mdi_pi_offline(mdi_pathinfo_t *, int); 1977c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_create(mdi_vhci_t *, char *, char *, 1987c478bd9Sstevel@tonic-gate char **, int, int); 1997c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_find(mdi_vhci_t *, char *, char *); 2007c478bd9Sstevel@tonic-gate static int i_mdi_devinfo_remove(dev_info_t *, dev_info_t *, int); 2017c478bd9Sstevel@tonic-gate static int i_mdi_is_child_present(dev_info_t *, dev_info_t *); 2027c478bd9Sstevel@tonic-gate static mdi_client_t *i_mdi_client_alloc(mdi_vhci_t *, char *, char *, int); 2037c478bd9Sstevel@tonic-gate static void i_mdi_client_enlist_table(mdi_vhci_t *, mdi_client_t *); 2047c478bd9Sstevel@tonic-gate static void i_mdi_client_delist_table(mdi_vhci_t *, mdi_client_t *); 2057c478bd9Sstevel@tonic-gate static mdi_client_t *i_mdi_client_find(mdi_vhci_t *, char *); 2067c478bd9Sstevel@tonic-gate static void i_mdi_client_update_state(mdi_client_t *); 2077c478bd9Sstevel@tonic-gate static int i_mdi_client_compute_state(mdi_client_t *, 2087c478bd9Sstevel@tonic-gate mdi_phci_t *); 2097c478bd9Sstevel@tonic-gate static void i_mdi_client_lock(mdi_client_t *, mdi_pathinfo_t *); 2107c478bd9Sstevel@tonic-gate static void i_mdi_client_unlock(mdi_client_t *); 2117c478bd9Sstevel@tonic-gate static int i_mdi_client_free(mdi_vhci_t *, mdi_client_t *); 2127c478bd9Sstevel@tonic-gate static mdi_client_t *i_devi_get_client(dev_info_t *); 2137c478bd9Sstevel@tonic-gate static int i_mdi_pi_enable_disable(dev_info_t *, dev_info_t *, int, 2147c478bd9Sstevel@tonic-gate int); 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * Failover related function prototypes 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate static int i_mdi_failover(void *); 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* 2217c478bd9Sstevel@tonic-gate * misc internal functions 2227c478bd9Sstevel@tonic-gate */ 2237c478bd9Sstevel@tonic-gate static int i_mdi_get_hash_key(char *); 2247c478bd9Sstevel@tonic-gate static int i_map_nvlist_error_to_mdi(int); 2257c478bd9Sstevel@tonic-gate static void i_mdi_report_path_state(mdi_client_t *, 2267c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* called once when first vhci registers with mdi */ 2297c478bd9Sstevel@tonic-gate static void 2307c478bd9Sstevel@tonic-gate i_mdi_init() 2317c478bd9Sstevel@tonic-gate { 2327c478bd9Sstevel@tonic-gate static int initialized = 0; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (initialized) 2357c478bd9Sstevel@tonic-gate return; 2367c478bd9Sstevel@tonic-gate initialized = 1; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate mutex_init(&mdi_mutex, NULL, MUTEX_DEFAULT, NULL); 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Create our taskq resources 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate mdi_taskq = taskq_create("mdi_taskq", mdi_taskq_n_threads, 2437c478bd9Sstevel@tonic-gate MDI_TASKQ_PRI, MDI_TASKQ_MINALLOC, MDI_TASKQ_MAXALLOC, 2447c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE | TASKQ_CPR_SAFE); 2457c478bd9Sstevel@tonic-gate ASSERT(mdi_taskq != NULL); /* taskq_create never fails */ 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * mdi_get_component_type(): 2507c478bd9Sstevel@tonic-gate * Return mpxio component type 2517c478bd9Sstevel@tonic-gate * Return Values: 2527c478bd9Sstevel@tonic-gate * MDI_COMPONENT_NONE 2537c478bd9Sstevel@tonic-gate * MDI_COMPONENT_VHCI 2547c478bd9Sstevel@tonic-gate * MDI_COMPONENT_PHCI 2557c478bd9Sstevel@tonic-gate * MDI_COMPONENT_CLIENT 2567c478bd9Sstevel@tonic-gate * XXX This doesn't work under multi-level MPxIO and should be 2577c478bd9Sstevel@tonic-gate * removed when clients migrate mdi_is_*() interfaces. 2587c478bd9Sstevel@tonic-gate */ 2597c478bd9Sstevel@tonic-gate int 2607c478bd9Sstevel@tonic-gate mdi_get_component_type(dev_info_t *dip) 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate return (DEVI(dip)->devi_mdi_component); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * mdi_vhci_register(): 2677c478bd9Sstevel@tonic-gate * Register a vHCI module with the mpxio framework 2687c478bd9Sstevel@tonic-gate * mdi_vhci_register() is called by vHCI drivers to register the 2697c478bd9Sstevel@tonic-gate * 'class_driver' vHCI driver and its MDI entrypoints with the 2707c478bd9Sstevel@tonic-gate * mpxio framework. The vHCI driver must call this interface as 2717c478bd9Sstevel@tonic-gate * part of its attach(9e) handler. 2727c478bd9Sstevel@tonic-gate * Competing threads may try to attach mdi_vhci_register() as 2737c478bd9Sstevel@tonic-gate * the vHCI drivers are loaded and attached as a result of pHCI 2747c478bd9Sstevel@tonic-gate * driver instance registration (mdi_phci_register()) with the 2757c478bd9Sstevel@tonic-gate * framework. 2767c478bd9Sstevel@tonic-gate * Return Values: 2777c478bd9Sstevel@tonic-gate * MDI_SUCCESS 2787c478bd9Sstevel@tonic-gate * MDI_FAILURE 2797c478bd9Sstevel@tonic-gate */ 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2827c478bd9Sstevel@tonic-gate int 2837c478bd9Sstevel@tonic-gate mdi_vhci_register(char *class, dev_info_t *vdip, mdi_vhci_ops_t *vops, 2847c478bd9Sstevel@tonic-gate int flags) 2857c478bd9Sstevel@tonic-gate { 2867c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate ASSERT(vops->vo_revision == MDI_VHCI_OPS_REV); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate i_mdi_init(); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * Scan for already registered vhci 2957c478bd9Sstevel@tonic-gate */ 2967c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 2977c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * vHCI has already been created. Check for valid 3007c478bd9Sstevel@tonic-gate * vHCI ops registration. We only support one vHCI 3017c478bd9Sstevel@tonic-gate * module per class 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate if (vh->vh_ops != NULL) { 3047c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 3057c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, vhci_greeting, class); 3067c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate break; 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * if not yet created, create the vHCI component 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate if (vh == NULL) { 3167c478bd9Sstevel@tonic-gate struct client_hash *hash = NULL; 3177c478bd9Sstevel@tonic-gate char *load_balance; 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * Allocate and initialize the mdi extensions 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate vh = kmem_zalloc(sizeof (mdi_vhci_t), KM_SLEEP); 3237c478bd9Sstevel@tonic-gate hash = kmem_zalloc(mdi_client_table_size * sizeof (*hash), 3247c478bd9Sstevel@tonic-gate KM_SLEEP); 3257c478bd9Sstevel@tonic-gate vh->vh_client_table = hash; 3267c478bd9Sstevel@tonic-gate vh->vh_class = kmem_zalloc(strlen(class) + 1, KM_SLEEP); 3277c478bd9Sstevel@tonic-gate (void) strcpy(vh->vh_class, class); 3287c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_RR; 3297c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vdip, 3307c478bd9Sstevel@tonic-gate 0, LOAD_BALANCE_PROP, &load_balance) == DDI_SUCCESS) { 3317c478bd9Sstevel@tonic-gate if (strcmp(load_balance, LOAD_BALANCE_PROP_NONE) == 0) { 3327c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_NONE; 3337c478bd9Sstevel@tonic-gate } else if (strcmp(load_balance, LOAD_BALANCE_PROP_LBA) 3347c478bd9Sstevel@tonic-gate == 0) { 3357c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_LBA; 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate ddi_prop_free(load_balance); 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* 3417c478bd9Sstevel@tonic-gate * Store the vHCI ops vectors 3427c478bd9Sstevel@tonic-gate */ 3437c478bd9Sstevel@tonic-gate vh->vh_dip = vdip; 3447c478bd9Sstevel@tonic-gate vh->vh_ops = vops; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate /* 3477c478bd9Sstevel@tonic-gate * other members of vh_bus_config are initialized by 3487c478bd9Sstevel@tonic-gate * the above kmem_zalloc of the vhci structure. 3497c478bd9Sstevel@tonic-gate */ 3507c478bd9Sstevel@tonic-gate cv_init(&vh->vh_bus_config.vhc_cv, NULL, CV_DRIVER, NULL); 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate if (mdi_vhci_head == NULL) { 3537c478bd9Sstevel@tonic-gate mdi_vhci_head = vh; 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate if (mdi_vhci_tail) { 3567c478bd9Sstevel@tonic-gate mdi_vhci_tail->vh_next = vh; 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate mdi_vhci_tail = vh; 3597c478bd9Sstevel@tonic-gate mdi_vhci_count++; 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * Claim the devfs node as a vhci component 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component |= MDI_COMPONENT_VHCI; 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * Initialize our back reference from dev_info node 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = (caddr_t)vh; 3717c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 3727c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate /* 3767c478bd9Sstevel@tonic-gate * mdi_vhci_unregister(): 3777c478bd9Sstevel@tonic-gate * Unregister a vHCI module from mpxio framework 3787c478bd9Sstevel@tonic-gate * mdi_vhci_unregister() is called from the detach(9E) entrypoint 3797c478bd9Sstevel@tonic-gate * of a vhci to unregister it from the framework. 3807c478bd9Sstevel@tonic-gate * Return Values: 3817c478bd9Sstevel@tonic-gate * MDI_SUCCESS 3827c478bd9Sstevel@tonic-gate * MDI_FAILURE 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3867c478bd9Sstevel@tonic-gate int 3877c478bd9Sstevel@tonic-gate mdi_vhci_unregister(dev_info_t *vdip, int flags) 3887c478bd9Sstevel@tonic-gate { 3897c478bd9Sstevel@tonic-gate mdi_vhci_t *found, *vh, *prev = NULL; 3907c478bd9Sstevel@tonic-gate mdi_phci_config_t *phc, *next_phc; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* 3937c478bd9Sstevel@tonic-gate * Check for invalid VHCI 3947c478bd9Sstevel@tonic-gate */ 3957c478bd9Sstevel@tonic-gate if ((vh = i_devi_get_vhci(vdip)) == NULL) 3967c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * Scan the list of registered vHCIs for a match 4027c478bd9Sstevel@tonic-gate */ 4037c478bd9Sstevel@tonic-gate for (found = mdi_vhci_head; found != NULL; found = found->vh_next) { 4047c478bd9Sstevel@tonic-gate if (found == vh) 4057c478bd9Sstevel@tonic-gate break; 4067c478bd9Sstevel@tonic-gate prev = found; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate if (found == NULL) { 4107c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4117c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate /* 4157c478bd9Sstevel@tonic-gate * Check the pHCI and client count. All the pHCIs and clients 4167c478bd9Sstevel@tonic-gate * should have been unregistered, before a vHCI can be 4177c478bd9Sstevel@tonic-gate * unregistered. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate if (vh->vh_phci_count || vh->vh_client_count) { 4207c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 4217c478bd9Sstevel@tonic-gate "!mdi_vhci_unregister: pHCI in registered state.\n")); 4227c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4237c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * Remove the vHCI from the global list 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_head) { 4307c478bd9Sstevel@tonic-gate mdi_vhci_head = vh->vh_next; 4317c478bd9Sstevel@tonic-gate } else { 4327c478bd9Sstevel@tonic-gate prev->vh_next = vh->vh_next; 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_tail) { 4357c478bd9Sstevel@tonic-gate mdi_vhci_tail = prev; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate vh->vh_ops = NULL; 4397c478bd9Sstevel@tonic-gate mdi_vhci_count--; 4407c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4417c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component &= ~MDI_COMPONENT_VHCI; 4427c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = NULL; 4437c478bd9Sstevel@tonic-gate kmem_free(vh->vh_class, strlen(vh->vh_class)+1); 4447c478bd9Sstevel@tonic-gate kmem_free(vh->vh_client_table, 4457c478bd9Sstevel@tonic-gate mdi_client_table_size * sizeof (struct client_hash)); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * there must be no more tasks on the bus config taskq as the vhci 4497c478bd9Sstevel@tonic-gate * driver can not be detached while bus config is in progress. 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate ASSERT(vh->vh_bus_config.vhc_start_time == 0); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate if (vh->vh_bus_config.vhc_taskq != NULL) 4547c478bd9Sstevel@tonic-gate taskq_destroy(vh->vh_bus_config.vhc_taskq); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate for (phc = vh->vh_bus_config.vhc_phc; phc != NULL; phc = next_phc) { 4577c478bd9Sstevel@tonic-gate next_phc = phc->phc_next; 4587c478bd9Sstevel@tonic-gate kmem_free(phc, sizeof (*phc)); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate cv_destroy(&vh->vh_bus_config.vhc_cv); 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate kmem_free(vh, sizeof (mdi_vhci_t)); 4647c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * i_mdi_vhci_class2vhci(): 4697c478bd9Sstevel@tonic-gate * Look for a matching vHCI module given a vHCI class name 4707c478bd9Sstevel@tonic-gate * Return Values: 4717c478bd9Sstevel@tonic-gate * Handle to a vHCI component 4727c478bd9Sstevel@tonic-gate * NULL 4737c478bd9Sstevel@tonic-gate */ 4747c478bd9Sstevel@tonic-gate static mdi_vhci_t * 4757c478bd9Sstevel@tonic-gate i_mdi_vhci_class2vhci(char *class) 4767c478bd9Sstevel@tonic-gate { 4777c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&mdi_mutex)); 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 4827c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 4837c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 4847c478bd9Sstevel@tonic-gate break; 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4887c478bd9Sstevel@tonic-gate return (vh); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate /* 4927c478bd9Sstevel@tonic-gate * i_devi_get_vhci(): 4937c478bd9Sstevel@tonic-gate * Utility function to get the handle to a vHCI component 4947c478bd9Sstevel@tonic-gate * Return Values: 4957c478bd9Sstevel@tonic-gate * Handle to a vHCI component 4967c478bd9Sstevel@tonic-gate * NULL 4977c478bd9Sstevel@tonic-gate */ 4987c478bd9Sstevel@tonic-gate mdi_vhci_t * 4997c478bd9Sstevel@tonic-gate i_devi_get_vhci(dev_info_t *vdip) 5007c478bd9Sstevel@tonic-gate { 5017c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 5027c478bd9Sstevel@tonic-gate if (MDI_VHCI(vdip)) { 5037c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate return (vh); 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate /* 5097c478bd9Sstevel@tonic-gate * mdi_phci_register(): 5107c478bd9Sstevel@tonic-gate * Register a pHCI module with mpxio framework 5117c478bd9Sstevel@tonic-gate * mdi_phci_register() is called by pHCI drivers to register with 5127c478bd9Sstevel@tonic-gate * the mpxio framework and a specific 'class_driver' vHCI. The 5137c478bd9Sstevel@tonic-gate * pHCI driver must call this interface as part of its attach(9e) 5147c478bd9Sstevel@tonic-gate * handler. 5157c478bd9Sstevel@tonic-gate * Return Values: 5167c478bd9Sstevel@tonic-gate * MDI_SUCCESS 5177c478bd9Sstevel@tonic-gate * MDI_FAILURE 5187c478bd9Sstevel@tonic-gate */ 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5217c478bd9Sstevel@tonic-gate int 5227c478bd9Sstevel@tonic-gate mdi_phci_register(char *class, dev_info_t *pdip, int flags) 5237c478bd9Sstevel@tonic-gate { 5247c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 5257c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 5267c478bd9Sstevel@tonic-gate char *data; 5277c478bd9Sstevel@tonic-gate char *pathname; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 5307c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, pathname); 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate /* 5337c478bd9Sstevel@tonic-gate * Check for mpxio-disable property. Enable mpxio if the property is 5347c478bd9Sstevel@tonic-gate * missing or not set to "yes". 5357c478bd9Sstevel@tonic-gate * If the property is set to "yes" then emit a brief message. 5367c478bd9Sstevel@tonic-gate */ 5377c478bd9Sstevel@tonic-gate if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0, "mpxio-disable", 5387c478bd9Sstevel@tonic-gate &data) == DDI_SUCCESS)) { 5397c478bd9Sstevel@tonic-gate if (strcmp(data, "yes") == 0) { 5407c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_CONT, pdip, 5417c478bd9Sstevel@tonic-gate "?%s (%s%d) multipath capabilities " 5427c478bd9Sstevel@tonic-gate "disabled via %s.conf.\n", pathname, 5437c478bd9Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip), 5447c478bd9Sstevel@tonic-gate ddi_driver_name(pdip))); 5457c478bd9Sstevel@tonic-gate ddi_prop_free(data); 5467c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 5477c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate ddi_prop_free(data); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * Search for a matching vHCI 5567c478bd9Sstevel@tonic-gate */ 5577c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)i_mdi_vhci_class2vhci(class); 5587c478bd9Sstevel@tonic-gate if (vh == NULL) { 5597c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate ph = kmem_zalloc(sizeof (mdi_phci_t), KM_SLEEP); 5637c478bd9Sstevel@tonic-gate mutex_init(&ph->ph_mutex, NULL, MUTEX_DEFAULT, NULL); 5647c478bd9Sstevel@tonic-gate ph->ph_dip = pdip; 5657c478bd9Sstevel@tonic-gate ph->ph_vhci = vh; 5667c478bd9Sstevel@tonic-gate ph->ph_next = NULL; 5677c478bd9Sstevel@tonic-gate ph->ph_unstable = 0; 5687c478bd9Sstevel@tonic-gate ph->ph_vprivate = 0; 5697c478bd9Sstevel@tonic-gate cv_init(&ph->ph_unstable_cv, NULL, CV_DRIVER, NULL); 5707c478bd9Sstevel@tonic-gate cv_init(&ph->ph_powerchange_cv, NULL, CV_DRIVER, NULL); 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate MDI_PHCI_SET_POWER_UP(ph); 5737c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component |= MDI_COMPONENT_PHCI; 5747c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = (caddr_t)ph; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 5777c478bd9Sstevel@tonic-gate if (vh->vh_phci_head == NULL) { 5787c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph; 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate if (vh->vh_phci_tail) { 5817c478bd9Sstevel@tonic-gate vh->vh_phci_tail->ph_next = ph; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate vh->vh_phci_tail = ph; 5847c478bd9Sstevel@tonic-gate vh->vh_phci_count++; 5857c478bd9Sstevel@tonic-gate /* to force discovery of all phci children during busconfig */ 5867c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_cutoff_time = -1; 5877c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5887c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * mdi_phci_unregister(): 5937c478bd9Sstevel@tonic-gate * Unregister a pHCI module from mpxio framework 5947c478bd9Sstevel@tonic-gate * mdi_phci_unregister() is called by the pHCI drivers from their 5957c478bd9Sstevel@tonic-gate * detach(9E) handler to unregister their instances from the 5967c478bd9Sstevel@tonic-gate * framework. 5977c478bd9Sstevel@tonic-gate * Return Values: 5987c478bd9Sstevel@tonic-gate * MDI_SUCCESS 5997c478bd9Sstevel@tonic-gate * MDI_FAILURE 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6037c478bd9Sstevel@tonic-gate int 6047c478bd9Sstevel@tonic-gate mdi_phci_unregister(dev_info_t *pdip, int flags) 6057c478bd9Sstevel@tonic-gate { 6067c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 6077c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 6087c478bd9Sstevel@tonic-gate mdi_phci_t *tmp; 6097c478bd9Sstevel@tonic-gate mdi_phci_t *prev = NULL; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 6127c478bd9Sstevel@tonic-gate if (ph == NULL) { 6137c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 6147c478bd9Sstevel@tonic-gate "!pHCI unregister: Not a valid pHCI")); 6157c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 6197c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 6207c478bd9Sstevel@tonic-gate if (vh == NULL) { 6217c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 6227c478bd9Sstevel@tonic-gate "!pHCI unregister: Not a valid vHCI")); 6237c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 6277c478bd9Sstevel@tonic-gate tmp = vh->vh_phci_head; 6287c478bd9Sstevel@tonic-gate while (tmp) { 6297c478bd9Sstevel@tonic-gate if (tmp == ph) { 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate prev = tmp; 6337c478bd9Sstevel@tonic-gate tmp = tmp->ph_next; 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_head) { 6377c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph->ph_next; 6387c478bd9Sstevel@tonic-gate } else { 6397c478bd9Sstevel@tonic-gate prev->ph_next = ph->ph_next; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_tail) { 6437c478bd9Sstevel@tonic-gate vh->vh_phci_tail = prev; 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate vh->vh_phci_count--; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate /* 6497c478bd9Sstevel@tonic-gate * If no busconfig is in progress, release the phci busconfig resources. 6507c478bd9Sstevel@tonic-gate * We only need vh->vh_phci_count of busconfig resources. 6517c478bd9Sstevel@tonic-gate */ 6527c478bd9Sstevel@tonic-gate if (vh->vh_bus_config.vhc_start_time == 0 && 6537c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc_cnt > vh->vh_phci_count) { 6547c478bd9Sstevel@tonic-gate int count; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate count = vh->vh_bus_config.vhc_phc_cnt - vh->vh_phci_count; 6577c478bd9Sstevel@tonic-gate while (count--) { 6587c478bd9Sstevel@tonic-gate mdi_phci_config_t *phc; 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate phc = vh->vh_bus_config.vhc_phc; 6617c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc = phc->phc_next; 6627c478bd9Sstevel@tonic-gate kmem_free(phc, sizeof (*phc)); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc_cnt = vh->vh_phci_count; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate cv_destroy(&ph->ph_unstable_cv); 6707c478bd9Sstevel@tonic-gate cv_destroy(&ph->ph_powerchange_cv); 6717c478bd9Sstevel@tonic-gate mutex_destroy(&ph->ph_mutex); 6727c478bd9Sstevel@tonic-gate kmem_free(ph, sizeof (mdi_phci_t)); 6737c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component &= ~MDI_COMPONENT_PHCI; 6747c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = NULL; 6757c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* 6797c478bd9Sstevel@tonic-gate * i_devi_get_phci(): 6807c478bd9Sstevel@tonic-gate * Utility function to return the phci extensions. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate static mdi_phci_t * 6837c478bd9Sstevel@tonic-gate i_devi_get_phci(dev_info_t *pdip) 6847c478bd9Sstevel@tonic-gate { 6857c478bd9Sstevel@tonic-gate mdi_phci_t *ph = NULL; 6867c478bd9Sstevel@tonic-gate if (MDI_PHCI(pdip)) { 6877c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(pdip)->devi_mdi_xhci; 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate return (ph); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate /* 6937c478bd9Sstevel@tonic-gate * mdi_phci_path2devinfo(): 6947c478bd9Sstevel@tonic-gate * Utility function to search for a valid phci device given 6957c478bd9Sstevel@tonic-gate * the devfs pathname. 6967c478bd9Sstevel@tonic-gate */ 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate dev_info_t * 6997c478bd9Sstevel@tonic-gate mdi_phci_path2devinfo(dev_info_t *vdip, caddr_t pathname) 7007c478bd9Sstevel@tonic-gate { 7017c478bd9Sstevel@tonic-gate char *temp_pathname; 7027c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 7037c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 7047c478bd9Sstevel@tonic-gate dev_info_t *pdip = NULL; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate vh = i_devi_get_vhci(vdip); 7077c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate if (vh == NULL) { 7107c478bd9Sstevel@tonic-gate /* 7117c478bd9Sstevel@tonic-gate * Invalid vHCI component, return failure 7127c478bd9Sstevel@tonic-gate */ 7137c478bd9Sstevel@tonic-gate return (NULL); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7177c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 7187c478bd9Sstevel@tonic-gate ph = vh->vh_phci_head; 7197c478bd9Sstevel@tonic-gate while (ph != NULL) { 7207c478bd9Sstevel@tonic-gate pdip = ph->ph_dip; 7217c478bd9Sstevel@tonic-gate ASSERT(pdip != NULL); 7227c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 7237c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, temp_pathname); 7247c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 7257c478bd9Sstevel@tonic-gate break; 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate ph = ph->ph_next; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate if (ph == NULL) { 7307c478bd9Sstevel@tonic-gate pdip = NULL; 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 7337c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 7347c478bd9Sstevel@tonic-gate return (pdip); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * mdi_phci_get_path_count(): 7397c478bd9Sstevel@tonic-gate * get number of path information nodes associated with a given 7407c478bd9Sstevel@tonic-gate * pHCI device. 7417c478bd9Sstevel@tonic-gate */ 7427c478bd9Sstevel@tonic-gate int 7437c478bd9Sstevel@tonic-gate mdi_phci_get_path_count(dev_info_t *pdip) 7447c478bd9Sstevel@tonic-gate { 7457c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 7467c478bd9Sstevel@tonic-gate int count = 0; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 7497c478bd9Sstevel@tonic-gate if (ph != NULL) { 7507c478bd9Sstevel@tonic-gate count = ph->ph_path_count; 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate return (count); 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate /* 7567c478bd9Sstevel@tonic-gate * i_mdi_phci_lock(): 7577c478bd9Sstevel@tonic-gate * Lock a pHCI device 7587c478bd9Sstevel@tonic-gate * Return Values: 7597c478bd9Sstevel@tonic-gate * None 7607c478bd9Sstevel@tonic-gate * Note: 7617c478bd9Sstevel@tonic-gate * The default locking order is: 7627c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 7637c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 7647c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 7657c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 7667c478bd9Sstevel@tonic-gate */ 7677c478bd9Sstevel@tonic-gate static void 7687c478bd9Sstevel@tonic-gate i_mdi_phci_lock(mdi_phci_t *ph, mdi_pathinfo_t *pip) 7697c478bd9Sstevel@tonic-gate { 7707c478bd9Sstevel@tonic-gate if (pip) { 7717c478bd9Sstevel@tonic-gate /* Reverse locking is requested. */ 7727c478bd9Sstevel@tonic-gate while (MDI_PHCI_TRYLOCK(ph) == 0) { 7737c478bd9Sstevel@tonic-gate /* 7747c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 7757c478bd9Sstevel@tonic-gate * after a small delay 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 7787c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 7797c478bd9Sstevel@tonic-gate delay(1); 7807c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 7817c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate } else { 7847c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * i_mdi_phci_get_client_lock(): 7907c478bd9Sstevel@tonic-gate * Lock a pHCI device 7917c478bd9Sstevel@tonic-gate * Return Values: 7927c478bd9Sstevel@tonic-gate * None 7937c478bd9Sstevel@tonic-gate * Note: 7947c478bd9Sstevel@tonic-gate * The default locking order is: 7957c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex)) 7967c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 7977c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 7987c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate static void 8017c478bd9Sstevel@tonic-gate i_mdi_phci_get_client_lock(mdi_phci_t *ph, mdi_client_t *ct) 8027c478bd9Sstevel@tonic-gate { 8037c478bd9Sstevel@tonic-gate if (ct) { 8047c478bd9Sstevel@tonic-gate /* Reverse locking is requested. */ 8057c478bd9Sstevel@tonic-gate while (MDI_PHCI_TRYLOCK(ph) == 0) { 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 8087c478bd9Sstevel@tonic-gate * after a small delay 8097c478bd9Sstevel@tonic-gate */ 8107c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 8117c478bd9Sstevel@tonic-gate delay(1); 8127c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate } else { 8157c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate /* 8207c478bd9Sstevel@tonic-gate * i_mdi_phci_unlock(): 8217c478bd9Sstevel@tonic-gate * Unlock the pHCI component 8227c478bd9Sstevel@tonic-gate */ 8237c478bd9Sstevel@tonic-gate static void 8247c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(mdi_phci_t *ph) 8257c478bd9Sstevel@tonic-gate { 8267c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate /* 8307c478bd9Sstevel@tonic-gate * i_mdi_devinfo_create(): 8317c478bd9Sstevel@tonic-gate * create client device's devinfo node 8327c478bd9Sstevel@tonic-gate * Return Values: 8337c478bd9Sstevel@tonic-gate * dev_info 8347c478bd9Sstevel@tonic-gate * NULL 8357c478bd9Sstevel@tonic-gate * Notes: 8367c478bd9Sstevel@tonic-gate */ 8377c478bd9Sstevel@tonic-gate static dev_info_t * 8387c478bd9Sstevel@tonic-gate i_mdi_devinfo_create(mdi_vhci_t *vh, char *name, char *guid, 8397c478bd9Sstevel@tonic-gate char **compatible, int ncompatible, int flags) 8407c478bd9Sstevel@tonic-gate { 8417c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate /* Verify for duplicate entry */ 8467c478bd9Sstevel@tonic-gate cdip = i_mdi_devinfo_find(vh, name, guid); 8477c478bd9Sstevel@tonic-gate ASSERT(cdip == NULL); 8487c478bd9Sstevel@tonic-gate if (cdip) { 8497c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8507c478bd9Sstevel@tonic-gate "i_mdi_devinfo_create: client dip %p already exists", 8517c478bd9Sstevel@tonic-gate (void *)cdip); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate if (flags == DDI_SLEEP) { 8557c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(vh->vh_dip, name, 8567c478bd9Sstevel@tonic-gate DEVI_SID_NODEID, &cdip); 8577c478bd9Sstevel@tonic-gate } else { 8587c478bd9Sstevel@tonic-gate (void) ndi_devi_alloc(vh->vh_dip, name, 8597c478bd9Sstevel@tonic-gate DEVI_SID_NODEID, &cdip); 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate if (cdip == NULL) 8627c478bd9Sstevel@tonic-gate goto fail; 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate * Create component type and Global unique identifier 8667c478bd9Sstevel@tonic-gate * properties 8677c478bd9Sstevel@tonic-gate */ 8687c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, 8697c478bd9Sstevel@tonic-gate MDI_CLIENT_GUID_PROP, guid) != DDI_PROP_SUCCESS) { 8707c478bd9Sstevel@tonic-gate goto fail; 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate /* Decorate the node with compatible property */ 8747c478bd9Sstevel@tonic-gate if (compatible && 8757c478bd9Sstevel@tonic-gate (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip, 8767c478bd9Sstevel@tonic-gate "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS)) { 8777c478bd9Sstevel@tonic-gate goto fail; 8787c478bd9Sstevel@tonic-gate } 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate return (cdip); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate fail: 8837c478bd9Sstevel@tonic-gate if (cdip) { 8847c478bd9Sstevel@tonic-gate (void) ndi_prop_remove_all(cdip); 8857c478bd9Sstevel@tonic-gate (void) ndi_devi_free(cdip); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate return (NULL); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* 8917c478bd9Sstevel@tonic-gate * i_mdi_devinfo_find(): 8927c478bd9Sstevel@tonic-gate * Find a matching devinfo node for given client node name 8937c478bd9Sstevel@tonic-gate * and its guid. 8947c478bd9Sstevel@tonic-gate * Return Values: 8957c478bd9Sstevel@tonic-gate * Handle to a dev_info node or NULL 8967c478bd9Sstevel@tonic-gate */ 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate static dev_info_t * 8997c478bd9Sstevel@tonic-gate i_mdi_devinfo_find(mdi_vhci_t *vh, caddr_t name, char *guid) 9007c478bd9Sstevel@tonic-gate { 9017c478bd9Sstevel@tonic-gate char *data; 9027c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 9037c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 9047c478bd9Sstevel@tonic-gate int circular; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate ndi_devi_enter(vh->vh_dip, &circular); 9077c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vh->vh_dip)->devi_child; 9087c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 9097c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate if (strcmp(DEVI(cdip)->devi_node_name, name)) { 9127c478bd9Sstevel@tonic-gate continue; 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip, 9167c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, MDI_CLIENT_GUID_PROP, 9177c478bd9Sstevel@tonic-gate &data) != DDI_PROP_SUCCESS) { 9187c478bd9Sstevel@tonic-gate continue; 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate if (strcmp(data, guid) != 0) { 9227c478bd9Sstevel@tonic-gate ddi_prop_free(data); 9237c478bd9Sstevel@tonic-gate continue; 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate ddi_prop_free(data); 9267c478bd9Sstevel@tonic-gate break; 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate ndi_devi_exit(vh->vh_dip, circular); 9297c478bd9Sstevel@tonic-gate return (cdip); 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate /* 9337c478bd9Sstevel@tonic-gate * i_mdi_devinfo_remove(): 9347c478bd9Sstevel@tonic-gate * Remove a client device node 9357c478bd9Sstevel@tonic-gate */ 9367c478bd9Sstevel@tonic-gate static int 9377c478bd9Sstevel@tonic-gate i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags) 9387c478bd9Sstevel@tonic-gate { 9397c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 9407c478bd9Sstevel@tonic-gate if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS || 9417c478bd9Sstevel@tonic-gate (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) { 9427c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 9437c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 9447c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_devinfo_remove:" 9457c478bd9Sstevel@tonic-gate " failed. cdip = %p\n", cdip)); 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate /* 9487c478bd9Sstevel@tonic-gate * Convert to MDI error code 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate switch (rv) { 9517c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 9527c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 9537c478bd9Sstevel@tonic-gate break; 9547c478bd9Sstevel@tonic-gate case NDI_BUSY: 9557c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 9567c478bd9Sstevel@tonic-gate break; 9577c478bd9Sstevel@tonic-gate default: 9587c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 9597c478bd9Sstevel@tonic-gate break; 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate return (rv); 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* 9667c478bd9Sstevel@tonic-gate * i_devi_get_client() 9677c478bd9Sstevel@tonic-gate * Utility function to get mpxio component extensions 9687c478bd9Sstevel@tonic-gate */ 9697c478bd9Sstevel@tonic-gate static mdi_client_t * 9707c478bd9Sstevel@tonic-gate i_devi_get_client(dev_info_t *cdip) 9717c478bd9Sstevel@tonic-gate { 9727c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 9737c478bd9Sstevel@tonic-gate if (MDI_CLIENT(cdip)) { 9747c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(cdip)->devi_mdi_client; 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate return (ct); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate /* 9807c478bd9Sstevel@tonic-gate * i_mdi_is_child_present(): 9817c478bd9Sstevel@tonic-gate * Search for the presence of client device dev_info node 9827c478bd9Sstevel@tonic-gate */ 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate static int 9857c478bd9Sstevel@tonic-gate i_mdi_is_child_present(dev_info_t *vdip, dev_info_t *cdip) 9867c478bd9Sstevel@tonic-gate { 9877c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 9887c478bd9Sstevel@tonic-gate struct dev_info *dip; 9897c478bd9Sstevel@tonic-gate int circular; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 9927c478bd9Sstevel@tonic-gate dip = DEVI(vdip)->devi_child; 9937c478bd9Sstevel@tonic-gate while (dip) { 9947c478bd9Sstevel@tonic-gate if (dip == DEVI(cdip)) { 9957c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 9967c478bd9Sstevel@tonic-gate break; 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate dip = dip->devi_sibling; 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 10017c478bd9Sstevel@tonic-gate return (rv); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate /* 10067c478bd9Sstevel@tonic-gate * i_mdi_client_lock(): 10077c478bd9Sstevel@tonic-gate * Grab client component lock 10087c478bd9Sstevel@tonic-gate * Return Values: 10097c478bd9Sstevel@tonic-gate * None 10107c478bd9Sstevel@tonic-gate * Note: 10117c478bd9Sstevel@tonic-gate * The default locking order is: 10127c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 10137c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 10147c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 10157c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate static void 10197c478bd9Sstevel@tonic-gate i_mdi_client_lock(mdi_client_t *ct, mdi_pathinfo_t *pip) 10207c478bd9Sstevel@tonic-gate { 10217c478bd9Sstevel@tonic-gate if (pip) { 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * Reverse locking is requested. 10247c478bd9Sstevel@tonic-gate */ 10257c478bd9Sstevel@tonic-gate while (MDI_CLIENT_TRYLOCK(ct) == 0) { 10267c478bd9Sstevel@tonic-gate /* 10277c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 10287c478bd9Sstevel@tonic-gate * after a small delay 10297c478bd9Sstevel@tonic-gate */ 10307c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 10317c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 10327c478bd9Sstevel@tonic-gate delay(1); 10337c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 10347c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate } else { 10377c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate /* 10427c478bd9Sstevel@tonic-gate * i_mdi_client_unlock(): 10437c478bd9Sstevel@tonic-gate * Unlock a client component 10447c478bd9Sstevel@tonic-gate */ 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate static void 10477c478bd9Sstevel@tonic-gate i_mdi_client_unlock(mdi_client_t *ct) 10487c478bd9Sstevel@tonic-gate { 10497c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate /* 10537c478bd9Sstevel@tonic-gate * i_mdi_client_alloc(): 10547c478bd9Sstevel@tonic-gate * Allocate and initialize a client structure. Caller should 10557c478bd9Sstevel@tonic-gate * hold the global mdi_mutex. 10567c478bd9Sstevel@tonic-gate * Return Values: 10577c478bd9Sstevel@tonic-gate * Handle to a client component 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10607c478bd9Sstevel@tonic-gate static mdi_client_t * 10617c478bd9Sstevel@tonic-gate i_mdi_client_alloc(mdi_vhci_t *vh, char *name, char *lguid, int flags) 10627c478bd9Sstevel@tonic-gate { 10637c478bd9Sstevel@tonic-gate mdi_client_t *ct; 10647c478bd9Sstevel@tonic-gate char *drvname = NULL; 10657c478bd9Sstevel@tonic-gate char *guid = NULL; 10667c478bd9Sstevel@tonic-gate client_lb_args_t *lb_args = NULL; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /* 10717c478bd9Sstevel@tonic-gate * Allocate and initialize a component structure. 10727c478bd9Sstevel@tonic-gate */ 10737c478bd9Sstevel@tonic-gate ct = kmem_zalloc(sizeof (*ct), 10747c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 10757c478bd9Sstevel@tonic-gate if (ct == NULL) 10767c478bd9Sstevel@tonic-gate goto fail; 10777c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); 10787c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 10797c478bd9Sstevel@tonic-gate ct->ct_hprev = NULL; 10807c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 10817c478bd9Sstevel@tonic-gate ct->ct_vhci = vh; 10827c478bd9Sstevel@tonic-gate drvname = kmem_alloc(strlen(name) + 1, 10837c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 10847c478bd9Sstevel@tonic-gate if (drvname == NULL) 10857c478bd9Sstevel@tonic-gate goto fail; 10867c478bd9Sstevel@tonic-gate ct->ct_drvname = drvname; 10877c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_drvname, name); 10887c478bd9Sstevel@tonic-gate guid = kmem_alloc(strlen(lguid) + 1, 10897c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 10907c478bd9Sstevel@tonic-gate if (guid == NULL) 10917c478bd9Sstevel@tonic-gate goto fail; 10927c478bd9Sstevel@tonic-gate ct->ct_guid = guid; 10937c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_guid, lguid); 10947c478bd9Sstevel@tonic-gate ct->ct_cprivate = NULL; 10957c478bd9Sstevel@tonic-gate ct->ct_vprivate = NULL; 10967c478bd9Sstevel@tonic-gate ct->ct_flags = 0; 10977c478bd9Sstevel@tonic-gate ct->ct_state = MDI_CLIENT_STATE_FAILED; 10987c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 10997c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 11007c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 11017c478bd9Sstevel@tonic-gate ct->ct_failover_flags = 0; 11027c478bd9Sstevel@tonic-gate ct->ct_failover_status = 0; 11037c478bd9Sstevel@tonic-gate cv_init(&ct->ct_failover_cv, NULL, CV_DRIVER, NULL); 11047c478bd9Sstevel@tonic-gate ct->ct_unstable = 0; 11057c478bd9Sstevel@tonic-gate cv_init(&ct->ct_unstable_cv, NULL, CV_DRIVER, NULL); 11067c478bd9Sstevel@tonic-gate cv_init(&ct->ct_powerchange_cv, NULL, CV_DRIVER, NULL); 11077c478bd9Sstevel@tonic-gate ct->ct_lb = vh->vh_lb; 11087c478bd9Sstevel@tonic-gate lb_args = kmem_zalloc(sizeof (client_lb_args_t), 11097c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 11107c478bd9Sstevel@tonic-gate if (lb_args == NULL) 11117c478bd9Sstevel@tonic-gate goto fail; 11127c478bd9Sstevel@tonic-gate ct->ct_lb_args = lb_args; 11137c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = LOAD_BALANCE_DEFAULT_REGION_SIZE; 11147c478bd9Sstevel@tonic-gate ct->ct_path_count = 0; 11157c478bd9Sstevel@tonic-gate ct->ct_path_head = NULL; 11167c478bd9Sstevel@tonic-gate ct->ct_path_tail = NULL; 11177c478bd9Sstevel@tonic-gate ct->ct_path_last = NULL; 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate /* 11217c478bd9Sstevel@tonic-gate * Add this client component to our client hash queue 11227c478bd9Sstevel@tonic-gate */ 11237c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(vh, ct); 11247c478bd9Sstevel@tonic-gate return (ct); 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate fail: 11277c478bd9Sstevel@tonic-gate if (guid) 11287c478bd9Sstevel@tonic-gate kmem_free(guid, strlen(lguid) + 1); 11297c478bd9Sstevel@tonic-gate if (drvname) 11307c478bd9Sstevel@tonic-gate kmem_free(drvname, strlen(name) + 1); 11317c478bd9Sstevel@tonic-gate if (lb_args) 11327c478bd9Sstevel@tonic-gate kmem_free(lb_args, sizeof (client_lb_args_t)); 11337c478bd9Sstevel@tonic-gate kmem_free(ct, sizeof (*ct)); 11347c478bd9Sstevel@tonic-gate return (NULL); 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate /* 11387c478bd9Sstevel@tonic-gate * i_mdi_client_enlist_table(): 11397c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. Caller 11407c478bd9Sstevel@tonic-gate * should hold the mdi_mutex 11417c478bd9Sstevel@tonic-gate */ 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate static void 11447c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(mdi_vhci_t *vh, mdi_client_t *ct) 11457c478bd9Sstevel@tonic-gate { 11467c478bd9Sstevel@tonic-gate int index; 11477c478bd9Sstevel@tonic-gate struct client_hash *head; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 11507c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(ct->ct_guid); 11517c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 11527c478bd9Sstevel@tonic-gate ct->ct_hnext = (mdi_client_t *)head->ct_hash_head; 11537c478bd9Sstevel@tonic-gate head->ct_hash_head = ct; 11547c478bd9Sstevel@tonic-gate head->ct_hash_count++; 11557c478bd9Sstevel@tonic-gate vh->vh_client_count++; 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate /* 11597c478bd9Sstevel@tonic-gate * i_mdi_client_delist_table(): 11607c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. 11617c478bd9Sstevel@tonic-gate * Caller should hold the mdi_mutex 11627c478bd9Sstevel@tonic-gate */ 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate static void 11657c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(mdi_vhci_t *vh, mdi_client_t *ct) 11667c478bd9Sstevel@tonic-gate { 11677c478bd9Sstevel@tonic-gate int index; 11687c478bd9Sstevel@tonic-gate char *guid; 11697c478bd9Sstevel@tonic-gate struct client_hash *head; 11707c478bd9Sstevel@tonic-gate mdi_client_t *next; 11717c478bd9Sstevel@tonic-gate mdi_client_t *last; 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 11747c478bd9Sstevel@tonic-gate guid = ct->ct_guid; 11757c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 11767c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate last = NULL; 11797c478bd9Sstevel@tonic-gate next = (mdi_client_t *)head->ct_hash_head; 11807c478bd9Sstevel@tonic-gate while (next != NULL) { 11817c478bd9Sstevel@tonic-gate if (next == ct) { 11827c478bd9Sstevel@tonic-gate break; 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate last = next; 11857c478bd9Sstevel@tonic-gate next = next->ct_hnext; 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate if (next) { 11897c478bd9Sstevel@tonic-gate head->ct_hash_count--; 11907c478bd9Sstevel@tonic-gate if (last == NULL) { 11917c478bd9Sstevel@tonic-gate head->ct_hash_head = ct->ct_hnext; 11927c478bd9Sstevel@tonic-gate } else { 11937c478bd9Sstevel@tonic-gate last->ct_hnext = ct->ct_hnext; 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 11967c478bd9Sstevel@tonic-gate vh->vh_client_count--; 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* 12027c478bd9Sstevel@tonic-gate * i_mdi_client_free(): 12037c478bd9Sstevel@tonic-gate * Free a client component 12047c478bd9Sstevel@tonic-gate */ 12057c478bd9Sstevel@tonic-gate static int 12067c478bd9Sstevel@tonic-gate i_mdi_client_free(mdi_vhci_t *vh, mdi_client_t *ct) 12077c478bd9Sstevel@tonic-gate { 12087c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 12097c478bd9Sstevel@tonic-gate int flags = ct->ct_flags; 12107c478bd9Sstevel@tonic-gate dev_info_t *cdip; 12117c478bd9Sstevel@tonic-gate dev_info_t *vdip; 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 12147c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 12157c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, MDI_CLIENT_GUID_PROP); 12187c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component &= ~MDI_COMPONENT_CLIENT; 12197c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = NULL; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate * Clear out back ref. to dev_info_t node 12237c478bd9Sstevel@tonic-gate */ 12247c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate /* 12277c478bd9Sstevel@tonic-gate * Remove this client from our hash queue 12287c478bd9Sstevel@tonic-gate */ 12297c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(vh, ct); 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate /* 12327c478bd9Sstevel@tonic-gate * Uninitialize and free the component 12337c478bd9Sstevel@tonic-gate */ 12347c478bd9Sstevel@tonic-gate kmem_free(ct->ct_drvname, strlen(ct->ct_drvname) + 1); 12357c478bd9Sstevel@tonic-gate kmem_free(ct->ct_guid, strlen(ct->ct_guid) + 1); 12367c478bd9Sstevel@tonic-gate kmem_free(ct->ct_lb_args, sizeof (client_lb_args_t)); 12377c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_failover_cv); 12387c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_unstable_cv); 12397c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_powerchange_cv); 12407c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_mutex); 12417c478bd9Sstevel@tonic-gate kmem_free(ct, sizeof (*ct)); 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (cdip != NULL) { 12447c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 12457c478bd9Sstevel@tonic-gate (void) i_mdi_devinfo_remove(vdip, cdip, flags); 12467c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate return (rv); 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate /* 12527c478bd9Sstevel@tonic-gate * i_mdi_client_find(): 12537c478bd9Sstevel@tonic-gate * Find the client structure corresponding to a given guid 12547c478bd9Sstevel@tonic-gate * Caller should hold the mdi_mutex 12557c478bd9Sstevel@tonic-gate */ 12567c478bd9Sstevel@tonic-gate static mdi_client_t * 12577c478bd9Sstevel@tonic-gate i_mdi_client_find(mdi_vhci_t *vh, char *guid) 12587c478bd9Sstevel@tonic-gate { 12597c478bd9Sstevel@tonic-gate int index; 12607c478bd9Sstevel@tonic-gate struct client_hash *head; 12617c478bd9Sstevel@tonic-gate mdi_client_t *ct; 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 12647c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 12657c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate ct = head->ct_hash_head; 12687c478bd9Sstevel@tonic-gate while (ct != NULL) { 12697c478bd9Sstevel@tonic-gate if (strcmp(ct->ct_guid, guid) == 0) { 12707c478bd9Sstevel@tonic-gate break; 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate ct = ct->ct_hnext; 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate return (ct); 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate /* 12807c478bd9Sstevel@tonic-gate * i_mdi_client_update_state(): 12817c478bd9Sstevel@tonic-gate * Compute and update client device state 12827c478bd9Sstevel@tonic-gate * Notes: 12837c478bd9Sstevel@tonic-gate * A client device can be in any of three possible states: 12847c478bd9Sstevel@tonic-gate * 12857c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_OPTIMAL - Client in optimal state with more 12867c478bd9Sstevel@tonic-gate * one online/standby paths. Can tolerate failures. 12877c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_DEGRADED - Client device in degraded state with 12887c478bd9Sstevel@tonic-gate * no alternate paths available as standby. A failure on the online 12897c478bd9Sstevel@tonic-gate * would result in loss of access to device data. 12907c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_FAILED - Client device in failed state with 12917c478bd9Sstevel@tonic-gate * no paths available to access the device. 12927c478bd9Sstevel@tonic-gate */ 12937c478bd9Sstevel@tonic-gate static void 12947c478bd9Sstevel@tonic-gate i_mdi_client_update_state(mdi_client_t *ct) 12957c478bd9Sstevel@tonic-gate { 12967c478bd9Sstevel@tonic-gate int state; 12977c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_mutex)); 12987c478bd9Sstevel@tonic-gate state = i_mdi_client_compute_state(ct, NULL); 12997c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_STATE(ct, state); 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate /* 13037c478bd9Sstevel@tonic-gate * i_mdi_client_compute_state(): 13047c478bd9Sstevel@tonic-gate * Compute client device state 13057c478bd9Sstevel@tonic-gate * 13067c478bd9Sstevel@tonic-gate * mdi_phci_t * Pointer to pHCI structure which should 13077c478bd9Sstevel@tonic-gate * while computing the new value. Used by 13087c478bd9Sstevel@tonic-gate * i_mdi_phci_offline() to find the new 13097c478bd9Sstevel@tonic-gate * client state after DR of a pHCI. 13107c478bd9Sstevel@tonic-gate */ 13117c478bd9Sstevel@tonic-gate static int 13127c478bd9Sstevel@tonic-gate i_mdi_client_compute_state(mdi_client_t *ct, mdi_phci_t *ph) 13137c478bd9Sstevel@tonic-gate { 13147c478bd9Sstevel@tonic-gate int state; 13157c478bd9Sstevel@tonic-gate int online_count = 0; 13167c478bd9Sstevel@tonic-gate int standby_count = 0; 13177c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_mutex)); 13207c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 13217c478bd9Sstevel@tonic-gate while (pip != NULL) { 13227c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 13237c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 13247c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 13257c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 13267c478bd9Sstevel@tonic-gate pip = next; 13277c478bd9Sstevel@tonic-gate continue; 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 13307c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_ONLINE) 13317c478bd9Sstevel@tonic-gate online_count++; 13327c478bd9Sstevel@tonic-gate else if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 13337c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_STANDBY) 13347c478bd9Sstevel@tonic-gate standby_count++; 13357c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 13367c478bd9Sstevel@tonic-gate pip = next; 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate if (online_count == 0) { 13407c478bd9Sstevel@tonic-gate if (standby_count == 0) { 13417c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_FAILED; 13427c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!client state: failed" 13437c478bd9Sstevel@tonic-gate " ct = %p\n", ct)); 13447c478bd9Sstevel@tonic-gate } else if (standby_count == 1) { 13457c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 13467c478bd9Sstevel@tonic-gate } else { 13477c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate } else if (online_count == 1) { 13507c478bd9Sstevel@tonic-gate if (standby_count == 0) { 13517c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 13527c478bd9Sstevel@tonic-gate } else { 13537c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate } else { 13567c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate return (state); 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate /* 13627c478bd9Sstevel@tonic-gate * i_mdi_client2devinfo(): 13637c478bd9Sstevel@tonic-gate * Utility function 13647c478bd9Sstevel@tonic-gate */ 13657c478bd9Sstevel@tonic-gate dev_info_t * 13667c478bd9Sstevel@tonic-gate i_mdi_client2devinfo(mdi_client_t *ct) 13677c478bd9Sstevel@tonic-gate { 13687c478bd9Sstevel@tonic-gate return (ct->ct_dip); 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* 13727c478bd9Sstevel@tonic-gate * mdi_client_path2_devinfo(): 13737c478bd9Sstevel@tonic-gate * Given the parent devinfo and child devfs pathname, search for 13747c478bd9Sstevel@tonic-gate * a valid devfs node handle. 13757c478bd9Sstevel@tonic-gate */ 13767c478bd9Sstevel@tonic-gate dev_info_t * 13777c478bd9Sstevel@tonic-gate mdi_client_path2devinfo(dev_info_t *vdip, char *pathname) 13787c478bd9Sstevel@tonic-gate { 13797c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 13807c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 13817c478bd9Sstevel@tonic-gate char *temp_pathname; 13827c478bd9Sstevel@tonic-gate int circular; 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate /* 13857c478bd9Sstevel@tonic-gate * Allocate temp buffer 13867c478bd9Sstevel@tonic-gate */ 13877c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * Lock parent against changes 13917c478bd9Sstevel@tonic-gate */ 13927c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 13937c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vdip)->devi_child; 13947c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 13957c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 13987c478bd9Sstevel@tonic-gate (void) ddi_pathname(cdip, temp_pathname); 13997c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 14007c478bd9Sstevel@tonic-gate break; 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate /* 14047c478bd9Sstevel@tonic-gate * Release devinfo lock 14057c478bd9Sstevel@tonic-gate */ 14067c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate /* 14097c478bd9Sstevel@tonic-gate * Free the temp buffer 14107c478bd9Sstevel@tonic-gate */ 14117c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 14127c478bd9Sstevel@tonic-gate return (cdip); 14137c478bd9Sstevel@tonic-gate } 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate /* 14177c478bd9Sstevel@tonic-gate * mdi_client_get_path_count(): 14187c478bd9Sstevel@tonic-gate * Utility function to get number of path information nodes 14197c478bd9Sstevel@tonic-gate * associated with a given client device. 14207c478bd9Sstevel@tonic-gate */ 14217c478bd9Sstevel@tonic-gate int 14227c478bd9Sstevel@tonic-gate mdi_client_get_path_count(dev_info_t *cdip) 14237c478bd9Sstevel@tonic-gate { 14247c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14257c478bd9Sstevel@tonic-gate int count = 0; 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14287c478bd9Sstevel@tonic-gate if (ct != NULL) { 14297c478bd9Sstevel@tonic-gate count = ct->ct_path_count; 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate return (count); 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate /* 14367c478bd9Sstevel@tonic-gate * i_mdi_get_hash_key(): 14377c478bd9Sstevel@tonic-gate * Create a hash using strings as keys 14387c478bd9Sstevel@tonic-gate * 14397c478bd9Sstevel@tonic-gate */ 14407c478bd9Sstevel@tonic-gate static int 14417c478bd9Sstevel@tonic-gate i_mdi_get_hash_key(char *str) 14427c478bd9Sstevel@tonic-gate { 14437c478bd9Sstevel@tonic-gate uint32_t g, hash = 0; 14447c478bd9Sstevel@tonic-gate char *p; 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate for (p = str; *p != '\0'; p++) { 14477c478bd9Sstevel@tonic-gate g = *p; 14487c478bd9Sstevel@tonic-gate hash += g; 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate return (hash % (CLIENT_HASH_TABLE_SIZE - 1)); 14517c478bd9Sstevel@tonic-gate } 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate /* 14547c478bd9Sstevel@tonic-gate * mdi_get_lb_policy(): 14557c478bd9Sstevel@tonic-gate * Get current load balancing policy for a given client device 14567c478bd9Sstevel@tonic-gate */ 14577c478bd9Sstevel@tonic-gate client_lb_t 14587c478bd9Sstevel@tonic-gate mdi_get_lb_policy(dev_info_t *cdip) 14597c478bd9Sstevel@tonic-gate { 14607c478bd9Sstevel@tonic-gate client_lb_t lb = LOAD_BALANCE_NONE; 14617c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14647c478bd9Sstevel@tonic-gate if (ct != NULL) { 14657c478bd9Sstevel@tonic-gate lb = ct->ct_lb; 14667c478bd9Sstevel@tonic-gate } 14677c478bd9Sstevel@tonic-gate return (lb); 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate /* 14717c478bd9Sstevel@tonic-gate * mdi_set_lb_region_size(): 14727c478bd9Sstevel@tonic-gate * Set current region size for the load-balance 14737c478bd9Sstevel@tonic-gate */ 14747c478bd9Sstevel@tonic-gate int 14757c478bd9Sstevel@tonic-gate mdi_set_lb_region_size(dev_info_t *cdip, int region_size) 14767c478bd9Sstevel@tonic-gate { 14777c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14787c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14817c478bd9Sstevel@tonic-gate if (ct != NULL && ct->ct_lb_args != NULL) { 14827c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = region_size; 14837c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate return (rv); 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate /* 14897c478bd9Sstevel@tonic-gate * mdi_Set_lb_policy(): 14907c478bd9Sstevel@tonic-gate * Set current load balancing policy for a given client device 14917c478bd9Sstevel@tonic-gate */ 14927c478bd9Sstevel@tonic-gate int 14937c478bd9Sstevel@tonic-gate mdi_set_lb_policy(dev_info_t *cdip, client_lb_t lb) 14947c478bd9Sstevel@tonic-gate { 14957c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14967c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14997c478bd9Sstevel@tonic-gate if (ct != NULL) { 15007c478bd9Sstevel@tonic-gate ct->ct_lb = lb; 15017c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate return (rv); 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate /* 15077c478bd9Sstevel@tonic-gate * mdi_failover(): 15087c478bd9Sstevel@tonic-gate * failover function called by the vHCI drivers to initiate 15097c478bd9Sstevel@tonic-gate * a failover operation. This is typically due to non-availability 15107c478bd9Sstevel@tonic-gate * of online paths to route I/O requests. Failover can be 15117c478bd9Sstevel@tonic-gate * triggered through user application also. 15127c478bd9Sstevel@tonic-gate * 15137c478bd9Sstevel@tonic-gate * The vHCI driver calls mdi_failover() to initiate a failover 15147c478bd9Sstevel@tonic-gate * operation. mdi_failover() calls back into the vHCI driver's 15157c478bd9Sstevel@tonic-gate * vo_failover() entry point to perform the actual failover 15167c478bd9Sstevel@tonic-gate * operation. The reason for requiring the vHCI driver to 15177c478bd9Sstevel@tonic-gate * initiate failover by calling mdi_failover(), instead of directly 15187c478bd9Sstevel@tonic-gate * executing vo_failover() itself, is to ensure that the mdi 15197c478bd9Sstevel@tonic-gate * framework can keep track of the client state properly. 15207c478bd9Sstevel@tonic-gate * Additionally, mdi_failover() provides as a convenience the 15217c478bd9Sstevel@tonic-gate * option of performing the failover operation synchronously or 15227c478bd9Sstevel@tonic-gate * asynchronously 15237c478bd9Sstevel@tonic-gate * 15247c478bd9Sstevel@tonic-gate * Upon successful completion of the failover operation, the 15257c478bd9Sstevel@tonic-gate * paths that were previously ONLINE will be in the STANDBY state, 15267c478bd9Sstevel@tonic-gate * and the newly activated paths will be in the ONLINE state. 15277c478bd9Sstevel@tonic-gate * 15287c478bd9Sstevel@tonic-gate * The flags modifier determines whether the activation is done 15297c478bd9Sstevel@tonic-gate * synchronously: MDI_FAILOVER_SYNC 15307c478bd9Sstevel@tonic-gate * Return Values: 15317c478bd9Sstevel@tonic-gate * MDI_SUCCESS 15327c478bd9Sstevel@tonic-gate * MDI_FAILURE 15337c478bd9Sstevel@tonic-gate * MDI_BUSY 15347c478bd9Sstevel@tonic-gate */ 15357c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15367c478bd9Sstevel@tonic-gate int 15377c478bd9Sstevel@tonic-gate mdi_failover(dev_info_t *vdip, dev_info_t *cdip, int flags) 15387c478bd9Sstevel@tonic-gate { 15397c478bd9Sstevel@tonic-gate int rv; 15407c478bd9Sstevel@tonic-gate mdi_client_t *ct; 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 15437c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 15447c478bd9Sstevel@tonic-gate if (ct == NULL) { 15457c478bd9Sstevel@tonic-gate /* cdip is not a valid client device. Nothing more to do. */ 15467c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 15477c478bd9Sstevel@tonic-gate } 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_PATH_FREE_IN_PROGRESS(ct)) { 15527c478bd9Sstevel@tonic-gate /* A path to the client is being freed */ 15537c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15547c478bd9Sstevel@tonic-gate return (MDI_BUSY); 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 15597c478bd9Sstevel@tonic-gate /* 15607c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 15617c478bd9Sstevel@tonic-gate */ 15627c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15637c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 15677c478bd9Sstevel@tonic-gate /* 15687c478bd9Sstevel@tonic-gate * Failover is already in progress; return BUSY 15697c478bd9Sstevel@tonic-gate */ 15707c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15717c478bd9Sstevel@tonic-gate return (MDI_BUSY); 15727c478bd9Sstevel@tonic-gate } 15737c478bd9Sstevel@tonic-gate /* 15747c478bd9Sstevel@tonic-gate * Make sure that mdi_pathinfo node state changes are processed. 15757c478bd9Sstevel@tonic-gate * We do not allow failovers to progress while client path state 15767c478bd9Sstevel@tonic-gate * changes are in progress 15777c478bd9Sstevel@tonic-gate */ 15787c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 15797c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 15807c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15817c478bd9Sstevel@tonic-gate return (MDI_BUSY); 15827c478bd9Sstevel@tonic-gate } else { 15837c478bd9Sstevel@tonic-gate while (ct->ct_unstable) 15847c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_unstable_cv, &ct->ct_mutex); 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate /* 15897c478bd9Sstevel@tonic-gate * Client device is in stable state. Before proceeding, perform sanity 15907c478bd9Sstevel@tonic-gate * checks again. 15917c478bd9Sstevel@tonic-gate */ 15927c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct)) || (MDI_CLIENT_IS_FAILED(ct)) || 15937c478bd9Sstevel@tonic-gate (i_ddi_node_state(ct->ct_dip) < DS_READY)) { 15947c478bd9Sstevel@tonic-gate /* 15957c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 15967c478bd9Sstevel@tonic-gate */ 15977c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15987c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate /* 16027c478bd9Sstevel@tonic-gate * Set the client state as failover in progress. 16037c478bd9Sstevel@tonic-gate */ 16047c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_FAILOVER_IN_PROGRESS(ct); 16057c478bd9Sstevel@tonic-gate ct->ct_failover_flags = flags; 16067c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 16097c478bd9Sstevel@tonic-gate /* 16107c478bd9Sstevel@tonic-gate * Submit the initiate failover request via CPR safe 16117c478bd9Sstevel@tonic-gate * taskq threads. 16127c478bd9Sstevel@tonic-gate */ 16137c478bd9Sstevel@tonic-gate (void) taskq_dispatch(mdi_taskq, (task_func_t *)i_mdi_failover, 16147c478bd9Sstevel@tonic-gate ct, KM_SLEEP); 16157c478bd9Sstevel@tonic-gate return (MDI_ACCEPT); 16167c478bd9Sstevel@tonic-gate } else { 16177c478bd9Sstevel@tonic-gate /* 16187c478bd9Sstevel@tonic-gate * Synchronous failover mode. Typically invoked from the user 16197c478bd9Sstevel@tonic-gate * land. 16207c478bd9Sstevel@tonic-gate */ 16217c478bd9Sstevel@tonic-gate rv = i_mdi_failover(ct); 16227c478bd9Sstevel@tonic-gate } 16237c478bd9Sstevel@tonic-gate return (rv); 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate /* 16277c478bd9Sstevel@tonic-gate * i_mdi_failover(): 16287c478bd9Sstevel@tonic-gate * internal failover function. Invokes vHCI drivers failover 16297c478bd9Sstevel@tonic-gate * callback function and process the failover status 16307c478bd9Sstevel@tonic-gate * Return Values: 16317c478bd9Sstevel@tonic-gate * None 16327c478bd9Sstevel@tonic-gate * 16337c478bd9Sstevel@tonic-gate * Note: A client device in failover state can not be detached or freed. 16347c478bd9Sstevel@tonic-gate */ 16357c478bd9Sstevel@tonic-gate static int 16367c478bd9Sstevel@tonic-gate i_mdi_failover(void *arg) 16377c478bd9Sstevel@tonic-gate { 16387c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 16397c478bd9Sstevel@tonic-gate mdi_client_t *ct = (mdi_client_t *)arg; 16407c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = ct->ct_vhci; 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&ct->ct_mutex)); 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate if (vh->vh_ops->vo_failover != NULL) { 16457c478bd9Sstevel@tonic-gate /* 16467c478bd9Sstevel@tonic-gate * Call vHCI drivers callback routine 16477c478bd9Sstevel@tonic-gate */ 16487c478bd9Sstevel@tonic-gate rv = (*vh->vh_ops->vo_failover)(vh->vh_dip, ct->ct_dip, 16497c478bd9Sstevel@tonic-gate ct->ct_failover_flags); 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 16537c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_FAILOVER_IN_PROGRESS(ct); 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate /* 16567c478bd9Sstevel@tonic-gate * Save the failover return status 16577c478bd9Sstevel@tonic-gate */ 16587c478bd9Sstevel@tonic-gate ct->ct_failover_status = rv; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate /* 16617c478bd9Sstevel@tonic-gate * As a result of failover, client status would have been changed. 16627c478bd9Sstevel@tonic-gate * Update the client state and wake up anyone waiting on this client 16637c478bd9Sstevel@tonic-gate * device. 16647c478bd9Sstevel@tonic-gate */ 16657c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_failover_cv); 16687c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 16697c478bd9Sstevel@tonic-gate return (rv); 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* 16737c478bd9Sstevel@tonic-gate * Load balancing is logical block. 16747c478bd9Sstevel@tonic-gate * IOs within the range described by region_size 16757c478bd9Sstevel@tonic-gate * would go on the same path. This would improve the 16767c478bd9Sstevel@tonic-gate * performance by cache-hit on some of the RAID devices. 16777c478bd9Sstevel@tonic-gate * Search only for online paths(At some point we 16787c478bd9Sstevel@tonic-gate * may want to balance across target ports). 16797c478bd9Sstevel@tonic-gate * If no paths are found then default to round-robin. 16807c478bd9Sstevel@tonic-gate */ 16817c478bd9Sstevel@tonic-gate static int 16827c478bd9Sstevel@tonic-gate i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp) 16837c478bd9Sstevel@tonic-gate { 16847c478bd9Sstevel@tonic-gate int path_index = -1; 16857c478bd9Sstevel@tonic-gate int online_path_count = 0; 16867c478bd9Sstevel@tonic-gate int online_nonpref_path_count = 0; 16877c478bd9Sstevel@tonic-gate int region_size = ct->ct_lb_args->region_size; 16887c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 16897c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 16907c478bd9Sstevel@tonic-gate int preferred, path_cnt; 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 16937c478bd9Sstevel@tonic-gate while (pip) { 16947c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 16957c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_state == 16967c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && MDI_PI(pip)->pi_preferred) { 16977c478bd9Sstevel@tonic-gate online_path_count++; 16987c478bd9Sstevel@tonic-gate } else if (MDI_PI(pip)->pi_state == 16997c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && !MDI_PI(pip)->pi_preferred) { 17007c478bd9Sstevel@tonic-gate online_nonpref_path_count++; 17017c478bd9Sstevel@tonic-gate } 17027c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 17037c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 17047c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 17057c478bd9Sstevel@tonic-gate pip = next; 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate /* if found any online/preferred then use this type */ 17087c478bd9Sstevel@tonic-gate if (online_path_count > 0) { 17097c478bd9Sstevel@tonic-gate path_cnt = online_path_count; 17107c478bd9Sstevel@tonic-gate preferred = 1; 17117c478bd9Sstevel@tonic-gate } else if (online_nonpref_path_count > 0) { 17127c478bd9Sstevel@tonic-gate path_cnt = online_nonpref_path_count; 17137c478bd9Sstevel@tonic-gate preferred = 0; 17147c478bd9Sstevel@tonic-gate } else { 17157c478bd9Sstevel@tonic-gate path_cnt = 0; 17167c478bd9Sstevel@tonic-gate } 17177c478bd9Sstevel@tonic-gate if (path_cnt) { 17187c478bd9Sstevel@tonic-gate path_index = (bp->b_blkno >> region_size) % path_cnt; 17197c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 17207c478bd9Sstevel@tonic-gate while (pip && path_index != -1) { 17217c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 17227c478bd9Sstevel@tonic-gate if (path_index == 0 && 17237c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 17247c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE) && 17257c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == preferred) { 17267c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 17277c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 17287c478bd9Sstevel@tonic-gate *ret_pip = pip; 17297c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 17307c478bd9Sstevel@tonic-gate } 17317c478bd9Sstevel@tonic-gate path_index --; 17327c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 17337c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 17347c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 17357c478bd9Sstevel@tonic-gate pip = next; 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate if (pip == NULL) { 17387c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 17397c478bd9Sstevel@tonic-gate "!lba %p, no pip !!\n", 17407c478bd9Sstevel@tonic-gate bp->b_blkno)); 17417c478bd9Sstevel@tonic-gate } else { 17427c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 17437c478bd9Sstevel@tonic-gate "!lba %p, no pip for path_index, " 17447c478bd9Sstevel@tonic-gate "pip %p\n", pip)); 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate /* 17517c478bd9Sstevel@tonic-gate * mdi_select_path(): 17527c478bd9Sstevel@tonic-gate * select a path to access a client device. 17537c478bd9Sstevel@tonic-gate * 17547c478bd9Sstevel@tonic-gate * mdi_select_path() function is called by the vHCI drivers to 17557c478bd9Sstevel@tonic-gate * select a path to route the I/O request to. The caller passes 17567c478bd9Sstevel@tonic-gate * the block I/O data transfer structure ("buf") as one of the 17577c478bd9Sstevel@tonic-gate * parameters. The mpxio framework uses the buf structure 17587c478bd9Sstevel@tonic-gate * contents to maintain per path statistics (total I/O size / 17597c478bd9Sstevel@tonic-gate * count pending). If more than one online paths are available to 17607c478bd9Sstevel@tonic-gate * select, the framework automatically selects a suitable path 17617c478bd9Sstevel@tonic-gate * for routing I/O request. If a failover operation is active for 17627c478bd9Sstevel@tonic-gate * this client device the call shall be failed with MDI_BUSY error 17637c478bd9Sstevel@tonic-gate * code. 17647c478bd9Sstevel@tonic-gate * 17657c478bd9Sstevel@tonic-gate * By default this function returns a suitable path in online 17667c478bd9Sstevel@tonic-gate * state based on the current load balancing policy. Currently 17677c478bd9Sstevel@tonic-gate * we support LOAD_BALANCE_NONE (Previously selected online path 17687c478bd9Sstevel@tonic-gate * will continue to be used till the path is usable) and 17697c478bd9Sstevel@tonic-gate * LOAD_BALANCE_RR (Online paths will be selected in a round 17707c478bd9Sstevel@tonic-gate * robin fashion), LOAD_BALANCE_LB(Online paths will be selected 17717c478bd9Sstevel@tonic-gate * based on the logical block). The load balancing 17727c478bd9Sstevel@tonic-gate * through vHCI drivers configuration file (driver.conf). 17737c478bd9Sstevel@tonic-gate * 17747c478bd9Sstevel@tonic-gate * vHCI drivers may override this default behavior by specifying 17757c478bd9Sstevel@tonic-gate * appropriate flags. If start_pip is specified (non NULL) is 17767c478bd9Sstevel@tonic-gate * used as start point to walk and find the next appropriate path. 17777c478bd9Sstevel@tonic-gate * The following values are currently defined: 17787c478bd9Sstevel@tonic-gate * MDI_SELECT_ONLINE_PATH (to select an ONLINE path) and/or 17797c478bd9Sstevel@tonic-gate * MDI_SELECT_STANDBY_PATH (to select an STANDBY path). 17807c478bd9Sstevel@tonic-gate * 17817c478bd9Sstevel@tonic-gate * The non-standard behavior is used by the scsi_vhci driver, 17827c478bd9Sstevel@tonic-gate * whenever it has to use a STANDBY/FAULTED path. Eg. during 17837c478bd9Sstevel@tonic-gate * attach of client devices (to avoid an unnecessary failover 17847c478bd9Sstevel@tonic-gate * when the STANDBY path comes up first), during failover 17857c478bd9Sstevel@tonic-gate * (to activate a STANDBY path as ONLINE). 17867c478bd9Sstevel@tonic-gate * 17877c478bd9Sstevel@tonic-gate * The selected path in returned in a held state (ref_cnt). 17887c478bd9Sstevel@tonic-gate * Caller should release the hold by calling mdi_rele_path(). 17897c478bd9Sstevel@tonic-gate * 17907c478bd9Sstevel@tonic-gate * Return Values: 17917c478bd9Sstevel@tonic-gate * MDI_SUCCESS - Completed successfully 17927c478bd9Sstevel@tonic-gate * MDI_BUSY - Client device is busy failing over 17937c478bd9Sstevel@tonic-gate * MDI_NOPATH - Client device is online, but no valid path are 17947c478bd9Sstevel@tonic-gate * available to access this client device 17957c478bd9Sstevel@tonic-gate * MDI_FAILURE - Invalid client device or state 17967c478bd9Sstevel@tonic-gate * MDI_DEVI_ONLINING 17977c478bd9Sstevel@tonic-gate * - Client device (struct dev_info state) is in 17987c478bd9Sstevel@tonic-gate * onlining state. 17997c478bd9Sstevel@tonic-gate */ 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18027c478bd9Sstevel@tonic-gate int 18037c478bd9Sstevel@tonic-gate mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags, 18047c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start_pip, mdi_pathinfo_t **ret_pip) 18057c478bd9Sstevel@tonic-gate { 18067c478bd9Sstevel@tonic-gate mdi_client_t *ct; 18077c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 18087c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 18097c478bd9Sstevel@tonic-gate mdi_pathinfo_t *head; 18107c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start; 18117c478bd9Sstevel@tonic-gate client_lb_t lbp; /* load balancing policy */ 18127c478bd9Sstevel@tonic-gate int sb = 1; /* standard behavior */ 18137c478bd9Sstevel@tonic-gate int preferred = 1; /* preferred path */ 18147c478bd9Sstevel@tonic-gate int cond, cont = 1; 18157c478bd9Sstevel@tonic-gate int retry = 0; 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate if (flags != 0) { 18187c478bd9Sstevel@tonic-gate /* 18197c478bd9Sstevel@tonic-gate * disable default behavior 18207c478bd9Sstevel@tonic-gate */ 18217c478bd9Sstevel@tonic-gate sb = 0; 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate *ret_pip = NULL; 18257c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 18267c478bd9Sstevel@tonic-gate if (ct == NULL) { 18277c478bd9Sstevel@tonic-gate /* mdi extensions are NULL, Nothing more to do */ 18287c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 18327c478bd9Sstevel@tonic-gate 18337c478bd9Sstevel@tonic-gate if (sb) { 18347c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 18357c478bd9Sstevel@tonic-gate /* 18367c478bd9Sstevel@tonic-gate * Client is not ready to accept any I/O requests. 18377c478bd9Sstevel@tonic-gate * Fail this request. 18387c478bd9Sstevel@tonic-gate */ 18397c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 18407c478bd9Sstevel@tonic-gate "client state offline ct = %p\n", ct)); 18417c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18427c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 18467c478bd9Sstevel@tonic-gate /* 18477c478bd9Sstevel@tonic-gate * Check for Failover is in progress. If so tell the 18487c478bd9Sstevel@tonic-gate * caller that this device is busy. 18497c478bd9Sstevel@tonic-gate */ 18507c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 18517c478bd9Sstevel@tonic-gate "client failover in progress ct = %p\n", ct)); 18527c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18537c478bd9Sstevel@tonic-gate return (MDI_BUSY); 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate /* 18577c478bd9Sstevel@tonic-gate * Check to see whether the client device is attached. 18587c478bd9Sstevel@tonic-gate * If not so, let the vHCI driver manually select a path 18597c478bd9Sstevel@tonic-gate * (standby) and let the probe/attach process to continue. 18607c478bd9Sstevel@tonic-gate */ 18617c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct)) || 18627c478bd9Sstevel@tonic-gate i_ddi_node_state(cdip) < DS_READY) { 18637c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, cdip, "!Devi is onlining\n")); 18647c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18657c478bd9Sstevel@tonic-gate return (MDI_DEVI_ONLINING); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate /* 18707c478bd9Sstevel@tonic-gate * Cache in the client list head. If head of the list is NULL 18717c478bd9Sstevel@tonic-gate * return MDI_NOPATH 18727c478bd9Sstevel@tonic-gate */ 18737c478bd9Sstevel@tonic-gate head = ct->ct_path_head; 18747c478bd9Sstevel@tonic-gate if (head == NULL) { 18757c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18767c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate /* 18807c478bd9Sstevel@tonic-gate * for non default behavior, bypass current 18817c478bd9Sstevel@tonic-gate * load balancing policy and always use LOAD_BALANCE_RR 18827c478bd9Sstevel@tonic-gate * except that the start point will be adjusted based 18837c478bd9Sstevel@tonic-gate * on the provided start_pip 18847c478bd9Sstevel@tonic-gate */ 18857c478bd9Sstevel@tonic-gate lbp = sb ? ct->ct_lb : LOAD_BALANCE_RR; 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate switch (lbp) { 18887c478bd9Sstevel@tonic-gate case LOAD_BALANCE_NONE: 18897c478bd9Sstevel@tonic-gate /* 18907c478bd9Sstevel@tonic-gate * Load balancing is None or Alternate path mode 18917c478bd9Sstevel@tonic-gate * Start looking for a online mdi_pathinfo node starting from 18927c478bd9Sstevel@tonic-gate * last known selected path 18937c478bd9Sstevel@tonic-gate */ 18947c478bd9Sstevel@tonic-gate preferred = 1; 18957c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_last; 18967c478bd9Sstevel@tonic-gate if (pip == NULL) { 18977c478bd9Sstevel@tonic-gate pip = head; 18987c478bd9Sstevel@tonic-gate } 18997c478bd9Sstevel@tonic-gate start = pip; 19007c478bd9Sstevel@tonic-gate do { 19017c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 19027c478bd9Sstevel@tonic-gate /* 19037c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 19047c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 19057c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 19067c478bd9Sstevel@tonic-gate */ 19077c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_state == 19087c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 19097c478bd9Sstevel@tonic-gate preferred == MDI_PI(pip)->pi_preferred) { 19107c478bd9Sstevel@tonic-gate /* 19117c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 19127c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 19137c478bd9Sstevel@tonic-gate */ 19147c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 19157c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19167c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 19177c478bd9Sstevel@tonic-gate *ret_pip = pip; 19187c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 19197c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate /* 19237c478bd9Sstevel@tonic-gate * Path is busy. 19247c478bd9Sstevel@tonic-gate */ 19257c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 19267c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 19277c478bd9Sstevel@tonic-gate retry = 1; 19287c478bd9Sstevel@tonic-gate /* 19297c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 19307c478bd9Sstevel@tonic-gate */ 19317c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 19327c478bd9Sstevel@tonic-gate if (next == NULL) { 19337c478bd9Sstevel@tonic-gate next = head; 19347c478bd9Sstevel@tonic-gate } 19357c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19367c478bd9Sstevel@tonic-gate pip = next; 19377c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 19387c478bd9Sstevel@tonic-gate preferred = 0; 19397c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 19407c478bd9Sstevel@tonic-gate cont = 0; 19417c478bd9Sstevel@tonic-gate } 19427c478bd9Sstevel@tonic-gate } while (cont); 19437c478bd9Sstevel@tonic-gate break; 19447c478bd9Sstevel@tonic-gate 19457c478bd9Sstevel@tonic-gate case LOAD_BALANCE_LBA: 19467c478bd9Sstevel@tonic-gate /* 19477c478bd9Sstevel@tonic-gate * Make sure we are looking 19487c478bd9Sstevel@tonic-gate * for an online path. Otherwise, if it is for a STANDBY 19497c478bd9Sstevel@tonic-gate * path request, it will go through and fetch an ONLINE 19507c478bd9Sstevel@tonic-gate * path which is not desirable. 19517c478bd9Sstevel@tonic-gate */ 19527c478bd9Sstevel@tonic-gate if ((ct->ct_lb_args != NULL) && 19537c478bd9Sstevel@tonic-gate (ct->ct_lb_args->region_size) && bp && 19547c478bd9Sstevel@tonic-gate (sb || (flags == MDI_SELECT_ONLINE_PATH))) { 19557c478bd9Sstevel@tonic-gate if (i_mdi_lba_lb(ct, ret_pip, bp) 19567c478bd9Sstevel@tonic-gate == MDI_SUCCESS) { 19577c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 19587c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 19597c478bd9Sstevel@tonic-gate } 19607c478bd9Sstevel@tonic-gate } 19617c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 19627c478bd9Sstevel@tonic-gate case LOAD_BALANCE_RR: 19637c478bd9Sstevel@tonic-gate /* 19647c478bd9Sstevel@tonic-gate * Load balancing is Round Robin. Start looking for a online 19657c478bd9Sstevel@tonic-gate * mdi_pathinfo node starting from last known selected path 19667c478bd9Sstevel@tonic-gate * as the start point. If override flags are specified, 19677c478bd9Sstevel@tonic-gate * process accordingly. 19687c478bd9Sstevel@tonic-gate * If the search is already in effect(start_pip not null), 19697c478bd9Sstevel@tonic-gate * then lets just use the same path preference to continue the 19707c478bd9Sstevel@tonic-gate * traversal. 19717c478bd9Sstevel@tonic-gate */ 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate if (start_pip != NULL) { 19747c478bd9Sstevel@tonic-gate preferred = MDI_PI(start_pip)->pi_preferred; 19757c478bd9Sstevel@tonic-gate } else { 19767c478bd9Sstevel@tonic-gate preferred = 1; 19777c478bd9Sstevel@tonic-gate } 19787c478bd9Sstevel@tonic-gate 19797c478bd9Sstevel@tonic-gate start = sb ? (mdi_pathinfo_t *)ct->ct_path_last : start_pip; 19807c478bd9Sstevel@tonic-gate if (start == NULL) { 19817c478bd9Sstevel@tonic-gate pip = head; 19827c478bd9Sstevel@tonic-gate } else { 19837c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(start)->pi_client_link; 19847c478bd9Sstevel@tonic-gate if (pip == NULL) { 19857c478bd9Sstevel@tonic-gate if (!sb) { 19867c478bd9Sstevel@tonic-gate if (preferred == 0) { 19877c478bd9Sstevel@tonic-gate /* 19887c478bd9Sstevel@tonic-gate * Looks like we have completed 19897c478bd9Sstevel@tonic-gate * the traversal as preferred 19907c478bd9Sstevel@tonic-gate * value is 0. Time to bail out. 19917c478bd9Sstevel@tonic-gate */ 19927c478bd9Sstevel@tonic-gate *ret_pip = NULL; 19937c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 19947c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 19957c478bd9Sstevel@tonic-gate } else { 19967c478bd9Sstevel@tonic-gate /* 19977c478bd9Sstevel@tonic-gate * Looks like we reached the 19987c478bd9Sstevel@tonic-gate * end of the list. Lets enable 19997c478bd9Sstevel@tonic-gate * traversal of non preferred 20007c478bd9Sstevel@tonic-gate * paths. 20017c478bd9Sstevel@tonic-gate */ 20027c478bd9Sstevel@tonic-gate preferred = 0; 20037c478bd9Sstevel@tonic-gate } 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate pip = head; 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate start = pip; 20097c478bd9Sstevel@tonic-gate do { 20107c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 20117c478bd9Sstevel@tonic-gate if (sb) { 20127c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 20137c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 20147c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20157c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20167c478bd9Sstevel@tonic-gate } else { 20177c478bd9Sstevel@tonic-gate if (flags == MDI_SELECT_ONLINE_PATH) { 20187c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 20197c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 20207c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20217c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20227c478bd9Sstevel@tonic-gate } else if (flags == MDI_SELECT_STANDBY_PATH) { 20237c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 20247c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY && 20257c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20267c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20277c478bd9Sstevel@tonic-gate } else if (flags == (MDI_SELECT_ONLINE_PATH | 20287c478bd9Sstevel@tonic-gate MDI_SELECT_STANDBY_PATH)) { 20297c478bd9Sstevel@tonic-gate cond = (((MDI_PI(pip)->pi_state == 20307c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE || 20317c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 20327c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY)) && 20337c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20347c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20357c478bd9Sstevel@tonic-gate } else { 20367c478bd9Sstevel@tonic-gate cond = 0; 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate } 20397c478bd9Sstevel@tonic-gate /* 20407c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 20417c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 20427c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 20437c478bd9Sstevel@tonic-gate */ 20447c478bd9Sstevel@tonic-gate if (cond) { 20457c478bd9Sstevel@tonic-gate /* 20467c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 20477c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 20487c478bd9Sstevel@tonic-gate */ 20497c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 20507c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 20517c478bd9Sstevel@tonic-gate if (sb) 20527c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 20537c478bd9Sstevel@tonic-gate *ret_pip = pip; 20547c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 20557c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 20567c478bd9Sstevel@tonic-gate } 20577c478bd9Sstevel@tonic-gate /* 20587c478bd9Sstevel@tonic-gate * Path is busy. 20597c478bd9Sstevel@tonic-gate */ 20607c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 20617c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 20627c478bd9Sstevel@tonic-gate retry = 1; 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate /* 20657c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 20667c478bd9Sstevel@tonic-gate */ 20677c478bd9Sstevel@tonic-gate do_again: 20687c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 20697c478bd9Sstevel@tonic-gate if (next == NULL) { 20707c478bd9Sstevel@tonic-gate if (!sb) { 20717c478bd9Sstevel@tonic-gate if (preferred == 1) { 20727c478bd9Sstevel@tonic-gate /* 20737c478bd9Sstevel@tonic-gate * Looks like we reached the 20747c478bd9Sstevel@tonic-gate * end of the list. Lets enable 20757c478bd9Sstevel@tonic-gate * traversal of non preferred 20767c478bd9Sstevel@tonic-gate * paths. 20777c478bd9Sstevel@tonic-gate */ 20787c478bd9Sstevel@tonic-gate preferred = 0; 20797c478bd9Sstevel@tonic-gate next = head; 20807c478bd9Sstevel@tonic-gate } else { 20817c478bd9Sstevel@tonic-gate /* 20827c478bd9Sstevel@tonic-gate * We have done both the passes 20837c478bd9Sstevel@tonic-gate * Preferred as well as for 20847c478bd9Sstevel@tonic-gate * Non-preferred. Bail out now. 20857c478bd9Sstevel@tonic-gate */ 20867c478bd9Sstevel@tonic-gate cont = 0; 20877c478bd9Sstevel@tonic-gate } 20887c478bd9Sstevel@tonic-gate } else { 20897c478bd9Sstevel@tonic-gate /* 20907c478bd9Sstevel@tonic-gate * Standard behavior case. 20917c478bd9Sstevel@tonic-gate */ 20927c478bd9Sstevel@tonic-gate next = head; 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate } 20957c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 20967c478bd9Sstevel@tonic-gate if (cont == 0) { 20977c478bd9Sstevel@tonic-gate break; 20987c478bd9Sstevel@tonic-gate } 20997c478bd9Sstevel@tonic-gate pip = next; 21007c478bd9Sstevel@tonic-gate 21017c478bd9Sstevel@tonic-gate if (!sb) { 21027c478bd9Sstevel@tonic-gate /* 21037c478bd9Sstevel@tonic-gate * We need to handle the selection of 21047c478bd9Sstevel@tonic-gate * non-preferred path in the following 21057c478bd9Sstevel@tonic-gate * case: 21067c478bd9Sstevel@tonic-gate * 21077c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 21087c478bd9Sstevel@tonic-gate * | A : 1| - | B : 1| - | C : 0| - |NULL | 21097c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 21107c478bd9Sstevel@tonic-gate * 21117c478bd9Sstevel@tonic-gate * If we start the search with B, we need to 21127c478bd9Sstevel@tonic-gate * skip beyond B to pick C which is non - 21137c478bd9Sstevel@tonic-gate * preferred in the second pass. The following 21147c478bd9Sstevel@tonic-gate * test, if true, will allow us to skip over 21157c478bd9Sstevel@tonic-gate * the 'start'(B in the example) to select 21167c478bd9Sstevel@tonic-gate * other non preferred elements. 21177c478bd9Sstevel@tonic-gate */ 21187c478bd9Sstevel@tonic-gate if ((start_pip != NULL) && (start_pip == pip) && 21197c478bd9Sstevel@tonic-gate (MDI_PI(start_pip)->pi_preferred 21207c478bd9Sstevel@tonic-gate != preferred)) { 21217c478bd9Sstevel@tonic-gate /* 21227c478bd9Sstevel@tonic-gate * try again after going past the start 21237c478bd9Sstevel@tonic-gate * pip 21247c478bd9Sstevel@tonic-gate */ 21257c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 21267c478bd9Sstevel@tonic-gate goto do_again; 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate } else { 21297c478bd9Sstevel@tonic-gate /* 21307c478bd9Sstevel@tonic-gate * Standard behavior case 21317c478bd9Sstevel@tonic-gate */ 21327c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 21337c478bd9Sstevel@tonic-gate /* look for nonpreferred paths */ 21347c478bd9Sstevel@tonic-gate preferred = 0; 21357c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 21367c478bd9Sstevel@tonic-gate /* 21377c478bd9Sstevel@tonic-gate * Exit condition 21387c478bd9Sstevel@tonic-gate */ 21397c478bd9Sstevel@tonic-gate cont = 0; 21407c478bd9Sstevel@tonic-gate } 21417c478bd9Sstevel@tonic-gate } 21427c478bd9Sstevel@tonic-gate } while (cont); 21437c478bd9Sstevel@tonic-gate break; 21447c478bd9Sstevel@tonic-gate } 21457c478bd9Sstevel@tonic-gate 21467c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 21477c478bd9Sstevel@tonic-gate if (retry == 1) { 21487c478bd9Sstevel@tonic-gate return (MDI_BUSY); 21497c478bd9Sstevel@tonic-gate } else { 21507c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 21517c478bd9Sstevel@tonic-gate } 21527c478bd9Sstevel@tonic-gate } 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate /* 21557c478bd9Sstevel@tonic-gate * For a client, return the next available path to any phci 21567c478bd9Sstevel@tonic-gate * 21577c478bd9Sstevel@tonic-gate * Note: 21587c478bd9Sstevel@tonic-gate * Caller should hold the branch's devinfo node to get a consistent 21597c478bd9Sstevel@tonic-gate * snap shot of the mdi_pathinfo nodes. 21607c478bd9Sstevel@tonic-gate * 21617c478bd9Sstevel@tonic-gate * Please note that even the list is stable the mdi_pathinfo 21627c478bd9Sstevel@tonic-gate * node state and properties are volatile. The caller should lock 21637c478bd9Sstevel@tonic-gate * and unlock the nodes by calling mdi_pi_lock() and 21647c478bd9Sstevel@tonic-gate * mdi_pi_unlock() functions to get a stable properties. 21657c478bd9Sstevel@tonic-gate * 21667c478bd9Sstevel@tonic-gate * If there is a need to use the nodes beyond the hold of the 21677c478bd9Sstevel@tonic-gate * devinfo node period (For ex. I/O), then mdi_pathinfo node 21687c478bd9Sstevel@tonic-gate * need to be held against unexpected removal by calling 21697c478bd9Sstevel@tonic-gate * mdi_hold_path() and should be released by calling 21707c478bd9Sstevel@tonic-gate * mdi_rele_path() on completion. 21717c478bd9Sstevel@tonic-gate */ 21727c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 21737c478bd9Sstevel@tonic-gate mdi_get_next_phci_path(dev_info_t *ct_dip, mdi_pathinfo_t *pip) 21747c478bd9Sstevel@tonic-gate { 21757c478bd9Sstevel@tonic-gate mdi_client_t *ct; 21767c478bd9Sstevel@tonic-gate 21777c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(ct_dip)) 21787c478bd9Sstevel@tonic-gate return (NULL); 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate /* 21817c478bd9Sstevel@tonic-gate * Walk through client link 21827c478bd9Sstevel@tonic-gate */ 21837c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(ct_dip)->devi_mdi_client; 21847c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 21857c478bd9Sstevel@tonic-gate 21867c478bd9Sstevel@tonic-gate if (pip == NULL) 21877c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ct->ct_path_head); 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link); 21907c478bd9Sstevel@tonic-gate } 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate /* 21937c478bd9Sstevel@tonic-gate * For a phci, return the next available path to any client 21947c478bd9Sstevel@tonic-gate * Note: ditto mdi_get_next_phci_path() 21957c478bd9Sstevel@tonic-gate */ 21967c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 21977c478bd9Sstevel@tonic-gate mdi_get_next_client_path(dev_info_t *ph_dip, mdi_pathinfo_t *pip) 21987c478bd9Sstevel@tonic-gate { 21997c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 22007c478bd9Sstevel@tonic-gate 22017c478bd9Sstevel@tonic-gate if (!MDI_PHCI(ph_dip)) 22027c478bd9Sstevel@tonic-gate return (NULL); 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate /* 22057c478bd9Sstevel@tonic-gate * Walk through pHCI link 22067c478bd9Sstevel@tonic-gate */ 22077c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(ph_dip)->devi_mdi_xhci; 22087c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate if (pip == NULL) 22117c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ph->ph_path_head); 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link); 22147c478bd9Sstevel@tonic-gate } 22157c478bd9Sstevel@tonic-gate 22167c478bd9Sstevel@tonic-gate /* 22177c478bd9Sstevel@tonic-gate * mdi_get_nextpath(): 22187c478bd9Sstevel@tonic-gate * mdi_pathinfo node walker function. Get the next node from the 22197c478bd9Sstevel@tonic-gate * client or pHCI device list. 22207c478bd9Sstevel@tonic-gate * 22217c478bd9Sstevel@tonic-gate * XXX This is wrapper function for compatibility purposes only. 22227c478bd9Sstevel@tonic-gate * 22237c478bd9Sstevel@tonic-gate * It doesn't work under Multi-level MPxIO, where a dip 22247c478bd9Sstevel@tonic-gate * is both client and phci (which link should next_path follow?). 22257c478bd9Sstevel@tonic-gate * Once Leadville is modified to call mdi_get_next_phci/client_path, 22267c478bd9Sstevel@tonic-gate * this interface should be removed. 22277c478bd9Sstevel@tonic-gate */ 22287c478bd9Sstevel@tonic-gate void 22297c478bd9Sstevel@tonic-gate mdi_get_next_path(dev_info_t *dip, mdi_pathinfo_t *pip, 22307c478bd9Sstevel@tonic-gate mdi_pathinfo_t **ret_pip) 22317c478bd9Sstevel@tonic-gate { 22327c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 22337c478bd9Sstevel@tonic-gate *ret_pip = mdi_get_next_phci_path(dip, pip); 22347c478bd9Sstevel@tonic-gate } else if (MDI_PHCI(dip)) { 22357c478bd9Sstevel@tonic-gate *ret_pip = mdi_get_next_client_path(dip, pip); 22367c478bd9Sstevel@tonic-gate } else { 22377c478bd9Sstevel@tonic-gate *ret_pip = NULL; 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate /* 22427c478bd9Sstevel@tonic-gate * mdi_hold_path(): 22437c478bd9Sstevel@tonic-gate * Hold the mdi_pathinfo node against unwanted unexpected free. 22447c478bd9Sstevel@tonic-gate * Return Values: 22457c478bd9Sstevel@tonic-gate * None 22467c478bd9Sstevel@tonic-gate */ 22477c478bd9Sstevel@tonic-gate void 22487c478bd9Sstevel@tonic-gate mdi_hold_path(mdi_pathinfo_t *pip) 22497c478bd9Sstevel@tonic-gate { 22507c478bd9Sstevel@tonic-gate if (pip) { 22517c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22527c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 22537c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate 22587c478bd9Sstevel@tonic-gate /* 22597c478bd9Sstevel@tonic-gate * mdi_rele_path(): 22607c478bd9Sstevel@tonic-gate * Release the mdi_pathinfo node which was selected 22617c478bd9Sstevel@tonic-gate * through mdi_select_path() mechanism or manually held by 22627c478bd9Sstevel@tonic-gate * calling mdi_hold_path(). 22637c478bd9Sstevel@tonic-gate * Return Values: 22647c478bd9Sstevel@tonic-gate * None 22657c478bd9Sstevel@tonic-gate */ 22667c478bd9Sstevel@tonic-gate void 22677c478bd9Sstevel@tonic-gate mdi_rele_path(mdi_pathinfo_t *pip) 22687c478bd9Sstevel@tonic-gate { 22697c478bd9Sstevel@tonic-gate if (pip) { 22707c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22717c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 22727c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_ref_cnt == 0) { 22737c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_ref_cv); 22747c478bd9Sstevel@tonic-gate } 22757c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 22767c478bd9Sstevel@tonic-gate } 22777c478bd9Sstevel@tonic-gate } 22787c478bd9Sstevel@tonic-gate 22797c478bd9Sstevel@tonic-gate 22807c478bd9Sstevel@tonic-gate /* 22817c478bd9Sstevel@tonic-gate * mdi_pi_lock(): 22827c478bd9Sstevel@tonic-gate * Lock the mdi_pathinfo node. 22837c478bd9Sstevel@tonic-gate * Note: 22847c478bd9Sstevel@tonic-gate * The caller should release the lock by calling mdi_pi_unlock() 22857c478bd9Sstevel@tonic-gate */ 22867c478bd9Sstevel@tonic-gate void 22877c478bd9Sstevel@tonic-gate mdi_pi_lock(mdi_pathinfo_t *pip) 22887c478bd9Sstevel@tonic-gate { 22897c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 22907c478bd9Sstevel@tonic-gate if (pip) { 22917c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22927c478bd9Sstevel@tonic-gate } 22937c478bd9Sstevel@tonic-gate } 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate 22967c478bd9Sstevel@tonic-gate /* 22977c478bd9Sstevel@tonic-gate * mdi_pi_unlock(): 22987c478bd9Sstevel@tonic-gate * Unlock the mdi_pathinfo node. 22997c478bd9Sstevel@tonic-gate * Note: 23007c478bd9Sstevel@tonic-gate * The mdi_pathinfo node should have been locked with mdi_pi_lock() 23017c478bd9Sstevel@tonic-gate */ 23027c478bd9Sstevel@tonic-gate void 23037c478bd9Sstevel@tonic-gate mdi_pi_unlock(mdi_pathinfo_t *pip) 23047c478bd9Sstevel@tonic-gate { 23057c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 23067c478bd9Sstevel@tonic-gate if (pip) { 23077c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 23087c478bd9Sstevel@tonic-gate } 23097c478bd9Sstevel@tonic-gate } 23107c478bd9Sstevel@tonic-gate 23117c478bd9Sstevel@tonic-gate /* 23127c478bd9Sstevel@tonic-gate * mdi_pi_find(): 23137c478bd9Sstevel@tonic-gate * Search the list of mdi_pathinfo nodes attached to the 23147c478bd9Sstevel@tonic-gate * pHCI/Client device node whose path address matches "paddr". 23157c478bd9Sstevel@tonic-gate * Returns a pointer to the mdi_pathinfo node if a matching node is 23167c478bd9Sstevel@tonic-gate * found. 23177c478bd9Sstevel@tonic-gate * Return Values: 23187c478bd9Sstevel@tonic-gate * mdi_pathinfo node handle 23197c478bd9Sstevel@tonic-gate * NULL 23207c478bd9Sstevel@tonic-gate * Notes: 23217c478bd9Sstevel@tonic-gate * Caller need not hold any locks to call this function. 23227c478bd9Sstevel@tonic-gate */ 23237c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 23247c478bd9Sstevel@tonic-gate mdi_pi_find(dev_info_t *pdip, char *caddr, char *paddr) 23257c478bd9Sstevel@tonic-gate { 23267c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 23277c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 23287c478bd9Sstevel@tonic-gate mdi_client_t *ct; 23297c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 23307c478bd9Sstevel@tonic-gate 23317c478bd9Sstevel@tonic-gate if ((pdip == NULL) || (paddr == NULL)) { 23327c478bd9Sstevel@tonic-gate return (NULL); 23337c478bd9Sstevel@tonic-gate } 23347c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 23357c478bd9Sstevel@tonic-gate if (ph == NULL) { 23367c478bd9Sstevel@tonic-gate /* 23377c478bd9Sstevel@tonic-gate * Invalid pHCI device, Nothing more to do. 23387c478bd9Sstevel@tonic-gate */ 23397c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, NULL, 23407c478bd9Sstevel@tonic-gate "!mdi_pi_find: invalid phci")); 23417c478bd9Sstevel@tonic-gate return (NULL); 23427c478bd9Sstevel@tonic-gate } 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 23457c478bd9Sstevel@tonic-gate if (vh == NULL) { 23467c478bd9Sstevel@tonic-gate /* 23477c478bd9Sstevel@tonic-gate * Invalid vHCI device, Nothing more to do. 23487c478bd9Sstevel@tonic-gate */ 23497c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, NULL, 23507c478bd9Sstevel@tonic-gate "!mdi_pi_find: invalid phci")); 23517c478bd9Sstevel@tonic-gate return (NULL); 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate /* 23557c478bd9Sstevel@tonic-gate * Look for client device identified by caddr (guid) 23567c478bd9Sstevel@tonic-gate */ 23577c478bd9Sstevel@tonic-gate if (caddr == NULL) { 23587c478bd9Sstevel@tonic-gate /* 23597c478bd9Sstevel@tonic-gate * Find a mdi_pathinfo node under pHCI list for a matching 23607c478bd9Sstevel@tonic-gate * unit address. 23617c478bd9Sstevel@tonic-gate */ 23627c478bd9Sstevel@tonic-gate mutex_enter(&ph->ph_mutex); 23637c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ph->ph_path_head; 23647c478bd9Sstevel@tonic-gate 23657c478bd9Sstevel@tonic-gate while (pip != NULL) { 23667c478bd9Sstevel@tonic-gate if (strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 23677c478bd9Sstevel@tonic-gate break; 23687c478bd9Sstevel@tonic-gate } 23697c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 23707c478bd9Sstevel@tonic-gate } 23717c478bd9Sstevel@tonic-gate mutex_exit(&ph->ph_mutex); 23727c478bd9Sstevel@tonic-gate return (pip); 23737c478bd9Sstevel@tonic-gate } 23747c478bd9Sstevel@tonic-gate 23757c478bd9Sstevel@tonic-gate /* 23767c478bd9Sstevel@tonic-gate * Find the client device corresponding to 'caddr' 23777c478bd9Sstevel@tonic-gate */ 23787c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 23797c478bd9Sstevel@tonic-gate ct = i_mdi_client_find(vh, caddr); 23807c478bd9Sstevel@tonic-gate if (ct == NULL) { 23817c478bd9Sstevel@tonic-gate /* 23827c478bd9Sstevel@tonic-gate * Client not found, Obviously mdi_pathinfo node has not been 23837c478bd9Sstevel@tonic-gate * created yet. 23847c478bd9Sstevel@tonic-gate */ 23857c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 23867c478bd9Sstevel@tonic-gate return (pip); 23877c478bd9Sstevel@tonic-gate } 23887c478bd9Sstevel@tonic-gate 23897c478bd9Sstevel@tonic-gate /* 23907c478bd9Sstevel@tonic-gate * Hold the client lock and look for a mdi_pathinfo node with matching 23917c478bd9Sstevel@tonic-gate * pHCI and paddr 23927c478bd9Sstevel@tonic-gate */ 23937c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate /* 23967c478bd9Sstevel@tonic-gate * Release the global mutex as it is no more needed. Note: We always 23977c478bd9Sstevel@tonic-gate * respect the locking order while acquiring. 23987c478bd9Sstevel@tonic-gate */ 23997c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 24027c478bd9Sstevel@tonic-gate while (pip != NULL) { 24037c478bd9Sstevel@tonic-gate /* 24047c478bd9Sstevel@tonic-gate * Compare the unit address 24057c478bd9Sstevel@tonic-gate */ 24067c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 24077c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 24087c478bd9Sstevel@tonic-gate break; 24097c478bd9Sstevel@tonic-gate } 24107c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 24117c478bd9Sstevel@tonic-gate } 24127c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 24137c478bd9Sstevel@tonic-gate return (pip); 24147c478bd9Sstevel@tonic-gate } 24157c478bd9Sstevel@tonic-gate 24167c478bd9Sstevel@tonic-gate /* 24177c478bd9Sstevel@tonic-gate * mdi_pi_alloc(): 24187c478bd9Sstevel@tonic-gate * Allocate and initialize a new instance of a mdi_pathinfo node. 24197c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function identifies a 24207c478bd9Sstevel@tonic-gate * unique device path is capable of having properties attached 24217c478bd9Sstevel@tonic-gate * and passed to mdi_pi_online() to fully attach and online the 24227c478bd9Sstevel@tonic-gate * path and client device node. 24237c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function must be 24247c478bd9Sstevel@tonic-gate * destroyed using mdi_pi_free() if the path is no longer 24257c478bd9Sstevel@tonic-gate * operational or if the caller fails to attach a client device 24267c478bd9Sstevel@tonic-gate * node when calling mdi_pi_online(). The framework will not free 24277c478bd9Sstevel@tonic-gate * the resources allocated. 24287c478bd9Sstevel@tonic-gate * This function can be called from both interrupt and kernel 24297c478bd9Sstevel@tonic-gate * contexts. DDI_NOSLEEP flag should be used while calling 24307c478bd9Sstevel@tonic-gate * from interrupt contexts. 24317c478bd9Sstevel@tonic-gate * Return Values: 24327c478bd9Sstevel@tonic-gate * MDI_SUCCESS 24337c478bd9Sstevel@tonic-gate * MDI_FAILURE 24347c478bd9Sstevel@tonic-gate * MDI_NOMEM 24357c478bd9Sstevel@tonic-gate */ 24367c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 24377c478bd9Sstevel@tonic-gate int 24387c478bd9Sstevel@tonic-gate mdi_pi_alloc_compatible(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 24397c478bd9Sstevel@tonic-gate char **compatible, int ncompatible, int flags, mdi_pathinfo_t **ret_pip) 24407c478bd9Sstevel@tonic-gate { 24417c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 24427c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 24437c478bd9Sstevel@tonic-gate mdi_client_t *ct; 24447c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 24457c478bd9Sstevel@tonic-gate dev_info_t *cdip; 24467c478bd9Sstevel@tonic-gate int rv = MDI_NOMEM; 24477c478bd9Sstevel@tonic-gate 24487c478bd9Sstevel@tonic-gate if (pdip == NULL || cname == NULL || caddr == NULL || paddr == NULL || 24497c478bd9Sstevel@tonic-gate ret_pip == NULL) { 24507c478bd9Sstevel@tonic-gate /* Nothing more to do */ 24517c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 24527c478bd9Sstevel@tonic-gate } 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate *ret_pip = NULL; 24557c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 24567c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 24577c478bd9Sstevel@tonic-gate if (ph == NULL) { 24587c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 24597c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 24607c478bd9Sstevel@tonic-gate "!mdi_pi_alloc: invalid pHCI=%p", pdip)); 24617c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 24627c478bd9Sstevel@tonic-gate } 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 24657c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 24667c478bd9Sstevel@tonic-gate if (vh == NULL) { 24677c478bd9Sstevel@tonic-gate /* Invalid vHCI device, return failure */ 24687c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 24697c478bd9Sstevel@tonic-gate "!mdi_pi_alloc: invalid pHCI=%p", pdip)); 24707c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 24717c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 24727c478bd9Sstevel@tonic-gate } 24737c478bd9Sstevel@tonic-gate 24747c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 24757c478bd9Sstevel@tonic-gate /* 24767c478bd9Sstevel@tonic-gate * Do not allow new node creation when pHCI is in 24777c478bd9Sstevel@tonic-gate * offline/suspended states 24787c478bd9Sstevel@tonic-gate */ 24797c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 24807c478bd9Sstevel@tonic-gate "mdi_pi_alloc: pHCI=%p is not ready", ph)); 24817c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 24827c478bd9Sstevel@tonic-gate return (MDI_BUSY); 24837c478bd9Sstevel@tonic-gate } 24847c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 24857c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 24867c478bd9Sstevel@tonic-gate 24877c478bd9Sstevel@tonic-gate /* 24887c478bd9Sstevel@tonic-gate * Look for a client device with matching guid identified by caddr, 24897c478bd9Sstevel@tonic-gate * If not found create one 24907c478bd9Sstevel@tonic-gate */ 24917c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 24927c478bd9Sstevel@tonic-gate ct = i_mdi_client_find(vh, caddr); 24937c478bd9Sstevel@tonic-gate if (ct == NULL) { 24947c478bd9Sstevel@tonic-gate ct = i_mdi_client_alloc(vh, cname, caddr, flags); 24957c478bd9Sstevel@tonic-gate if (ct == NULL) 24967c478bd9Sstevel@tonic-gate goto fail; 24977c478bd9Sstevel@tonic-gate } 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 25007c478bd9Sstevel@tonic-gate /* 25017c478bd9Sstevel@tonic-gate * Allocate a devinfo node 25027c478bd9Sstevel@tonic-gate */ 25037c478bd9Sstevel@tonic-gate ct->ct_dip = i_mdi_devinfo_create(vh, cname, caddr, 25047c478bd9Sstevel@tonic-gate compatible, ncompatible, flags); 25057c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 25067c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(vh, ct); 25077c478bd9Sstevel@tonic-gate goto fail; 25087c478bd9Sstevel@tonic-gate } 25097c478bd9Sstevel@tonic-gate } 25107c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component |= MDI_COMPONENT_CLIENT; 25137c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = (caddr_t)ct; 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 25167c478bd9Sstevel@tonic-gate while (pip != NULL) { 25177c478bd9Sstevel@tonic-gate /* 25187c478bd9Sstevel@tonic-gate * Compare the unit address 25197c478bd9Sstevel@tonic-gate */ 25207c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 25217c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 25227c478bd9Sstevel@tonic-gate break; 25237c478bd9Sstevel@tonic-gate } 25247c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 25257c478bd9Sstevel@tonic-gate } 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate if (pip == NULL) { 25287c478bd9Sstevel@tonic-gate /* 25297c478bd9Sstevel@tonic-gate * This is a new path for this client device. Allocate and 25307c478bd9Sstevel@tonic-gate * initialize a new pathinfo node 25317c478bd9Sstevel@tonic-gate */ 25327c478bd9Sstevel@tonic-gate pip = i_mdi_pi_alloc(ph, paddr, ct, flags); 25337c478bd9Sstevel@tonic-gate if (pip == NULL) { 25347c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(vh, ct); 25357c478bd9Sstevel@tonic-gate goto fail; 25367c478bd9Sstevel@tonic-gate } 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate fail: 25417c478bd9Sstevel@tonic-gate /* 25427c478bd9Sstevel@tonic-gate * Release the global mutex. 25437c478bd9Sstevel@tonic-gate */ 25447c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate /* 25477c478bd9Sstevel@tonic-gate * Mark the pHCI as stable 25487c478bd9Sstevel@tonic-gate */ 25497c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 25507c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 25517c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 25527c478bd9Sstevel@tonic-gate *ret_pip = pip; 25537c478bd9Sstevel@tonic-gate return (rv); 25547c478bd9Sstevel@tonic-gate } 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 25577c478bd9Sstevel@tonic-gate int 25587c478bd9Sstevel@tonic-gate mdi_pi_alloc(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 25597c478bd9Sstevel@tonic-gate int flags, mdi_pathinfo_t **ret_pip) 25607c478bd9Sstevel@tonic-gate { 25617c478bd9Sstevel@tonic-gate return (mdi_pi_alloc_compatible(pdip, cname, caddr, paddr, NULL, 0, 25627c478bd9Sstevel@tonic-gate flags, ret_pip)); 25637c478bd9Sstevel@tonic-gate } 25647c478bd9Sstevel@tonic-gate 25657c478bd9Sstevel@tonic-gate /* 25667c478bd9Sstevel@tonic-gate * i_mdi_pi_alloc(): 25677c478bd9Sstevel@tonic-gate * Allocate a mdi_pathinfo node and add to the pHCI path list 25687c478bd9Sstevel@tonic-gate * Return Values: 25697c478bd9Sstevel@tonic-gate * mdi_pathinfo 25707c478bd9Sstevel@tonic-gate */ 25717c478bd9Sstevel@tonic-gate 25727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 25737c478bd9Sstevel@tonic-gate static mdi_pathinfo_t * 25747c478bd9Sstevel@tonic-gate i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct, int flags) 25757c478bd9Sstevel@tonic-gate { 25767c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 25777c478bd9Sstevel@tonic-gate char *pi_addr = NULL; 25787c478bd9Sstevel@tonic-gate nvlist_t *pi_prop = NULL; 25797c478bd9Sstevel@tonic-gate 25807c478bd9Sstevel@tonic-gate int ct_circular; 25817c478bd9Sstevel@tonic-gate int ph_circular; 25827c478bd9Sstevel@tonic-gate 25837c478bd9Sstevel@tonic-gate pip = kmem_zalloc(sizeof (struct mdi_pathinfo), 25847c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 25857c478bd9Sstevel@tonic-gate if (pip == NULL) 25867c478bd9Sstevel@tonic-gate goto fail; 25877c478bd9Sstevel@tonic-gate mutex_init(&MDI_PI(pip)->pi_mutex, NULL, MUTEX_DEFAULT, NULL); 25887c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PATHINFO_STATE_INIT | 25897c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_TRANSIENT; 25907c478bd9Sstevel@tonic-gate 25917c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_USER_DISABLED(ph)) 25927c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 25937c478bd9Sstevel@tonic-gate 25947c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED_TRANSIENT(ph)) 25957c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 25967c478bd9Sstevel@tonic-gate 25977c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED(ph)) 25987c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 25997c478bd9Sstevel@tonic-gate 26007c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_old_state = MDI_PATHINFO_STATE_INIT; 26017c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_state_cv, NULL, CV_DEFAULT, NULL); 26027c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = ct; 26037c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = ph; 26047c478bd9Sstevel@tonic-gate pi_addr = 26057c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr = kmem_alloc(strlen(paddr) + 1, 26067c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 26077c478bd9Sstevel@tonic-gate if (pi_addr == NULL) 26087c478bd9Sstevel@tonic-gate goto fail; 26097c478bd9Sstevel@tonic-gate (void) strcpy(MDI_PI(pip)->pi_addr, paddr); 26107c478bd9Sstevel@tonic-gate (void) nvlist_alloc(&pi_prop, NV_UNIQUE_NAME, 26117c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 26127c478bd9Sstevel@tonic-gate if (pi_prop == NULL) 26137c478bd9Sstevel@tonic-gate goto fail; 26147c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_prop = pi_prop; 26157c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = NULL; 26167c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = NULL; 26177c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = NULL; 26187c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 26197c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 26207c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt = 0; 26217c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 26227c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = 1; 26237c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_ref_cv, NULL, CV_DEFAULT, NULL); 26247c478bd9Sstevel@tonic-gate 26257c478bd9Sstevel@tonic-gate /* 26267c478bd9Sstevel@tonic-gate * Lock both dev_info nodes against changes in parallel. 26277c478bd9Sstevel@tonic-gate */ 26287c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 26297c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 26307c478bd9Sstevel@tonic-gate 26317c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(ph, pip); 26327c478bd9Sstevel@tonic-gate i_mdi_client_add_path(ct, pip); 26337c478bd9Sstevel@tonic-gate 26347c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 26357c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate return (pip); 26387c478bd9Sstevel@tonic-gate 26397c478bd9Sstevel@tonic-gate fail: 26407c478bd9Sstevel@tonic-gate if (pi_prop) 26417c478bd9Sstevel@tonic-gate (void) nvlist_free(pi_prop); 26427c478bd9Sstevel@tonic-gate if (pi_addr) 26437c478bd9Sstevel@tonic-gate kmem_free(pi_addr, strlen(paddr) + 1); 26447c478bd9Sstevel@tonic-gate kmem_free(pip, sizeof (struct mdi_pathinfo)); 26457c478bd9Sstevel@tonic-gate return (NULL); 26467c478bd9Sstevel@tonic-gate } 26477c478bd9Sstevel@tonic-gate 26487c478bd9Sstevel@tonic-gate /* 26497c478bd9Sstevel@tonic-gate * i_mdi_phci_add_path(): 26507c478bd9Sstevel@tonic-gate * Add a mdi_pathinfo node to pHCI list. 26517c478bd9Sstevel@tonic-gate * Notes: 26527c478bd9Sstevel@tonic-gate * Caller should per-pHCI mutex 26537c478bd9Sstevel@tonic-gate */ 26547c478bd9Sstevel@tonic-gate 26557c478bd9Sstevel@tonic-gate static void 26567c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 26577c478bd9Sstevel@tonic-gate { 26587c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 26597c478bd9Sstevel@tonic-gate 26607c478bd9Sstevel@tonic-gate if (ph->ph_path_head == NULL) { 26617c478bd9Sstevel@tonic-gate ph->ph_path_head = pip; 26627c478bd9Sstevel@tonic-gate } else { 26637c478bd9Sstevel@tonic-gate MDI_PI(ph->ph_path_tail)->pi_phci_link = MDI_PI(pip); 26647c478bd9Sstevel@tonic-gate } 26657c478bd9Sstevel@tonic-gate ph->ph_path_tail = pip; 26667c478bd9Sstevel@tonic-gate ph->ph_path_count++; 26677c478bd9Sstevel@tonic-gate } 26687c478bd9Sstevel@tonic-gate 26697c478bd9Sstevel@tonic-gate /* 26707c478bd9Sstevel@tonic-gate * i_mdi_client_add_path(): 26717c478bd9Sstevel@tonic-gate * Add mdi_pathinfo node to client list 26727c478bd9Sstevel@tonic-gate */ 26737c478bd9Sstevel@tonic-gate 26747c478bd9Sstevel@tonic-gate static void 26757c478bd9Sstevel@tonic-gate i_mdi_client_add_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 26767c478bd9Sstevel@tonic-gate { 26777c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate if (ct->ct_path_head == NULL) { 26807c478bd9Sstevel@tonic-gate ct->ct_path_head = pip; 26817c478bd9Sstevel@tonic-gate } else { 26827c478bd9Sstevel@tonic-gate MDI_PI(ct->ct_path_tail)->pi_client_link = MDI_PI(pip); 26837c478bd9Sstevel@tonic-gate } 26847c478bd9Sstevel@tonic-gate ct->ct_path_tail = pip; 26857c478bd9Sstevel@tonic-gate ct->ct_path_count++; 26867c478bd9Sstevel@tonic-gate } 26877c478bd9Sstevel@tonic-gate 26887c478bd9Sstevel@tonic-gate /* 26897c478bd9Sstevel@tonic-gate * mdi_pi_free(): 26907c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node and also client device node if this 26917c478bd9Sstevel@tonic-gate * is the last path to the device 26927c478bd9Sstevel@tonic-gate * Return Values: 26937c478bd9Sstevel@tonic-gate * MDI_SUCCESS 26947c478bd9Sstevel@tonic-gate * MDI_FAILURE 26957c478bd9Sstevel@tonic-gate * MDI_BUSY 26967c478bd9Sstevel@tonic-gate */ 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 26997c478bd9Sstevel@tonic-gate int 27007c478bd9Sstevel@tonic-gate mdi_pi_free(mdi_pathinfo_t *pip, int flags) 27017c478bd9Sstevel@tonic-gate { 27027c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 27037c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 27047c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 27057c478bd9Sstevel@tonic-gate mdi_client_t *ct; 27067c478bd9Sstevel@tonic-gate int (*f)(); 27077c478bd9Sstevel@tonic-gate int client_held = 0; 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 27107c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 27117c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 27127c478bd9Sstevel@tonic-gate if (ph == NULL) { 27137c478bd9Sstevel@tonic-gate /* 27147c478bd9Sstevel@tonic-gate * Invalid pHCI device, return failure 27157c478bd9Sstevel@tonic-gate */ 27167c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 27177c478bd9Sstevel@tonic-gate "!mdi_pi_free: invalid pHCI")); 27187c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27197c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27207c478bd9Sstevel@tonic-gate } 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 27237c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 27247c478bd9Sstevel@tonic-gate if (vh == NULL) { 27257c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 27267c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 27277c478bd9Sstevel@tonic-gate "!mdi_pi_free: invalid vHCI")); 27287c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27297c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27307c478bd9Sstevel@tonic-gate } 27317c478bd9Sstevel@tonic-gate 27327c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 27337c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 27347c478bd9Sstevel@tonic-gate if (ct == NULL) { 27357c478bd9Sstevel@tonic-gate /* 27367c478bd9Sstevel@tonic-gate * Invalid Client device, return failure 27377c478bd9Sstevel@tonic-gate */ 27387c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 27397c478bd9Sstevel@tonic-gate "!mdi_pi_free: invalid client")); 27407c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27417c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27427c478bd9Sstevel@tonic-gate } 27437c478bd9Sstevel@tonic-gate 27447c478bd9Sstevel@tonic-gate /* 27457c478bd9Sstevel@tonic-gate * Check to see for busy condition. A mdi_pathinfo can only be freed 27467c478bd9Sstevel@tonic-gate * if the node state is either offline or init and the reference count 27477c478bd9Sstevel@tonic-gate * is zero. 27487c478bd9Sstevel@tonic-gate */ 27497c478bd9Sstevel@tonic-gate if (!(MDI_PI_IS_OFFLINE(pip) || MDI_PI_IS_INIT(pip) || 27507c478bd9Sstevel@tonic-gate MDI_PI_IS_INITING(pip))) { 27517c478bd9Sstevel@tonic-gate /* 27527c478bd9Sstevel@tonic-gate * Node is busy 27537c478bd9Sstevel@tonic-gate */ 27547c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 27557c478bd9Sstevel@tonic-gate "!mdi_pi_free: pathinfo node is busy pip=%p", pip)); 27567c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27577c478bd9Sstevel@tonic-gate return (MDI_BUSY); 27587c478bd9Sstevel@tonic-gate } 27597c478bd9Sstevel@tonic-gate 27607c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 27617c478bd9Sstevel@tonic-gate /* 27627c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 27637c478bd9Sstevel@tonic-gate */ 27647c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, "!i_mdi_pi_free: " 27657c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 27667c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 27677c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 27687c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 27697c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 27707c478bd9Sstevel@tonic-gate /* 27717c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 27727c478bd9Sstevel@tonic-gate * being signaled. 27737c478bd9Sstevel@tonic-gate */ 27747c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, 27757c478bd9Sstevel@tonic-gate "!i_mdi_pi_free: " 27767c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 27777c478bd9Sstevel@tonic-gate pip)); 27787c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, 27797c478bd9Sstevel@tonic-gate "!i_mdi_pi_free: " 27807c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 27817c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 27827c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27837c478bd9Sstevel@tonic-gate return (MDI_BUSY); 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate } 27867c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 27877c478bd9Sstevel@tonic-gate client_held = 1; 27887c478bd9Sstevel@tonic-gate } 27897c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 27927c478bd9Sstevel@tonic-gate 27937c478bd9Sstevel@tonic-gate /* Prevent further failovers till mdi_mutex is held */ 27947c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_PATH_FREE_IN_PROGRESS(ct); 27957c478bd9Sstevel@tonic-gate 27967c478bd9Sstevel@tonic-gate /* 27977c478bd9Sstevel@tonic-gate * Wait till failover is complete before removing this node. 27987c478bd9Sstevel@tonic-gate */ 27997c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 28007c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 28037c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 28047c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 28057c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_PATH_FREE_IN_PROGRESS(ct); 28067c478bd9Sstevel@tonic-gate 28077c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_INITING(pip)) { 28087c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_uninit; 28097c478bd9Sstevel@tonic-gate if (f != NULL) { 28107c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 28117c478bd9Sstevel@tonic-gate } 28127c478bd9Sstevel@tonic-gate } 28137c478bd9Sstevel@tonic-gate /* 28147c478bd9Sstevel@tonic-gate * If vo_pi_uninit() completed successfully. 28157c478bd9Sstevel@tonic-gate */ 28167c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 28177c478bd9Sstevel@tonic-gate if (client_held) { 28187c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_free " 28197c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 28207c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate i_mdi_pi_free(ph, pip, ct); 28237c478bd9Sstevel@tonic-gate if (ct->ct_path_count == 0) { 28247c478bd9Sstevel@tonic-gate /* 28257c478bd9Sstevel@tonic-gate * Client lost its last path. 28267c478bd9Sstevel@tonic-gate * Clean up the client device 28277c478bd9Sstevel@tonic-gate */ 28287c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 28297c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(ct->ct_vhci, ct); 28307c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 28317c478bd9Sstevel@tonic-gate return (rv); 28327c478bd9Sstevel@tonic-gate } 28337c478bd9Sstevel@tonic-gate } 28347c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 28357c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 28367c478bd9Sstevel@tonic-gate return (rv); 28377c478bd9Sstevel@tonic-gate } 28387c478bd9Sstevel@tonic-gate 28397c478bd9Sstevel@tonic-gate /* 28407c478bd9Sstevel@tonic-gate * i_mdi_pi_free(): 28417c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node 28427c478bd9Sstevel@tonic-gate */ 28437c478bd9Sstevel@tonic-gate static void 28447c478bd9Sstevel@tonic-gate i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct) 28457c478bd9Sstevel@tonic-gate { 28467c478bd9Sstevel@tonic-gate int ct_circular; 28477c478bd9Sstevel@tonic-gate int ph_circular; 28487c478bd9Sstevel@tonic-gate 28497c478bd9Sstevel@tonic-gate /* 28507c478bd9Sstevel@tonic-gate * remove any per-path kstats 28517c478bd9Sstevel@tonic-gate */ 28527c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(pip); 28537c478bd9Sstevel@tonic-gate 28547c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 28557c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 28567c478bd9Sstevel@tonic-gate 28577c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(ct, pip); 28587c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(ph, pip); 28597c478bd9Sstevel@tonic-gate 28607c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 28617c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 28627c478bd9Sstevel@tonic-gate 28637c478bd9Sstevel@tonic-gate mutex_destroy(&MDI_PI(pip)->pi_mutex); 28647c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_state_cv); 28657c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_ref_cv); 28667c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_addr) { 28677c478bd9Sstevel@tonic-gate kmem_free(MDI_PI(pip)->pi_addr, 28687c478bd9Sstevel@tonic-gate strlen(MDI_PI(pip)->pi_addr) + 1); 28697c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr = NULL; 28707c478bd9Sstevel@tonic-gate } 28717c478bd9Sstevel@tonic-gate 28727c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop) { 28737c478bd9Sstevel@tonic-gate (void) nvlist_free(MDI_PI(pip)->pi_prop); 28747c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_prop = NULL; 28757c478bd9Sstevel@tonic-gate } 28767c478bd9Sstevel@tonic-gate kmem_free(pip, sizeof (struct mdi_pathinfo)); 28777c478bd9Sstevel@tonic-gate } 28787c478bd9Sstevel@tonic-gate 28797c478bd9Sstevel@tonic-gate 28807c478bd9Sstevel@tonic-gate /* 28817c478bd9Sstevel@tonic-gate * i_mdi_phci_remove_path(): 28827c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from pHCI list. 28837c478bd9Sstevel@tonic-gate * Notes: 28847c478bd9Sstevel@tonic-gate * Caller should hold per-pHCI mutex 28857c478bd9Sstevel@tonic-gate */ 28867c478bd9Sstevel@tonic-gate 28877c478bd9Sstevel@tonic-gate static void 28887c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 28897c478bd9Sstevel@tonic-gate { 28907c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 28917c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path = NULL; 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate path = ph->ph_path_head; 28967c478bd9Sstevel@tonic-gate while (path != NULL) { 28977c478bd9Sstevel@tonic-gate if (path == pip) { 28987c478bd9Sstevel@tonic-gate break; 28997c478bd9Sstevel@tonic-gate } 29007c478bd9Sstevel@tonic-gate prev = path; 29017c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 29027c478bd9Sstevel@tonic-gate } 29037c478bd9Sstevel@tonic-gate 29047c478bd9Sstevel@tonic-gate if (path) { 29057c478bd9Sstevel@tonic-gate ph->ph_path_count--; 29067c478bd9Sstevel@tonic-gate if (prev) { 29077c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_phci_link = MDI_PI(path)->pi_phci_link; 29087c478bd9Sstevel@tonic-gate } else { 29097c478bd9Sstevel@tonic-gate ph->ph_path_head = 29107c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 29117c478bd9Sstevel@tonic-gate } 29127c478bd9Sstevel@tonic-gate if (ph->ph_path_tail == path) { 29137c478bd9Sstevel@tonic-gate ph->ph_path_tail = prev; 29147c478bd9Sstevel@tonic-gate } 29157c478bd9Sstevel@tonic-gate } 29167c478bd9Sstevel@tonic-gate 29177c478bd9Sstevel@tonic-gate /* 29187c478bd9Sstevel@tonic-gate * Clear the pHCI link 29197c478bd9Sstevel@tonic-gate */ 29207c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 29217c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = NULL; 29227c478bd9Sstevel@tonic-gate } 29237c478bd9Sstevel@tonic-gate 29247c478bd9Sstevel@tonic-gate /* 29257c478bd9Sstevel@tonic-gate * i_mdi_client_remove_path(): 29267c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from client path list. 29277c478bd9Sstevel@tonic-gate */ 29287c478bd9Sstevel@tonic-gate 29297c478bd9Sstevel@tonic-gate static void 29307c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 29317c478bd9Sstevel@tonic-gate { 29327c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 29337c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path; 29347c478bd9Sstevel@tonic-gate 29357c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 29367c478bd9Sstevel@tonic-gate 29377c478bd9Sstevel@tonic-gate path = ct->ct_path_head; 29387c478bd9Sstevel@tonic-gate while (path != NULL) { 29397c478bd9Sstevel@tonic-gate if (path == pip) { 29407c478bd9Sstevel@tonic-gate break; 29417c478bd9Sstevel@tonic-gate } 29427c478bd9Sstevel@tonic-gate prev = path; 29437c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 29447c478bd9Sstevel@tonic-gate } 29457c478bd9Sstevel@tonic-gate 29467c478bd9Sstevel@tonic-gate if (path) { 29477c478bd9Sstevel@tonic-gate ct->ct_path_count--; 29487c478bd9Sstevel@tonic-gate if (prev) { 29497c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_client_link = 29507c478bd9Sstevel@tonic-gate MDI_PI(path)->pi_client_link; 29517c478bd9Sstevel@tonic-gate } else { 29527c478bd9Sstevel@tonic-gate ct->ct_path_head = 29537c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 29547c478bd9Sstevel@tonic-gate } 29557c478bd9Sstevel@tonic-gate if (ct->ct_path_tail == path) { 29567c478bd9Sstevel@tonic-gate ct->ct_path_tail = prev; 29577c478bd9Sstevel@tonic-gate } 29587c478bd9Sstevel@tonic-gate if (ct->ct_path_last == path) { 29597c478bd9Sstevel@tonic-gate ct->ct_path_last = ct->ct_path_head; 29607c478bd9Sstevel@tonic-gate } 29617c478bd9Sstevel@tonic-gate } 29627c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 29637c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = NULL; 29647c478bd9Sstevel@tonic-gate } 29657c478bd9Sstevel@tonic-gate 29667c478bd9Sstevel@tonic-gate /* 29677c478bd9Sstevel@tonic-gate * i_mdi_pi_state_change(): 29687c478bd9Sstevel@tonic-gate * online a mdi_pathinfo node 29697c478bd9Sstevel@tonic-gate * 29707c478bd9Sstevel@tonic-gate * Return Values: 29717c478bd9Sstevel@tonic-gate * MDI_SUCCESS 29727c478bd9Sstevel@tonic-gate * MDI_FAILURE 29737c478bd9Sstevel@tonic-gate */ 29747c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 29757c478bd9Sstevel@tonic-gate static int 29767c478bd9Sstevel@tonic-gate i_mdi_pi_state_change(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state, int flag) 29777c478bd9Sstevel@tonic-gate { 29787c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 29797c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 29807c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 29817c478bd9Sstevel@tonic-gate mdi_client_t *ct; 29827c478bd9Sstevel@tonic-gate int (*f)(); 29837c478bd9Sstevel@tonic-gate dev_info_t *cdip; 29847c478bd9Sstevel@tonic-gate 29857c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 29887c478bd9Sstevel@tonic-gate ASSERT(ph); 29897c478bd9Sstevel@tonic-gate if (ph == NULL) { 29907c478bd9Sstevel@tonic-gate /* 29917c478bd9Sstevel@tonic-gate * Invalid pHCI device, fail the request 29927c478bd9Sstevel@tonic-gate */ 29937c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 29947c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 29957c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: invalid phci")); 29967c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 29977c478bd9Sstevel@tonic-gate } 29987c478bd9Sstevel@tonic-gate 29997c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 30007c478bd9Sstevel@tonic-gate ASSERT(vh); 30017c478bd9Sstevel@tonic-gate if (vh == NULL) { 30027c478bd9Sstevel@tonic-gate /* 30037c478bd9Sstevel@tonic-gate * Invalid vHCI device, fail the request 30047c478bd9Sstevel@tonic-gate */ 30057c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30067c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 30077c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: invalid vhci")); 30087c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30097c478bd9Sstevel@tonic-gate } 30107c478bd9Sstevel@tonic-gate 30117c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 30127c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 30137c478bd9Sstevel@tonic-gate if (ct == NULL) { 30147c478bd9Sstevel@tonic-gate /* 30157c478bd9Sstevel@tonic-gate * Invalid client device, fail the request 30167c478bd9Sstevel@tonic-gate */ 30177c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30187c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 30197c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: invalid client")); 30207c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30217c478bd9Sstevel@tonic-gate } 30227c478bd9Sstevel@tonic-gate 30237c478bd9Sstevel@tonic-gate /* 30247c478bd9Sstevel@tonic-gate * If this path has not been initialized yet, Callback vHCI driver's 30257c478bd9Sstevel@tonic-gate * pathinfo node initialize entry point 30267c478bd9Sstevel@tonic-gate */ 30277c478bd9Sstevel@tonic-gate 30287c478bd9Sstevel@tonic-gate if (MDI_PI_IS_INITING(pip)) { 30297c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30307c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_init; 30317c478bd9Sstevel@tonic-gate if (f != NULL) { 30327c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 30337c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 30347c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, vh->vh_dip, 30357c478bd9Sstevel@tonic-gate "!vo_pi_init: failed vHCI=0x%p, pip=0x%p", 30367c478bd9Sstevel@tonic-gate vh, pip)); 30377c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30387c478bd9Sstevel@tonic-gate } 30397c478bd9Sstevel@tonic-gate } 30407c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 30417c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 30427c478bd9Sstevel@tonic-gate } 30437c478bd9Sstevel@tonic-gate 30447c478bd9Sstevel@tonic-gate /* 30457c478bd9Sstevel@tonic-gate * Do not allow state transition when pHCI is in offline/suspended 30467c478bd9Sstevel@tonic-gate * states 30477c478bd9Sstevel@tonic-gate */ 30487c478bd9Sstevel@tonic-gate i_mdi_phci_lock(ph, pip); 30497c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 30507c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 30517c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: pHCI not ready, pHCI=%p", ph)); 30527c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30537c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 30547c478bd9Sstevel@tonic-gate return (MDI_BUSY); 30557c478bd9Sstevel@tonic-gate } 30567c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 30577c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 30587c478bd9Sstevel@tonic-gate 30597c478bd9Sstevel@tonic-gate /* 30607c478bd9Sstevel@tonic-gate * Check if mdi_pathinfo state is in transient state. 30617c478bd9Sstevel@tonic-gate * If yes, offlining is in progress and wait till transient state is 30627c478bd9Sstevel@tonic-gate * cleared. 30637c478bd9Sstevel@tonic-gate */ 30647c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 30657c478bd9Sstevel@tonic-gate while (MDI_PI_IS_TRANSIENT(pip)) { 30667c478bd9Sstevel@tonic-gate cv_wait(&MDI_PI(pip)->pi_state_cv, 30677c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex); 30687c478bd9Sstevel@tonic-gate } 30697c478bd9Sstevel@tonic-gate } 30707c478bd9Sstevel@tonic-gate 30717c478bd9Sstevel@tonic-gate /* 30727c478bd9Sstevel@tonic-gate * Grab the client lock in reverse order sequence and release the 30737c478bd9Sstevel@tonic-gate * mdi_pathinfo mutex. 30747c478bd9Sstevel@tonic-gate */ 30757c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 30767c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30777c478bd9Sstevel@tonic-gate 30787c478bd9Sstevel@tonic-gate /* 30797c478bd9Sstevel@tonic-gate * Wait till failover state is cleared 30807c478bd9Sstevel@tonic-gate */ 30817c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 30827c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 30837c478bd9Sstevel@tonic-gate 30847c478bd9Sstevel@tonic-gate /* 30857c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 30867c478bd9Sstevel@tonic-gate */ 30877c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 30887c478bd9Sstevel@tonic-gate switch (state) { 30897c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_ONLINE: 30907c478bd9Sstevel@tonic-gate MDI_PI_SET_ONLINING(pip); 30917c478bd9Sstevel@tonic-gate break; 30927c478bd9Sstevel@tonic-gate 30937c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_STANDBY: 30947c478bd9Sstevel@tonic-gate MDI_PI_SET_STANDBYING(pip); 30957c478bd9Sstevel@tonic-gate break; 30967c478bd9Sstevel@tonic-gate 30977c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_FAULT: 30987c478bd9Sstevel@tonic-gate /* 30997c478bd9Sstevel@tonic-gate * Mark the pathinfo state as FAULTED 31007c478bd9Sstevel@tonic-gate */ 31017c478bd9Sstevel@tonic-gate MDI_PI_SET_FAULTING(pip); 31027c478bd9Sstevel@tonic-gate MDI_PI_ERRSTAT(pip, MDI_PI_HARDERR); 31037c478bd9Sstevel@tonic-gate break; 31047c478bd9Sstevel@tonic-gate 31057c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_OFFLINE: 31067c478bd9Sstevel@tonic-gate /* 31077c478bd9Sstevel@tonic-gate * ndi_devi_offline() cannot hold pip or ct locks. 31087c478bd9Sstevel@tonic-gate */ 31097c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31107c478bd9Sstevel@tonic-gate /* 31117c478bd9Sstevel@tonic-gate * Do not offline if path will become last path and path 31127c478bd9Sstevel@tonic-gate * is busy for user initiated events. 31137c478bd9Sstevel@tonic-gate */ 31147c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 31157c478bd9Sstevel@tonic-gate if ((flag & NDI_DEVI_REMOVE) && 31167c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED)) { 31177c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 31187c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 31197c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 31207c478bd9Sstevel@tonic-gate /* 31217c478bd9Sstevel@tonic-gate * Convert to MDI error code 31227c478bd9Sstevel@tonic-gate */ 31237c478bd9Sstevel@tonic-gate switch (rv) { 31247c478bd9Sstevel@tonic-gate case NDI_BUSY: 31257c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 31267c478bd9Sstevel@tonic-gate break; 31277c478bd9Sstevel@tonic-gate default: 31287c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 31297c478bd9Sstevel@tonic-gate break; 31307c478bd9Sstevel@tonic-gate } 31317c478bd9Sstevel@tonic-gate goto state_change_exit; 31327c478bd9Sstevel@tonic-gate } else { 31337c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 31347c478bd9Sstevel@tonic-gate } 31357c478bd9Sstevel@tonic-gate } 31367c478bd9Sstevel@tonic-gate /* 31377c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 31387c478bd9Sstevel@tonic-gate */ 31397c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 31407c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 31417c478bd9Sstevel@tonic-gate break; 31427c478bd9Sstevel@tonic-gate } 31437c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31447c478bd9Sstevel@tonic-gate MDI_CLIENT_UNSTABLE(ct); 31457c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 31467c478bd9Sstevel@tonic-gate 31477c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 31487c478bd9Sstevel@tonic-gate if (f != NULL) { 31497c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, state, 0, flag); 31507c478bd9Sstevel@tonic-gate if (rv == MDI_NOT_SUPPORTED) { 31517c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DEV_NOT_SUPPORTED(ct); 31527c478bd9Sstevel@tonic-gate } 31537c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 31547c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 31557c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 31567c478bd9Sstevel@tonic-gate } 31577c478bd9Sstevel@tonic-gate } 31587c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 31597c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 31607c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 31617c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 31627c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 31637c478bd9Sstevel@tonic-gate } else { 31647c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip); 31657c478bd9Sstevel@tonic-gate } 31667c478bd9Sstevel@tonic-gate } 31677c478bd9Sstevel@tonic-gate 31687c478bd9Sstevel@tonic-gate /* 31697c478bd9Sstevel@tonic-gate * Wake anyone waiting for this mdi_pathinfo node 31707c478bd9Sstevel@tonic-gate */ 31717c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 31727c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31737c478bd9Sstevel@tonic-gate 31747c478bd9Sstevel@tonic-gate /* 31757c478bd9Sstevel@tonic-gate * Mark the client device as stable 31767c478bd9Sstevel@tonic-gate */ 31777c478bd9Sstevel@tonic-gate MDI_CLIENT_STABLE(ct); 31787c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 31797c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 31807c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 31817c478bd9Sstevel@tonic-gate 31827c478bd9Sstevel@tonic-gate /* 31837c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 31847c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 31857c478bd9Sstevel@tonic-gate * state accordingly 31867c478bd9Sstevel@tonic-gate */ 31877c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 31887c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 31897c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 31907c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 31917c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 31927c478bd9Sstevel@tonic-gate if (cdip && 31937c478bd9Sstevel@tonic-gate (i_ddi_node_state(cdip) < DS_READY) && 31947c478bd9Sstevel@tonic-gate ((state == MDI_PATHINFO_STATE_ONLINE) || 31957c478bd9Sstevel@tonic-gate (state == MDI_PATHINFO_STATE_STANDBY))) { 31967c478bd9Sstevel@tonic-gate 31977c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 31987c478bd9Sstevel@tonic-gate /* 31997c478bd9Sstevel@tonic-gate * Must do ndi_devi_online() through 32007c478bd9Sstevel@tonic-gate * hotplug thread for deferred 32017c478bd9Sstevel@tonic-gate * attach mechanism to work 32027c478bd9Sstevel@tonic-gate */ 32037c478bd9Sstevel@tonic-gate rv = ndi_devi_online(cdip, 0); 32047c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 32057c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && 32067c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == 32077c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_DEGRADED)) { 32087c478bd9Sstevel@tonic-gate /* 32097c478bd9Sstevel@tonic-gate * ndi_devi_online failed. 32107c478bd9Sstevel@tonic-gate * Reset client flags to 32117c478bd9Sstevel@tonic-gate * offline. 32127c478bd9Sstevel@tonic-gate */ 32137c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 32147c478bd9Sstevel@tonic-gate "!ndi_devi_online: failed " 32157c478bd9Sstevel@tonic-gate " Error: %x", rv)); 32167c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 32177c478bd9Sstevel@tonic-gate } 32187c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 32197c478bd9Sstevel@tonic-gate /* Reset the path state */ 32207c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 32217c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = 32227c478bd9Sstevel@tonic-gate MDI_PI_OLD_STATE(pip); 32237c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 32247c478bd9Sstevel@tonic-gate } 32257c478bd9Sstevel@tonic-gate } 32267c478bd9Sstevel@tonic-gate break; 32277c478bd9Sstevel@tonic-gate 32287c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 32297c478bd9Sstevel@tonic-gate /* 32307c478bd9Sstevel@tonic-gate * This is the last path case for 32317c478bd9Sstevel@tonic-gate * non-user initiated events. 32327c478bd9Sstevel@tonic-gate */ 32337c478bd9Sstevel@tonic-gate if (((flag & NDI_DEVI_REMOVE) == 0) && 32347c478bd9Sstevel@tonic-gate cdip && (i_ddi_node_state(cdip) >= 32357c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 32367c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 32377c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 32387c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 32397c478bd9Sstevel@tonic-gate 32407c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 32417c478bd9Sstevel@tonic-gate /* 32427c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 32437c478bd9Sstevel@tonic-gate * Reset client flags to 32447c478bd9Sstevel@tonic-gate * online as the path could not 32457c478bd9Sstevel@tonic-gate * be offlined. 32467c478bd9Sstevel@tonic-gate */ 32477c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 32487c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 32497c478bd9Sstevel@tonic-gate " Error: %x", rv)); 32507c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 32517c478bd9Sstevel@tonic-gate } 32527c478bd9Sstevel@tonic-gate } 32537c478bd9Sstevel@tonic-gate break; 32547c478bd9Sstevel@tonic-gate } 32557c478bd9Sstevel@tonic-gate /* 32567c478bd9Sstevel@tonic-gate * Convert to MDI error code 32577c478bd9Sstevel@tonic-gate */ 32587c478bd9Sstevel@tonic-gate switch (rv) { 32597c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 32607c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 32617c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 32627c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 32637c478bd9Sstevel@tonic-gate break; 32647c478bd9Sstevel@tonic-gate case NDI_BUSY: 32657c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 32667c478bd9Sstevel@tonic-gate break; 32677c478bd9Sstevel@tonic-gate default: 32687c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 32697c478bd9Sstevel@tonic-gate break; 32707c478bd9Sstevel@tonic-gate } 32717c478bd9Sstevel@tonic-gate } 32727c478bd9Sstevel@tonic-gate } 32737c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 32747c478bd9Sstevel@tonic-gate 32757c478bd9Sstevel@tonic-gate state_change_exit: 32767c478bd9Sstevel@tonic-gate /* 32777c478bd9Sstevel@tonic-gate * Mark the pHCI as stable again. 32787c478bd9Sstevel@tonic-gate */ 32797c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 32807c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 32817c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 32827c478bd9Sstevel@tonic-gate return (rv); 32837c478bd9Sstevel@tonic-gate } 32847c478bd9Sstevel@tonic-gate 32857c478bd9Sstevel@tonic-gate /* 32867c478bd9Sstevel@tonic-gate * mdi_pi_online(): 32877c478bd9Sstevel@tonic-gate * Place the path_info node in the online state. The path is 32887c478bd9Sstevel@tonic-gate * now available to be selected by mdi_select_path() for 32897c478bd9Sstevel@tonic-gate * transporting I/O requests to client devices. 32907c478bd9Sstevel@tonic-gate * Return Values: 32917c478bd9Sstevel@tonic-gate * MDI_SUCCESS 32927c478bd9Sstevel@tonic-gate * MDI_FAILURE 32937c478bd9Sstevel@tonic-gate */ 32947c478bd9Sstevel@tonic-gate int 32957c478bd9Sstevel@tonic-gate mdi_pi_online(mdi_pathinfo_t *pip, int flags) 32967c478bd9Sstevel@tonic-gate { 32977c478bd9Sstevel@tonic-gate mdi_client_t *ct = MDI_PI(pip)->pi_client; 32987c478bd9Sstevel@tonic-gate dev_info_t *cdip; 32997c478bd9Sstevel@tonic-gate int client_held = 0; 33007c478bd9Sstevel@tonic-gate int rv; 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 33037c478bd9Sstevel@tonic-gate rv = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_ONLINE, flags); 33047c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) 33057c478bd9Sstevel@tonic-gate return (rv); 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 33087c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 33097c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 33107c478bd9Sstevel@tonic-gate "i_mdi_pm_hold_pip\n")); 33117c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 33127c478bd9Sstevel@tonic-gate client_held = 1; 33137c478bd9Sstevel@tonic-gate } 33147c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 33157c478bd9Sstevel@tonic-gate 33167c478bd9Sstevel@tonic-gate if (client_held) { 33177c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 33187c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 33197c478bd9Sstevel@tonic-gate rv = i_mdi_power_all_phci(ct); 33207c478bd9Sstevel@tonic-gate } 33217c478bd9Sstevel@tonic-gate 33227c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 33237c478bd9Sstevel@tonic-gate "i_mdi_pm_hold_client\n")); 33247c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 33257c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 33267c478bd9Sstevel@tonic-gate } 33277c478bd9Sstevel@tonic-gate 33287c478bd9Sstevel@tonic-gate /* 33297c478bd9Sstevel@tonic-gate * Create the per-path (pathinfo) IO and error kstats which 33307c478bd9Sstevel@tonic-gate * are reported via iostat(1m). 33317c478bd9Sstevel@tonic-gate * 33327c478bd9Sstevel@tonic-gate * Defer creating the per-path kstats if device is not yet 33337c478bd9Sstevel@tonic-gate * attached; the names of the kstats are constructed in part 33347c478bd9Sstevel@tonic-gate * using the devices instance number which is assigned during 33357c478bd9Sstevel@tonic-gate * process of attaching the client device. 33367c478bd9Sstevel@tonic-gate * 33377c478bd9Sstevel@tonic-gate * The framework post_attach handler, mdi_post_attach(), is 33387c478bd9Sstevel@tonic-gate * is responsible for initializing the client's pathinfo list 33397c478bd9Sstevel@tonic-gate * once successfully attached. 33407c478bd9Sstevel@tonic-gate */ 33417c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 33427c478bd9Sstevel@tonic-gate ASSERT(cdip); 33437c478bd9Sstevel@tonic-gate if (cdip == NULL || (i_ddi_node_state(cdip) < DS_ATTACHED)) 33447c478bd9Sstevel@tonic-gate return (rv); 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 33477c478bd9Sstevel@tonic-gate rv = i_mdi_pi_kstat_create(pip); 33487c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 33497c478bd9Sstevel@tonic-gate return (rv); 33507c478bd9Sstevel@tonic-gate } 33517c478bd9Sstevel@tonic-gate 33527c478bd9Sstevel@tonic-gate /* 33537c478bd9Sstevel@tonic-gate * mdi_pi_standby(): 33547c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in standby state 33557c478bd9Sstevel@tonic-gate * 33567c478bd9Sstevel@tonic-gate * Return Values: 33577c478bd9Sstevel@tonic-gate * MDI_SUCCESS 33587c478bd9Sstevel@tonic-gate * MDI_FAILURE 33597c478bd9Sstevel@tonic-gate */ 33607c478bd9Sstevel@tonic-gate int 33617c478bd9Sstevel@tonic-gate mdi_pi_standby(mdi_pathinfo_t *pip, int flags) 33627c478bd9Sstevel@tonic-gate { 33637c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_STANDBY, flags)); 33647c478bd9Sstevel@tonic-gate } 33657c478bd9Sstevel@tonic-gate 33667c478bd9Sstevel@tonic-gate /* 33677c478bd9Sstevel@tonic-gate * mdi_pi_fault(): 33687c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in fault'ed state 33697c478bd9Sstevel@tonic-gate * Return Values: 33707c478bd9Sstevel@tonic-gate * MDI_SUCCESS 33717c478bd9Sstevel@tonic-gate * MDI_FAILURE 33727c478bd9Sstevel@tonic-gate */ 33737c478bd9Sstevel@tonic-gate int 33747c478bd9Sstevel@tonic-gate mdi_pi_fault(mdi_pathinfo_t *pip, int flags) 33757c478bd9Sstevel@tonic-gate { 33767c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_FAULT, flags)); 33777c478bd9Sstevel@tonic-gate } 33787c478bd9Sstevel@tonic-gate 33797c478bd9Sstevel@tonic-gate /* 33807c478bd9Sstevel@tonic-gate * mdi_pi_offline(): 33817c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node. 33827c478bd9Sstevel@tonic-gate * Return Values: 33837c478bd9Sstevel@tonic-gate * MDI_SUCCESS 33847c478bd9Sstevel@tonic-gate * MDI_FAILURE 33857c478bd9Sstevel@tonic-gate */ 33867c478bd9Sstevel@tonic-gate int 33877c478bd9Sstevel@tonic-gate mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 33887c478bd9Sstevel@tonic-gate { 33897c478bd9Sstevel@tonic-gate int ret, client_held = 0; 33907c478bd9Sstevel@tonic-gate mdi_client_t *ct; 33917c478bd9Sstevel@tonic-gate 33927c478bd9Sstevel@tonic-gate ret = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_OFFLINE, flags); 33937c478bd9Sstevel@tonic-gate 33947c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) { 33957c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 33967c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 33977c478bd9Sstevel@tonic-gate client_held = 1; 33987c478bd9Sstevel@tonic-gate } 33997c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34007c478bd9Sstevel@tonic-gate 34017c478bd9Sstevel@tonic-gate if (client_held) { 34027c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 34037c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 34047c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, 34057c478bd9Sstevel@tonic-gate "mdi_pi_offline i_mdi_pm_rele_client\n")); 34067c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 34077c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 34087c478bd9Sstevel@tonic-gate } 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate 34117c478bd9Sstevel@tonic-gate return (ret); 34127c478bd9Sstevel@tonic-gate } 34137c478bd9Sstevel@tonic-gate 34147c478bd9Sstevel@tonic-gate /* 34157c478bd9Sstevel@tonic-gate * i_mdi_pi_offline(): 34167c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node and call the vHCI driver's callback 34177c478bd9Sstevel@tonic-gate */ 34187c478bd9Sstevel@tonic-gate static int 34197c478bd9Sstevel@tonic-gate i_mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 34207c478bd9Sstevel@tonic-gate { 34217c478bd9Sstevel@tonic-gate dev_info_t *vdip = NULL; 34227c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 34237c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 34247c478bd9Sstevel@tonic-gate int (*f)(); 34257c478bd9Sstevel@tonic-gate int rv; 34267c478bd9Sstevel@tonic-gate 34277c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34287c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 34297c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 34307c478bd9Sstevel@tonic-gate 34317c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 34327c478bd9Sstevel@tonic-gate /* 34337c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 34347c478bd9Sstevel@tonic-gate */ 34357c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 34367c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 34377c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 34387c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 34397c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 34407c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 34417c478bd9Sstevel@tonic-gate /* 34427c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 34437c478bd9Sstevel@tonic-gate * being signaled. 34447c478bd9Sstevel@tonic-gate */ 34457c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 34467c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 34477c478bd9Sstevel@tonic-gate pip)); 34487c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 34497c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 34507c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 34517c478bd9Sstevel@tonic-gate } 34527c478bd9Sstevel@tonic-gate } 34537c478bd9Sstevel@tonic-gate vh = ct->ct_vhci; 34547c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 34557c478bd9Sstevel@tonic-gate 34567c478bd9Sstevel@tonic-gate /* 34577c478bd9Sstevel@tonic-gate * Notify vHCI that has registered this event 34587c478bd9Sstevel@tonic-gate */ 34597c478bd9Sstevel@tonic-gate ASSERT(vh->vh_ops); 34607c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 34617c478bd9Sstevel@tonic-gate 34627c478bd9Sstevel@tonic-gate if (f != NULL) { 34637c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34647c478bd9Sstevel@tonic-gate if ((rv = (*f)(vdip, pip, MDI_PATHINFO_STATE_OFFLINE, 0, 34657c478bd9Sstevel@tonic-gate flags)) != MDI_SUCCESS) { 34667c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, vdip, "!vo_path_offline failed " 34677c478bd9Sstevel@tonic-gate "vdip 0x%x, pip 0x%x", vdip, pip)); 34687c478bd9Sstevel@tonic-gate } 34697c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34707c478bd9Sstevel@tonic-gate } 34717c478bd9Sstevel@tonic-gate 34727c478bd9Sstevel@tonic-gate /* 34737c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state and clear the transient condition 34747c478bd9Sstevel@tonic-gate */ 34757c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINE(pip); 34767c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 34777c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34787c478bd9Sstevel@tonic-gate 34797c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 34807c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 34817c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 34827c478bd9Sstevel@tonic-gate dev_info_t *cdip = ct->ct_dip; 34837c478bd9Sstevel@tonic-gate 34847c478bd9Sstevel@tonic-gate /* 34857c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 34867c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 34877c478bd9Sstevel@tonic-gate * state accordingly 34887c478bd9Sstevel@tonic-gate */ 34897c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 34907c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 34917c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 34927c478bd9Sstevel@tonic-gate if (cdip && 34937c478bd9Sstevel@tonic-gate (i_ddi_node_state(cdip) >= 34947c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 34957c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 34967c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 34977c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 34987c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 34997c478bd9Sstevel@tonic-gate /* 35007c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 35017c478bd9Sstevel@tonic-gate * Reset client flags to 35027c478bd9Sstevel@tonic-gate * online. 35037c478bd9Sstevel@tonic-gate */ 35047c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, cdip, 35057c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 35067c478bd9Sstevel@tonic-gate " Error: %x", rv)); 35077c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 35087c478bd9Sstevel@tonic-gate } 35097c478bd9Sstevel@tonic-gate } 35107c478bd9Sstevel@tonic-gate } 35117c478bd9Sstevel@tonic-gate /* 35127c478bd9Sstevel@tonic-gate * Convert to MDI error code 35137c478bd9Sstevel@tonic-gate */ 35147c478bd9Sstevel@tonic-gate switch (rv) { 35157c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 35167c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 35177c478bd9Sstevel@tonic-gate break; 35187c478bd9Sstevel@tonic-gate case NDI_BUSY: 35197c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 35207c478bd9Sstevel@tonic-gate break; 35217c478bd9Sstevel@tonic-gate default: 35227c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 35237c478bd9Sstevel@tonic-gate break; 35247c478bd9Sstevel@tonic-gate } 35257c478bd9Sstevel@tonic-gate } 35267c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 35277c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 35287c478bd9Sstevel@tonic-gate } 35297c478bd9Sstevel@tonic-gate 35307c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 35317c478bd9Sstevel@tonic-gate 35327c478bd9Sstevel@tonic-gate /* 35337c478bd9Sstevel@tonic-gate * Change in the mdi_pathinfo node state will impact the client state 35347c478bd9Sstevel@tonic-gate */ 35357c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!i_mdi_pi_offline ct = %p pip = %p", 35367c478bd9Sstevel@tonic-gate ct, pip)); 35377c478bd9Sstevel@tonic-gate return (rv); 35387c478bd9Sstevel@tonic-gate } 35397c478bd9Sstevel@tonic-gate 35407c478bd9Sstevel@tonic-gate 35417c478bd9Sstevel@tonic-gate /* 35427c478bd9Sstevel@tonic-gate * mdi_pi_get_addr(): 35437c478bd9Sstevel@tonic-gate * Get the unit address associated with a mdi_pathinfo node 35447c478bd9Sstevel@tonic-gate * 35457c478bd9Sstevel@tonic-gate * Return Values: 35467c478bd9Sstevel@tonic-gate * char * 35477c478bd9Sstevel@tonic-gate */ 35487c478bd9Sstevel@tonic-gate char * 35497c478bd9Sstevel@tonic-gate mdi_pi_get_addr(mdi_pathinfo_t *pip) 35507c478bd9Sstevel@tonic-gate { 35517c478bd9Sstevel@tonic-gate if (pip == NULL) 35527c478bd9Sstevel@tonic-gate return (NULL); 35537c478bd9Sstevel@tonic-gate 3554*72a50065Scth return (MDI_PI(pip)->pi_addr); 35557c478bd9Sstevel@tonic-gate } 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate /* 35587c478bd9Sstevel@tonic-gate * mdi_pi_get_client(): 35597c478bd9Sstevel@tonic-gate * Get the client devinfo associated with a mdi_pathinfo node 35607c478bd9Sstevel@tonic-gate * 35617c478bd9Sstevel@tonic-gate * Return Values: 35627c478bd9Sstevel@tonic-gate * Handle to client device dev_info node 35637c478bd9Sstevel@tonic-gate */ 35647c478bd9Sstevel@tonic-gate dev_info_t * 35657c478bd9Sstevel@tonic-gate mdi_pi_get_client(mdi_pathinfo_t *pip) 35667c478bd9Sstevel@tonic-gate { 35677c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 35687c478bd9Sstevel@tonic-gate if (pip) { 35697c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_client->ct_dip; 35707c478bd9Sstevel@tonic-gate } 35717c478bd9Sstevel@tonic-gate return (dip); 35727c478bd9Sstevel@tonic-gate } 35737c478bd9Sstevel@tonic-gate 35747c478bd9Sstevel@tonic-gate /* 35757c478bd9Sstevel@tonic-gate * mdi_pi_get_phci(): 35767c478bd9Sstevel@tonic-gate * Get the pHCI devinfo associated with the mdi_pathinfo node 35777c478bd9Sstevel@tonic-gate * Return Values: 35787c478bd9Sstevel@tonic-gate * Handle to dev_info node 35797c478bd9Sstevel@tonic-gate */ 35807c478bd9Sstevel@tonic-gate dev_info_t * 35817c478bd9Sstevel@tonic-gate mdi_pi_get_phci(mdi_pathinfo_t *pip) 35827c478bd9Sstevel@tonic-gate { 35837c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 35847c478bd9Sstevel@tonic-gate if (pip) { 35857c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_phci->ph_dip; 35867c478bd9Sstevel@tonic-gate } 35877c478bd9Sstevel@tonic-gate return (dip); 35887c478bd9Sstevel@tonic-gate } 35897c478bd9Sstevel@tonic-gate 35907c478bd9Sstevel@tonic-gate /* 35917c478bd9Sstevel@tonic-gate * mdi_pi_get_client_private(): 35927c478bd9Sstevel@tonic-gate * Get the client private information associated with the 35937c478bd9Sstevel@tonic-gate * mdi_pathinfo node 35947c478bd9Sstevel@tonic-gate */ 35957c478bd9Sstevel@tonic-gate void * 35967c478bd9Sstevel@tonic-gate mdi_pi_get_client_private(mdi_pathinfo_t *pip) 35977c478bd9Sstevel@tonic-gate { 35987c478bd9Sstevel@tonic-gate void *cprivate = NULL; 35997c478bd9Sstevel@tonic-gate if (pip) { 36007c478bd9Sstevel@tonic-gate cprivate = MDI_PI(pip)->pi_cprivate; 36017c478bd9Sstevel@tonic-gate } 36027c478bd9Sstevel@tonic-gate return (cprivate); 36037c478bd9Sstevel@tonic-gate } 36047c478bd9Sstevel@tonic-gate 36057c478bd9Sstevel@tonic-gate /* 36067c478bd9Sstevel@tonic-gate * mdi_pi_set_client_private(): 36077c478bd9Sstevel@tonic-gate * Set the client private information in the mdi_pathinfo node 36087c478bd9Sstevel@tonic-gate */ 36097c478bd9Sstevel@tonic-gate void 36107c478bd9Sstevel@tonic-gate mdi_pi_set_client_private(mdi_pathinfo_t *pip, void *priv) 36117c478bd9Sstevel@tonic-gate { 36127c478bd9Sstevel@tonic-gate if (pip) { 36137c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = priv; 36147c478bd9Sstevel@tonic-gate } 36157c478bd9Sstevel@tonic-gate } 36167c478bd9Sstevel@tonic-gate 36177c478bd9Sstevel@tonic-gate /* 36187c478bd9Sstevel@tonic-gate * mdi_pi_get_phci_private(): 36197c478bd9Sstevel@tonic-gate * Get the pHCI private information associated with the 36207c478bd9Sstevel@tonic-gate * mdi_pathinfo node 36217c478bd9Sstevel@tonic-gate */ 36227c478bd9Sstevel@tonic-gate caddr_t 36237c478bd9Sstevel@tonic-gate mdi_pi_get_phci_private(mdi_pathinfo_t *pip) 36247c478bd9Sstevel@tonic-gate { 36257c478bd9Sstevel@tonic-gate caddr_t pprivate = NULL; 36267c478bd9Sstevel@tonic-gate if (pip) { 36277c478bd9Sstevel@tonic-gate pprivate = MDI_PI(pip)->pi_pprivate; 36287c478bd9Sstevel@tonic-gate } 36297c478bd9Sstevel@tonic-gate return (pprivate); 36307c478bd9Sstevel@tonic-gate } 36317c478bd9Sstevel@tonic-gate 36327c478bd9Sstevel@tonic-gate /* 36337c478bd9Sstevel@tonic-gate * mdi_pi_set_phci_private(): 36347c478bd9Sstevel@tonic-gate * Set the pHCI private information in the mdi_pathinfo node 36357c478bd9Sstevel@tonic-gate */ 36367c478bd9Sstevel@tonic-gate void 36377c478bd9Sstevel@tonic-gate mdi_pi_set_phci_private(mdi_pathinfo_t *pip, caddr_t priv) 36387c478bd9Sstevel@tonic-gate { 36397c478bd9Sstevel@tonic-gate if (pip) { 36407c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = priv; 36417c478bd9Sstevel@tonic-gate } 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate /* 36457c478bd9Sstevel@tonic-gate * mdi_pi_get_state(): 36467c478bd9Sstevel@tonic-gate * Get the mdi_pathinfo node state. Transient states are internal 36477c478bd9Sstevel@tonic-gate * and not provided to the users 36487c478bd9Sstevel@tonic-gate */ 36497c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t 36507c478bd9Sstevel@tonic-gate mdi_pi_get_state(mdi_pathinfo_t *pip) 36517c478bd9Sstevel@tonic-gate { 36527c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t state = MDI_PATHINFO_STATE_INIT; 36537c478bd9Sstevel@tonic-gate 36547c478bd9Sstevel@tonic-gate if (pip) { 36557c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 36567c478bd9Sstevel@tonic-gate /* 36577c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 36587c478bd9Sstevel@tonic-gate * last good state. 36597c478bd9Sstevel@tonic-gate */ 36607c478bd9Sstevel@tonic-gate state = MDI_PI_OLD_STATE(pip); 36617c478bd9Sstevel@tonic-gate } else { 36627c478bd9Sstevel@tonic-gate state = MDI_PI_STATE(pip); 36637c478bd9Sstevel@tonic-gate } 36647c478bd9Sstevel@tonic-gate } 36657c478bd9Sstevel@tonic-gate return (state); 36667c478bd9Sstevel@tonic-gate } 36677c478bd9Sstevel@tonic-gate 36687c478bd9Sstevel@tonic-gate /* 36697c478bd9Sstevel@tonic-gate * Note that the following function needs to be the new interface for 36707c478bd9Sstevel@tonic-gate * mdi_pi_get_state when mpxio gets integrated to ON. 36717c478bd9Sstevel@tonic-gate */ 36727c478bd9Sstevel@tonic-gate int 36737c478bd9Sstevel@tonic-gate mdi_pi_get_state2(mdi_pathinfo_t *pip, mdi_pathinfo_state_t *state, 36747c478bd9Sstevel@tonic-gate uint32_t *ext_state) 36757c478bd9Sstevel@tonic-gate { 36767c478bd9Sstevel@tonic-gate *state = MDI_PATHINFO_STATE_INIT; 36777c478bd9Sstevel@tonic-gate 36787c478bd9Sstevel@tonic-gate if (pip) { 36797c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 36807c478bd9Sstevel@tonic-gate /* 36817c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 36827c478bd9Sstevel@tonic-gate * last good state. 36837c478bd9Sstevel@tonic-gate */ 36847c478bd9Sstevel@tonic-gate *state = MDI_PI_OLD_STATE(pip); 36857c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_OLD_EXT_STATE(pip); 36867c478bd9Sstevel@tonic-gate } else { 36877c478bd9Sstevel@tonic-gate *state = MDI_PI_STATE(pip); 36887c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_EXT_STATE(pip); 36897c478bd9Sstevel@tonic-gate } 36907c478bd9Sstevel@tonic-gate } 36917c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 36927c478bd9Sstevel@tonic-gate } 36937c478bd9Sstevel@tonic-gate 36947c478bd9Sstevel@tonic-gate /* 36957c478bd9Sstevel@tonic-gate * mdi_pi_get_preferred: 36967c478bd9Sstevel@tonic-gate * Get the preferred path flag 36977c478bd9Sstevel@tonic-gate */ 36987c478bd9Sstevel@tonic-gate int 36997c478bd9Sstevel@tonic-gate mdi_pi_get_preferred(mdi_pathinfo_t *pip) 37007c478bd9Sstevel@tonic-gate { 37017c478bd9Sstevel@tonic-gate if (pip) { 37027c478bd9Sstevel@tonic-gate return (MDI_PI(pip)->pi_preferred); 37037c478bd9Sstevel@tonic-gate } 37047c478bd9Sstevel@tonic-gate return (0); 37057c478bd9Sstevel@tonic-gate } 37067c478bd9Sstevel@tonic-gate 37077c478bd9Sstevel@tonic-gate /* 37087c478bd9Sstevel@tonic-gate * mdi_pi_set_preferred: 37097c478bd9Sstevel@tonic-gate * Set the preferred path flag 37107c478bd9Sstevel@tonic-gate */ 37117c478bd9Sstevel@tonic-gate void 37127c478bd9Sstevel@tonic-gate mdi_pi_set_preferred(mdi_pathinfo_t *pip, int preferred) 37137c478bd9Sstevel@tonic-gate { 37147c478bd9Sstevel@tonic-gate if (pip) { 37157c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = preferred; 37167c478bd9Sstevel@tonic-gate } 37177c478bd9Sstevel@tonic-gate } 37187c478bd9Sstevel@tonic-gate 37197c478bd9Sstevel@tonic-gate 37207c478bd9Sstevel@tonic-gate /* 37217c478bd9Sstevel@tonic-gate * mdi_pi_set_state(): 37227c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state 37237c478bd9Sstevel@tonic-gate */ 37247c478bd9Sstevel@tonic-gate void 37257c478bd9Sstevel@tonic-gate mdi_pi_set_state(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state) 37267c478bd9Sstevel@tonic-gate { 37277c478bd9Sstevel@tonic-gate uint32_t ext_state; 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate if (pip) { 37307c478bd9Sstevel@tonic-gate ext_state = MDI_PI(pip)->pi_state & MDI_PATHINFO_EXT_STATE_MASK; 37317c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = state; 37327c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state |= ext_state; 37337c478bd9Sstevel@tonic-gate } 37347c478bd9Sstevel@tonic-gate } 37357c478bd9Sstevel@tonic-gate 37367c478bd9Sstevel@tonic-gate /* 37377c478bd9Sstevel@tonic-gate * Property functions: 37387c478bd9Sstevel@tonic-gate */ 37397c478bd9Sstevel@tonic-gate 37407c478bd9Sstevel@tonic-gate int 37417c478bd9Sstevel@tonic-gate i_map_nvlist_error_to_mdi(int val) 37427c478bd9Sstevel@tonic-gate { 37437c478bd9Sstevel@tonic-gate int rv; 37447c478bd9Sstevel@tonic-gate 37457c478bd9Sstevel@tonic-gate switch (val) { 37467c478bd9Sstevel@tonic-gate case 0: 37477c478bd9Sstevel@tonic-gate rv = DDI_PROP_SUCCESS; 37487c478bd9Sstevel@tonic-gate break; 37497c478bd9Sstevel@tonic-gate case EINVAL: 37507c478bd9Sstevel@tonic-gate case ENOTSUP: 37517c478bd9Sstevel@tonic-gate rv = DDI_PROP_INVAL_ARG; 37527c478bd9Sstevel@tonic-gate break; 37537c478bd9Sstevel@tonic-gate case ENOMEM: 37547c478bd9Sstevel@tonic-gate rv = DDI_PROP_NO_MEMORY; 37557c478bd9Sstevel@tonic-gate break; 37567c478bd9Sstevel@tonic-gate default: 37577c478bd9Sstevel@tonic-gate rv = DDI_PROP_NOT_FOUND; 37587c478bd9Sstevel@tonic-gate break; 37597c478bd9Sstevel@tonic-gate } 37607c478bd9Sstevel@tonic-gate return (rv); 37617c478bd9Sstevel@tonic-gate } 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate /* 37647c478bd9Sstevel@tonic-gate * mdi_pi_get_next_prop(): 37657c478bd9Sstevel@tonic-gate * Property walk function. The caller should hold mdi_pi_lock() 37667c478bd9Sstevel@tonic-gate * and release by calling mdi_pi_unlock() at the end of walk to 37677c478bd9Sstevel@tonic-gate * get a consistent value. 37687c478bd9Sstevel@tonic-gate */ 37697c478bd9Sstevel@tonic-gate 37707c478bd9Sstevel@tonic-gate nvpair_t * 37717c478bd9Sstevel@tonic-gate mdi_pi_get_next_prop(mdi_pathinfo_t *pip, nvpair_t *prev) 37727c478bd9Sstevel@tonic-gate { 37737c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 37747c478bd9Sstevel@tonic-gate return (NULL); 37757c478bd9Sstevel@tonic-gate } 37767c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 37777c478bd9Sstevel@tonic-gate return (nvlist_next_nvpair(MDI_PI(pip)->pi_prop, prev)); 37787c478bd9Sstevel@tonic-gate } 37797c478bd9Sstevel@tonic-gate 37807c478bd9Sstevel@tonic-gate /* 37817c478bd9Sstevel@tonic-gate * mdi_prop_remove(): 37827c478bd9Sstevel@tonic-gate * Remove the named property from the named list. 37837c478bd9Sstevel@tonic-gate */ 37847c478bd9Sstevel@tonic-gate 37857c478bd9Sstevel@tonic-gate int 37867c478bd9Sstevel@tonic-gate mdi_prop_remove(mdi_pathinfo_t *pip, char *name) 37877c478bd9Sstevel@tonic-gate { 37887c478bd9Sstevel@tonic-gate if (pip == NULL) { 37897c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 37907c478bd9Sstevel@tonic-gate } 37917c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 37927c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 37937c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 37947c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 37957c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 37967c478bd9Sstevel@tonic-gate } 37977c478bd9Sstevel@tonic-gate if (name) { 37987c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, name); 37997c478bd9Sstevel@tonic-gate } else { 38007c478bd9Sstevel@tonic-gate char nvp_name[MAXNAMELEN]; 38017c478bd9Sstevel@tonic-gate nvpair_t *nvp; 38027c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, NULL); 38037c478bd9Sstevel@tonic-gate while (nvp) { 38047c478bd9Sstevel@tonic-gate nvpair_t *next; 38057c478bd9Sstevel@tonic-gate next = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, nvp); 38067c478bd9Sstevel@tonic-gate (void) snprintf(nvp_name, MAXNAMELEN, "%s", 38077c478bd9Sstevel@tonic-gate nvpair_name(nvp)); 38087c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, 38097c478bd9Sstevel@tonic-gate nvp_name); 38107c478bd9Sstevel@tonic-gate nvp = next; 38117c478bd9Sstevel@tonic-gate } 38127c478bd9Sstevel@tonic-gate } 38137c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38147c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 38157c478bd9Sstevel@tonic-gate } 38167c478bd9Sstevel@tonic-gate 38177c478bd9Sstevel@tonic-gate /* 38187c478bd9Sstevel@tonic-gate * mdi_prop_size(): 38197c478bd9Sstevel@tonic-gate * Get buffer size needed to pack the property data. 38207c478bd9Sstevel@tonic-gate * Caller should hold the mdi_pathinfo_t lock to get a consistent 38217c478bd9Sstevel@tonic-gate * buffer size. 38227c478bd9Sstevel@tonic-gate */ 38237c478bd9Sstevel@tonic-gate 38247c478bd9Sstevel@tonic-gate int 38257c478bd9Sstevel@tonic-gate mdi_prop_size(mdi_pathinfo_t *pip, size_t *buflenp) 38267c478bd9Sstevel@tonic-gate { 38277c478bd9Sstevel@tonic-gate int rv; 38287c478bd9Sstevel@tonic-gate size_t bufsize; 38297c478bd9Sstevel@tonic-gate 38307c478bd9Sstevel@tonic-gate *buflenp = 0; 38317c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 38327c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38337c478bd9Sstevel@tonic-gate } 38347c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38357c478bd9Sstevel@tonic-gate rv = nvlist_size(MDI_PI(pip)->pi_prop, 38367c478bd9Sstevel@tonic-gate &bufsize, NV_ENCODE_NATIVE); 38377c478bd9Sstevel@tonic-gate *buflenp = bufsize; 38387c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 38397c478bd9Sstevel@tonic-gate } 38407c478bd9Sstevel@tonic-gate 38417c478bd9Sstevel@tonic-gate /* 38427c478bd9Sstevel@tonic-gate * mdi_prop_pack(): 38437c478bd9Sstevel@tonic-gate * pack the property list. The caller should hold the 38447c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node to get a consistent data 38457c478bd9Sstevel@tonic-gate */ 38467c478bd9Sstevel@tonic-gate 38477c478bd9Sstevel@tonic-gate int 38487c478bd9Sstevel@tonic-gate mdi_prop_pack(mdi_pathinfo_t *pip, char **bufp, uint_t buflen) 38497c478bd9Sstevel@tonic-gate { 38507c478bd9Sstevel@tonic-gate int rv; 38517c478bd9Sstevel@tonic-gate size_t bufsize; 38527c478bd9Sstevel@tonic-gate 38537c478bd9Sstevel@tonic-gate if ((pip == NULL) || MDI_PI(pip)->pi_prop == NULL) { 38547c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38557c478bd9Sstevel@tonic-gate } 38567c478bd9Sstevel@tonic-gate 38577c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38587c478bd9Sstevel@tonic-gate 38597c478bd9Sstevel@tonic-gate bufsize = buflen; 38607c478bd9Sstevel@tonic-gate rv = nvlist_pack(MDI_PI(pip)->pi_prop, bufp, (size_t *)&bufsize, 38617c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE, KM_SLEEP); 38627c478bd9Sstevel@tonic-gate 38637c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 38647c478bd9Sstevel@tonic-gate } 38657c478bd9Sstevel@tonic-gate 38667c478bd9Sstevel@tonic-gate /* 38677c478bd9Sstevel@tonic-gate * mdi_prop_update_byte(): 38687c478bd9Sstevel@tonic-gate * Create/Update a byte property 38697c478bd9Sstevel@tonic-gate */ 38707c478bd9Sstevel@tonic-gate int 38717c478bd9Sstevel@tonic-gate mdi_prop_update_byte(mdi_pathinfo_t *pip, char *name, uchar_t data) 38727c478bd9Sstevel@tonic-gate { 38737c478bd9Sstevel@tonic-gate int rv; 38747c478bd9Sstevel@tonic-gate 38757c478bd9Sstevel@tonic-gate if (pip == NULL) { 38767c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 38777c478bd9Sstevel@tonic-gate } 38787c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38797c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 38807c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 38817c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38827c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38837c478bd9Sstevel@tonic-gate } 38847c478bd9Sstevel@tonic-gate rv = nvlist_add_byte(MDI_PI(pip)->pi_prop, name, data); 38857c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38867c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 38877c478bd9Sstevel@tonic-gate } 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate /* 38907c478bd9Sstevel@tonic-gate * mdi_prop_update_byte_array(): 38917c478bd9Sstevel@tonic-gate * Create/Update a byte array property 38927c478bd9Sstevel@tonic-gate */ 38937c478bd9Sstevel@tonic-gate int 38947c478bd9Sstevel@tonic-gate mdi_prop_update_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t *data, 38957c478bd9Sstevel@tonic-gate uint_t nelements) 38967c478bd9Sstevel@tonic-gate { 38977c478bd9Sstevel@tonic-gate int rv; 38987c478bd9Sstevel@tonic-gate 38997c478bd9Sstevel@tonic-gate if (pip == NULL) { 39007c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39017c478bd9Sstevel@tonic-gate } 39027c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39037c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39047c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39057c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39067c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39077c478bd9Sstevel@tonic-gate } 39087c478bd9Sstevel@tonic-gate rv = nvlist_add_byte_array(MDI_PI(pip)->pi_prop, name, data, nelements); 39097c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39107c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39117c478bd9Sstevel@tonic-gate } 39127c478bd9Sstevel@tonic-gate 39137c478bd9Sstevel@tonic-gate /* 39147c478bd9Sstevel@tonic-gate * mdi_prop_update_int(): 39157c478bd9Sstevel@tonic-gate * Create/Update a 32 bit integer property 39167c478bd9Sstevel@tonic-gate */ 39177c478bd9Sstevel@tonic-gate int 39187c478bd9Sstevel@tonic-gate mdi_prop_update_int(mdi_pathinfo_t *pip, char *name, int data) 39197c478bd9Sstevel@tonic-gate { 39207c478bd9Sstevel@tonic-gate int rv; 39217c478bd9Sstevel@tonic-gate 39227c478bd9Sstevel@tonic-gate if (pip == NULL) { 39237c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39247c478bd9Sstevel@tonic-gate } 39257c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39267c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39277c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39287c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39297c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39307c478bd9Sstevel@tonic-gate } 39317c478bd9Sstevel@tonic-gate rv = nvlist_add_int32(MDI_PI(pip)->pi_prop, name, (int32_t)data); 39327c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39337c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39347c478bd9Sstevel@tonic-gate } 39357c478bd9Sstevel@tonic-gate 39367c478bd9Sstevel@tonic-gate /* 39377c478bd9Sstevel@tonic-gate * mdi_prop_update_int64(): 39387c478bd9Sstevel@tonic-gate * Create/Update a 64 bit integer property 39397c478bd9Sstevel@tonic-gate */ 39407c478bd9Sstevel@tonic-gate int 39417c478bd9Sstevel@tonic-gate mdi_prop_update_int64(mdi_pathinfo_t *pip, char *name, int64_t data) 39427c478bd9Sstevel@tonic-gate { 39437c478bd9Sstevel@tonic-gate int rv; 39447c478bd9Sstevel@tonic-gate 39457c478bd9Sstevel@tonic-gate if (pip == NULL) { 39467c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39477c478bd9Sstevel@tonic-gate } 39487c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39497c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39507c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39517c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39527c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39537c478bd9Sstevel@tonic-gate } 39547c478bd9Sstevel@tonic-gate rv = nvlist_add_int64(MDI_PI(pip)->pi_prop, name, data); 39557c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39567c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39577c478bd9Sstevel@tonic-gate } 39587c478bd9Sstevel@tonic-gate 39597c478bd9Sstevel@tonic-gate /* 39607c478bd9Sstevel@tonic-gate * mdi_prop_update_int_array(): 39617c478bd9Sstevel@tonic-gate * Create/Update a int array property 39627c478bd9Sstevel@tonic-gate */ 39637c478bd9Sstevel@tonic-gate int 39647c478bd9Sstevel@tonic-gate mdi_prop_update_int_array(mdi_pathinfo_t *pip, char *name, int *data, 39657c478bd9Sstevel@tonic-gate uint_t nelements) 39667c478bd9Sstevel@tonic-gate { 39677c478bd9Sstevel@tonic-gate int rv; 39687c478bd9Sstevel@tonic-gate 39697c478bd9Sstevel@tonic-gate if (pip == NULL) { 39707c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39717c478bd9Sstevel@tonic-gate } 39727c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39737c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39747c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39757c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39767c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39777c478bd9Sstevel@tonic-gate } 39787c478bd9Sstevel@tonic-gate rv = nvlist_add_int32_array(MDI_PI(pip)->pi_prop, name, (int32_t *)data, 39797c478bd9Sstevel@tonic-gate nelements); 39807c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39817c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39827c478bd9Sstevel@tonic-gate } 39837c478bd9Sstevel@tonic-gate 39847c478bd9Sstevel@tonic-gate /* 39857c478bd9Sstevel@tonic-gate * mdi_prop_update_string(): 39867c478bd9Sstevel@tonic-gate * Create/Update a string property 39877c478bd9Sstevel@tonic-gate */ 39887c478bd9Sstevel@tonic-gate int 39897c478bd9Sstevel@tonic-gate mdi_prop_update_string(mdi_pathinfo_t *pip, char *name, char *data) 39907c478bd9Sstevel@tonic-gate { 39917c478bd9Sstevel@tonic-gate int rv; 39927c478bd9Sstevel@tonic-gate 39937c478bd9Sstevel@tonic-gate if (pip == NULL) { 39947c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39957c478bd9Sstevel@tonic-gate } 39967c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39977c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39987c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39997c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40007c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40017c478bd9Sstevel@tonic-gate } 40027c478bd9Sstevel@tonic-gate rv = nvlist_add_string(MDI_PI(pip)->pi_prop, name, data); 40037c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40047c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40057c478bd9Sstevel@tonic-gate } 40067c478bd9Sstevel@tonic-gate 40077c478bd9Sstevel@tonic-gate /* 40087c478bd9Sstevel@tonic-gate * mdi_prop_update_string_array(): 40097c478bd9Sstevel@tonic-gate * Create/Update a string array property 40107c478bd9Sstevel@tonic-gate */ 40117c478bd9Sstevel@tonic-gate int 40127c478bd9Sstevel@tonic-gate mdi_prop_update_string_array(mdi_pathinfo_t *pip, char *name, char **data, 40137c478bd9Sstevel@tonic-gate uint_t nelements) 40147c478bd9Sstevel@tonic-gate { 40157c478bd9Sstevel@tonic-gate int rv; 40167c478bd9Sstevel@tonic-gate 40177c478bd9Sstevel@tonic-gate if (pip == NULL) { 40187c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 40197c478bd9Sstevel@tonic-gate } 40207c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 40217c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 40227c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 40237c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40247c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40257c478bd9Sstevel@tonic-gate } 40267c478bd9Sstevel@tonic-gate rv = nvlist_add_string_array(MDI_PI(pip)->pi_prop, name, data, 40277c478bd9Sstevel@tonic-gate nelements); 40287c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40297c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40307c478bd9Sstevel@tonic-gate } 40317c478bd9Sstevel@tonic-gate 40327c478bd9Sstevel@tonic-gate /* 40337c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte(): 40347c478bd9Sstevel@tonic-gate * Look for byte property identified by name. The data returned 40357c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 40367c478bd9Sstevel@tonic-gate * is alive. 40377c478bd9Sstevel@tonic-gate */ 40387c478bd9Sstevel@tonic-gate int 40397c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte(mdi_pathinfo_t *pip, char *name, uchar_t *data) 40407c478bd9Sstevel@tonic-gate { 40417c478bd9Sstevel@tonic-gate int rv; 40427c478bd9Sstevel@tonic-gate 40437c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 40447c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40457c478bd9Sstevel@tonic-gate } 40467c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte(MDI_PI(pip)->pi_prop, name, data); 40477c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40487c478bd9Sstevel@tonic-gate } 40497c478bd9Sstevel@tonic-gate 40507c478bd9Sstevel@tonic-gate 40517c478bd9Sstevel@tonic-gate /* 40527c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte_array(): 40537c478bd9Sstevel@tonic-gate * Look for byte array property identified by name. The data 40547c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 40557c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 40567c478bd9Sstevel@tonic-gate */ 40577c478bd9Sstevel@tonic-gate int 40587c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t **data, 40597c478bd9Sstevel@tonic-gate uint_t *nelements) 40607c478bd9Sstevel@tonic-gate { 40617c478bd9Sstevel@tonic-gate int rv; 40627c478bd9Sstevel@tonic-gate 40637c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 40647c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40657c478bd9Sstevel@tonic-gate } 40667c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte_array(MDI_PI(pip)->pi_prop, name, data, 40677c478bd9Sstevel@tonic-gate nelements); 40687c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40697c478bd9Sstevel@tonic-gate } 40707c478bd9Sstevel@tonic-gate 40717c478bd9Sstevel@tonic-gate /* 40727c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int(): 40737c478bd9Sstevel@tonic-gate * Look for int property identified by name. The data returned 40747c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t 40757c478bd9Sstevel@tonic-gate * node is alive. 40767c478bd9Sstevel@tonic-gate */ 40777c478bd9Sstevel@tonic-gate int 40787c478bd9Sstevel@tonic-gate mdi_prop_lookup_int(mdi_pathinfo_t *pip, char *name, int *data) 40797c478bd9Sstevel@tonic-gate { 40807c478bd9Sstevel@tonic-gate int rv; 40817c478bd9Sstevel@tonic-gate 40827c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 40837c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40847c478bd9Sstevel@tonic-gate } 40857c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32(MDI_PI(pip)->pi_prop, name, (int32_t *)data); 40867c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40877c478bd9Sstevel@tonic-gate } 40887c478bd9Sstevel@tonic-gate 40897c478bd9Sstevel@tonic-gate /* 40907c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int64(): 40917c478bd9Sstevel@tonic-gate * Look for int64 property identified by name. The data returned 40927c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 40937c478bd9Sstevel@tonic-gate * is alive. 40947c478bd9Sstevel@tonic-gate */ 40957c478bd9Sstevel@tonic-gate int 40967c478bd9Sstevel@tonic-gate mdi_prop_lookup_int64(mdi_pathinfo_t *pip, char *name, int64_t *data) 40977c478bd9Sstevel@tonic-gate { 40987c478bd9Sstevel@tonic-gate int rv; 40997c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41007c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41017c478bd9Sstevel@tonic-gate } 41027c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int64(MDI_PI(pip)->pi_prop, name, data); 41037c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41047c478bd9Sstevel@tonic-gate } 41057c478bd9Sstevel@tonic-gate 41067c478bd9Sstevel@tonic-gate /* 41077c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int_array(): 41087c478bd9Sstevel@tonic-gate * Look for int array property identified by name. The data 41097c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 41107c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 41117c478bd9Sstevel@tonic-gate */ 41127c478bd9Sstevel@tonic-gate int 41137c478bd9Sstevel@tonic-gate mdi_prop_lookup_int_array(mdi_pathinfo_t *pip, char *name, int **data, 41147c478bd9Sstevel@tonic-gate uint_t *nelements) 41157c478bd9Sstevel@tonic-gate { 41167c478bd9Sstevel@tonic-gate int rv; 41177c478bd9Sstevel@tonic-gate 41187c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41197c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41207c478bd9Sstevel@tonic-gate } 41217c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32_array(MDI_PI(pip)->pi_prop, name, 41227c478bd9Sstevel@tonic-gate (int32_t **)data, nelements); 41237c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41247c478bd9Sstevel@tonic-gate } 41257c478bd9Sstevel@tonic-gate 41267c478bd9Sstevel@tonic-gate /* 41277c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string(): 41287c478bd9Sstevel@tonic-gate * Look for string property identified by name. The data 41297c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 41307c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 41317c478bd9Sstevel@tonic-gate */ 41327c478bd9Sstevel@tonic-gate int 41337c478bd9Sstevel@tonic-gate mdi_prop_lookup_string(mdi_pathinfo_t *pip, char *name, char **data) 41347c478bd9Sstevel@tonic-gate { 41357c478bd9Sstevel@tonic-gate int rv; 41367c478bd9Sstevel@tonic-gate 41377c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41387c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41397c478bd9Sstevel@tonic-gate } 41407c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string(MDI_PI(pip)->pi_prop, name, data); 41417c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41427c478bd9Sstevel@tonic-gate } 41437c478bd9Sstevel@tonic-gate 41447c478bd9Sstevel@tonic-gate /* 41457c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string_array(): 41467c478bd9Sstevel@tonic-gate * Look for string array property identified by name. The data 41477c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 41487c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 41497c478bd9Sstevel@tonic-gate */ 41507c478bd9Sstevel@tonic-gate 41517c478bd9Sstevel@tonic-gate int 41527c478bd9Sstevel@tonic-gate mdi_prop_lookup_string_array(mdi_pathinfo_t *pip, char *name, char ***data, 41537c478bd9Sstevel@tonic-gate uint_t *nelements) 41547c478bd9Sstevel@tonic-gate { 41557c478bd9Sstevel@tonic-gate int rv; 41567c478bd9Sstevel@tonic-gate 41577c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41587c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41597c478bd9Sstevel@tonic-gate } 41607c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string_array(MDI_PI(pip)->pi_prop, name, data, 41617c478bd9Sstevel@tonic-gate nelements); 41627c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41637c478bd9Sstevel@tonic-gate } 41647c478bd9Sstevel@tonic-gate 41657c478bd9Sstevel@tonic-gate /* 41667c478bd9Sstevel@tonic-gate * mdi_prop_free(): 41677c478bd9Sstevel@tonic-gate * Symmetrical function to ddi_prop_free(). nvlist_lookup_xx() 41687c478bd9Sstevel@tonic-gate * functions return the pointer to actual property data and not a 41697c478bd9Sstevel@tonic-gate * copy of it. So the data returned is valid as long as 41707c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is valid. 41717c478bd9Sstevel@tonic-gate */ 41727c478bd9Sstevel@tonic-gate 41737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41747c478bd9Sstevel@tonic-gate int 41757c478bd9Sstevel@tonic-gate mdi_prop_free(void *data) 41767c478bd9Sstevel@tonic-gate { 41777c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 41787c478bd9Sstevel@tonic-gate } 41797c478bd9Sstevel@tonic-gate 41807c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41817c478bd9Sstevel@tonic-gate static void 41827c478bd9Sstevel@tonic-gate i_mdi_report_path_state(mdi_client_t *ct, mdi_pathinfo_t *pip) 41837c478bd9Sstevel@tonic-gate { 41847c478bd9Sstevel@tonic-gate char *phci_path, *ct_path; 41857c478bd9Sstevel@tonic-gate char *ct_status; 41867c478bd9Sstevel@tonic-gate char *status; 41877c478bd9Sstevel@tonic-gate dev_info_t *dip = ct->ct_dip; 41887c478bd9Sstevel@tonic-gate char lb_buf[64]; 41897c478bd9Sstevel@tonic-gate 41907c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_mutex)); 41917c478bd9Sstevel@tonic-gate if ((dip == NULL) || (ddi_get_instance(dip) == -1) || 41927c478bd9Sstevel@tonic-gate (MDI_CLIENT_IS_REPORT_DEV_NEEDED(ct) == 0)) { 41937c478bd9Sstevel@tonic-gate return; 41947c478bd9Sstevel@tonic-gate } 41957c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL) { 41967c478bd9Sstevel@tonic-gate ct_status = "optimal"; 41977c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) { 41987c478bd9Sstevel@tonic-gate ct_status = "degraded"; 41997c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 42007c478bd9Sstevel@tonic-gate ct_status = "failed"; 42017c478bd9Sstevel@tonic-gate } else { 42027c478bd9Sstevel@tonic-gate ct_status = "unknown"; 42037c478bd9Sstevel@tonic-gate } 42047c478bd9Sstevel@tonic-gate 42057c478bd9Sstevel@tonic-gate if (MDI_PI_IS_OFFLINE(pip)) { 42067c478bd9Sstevel@tonic-gate status = "offline"; 42077c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_ONLINE(pip)) { 42087c478bd9Sstevel@tonic-gate status = "online"; 42097c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_STANDBY(pip)) { 42107c478bd9Sstevel@tonic-gate status = "standby"; 42117c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_FAULT(pip)) { 42127c478bd9Sstevel@tonic-gate status = "faulted"; 42137c478bd9Sstevel@tonic-gate } else { 42147c478bd9Sstevel@tonic-gate status = "unknown"; 42157c478bd9Sstevel@tonic-gate } 42167c478bd9Sstevel@tonic-gate 42177c478bd9Sstevel@tonic-gate if (ct->ct_lb == LOAD_BALANCE_LBA) { 42187c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 42197c478bd9Sstevel@tonic-gate "%s, region-size: %d", mdi_load_balance_lba, 42207c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size); 42217c478bd9Sstevel@tonic-gate } else if (ct->ct_lb == LOAD_BALANCE_NONE) { 42227c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 42237c478bd9Sstevel@tonic-gate "%s", mdi_load_balance_none); 42247c478bd9Sstevel@tonic-gate } else { 42257c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), "%s", 42267c478bd9Sstevel@tonic-gate mdi_load_balance_rr); 42277c478bd9Sstevel@tonic-gate } 42287c478bd9Sstevel@tonic-gate 42297c478bd9Sstevel@tonic-gate if (dip) { 42307c478bd9Sstevel@tonic-gate ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 42317c478bd9Sstevel@tonic-gate phci_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 42327c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s (%s%d) multipath status: %s, " 42337c478bd9Sstevel@tonic-gate "path %s (%s%d) to target address: %s is %s" 42347c478bd9Sstevel@tonic-gate " Load balancing: %s\n", 42357c478bd9Sstevel@tonic-gate ddi_pathname(dip, ct_path), ddi_driver_name(dip), 42367c478bd9Sstevel@tonic-gate ddi_get_instance(dip), ct_status, 42377c478bd9Sstevel@tonic-gate ddi_pathname(MDI_PI(pip)->pi_phci->ph_dip, phci_path), 42387c478bd9Sstevel@tonic-gate ddi_driver_name(MDI_PI(pip)->pi_phci->ph_dip), 42397c478bd9Sstevel@tonic-gate ddi_get_instance(MDI_PI(pip)->pi_phci->ph_dip), 42407c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr, status, lb_buf); 42417c478bd9Sstevel@tonic-gate kmem_free(phci_path, MAXPATHLEN); 42427c478bd9Sstevel@tonic-gate kmem_free(ct_path, MAXPATHLEN); 42437c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct); 42447c478bd9Sstevel@tonic-gate } 42457c478bd9Sstevel@tonic-gate } 42467c478bd9Sstevel@tonic-gate 42477c478bd9Sstevel@tonic-gate #ifdef DEBUG 42487c478bd9Sstevel@tonic-gate /* 42497c478bd9Sstevel@tonic-gate * i_mdi_log(): 42507c478bd9Sstevel@tonic-gate * Utility function for error message management 42517c478bd9Sstevel@tonic-gate * 42527c478bd9Sstevel@tonic-gate */ 42537c478bd9Sstevel@tonic-gate 42547c478bd9Sstevel@tonic-gate /*VARARGS3*/ 42557c478bd9Sstevel@tonic-gate static void 42567c478bd9Sstevel@tonic-gate i_mdi_log(int level, dev_info_t *dip, const char *fmt, ...) 42577c478bd9Sstevel@tonic-gate { 42587c478bd9Sstevel@tonic-gate char buf[MAXNAMELEN]; 42597c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 42607c478bd9Sstevel@tonic-gate va_list ap; 42617c478bd9Sstevel@tonic-gate int log_only = 0; 42627c478bd9Sstevel@tonic-gate int boot_only = 0; 42637c478bd9Sstevel@tonic-gate int console_only = 0; 42647c478bd9Sstevel@tonic-gate 42657c478bd9Sstevel@tonic-gate if (dip) { 42667c478bd9Sstevel@tonic-gate if (level == CE_PANIC || level == CE_WARN || level == CE_NOTE) { 42677c478bd9Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "%s%d:\n", 42687c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip)); 42697c478bd9Sstevel@tonic-gate } else { 42707c478bd9Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "%s%d:", 42717c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip)); 42727c478bd9Sstevel@tonic-gate } 42737c478bd9Sstevel@tonic-gate } else { 42747c478bd9Sstevel@tonic-gate name[0] = '\0'; 42757c478bd9Sstevel@tonic-gate } 42767c478bd9Sstevel@tonic-gate 42777c478bd9Sstevel@tonic-gate va_start(ap, fmt); 42787c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, MAXNAMELEN, fmt, ap); 42797c478bd9Sstevel@tonic-gate va_end(ap); 42807c478bd9Sstevel@tonic-gate 42817c478bd9Sstevel@tonic-gate switch (buf[0]) { 42827c478bd9Sstevel@tonic-gate case '!': 42837c478bd9Sstevel@tonic-gate log_only = 1; 42847c478bd9Sstevel@tonic-gate break; 42857c478bd9Sstevel@tonic-gate case '?': 42867c478bd9Sstevel@tonic-gate boot_only = 1; 42877c478bd9Sstevel@tonic-gate break; 42887c478bd9Sstevel@tonic-gate case '^': 42897c478bd9Sstevel@tonic-gate console_only = 1; 42907c478bd9Sstevel@tonic-gate break; 42917c478bd9Sstevel@tonic-gate } 42927c478bd9Sstevel@tonic-gate 42937c478bd9Sstevel@tonic-gate switch (level) { 42947c478bd9Sstevel@tonic-gate case CE_NOTE: 42957c478bd9Sstevel@tonic-gate level = CE_CONT; 42967c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 42977c478bd9Sstevel@tonic-gate case CE_CONT: 42987c478bd9Sstevel@tonic-gate case CE_WARN: 42997c478bd9Sstevel@tonic-gate case CE_PANIC: 43007c478bd9Sstevel@tonic-gate if (boot_only) { 43017c478bd9Sstevel@tonic-gate cmn_err(level, "?%s\t%s", name, &buf[1]); 43027c478bd9Sstevel@tonic-gate } else if (console_only) { 43037c478bd9Sstevel@tonic-gate cmn_err(level, "^%s\t%s", name, &buf[1]); 43047c478bd9Sstevel@tonic-gate } else if (log_only) { 43057c478bd9Sstevel@tonic-gate cmn_err(level, "!%s\t%s", name, &buf[1]); 43067c478bd9Sstevel@tonic-gate } else { 43077c478bd9Sstevel@tonic-gate cmn_err(level, "%s\t%s", name, buf); 43087c478bd9Sstevel@tonic-gate } 43097c478bd9Sstevel@tonic-gate break; 43107c478bd9Sstevel@tonic-gate default: 43117c478bd9Sstevel@tonic-gate cmn_err(level, "%s\t%s", name, buf); 43127c478bd9Sstevel@tonic-gate break; 43137c478bd9Sstevel@tonic-gate } 43147c478bd9Sstevel@tonic-gate } 43157c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 43167c478bd9Sstevel@tonic-gate 43177c478bd9Sstevel@tonic-gate void 43187c478bd9Sstevel@tonic-gate i_mdi_client_online(dev_info_t *ct_dip) 43197c478bd9Sstevel@tonic-gate { 43207c478bd9Sstevel@tonic-gate mdi_client_t *ct; 43217c478bd9Sstevel@tonic-gate 43227c478bd9Sstevel@tonic-gate /* 43237c478bd9Sstevel@tonic-gate * Client online notification. Mark client state as online 43247c478bd9Sstevel@tonic-gate * restore our binding with dev_info node 43257c478bd9Sstevel@tonic-gate */ 43267c478bd9Sstevel@tonic-gate ct = i_devi_get_client(ct_dip); 43277c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 43287c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 43297c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 43307c478bd9Sstevel@tonic-gate /* catch for any memory leaks */ 43317c478bd9Sstevel@tonic-gate ASSERT((ct->ct_dip == NULL) || (ct->ct_dip == ct_dip)); 43327c478bd9Sstevel@tonic-gate ct->ct_dip = ct_dip; 43337c478bd9Sstevel@tonic-gate 43347c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) 43357c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 43367c478bd9Sstevel@tonic-gate 43377c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct_dip, "i_mdi_client_online " 43387c478bd9Sstevel@tonic-gate "i_mdi_pm_hold_client\n")); 43397c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 43407c478bd9Sstevel@tonic-gate 43417c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 43427c478bd9Sstevel@tonic-gate } 43437c478bd9Sstevel@tonic-gate 43447c478bd9Sstevel@tonic-gate void 43457c478bd9Sstevel@tonic-gate i_mdi_phci_online(dev_info_t *ph_dip) 43467c478bd9Sstevel@tonic-gate { 43477c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 43487c478bd9Sstevel@tonic-gate 43497c478bd9Sstevel@tonic-gate /* pHCI online notification. Mark state accordingly */ 43507c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(ph_dip); 43517c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 43527c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 43537c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 43547c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 43557c478bd9Sstevel@tonic-gate } 43567c478bd9Sstevel@tonic-gate 43577c478bd9Sstevel@tonic-gate /* 43587c478bd9Sstevel@tonic-gate * mdi_devi_online(): 43597c478bd9Sstevel@tonic-gate * Online notification from NDI framework on pHCI/client 43607c478bd9Sstevel@tonic-gate * device online. 43617c478bd9Sstevel@tonic-gate * Return Values: 43627c478bd9Sstevel@tonic-gate * NDI_SUCCESS 43637c478bd9Sstevel@tonic-gate * MDI_FAILURE 43647c478bd9Sstevel@tonic-gate */ 43657c478bd9Sstevel@tonic-gate 43667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 43677c478bd9Sstevel@tonic-gate int 43687c478bd9Sstevel@tonic-gate mdi_devi_online(dev_info_t *dip, uint_t flags) 43697c478bd9Sstevel@tonic-gate { 43707c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 43717c478bd9Sstevel@tonic-gate i_mdi_phci_online(dip); 43727c478bd9Sstevel@tonic-gate } 43737c478bd9Sstevel@tonic-gate 43747c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 43757c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 43767c478bd9Sstevel@tonic-gate } 43777c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 43787c478bd9Sstevel@tonic-gate } 43797c478bd9Sstevel@tonic-gate 43807c478bd9Sstevel@tonic-gate /* 43817c478bd9Sstevel@tonic-gate * mdi_devi_offline(): 43827c478bd9Sstevel@tonic-gate * Offline notification from NDI framework on pHCI/Client device 43837c478bd9Sstevel@tonic-gate * offline. 43847c478bd9Sstevel@tonic-gate * 43857c478bd9Sstevel@tonic-gate * Return Values: 43867c478bd9Sstevel@tonic-gate * NDI_SUCCESS 43877c478bd9Sstevel@tonic-gate * NDI_FAILURE 43887c478bd9Sstevel@tonic-gate */ 43897c478bd9Sstevel@tonic-gate 43907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 43917c478bd9Sstevel@tonic-gate int 43927c478bd9Sstevel@tonic-gate mdi_devi_offline(dev_info_t *dip, uint_t flags) 43937c478bd9Sstevel@tonic-gate { 43947c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 43957c478bd9Sstevel@tonic-gate 43967c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 43977c478bd9Sstevel@tonic-gate rv = i_mdi_client_offline(dip, flags); 43987c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) 43997c478bd9Sstevel@tonic-gate return (rv); 44007c478bd9Sstevel@tonic-gate } 44017c478bd9Sstevel@tonic-gate 44027c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 44037c478bd9Sstevel@tonic-gate rv = i_mdi_phci_offline(dip, flags); 44047c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && MDI_CLIENT(dip)) { 44057c478bd9Sstevel@tonic-gate /* set client back online */ 44067c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 44077c478bd9Sstevel@tonic-gate } 44087c478bd9Sstevel@tonic-gate } 44097c478bd9Sstevel@tonic-gate 44107c478bd9Sstevel@tonic-gate return (rv); 44117c478bd9Sstevel@tonic-gate } 44127c478bd9Sstevel@tonic-gate 44137c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 44147c478bd9Sstevel@tonic-gate static int 44157c478bd9Sstevel@tonic-gate i_mdi_phci_offline(dev_info_t *dip, uint_t flags) 44167c478bd9Sstevel@tonic-gate { 44177c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 44187c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 44197c478bd9Sstevel@tonic-gate mdi_client_t *ct; 44207c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 44217c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 44227c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 44237c478bd9Sstevel@tonic-gate dev_info_t *cdip; 44247c478bd9Sstevel@tonic-gate 44257c478bd9Sstevel@tonic-gate /* 44267c478bd9Sstevel@tonic-gate * pHCI component offline notification 44277c478bd9Sstevel@tonic-gate * Make sure that this pHCI instance is free to be offlined. 44287c478bd9Sstevel@tonic-gate * If it is OK to proceed, Offline and remove all the child 44297c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes. This process automatically offlines 44307c478bd9Sstevel@tonic-gate * corresponding client devices, for which this pHCI provides 44317c478bd9Sstevel@tonic-gate * critical services. 44327c478bd9Sstevel@tonic-gate */ 44337c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, "!mdi_phci_offline called %p\n", 44347c478bd9Sstevel@tonic-gate dip)); 44357c478bd9Sstevel@tonic-gate 44367c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 44377c478bd9Sstevel@tonic-gate if (ph == NULL) { 44387c478bd9Sstevel@tonic-gate return (rv); 44397c478bd9Sstevel@tonic-gate } 44407c478bd9Sstevel@tonic-gate 44417c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 44427c478bd9Sstevel@tonic-gate 44437c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_OFFLINE(ph)) { 44447c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, "!pHCI %p already offlined", ph)); 44457c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44467c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 44477c478bd9Sstevel@tonic-gate } 44487c478bd9Sstevel@tonic-gate 44497c478bd9Sstevel@tonic-gate /* 44507c478bd9Sstevel@tonic-gate * Check to see if the pHCI can be offlined 44517c478bd9Sstevel@tonic-gate */ 44527c478bd9Sstevel@tonic-gate if (ph->ph_unstable) { 44537c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 44547c478bd9Sstevel@tonic-gate "!One or more target devices are in transient " 44557c478bd9Sstevel@tonic-gate "state. This device can not be removed at " 44567c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 44577c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44587c478bd9Sstevel@tonic-gate return (NDI_BUSY); 44597c478bd9Sstevel@tonic-gate } 44607c478bd9Sstevel@tonic-gate 44617c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 44627c478bd9Sstevel@tonic-gate while (pip != NULL) { 44637c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 44647c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 44657c478bd9Sstevel@tonic-gate /* 44667c478bd9Sstevel@tonic-gate * The mdi_pathinfo state is OK. Check the client state. 44677c478bd9Sstevel@tonic-gate * If failover in progress fail the pHCI from offlining 44687c478bd9Sstevel@tonic-gate */ 44697c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 44707c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 44717c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 44727c478bd9Sstevel@tonic-gate (ct->ct_unstable)) { 44737c478bd9Sstevel@tonic-gate /* 44747c478bd9Sstevel@tonic-gate * Failover is in progress, Fail the DR 44757c478bd9Sstevel@tonic-gate */ 44767c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 44777c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 44787c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 44797c478bd9Sstevel@tonic-gate "This device can not be removed at " 44807c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 44817c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44827c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 44837c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44847c478bd9Sstevel@tonic-gate return (NDI_BUSY); 44857c478bd9Sstevel@tonic-gate } 44867c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44877c478bd9Sstevel@tonic-gate 44887c478bd9Sstevel@tonic-gate /* 44897c478bd9Sstevel@tonic-gate * Check to see of we are removing the last path of this 44907c478bd9Sstevel@tonic-gate * client device... 44917c478bd9Sstevel@tonic-gate */ 44927c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 44937c478bd9Sstevel@tonic-gate if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 44947c478bd9Sstevel@tonic-gate (i_mdi_client_compute_state(ct, ph) == 44957c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_FAILED)) { 44967c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 44977c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44987c478bd9Sstevel@tonic-gate if (ndi_devi_offline(cdip, 0) != NDI_SUCCESS) { 44997c478bd9Sstevel@tonic-gate /* 45007c478bd9Sstevel@tonic-gate * ndi_devi_offline() failed. 45017c478bd9Sstevel@tonic-gate * This pHCI provides the critical path 45027c478bd9Sstevel@tonic-gate * to one or more client devices. 45037c478bd9Sstevel@tonic-gate * Return busy. 45047c478bd9Sstevel@tonic-gate */ 45057c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45067c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 45077c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 45087c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 45097c478bd9Sstevel@tonic-gate "This device can not be removed at " 45107c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 45117c478bd9Sstevel@tonic-gate failed_pip = pip; 45127c478bd9Sstevel@tonic-gate break; 45137c478bd9Sstevel@tonic-gate } else { 45147c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45157c478bd9Sstevel@tonic-gate pip = next; 45167c478bd9Sstevel@tonic-gate } 45177c478bd9Sstevel@tonic-gate } else { 45187c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45197c478bd9Sstevel@tonic-gate pip = next; 45207c478bd9Sstevel@tonic-gate } 45217c478bd9Sstevel@tonic-gate } 45227c478bd9Sstevel@tonic-gate 45237c478bd9Sstevel@tonic-gate if (failed_pip) { 45247c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 45257c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 45267c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45277c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 45287c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 45297c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 45307c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 45317c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 45327c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 45337c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 45347c478bd9Sstevel@tonic-gate if (cdip) { 45357c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45367c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45377c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45387c478bd9Sstevel@tonic-gate (void) ndi_devi_online(cdip, 0); 45397c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45407c478bd9Sstevel@tonic-gate pip = next; 45417c478bd9Sstevel@tonic-gate continue; 45427c478bd9Sstevel@tonic-gate } 45437c478bd9Sstevel@tonic-gate break; 45447c478bd9Sstevel@tonic-gate 45457c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 45467c478bd9Sstevel@tonic-gate if (cdip) { 45477c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45487c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45497c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45507c478bd9Sstevel@tonic-gate (void) ndi_devi_offline(cdip, 0); 45517c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45527c478bd9Sstevel@tonic-gate pip = next; 45537c478bd9Sstevel@tonic-gate continue; 45547c478bd9Sstevel@tonic-gate } 45557c478bd9Sstevel@tonic-gate break; 45567c478bd9Sstevel@tonic-gate } 45577c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45587c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45597c478bd9Sstevel@tonic-gate pip = next; 45607c478bd9Sstevel@tonic-gate } 45617c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45627c478bd9Sstevel@tonic-gate return (NDI_BUSY); 45637c478bd9Sstevel@tonic-gate } 45647c478bd9Sstevel@tonic-gate 45657c478bd9Sstevel@tonic-gate /* 45667c478bd9Sstevel@tonic-gate * Mark the pHCI as offline 45677c478bd9Sstevel@tonic-gate */ 45687c478bd9Sstevel@tonic-gate MDI_PHCI_SET_OFFLINE(ph); 45697c478bd9Sstevel@tonic-gate 45707c478bd9Sstevel@tonic-gate /* 45717c478bd9Sstevel@tonic-gate * Mark the child mdi_pathinfo nodes as transient 45727c478bd9Sstevel@tonic-gate */ 45737c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 45747c478bd9Sstevel@tonic-gate while (pip != NULL) { 45757c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45767c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 45777c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 45787c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45797c478bd9Sstevel@tonic-gate pip = next; 45807c478bd9Sstevel@tonic-gate } 45817c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45827c478bd9Sstevel@tonic-gate /* 45837c478bd9Sstevel@tonic-gate * Give a chance for any pending commands to execute 45847c478bd9Sstevel@tonic-gate */ 45857c478bd9Sstevel@tonic-gate delay(1); 45867c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45877c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 45887c478bd9Sstevel@tonic-gate while (pip != NULL) { 45897c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 45907c478bd9Sstevel@tonic-gate (void) i_mdi_pi_offline(pip, flags); 45917c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45927c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 45937c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_OFFLINE(pip)) { 45947c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 45957c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 45967c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 45977c478bd9Sstevel@tonic-gate "This device can not be removed at " 45987c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 45997c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46007c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 46017c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 46027c478bd9Sstevel@tonic-gate return (NDI_BUSY); 46037c478bd9Sstevel@tonic-gate } 46047c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46057c478bd9Sstevel@tonic-gate pip = next; 46067c478bd9Sstevel@tonic-gate } 46077c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 46087c478bd9Sstevel@tonic-gate 46097c478bd9Sstevel@tonic-gate return (rv); 46107c478bd9Sstevel@tonic-gate } 46117c478bd9Sstevel@tonic-gate 46127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 46137c478bd9Sstevel@tonic-gate static int 46147c478bd9Sstevel@tonic-gate i_mdi_client_offline(dev_info_t *dip, uint_t flags) 46157c478bd9Sstevel@tonic-gate { 46167c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 46177c478bd9Sstevel@tonic-gate mdi_client_t *ct; 46187c478bd9Sstevel@tonic-gate 46197c478bd9Sstevel@tonic-gate /* 46207c478bd9Sstevel@tonic-gate * Client component to go offline. Make sure that we are 46217c478bd9Sstevel@tonic-gate * not in failing over state and update client state 46227c478bd9Sstevel@tonic-gate * accordingly 46237c478bd9Sstevel@tonic-gate */ 46247c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, "!i_mdi_client_offline called %p\n", 46257c478bd9Sstevel@tonic-gate dip)); 46267c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 46277c478bd9Sstevel@tonic-gate if (ct != NULL) { 46287c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 46297c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 46307c478bd9Sstevel@tonic-gate /* 46317c478bd9Sstevel@tonic-gate * One or more paths are in transient state, 46327c478bd9Sstevel@tonic-gate * Dont allow offline of a client device 46337c478bd9Sstevel@tonic-gate */ 46347c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 46357c478bd9Sstevel@tonic-gate "!One or more paths to this device is " 46367c478bd9Sstevel@tonic-gate "in transient state. This device can not " 46377c478bd9Sstevel@tonic-gate "be removed at this moment. " 46387c478bd9Sstevel@tonic-gate "Please try again later.")); 46397c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 46407c478bd9Sstevel@tonic-gate return (NDI_BUSY); 46417c478bd9Sstevel@tonic-gate } 46427c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 46437c478bd9Sstevel@tonic-gate /* 46447c478bd9Sstevel@tonic-gate * Failover is in progress, Dont allow DR of 46457c478bd9Sstevel@tonic-gate * a client device 46467c478bd9Sstevel@tonic-gate */ 46477c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 46487c478bd9Sstevel@tonic-gate "!Client device (%s%d) is Busy. %s", 46497c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 46507c478bd9Sstevel@tonic-gate "This device can not be removed at " 46517c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 46527c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 46537c478bd9Sstevel@tonic-gate return (NDI_BUSY); 46547c478bd9Sstevel@tonic-gate } 46557c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 46567c478bd9Sstevel@tonic-gate 46577c478bd9Sstevel@tonic-gate /* 46587c478bd9Sstevel@tonic-gate * Unbind our relationship with the dev_info node 46597c478bd9Sstevel@tonic-gate */ 46607c478bd9Sstevel@tonic-gate if (flags & NDI_DEVI_REMOVE) { 46617c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 46627c478bd9Sstevel@tonic-gate } 46637c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 46647c478bd9Sstevel@tonic-gate } 46657c478bd9Sstevel@tonic-gate return (rv); 46667c478bd9Sstevel@tonic-gate } 46677c478bd9Sstevel@tonic-gate 46687c478bd9Sstevel@tonic-gate /* 46697c478bd9Sstevel@tonic-gate * mdi_pre_attach(): 46707c478bd9Sstevel@tonic-gate * Pre attach() notification handler 46717c478bd9Sstevel@tonic-gate */ 46727c478bd9Sstevel@tonic-gate 46737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 46747c478bd9Sstevel@tonic-gate int 46757c478bd9Sstevel@tonic-gate mdi_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 46767c478bd9Sstevel@tonic-gate { 46777c478bd9Sstevel@tonic-gate /* don't support old DDI_PM_RESUME */ 46787c478bd9Sstevel@tonic-gate if ((DEVI(dip)->devi_mdi_component != MDI_COMPONENT_NONE) && 46797c478bd9Sstevel@tonic-gate (cmd == DDI_PM_RESUME)) 46807c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 46817c478bd9Sstevel@tonic-gate 46827c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 46837c478bd9Sstevel@tonic-gate } 46847c478bd9Sstevel@tonic-gate 46857c478bd9Sstevel@tonic-gate /* 46867c478bd9Sstevel@tonic-gate * mdi_post_attach(): 46877c478bd9Sstevel@tonic-gate * Post attach() notification handler 46887c478bd9Sstevel@tonic-gate */ 46897c478bd9Sstevel@tonic-gate 46907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 46917c478bd9Sstevel@tonic-gate void 46927c478bd9Sstevel@tonic-gate mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error) 46937c478bd9Sstevel@tonic-gate { 46947c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 46957c478bd9Sstevel@tonic-gate mdi_client_t *ct; 46967c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 46977c478bd9Sstevel@tonic-gate 46987c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 46997c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 47007c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 47017c478bd9Sstevel@tonic-gate 47027c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 47037c478bd9Sstevel@tonic-gate switch (cmd) { 47047c478bd9Sstevel@tonic-gate case DDI_ATTACH: 47057c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 47067c478bd9Sstevel@tonic-gate "!pHCI post_attach: called %p\n", ph)); 47077c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 47087c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 47097c478bd9Sstevel@tonic-gate } else { 47107c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47117c478bd9Sstevel@tonic-gate "!pHCI post_attach: failed error=%d\n", 47127c478bd9Sstevel@tonic-gate error)); 47137c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 47147c478bd9Sstevel@tonic-gate } 47157c478bd9Sstevel@tonic-gate break; 47167c478bd9Sstevel@tonic-gate 47177c478bd9Sstevel@tonic-gate case DDI_RESUME: 47187c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 47197c478bd9Sstevel@tonic-gate "!pHCI post_resume: called %p\n", ph)); 47207c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 47217c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 47227c478bd9Sstevel@tonic-gate } else { 47237c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47247c478bd9Sstevel@tonic-gate "!pHCI post_resume: failed error=%d\n", 47257c478bd9Sstevel@tonic-gate error)); 47267c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 47277c478bd9Sstevel@tonic-gate } 47287c478bd9Sstevel@tonic-gate break; 47297c478bd9Sstevel@tonic-gate } 47307c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 47317c478bd9Sstevel@tonic-gate } 47327c478bd9Sstevel@tonic-gate 47337c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 47347c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 47357c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 47367c478bd9Sstevel@tonic-gate 47377c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 47387c478bd9Sstevel@tonic-gate switch (cmd) { 47397c478bd9Sstevel@tonic-gate case DDI_ATTACH: 47407c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 47417c478bd9Sstevel@tonic-gate "!Client post_attach: called %p\n", ct)); 47427c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) { 47437c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47447c478bd9Sstevel@tonic-gate "!Client post_attach: failed error=%d\n", 47457c478bd9Sstevel@tonic-gate error)); 47467c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 47477c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, dip, 47487c478bd9Sstevel@tonic-gate "mdi_post_attach i_mdi_pm_reset_client\n")); 47497c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 47507c478bd9Sstevel@tonic-gate break; 47517c478bd9Sstevel@tonic-gate } 47527c478bd9Sstevel@tonic-gate 47537c478bd9Sstevel@tonic-gate /* 47547c478bd9Sstevel@tonic-gate * Client device has successfully attached. 47557c478bd9Sstevel@tonic-gate * Create kstats for any pathinfo structures 47567c478bd9Sstevel@tonic-gate * initially associated with this client. 47577c478bd9Sstevel@tonic-gate */ 47587c478bd9Sstevel@tonic-gate for (pip = ct->ct_path_head; pip != NULL; 47597c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *) 47607c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link) { 47617c478bd9Sstevel@tonic-gate (void) i_mdi_pi_kstat_create(pip); 47627c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 47637c478bd9Sstevel@tonic-gate } 47647c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 47657c478bd9Sstevel@tonic-gate break; 47667c478bd9Sstevel@tonic-gate 47677c478bd9Sstevel@tonic-gate case DDI_RESUME: 47687c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 47697c478bd9Sstevel@tonic-gate "!Client post_attach: called %p\n", ct)); 47707c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 47717c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 47727c478bd9Sstevel@tonic-gate } else { 47737c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47747c478bd9Sstevel@tonic-gate "!Client post_resume: failed error=%d\n", 47757c478bd9Sstevel@tonic-gate error)); 47767c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 47777c478bd9Sstevel@tonic-gate } 47787c478bd9Sstevel@tonic-gate break; 47797c478bd9Sstevel@tonic-gate } 47807c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 47817c478bd9Sstevel@tonic-gate } 47827c478bd9Sstevel@tonic-gate } 47837c478bd9Sstevel@tonic-gate 47847c478bd9Sstevel@tonic-gate /* 47857c478bd9Sstevel@tonic-gate * mdi_pre_detach(): 47867c478bd9Sstevel@tonic-gate * Pre detach notification handler 47877c478bd9Sstevel@tonic-gate */ 47887c478bd9Sstevel@tonic-gate 47897c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47907c478bd9Sstevel@tonic-gate int 47917c478bd9Sstevel@tonic-gate mdi_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 47927c478bd9Sstevel@tonic-gate { 47937c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 47947c478bd9Sstevel@tonic-gate 47957c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 47967c478bd9Sstevel@tonic-gate (void) i_mdi_client_pre_detach(dip, cmd); 47977c478bd9Sstevel@tonic-gate } 47987c478bd9Sstevel@tonic-gate 47997c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 48007c478bd9Sstevel@tonic-gate rv = i_mdi_phci_pre_detach(dip, cmd); 48017c478bd9Sstevel@tonic-gate } 48027c478bd9Sstevel@tonic-gate 48037c478bd9Sstevel@tonic-gate return (rv); 48047c478bd9Sstevel@tonic-gate } 48057c478bd9Sstevel@tonic-gate 48067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 48077c478bd9Sstevel@tonic-gate static int 48087c478bd9Sstevel@tonic-gate i_mdi_phci_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 48097c478bd9Sstevel@tonic-gate { 48107c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 48117c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 48127c478bd9Sstevel@tonic-gate mdi_client_t *ct; 48137c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 48147c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 48157c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 48167c478bd9Sstevel@tonic-gate 48177c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 48187c478bd9Sstevel@tonic-gate if (ph == NULL) { 48197c478bd9Sstevel@tonic-gate return (rv); 48207c478bd9Sstevel@tonic-gate } 48217c478bd9Sstevel@tonic-gate 48227c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 48237c478bd9Sstevel@tonic-gate switch (cmd) { 48247c478bd9Sstevel@tonic-gate case DDI_DETACH: 48257c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 48267c478bd9Sstevel@tonic-gate "!pHCI pre_detach: called %p\n", ph)); 48277c478bd9Sstevel@tonic-gate if (!MDI_PHCI_IS_OFFLINE(ph)) { 48287c478bd9Sstevel@tonic-gate /* 48297c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes are still attached to 48307c478bd9Sstevel@tonic-gate * this pHCI. Fail the detach for this pHCI. 48317c478bd9Sstevel@tonic-gate */ 48327c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, dip, 48337c478bd9Sstevel@tonic-gate "!pHCI pre_detach: " 48347c478bd9Sstevel@tonic-gate "mdi_pathinfo nodes are still attached " 48357c478bd9Sstevel@tonic-gate "%p\n", ph)); 48367c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 48377c478bd9Sstevel@tonic-gate break; 48387c478bd9Sstevel@tonic-gate } 48397c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 48407c478bd9Sstevel@tonic-gate break; 48417c478bd9Sstevel@tonic-gate 48427c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 48437c478bd9Sstevel@tonic-gate /* 48447c478bd9Sstevel@tonic-gate * pHCI is getting suspended. Since mpxio client 48457c478bd9Sstevel@tonic-gate * devices may not be suspended at this point, to avoid 48467c478bd9Sstevel@tonic-gate * a potential stack overflow, it is important to suspend 48477c478bd9Sstevel@tonic-gate * client devices before pHCI can be suspended. 48487c478bd9Sstevel@tonic-gate */ 48497c478bd9Sstevel@tonic-gate 48507c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 48517c478bd9Sstevel@tonic-gate "!pHCI pre_suspend: called %p\n", ph)); 48527c478bd9Sstevel@tonic-gate /* 48537c478bd9Sstevel@tonic-gate * Suspend all the client devices accessible through this pHCI 48547c478bd9Sstevel@tonic-gate */ 48557c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 48567c478bd9Sstevel@tonic-gate while (pip != NULL && rv == DDI_SUCCESS) { 48577c478bd9Sstevel@tonic-gate dev_info_t *cdip; 48587c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 48597c478bd9Sstevel@tonic-gate next = 48607c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 48617c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 48627c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 48637c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 48647c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 48657c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct) == 0) && 48667c478bd9Sstevel@tonic-gate MDI_CLIENT_IS_SUSPENDED(ct) == 0) { 48677c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 48687c478bd9Sstevel@tonic-gate if ((rv = devi_detach(cdip, DDI_SUSPEND)) != 48697c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 48707c478bd9Sstevel@tonic-gate /* 48717c478bd9Sstevel@tonic-gate * Suspend of one of the client 48727c478bd9Sstevel@tonic-gate * device has failed. 48737c478bd9Sstevel@tonic-gate */ 48747c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 48757c478bd9Sstevel@tonic-gate "!Suspend of device (%s%d) failed.", 48767c478bd9Sstevel@tonic-gate ddi_driver_name(cdip), 48777c478bd9Sstevel@tonic-gate ddi_get_instance(cdip))); 48787c478bd9Sstevel@tonic-gate failed_pip = pip; 48797c478bd9Sstevel@tonic-gate break; 48807c478bd9Sstevel@tonic-gate } 48817c478bd9Sstevel@tonic-gate } else { 48827c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 48837c478bd9Sstevel@tonic-gate } 48847c478bd9Sstevel@tonic-gate pip = next; 48857c478bd9Sstevel@tonic-gate } 48867c478bd9Sstevel@tonic-gate 48877c478bd9Sstevel@tonic-gate if (rv == DDI_SUCCESS) { 48887c478bd9Sstevel@tonic-gate /* 48897c478bd9Sstevel@tonic-gate * Suspend of client devices is complete. Proceed 48907c478bd9Sstevel@tonic-gate * with pHCI suspend. 48917c478bd9Sstevel@tonic-gate */ 48927c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 48937c478bd9Sstevel@tonic-gate } else { 48947c478bd9Sstevel@tonic-gate /* 48957c478bd9Sstevel@tonic-gate * Revert back all the suspended client device states 48967c478bd9Sstevel@tonic-gate * to converse. 48977c478bd9Sstevel@tonic-gate */ 48987c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 48997c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 49007c478bd9Sstevel@tonic-gate dev_info_t *cdip; 49017c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 49027c478bd9Sstevel@tonic-gate next = 49037c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 49047c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 49057c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 49067c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 49077c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 49087c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_SUSPENDED(ct)) { 49097c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49107c478bd9Sstevel@tonic-gate (void) devi_attach(cdip, DDI_RESUME); 49117c478bd9Sstevel@tonic-gate } else { 49127c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49137c478bd9Sstevel@tonic-gate } 49147c478bd9Sstevel@tonic-gate pip = next; 49157c478bd9Sstevel@tonic-gate } 49167c478bd9Sstevel@tonic-gate } 49177c478bd9Sstevel@tonic-gate break; 49187c478bd9Sstevel@tonic-gate 49197c478bd9Sstevel@tonic-gate default: 49207c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 49217c478bd9Sstevel@tonic-gate break; 49227c478bd9Sstevel@tonic-gate } 49237c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 49247c478bd9Sstevel@tonic-gate return (rv); 49257c478bd9Sstevel@tonic-gate } 49267c478bd9Sstevel@tonic-gate 49277c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49287c478bd9Sstevel@tonic-gate static int 49297c478bd9Sstevel@tonic-gate i_mdi_client_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 49307c478bd9Sstevel@tonic-gate { 49317c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 49327c478bd9Sstevel@tonic-gate mdi_client_t *ct; 49337c478bd9Sstevel@tonic-gate 49347c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 49357c478bd9Sstevel@tonic-gate if (ct == NULL) { 49367c478bd9Sstevel@tonic-gate return (rv); 49377c478bd9Sstevel@tonic-gate } 49387c478bd9Sstevel@tonic-gate 49397c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 49407c478bd9Sstevel@tonic-gate switch (cmd) { 49417c478bd9Sstevel@tonic-gate case DDI_DETACH: 49427c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 49437c478bd9Sstevel@tonic-gate "!Client pre_detach: called %p\n", ct)); 49447c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 49457c478bd9Sstevel@tonic-gate break; 49467c478bd9Sstevel@tonic-gate 49477c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 49487c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 49497c478bd9Sstevel@tonic-gate "!Client pre_suspend: called %p\n", ct)); 49507c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 49517c478bd9Sstevel@tonic-gate break; 49527c478bd9Sstevel@tonic-gate 49537c478bd9Sstevel@tonic-gate default: 49547c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 49557c478bd9Sstevel@tonic-gate break; 49567c478bd9Sstevel@tonic-gate } 49577c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 49587c478bd9Sstevel@tonic-gate return (rv); 49597c478bd9Sstevel@tonic-gate } 49607c478bd9Sstevel@tonic-gate 49617c478bd9Sstevel@tonic-gate /* 49627c478bd9Sstevel@tonic-gate * mdi_post_detach(): 49637c478bd9Sstevel@tonic-gate * Post detach notification handler 49647c478bd9Sstevel@tonic-gate */ 49657c478bd9Sstevel@tonic-gate 49667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49677c478bd9Sstevel@tonic-gate void 49687c478bd9Sstevel@tonic-gate mdi_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 49697c478bd9Sstevel@tonic-gate { 49707c478bd9Sstevel@tonic-gate /* 49717c478bd9Sstevel@tonic-gate * Detach/Suspend of mpxio component failed. Update our state 49727c478bd9Sstevel@tonic-gate * too 49737c478bd9Sstevel@tonic-gate */ 49747c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) 49757c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dip, cmd, error); 49767c478bd9Sstevel@tonic-gate 49777c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) 49787c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dip, cmd, error); 49797c478bd9Sstevel@tonic-gate } 49807c478bd9Sstevel@tonic-gate 49817c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49827c478bd9Sstevel@tonic-gate static void 49837c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 49847c478bd9Sstevel@tonic-gate { 49857c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 49867c478bd9Sstevel@tonic-gate 49877c478bd9Sstevel@tonic-gate /* 49887c478bd9Sstevel@tonic-gate * Detach/Suspend of phci component failed. Update our state 49897c478bd9Sstevel@tonic-gate * too 49907c478bd9Sstevel@tonic-gate */ 49917c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 49927c478bd9Sstevel@tonic-gate if (ph == NULL) { 49937c478bd9Sstevel@tonic-gate return; 49947c478bd9Sstevel@tonic-gate } 49957c478bd9Sstevel@tonic-gate 49967c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 49977c478bd9Sstevel@tonic-gate /* 49987c478bd9Sstevel@tonic-gate * Detach of pHCI failed. Restore back converse 49997c478bd9Sstevel@tonic-gate * state 50007c478bd9Sstevel@tonic-gate */ 50017c478bd9Sstevel@tonic-gate switch (cmd) { 50027c478bd9Sstevel@tonic-gate case DDI_DETACH: 50037c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 50047c478bd9Sstevel@tonic-gate "!pHCI post_detach: called %p\n", ph)); 50057c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50067c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 50077c478bd9Sstevel@tonic-gate break; 50087c478bd9Sstevel@tonic-gate 50097c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 50107c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 50117c478bd9Sstevel@tonic-gate "!pHCI post_suspend: called %p\n", ph)); 50127c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50137c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 50147c478bd9Sstevel@tonic-gate break; 50157c478bd9Sstevel@tonic-gate } 50167c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 50177c478bd9Sstevel@tonic-gate } 50187c478bd9Sstevel@tonic-gate 50197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 50207c478bd9Sstevel@tonic-gate static void 50217c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 50227c478bd9Sstevel@tonic-gate { 50237c478bd9Sstevel@tonic-gate mdi_client_t *ct; 50247c478bd9Sstevel@tonic-gate 50257c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 50267c478bd9Sstevel@tonic-gate if (ct == NULL) { 50277c478bd9Sstevel@tonic-gate return; 50287c478bd9Sstevel@tonic-gate } 50297c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 50307c478bd9Sstevel@tonic-gate /* 50317c478bd9Sstevel@tonic-gate * Detach of Client failed. Restore back converse 50327c478bd9Sstevel@tonic-gate * state 50337c478bd9Sstevel@tonic-gate */ 50347c478bd9Sstevel@tonic-gate switch (cmd) { 50357c478bd9Sstevel@tonic-gate case DDI_DETACH: 50367c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 50377c478bd9Sstevel@tonic-gate "!Client post_detach: called %p\n", ct)); 50387c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 50397c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 50407c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 50417c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 50427c478bd9Sstevel@tonic-gate } else { 50437c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 50447c478bd9Sstevel@tonic-gate "i_mdi_pm_reset_client\n")); 50457c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 50467c478bd9Sstevel@tonic-gate } 50477c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50487c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 50497c478bd9Sstevel@tonic-gate break; 50507c478bd9Sstevel@tonic-gate 50517c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 50527c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 50537c478bd9Sstevel@tonic-gate "!Client post_suspend: called %p\n", ct)); 50547c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50557c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 50567c478bd9Sstevel@tonic-gate break; 50577c478bd9Sstevel@tonic-gate } 50587c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 50597c478bd9Sstevel@tonic-gate } 50607c478bd9Sstevel@tonic-gate 50617c478bd9Sstevel@tonic-gate /* 50627c478bd9Sstevel@tonic-gate * create and install per-path (client - pHCI) statistics 50637c478bd9Sstevel@tonic-gate * I/O stats supported: nread, nwritten, reads, and writes 50647c478bd9Sstevel@tonic-gate * Error stats - hard errors, soft errors, & transport errors 50657c478bd9Sstevel@tonic-gate */ 50667c478bd9Sstevel@tonic-gate static int 50677c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_create(mdi_pathinfo_t *pip) 50687c478bd9Sstevel@tonic-gate { 50697c478bd9Sstevel@tonic-gate 50707c478bd9Sstevel@tonic-gate dev_info_t *client = MDI_PI(pip)->pi_client->ct_dip; 50717c478bd9Sstevel@tonic-gate dev_info_t *ppath = MDI_PI(pip)->pi_phci->ph_dip; 50727c478bd9Sstevel@tonic-gate char ksname[KSTAT_STRLEN]; 50737c478bd9Sstevel@tonic-gate mdi_pathinfo_t *cpip; 50747c478bd9Sstevel@tonic-gate const char *err_postfix = ",err"; 50757c478bd9Sstevel@tonic-gate kstat_t *kiosp, *kerrsp; 50767c478bd9Sstevel@tonic-gate struct pi_errs *nsp; 50777c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 50787c478bd9Sstevel@tonic-gate 50797c478bd9Sstevel@tonic-gate ASSERT(client != NULL && ppath != NULL); 50807c478bd9Sstevel@tonic-gate 50817c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&(MDI_PI(pip)->pi_client->ct_mutex))); 50827c478bd9Sstevel@tonic-gate 50837c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_kstats != NULL) 50847c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 50857c478bd9Sstevel@tonic-gate 50867c478bd9Sstevel@tonic-gate for (cpip = MDI_PI(pip)->pi_client->ct_path_head; cpip != NULL; 50877c478bd9Sstevel@tonic-gate cpip = (mdi_pathinfo_t *)(MDI_PI(cpip)->pi_client_link)) { 50887c478bd9Sstevel@tonic-gate if (cpip == pip) 50897c478bd9Sstevel@tonic-gate continue; 50907c478bd9Sstevel@tonic-gate /* 50917c478bd9Sstevel@tonic-gate * We have found a different path with same parent 50927c478bd9Sstevel@tonic-gate * kstats for a given client-pHCI are common 50937c478bd9Sstevel@tonic-gate */ 50947c478bd9Sstevel@tonic-gate if ((MDI_PI(cpip)->pi_phci->ph_dip == ppath) && 50957c478bd9Sstevel@tonic-gate (MDI_PI(cpip)->pi_kstats != NULL)) { 50967c478bd9Sstevel@tonic-gate MDI_PI(cpip)->pi_kstats->pi_kstat_ref++; 50977c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = MDI_PI(cpip)->pi_kstats; 50987c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 50997c478bd9Sstevel@tonic-gate } 51007c478bd9Sstevel@tonic-gate } 51017c478bd9Sstevel@tonic-gate 51027c478bd9Sstevel@tonic-gate /* 51037c478bd9Sstevel@tonic-gate * stats are named as follows: TGTx.HBAy, e.g. "ssd0.fp0" 51047c478bd9Sstevel@tonic-gate * clamp length of name against max length of error kstat name 51057c478bd9Sstevel@tonic-gate */ 51067c478bd9Sstevel@tonic-gate if (snprintf(ksname, KSTAT_STRLEN, "%s%d.%s%d", 51077c478bd9Sstevel@tonic-gate ddi_driver_name(client), ddi_get_instance(client), 51087c478bd9Sstevel@tonic-gate ddi_driver_name(ppath), ddi_get_instance(ppath)) > 51097c478bd9Sstevel@tonic-gate (KSTAT_STRLEN - strlen(err_postfix))) { 51107c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 51117c478bd9Sstevel@tonic-gate } 51127c478bd9Sstevel@tonic-gate if ((kiosp = kstat_create("mdi", 0, ksname, "iopath", 51137c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, 0)) == NULL) { 51147c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 51157c478bd9Sstevel@tonic-gate } 51167c478bd9Sstevel@tonic-gate 51177c478bd9Sstevel@tonic-gate (void) strcat(ksname, err_postfix); 51187c478bd9Sstevel@tonic-gate kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors", 51197c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, 51207c478bd9Sstevel@tonic-gate sizeof (struct pi_errs) / sizeof (kstat_named_t), 0); 51217c478bd9Sstevel@tonic-gate 51227c478bd9Sstevel@tonic-gate if (kerrsp == NULL) { 51237c478bd9Sstevel@tonic-gate kstat_delete(kiosp); 51247c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 51257c478bd9Sstevel@tonic-gate } 51267c478bd9Sstevel@tonic-gate 51277c478bd9Sstevel@tonic-gate nsp = (struct pi_errs *)kerrsp->ks_data; 51287c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32); 51297c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32); 51307c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_transerrs, "Transport Errors", 51317c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51327c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy", 51337c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51347c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors", 51357c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51367c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources", 51377c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51387c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors", 51397c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51407c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State", 51417c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51427c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedfrom, "Failed From", 51437c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51447c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32); 51457c478bd9Sstevel@tonic-gate 51467c478bd9Sstevel@tonic-gate mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP); 51477c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_ref = 1; 51487c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_iostats = kiosp; 51497c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_errstats = kerrsp; 51507c478bd9Sstevel@tonic-gate kstat_install(kiosp); 51517c478bd9Sstevel@tonic-gate kstat_install(kerrsp); 51527c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = mdi_statp; 51537c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 51547c478bd9Sstevel@tonic-gate } 51557c478bd9Sstevel@tonic-gate 51567c478bd9Sstevel@tonic-gate /* 51577c478bd9Sstevel@tonic-gate * destroy per-path properties 51587c478bd9Sstevel@tonic-gate */ 51597c478bd9Sstevel@tonic-gate static void 51607c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip) 51617c478bd9Sstevel@tonic-gate { 51627c478bd9Sstevel@tonic-gate 51637c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 51647c478bd9Sstevel@tonic-gate 51657c478bd9Sstevel@tonic-gate if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL) 51667c478bd9Sstevel@tonic-gate return; 51677c478bd9Sstevel@tonic-gate 51687c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 51697c478bd9Sstevel@tonic-gate 51707c478bd9Sstevel@tonic-gate /* 51717c478bd9Sstevel@tonic-gate * the kstat may be shared between multiple pathinfo nodes 51727c478bd9Sstevel@tonic-gate * decrement this pathinfo's usage, removing the kstats 51737c478bd9Sstevel@tonic-gate * themselves when the last pathinfo reference is removed. 51747c478bd9Sstevel@tonic-gate */ 51757c478bd9Sstevel@tonic-gate ASSERT(mdi_statp->pi_kstat_ref > 0); 51767c478bd9Sstevel@tonic-gate if (--mdi_statp->pi_kstat_ref != 0) 51777c478bd9Sstevel@tonic-gate return; 51787c478bd9Sstevel@tonic-gate 51797c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_iostats); 51807c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_errstats); 51817c478bd9Sstevel@tonic-gate kmem_free(mdi_statp, sizeof (*mdi_statp)); 51827c478bd9Sstevel@tonic-gate } 51837c478bd9Sstevel@tonic-gate 51847c478bd9Sstevel@tonic-gate /* 51857c478bd9Sstevel@tonic-gate * update I/O paths KSTATS 51867c478bd9Sstevel@tonic-gate */ 51877c478bd9Sstevel@tonic-gate void 51887c478bd9Sstevel@tonic-gate mdi_pi_kstat_iosupdate(mdi_pathinfo_t *pip, struct buf *bp) 51897c478bd9Sstevel@tonic-gate { 51907c478bd9Sstevel@tonic-gate kstat_t *iostatp; 51917c478bd9Sstevel@tonic-gate size_t xfer_cnt; 51927c478bd9Sstevel@tonic-gate 51937c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 51947c478bd9Sstevel@tonic-gate 51957c478bd9Sstevel@tonic-gate /* 51967c478bd9Sstevel@tonic-gate * I/O can be driven across a path prior to having path 51977c478bd9Sstevel@tonic-gate * statistics available, i.e. probe(9e). 51987c478bd9Sstevel@tonic-gate */ 51997c478bd9Sstevel@tonic-gate if (bp != NULL && MDI_PI(pip)->pi_kstats != NULL) { 52007c478bd9Sstevel@tonic-gate iostatp = MDI_PI(pip)->pi_kstats->pi_kstat_iostats; 52017c478bd9Sstevel@tonic-gate xfer_cnt = bp->b_bcount - bp->b_resid; 52027c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 52037c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->reads++; 52047c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nread += xfer_cnt; 52057c478bd9Sstevel@tonic-gate } else { 52067c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->writes++; 52077c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nwritten += xfer_cnt; 52087c478bd9Sstevel@tonic-gate } 52097c478bd9Sstevel@tonic-gate } 52107c478bd9Sstevel@tonic-gate } 52117c478bd9Sstevel@tonic-gate 52127c478bd9Sstevel@tonic-gate /* 52137c478bd9Sstevel@tonic-gate * disable the path to a particular pHCI (pHCI specified in the phci_path 52147c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 52157c478bd9Sstevel@tonic-gate * Disabling a path means that MPxIO will not select the disabled path for 52167c478bd9Sstevel@tonic-gate * routing any new I/O requests. 52177c478bd9Sstevel@tonic-gate */ 52187c478bd9Sstevel@tonic-gate int 52197c478bd9Sstevel@tonic-gate mdi_pi_disable(dev_info_t *cdip, dev_info_t *pdip, int flags) 52207c478bd9Sstevel@tonic-gate { 52217c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_DISABLE_OP)); 52227c478bd9Sstevel@tonic-gate } 52237c478bd9Sstevel@tonic-gate 52247c478bd9Sstevel@tonic-gate /* 52257c478bd9Sstevel@tonic-gate * Enable the path to a particular pHCI (pHCI specified in the phci_path 52267c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 52277c478bd9Sstevel@tonic-gate * Enabling a path means that MPxIO may select the enabled path for routing 52287c478bd9Sstevel@tonic-gate * future I/O requests, subject to other path state constraints. 52297c478bd9Sstevel@tonic-gate */ 52307c478bd9Sstevel@tonic-gate 52317c478bd9Sstevel@tonic-gate int 52327c478bd9Sstevel@tonic-gate mdi_pi_enable(dev_info_t *cdip, dev_info_t *pdip, int flags) 52337c478bd9Sstevel@tonic-gate { 52347c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_ENABLE_OP)); 52357c478bd9Sstevel@tonic-gate } 52367c478bd9Sstevel@tonic-gate 52377c478bd9Sstevel@tonic-gate 52387c478bd9Sstevel@tonic-gate /* 52397c478bd9Sstevel@tonic-gate * Common routine for doing enable/disable. 52407c478bd9Sstevel@tonic-gate */ 52417c478bd9Sstevel@tonic-gate int 52427c478bd9Sstevel@tonic-gate i_mdi_pi_enable_disable(dev_info_t *cdip, dev_info_t *pdip, int flags, int op) 52437c478bd9Sstevel@tonic-gate { 52447c478bd9Sstevel@tonic-gate 52457c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 52467c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 52477c478bd9Sstevel@tonic-gate mdi_client_t *ct; 52487c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next, *pip; 52497c478bd9Sstevel@tonic-gate int found_it; 52507c478bd9Sstevel@tonic-gate int (*f)() = NULL; 52517c478bd9Sstevel@tonic-gate int rv; 52527c478bd9Sstevel@tonic-gate int sync_flag = 0; 52537c478bd9Sstevel@tonic-gate 52547c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 52557c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 52567c478bd9Sstevel@tonic-gate " Operation = %d pdip = %p cdip = %p\n", op, pdip, cdip)); 52577c478bd9Sstevel@tonic-gate if (ph == NULL) { 52587c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 52597c478bd9Sstevel@tonic-gate " failed. ph = NULL operation = %d\n", op)); 52607c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 52617c478bd9Sstevel@tonic-gate } 52627c478bd9Sstevel@tonic-gate 52637c478bd9Sstevel@tonic-gate if ((op != MDI_ENABLE_OP) && (op != MDI_DISABLE_OP)) { 52647c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 52657c478bd9Sstevel@tonic-gate " Invalid operation = %d\n", op)); 52667c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 52677c478bd9Sstevel@tonic-gate } 52687c478bd9Sstevel@tonic-gate 52697c478bd9Sstevel@tonic-gate sync_flag = (flags << 8) & 0xf00; 52707c478bd9Sstevel@tonic-gate 52717c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 52727c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 52737c478bd9Sstevel@tonic-gate 52747c478bd9Sstevel@tonic-gate if (cdip == NULL) { 52757c478bd9Sstevel@tonic-gate /* 52767c478bd9Sstevel@tonic-gate * Need to mark the Phci as enabled/disabled. 52777c478bd9Sstevel@tonic-gate */ 52787c478bd9Sstevel@tonic-gate MDI_DEBUG(3, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 52797c478bd9Sstevel@tonic-gate "Operation %d for the phci\n", op)); 52807c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 52817c478bd9Sstevel@tonic-gate switch (flags) { 52827c478bd9Sstevel@tonic-gate case USER_DISABLE: 52837c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 52847c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_DISABLE(ph); 52857c478bd9Sstevel@tonic-gate else 52867c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_ENABLE(ph); 52877c478bd9Sstevel@tonic-gate break; 52887c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 52897c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 52907c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE(ph); 52917c478bd9Sstevel@tonic-gate else 52927c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE(ph); 52937c478bd9Sstevel@tonic-gate break; 52947c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 52957c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 52967c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE_TRANSIENT(ph); 52977c478bd9Sstevel@tonic-gate else 52987c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE_TRANSIENT(ph); 52997c478bd9Sstevel@tonic-gate break; 53007c478bd9Sstevel@tonic-gate default: 53017c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 53027c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 53037c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 53047c478bd9Sstevel@tonic-gate " Invalid flag argument= %d\n", flags)); 53057c478bd9Sstevel@tonic-gate } 53067c478bd9Sstevel@tonic-gate 53077c478bd9Sstevel@tonic-gate /* 53087c478bd9Sstevel@tonic-gate * Phci has been disabled. Now try to enable/disable 53097c478bd9Sstevel@tonic-gate * path info's to each client. 53107c478bd9Sstevel@tonic-gate */ 53117c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 53127c478bd9Sstevel@tonic-gate while (pip != NULL) { 53137c478bd9Sstevel@tonic-gate /* 53147c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 53157c478bd9Sstevel@tonic-gate * know that path is about to be enabled/disabled. 53167c478bd9Sstevel@tonic-gate */ 53177c478bd9Sstevel@tonic-gate if (f != NULL) { 53187c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 53197c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 53207c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 53217c478bd9Sstevel@tonic-gate op | MDI_BEFORE_STATE_CHANGE); 53227c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 53237c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 53247c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 53257c478bd9Sstevel@tonic-gate } 53267c478bd9Sstevel@tonic-gate } 53277c478bd9Sstevel@tonic-gate 53287c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 53297c478bd9Sstevel@tonic-gate next = 53307c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 53317c478bd9Sstevel@tonic-gate switch (flags) { 53327c478bd9Sstevel@tonic-gate case USER_DISABLE: 53337c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 53347c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 53357c478bd9Sstevel@tonic-gate else 53367c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_ENABLE(pip); 53377c478bd9Sstevel@tonic-gate break; 53387c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 53397c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 53407c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 53417c478bd9Sstevel@tonic-gate else 53427c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE(pip); 53437c478bd9Sstevel@tonic-gate break; 53447c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 53457c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) 53467c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 53477c478bd9Sstevel@tonic-gate else 53487c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE_TRANS(pip); 53497c478bd9Sstevel@tonic-gate break; 53507c478bd9Sstevel@tonic-gate } 53517c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 53527c478bd9Sstevel@tonic-gate /* 53537c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 53547c478bd9Sstevel@tonic-gate * know that path is now enabled/disabled. 53557c478bd9Sstevel@tonic-gate */ 53567c478bd9Sstevel@tonic-gate if (f != NULL) { 53577c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 53587c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 53597c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 53607c478bd9Sstevel@tonic-gate op | MDI_AFTER_STATE_CHANGE); 53617c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 53627c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 53637c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 53647c478bd9Sstevel@tonic-gate } 53657c478bd9Sstevel@tonic-gate } 53667c478bd9Sstevel@tonic-gate pip = next; 53677c478bd9Sstevel@tonic-gate } 53687c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 53697c478bd9Sstevel@tonic-gate } else { 53707c478bd9Sstevel@tonic-gate 53717c478bd9Sstevel@tonic-gate /* 53727c478bd9Sstevel@tonic-gate * Disable a specific client. 53737c478bd9Sstevel@tonic-gate */ 53747c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 53757c478bd9Sstevel@tonic-gate if (ct == NULL) { 53767c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 53777c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 53787c478bd9Sstevel@tonic-gate " failed. ct = NULL operation = %d\n", op)); 53797c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 53807c478bd9Sstevel@tonic-gate } 53817c478bd9Sstevel@tonic-gate 53827c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 53837c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 53847c478bd9Sstevel@tonic-gate found_it = 0; 53857c478bd9Sstevel@tonic-gate while (pip != NULL) { 53867c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 53877c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 53887c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 53897c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 53907c478bd9Sstevel@tonic-gate found_it = 1; 53917c478bd9Sstevel@tonic-gate break; 53927c478bd9Sstevel@tonic-gate } 53937c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 53947c478bd9Sstevel@tonic-gate pip = next; 53957c478bd9Sstevel@tonic-gate } 53967c478bd9Sstevel@tonic-gate 53977c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 53987c478bd9Sstevel@tonic-gate if (found_it == 0) { 53997c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 54007c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 54017c478bd9Sstevel@tonic-gate " failed. Could not find corresponding pip\n")); 54027c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54037c478bd9Sstevel@tonic-gate } 54047c478bd9Sstevel@tonic-gate /* 54057c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 54067c478bd9Sstevel@tonic-gate * know that path is about to get enabled/disabled. 54077c478bd9Sstevel@tonic-gate */ 54087c478bd9Sstevel@tonic-gate if (f != NULL) { 54097c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 54107c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 54117c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 54127c478bd9Sstevel@tonic-gate op | MDI_BEFORE_STATE_CHANGE); 54137c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 54147c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 54157c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 54167c478bd9Sstevel@tonic-gate } 54177c478bd9Sstevel@tonic-gate } 54187c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 54197c478bd9Sstevel@tonic-gate switch (flags) { 54207c478bd9Sstevel@tonic-gate case USER_DISABLE: 54217c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 54227c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 54237c478bd9Sstevel@tonic-gate else 54247c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_ENABLE(pip); 54257c478bd9Sstevel@tonic-gate break; 54267c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 54277c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 54287c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 54297c478bd9Sstevel@tonic-gate else 54307c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE(pip); 54317c478bd9Sstevel@tonic-gate break; 54327c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 54337c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) 54347c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 54357c478bd9Sstevel@tonic-gate else 54367c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE_TRANS(pip); 54377c478bd9Sstevel@tonic-gate break; 54387c478bd9Sstevel@tonic-gate } 54397c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 54407c478bd9Sstevel@tonic-gate /* 54417c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 54427c478bd9Sstevel@tonic-gate * know that path is now enabled/disabled. 54437c478bd9Sstevel@tonic-gate */ 54447c478bd9Sstevel@tonic-gate if (f != NULL) { 54457c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 54467c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 54477c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 54487c478bd9Sstevel@tonic-gate op | MDI_AFTER_STATE_CHANGE); 54497c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 54507c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 54517c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 54527c478bd9Sstevel@tonic-gate } 54537c478bd9Sstevel@tonic-gate } 54547c478bd9Sstevel@tonic-gate } 54557c478bd9Sstevel@tonic-gate 54567c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 54577c478bd9Sstevel@tonic-gate " Returning success pdip = %p cdip = %p\n", op, pdip, cdip)); 54587c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 54597c478bd9Sstevel@tonic-gate } 54607c478bd9Sstevel@tonic-gate 54617c478bd9Sstevel@tonic-gate /*ARGSUSED3*/ 54627c478bd9Sstevel@tonic-gate int 54637c478bd9Sstevel@tonic-gate mdi_devi_config_one(dev_info_t *pdip, char *devnm, dev_info_t **cdipp, 54647c478bd9Sstevel@tonic-gate int flags, clock_t timeout) 54657c478bd9Sstevel@tonic-gate { 54667c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 54677c478bd9Sstevel@tonic-gate dev_info_t *dip; 54687c478bd9Sstevel@tonic-gate clock_t interval = drv_usectohz(100000); /* 0.1 sec */ 54697c478bd9Sstevel@tonic-gate char *paddr; 54707c478bd9Sstevel@tonic-gate 54717c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "configure device %s", devnm)); 54727c478bd9Sstevel@tonic-gate 54737c478bd9Sstevel@tonic-gate if (!MDI_PHCI(pdip)) 54747c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54757c478bd9Sstevel@tonic-gate 54767c478bd9Sstevel@tonic-gate paddr = strchr(devnm, '@'); 54777c478bd9Sstevel@tonic-gate if (paddr == NULL) 54787c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54797c478bd9Sstevel@tonic-gate 54807c478bd9Sstevel@tonic-gate paddr++; /* skip '@' */ 54817c478bd9Sstevel@tonic-gate pip = mdi_pi_find(pdip, NULL, paddr); 54827c478bd9Sstevel@tonic-gate while (pip == NULL && timeout > 0) { 54837c478bd9Sstevel@tonic-gate if (interval > timeout) 54847c478bd9Sstevel@tonic-gate interval = timeout; 54857c478bd9Sstevel@tonic-gate if (flags & NDI_DEVI_DEBUG) { 54867c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: %s timeout %ld %ld\n", 54877c478bd9Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip), 54887c478bd9Sstevel@tonic-gate paddr, interval, timeout); 54897c478bd9Sstevel@tonic-gate } 54907c478bd9Sstevel@tonic-gate delay(interval); 54917c478bd9Sstevel@tonic-gate timeout -= interval; 54927c478bd9Sstevel@tonic-gate interval += interval; 54937c478bd9Sstevel@tonic-gate pip = mdi_pi_find(pdip, NULL, paddr); 54947c478bd9Sstevel@tonic-gate } 54957c478bd9Sstevel@tonic-gate 54967c478bd9Sstevel@tonic-gate if (pip == NULL) 54977c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54987c478bd9Sstevel@tonic-gate dip = mdi_pi_get_client(pip); 54997c478bd9Sstevel@tonic-gate if (ndi_devi_online(dip, flags) != NDI_SUCCESS) 55007c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 55017c478bd9Sstevel@tonic-gate *cdipp = dip; 55027c478bd9Sstevel@tonic-gate 55037c478bd9Sstevel@tonic-gate /* TODO: holding should happen inside search functions */ 55047c478bd9Sstevel@tonic-gate ndi_hold_devi(dip); 55057c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 55067c478bd9Sstevel@tonic-gate } 55077c478bd9Sstevel@tonic-gate 55087c478bd9Sstevel@tonic-gate /* 55097c478bd9Sstevel@tonic-gate * Ensure phci powered up 55107c478bd9Sstevel@tonic-gate */ 55117c478bd9Sstevel@tonic-gate static void 55127c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(mdi_pathinfo_t *pip) 55137c478bd9Sstevel@tonic-gate { 55147c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 55157c478bd9Sstevel@tonic-gate 55167c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 55177c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 55187c478bd9Sstevel@tonic-gate 55197c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 55207c478bd9Sstevel@tonic-gate return; 55217c478bd9Sstevel@tonic-gate } 55227c478bd9Sstevel@tonic-gate 55237c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 55247c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_hold_pip for %s%d\n", 55257c478bd9Sstevel@tonic-gate ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 55267c478bd9Sstevel@tonic-gate if (ph_dip == NULL) { 55277c478bd9Sstevel@tonic-gate return; 55287c478bd9Sstevel@tonic-gate } 55297c478bd9Sstevel@tonic-gate 55307c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 55317c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 55327c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55337c478bd9Sstevel@tonic-gate pm_hold_power(ph_dip); 55347c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 55357c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55367c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 55377c478bd9Sstevel@tonic-gate 55387c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 1; 55397c478bd9Sstevel@tonic-gate } 55407c478bd9Sstevel@tonic-gate 55417c478bd9Sstevel@tonic-gate /* 55427c478bd9Sstevel@tonic-gate * Allow phci powered down 55437c478bd9Sstevel@tonic-gate */ 55447c478bd9Sstevel@tonic-gate static void 55457c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(mdi_pathinfo_t *pip) 55467c478bd9Sstevel@tonic-gate { 55477c478bd9Sstevel@tonic-gate dev_info_t *ph_dip = NULL; 55487c478bd9Sstevel@tonic-gate 55497c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 55507c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 55517c478bd9Sstevel@tonic-gate 55527c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 55537c478bd9Sstevel@tonic-gate return; 55547c478bd9Sstevel@tonic-gate } 55557c478bd9Sstevel@tonic-gate 55567c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 55577c478bd9Sstevel@tonic-gate ASSERT(ph_dip != NULL); 55587c478bd9Sstevel@tonic-gate 55597c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 55607c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_rele_pip for %s%d\n", 55617c478bd9Sstevel@tonic-gate ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 55627c478bd9Sstevel@tonic-gate 55637c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 55647c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55657c478bd9Sstevel@tonic-gate pm_rele_power(ph_dip); 55667c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 55677c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55687c478bd9Sstevel@tonic-gate 55697c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 55707c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 0; 55717c478bd9Sstevel@tonic-gate } 55727c478bd9Sstevel@tonic-gate 55737c478bd9Sstevel@tonic-gate static void 55747c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(mdi_client_t *ct, int incr) 55757c478bd9Sstevel@tonic-gate { 55767c478bd9Sstevel@tonic-gate ASSERT(ct); 55777c478bd9Sstevel@tonic-gate 55787c478bd9Sstevel@tonic-gate ct->ct_power_cnt += incr; 55797c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_hold_client " 55807c478bd9Sstevel@tonic-gate "ct_power_cnt = %d incr = %d\n", ct->ct_power_cnt, incr)); 55817c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 55827c478bd9Sstevel@tonic-gate } 55837c478bd9Sstevel@tonic-gate 55847c478bd9Sstevel@tonic-gate static void 55857c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(mdi_client_t *ct) 55867c478bd9Sstevel@tonic-gate { 55877c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 55887c478bd9Sstevel@tonic-gate 55897c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ct->ct_mutex)); 55907c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 55917c478bd9Sstevel@tonic-gate while (pip != NULL) { 55927c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 55937c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 55947c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 55957c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 55967c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 55977c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 55987c478bd9Sstevel@tonic-gate } 55997c478bd9Sstevel@tonic-gate } 56007c478bd9Sstevel@tonic-gate 56017c478bd9Sstevel@tonic-gate static void 56027c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(mdi_client_t *ct, int decr) 56037c478bd9Sstevel@tonic-gate { 56047c478bd9Sstevel@tonic-gate ASSERT(ct); 56057c478bd9Sstevel@tonic-gate 56067c478bd9Sstevel@tonic-gate if (i_ddi_node_state(ct->ct_dip) >= DS_READY) { 56077c478bd9Sstevel@tonic-gate ct->ct_power_cnt -= decr; 56087c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_rele_client " 56097c478bd9Sstevel@tonic-gate "ct_power_cnt = %d decr = %d\n", ct->ct_power_cnt, decr)); 56107c478bd9Sstevel@tonic-gate } 56117c478bd9Sstevel@tonic-gate 56127c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 56137c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 56147c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 56157c478bd9Sstevel@tonic-gate return; 56167c478bd9Sstevel@tonic-gate } 56177c478bd9Sstevel@tonic-gate } 56187c478bd9Sstevel@tonic-gate 56197c478bd9Sstevel@tonic-gate static void 56207c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(mdi_client_t *ct) 56217c478bd9Sstevel@tonic-gate { 56227c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_reset_client " 56237c478bd9Sstevel@tonic-gate "ct_power_cnt = %d\n", ct->ct_power_cnt)); 56247c478bd9Sstevel@tonic-gate ct->ct_power_cnt = 0; 56257c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 56267c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 1; 56277c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 0; 56287c478bd9Sstevel@tonic-gate } 56297c478bd9Sstevel@tonic-gate 56307c478bd9Sstevel@tonic-gate static void 56317c478bd9Sstevel@tonic-gate i_mdi_pm_hold_all_phci(mdi_client_t *ct) 56327c478bd9Sstevel@tonic-gate { 56337c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 56347c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ct->ct_mutex)); 56357c478bd9Sstevel@tonic-gate 56367c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 56377c478bd9Sstevel@tonic-gate while (pip != NULL) { 56387c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 56397c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 56407c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 56417c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 56427c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 56437c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 56447c478bd9Sstevel@tonic-gate } 56457c478bd9Sstevel@tonic-gate } 56467c478bd9Sstevel@tonic-gate 56477c478bd9Sstevel@tonic-gate static int 56487c478bd9Sstevel@tonic-gate i_mdi_power_one_phci(mdi_pathinfo_t *pip) 56497c478bd9Sstevel@tonic-gate { 56507c478bd9Sstevel@tonic-gate int ret; 56517c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 56527c478bd9Sstevel@tonic-gate 56537c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 56547c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 56557c478bd9Sstevel@tonic-gate 56567c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 56577c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 56587c478bd9Sstevel@tonic-gate 56597c478bd9Sstevel@tonic-gate /* bring all components of phci to full power */ 56607c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 56617c478bd9Sstevel@tonic-gate "pm_powerup for %s%d\n", ddi_get_name(ph_dip), 56627c478bd9Sstevel@tonic-gate ddi_get_instance(ph_dip))); 56637c478bd9Sstevel@tonic-gate 56647c478bd9Sstevel@tonic-gate ret = pm_powerup(ph_dip); 56657c478bd9Sstevel@tonic-gate 56667c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 56677c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 56687c478bd9Sstevel@tonic-gate "pm_powerup FAILED for %s%d\n", 56697c478bd9Sstevel@tonic-gate ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 56707c478bd9Sstevel@tonic-gate 56717c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 56727c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 56737c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 56747c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 56757c478bd9Sstevel@tonic-gate } 56767c478bd9Sstevel@tonic-gate 56777c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 56787c478bd9Sstevel@tonic-gate } 56797c478bd9Sstevel@tonic-gate 56807c478bd9Sstevel@tonic-gate static int 56817c478bd9Sstevel@tonic-gate i_mdi_power_all_phci(mdi_client_t *ct) 56827c478bd9Sstevel@tonic-gate { 56837c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 56847c478bd9Sstevel@tonic-gate int succeeded = 0; 56857c478bd9Sstevel@tonic-gate 56867c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 56877c478bd9Sstevel@tonic-gate while (pip != NULL) { 56887c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 56897c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 56907c478bd9Sstevel@tonic-gate if (i_mdi_power_one_phci(pip) == MDI_SUCCESS) 56917c478bd9Sstevel@tonic-gate succeeded = 1; 56927c478bd9Sstevel@tonic-gate 56937c478bd9Sstevel@tonic-gate ASSERT(ct == MDI_PI(pip)->pi_client); 56947c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 56957c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 56967c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 56977c478bd9Sstevel@tonic-gate } 56987c478bd9Sstevel@tonic-gate 56997c478bd9Sstevel@tonic-gate return (succeeded ? MDI_SUCCESS : MDI_FAILURE); 57007c478bd9Sstevel@tonic-gate } 57017c478bd9Sstevel@tonic-gate 57027c478bd9Sstevel@tonic-gate /* 57037c478bd9Sstevel@tonic-gate * mdi_bus_power(): 57047c478bd9Sstevel@tonic-gate * 1. Place the phci(s) into powered up state so that 57057c478bd9Sstevel@tonic-gate * client can do power management 57067c478bd9Sstevel@tonic-gate * 2. Ensure phci powered up as client power managing 57077c478bd9Sstevel@tonic-gate * Return Values: 57087c478bd9Sstevel@tonic-gate * MDI_SUCCESS 57097c478bd9Sstevel@tonic-gate * MDI_FAILURE 57107c478bd9Sstevel@tonic-gate */ 57117c478bd9Sstevel@tonic-gate int 57127c478bd9Sstevel@tonic-gate mdi_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op, 57137c478bd9Sstevel@tonic-gate void *arg, void *result) 57147c478bd9Sstevel@tonic-gate { 57157c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 57167c478bd9Sstevel@tonic-gate pm_bp_child_pwrchg_t *bpc; 57177c478bd9Sstevel@tonic-gate mdi_client_t *ct; 57187c478bd9Sstevel@tonic-gate dev_info_t *cdip; 57197c478bd9Sstevel@tonic-gate pm_bp_has_changed_t *bphc; 57207c478bd9Sstevel@tonic-gate 57217c478bd9Sstevel@tonic-gate /* 57227c478bd9Sstevel@tonic-gate * BUS_POWER_NOINVOL not supported 57237c478bd9Sstevel@tonic-gate */ 57247c478bd9Sstevel@tonic-gate if (op == BUS_POWER_NOINVOL) 57257c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 57267c478bd9Sstevel@tonic-gate 57277c478bd9Sstevel@tonic-gate /* 57287c478bd9Sstevel@tonic-gate * ignore other OPs. 57297c478bd9Sstevel@tonic-gate * return quickly to save cou cycles on the ct processing 57307c478bd9Sstevel@tonic-gate */ 57317c478bd9Sstevel@tonic-gate switch (op) { 57327c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 57337c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 57347c478bd9Sstevel@tonic-gate bpc = (pm_bp_child_pwrchg_t *)arg; 57357c478bd9Sstevel@tonic-gate cdip = bpc->bpc_dip; 57367c478bd9Sstevel@tonic-gate break; 57377c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 57387c478bd9Sstevel@tonic-gate bphc = (pm_bp_has_changed_t *)arg; 57397c478bd9Sstevel@tonic-gate cdip = bphc->bphc_dip; 57407c478bd9Sstevel@tonic-gate break; 57417c478bd9Sstevel@tonic-gate default: 57427c478bd9Sstevel@tonic-gate return (pm_busop_bus_power(parent, impl_arg, op, arg, result)); 57437c478bd9Sstevel@tonic-gate } 57447c478bd9Sstevel@tonic-gate 57457c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(cdip)); 57467c478bd9Sstevel@tonic-gate 57477c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 57487c478bd9Sstevel@tonic-gate if (ct == NULL) 57497c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 57507c478bd9Sstevel@tonic-gate 57517c478bd9Sstevel@tonic-gate /* 57527c478bd9Sstevel@tonic-gate * wait till the mdi_pathinfo node state change are processed 57537c478bd9Sstevel@tonic-gate */ 57547c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 57557c478bd9Sstevel@tonic-gate switch (op) { 57567c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 57577c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 57587c478bd9Sstevel@tonic-gate "BUS_POWER_PRE_NOTIFICATION:" 57597c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 57607c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 57617c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp)); 57627c478bd9Sstevel@tonic-gate 57637c478bd9Sstevel@tonic-gate /* serialize power level change per client */ 57647c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 57657c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 57667c478bd9Sstevel@tonic-gate 57677c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_TRANSITION(ct); 57687c478bd9Sstevel@tonic-gate 57697c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 57707c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 57717c478bd9Sstevel@tonic-gate } 57727c478bd9Sstevel@tonic-gate 57737c478bd9Sstevel@tonic-gate /* 57747c478bd9Sstevel@tonic-gate * if new_level > 0: 57757c478bd9Sstevel@tonic-gate * - hold phci(s) 57767c478bd9Sstevel@tonic-gate * - power up phci(s) if not already 57777c478bd9Sstevel@tonic-gate * ignore power down 57787c478bd9Sstevel@tonic-gate */ 57797c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 57807c478bd9Sstevel@tonic-gate if (!DEVI_IS_ATTACHING(ct->ct_dip)) { 57817c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 57827c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 57837c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 57847c478bd9Sstevel@tonic-gate } 57857c478bd9Sstevel@tonic-gate } 57867c478bd9Sstevel@tonic-gate break; 57877c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 57887c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 57897c478bd9Sstevel@tonic-gate "BUS_POWER_POST_NOTIFICATION:" 57907c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d result=%d\n", 57917c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 57927c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp, 57937c478bd9Sstevel@tonic-gate *(int *)result)); 57947c478bd9Sstevel@tonic-gate 57957c478bd9Sstevel@tonic-gate if (*(int *)result == DDI_SUCCESS) { 57967c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 57977c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 57987c478bd9Sstevel@tonic-gate } else { 57997c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_DOWN(ct); 58007c478bd9Sstevel@tonic-gate } 58017c478bd9Sstevel@tonic-gate } 58027c478bd9Sstevel@tonic-gate 58037c478bd9Sstevel@tonic-gate /* release the hold we did in pre-notification */ 58047c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0 && (*(int *)result != DDI_SUCCESS) && 58057c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) { 58067c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 58077c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 58087c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 58097c478bd9Sstevel@tonic-gate } 58107c478bd9Sstevel@tonic-gate 58117c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel == 0 && (*(int *)result == DDI_SUCCESS)) { 58127c478bd9Sstevel@tonic-gate /* another thread might started attaching */ 58137c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 58147c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 58157c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 58167c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 58177c478bd9Sstevel@tonic-gate /* detaching has been taken care in pm_post_unconfig */ 58187c478bd9Sstevel@tonic-gate } else if (!DEVI_IS_DETACHING(ct->ct_dip)) { 58197c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 58207c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_reset_client\n")); 58217c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 58227c478bd9Sstevel@tonic-gate } 58237c478bd9Sstevel@tonic-gate } 58247c478bd9Sstevel@tonic-gate 58257c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_POWER_TRANSITION(ct); 58267c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_powerchange_cv); 58277c478bd9Sstevel@tonic-gate 58287c478bd9Sstevel@tonic-gate break; 58297c478bd9Sstevel@tonic-gate 58307c478bd9Sstevel@tonic-gate /* need to do more */ 58317c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 58327c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, "mdi_bus_power " 58337c478bd9Sstevel@tonic-gate "BUS_POWER_HAS_CHANGED:" 58347c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 58357c478bd9Sstevel@tonic-gate PM_NAME(bphc->bphc_dip), PM_ADDR(bphc->bphc_dip), 58367c478bd9Sstevel@tonic-gate bphc->bphc_olevel, bphc->bphc_nlevel, bphc->bphc_comp)); 58377c478bd9Sstevel@tonic-gate 58387c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel > 0 && 58397c478bd9Sstevel@tonic-gate bphc->bphc_nlevel > bphc->bphc_olevel) { 58407c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 58417c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 58427c478bd9Sstevel@tonic-gate } 58437c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 58447c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 58457c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 58467c478bd9Sstevel@tonic-gate } 58477c478bd9Sstevel@tonic-gate 58487c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel == 0 && bphc->bphc_olevel != -1) { 58497c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 58507c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 58517c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 58527c478bd9Sstevel@tonic-gate } 58537c478bd9Sstevel@tonic-gate break; 58547c478bd9Sstevel@tonic-gate } 58557c478bd9Sstevel@tonic-gate 58567c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 58577c478bd9Sstevel@tonic-gate return (ret); 58587c478bd9Sstevel@tonic-gate } 58597c478bd9Sstevel@tonic-gate 58607c478bd9Sstevel@tonic-gate static int 58617c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config_one(dev_info_t *child) 58627c478bd9Sstevel@tonic-gate { 58637c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 58647c478bd9Sstevel@tonic-gate mdi_client_t *ct; 58657c478bd9Sstevel@tonic-gate 58667c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 58677c478bd9Sstevel@tonic-gate if (ct == NULL) 58687c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 58697c478bd9Sstevel@tonic-gate 58707c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 58717c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 58727c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 58737c478bd9Sstevel@tonic-gate 58747c478bd9Sstevel@tonic-gate if (!MDI_CLIENT_IS_FAILED(ct)) { 58757c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 58767c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 58777c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one already configured\n")); 58787c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 58797c478bd9Sstevel@tonic-gate } 58807c478bd9Sstevel@tonic-gate 58817c478bd9Sstevel@tonic-gate if (ct->ct_powercnt_held) { 58827c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 58837c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 58847c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one ALREADY held\n")); 58857c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 58867c478bd9Sstevel@tonic-gate } 58877c478bd9Sstevel@tonic-gate 58887c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 58897c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 58907c478bd9Sstevel@tonic-gate } 58917c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 58927c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one i_mdi_pm_hold_client\n")); 58937c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 58947c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 1; 58957c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 58967c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 58977c478bd9Sstevel@tonic-gate return (ret); 58987c478bd9Sstevel@tonic-gate } 58997c478bd9Sstevel@tonic-gate 59007c478bd9Sstevel@tonic-gate static int 59017c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config(dev_info_t *parent, dev_info_t *child) 59027c478bd9Sstevel@tonic-gate { 59037c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 59047c478bd9Sstevel@tonic-gate dev_info_t *cdip; 59057c478bd9Sstevel@tonic-gate int circ; 59067c478bd9Sstevel@tonic-gate 59077c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 59087c478bd9Sstevel@tonic-gate 59097c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 59107c478bd9Sstevel@tonic-gate if (child) { 59117c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_config_one(child)); 59127c478bd9Sstevel@tonic-gate } 59137c478bd9Sstevel@tonic-gate 59147c478bd9Sstevel@tonic-gate /* devi_config_common */ 59157c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 59167c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 59177c478bd9Sstevel@tonic-gate while (cdip) { 59187c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 59197c478bd9Sstevel@tonic-gate 59207c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config_one(cdip); 59217c478bd9Sstevel@tonic-gate if (ret != MDI_SUCCESS) 59227c478bd9Sstevel@tonic-gate break; 59237c478bd9Sstevel@tonic-gate cdip = next; 59247c478bd9Sstevel@tonic-gate } 59257c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 59267c478bd9Sstevel@tonic-gate return (ret); 59277c478bd9Sstevel@tonic-gate } 59287c478bd9Sstevel@tonic-gate 59297c478bd9Sstevel@tonic-gate static int 59307c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig_one(dev_info_t *child, int *held, int flags) 59317c478bd9Sstevel@tonic-gate { 59327c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 59337c478bd9Sstevel@tonic-gate mdi_client_t *ct; 59347c478bd9Sstevel@tonic-gate 59357c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 59367c478bd9Sstevel@tonic-gate if (ct == NULL) 59377c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 59387c478bd9Sstevel@tonic-gate 59397c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 59407c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 59417c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 59427c478bd9Sstevel@tonic-gate 59437c478bd9Sstevel@tonic-gate if (i_ddi_node_state(ct->ct_dip) < DS_READY) { 59447c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59457c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig node detached already\n")); 59467c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59477c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 59487c478bd9Sstevel@tonic-gate } 59497c478bd9Sstevel@tonic-gate 59507c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_POWERED_DOWN(ct) && 59517c478bd9Sstevel@tonic-gate (flags & NDI_AUTODETACH)) { 59527c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59537c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig auto-modunload\n")); 59547c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59557c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 59567c478bd9Sstevel@tonic-gate } 59577c478bd9Sstevel@tonic-gate 59587c478bd9Sstevel@tonic-gate if (ct->ct_powercnt_held) { 59597c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59607c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig ct_powercnt_held\n")); 59617c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59627c478bd9Sstevel@tonic-gate *held = 1; 59637c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 59647c478bd9Sstevel@tonic-gate } 59657c478bd9Sstevel@tonic-gate 59667c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 59677c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 59687c478bd9Sstevel@tonic-gate } 59697c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59707c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig i_mdi_pm_hold_client\n")); 59717c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 59727c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 1; 59737c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 59747c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59757c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) 59767c478bd9Sstevel@tonic-gate *held = 1; 59777c478bd9Sstevel@tonic-gate return (ret); 59787c478bd9Sstevel@tonic-gate } 59797c478bd9Sstevel@tonic-gate 59807c478bd9Sstevel@tonic-gate static int 59817c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig(dev_info_t *parent, dev_info_t *child, int *held, 59827c478bd9Sstevel@tonic-gate int flags) 59837c478bd9Sstevel@tonic-gate { 59847c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 59857c478bd9Sstevel@tonic-gate dev_info_t *cdip; 59867c478bd9Sstevel@tonic-gate int circ; 59877c478bd9Sstevel@tonic-gate 59887c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 59897c478bd9Sstevel@tonic-gate *held = 0; 59907c478bd9Sstevel@tonic-gate 59917c478bd9Sstevel@tonic-gate /* ndi_devi_unconfig_one */ 59927c478bd9Sstevel@tonic-gate if (child) { 59937c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_unconfig_one(child, held, flags)); 59947c478bd9Sstevel@tonic-gate } 59957c478bd9Sstevel@tonic-gate 59967c478bd9Sstevel@tonic-gate /* devi_unconfig_common */ 59977c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 59987c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 59997c478bd9Sstevel@tonic-gate while (cdip) { 60007c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 60017c478bd9Sstevel@tonic-gate 60027c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig_one(cdip, held, flags); 60037c478bd9Sstevel@tonic-gate cdip = next; 60047c478bd9Sstevel@tonic-gate } 60057c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 60067c478bd9Sstevel@tonic-gate 60077c478bd9Sstevel@tonic-gate if (*held) 60087c478bd9Sstevel@tonic-gate ret = MDI_SUCCESS; 60097c478bd9Sstevel@tonic-gate 60107c478bd9Sstevel@tonic-gate return (ret); 60117c478bd9Sstevel@tonic-gate } 60127c478bd9Sstevel@tonic-gate 60137c478bd9Sstevel@tonic-gate static void 60147c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(dev_info_t *child) 60157c478bd9Sstevel@tonic-gate { 60167c478bd9Sstevel@tonic-gate mdi_client_t *ct; 60177c478bd9Sstevel@tonic-gate 60187c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 60197c478bd9Sstevel@tonic-gate if (ct == NULL) 60207c478bd9Sstevel@tonic-gate return; 60217c478bd9Sstevel@tonic-gate 60227c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 60237c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 60247c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 60257c478bd9Sstevel@tonic-gate 60267c478bd9Sstevel@tonic-gate if (ct->ct_powercnt_reset || !ct->ct_powercnt_held) { 60277c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60287c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config_one NOT held\n")); 60297c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60307c478bd9Sstevel@tonic-gate return; 60317c478bd9Sstevel@tonic-gate } 60327c478bd9Sstevel@tonic-gate 60337c478bd9Sstevel@tonic-gate /* client has not been updated */ 60347c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 60357c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60367c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config_one NOT configured\n")); 60377c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60387c478bd9Sstevel@tonic-gate return; 60397c478bd9Sstevel@tonic-gate } 60407c478bd9Sstevel@tonic-gate 60417c478bd9Sstevel@tonic-gate /* another thread might have powered it down or detached it */ 60427c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 60437c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) || 60447c478bd9Sstevel@tonic-gate (i_ddi_node_state(ct->ct_dip) < DS_READY && 60457c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 60467c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60477c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_reset_client\n")); 60487c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 60497c478bd9Sstevel@tonic-gate } else { 60507c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 60517c478bd9Sstevel@tonic-gate int valid_path_count = 0; 60527c478bd9Sstevel@tonic-gate 60537c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60547c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_rele_client\n")); 60557c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 60567c478bd9Sstevel@tonic-gate while (pip != NULL) { 60577c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 60587c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 60597c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 60607c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_ONLINE || 60617c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 60627c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_STANDBY) 60637c478bd9Sstevel@tonic-gate valid_path_count ++; 60647c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 60657c478bd9Sstevel@tonic-gate pip = next; 60667c478bd9Sstevel@tonic-gate } 60677c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, valid_path_count); 60687c478bd9Sstevel@tonic-gate } 60697c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 0; 60707c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60717c478bd9Sstevel@tonic-gate } 60727c478bd9Sstevel@tonic-gate 60737c478bd9Sstevel@tonic-gate static void 60747c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(dev_info_t *parent, dev_info_t *child) 60757c478bd9Sstevel@tonic-gate { 60767c478bd9Sstevel@tonic-gate int circ; 60777c478bd9Sstevel@tonic-gate dev_info_t *cdip; 60787c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 60797c478bd9Sstevel@tonic-gate 60807c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 60817c478bd9Sstevel@tonic-gate if (child) { 60827c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(child); 60837c478bd9Sstevel@tonic-gate return; 60847c478bd9Sstevel@tonic-gate } 60857c478bd9Sstevel@tonic-gate 60867c478bd9Sstevel@tonic-gate /* devi_config_common */ 60877c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 60887c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 60897c478bd9Sstevel@tonic-gate while (cdip) { 60907c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 60917c478bd9Sstevel@tonic-gate 60927c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(cdip); 60937c478bd9Sstevel@tonic-gate cdip = next; 60947c478bd9Sstevel@tonic-gate } 60957c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 60967c478bd9Sstevel@tonic-gate } 60977c478bd9Sstevel@tonic-gate 60987c478bd9Sstevel@tonic-gate static void 60997c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(dev_info_t *child) 61007c478bd9Sstevel@tonic-gate { 61017c478bd9Sstevel@tonic-gate mdi_client_t *ct; 61027c478bd9Sstevel@tonic-gate 61037c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 61047c478bd9Sstevel@tonic-gate if (ct == NULL) 61057c478bd9Sstevel@tonic-gate return; 61067c478bd9Sstevel@tonic-gate 61077c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 61087c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 61097c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 61107c478bd9Sstevel@tonic-gate 61117c478bd9Sstevel@tonic-gate if (!ct->ct_powercnt_held) { 61127c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 61137c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig NOT held\n")); 61147c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 61157c478bd9Sstevel@tonic-gate return; 61167c478bd9Sstevel@tonic-gate } 61177c478bd9Sstevel@tonic-gate 61187c478bd9Sstevel@tonic-gate /* failure detaching or another thread just attached it */ 61197c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 61207c478bd9Sstevel@tonic-gate i_ddi_node_state(ct->ct_dip) == DS_READY) || 61217c478bd9Sstevel@tonic-gate (i_ddi_node_state(ct->ct_dip) != DS_READY && 61227c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 61237c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 61247c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig i_mdi_pm_reset_client\n")); 61257c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 61267c478bd9Sstevel@tonic-gate } 61277c478bd9Sstevel@tonic-gate 61287c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 61297c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig not changed\n")); 61307c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 61317c478bd9Sstevel@tonic-gate } 61327c478bd9Sstevel@tonic-gate 61337c478bd9Sstevel@tonic-gate static void 61347c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(dev_info_t *parent, dev_info_t *child, int held) 61357c478bd9Sstevel@tonic-gate { 61367c478bd9Sstevel@tonic-gate int circ; 61377c478bd9Sstevel@tonic-gate dev_info_t *cdip; 61387c478bd9Sstevel@tonic-gate 61397c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 61407c478bd9Sstevel@tonic-gate 61417c478bd9Sstevel@tonic-gate if (!held) { 61427c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, parent, 61437c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig held = %d\n", held)); 61447c478bd9Sstevel@tonic-gate return; 61457c478bd9Sstevel@tonic-gate } 61467c478bd9Sstevel@tonic-gate 61477c478bd9Sstevel@tonic-gate if (child) { 61487c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(child); 61497c478bd9Sstevel@tonic-gate return; 61507c478bd9Sstevel@tonic-gate } 61517c478bd9Sstevel@tonic-gate 61527c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 61537c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 61547c478bd9Sstevel@tonic-gate while (cdip) { 61557c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 61567c478bd9Sstevel@tonic-gate 61577c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(cdip); 61587c478bd9Sstevel@tonic-gate cdip = next; 61597c478bd9Sstevel@tonic-gate } 61607c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 61617c478bd9Sstevel@tonic-gate } 61627c478bd9Sstevel@tonic-gate 61637c478bd9Sstevel@tonic-gate int 61647c478bd9Sstevel@tonic-gate mdi_power(dev_info_t *vdip, mdi_pm_op_t op, void *args, char *devnm, int flags) 61657c478bd9Sstevel@tonic-gate { 61667c478bd9Sstevel@tonic-gate int circ, ret = MDI_SUCCESS; 61677c478bd9Sstevel@tonic-gate dev_info_t *client_dip = NULL; 61687c478bd9Sstevel@tonic-gate mdi_client_t *ct; 61697c478bd9Sstevel@tonic-gate 61707c478bd9Sstevel@tonic-gate /* 61717c478bd9Sstevel@tonic-gate * Handling ndi_devi_config_one and ndi_devi_unconfig_one. 61727c478bd9Sstevel@tonic-gate * Power up pHCI for the named client device. 61737c478bd9Sstevel@tonic-gate * Note: Before the client is enumerated under vhci by phci, 61747c478bd9Sstevel@tonic-gate * client_dip can be NULL. Then proceed to power up all the 61757c478bd9Sstevel@tonic-gate * pHCIs. 61767c478bd9Sstevel@tonic-gate */ 61777c478bd9Sstevel@tonic-gate if (devnm != NULL) { 61787c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circ); 61797c478bd9Sstevel@tonic-gate client_dip = ndi_devi_findchild(vdip, devnm); 61807c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circ); 61817c478bd9Sstevel@tonic-gate } 61827c478bd9Sstevel@tonic-gate 61837c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, vdip, "mdi_power op = %d\n", op)); 61847c478bd9Sstevel@tonic-gate 61857c478bd9Sstevel@tonic-gate switch (op) { 61867c478bd9Sstevel@tonic-gate case MDI_PM_PRE_CONFIG: 61877c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config(vdip, client_dip); 61887c478bd9Sstevel@tonic-gate 61897c478bd9Sstevel@tonic-gate break; 61907c478bd9Sstevel@tonic-gate case MDI_PM_PRE_UNCONFIG: 61917c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig(vdip, client_dip, (int *)args, 61927c478bd9Sstevel@tonic-gate flags); 61937c478bd9Sstevel@tonic-gate 61947c478bd9Sstevel@tonic-gate break; 61957c478bd9Sstevel@tonic-gate case MDI_PM_POST_CONFIG: 61967c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(vdip, client_dip); 61977c478bd9Sstevel@tonic-gate 61987c478bd9Sstevel@tonic-gate break; 61997c478bd9Sstevel@tonic-gate case MDI_PM_POST_UNCONFIG: 62007c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(vdip, client_dip, *(int *)args); 62017c478bd9Sstevel@tonic-gate 62027c478bd9Sstevel@tonic-gate break; 62037c478bd9Sstevel@tonic-gate case MDI_PM_HOLD_POWER: 62047c478bd9Sstevel@tonic-gate case MDI_PM_RELE_POWER: 62057c478bd9Sstevel@tonic-gate ASSERT(args); 62067c478bd9Sstevel@tonic-gate 62077c478bd9Sstevel@tonic-gate client_dip = (dev_info_t *)args; 62087c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(client_dip)); 62097c478bd9Sstevel@tonic-gate 62107c478bd9Sstevel@tonic-gate ct = i_devi_get_client(client_dip); 62117c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 62127c478bd9Sstevel@tonic-gate 62137c478bd9Sstevel@tonic-gate if (op == MDI_PM_HOLD_POWER) { 62147c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 62157c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 62167c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 62177c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_hold_client\n")); 62187c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 62197c478bd9Sstevel@tonic-gate } 62207c478bd9Sstevel@tonic-gate } else { 62217c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 62227c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 62237c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_rele_client\n")); 62247c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 62257c478bd9Sstevel@tonic-gate } else { 62267c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 62277c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_reset_client\n")); 62287c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 62297c478bd9Sstevel@tonic-gate } 62307c478bd9Sstevel@tonic-gate } 62317c478bd9Sstevel@tonic-gate 62327c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 62337c478bd9Sstevel@tonic-gate break; 62347c478bd9Sstevel@tonic-gate default: 62357c478bd9Sstevel@tonic-gate break; 62367c478bd9Sstevel@tonic-gate } 62377c478bd9Sstevel@tonic-gate 62387c478bd9Sstevel@tonic-gate return (ret); 62397c478bd9Sstevel@tonic-gate } 62407c478bd9Sstevel@tonic-gate 62417c478bd9Sstevel@tonic-gate int 62427c478bd9Sstevel@tonic-gate mdi_component_is_vhci(dev_info_t *dip, const char **mdi_class) 62437c478bd9Sstevel@tonic-gate { 62447c478bd9Sstevel@tonic-gate mdi_vhci_t *vhci; 62457c478bd9Sstevel@tonic-gate 62467c478bd9Sstevel@tonic-gate if (!MDI_VHCI(dip)) 62477c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 62487c478bd9Sstevel@tonic-gate 62497c478bd9Sstevel@tonic-gate if (mdi_class) { 62507c478bd9Sstevel@tonic-gate vhci = DEVI(dip)->devi_mdi_xhci; 62517c478bd9Sstevel@tonic-gate ASSERT(vhci); 62527c478bd9Sstevel@tonic-gate *mdi_class = vhci->vh_class; 62537c478bd9Sstevel@tonic-gate } 62547c478bd9Sstevel@tonic-gate 62557c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 62567c478bd9Sstevel@tonic-gate } 62577c478bd9Sstevel@tonic-gate 62587c478bd9Sstevel@tonic-gate int 62597c478bd9Sstevel@tonic-gate mdi_component_is_phci(dev_info_t *dip, const char **mdi_class) 62607c478bd9Sstevel@tonic-gate { 62617c478bd9Sstevel@tonic-gate mdi_phci_t *phci; 62627c478bd9Sstevel@tonic-gate 62637c478bd9Sstevel@tonic-gate if (!MDI_PHCI(dip)) 62647c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 62657c478bd9Sstevel@tonic-gate 62667c478bd9Sstevel@tonic-gate if (mdi_class) { 62677c478bd9Sstevel@tonic-gate phci = DEVI(dip)->devi_mdi_xhci; 62687c478bd9Sstevel@tonic-gate ASSERT(phci); 62697c478bd9Sstevel@tonic-gate *mdi_class = phci->ph_vhci->vh_class; 62707c478bd9Sstevel@tonic-gate } 62717c478bd9Sstevel@tonic-gate 62727c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 62737c478bd9Sstevel@tonic-gate } 62747c478bd9Sstevel@tonic-gate 62757c478bd9Sstevel@tonic-gate int 62767c478bd9Sstevel@tonic-gate mdi_component_is_client(dev_info_t *dip, const char **mdi_class) 62777c478bd9Sstevel@tonic-gate { 62787c478bd9Sstevel@tonic-gate mdi_client_t *client; 62797c478bd9Sstevel@tonic-gate 62807c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(dip)) 62817c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 62827c478bd9Sstevel@tonic-gate 62837c478bd9Sstevel@tonic-gate if (mdi_class) { 62847c478bd9Sstevel@tonic-gate client = DEVI(dip)->devi_mdi_client; 62857c478bd9Sstevel@tonic-gate ASSERT(client); 62867c478bd9Sstevel@tonic-gate *mdi_class = client->ct_vhci->vh_class; 62877c478bd9Sstevel@tonic-gate } 62887c478bd9Sstevel@tonic-gate 62897c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 62907c478bd9Sstevel@tonic-gate } 62917c478bd9Sstevel@tonic-gate 62927c478bd9Sstevel@tonic-gate /* 62937c478bd9Sstevel@tonic-gate * XXX This list should include all phci drivers needed during boot time 62947c478bd9Sstevel@tonic-gate * though it currently contains "fp" only. 62957c478bd9Sstevel@tonic-gate * Hopefully, the mechanism provided here will be replaced with a better 62967c478bd9Sstevel@tonic-gate * mechanism by vhci driven enumeration project. 62977c478bd9Sstevel@tonic-gate */ 62987c478bd9Sstevel@tonic-gate static char *phci_driver_list[] = { "fp" }; 62997c478bd9Sstevel@tonic-gate #define N_PHCI_DRIVERS (sizeof (phci_driver_list) / sizeof (char *)) 63007c478bd9Sstevel@tonic-gate 63017c478bd9Sstevel@tonic-gate static void 63027c478bd9Sstevel@tonic-gate i_mdi_attach_phci_drivers() 63037c478bd9Sstevel@tonic-gate { 63047c478bd9Sstevel@tonic-gate int i; 63057c478bd9Sstevel@tonic-gate major_t m; 63067c478bd9Sstevel@tonic-gate 63077c478bd9Sstevel@tonic-gate for (i = 0; i < N_PHCI_DRIVERS; i++) { 63087c478bd9Sstevel@tonic-gate m = ddi_name_to_major(phci_driver_list[i]); 63097c478bd9Sstevel@tonic-gate if (m != (major_t)-1) { 63107c478bd9Sstevel@tonic-gate if (ddi_hold_installed_driver(m) != NULL) 63117c478bd9Sstevel@tonic-gate ddi_rele_driver(m); 63127c478bd9Sstevel@tonic-gate } 63137c478bd9Sstevel@tonic-gate } 63147c478bd9Sstevel@tonic-gate } 63157c478bd9Sstevel@tonic-gate 63167c478bd9Sstevel@tonic-gate /* bus config the specified phci */ 63177c478bd9Sstevel@tonic-gate static void 63187c478bd9Sstevel@tonic-gate i_mdi_phci_bus_config(void *arg) 63197c478bd9Sstevel@tonic-gate { 63207c478bd9Sstevel@tonic-gate mdi_phci_config_t *phc = (mdi_phci_config_t *)arg; 63217c478bd9Sstevel@tonic-gate mdi_vhci_config_t *vhc; 63227c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 63237c478bd9Sstevel@tonic-gate int rv; 63247c478bd9Sstevel@tonic-gate 63257c478bd9Sstevel@tonic-gate ASSERT(phc); 63267c478bd9Sstevel@tonic-gate vhc = phc->phc_vhc; 63277c478bd9Sstevel@tonic-gate ASSERT(vhc->vhc_op == BUS_CONFIG_ALL || 63287c478bd9Sstevel@tonic-gate vhc->vhc_op == BUS_CONFIG_DRIVER); 63297c478bd9Sstevel@tonic-gate 63307c478bd9Sstevel@tonic-gate /* 63317c478bd9Sstevel@tonic-gate * Must have already held the phci parent in 63327c478bd9Sstevel@tonic-gate * i_mdi_bus_config_all_phcis(). 63337c478bd9Sstevel@tonic-gate * First configure the phci itself. 63347c478bd9Sstevel@tonic-gate */ 63357c478bd9Sstevel@tonic-gate rv = ndi_devi_config_one(phc->phc_parent_dip, phc->phc_devnm + 1, 63367c478bd9Sstevel@tonic-gate &ph_dip, vhc->vhc_flags); 63377c478bd9Sstevel@tonic-gate 63387c478bd9Sstevel@tonic-gate /* release the hold that i_mdi_bus_config_all_phcis() placed */ 63397c478bd9Sstevel@tonic-gate ndi_rele_devi(phc->phc_parent_dip); 63407c478bd9Sstevel@tonic-gate 63417c478bd9Sstevel@tonic-gate if (rv == NDI_SUCCESS) { 63427c478bd9Sstevel@tonic-gate /* now bus config the phci */ 63437c478bd9Sstevel@tonic-gate if (vhc->vhc_op == BUS_CONFIG_DRIVER) { 63447c478bd9Sstevel@tonic-gate (void) ndi_devi_config_driver(ph_dip, vhc->vhc_flags, 63457c478bd9Sstevel@tonic-gate vhc->vhc_major); 63467c478bd9Sstevel@tonic-gate } else 63477c478bd9Sstevel@tonic-gate (void) ndi_devi_config(ph_dip, vhc->vhc_flags); 63487c478bd9Sstevel@tonic-gate 63497c478bd9Sstevel@tonic-gate /* release the hold that ndi_devi_config_one() placed */ 63507c478bd9Sstevel@tonic-gate ndi_rele_devi(ph_dip); 63517c478bd9Sstevel@tonic-gate } 63527c478bd9Sstevel@tonic-gate } 63537c478bd9Sstevel@tonic-gate 63547c478bd9Sstevel@tonic-gate /* 63557c478bd9Sstevel@tonic-gate * Bus config all registered phcis associated with the vhci in parallel. 63567c478bd9Sstevel@tonic-gate * This process guarantees that the child nodes are enumerated under the vhci, 63577c478bd9Sstevel@tonic-gate * but not necessarily attached. 63587c478bd9Sstevel@tonic-gate * op must be BUS_CONFIG_DRIVER or BUS_CONFIG_ALL. 63597c478bd9Sstevel@tonic-gate */ 63607c478bd9Sstevel@tonic-gate static int 63617c478bd9Sstevel@tonic-gate i_mdi_bus_config_all_phcis(dev_info_t *vdip, uint_t flags, 63627c478bd9Sstevel@tonic-gate ddi_bus_config_op_t op, major_t maj, int optimize) 63637c478bd9Sstevel@tonic-gate { 63647c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 63657c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 63667c478bd9Sstevel@tonic-gate mdi_phci_config_t *phc; 63677c478bd9Sstevel@tonic-gate int64_t req_time; 63687c478bd9Sstevel@tonic-gate int phci_count, rv; 63697c478bd9Sstevel@tonic-gate static int first_time = 1; 63707c478bd9Sstevel@tonic-gate 63717c478bd9Sstevel@tonic-gate ASSERT(op == BUS_CONFIG_ALL || op == BUS_CONFIG_DRIVER); 63727c478bd9Sstevel@tonic-gate ASSERT(!DEVI_BUSY_OWNED(vdip)); 63737c478bd9Sstevel@tonic-gate 63747c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, 63757c478bd9Sstevel@tonic-gate "!MDI: %s on all phcis: major = %d, flags = 0x%x, optimize = %d\n", 63767c478bd9Sstevel@tonic-gate (op == BUS_CONFIG_DRIVER) ? "BUS_CONFIG_DRIVER" : "BUS_CONFIG_ALL", 63777c478bd9Sstevel@tonic-gate (int)maj, flags, optimize)); 63787c478bd9Sstevel@tonic-gate 63797c478bd9Sstevel@tonic-gate vh = i_devi_get_vhci(vdip); 63807c478bd9Sstevel@tonic-gate ASSERT(vh); 63817c478bd9Sstevel@tonic-gate 63827c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 63837c478bd9Sstevel@tonic-gate 63847c478bd9Sstevel@tonic-gate req_time = lbolt64; 63857c478bd9Sstevel@tonic-gate 63867c478bd9Sstevel@tonic-gate /* 63877c478bd9Sstevel@tonic-gate * Reduce unnecessary BUS_CONFIG_ALLs when opening stale 63887c478bd9Sstevel@tonic-gate * /dev/[r]dsk links. 63897c478bd9Sstevel@tonic-gate */ 63907c478bd9Sstevel@tonic-gate if (optimize && (req_time < vh->vh_bus_config.vhc_cutoff_time)) { 63917c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 63927c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 63937c478bd9Sstevel@tonic-gate } 63947c478bd9Sstevel@tonic-gate 63957c478bd9Sstevel@tonic-gate /* 63967c478bd9Sstevel@tonic-gate * To initiate bus configs on all phcis in parallel, create a taskq 63977c478bd9Sstevel@tonic-gate * with multiple threads. Since creation of a taskq is a heavy weight 63987c478bd9Sstevel@tonic-gate * operation, taskq is created once per vhci and destroyed only when 63997c478bd9Sstevel@tonic-gate * vhci unregisters with mdi. 64007c478bd9Sstevel@tonic-gate * 64017c478bd9Sstevel@tonic-gate * If multiple bus config requests arrive at a time, bus configs on 64027c478bd9Sstevel@tonic-gate * phcis are initiated on behalf of one of the requests. Other requests 64037c478bd9Sstevel@tonic-gate * wait until the bus configs on phcis is done. 64047c478bd9Sstevel@tonic-gate * 64057c478bd9Sstevel@tonic-gate * When a BUS_CONFIG_ALL on phcis completes, the following is done 64067c478bd9Sstevel@tonic-gate * to avoid more of unnecessary bus configs. 64077c478bd9Sstevel@tonic-gate * 64087c478bd9Sstevel@tonic-gate * o all BUS_CONFIG_ALL requests currently waiting with optimize 64097c478bd9Sstevel@tonic-gate * flag set are returned, i.e., no new BUS_CONFIG_ALL is initiated 64107c478bd9Sstevel@tonic-gate * on phcis on behalf of these requests. 64117c478bd9Sstevel@tonic-gate * 64127c478bd9Sstevel@tonic-gate * o all BUS_CONFIG_ALL or BUS_CONFIG_DRIVER requests currently 64137c478bd9Sstevel@tonic-gate * waiting but have arrived prior to initiating BUS_CONFIG_ALL on 64147c478bd9Sstevel@tonic-gate * phcis are also returned. 64157c478bd9Sstevel@tonic-gate * 64167c478bd9Sstevel@tonic-gate * In other cases a new BUS_CONFIG_ALL or BUS_CONFIG_DRIVER is 64177c478bd9Sstevel@tonic-gate * initiated on phcis on behalf of a new request. 64187c478bd9Sstevel@tonic-gate */ 64197c478bd9Sstevel@tonic-gate 64207c478bd9Sstevel@tonic-gate /* check if a bus config on phcis is in progress */ 64217c478bd9Sstevel@tonic-gate while (vh->vh_bus_config.vhc_start_time != 0) { 64227c478bd9Sstevel@tonic-gate ddi_bus_config_op_t current_op; 64237c478bd9Sstevel@tonic-gate int64_t start_time; 64247c478bd9Sstevel@tonic-gate 64257c478bd9Sstevel@tonic-gate current_op = vh->vh_bus_config.vhc_op; 64267c478bd9Sstevel@tonic-gate start_time = vh->vh_bus_config.vhc_start_time; 64277c478bd9Sstevel@tonic-gate 64287c478bd9Sstevel@tonic-gate /* wait until the current bus configs on phcis are done */ 64297c478bd9Sstevel@tonic-gate while (vh->vh_bus_config.vhc_start_time == start_time) 64307c478bd9Sstevel@tonic-gate cv_wait(&vh->vh_bus_config.vhc_cv, &mdi_mutex); 64317c478bd9Sstevel@tonic-gate 64327c478bd9Sstevel@tonic-gate if (current_op == BUS_CONFIG_ALL && 64337c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_cutoff_time > 0 && (optimize || 64347c478bd9Sstevel@tonic-gate req_time < start_time)) { 64357c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 64367c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 64377c478bd9Sstevel@tonic-gate } 64387c478bd9Sstevel@tonic-gate } 64397c478bd9Sstevel@tonic-gate 64407c478bd9Sstevel@tonic-gate /* 64417c478bd9Sstevel@tonic-gate * At this point we are single threaded until vh_bus_config.start_time 64427c478bd9Sstevel@tonic-gate * is reset to 0 at the end of this function. 64437c478bd9Sstevel@tonic-gate */ 64447c478bd9Sstevel@tonic-gate 64457c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_op = op; 64467c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_major = maj; 64477c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_flags = flags; 64487c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_start_time = lbolt64; 64497c478bd9Sstevel@tonic-gate 64507c478bd9Sstevel@tonic-gate if (first_time && strcmp(vh->vh_class, MDI_HCI_CLASS_SCSI) == 0) { 64517c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 64527c478bd9Sstevel@tonic-gate i_mdi_attach_phci_drivers(); 64537c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 64547c478bd9Sstevel@tonic-gate first_time = 0; 64557c478bd9Sstevel@tonic-gate } 64567c478bd9Sstevel@tonic-gate 64577c478bd9Sstevel@tonic-gate ASSERT(vh->vh_phci_count >= 0); 64587c478bd9Sstevel@tonic-gate if (vh->vh_phci_count == 0) { 64597c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 64607c478bd9Sstevel@tonic-gate goto out1; 64617c478bd9Sstevel@tonic-gate } 64627c478bd9Sstevel@tonic-gate 64637c478bd9Sstevel@tonic-gate /* 64647c478bd9Sstevel@tonic-gate * Create a taskq to initiate bus configs in parallel on phcis. 64657c478bd9Sstevel@tonic-gate * Taskq allocation can be done in mdi_vhci_register() routine 64667c478bd9Sstevel@tonic-gate * instead of here. For most systems, doing it here on demand saves 64677c478bd9Sstevel@tonic-gate * resources as this code path is never called most of the times. 64687c478bd9Sstevel@tonic-gate */ 64697c478bd9Sstevel@tonic-gate if (vh->vh_bus_config.vhc_taskq == NULL) { 64707c478bd9Sstevel@tonic-gate /* 64717c478bd9Sstevel@tonic-gate * it is ok even if vh->vh_phci_count changes after we release 64727c478bd9Sstevel@tonic-gate * the mdi_mutex as phci_count is used just as an 64737c478bd9Sstevel@tonic-gate * advisory number to taskq_create. 64747c478bd9Sstevel@tonic-gate */ 64757c478bd9Sstevel@tonic-gate phci_count = vh->vh_phci_count; 64767c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 64777c478bd9Sstevel@tonic-gate 64787c478bd9Sstevel@tonic-gate /* 64797c478bd9Sstevel@tonic-gate * As we are single threaded, it is ok to access the 64807c478bd9Sstevel@tonic-gate * vh_bus_config.taskq member of vh outside of mdi_mutex 64817c478bd9Sstevel@tonic-gate */ 64827c478bd9Sstevel@tonic-gate if ((vh->vh_bus_config.vhc_taskq = taskq_create( 64837c478bd9Sstevel@tonic-gate "mdi_bus_config_taskq", mdi_max_bus_config_threads, 64847c478bd9Sstevel@tonic-gate MDI_TASKQ_PRI, phci_count, INT_MAX, 64857c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE | TASKQ_DYNAMIC)) == NULL) { 64867c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 64877c478bd9Sstevel@tonic-gate goto out; 64887c478bd9Sstevel@tonic-gate } 64897c478bd9Sstevel@tonic-gate 64907c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 64917c478bd9Sstevel@tonic-gate } 64927c478bd9Sstevel@tonic-gate 64937c478bd9Sstevel@tonic-gate /* allocate at least vh->vh_phci_count phci bus config structures */ 64947c478bd9Sstevel@tonic-gate while (vh->vh_bus_config.vhc_phc_cnt < vh->vh_phci_count) { 64957c478bd9Sstevel@tonic-gate int count; 64967c478bd9Sstevel@tonic-gate 64977c478bd9Sstevel@tonic-gate count = vh->vh_phci_count - vh->vh_bus_config.vhc_phc_cnt; 64987c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 64997c478bd9Sstevel@tonic-gate while (count--) { 65007c478bd9Sstevel@tonic-gate phc = kmem_alloc(sizeof (*phc), KM_SLEEP); 65017c478bd9Sstevel@tonic-gate phc->phc_vhc = &vh->vh_bus_config; 65027c478bd9Sstevel@tonic-gate /* 65037c478bd9Sstevel@tonic-gate * there is no need to hold a lock here as we 65047c478bd9Sstevel@tonic-gate * are single threaded and no one else manipulates 65057c478bd9Sstevel@tonic-gate * the list while we are here. 65067c478bd9Sstevel@tonic-gate */ 65077c478bd9Sstevel@tonic-gate phc->phc_next = vh->vh_bus_config.vhc_phc; 65087c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc = phc; 65097c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc_cnt++; 65107c478bd9Sstevel@tonic-gate } 65117c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 65127c478bd9Sstevel@tonic-gate /* 65137c478bd9Sstevel@tonic-gate * as new phcis could register with mdi after we dropped 65147c478bd9Sstevel@tonic-gate * the mdi_mutex, we need to recheck the vh->vh_phci_count. 65157c478bd9Sstevel@tonic-gate * Hence the while loop. 65167c478bd9Sstevel@tonic-gate */ 65177c478bd9Sstevel@tonic-gate } 65187c478bd9Sstevel@tonic-gate 65197c478bd9Sstevel@tonic-gate for (ph = vh->vh_phci_head, phc = vh->vh_bus_config.vhc_phc; 65207c478bd9Sstevel@tonic-gate ph != NULL; ph = ph->ph_next, phc = phc->phc_next) { 65217c478bd9Sstevel@tonic-gate 65227c478bd9Sstevel@tonic-gate ASSERT(phc != NULL); 65237c478bd9Sstevel@tonic-gate 65247c478bd9Sstevel@tonic-gate /* build a phci config handle to be passed to a taskq thread */ 65257c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 65267c478bd9Sstevel@tonic-gate ASSERT(ph->ph_dip); 65277c478bd9Sstevel@tonic-gate 65287c478bd9Sstevel@tonic-gate /* 65297c478bd9Sstevel@tonic-gate * We need to hold the phci dip before bus configuring the phci. 65307c478bd9Sstevel@tonic-gate * But placing a hold on the phci dip is not safe here due to 65317c478bd9Sstevel@tonic-gate * the race with phci detach. To get around this race, 65327c478bd9Sstevel@tonic-gate * we place a hold on the phci dip's parent and note down 65337c478bd9Sstevel@tonic-gate * the phci's name@addr. Later, in i_mdi_phci_bus_config(), 65347c478bd9Sstevel@tonic-gate * we'll first configure the phci itself before bus 65357c478bd9Sstevel@tonic-gate * configuring the phci. 65367c478bd9Sstevel@tonic-gate */ 65377c478bd9Sstevel@tonic-gate phc->phc_parent_dip = ddi_get_parent(ph->ph_dip); 65387c478bd9Sstevel@tonic-gate ndi_hold_devi(phc->phc_parent_dip); 65397c478bd9Sstevel@tonic-gate (void) ddi_deviname(ph->ph_dip, phc->phc_devnm); 65407c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 65417c478bd9Sstevel@tonic-gate } 65427c478bd9Sstevel@tonic-gate 65437c478bd9Sstevel@tonic-gate phci_count = vh->vh_phci_count; 65447c478bd9Sstevel@tonic-gate if (vh->vh_bus_config.vhc_cutoff_time == -1) 65457c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_cutoff_time = 0; 65467c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 65477c478bd9Sstevel@tonic-gate 65487c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, 65497c478bd9Sstevel@tonic-gate "!MDI: initiating %s on all phcis, major = %d, flags = 0x%x\n", 65507c478bd9Sstevel@tonic-gate (op == BUS_CONFIG_DRIVER) ? "BUS_CONFIG_DRIVER" : "BUS_CONFIG_ALL", 65517c478bd9Sstevel@tonic-gate (int)maj, flags)); 65527c478bd9Sstevel@tonic-gate 65537c478bd9Sstevel@tonic-gate /* 65547c478bd9Sstevel@tonic-gate * again, no need to hold a lock here as we are single threaded and 65557c478bd9Sstevel@tonic-gate * no one else manipulates the list while we are here. 65567c478bd9Sstevel@tonic-gate */ 65577c478bd9Sstevel@tonic-gate for (phc = vh->vh_bus_config.vhc_phc; phci_count--; 65587c478bd9Sstevel@tonic-gate phc = phc->phc_next) { 65597c478bd9Sstevel@tonic-gate (void) taskq_dispatch(vh->vh_bus_config.vhc_taskq, 65607c478bd9Sstevel@tonic-gate i_mdi_phci_bus_config, phc, TQ_SLEEP); 65617c478bd9Sstevel@tonic-gate } 65627c478bd9Sstevel@tonic-gate 65637c478bd9Sstevel@tonic-gate /* wait until all phci bus configs are done */ 65647c478bd9Sstevel@tonic-gate taskq_wait(vh->vh_bus_config.vhc_taskq); 65657c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 65667c478bd9Sstevel@tonic-gate 65677c478bd9Sstevel@tonic-gate out: 65687c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 65697c478bd9Sstevel@tonic-gate out1: 65707c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_start_time = 0; 65717c478bd9Sstevel@tonic-gate if (op == BUS_CONFIG_ALL && vh->vh_bus_config.vhc_cutoff_time != -1) { 65727c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_cutoff_time = lbolt64 + 65737c478bd9Sstevel@tonic-gate (int64_t)drv_usectohz(mdi_bus_config_timeout * 1000000); 65747c478bd9Sstevel@tonic-gate } 65757c478bd9Sstevel@tonic-gate cv_broadcast(&vh->vh_bus_config.vhc_cv); 65767c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 65777c478bd9Sstevel@tonic-gate 65787c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, "!MDI: %s on all phcis %s\n", 65797c478bd9Sstevel@tonic-gate (op == BUS_CONFIG_DRIVER) ? "BUS_CONFIG_DRIVER" : "BUS_CONFIG_ALL", 65807c478bd9Sstevel@tonic-gate (rv == MDI_SUCCESS) ? "successful" : "failed")); 65817c478bd9Sstevel@tonic-gate 65827c478bd9Sstevel@tonic-gate return (rv); 65837c478bd9Sstevel@tonic-gate } 65847c478bd9Sstevel@tonic-gate 65857c478bd9Sstevel@tonic-gate /* 65867c478bd9Sstevel@tonic-gate * A simple bus config implementation for vhcis with the assumption that all 65877c478bd9Sstevel@tonic-gate * phcis are always registered with MDI. 65887c478bd9Sstevel@tonic-gate * 65897c478bd9Sstevel@tonic-gate * BUS_CONFIG_ALL 65907c478bd9Sstevel@tonic-gate * 65917c478bd9Sstevel@tonic-gate * Do BUS_CONFIG_ALL on all phcis associated with the vhci. 65927c478bd9Sstevel@tonic-gate * 65937c478bd9Sstevel@tonic-gate * BUS_CONFIG_DRIVER 65947c478bd9Sstevel@tonic-gate * 65957c478bd9Sstevel@tonic-gate * Do BUS_CONFIG_DRIVER on all phcis associated with the vhci. 65967c478bd9Sstevel@tonic-gate * 65977c478bd9Sstevel@tonic-gate * BUS_CONFIG_ONE 65987c478bd9Sstevel@tonic-gate * 65997c478bd9Sstevel@tonic-gate * If the requested child has already been enumerated under the vhci 66007c478bd9Sstevel@tonic-gate * configure the child and return. Otherwise do BUS_CONFIG_ALL on all 66017c478bd9Sstevel@tonic-gate * phcis associated with the vhci. 66027c478bd9Sstevel@tonic-gate */ 66037c478bd9Sstevel@tonic-gate int 66047c478bd9Sstevel@tonic-gate mdi_vhci_bus_config(dev_info_t *vdip, uint_t flags, ddi_bus_config_op_t op, 66057c478bd9Sstevel@tonic-gate void *arg, dev_info_t **child) 66067c478bd9Sstevel@tonic-gate { 66077c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 66087c478bd9Sstevel@tonic-gate 66097c478bd9Sstevel@tonic-gate /* 66107c478bd9Sstevel@tonic-gate * While bus configuring phcis, the phci driver interactions with MDI 66117c478bd9Sstevel@tonic-gate * cause child nodes to be enumerated under the vhci node for which 66127c478bd9Sstevel@tonic-gate * they need to ndi_devi_enter the vhci node. 66137c478bd9Sstevel@tonic-gate * 66147c478bd9Sstevel@tonic-gate * Unfortunately, to avoid the deadlock, we ourself can not wait for 66157c478bd9Sstevel@tonic-gate * for the bus config operations on phcis to finish while holding the 66167c478bd9Sstevel@tonic-gate * ndi_devi_enter lock. To avoid this deadlock, skip bus configs on 66177c478bd9Sstevel@tonic-gate * phcis and call the default framework provided bus config function 66187c478bd9Sstevel@tonic-gate * if we are called with ndi_devi_enter lock held. 66197c478bd9Sstevel@tonic-gate */ 66207c478bd9Sstevel@tonic-gate if (DEVI_BUSY_OWNED(vdip)) { 66217c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, 66227c478bd9Sstevel@tonic-gate "!MDI: vhci bus config: vhci dip is busy owned\n")); 66237c478bd9Sstevel@tonic-gate goto default_bus_config; 66247c478bd9Sstevel@tonic-gate } 66257c478bd9Sstevel@tonic-gate 66267c478bd9Sstevel@tonic-gate switch (op) { 66277c478bd9Sstevel@tonic-gate case BUS_CONFIG_ONE: 66287c478bd9Sstevel@tonic-gate /* 66297c478bd9Sstevel@tonic-gate * First try to directly configure the requested child. 66307c478bd9Sstevel@tonic-gate * This will work only if the requested child has already 66317c478bd9Sstevel@tonic-gate * been enumerated under vhci, which is usually the most common 66327c478bd9Sstevel@tonic-gate * case. 66337c478bd9Sstevel@tonic-gate */ 66347c478bd9Sstevel@tonic-gate if (ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 66357c478bd9Sstevel@tonic-gate NDI_SUCCESS) { 66367c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 66377c478bd9Sstevel@tonic-gate } 66387c478bd9Sstevel@tonic-gate 66397c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, "!MDI: BUS_CONFIG_ONE on %s: " 66407c478bd9Sstevel@tonic-gate "will do BUS_CONFIG_ALL on all phcis\n", (char *)arg)); 66417c478bd9Sstevel@tonic-gate 66427c478bd9Sstevel@tonic-gate /* now do BUS_CONFIG_ALL on all phcis */ 66437c478bd9Sstevel@tonic-gate rv = i_mdi_bus_config_all_phcis(vdip, flags, 66447c478bd9Sstevel@tonic-gate BUS_CONFIG_ALL, -1, 1); 66457c478bd9Sstevel@tonic-gate break; 66467c478bd9Sstevel@tonic-gate 66477c478bd9Sstevel@tonic-gate case BUS_CONFIG_DRIVER: 66487c478bd9Sstevel@tonic-gate rv = i_mdi_bus_config_all_phcis(vdip, flags, op, 66497c478bd9Sstevel@tonic-gate (major_t)(uintptr_t)arg, 0); 66507c478bd9Sstevel@tonic-gate break; 66517c478bd9Sstevel@tonic-gate 66527c478bd9Sstevel@tonic-gate case BUS_CONFIG_ALL: 66537c478bd9Sstevel@tonic-gate rv = i_mdi_bus_config_all_phcis(vdip, flags, op, -1, 0); 66547c478bd9Sstevel@tonic-gate break; 66557c478bd9Sstevel@tonic-gate 66567c478bd9Sstevel@tonic-gate default: 66577c478bd9Sstevel@tonic-gate break; 66587c478bd9Sstevel@tonic-gate } 66597c478bd9Sstevel@tonic-gate 66607c478bd9Sstevel@tonic-gate default_bus_config: 66617c478bd9Sstevel@tonic-gate /* 66627c478bd9Sstevel@tonic-gate * i_mdi_bus_config_all_phcis() guarantees that child nodes are 66637c478bd9Sstevel@tonic-gate * enumerated under the vhci, but not necessarily attached. 66647c478bd9Sstevel@tonic-gate * Now configure the appropriate child nodes. 66657c478bd9Sstevel@tonic-gate */ 66667c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS && 66677c478bd9Sstevel@tonic-gate ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 66687c478bd9Sstevel@tonic-gate NDI_SUCCESS) { 66697c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 66707c478bd9Sstevel@tonic-gate } 66717c478bd9Sstevel@tonic-gate 66727c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 66737c478bd9Sstevel@tonic-gate } 66747c478bd9Sstevel@tonic-gate 66757c478bd9Sstevel@tonic-gate 66767c478bd9Sstevel@tonic-gate void * 66777c478bd9Sstevel@tonic-gate mdi_client_get_vhci_private(dev_info_t *dip) 66787c478bd9Sstevel@tonic-gate { 66797c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 66807c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 66817c478bd9Sstevel@tonic-gate mdi_client_t *ct; 66827c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 66837c478bd9Sstevel@tonic-gate return (ct->ct_vprivate); 66847c478bd9Sstevel@tonic-gate } 66857c478bd9Sstevel@tonic-gate return (NULL); 66867c478bd9Sstevel@tonic-gate } 66877c478bd9Sstevel@tonic-gate 66887c478bd9Sstevel@tonic-gate void 66897c478bd9Sstevel@tonic-gate mdi_client_set_vhci_private(dev_info_t *dip, void *data) 66907c478bd9Sstevel@tonic-gate { 66917c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 66927c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 66937c478bd9Sstevel@tonic-gate mdi_client_t *ct; 66947c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 66957c478bd9Sstevel@tonic-gate ct->ct_vprivate = data; 66967c478bd9Sstevel@tonic-gate } 66977c478bd9Sstevel@tonic-gate } 66987c478bd9Sstevel@tonic-gate /* 66997c478bd9Sstevel@tonic-gate * mdi_pi_get_vhci_private(): 67007c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 67017c478bd9Sstevel@tonic-gate * mdi_pathinfo node 67027c478bd9Sstevel@tonic-gate */ 67037c478bd9Sstevel@tonic-gate void * 67047c478bd9Sstevel@tonic-gate mdi_pi_get_vhci_private(mdi_pathinfo_t *pip) 67057c478bd9Sstevel@tonic-gate { 67067c478bd9Sstevel@tonic-gate caddr_t vprivate = NULL; 67077c478bd9Sstevel@tonic-gate if (pip) { 67087c478bd9Sstevel@tonic-gate vprivate = MDI_PI(pip)->pi_vprivate; 67097c478bd9Sstevel@tonic-gate } 67107c478bd9Sstevel@tonic-gate return (vprivate); 67117c478bd9Sstevel@tonic-gate } 67127c478bd9Sstevel@tonic-gate 67137c478bd9Sstevel@tonic-gate /* 67147c478bd9Sstevel@tonic-gate * mdi_pi_set_vhci_private(): 67157c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_pathinfo node 67167c478bd9Sstevel@tonic-gate */ 67177c478bd9Sstevel@tonic-gate void 67187c478bd9Sstevel@tonic-gate mdi_pi_set_vhci_private(mdi_pathinfo_t *pip, void *priv) 67197c478bd9Sstevel@tonic-gate { 67207c478bd9Sstevel@tonic-gate if (pip) { 67217c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = priv; 67227c478bd9Sstevel@tonic-gate } 67237c478bd9Sstevel@tonic-gate } 67247c478bd9Sstevel@tonic-gate 67257c478bd9Sstevel@tonic-gate /* 67267c478bd9Sstevel@tonic-gate * mdi_phci_get_vhci_private(): 67277c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 67287c478bd9Sstevel@tonic-gate * mdi_phci node 67297c478bd9Sstevel@tonic-gate */ 67307c478bd9Sstevel@tonic-gate void * 67317c478bd9Sstevel@tonic-gate mdi_phci_get_vhci_private(dev_info_t *dip) 67327c478bd9Sstevel@tonic-gate { 67337c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 67347c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 67357c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 67367c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 67377c478bd9Sstevel@tonic-gate return (ph->ph_vprivate); 67387c478bd9Sstevel@tonic-gate } 67397c478bd9Sstevel@tonic-gate return (NULL); 67407c478bd9Sstevel@tonic-gate } 67417c478bd9Sstevel@tonic-gate 67427c478bd9Sstevel@tonic-gate /* 67437c478bd9Sstevel@tonic-gate * mdi_phci_set_vhci_private(): 67447c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_phci node 67457c478bd9Sstevel@tonic-gate */ 67467c478bd9Sstevel@tonic-gate void 67477c478bd9Sstevel@tonic-gate mdi_phci_set_vhci_private(dev_info_t *dip, void *priv) 67487c478bd9Sstevel@tonic-gate { 67497c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 67507c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 67517c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 67527c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 67537c478bd9Sstevel@tonic-gate ph->ph_vprivate = priv; 67547c478bd9Sstevel@tonic-gate } 67557c478bd9Sstevel@tonic-gate } 6756