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 5ee28b439Scm136836 * Common Development and Distribution License (the "License"). 6ee28b439Scm136836 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22bf002425SStephen Hanson * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 267c478bd9Sstevel@tonic-gate * Multipath driver interface (MDI) implementation; see mdi_impl.h for a more 277c478bd9Sstevel@tonic-gate * detailed discussion of the overall mpxio architecture. 287c478bd9Sstevel@tonic-gate * 297c478bd9Sstevel@tonic-gate * Default locking order: 307c478bd9Sstevel@tonic-gate * 315e3986cbScth * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_phci_mutex); 325e3986cbScth * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_client_mutex); 335e3986cbScth * _NOTE(LOCK_ORDER(mdi_vhci:vh_phci_mutex, mdi_phci::ph_mutex); 345e3986cbScth * _NOTE(LOCK_ORDER(mdi_vhci:vh_client_mutex, mdi_client::ct_mutex); 357c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 367c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex)) 377c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <sys/note.h> 417c478bd9Sstevel@tonic-gate #include <sys/types.h> 427c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 437c478bd9Sstevel@tonic-gate #include <sys/param.h> 447c478bd9Sstevel@tonic-gate #include <sys/errno.h> 457c478bd9Sstevel@tonic-gate #include <sys/uio.h> 467c478bd9Sstevel@tonic-gate #include <sys/buf.h> 477c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 487c478bd9Sstevel@tonic-gate #include <sys/open.h> 497c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 507c478bd9Sstevel@tonic-gate #include <sys/poll.h> 517c478bd9Sstevel@tonic-gate #include <sys/conf.h> 527c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 537c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 547c478bd9Sstevel@tonic-gate #include <sys/stat.h> 557c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 567c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 577c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h> 587c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 597c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 607c478bd9Sstevel@tonic-gate #include <sys/promif.h> 617c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h> 627c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h> 637c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 647c478bd9Sstevel@tonic-gate #include <sys/epm.h> 657c478bd9Sstevel@tonic-gate #include <sys/sunpm.h> 663c34adc5Sramat #include <sys/modhash.h> 678c4f8890Srs135747 #include <sys/disp.h> 688c4f8890Srs135747 #include <sys/autoconf.h> 69f7209cf2Spramodbg #include <sys/sysmacros.h> 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate #ifdef DEBUG 727c478bd9Sstevel@tonic-gate #include <sys/debug.h> 737c478bd9Sstevel@tonic-gate int mdi_debug = 1; 745e3986cbScth int mdi_debug_logonly = 0; 754c06356bSdh142964 #define MDI_DEBUG(dbglevel, pargs) if (mdi_debug >= (dbglevel)) i_mdi_log pargs 764c06356bSdh142964 #define MDI_WARN CE_WARN, __func__ 774c06356bSdh142964 #define MDI_NOTE CE_NOTE, __func__ 784c06356bSdh142964 #define MDI_CONT CE_CONT, __func__ 794c06356bSdh142964 static void i_mdi_log(int, const char *, dev_info_t *, const char *, ...); 807c478bd9Sstevel@tonic-gate #else /* !DEBUG */ 814c06356bSdh142964 #define MDI_DEBUG(dbglevel, pargs) 827c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 834c06356bSdh142964 int mdi_debug_consoleonly = 0; 8496c4a178SChris Horne int mdi_delay = 3; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; 877c478bd9Sstevel@tonic-gate extern int modrootloaded; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * Global mutex: 915e3986cbScth * Protects vHCI list and structure members. 927c478bd9Sstevel@tonic-gate */ 937c478bd9Sstevel@tonic-gate kmutex_t mdi_mutex; 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * Registered vHCI class driver lists 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate int mdi_vhci_count; 997c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_head; 1007c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_tail; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * Client Hash Table size 1047c478bd9Sstevel@tonic-gate */ 1057c478bd9Sstevel@tonic-gate static int mdi_client_table_size = CLIENT_HASH_TABLE_SIZE; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * taskq interface definitions 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate #define MDI_TASKQ_N_THREADS 8 1117c478bd9Sstevel@tonic-gate #define MDI_TASKQ_PRI minclsyspri 1127c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MINALLOC (4*mdi_taskq_n_threads) 1137c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MAXALLOC (500*mdi_taskq_n_threads) 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate taskq_t *mdi_taskq; 1167c478bd9Sstevel@tonic-gate static uint_t mdi_taskq_n_threads = MDI_TASKQ_N_THREADS; 1177c478bd9Sstevel@tonic-gate 1183c34adc5Sramat #define TICKS_PER_SECOND (drv_usectohz(1000000)) 1193c34adc5Sramat 1207c478bd9Sstevel@tonic-gate /* 1213c34adc5Sramat * The data should be "quiet" for this interval (in seconds) before the 1223c34adc5Sramat * vhci cached data is flushed to the disk. 1237c478bd9Sstevel@tonic-gate */ 1243c34adc5Sramat static int mdi_vhcache_flush_delay = 10; 1253c34adc5Sramat 1263c34adc5Sramat /* number of seconds the vhcache flush daemon will sleep idle before exiting */ 1273c34adc5Sramat static int mdi_vhcache_flush_daemon_idle_time = 60; 1283c34adc5Sramat 1293c34adc5Sramat /* 13067e56d35Sramat * MDI falls back to discovery of all paths when a bus_config_one fails. 13167e56d35Sramat * The following parameters can be used to tune this operation. 13267e56d35Sramat * 13367e56d35Sramat * mdi_path_discovery_boot 13467e56d35Sramat * Number of times path discovery will be attempted during early boot. 13567e56d35Sramat * Probably there is no reason to ever set this value to greater than one. 13667e56d35Sramat * 13767e56d35Sramat * mdi_path_discovery_postboot 13867e56d35Sramat * Number of times path discovery will be attempted after early boot. 13967e56d35Sramat * Set it to a minimum of two to allow for discovery of iscsi paths which 14067e56d35Sramat * may happen very late during booting. 14167e56d35Sramat * 14267e56d35Sramat * mdi_path_discovery_interval 14367e56d35Sramat * Minimum number of seconds MDI will wait between successive discovery 14467e56d35Sramat * of all paths. Set it to -1 to disable discovery of all paths. 14567e56d35Sramat */ 14667e56d35Sramat static int mdi_path_discovery_boot = 1; 14767e56d35Sramat static int mdi_path_discovery_postboot = 2; 14867e56d35Sramat static int mdi_path_discovery_interval = 10; 14967e56d35Sramat 15067e56d35Sramat /* 1513c34adc5Sramat * number of seconds the asynchronous configuration thread will sleep idle 1523c34adc5Sramat * before exiting. 1533c34adc5Sramat */ 1543c34adc5Sramat static int mdi_async_config_idle_time = 600; 1553c34adc5Sramat 1563c34adc5Sramat static int mdi_bus_config_cache_hash_size = 256; 1573c34adc5Sramat 1583c34adc5Sramat /* turns off multithreaded configuration for certain operations */ 1593c34adc5Sramat static int mdi_mtc_off = 0; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 162602ca9eaScth * The "path" to a pathinfo node is identical to the /devices path to a 163602ca9eaScth * devinfo node had the device been enumerated under a pHCI instead of 164602ca9eaScth * a vHCI. This pathinfo "path" is associated with a 'path_instance'. 165602ca9eaScth * This association persists across create/delete of the pathinfo nodes, 166602ca9eaScth * but not across reboot. 167602ca9eaScth */ 168602ca9eaScth static uint_t mdi_pathmap_instance = 1; /* 0 -> any path */ 169602ca9eaScth static int mdi_pathmap_hash_size = 256; 170602ca9eaScth static kmutex_t mdi_pathmap_mutex; 171602ca9eaScth static mod_hash_t *mdi_pathmap_bypath; /* "path"->instance */ 172602ca9eaScth static mod_hash_t *mdi_pathmap_byinstance; /* instance->"path" */ 1734c06356bSdh142964 static mod_hash_t *mdi_pathmap_sbyinstance; /* inst->shortpath */ 174602ca9eaScth 175602ca9eaScth /* 1767c478bd9Sstevel@tonic-gate * MDI component property name/value string definitions 1777c478bd9Sstevel@tonic-gate */ 1787c478bd9Sstevel@tonic-gate const char *mdi_component_prop = "mpxio-component"; 1797c478bd9Sstevel@tonic-gate const char *mdi_component_prop_vhci = "vhci"; 1807c478bd9Sstevel@tonic-gate const char *mdi_component_prop_phci = "phci"; 1817c478bd9Sstevel@tonic-gate const char *mdi_component_prop_client = "client"; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate /* 1847c478bd9Sstevel@tonic-gate * MDI client global unique identifier property name 1857c478bd9Sstevel@tonic-gate */ 1867c478bd9Sstevel@tonic-gate const char *mdi_client_guid_prop = "client-guid"; 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * MDI client load balancing property name/value string definitions 1907c478bd9Sstevel@tonic-gate */ 1917c478bd9Sstevel@tonic-gate const char *mdi_load_balance = "load-balance"; 1927c478bd9Sstevel@tonic-gate const char *mdi_load_balance_none = "none"; 1937c478bd9Sstevel@tonic-gate const char *mdi_load_balance_rr = "round-robin"; 1947c478bd9Sstevel@tonic-gate const char *mdi_load_balance_lba = "logical-block"; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * Obsolete vHCI class definition; to be removed after Leadville update 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate const char *mdi_vhci_class_scsi = MDI_HCI_CLASS_SCSI; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate static char vhci_greeting[] = 2027c478bd9Sstevel@tonic-gate "\tThere already exists one vHCI driver for class %s\n" 2037c478bd9Sstevel@tonic-gate "\tOnly one vHCI driver for each class is allowed\n"; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * Static function prototypes 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate static int i_mdi_phci_offline(dev_info_t *, uint_t); 2097c478bd9Sstevel@tonic-gate static int i_mdi_client_offline(dev_info_t *, uint_t); 2107c478bd9Sstevel@tonic-gate static int i_mdi_phci_pre_detach(dev_info_t *, ddi_detach_cmd_t); 2117c478bd9Sstevel@tonic-gate static void i_mdi_phci_post_detach(dev_info_t *, 2127c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 2137c478bd9Sstevel@tonic-gate static int i_mdi_client_pre_detach(dev_info_t *, 2147c478bd9Sstevel@tonic-gate ddi_detach_cmd_t); 2157c478bd9Sstevel@tonic-gate static void i_mdi_client_post_detach(dev_info_t *, 2167c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 2177c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_pip(mdi_pathinfo_t *); 2187c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_pip(mdi_pathinfo_t *); 2197c478bd9Sstevel@tonic-gate static int i_mdi_lba_lb(mdi_client_t *ct, 2207c478bd9Sstevel@tonic-gate mdi_pathinfo_t **ret_pip, struct buf *buf); 2217c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_client(mdi_client_t *, int); 2227c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_client(mdi_client_t *, int); 2237c478bd9Sstevel@tonic-gate static void i_mdi_pm_reset_client(mdi_client_t *); 2247c478bd9Sstevel@tonic-gate static int i_mdi_power_all_phci(mdi_client_t *); 2258c4f8890Srs135747 static void i_mdi_log_sysevent(dev_info_t *, char *, char *); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * Internal mdi_pathinfo node functions 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate static void i_mdi_pi_kstat_destroy(mdi_pathinfo_t *); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_mdi_vhci_class2vhci(char *); 2347c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_devi_get_vhci(dev_info_t *); 2357c478bd9Sstevel@tonic-gate static mdi_phci_t *i_devi_get_phci(dev_info_t *); 2367c478bd9Sstevel@tonic-gate static void i_mdi_phci_lock(mdi_phci_t *, mdi_pathinfo_t *); 2377c478bd9Sstevel@tonic-gate static void i_mdi_phci_unlock(mdi_phci_t *); 2383c34adc5Sramat static mdi_pathinfo_t *i_mdi_pi_alloc(mdi_phci_t *, char *, mdi_client_t *); 2397c478bd9Sstevel@tonic-gate static void i_mdi_phci_add_path(mdi_phci_t *, mdi_pathinfo_t *); 2407c478bd9Sstevel@tonic-gate static void i_mdi_client_add_path(mdi_client_t *, mdi_pathinfo_t *); 2417c478bd9Sstevel@tonic-gate static void i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *, 2427c478bd9Sstevel@tonic-gate mdi_client_t *); 2437c478bd9Sstevel@tonic-gate static void i_mdi_phci_remove_path(mdi_phci_t *, mdi_pathinfo_t *); 2447c478bd9Sstevel@tonic-gate static void i_mdi_client_remove_path(mdi_client_t *, 2457c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate static int i_mdi_pi_state_change(mdi_pathinfo_t *, 2487c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t, int); 2497c478bd9Sstevel@tonic-gate static int i_mdi_pi_offline(mdi_pathinfo_t *, int); 2507c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_create(mdi_vhci_t *, char *, char *, 2513c34adc5Sramat char **, int); 2527c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_find(mdi_vhci_t *, char *, char *); 2537c478bd9Sstevel@tonic-gate static int i_mdi_devinfo_remove(dev_info_t *, dev_info_t *, int); 2547c478bd9Sstevel@tonic-gate static int i_mdi_is_child_present(dev_info_t *, dev_info_t *); 2553c34adc5Sramat static mdi_client_t *i_mdi_client_alloc(mdi_vhci_t *, char *, char *); 2567c478bd9Sstevel@tonic-gate static void i_mdi_client_enlist_table(mdi_vhci_t *, mdi_client_t *); 2577c478bd9Sstevel@tonic-gate static void i_mdi_client_delist_table(mdi_vhci_t *, mdi_client_t *); 2583c34adc5Sramat static mdi_client_t *i_mdi_client_find(mdi_vhci_t *, char *, char *); 2597c478bd9Sstevel@tonic-gate static void i_mdi_client_update_state(mdi_client_t *); 2607c478bd9Sstevel@tonic-gate static int i_mdi_client_compute_state(mdi_client_t *, 2617c478bd9Sstevel@tonic-gate mdi_phci_t *); 2627c478bd9Sstevel@tonic-gate static void i_mdi_client_lock(mdi_client_t *, mdi_pathinfo_t *); 2637c478bd9Sstevel@tonic-gate static void i_mdi_client_unlock(mdi_client_t *); 2647c478bd9Sstevel@tonic-gate static int i_mdi_client_free(mdi_vhci_t *, mdi_client_t *); 2657c478bd9Sstevel@tonic-gate static mdi_client_t *i_devi_get_client(dev_info_t *); 266ee28b439Scm136836 /* 267ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 268ee28b439Scm136836 * mdi_{enable,disable}_path interfaces 269ee28b439Scm136836 */ 270ee28b439Scm136836 static int i_mdi_pi_enable_disable(dev_info_t *, dev_info_t *, 271ee28b439Scm136836 int, int); 272ee28b439Scm136836 static mdi_pathinfo_t *i_mdi_enable_disable_path(mdi_pathinfo_t *pip, 273ee28b439Scm136836 mdi_vhci_t *vh, int flags, int op); 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * Failover related function prototypes 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate static int i_mdi_failover(void *); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * misc internal functions 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate static int i_mdi_get_hash_key(char *); 2837c478bd9Sstevel@tonic-gate static int i_map_nvlist_error_to_mdi(int); 2847c478bd9Sstevel@tonic-gate static void i_mdi_report_path_state(mdi_client_t *, 2857c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 2867c478bd9Sstevel@tonic-gate 2873c34adc5Sramat static void setup_vhci_cache(mdi_vhci_t *); 2883c34adc5Sramat static int destroy_vhci_cache(mdi_vhci_t *); 2893c34adc5Sramat static int stop_vhcache_async_threads(mdi_vhci_config_t *); 2903c34adc5Sramat static boolean_t stop_vhcache_flush_thread(void *, int); 2913c34adc5Sramat static void free_string_array(char **, int); 2923c34adc5Sramat static void free_vhcache_phci(mdi_vhcache_phci_t *); 2933c34adc5Sramat static void free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *); 2943c34adc5Sramat static void free_vhcache_client(mdi_vhcache_client_t *); 2953c34adc5Sramat static int mainnvl_to_vhcache(mdi_vhci_cache_t *, nvlist_t *); 2963c34adc5Sramat static nvlist_t *vhcache_to_mainnvl(mdi_vhci_cache_t *); 2973c34adc5Sramat static void vhcache_phci_add(mdi_vhci_config_t *, mdi_phci_t *); 2983c34adc5Sramat static void vhcache_phci_remove(mdi_vhci_config_t *, mdi_phci_t *); 2993c34adc5Sramat static void vhcache_pi_add(mdi_vhci_config_t *, 3003c34adc5Sramat struct mdi_pathinfo *); 3013c34adc5Sramat static void vhcache_pi_remove(mdi_vhci_config_t *, 3023c34adc5Sramat struct mdi_pathinfo *); 3033c34adc5Sramat static void free_phclient_path_list(mdi_phys_path_t *); 3043c34adc5Sramat static void sort_vhcache_paths(mdi_vhcache_client_t *); 3053c34adc5Sramat static int flush_vhcache(mdi_vhci_config_t *, int); 3063c34adc5Sramat static void vhcache_dirty(mdi_vhci_config_t *); 3073c34adc5Sramat static void free_async_client_config(mdi_async_client_config_t *); 30867e56d35Sramat static void single_threaded_vhconfig_enter(mdi_vhci_config_t *); 30967e56d35Sramat static void single_threaded_vhconfig_exit(mdi_vhci_config_t *); 3103c34adc5Sramat static nvlist_t *read_on_disk_vhci_cache(char *); 3113c34adc5Sramat extern int fread_nvlist(char *, nvlist_t **); 3123c34adc5Sramat extern int fwrite_nvlist(char *, nvlist_t *); 3133c34adc5Sramat 3147c478bd9Sstevel@tonic-gate /* called once when first vhci registers with mdi */ 3157c478bd9Sstevel@tonic-gate static void 3167c478bd9Sstevel@tonic-gate i_mdi_init() 3177c478bd9Sstevel@tonic-gate { 3187c478bd9Sstevel@tonic-gate static int initialized = 0; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate if (initialized) 3217c478bd9Sstevel@tonic-gate return; 3227c478bd9Sstevel@tonic-gate initialized = 1; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate mutex_init(&mdi_mutex, NULL, MUTEX_DEFAULT, NULL); 325602ca9eaScth 326602ca9eaScth /* Create our taskq resources */ 3277c478bd9Sstevel@tonic-gate mdi_taskq = taskq_create("mdi_taskq", mdi_taskq_n_threads, 3287c478bd9Sstevel@tonic-gate MDI_TASKQ_PRI, MDI_TASKQ_MINALLOC, MDI_TASKQ_MAXALLOC, 3297c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE | TASKQ_CPR_SAFE); 3307c478bd9Sstevel@tonic-gate ASSERT(mdi_taskq != NULL); /* taskq_create never fails */ 331602ca9eaScth 332602ca9eaScth /* Allocate ['path_instance' <-> "path"] maps */ 333602ca9eaScth mutex_init(&mdi_pathmap_mutex, NULL, MUTEX_DRIVER, NULL); 334602ca9eaScth mdi_pathmap_bypath = mod_hash_create_strhash( 335602ca9eaScth "mdi_pathmap_bypath", mdi_pathmap_hash_size, 336602ca9eaScth mod_hash_null_valdtor); 337602ca9eaScth mdi_pathmap_byinstance = mod_hash_create_idhash( 338602ca9eaScth "mdi_pathmap_byinstance", mdi_pathmap_hash_size, 339602ca9eaScth mod_hash_null_valdtor); 3404c06356bSdh142964 mdi_pathmap_sbyinstance = mod_hash_create_idhash( 3414c06356bSdh142964 "mdi_pathmap_sbyinstance", mdi_pathmap_hash_size, 3424c06356bSdh142964 mod_hash_null_valdtor); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * mdi_get_component_type(): 3477c478bd9Sstevel@tonic-gate * Return mpxio component type 3487c478bd9Sstevel@tonic-gate * Return Values: 3497c478bd9Sstevel@tonic-gate * MDI_COMPONENT_NONE 3507c478bd9Sstevel@tonic-gate * MDI_COMPONENT_VHCI 3517c478bd9Sstevel@tonic-gate * MDI_COMPONENT_PHCI 3527c478bd9Sstevel@tonic-gate * MDI_COMPONENT_CLIENT 3537c478bd9Sstevel@tonic-gate * XXX This doesn't work under multi-level MPxIO and should be 3545e3986cbScth * removed when clients migrate mdi_component_is_*() interfaces. 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate int 3577c478bd9Sstevel@tonic-gate mdi_get_component_type(dev_info_t *dip) 3587c478bd9Sstevel@tonic-gate { 3597c478bd9Sstevel@tonic-gate return (DEVI(dip)->devi_mdi_component); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * mdi_vhci_register(): 3647c478bd9Sstevel@tonic-gate * Register a vHCI module with the mpxio framework 3657c478bd9Sstevel@tonic-gate * mdi_vhci_register() is called by vHCI drivers to register the 3667c478bd9Sstevel@tonic-gate * 'class_driver' vHCI driver and its MDI entrypoints with the 3677c478bd9Sstevel@tonic-gate * mpxio framework. The vHCI driver must call this interface as 3687c478bd9Sstevel@tonic-gate * part of its attach(9e) handler. 3697c478bd9Sstevel@tonic-gate * Competing threads may try to attach mdi_vhci_register() as 3707c478bd9Sstevel@tonic-gate * the vHCI drivers are loaded and attached as a result of pHCI 3717c478bd9Sstevel@tonic-gate * driver instance registration (mdi_phci_register()) with the 3727c478bd9Sstevel@tonic-gate * framework. 3737c478bd9Sstevel@tonic-gate * Return Values: 3747c478bd9Sstevel@tonic-gate * MDI_SUCCESS 3757c478bd9Sstevel@tonic-gate * MDI_FAILURE 3767c478bd9Sstevel@tonic-gate */ 3777c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3787c478bd9Sstevel@tonic-gate int 3797c478bd9Sstevel@tonic-gate mdi_vhci_register(char *class, dev_info_t *vdip, mdi_vhci_ops_t *vops, 3807c478bd9Sstevel@tonic-gate int flags) 3817c478bd9Sstevel@tonic-gate { 3827c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 3837c478bd9Sstevel@tonic-gate 38455e592a2SRandall Ralphs /* Registrant can't be older */ 38555e592a2SRandall Ralphs ASSERT(vops->vo_revision <= MDI_VHCI_OPS_REV); 38655e592a2SRandall Ralphs 38700a3eaf3SRamaswamy Tummala #ifdef DEBUG 38800a3eaf3SRamaswamy Tummala /* 38900a3eaf3SRamaswamy Tummala * IB nexus driver is loaded only when IB hardware is present. 39000a3eaf3SRamaswamy Tummala * In order to be able to do this there is a need to drive the loading 39100a3eaf3SRamaswamy Tummala * and attaching of the IB nexus driver (especially when an IB hardware 39200a3eaf3SRamaswamy Tummala * is dynamically plugged in) when an IB HCA driver (PHCI) 39300a3eaf3SRamaswamy Tummala * is being attached. Unfortunately this gets into the limitations 39400a3eaf3SRamaswamy Tummala * of devfs as there seems to be no clean way to drive configuration 39500a3eaf3SRamaswamy Tummala * of a subtree from another subtree of a devfs. Hence, do not ASSERT 39600a3eaf3SRamaswamy Tummala * for IB. 39700a3eaf3SRamaswamy Tummala */ 39800a3eaf3SRamaswamy Tummala if (strcmp(class, MDI_HCI_CLASS_IB) != 0) 3995e3986cbScth ASSERT(DEVI_BUSY_OWNED(ddi_get_parent(vdip))); 40000a3eaf3SRamaswamy Tummala #endif 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate i_mdi_init(); 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 4057c478bd9Sstevel@tonic-gate /* 4067c478bd9Sstevel@tonic-gate * Scan for already registered vhci 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 4097c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * vHCI has already been created. Check for valid 4127c478bd9Sstevel@tonic-gate * vHCI ops registration. We only support one vHCI 4137c478bd9Sstevel@tonic-gate * module per class 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate if (vh->vh_ops != NULL) { 4167c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4177c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, vhci_greeting, class); 4187c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate break; 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * if not yet created, create the vHCI component 4267c478bd9Sstevel@tonic-gate */ 4277c478bd9Sstevel@tonic-gate if (vh == NULL) { 4287c478bd9Sstevel@tonic-gate struct client_hash *hash = NULL; 4297c478bd9Sstevel@tonic-gate char *load_balance; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* 4327c478bd9Sstevel@tonic-gate * Allocate and initialize the mdi extensions 4337c478bd9Sstevel@tonic-gate */ 4347c478bd9Sstevel@tonic-gate vh = kmem_zalloc(sizeof (mdi_vhci_t), KM_SLEEP); 4357c478bd9Sstevel@tonic-gate hash = kmem_zalloc(mdi_client_table_size * sizeof (*hash), 4367c478bd9Sstevel@tonic-gate KM_SLEEP); 4377c478bd9Sstevel@tonic-gate vh->vh_client_table = hash; 4387c478bd9Sstevel@tonic-gate vh->vh_class = kmem_zalloc(strlen(class) + 1, KM_SLEEP); 4397c478bd9Sstevel@tonic-gate (void) strcpy(vh->vh_class, class); 4407c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_RR; 4417c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vdip, 4427c478bd9Sstevel@tonic-gate 0, LOAD_BALANCE_PROP, &load_balance) == DDI_SUCCESS) { 4437c478bd9Sstevel@tonic-gate if (strcmp(load_balance, LOAD_BALANCE_PROP_NONE) == 0) { 4447c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_NONE; 4457c478bd9Sstevel@tonic-gate } else if (strcmp(load_balance, LOAD_BALANCE_PROP_LBA) 4467c478bd9Sstevel@tonic-gate == 0) { 4477c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_LBA; 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate ddi_prop_free(load_balance); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4525e3986cbScth mutex_init(&vh->vh_phci_mutex, NULL, MUTEX_DEFAULT, NULL); 4535e3986cbScth mutex_init(&vh->vh_client_mutex, NULL, MUTEX_DEFAULT, NULL); 4545e3986cbScth 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * Store the vHCI ops vectors 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate vh->vh_dip = vdip; 4597c478bd9Sstevel@tonic-gate vh->vh_ops = vops; 4607c478bd9Sstevel@tonic-gate 4613c34adc5Sramat setup_vhci_cache(vh); 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate if (mdi_vhci_head == NULL) { 4647c478bd9Sstevel@tonic-gate mdi_vhci_head = vh; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate if (mdi_vhci_tail) { 4677c478bd9Sstevel@tonic-gate mdi_vhci_tail->vh_next = vh; 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate mdi_vhci_tail = vh; 4707c478bd9Sstevel@tonic-gate mdi_vhci_count++; 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /* 4747c478bd9Sstevel@tonic-gate * Claim the devfs node as a vhci component 4757c478bd9Sstevel@tonic-gate */ 4767c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component |= MDI_COMPONENT_VHCI; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* 4797c478bd9Sstevel@tonic-gate * Initialize our back reference from dev_info node 4807c478bd9Sstevel@tonic-gate */ 4817c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = (caddr_t)vh; 4827c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4837c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * mdi_vhci_unregister(): 4887c478bd9Sstevel@tonic-gate * Unregister a vHCI module from mpxio framework 4897c478bd9Sstevel@tonic-gate * mdi_vhci_unregister() is called from the detach(9E) entrypoint 4907c478bd9Sstevel@tonic-gate * of a vhci to unregister it from the framework. 4917c478bd9Sstevel@tonic-gate * Return Values: 4927c478bd9Sstevel@tonic-gate * MDI_SUCCESS 4937c478bd9Sstevel@tonic-gate * MDI_FAILURE 4947c478bd9Sstevel@tonic-gate */ 4957c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4967c478bd9Sstevel@tonic-gate int 4977c478bd9Sstevel@tonic-gate mdi_vhci_unregister(dev_info_t *vdip, int flags) 4987c478bd9Sstevel@tonic-gate { 4997c478bd9Sstevel@tonic-gate mdi_vhci_t *found, *vh, *prev = NULL; 5007c478bd9Sstevel@tonic-gate 5015e3986cbScth ASSERT(DEVI_BUSY_OWNED(ddi_get_parent(vdip))); 5025e3986cbScth 5037c478bd9Sstevel@tonic-gate /* 5047c478bd9Sstevel@tonic-gate * Check for invalid VHCI 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate if ((vh = i_devi_get_vhci(vdip)) == NULL) 5077c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * Scan the list of registered vHCIs for a match 5117c478bd9Sstevel@tonic-gate */ 5125e3986cbScth mutex_enter(&mdi_mutex); 5137c478bd9Sstevel@tonic-gate for (found = mdi_vhci_head; found != NULL; found = found->vh_next) { 5147c478bd9Sstevel@tonic-gate if (found == vh) 5157c478bd9Sstevel@tonic-gate break; 5167c478bd9Sstevel@tonic-gate prev = found; 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate if (found == NULL) { 5207c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5217c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* 5258c4f8890Srs135747 * Check the vHCI, pHCI and client count. All the pHCIs and clients 5267c478bd9Sstevel@tonic-gate * should have been unregistered, before a vHCI can be 5277c478bd9Sstevel@tonic-gate * unregistered. 5287c478bd9Sstevel@tonic-gate */ 5295e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 5305e3986cbScth if (vh->vh_refcnt || vh->vh_phci_count || vh->vh_client_count) { 5315e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 5325e3986cbScth mutex_exit(&mdi_mutex); 5335e3986cbScth return (MDI_FAILURE); 5345e3986cbScth } 5355e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 5365e3986cbScth 5375e3986cbScth if (destroy_vhci_cache(vh) != MDI_SUCCESS) { 5387c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5397c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /* 5437c478bd9Sstevel@tonic-gate * Remove the vHCI from the global list 5447c478bd9Sstevel@tonic-gate */ 5457c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_head) { 5467c478bd9Sstevel@tonic-gate mdi_vhci_head = vh->vh_next; 5477c478bd9Sstevel@tonic-gate } else { 5487c478bd9Sstevel@tonic-gate prev->vh_next = vh->vh_next; 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_tail) { 5517c478bd9Sstevel@tonic-gate mdi_vhci_tail = prev; 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate mdi_vhci_count--; 5547c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5553c34adc5Sramat 5563c34adc5Sramat vh->vh_ops = NULL; 5577c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component &= ~MDI_COMPONENT_VHCI; 5587c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = NULL; 5597c478bd9Sstevel@tonic-gate kmem_free(vh->vh_class, strlen(vh->vh_class)+1); 5607c478bd9Sstevel@tonic-gate kmem_free(vh->vh_client_table, 5617c478bd9Sstevel@tonic-gate mdi_client_table_size * sizeof (struct client_hash)); 5625e3986cbScth mutex_destroy(&vh->vh_phci_mutex); 5635e3986cbScth mutex_destroy(&vh->vh_client_mutex); 56478dc6db2Sllai1 5657c478bd9Sstevel@tonic-gate kmem_free(vh, sizeof (mdi_vhci_t)); 5667c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * i_mdi_vhci_class2vhci(): 5717c478bd9Sstevel@tonic-gate * Look for a matching vHCI module given a vHCI class name 5727c478bd9Sstevel@tonic-gate * Return Values: 5737c478bd9Sstevel@tonic-gate * Handle to a vHCI component 5747c478bd9Sstevel@tonic-gate * NULL 5757c478bd9Sstevel@tonic-gate */ 5767c478bd9Sstevel@tonic-gate static mdi_vhci_t * 5777c478bd9Sstevel@tonic-gate i_mdi_vhci_class2vhci(char *class) 5787c478bd9Sstevel@tonic-gate { 5797c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&mdi_mutex)); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 5847c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 5857c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 5867c478bd9Sstevel@tonic-gate break; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5907c478bd9Sstevel@tonic-gate return (vh); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * i_devi_get_vhci(): 5957c478bd9Sstevel@tonic-gate * Utility function to get the handle to a vHCI component 5967c478bd9Sstevel@tonic-gate * Return Values: 5977c478bd9Sstevel@tonic-gate * Handle to a vHCI component 5987c478bd9Sstevel@tonic-gate * NULL 5997c478bd9Sstevel@tonic-gate */ 6007c478bd9Sstevel@tonic-gate mdi_vhci_t * 6017c478bd9Sstevel@tonic-gate i_devi_get_vhci(dev_info_t *vdip) 6027c478bd9Sstevel@tonic-gate { 6037c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 6047c478bd9Sstevel@tonic-gate if (MDI_VHCI(vdip)) { 6057c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci; 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate return (vh); 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* 6117c478bd9Sstevel@tonic-gate * mdi_phci_register(): 6127c478bd9Sstevel@tonic-gate * Register a pHCI module with mpxio framework 6137c478bd9Sstevel@tonic-gate * mdi_phci_register() is called by pHCI drivers to register with 6147c478bd9Sstevel@tonic-gate * the mpxio framework and a specific 'class_driver' vHCI. The 6157c478bd9Sstevel@tonic-gate * pHCI driver must call this interface as part of its attach(9e) 6167c478bd9Sstevel@tonic-gate * handler. 6177c478bd9Sstevel@tonic-gate * Return Values: 6187c478bd9Sstevel@tonic-gate * MDI_SUCCESS 6197c478bd9Sstevel@tonic-gate * MDI_FAILURE 6207c478bd9Sstevel@tonic-gate */ 6217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6227c478bd9Sstevel@tonic-gate int 6237c478bd9Sstevel@tonic-gate mdi_phci_register(char *class, dev_info_t *pdip, int flags) 6247c478bd9Sstevel@tonic-gate { 6257c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 6267c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 6277c478bd9Sstevel@tonic-gate char *data; 6287c478bd9Sstevel@tonic-gate 6295e3986cbScth /* 6305e3986cbScth * Some subsystems, like fcp, perform pHCI registration from a 6315e3986cbScth * different thread than the one doing the pHCI attach(9E) - the 6325e3986cbScth * driver attach code is waiting for this other thread to complete. 6335e3986cbScth * This means we can only ASSERT DEVI_BUSY_CHANGING of parent 6345e3986cbScth * (indicating that some thread has done an ndi_devi_enter of parent) 6355e3986cbScth * not DEVI_BUSY_OWNED (which would indicate that we did the enter). 6365e3986cbScth */ 6375e3986cbScth ASSERT(DEVI_BUSY_CHANGING(ddi_get_parent(pdip))); 6385e3986cbScth 6397c478bd9Sstevel@tonic-gate /* 6407c478bd9Sstevel@tonic-gate * Check for mpxio-disable property. Enable mpxio if the property is 6417c478bd9Sstevel@tonic-gate * missing or not set to "yes". 6427c478bd9Sstevel@tonic-gate * If the property is set to "yes" then emit a brief message. 6437c478bd9Sstevel@tonic-gate */ 6447c478bd9Sstevel@tonic-gate if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0, "mpxio-disable", 6457c478bd9Sstevel@tonic-gate &data) == DDI_SUCCESS)) { 6467c478bd9Sstevel@tonic-gate if (strcmp(data, "yes") == 0) { 6474c06356bSdh142964 MDI_DEBUG(1, (MDI_CONT, pdip, 6484c06356bSdh142964 "?multipath capabilities disabled via %s.conf.", 6497c478bd9Sstevel@tonic-gate ddi_driver_name(pdip))); 6507c478bd9Sstevel@tonic-gate ddi_prop_free(data); 6517c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate ddi_prop_free(data); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * Search for a matching vHCI 6587c478bd9Sstevel@tonic-gate */ 6597c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)i_mdi_vhci_class2vhci(class); 6607c478bd9Sstevel@tonic-gate if (vh == NULL) { 6617c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate ph = kmem_zalloc(sizeof (mdi_phci_t), KM_SLEEP); 6657c478bd9Sstevel@tonic-gate mutex_init(&ph->ph_mutex, NULL, MUTEX_DEFAULT, NULL); 6667c478bd9Sstevel@tonic-gate ph->ph_dip = pdip; 6677c478bd9Sstevel@tonic-gate ph->ph_vhci = vh; 6687c478bd9Sstevel@tonic-gate ph->ph_next = NULL; 6697c478bd9Sstevel@tonic-gate ph->ph_unstable = 0; 6707c478bd9Sstevel@tonic-gate ph->ph_vprivate = 0; 6717c478bd9Sstevel@tonic-gate cv_init(&ph->ph_unstable_cv, NULL, CV_DRIVER, NULL); 6727c478bd9Sstevel@tonic-gate 6735e3986cbScth MDI_PHCI_LOCK(ph); 6747c478bd9Sstevel@tonic-gate MDI_PHCI_SET_POWER_UP(ph); 6755e3986cbScth MDI_PHCI_UNLOCK(ph); 6767c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component |= MDI_COMPONENT_PHCI; 6777c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = (caddr_t)ph; 6787c478bd9Sstevel@tonic-gate 6793c34adc5Sramat vhcache_phci_add(vh->vh_config, ph); 6803c34adc5Sramat 6815e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 6827c478bd9Sstevel@tonic-gate if (vh->vh_phci_head == NULL) { 6837c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph; 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate if (vh->vh_phci_tail) { 6867c478bd9Sstevel@tonic-gate vh->vh_phci_tail->ph_next = ph; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate vh->vh_phci_tail = ph; 6897c478bd9Sstevel@tonic-gate vh->vh_phci_count++; 6905e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 6915e3986cbScth 6928c4f8890Srs135747 i_mdi_log_sysevent(pdip, class, ESC_DDI_INITIATOR_REGISTER); 6937c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* 6977c478bd9Sstevel@tonic-gate * mdi_phci_unregister(): 6987c478bd9Sstevel@tonic-gate * Unregister a pHCI module from mpxio framework 6997c478bd9Sstevel@tonic-gate * mdi_phci_unregister() is called by the pHCI drivers from their 7007c478bd9Sstevel@tonic-gate * detach(9E) handler to unregister their instances from the 7017c478bd9Sstevel@tonic-gate * framework. 7027c478bd9Sstevel@tonic-gate * Return Values: 7037c478bd9Sstevel@tonic-gate * MDI_SUCCESS 7047c478bd9Sstevel@tonic-gate * MDI_FAILURE 7057c478bd9Sstevel@tonic-gate */ 7067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7077c478bd9Sstevel@tonic-gate int 7087c478bd9Sstevel@tonic-gate mdi_phci_unregister(dev_info_t *pdip, int flags) 7097c478bd9Sstevel@tonic-gate { 7107c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 7117c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 7127c478bd9Sstevel@tonic-gate mdi_phci_t *tmp; 7137c478bd9Sstevel@tonic-gate mdi_phci_t *prev = NULL; 7144c06356bSdh142964 mdi_pathinfo_t *pip; 7157c478bd9Sstevel@tonic-gate 7165e3986cbScth ASSERT(DEVI_BUSY_CHANGING(ddi_get_parent(pdip))); 7175e3986cbScth 7187c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 7197c478bd9Sstevel@tonic-gate if (ph == NULL) { 7204c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, pdip, "!not a valid pHCI")); 7217c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 7257c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 7267c478bd9Sstevel@tonic-gate if (vh == NULL) { 7274c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, pdip, "!not a valid vHCI")); 7287c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7315e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 7327c478bd9Sstevel@tonic-gate tmp = vh->vh_phci_head; 7337c478bd9Sstevel@tonic-gate while (tmp) { 7347c478bd9Sstevel@tonic-gate if (tmp == ph) { 7357c478bd9Sstevel@tonic-gate break; 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate prev = tmp; 7387c478bd9Sstevel@tonic-gate tmp = tmp->ph_next; 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_head) { 7427c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph->ph_next; 7437c478bd9Sstevel@tonic-gate } else { 7447c478bd9Sstevel@tonic-gate prev->ph_next = ph->ph_next; 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_tail) { 7487c478bd9Sstevel@tonic-gate vh->vh_phci_tail = prev; 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate vh->vh_phci_count--; 7525e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 7537c478bd9Sstevel@tonic-gate 7544c06356bSdh142964 /* Walk remaining pathinfo nodes and disassociate them from pHCI */ 7554c06356bSdh142964 MDI_PHCI_LOCK(ph); 7564c06356bSdh142964 for (pip = (mdi_pathinfo_t *)ph->ph_path_head; pip; 7574c06356bSdh142964 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link) 7584c06356bSdh142964 MDI_PI(pip)->pi_phci = NULL; 7594c06356bSdh142964 MDI_PHCI_UNLOCK(ph); 7604c06356bSdh142964 7618c4f8890Srs135747 i_mdi_log_sysevent(pdip, ph->ph_vhci->vh_class, 7628c4f8890Srs135747 ESC_DDI_INITIATOR_UNREGISTER); 7633c34adc5Sramat vhcache_phci_remove(vh->vh_config, ph); 7647c478bd9Sstevel@tonic-gate cv_destroy(&ph->ph_unstable_cv); 7657c478bd9Sstevel@tonic-gate mutex_destroy(&ph->ph_mutex); 7667c478bd9Sstevel@tonic-gate kmem_free(ph, sizeof (mdi_phci_t)); 7677c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component &= ~MDI_COMPONENT_PHCI; 7687c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = NULL; 7697c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * i_devi_get_phci(): 7747c478bd9Sstevel@tonic-gate * Utility function to return the phci extensions. 7757c478bd9Sstevel@tonic-gate */ 7767c478bd9Sstevel@tonic-gate static mdi_phci_t * 7777c478bd9Sstevel@tonic-gate i_devi_get_phci(dev_info_t *pdip) 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate mdi_phci_t *ph = NULL; 78055e592a2SRandall Ralphs 7817c478bd9Sstevel@tonic-gate if (MDI_PHCI(pdip)) { 7827c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(pdip)->devi_mdi_xhci; 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate return (ph); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate /* 7885e3986cbScth * Single thread mdi entry into devinfo node for modifying its children. 7895e3986cbScth * If necessary we perform an ndi_devi_enter of the vHCI before doing 7905e3986cbScth * an ndi_devi_enter of 'dip'. We maintain circular in two parts: one 7915e3986cbScth * for the vHCI and one for the pHCI. 7925e3986cbScth */ 7935e3986cbScth void 7945e3986cbScth mdi_devi_enter(dev_info_t *phci_dip, int *circular) 7955e3986cbScth { 7965e3986cbScth dev_info_t *vdip; 7975e3986cbScth int vcircular, pcircular; 7985e3986cbScth 7995e3986cbScth /* Verify calling context */ 8005e3986cbScth ASSERT(MDI_PHCI(phci_dip)); 8015e3986cbScth vdip = mdi_devi_get_vdip(phci_dip); 8025e3986cbScth ASSERT(vdip); /* A pHCI always has a vHCI */ 8035e3986cbScth 8045e3986cbScth /* 8055e3986cbScth * If pHCI is detaching then the framework has already entered the 8065e3986cbScth * vHCI on a threads that went down the code path leading to 8075e3986cbScth * detach_node(). This framework enter of the vHCI during pHCI 8085e3986cbScth * detach is done to avoid deadlock with vHCI power management 8095e3986cbScth * operations which enter the vHCI and the enter down the path 8105e3986cbScth * to the pHCI. If pHCI is detaching then we piggyback this calls 8115e3986cbScth * enter of the vHCI on frameworks vHCI enter that has already 8125e3986cbScth * occurred - this is OK because we know that the framework thread 8135e3986cbScth * doing detach is waiting for our completion. 8145e3986cbScth * 8155e3986cbScth * We should DEVI_IS_DETACHING under an enter of the parent to avoid 8165e3986cbScth * race with detach - but we can't do that because the framework has 8175e3986cbScth * already entered the parent, so we have some complexity instead. 8185e3986cbScth */ 8195e3986cbScth for (;;) { 8205e3986cbScth if (ndi_devi_tryenter(vdip, &vcircular)) { 8215e3986cbScth ASSERT(vcircular != -1); 8225e3986cbScth if (DEVI_IS_DETACHING(phci_dip)) { 8235e3986cbScth ndi_devi_exit(vdip, vcircular); 8245e3986cbScth vcircular = -1; 8255e3986cbScth } 8265e3986cbScth break; 8275e3986cbScth } else if (DEVI_IS_DETACHING(phci_dip)) { 8285e3986cbScth vcircular = -1; 8295e3986cbScth break; 8304c06356bSdh142964 } else if (servicing_interrupt()) { 8314c06356bSdh142964 /* 8324c06356bSdh142964 * Don't delay an interrupt (and ensure adaptive 8334c06356bSdh142964 * mutex inversion support). 8344c06356bSdh142964 */ 8354c06356bSdh142964 ndi_devi_enter(vdip, &vcircular); 8364c06356bSdh142964 break; 8375e3986cbScth } else { 83896c4a178SChris Horne delay_random(mdi_delay); 8395e3986cbScth } 8405e3986cbScth } 8415e3986cbScth 8425e3986cbScth ndi_devi_enter(phci_dip, &pcircular); 8435e3986cbScth *circular = (vcircular << 16) | (pcircular & 0xFFFF); 8445e3986cbScth } 8455e3986cbScth 8465e3986cbScth /* 84755e592a2SRandall Ralphs * Attempt to mdi_devi_enter. 84855e592a2SRandall Ralphs */ 84955e592a2SRandall Ralphs int 85055e592a2SRandall Ralphs mdi_devi_tryenter(dev_info_t *phci_dip, int *circular) 85155e592a2SRandall Ralphs { 85255e592a2SRandall Ralphs dev_info_t *vdip; 85355e592a2SRandall Ralphs int vcircular, pcircular; 85455e592a2SRandall Ralphs 85555e592a2SRandall Ralphs /* Verify calling context */ 85655e592a2SRandall Ralphs ASSERT(MDI_PHCI(phci_dip)); 85755e592a2SRandall Ralphs vdip = mdi_devi_get_vdip(phci_dip); 85855e592a2SRandall Ralphs ASSERT(vdip); /* A pHCI always has a vHCI */ 85955e592a2SRandall Ralphs 86055e592a2SRandall Ralphs if (ndi_devi_tryenter(vdip, &vcircular)) { 86155e592a2SRandall Ralphs if (ndi_devi_tryenter(phci_dip, &pcircular)) { 86255e592a2SRandall Ralphs *circular = (vcircular << 16) | (pcircular & 0xFFFF); 86355e592a2SRandall Ralphs return (1); /* locked */ 86455e592a2SRandall Ralphs } 86555e592a2SRandall Ralphs ndi_devi_exit(vdip, vcircular); 86655e592a2SRandall Ralphs } 86755e592a2SRandall Ralphs return (0); /* busy */ 86855e592a2SRandall Ralphs } 86955e592a2SRandall Ralphs 87055e592a2SRandall Ralphs /* 8715e3986cbScth * Release mdi_devi_enter or successful mdi_devi_tryenter. 8725e3986cbScth */ 8735e3986cbScth void 8745e3986cbScth mdi_devi_exit(dev_info_t *phci_dip, int circular) 8755e3986cbScth { 8765e3986cbScth dev_info_t *vdip; 8775e3986cbScth int vcircular, pcircular; 8785e3986cbScth 8795e3986cbScth /* Verify calling context */ 8805e3986cbScth ASSERT(MDI_PHCI(phci_dip)); 8815e3986cbScth vdip = mdi_devi_get_vdip(phci_dip); 8825e3986cbScth ASSERT(vdip); /* A pHCI always has a vHCI */ 8835e3986cbScth 8845e3986cbScth /* extract two circular recursion values from single int */ 8855e3986cbScth pcircular = (short)(circular & 0xFFFF); 8865e3986cbScth vcircular = (short)((circular >> 16) & 0xFFFF); 8875e3986cbScth 8885e3986cbScth ndi_devi_exit(phci_dip, pcircular); 8895e3986cbScth if (vcircular != -1) 8905e3986cbScth ndi_devi_exit(vdip, vcircular); 8915e3986cbScth } 8925e3986cbScth 8935e3986cbScth /* 8945e3986cbScth * The functions mdi_devi_exit_phci() and mdi_devi_enter_phci() are used 8955e3986cbScth * around a pHCI drivers calls to mdi_pi_online/offline, after holding 8965e3986cbScth * the pathinfo node via mdi_hold_path/mdi_rele_path, to avoid deadlock 8975e3986cbScth * with vHCI power management code during path online/offline. Each 8985e3986cbScth * mdi_devi_exit_phci must have a matching mdi_devi_enter_phci, and both must 8995e3986cbScth * occur within the scope of an active mdi_devi_enter that establishes the 9005e3986cbScth * circular value. 9015e3986cbScth */ 9025e3986cbScth void 9035e3986cbScth mdi_devi_exit_phci(dev_info_t *phci_dip, int circular) 9045e3986cbScth { 9055e3986cbScth int pcircular; 9065e3986cbScth 9075e3986cbScth /* Verify calling context */ 9085e3986cbScth ASSERT(MDI_PHCI(phci_dip)); 9095e3986cbScth 9104c06356bSdh142964 /* Keep hold on pHCI until we reenter in mdi_devi_enter_phci */ 9114c06356bSdh142964 ndi_hold_devi(phci_dip); 9124c06356bSdh142964 9135e3986cbScth pcircular = (short)(circular & 0xFFFF); 9145e3986cbScth ndi_devi_exit(phci_dip, pcircular); 9155e3986cbScth } 9165e3986cbScth 9175e3986cbScth void 9185e3986cbScth mdi_devi_enter_phci(dev_info_t *phci_dip, int *circular) 9195e3986cbScth { 9205e3986cbScth int pcircular; 9215e3986cbScth 9225e3986cbScth /* Verify calling context */ 9235e3986cbScth ASSERT(MDI_PHCI(phci_dip)); 9245e3986cbScth 9255e3986cbScth ndi_devi_enter(phci_dip, &pcircular); 9265e3986cbScth 9274c06356bSdh142964 /* Drop hold from mdi_devi_exit_phci. */ 9284c06356bSdh142964 ndi_rele_devi(phci_dip); 9294c06356bSdh142964 9305e3986cbScth /* verify matching mdi_devi_exit_phci/mdi_devi_enter_phci use */ 9315e3986cbScth ASSERT(pcircular == ((short)(*circular & 0xFFFF))); 9325e3986cbScth } 9335e3986cbScth 9345e3986cbScth /* 9355e3986cbScth * mdi_devi_get_vdip(): 9365e3986cbScth * given a pHCI dip return vHCI dip 9375e3986cbScth */ 9385e3986cbScth dev_info_t * 9395e3986cbScth mdi_devi_get_vdip(dev_info_t *pdip) 9405e3986cbScth { 9415e3986cbScth mdi_phci_t *ph; 9425e3986cbScth 9435e3986cbScth ph = i_devi_get_phci(pdip); 9445e3986cbScth if (ph && ph->ph_vhci) 9455e3986cbScth return (ph->ph_vhci->vh_dip); 9465e3986cbScth return (NULL); 9475e3986cbScth } 9485e3986cbScth 9495e3986cbScth /* 9505e3986cbScth * mdi_devi_pdip_entered(): 9515e3986cbScth * Return 1 if we are vHCI and have done an ndi_devi_enter 9525e3986cbScth * of a pHCI 9535e3986cbScth */ 9545e3986cbScth int 9555e3986cbScth mdi_devi_pdip_entered(dev_info_t *vdip) 9565e3986cbScth { 9575e3986cbScth mdi_vhci_t *vh; 9585e3986cbScth mdi_phci_t *ph; 9595e3986cbScth 9605e3986cbScth vh = i_devi_get_vhci(vdip); 9615e3986cbScth if (vh == NULL) 9625e3986cbScth return (0); 9635e3986cbScth 9645e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 9655e3986cbScth ph = vh->vh_phci_head; 9665e3986cbScth while (ph) { 9675e3986cbScth if (ph->ph_dip && DEVI_BUSY_OWNED(ph->ph_dip)) { 9685e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 9695e3986cbScth return (1); 9705e3986cbScth } 9715e3986cbScth ph = ph->ph_next; 9725e3986cbScth } 9735e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 9745e3986cbScth return (0); 9755e3986cbScth } 9765e3986cbScth 9775e3986cbScth /* 9787c478bd9Sstevel@tonic-gate * mdi_phci_path2devinfo(): 9797c478bd9Sstevel@tonic-gate * Utility function to search for a valid phci device given 9807c478bd9Sstevel@tonic-gate * the devfs pathname. 9817c478bd9Sstevel@tonic-gate */ 9827c478bd9Sstevel@tonic-gate dev_info_t * 9837c478bd9Sstevel@tonic-gate mdi_phci_path2devinfo(dev_info_t *vdip, caddr_t pathname) 9847c478bd9Sstevel@tonic-gate { 9857c478bd9Sstevel@tonic-gate char *temp_pathname; 9867c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 9877c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 9887c478bd9Sstevel@tonic-gate dev_info_t *pdip = NULL; 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate vh = i_devi_get_vhci(vdip); 9917c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate if (vh == NULL) { 9947c478bd9Sstevel@tonic-gate /* 9957c478bd9Sstevel@tonic-gate * Invalid vHCI component, return failure 9967c478bd9Sstevel@tonic-gate */ 9977c478bd9Sstevel@tonic-gate return (NULL); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 10015e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 10027c478bd9Sstevel@tonic-gate ph = vh->vh_phci_head; 10037c478bd9Sstevel@tonic-gate while (ph != NULL) { 10047c478bd9Sstevel@tonic-gate pdip = ph->ph_dip; 10057c478bd9Sstevel@tonic-gate ASSERT(pdip != NULL); 10067c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 10077c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, temp_pathname); 10087c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 10097c478bd9Sstevel@tonic-gate break; 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate ph = ph->ph_next; 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate if (ph == NULL) { 10147c478bd9Sstevel@tonic-gate pdip = NULL; 10157c478bd9Sstevel@tonic-gate } 10165e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 10177c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 10187c478bd9Sstevel@tonic-gate return (pdip); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate /* 10227c478bd9Sstevel@tonic-gate * mdi_phci_get_path_count(): 10237c478bd9Sstevel@tonic-gate * get number of path information nodes associated with a given 10247c478bd9Sstevel@tonic-gate * pHCI device. 10257c478bd9Sstevel@tonic-gate */ 10267c478bd9Sstevel@tonic-gate int 10277c478bd9Sstevel@tonic-gate mdi_phci_get_path_count(dev_info_t *pdip) 10287c478bd9Sstevel@tonic-gate { 10297c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 10307c478bd9Sstevel@tonic-gate int count = 0; 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 10337c478bd9Sstevel@tonic-gate if (ph != NULL) { 10347c478bd9Sstevel@tonic-gate count = ph->ph_path_count; 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate return (count); 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate /* 10407c478bd9Sstevel@tonic-gate * i_mdi_phci_lock(): 10417c478bd9Sstevel@tonic-gate * Lock a pHCI device 10427c478bd9Sstevel@tonic-gate * Return Values: 10437c478bd9Sstevel@tonic-gate * None 10447c478bd9Sstevel@tonic-gate * Note: 10457c478bd9Sstevel@tonic-gate * The default locking order is: 10467c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 10477c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 10487c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 10497c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 10507c478bd9Sstevel@tonic-gate */ 10517c478bd9Sstevel@tonic-gate static void 10527c478bd9Sstevel@tonic-gate i_mdi_phci_lock(mdi_phci_t *ph, mdi_pathinfo_t *pip) 10537c478bd9Sstevel@tonic-gate { 10547c478bd9Sstevel@tonic-gate if (pip) { 10557c478bd9Sstevel@tonic-gate /* Reverse locking is requested. */ 10567c478bd9Sstevel@tonic-gate while (MDI_PHCI_TRYLOCK(ph) == 0) { 10574c06356bSdh142964 if (servicing_interrupt()) { 10584c06356bSdh142964 MDI_PI_HOLD(pip); 10594c06356bSdh142964 MDI_PI_UNLOCK(pip); 10604c06356bSdh142964 MDI_PHCI_LOCK(ph); 10614c06356bSdh142964 MDI_PI_LOCK(pip); 10624c06356bSdh142964 MDI_PI_RELE(pip); 10634c06356bSdh142964 break; 10644c06356bSdh142964 } else { 10657c478bd9Sstevel@tonic-gate /* 10667c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 10677c478bd9Sstevel@tonic-gate * after a small delay 10687c478bd9Sstevel@tonic-gate */ 10697c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 10707c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 107196c4a178SChris Horne delay_random(mdi_delay); 10727c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 10737c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 10747c478bd9Sstevel@tonic-gate } 10754c06356bSdh142964 } 10767c478bd9Sstevel@tonic-gate } else { 10777c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * i_mdi_phci_unlock(): 10837c478bd9Sstevel@tonic-gate * Unlock the pHCI component 10847c478bd9Sstevel@tonic-gate */ 10857c478bd9Sstevel@tonic-gate static void 10867c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(mdi_phci_t *ph) 10877c478bd9Sstevel@tonic-gate { 10887c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate /* 10927c478bd9Sstevel@tonic-gate * i_mdi_devinfo_create(): 10937c478bd9Sstevel@tonic-gate * create client device's devinfo node 10947c478bd9Sstevel@tonic-gate * Return Values: 10957c478bd9Sstevel@tonic-gate * dev_info 10967c478bd9Sstevel@tonic-gate * NULL 10977c478bd9Sstevel@tonic-gate * Notes: 10987c478bd9Sstevel@tonic-gate */ 10997c478bd9Sstevel@tonic-gate static dev_info_t * 11007c478bd9Sstevel@tonic-gate i_mdi_devinfo_create(mdi_vhci_t *vh, char *name, char *guid, 11013c34adc5Sramat char **compatible, int ncompatible) 11027c478bd9Sstevel@tonic-gate { 11037c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 11047c478bd9Sstevel@tonic-gate 11055e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate /* Verify for duplicate entry */ 11087c478bd9Sstevel@tonic-gate cdip = i_mdi_devinfo_find(vh, name, guid); 11097c478bd9Sstevel@tonic-gate ASSERT(cdip == NULL); 11107c478bd9Sstevel@tonic-gate if (cdip) { 11117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 11124c06356bSdh142964 "i_mdi_devinfo_create: client %s@%s already exists", 11134c06356bSdh142964 name ? name : "", guid ? guid : ""); 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11163c34adc5Sramat ndi_devi_alloc_sleep(vh->vh_dip, name, DEVI_SID_NODEID, &cdip); 11177c478bd9Sstevel@tonic-gate if (cdip == NULL) 11187c478bd9Sstevel@tonic-gate goto fail; 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate /* 11217c478bd9Sstevel@tonic-gate * Create component type and Global unique identifier 11227c478bd9Sstevel@tonic-gate * properties 11237c478bd9Sstevel@tonic-gate */ 11247c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, 11257c478bd9Sstevel@tonic-gate MDI_CLIENT_GUID_PROP, guid) != DDI_PROP_SUCCESS) { 11267c478bd9Sstevel@tonic-gate goto fail; 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate /* Decorate the node with compatible property */ 11307c478bd9Sstevel@tonic-gate if (compatible && 11317c478bd9Sstevel@tonic-gate (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip, 11327c478bd9Sstevel@tonic-gate "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS)) { 11337c478bd9Sstevel@tonic-gate goto fail; 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate return (cdip); 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate fail: 11397c478bd9Sstevel@tonic-gate if (cdip) { 11407c478bd9Sstevel@tonic-gate (void) ndi_prop_remove_all(cdip); 11417c478bd9Sstevel@tonic-gate (void) ndi_devi_free(cdip); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate return (NULL); 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * i_mdi_devinfo_find(): 11487c478bd9Sstevel@tonic-gate * Find a matching devinfo node for given client node name 11497c478bd9Sstevel@tonic-gate * and its guid. 11507c478bd9Sstevel@tonic-gate * Return Values: 11517c478bd9Sstevel@tonic-gate * Handle to a dev_info node or NULL 11527c478bd9Sstevel@tonic-gate */ 11537c478bd9Sstevel@tonic-gate static dev_info_t * 11547c478bd9Sstevel@tonic-gate i_mdi_devinfo_find(mdi_vhci_t *vh, caddr_t name, char *guid) 11557c478bd9Sstevel@tonic-gate { 11567c478bd9Sstevel@tonic-gate char *data; 11577c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 11587c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 11597c478bd9Sstevel@tonic-gate int circular; 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate ndi_devi_enter(vh->vh_dip, &circular); 11627c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vh->vh_dip)->devi_child; 11637c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 11647c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate if (strcmp(DEVI(cdip)->devi_node_name, name)) { 11677c478bd9Sstevel@tonic-gate continue; 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip, 11717c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, MDI_CLIENT_GUID_PROP, 11727c478bd9Sstevel@tonic-gate &data) != DDI_PROP_SUCCESS) { 11737c478bd9Sstevel@tonic-gate continue; 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate if (strcmp(data, guid) != 0) { 11777c478bd9Sstevel@tonic-gate ddi_prop_free(data); 11787c478bd9Sstevel@tonic-gate continue; 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate ddi_prop_free(data); 11817c478bd9Sstevel@tonic-gate break; 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate ndi_devi_exit(vh->vh_dip, circular); 11847c478bd9Sstevel@tonic-gate return (cdip); 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate /* 11887c478bd9Sstevel@tonic-gate * i_mdi_devinfo_remove(): 11897c478bd9Sstevel@tonic-gate * Remove a client device node 11907c478bd9Sstevel@tonic-gate */ 11917c478bd9Sstevel@tonic-gate static int 11927c478bd9Sstevel@tonic-gate i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags) 11937c478bd9Sstevel@tonic-gate { 11947c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 11955e3986cbScth 11967c478bd9Sstevel@tonic-gate if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS || 11977c478bd9Sstevel@tonic-gate (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) { 11984c06356bSdh142964 rv = ndi_devi_offline(cdip, NDI_DEVFS_CLEAN | NDI_DEVI_REMOVE); 11997c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 12004c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, cdip, 12014c06356bSdh142964 "!failed: cdip %p", (void *)cdip)); 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate /* 12047c478bd9Sstevel@tonic-gate * Convert to MDI error code 12057c478bd9Sstevel@tonic-gate */ 12067c478bd9Sstevel@tonic-gate switch (rv) { 12077c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 12087c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 12097c478bd9Sstevel@tonic-gate break; 12107c478bd9Sstevel@tonic-gate case NDI_BUSY: 12117c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 12127c478bd9Sstevel@tonic-gate break; 12137c478bd9Sstevel@tonic-gate default: 12147c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 12157c478bd9Sstevel@tonic-gate break; 12167c478bd9Sstevel@tonic-gate } 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate return (rv); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate * i_devi_get_client() 12237c478bd9Sstevel@tonic-gate * Utility function to get mpxio component extensions 12247c478bd9Sstevel@tonic-gate */ 12257c478bd9Sstevel@tonic-gate static mdi_client_t * 12267c478bd9Sstevel@tonic-gate i_devi_get_client(dev_info_t *cdip) 12277c478bd9Sstevel@tonic-gate { 12287c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 12295e3986cbScth 12307c478bd9Sstevel@tonic-gate if (MDI_CLIENT(cdip)) { 12317c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(cdip)->devi_mdi_client; 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate return (ct); 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate /* 12377c478bd9Sstevel@tonic-gate * i_mdi_is_child_present(): 12387c478bd9Sstevel@tonic-gate * Search for the presence of client device dev_info node 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate static int 12417c478bd9Sstevel@tonic-gate i_mdi_is_child_present(dev_info_t *vdip, dev_info_t *cdip) 12427c478bd9Sstevel@tonic-gate { 12437c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 12447c478bd9Sstevel@tonic-gate struct dev_info *dip; 12457c478bd9Sstevel@tonic-gate int circular; 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 12487c478bd9Sstevel@tonic-gate dip = DEVI(vdip)->devi_child; 12497c478bd9Sstevel@tonic-gate while (dip) { 12507c478bd9Sstevel@tonic-gate if (dip == DEVI(cdip)) { 12517c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 12527c478bd9Sstevel@tonic-gate break; 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate dip = dip->devi_sibling; 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 12577c478bd9Sstevel@tonic-gate return (rv); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate /* 12627c478bd9Sstevel@tonic-gate * i_mdi_client_lock(): 12637c478bd9Sstevel@tonic-gate * Grab client component lock 12647c478bd9Sstevel@tonic-gate * Return Values: 12657c478bd9Sstevel@tonic-gate * None 12667c478bd9Sstevel@tonic-gate * Note: 12677c478bd9Sstevel@tonic-gate * The default locking order is: 12687c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 12697c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 12707c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 12717c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 12727c478bd9Sstevel@tonic-gate */ 12737c478bd9Sstevel@tonic-gate static void 12747c478bd9Sstevel@tonic-gate i_mdi_client_lock(mdi_client_t *ct, mdi_pathinfo_t *pip) 12757c478bd9Sstevel@tonic-gate { 12767c478bd9Sstevel@tonic-gate if (pip) { 12777c478bd9Sstevel@tonic-gate /* 12787c478bd9Sstevel@tonic-gate * Reverse locking is requested. 12797c478bd9Sstevel@tonic-gate */ 12807c478bd9Sstevel@tonic-gate while (MDI_CLIENT_TRYLOCK(ct) == 0) { 12814c06356bSdh142964 if (servicing_interrupt()) { 12824c06356bSdh142964 MDI_PI_HOLD(pip); 12834c06356bSdh142964 MDI_PI_UNLOCK(pip); 12844c06356bSdh142964 MDI_CLIENT_LOCK(ct); 12854c06356bSdh142964 MDI_PI_LOCK(pip); 12864c06356bSdh142964 MDI_PI_RELE(pip); 12874c06356bSdh142964 break; 12884c06356bSdh142964 } else { 12897c478bd9Sstevel@tonic-gate /* 12907c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 12917c478bd9Sstevel@tonic-gate * after a small delay 12927c478bd9Sstevel@tonic-gate */ 12937c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 12947c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 129596c4a178SChris Horne delay_random(mdi_delay); 12967c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 12977c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 12987c478bd9Sstevel@tonic-gate } 12994c06356bSdh142964 } 13007c478bd9Sstevel@tonic-gate } else { 13017c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate } 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate /* 13067c478bd9Sstevel@tonic-gate * i_mdi_client_unlock(): 13077c478bd9Sstevel@tonic-gate * Unlock a client component 13087c478bd9Sstevel@tonic-gate */ 13097c478bd9Sstevel@tonic-gate static void 13107c478bd9Sstevel@tonic-gate i_mdi_client_unlock(mdi_client_t *ct) 13117c478bd9Sstevel@tonic-gate { 13127c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 13137c478bd9Sstevel@tonic-gate } 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate /* 13167c478bd9Sstevel@tonic-gate * i_mdi_client_alloc(): 13177c478bd9Sstevel@tonic-gate * Allocate and initialize a client structure. Caller should 13185e3986cbScth * hold the vhci client lock. 13197c478bd9Sstevel@tonic-gate * Return Values: 13207c478bd9Sstevel@tonic-gate * Handle to a client component 13217c478bd9Sstevel@tonic-gate */ 13227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13237c478bd9Sstevel@tonic-gate static mdi_client_t * 13243c34adc5Sramat i_mdi_client_alloc(mdi_vhci_t *vh, char *name, char *lguid) 13257c478bd9Sstevel@tonic-gate { 13267c478bd9Sstevel@tonic-gate mdi_client_t *ct; 13277c478bd9Sstevel@tonic-gate 13285e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate /* 13317c478bd9Sstevel@tonic-gate * Allocate and initialize a component structure. 13327c478bd9Sstevel@tonic-gate */ 13333c34adc5Sramat ct = kmem_zalloc(sizeof (*ct), KM_SLEEP); 13347c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); 13357c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 13367c478bd9Sstevel@tonic-gate ct->ct_hprev = NULL; 13377c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 13387c478bd9Sstevel@tonic-gate ct->ct_vhci = vh; 13393c34adc5Sramat ct->ct_drvname = kmem_alloc(strlen(name) + 1, KM_SLEEP); 13407c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_drvname, name); 13413c34adc5Sramat ct->ct_guid = kmem_alloc(strlen(lguid) + 1, KM_SLEEP); 13427c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_guid, lguid); 13437c478bd9Sstevel@tonic-gate ct->ct_cprivate = NULL; 13447c478bd9Sstevel@tonic-gate ct->ct_vprivate = NULL; 13457c478bd9Sstevel@tonic-gate ct->ct_flags = 0; 13467c478bd9Sstevel@tonic-gate ct->ct_state = MDI_CLIENT_STATE_FAILED; 13475e3986cbScth MDI_CLIENT_LOCK(ct); 13487c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 13497c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 13507c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 13515e3986cbScth MDI_CLIENT_UNLOCK(ct); 13527c478bd9Sstevel@tonic-gate ct->ct_failover_flags = 0; 13537c478bd9Sstevel@tonic-gate ct->ct_failover_status = 0; 13547c478bd9Sstevel@tonic-gate cv_init(&ct->ct_failover_cv, NULL, CV_DRIVER, NULL); 13557c478bd9Sstevel@tonic-gate ct->ct_unstable = 0; 13567c478bd9Sstevel@tonic-gate cv_init(&ct->ct_unstable_cv, NULL, CV_DRIVER, NULL); 13577c478bd9Sstevel@tonic-gate cv_init(&ct->ct_powerchange_cv, NULL, CV_DRIVER, NULL); 13587c478bd9Sstevel@tonic-gate ct->ct_lb = vh->vh_lb; 13593c34adc5Sramat ct->ct_lb_args = kmem_zalloc(sizeof (client_lb_args_t), KM_SLEEP); 13607c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = LOAD_BALANCE_DEFAULT_REGION_SIZE; 13617c478bd9Sstevel@tonic-gate ct->ct_path_count = 0; 13627c478bd9Sstevel@tonic-gate ct->ct_path_head = NULL; 13637c478bd9Sstevel@tonic-gate ct->ct_path_tail = NULL; 13647c478bd9Sstevel@tonic-gate ct->ct_path_last = NULL; 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* 13677c478bd9Sstevel@tonic-gate * Add this client component to our client hash queue 13687c478bd9Sstevel@tonic-gate */ 13697c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(vh, ct); 13707c478bd9Sstevel@tonic-gate return (ct); 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * i_mdi_client_enlist_table(): 13757c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. Caller 13765e3986cbScth * should hold the vhci client lock. 13777c478bd9Sstevel@tonic-gate */ 13787c478bd9Sstevel@tonic-gate static void 13797c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(mdi_vhci_t *vh, mdi_client_t *ct) 13807c478bd9Sstevel@tonic-gate { 13817c478bd9Sstevel@tonic-gate int index; 13827c478bd9Sstevel@tonic-gate struct client_hash *head; 13837c478bd9Sstevel@tonic-gate 13845e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 13855e3986cbScth 13867c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(ct->ct_guid); 13877c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 13887c478bd9Sstevel@tonic-gate ct->ct_hnext = (mdi_client_t *)head->ct_hash_head; 13897c478bd9Sstevel@tonic-gate head->ct_hash_head = ct; 13907c478bd9Sstevel@tonic-gate head->ct_hash_count++; 13917c478bd9Sstevel@tonic-gate vh->vh_client_count++; 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* 13957c478bd9Sstevel@tonic-gate * i_mdi_client_delist_table(): 13967c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. 13975e3986cbScth * Caller should hold the vhci client lock. 13987c478bd9Sstevel@tonic-gate */ 13997c478bd9Sstevel@tonic-gate static void 14007c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(mdi_vhci_t *vh, mdi_client_t *ct) 14017c478bd9Sstevel@tonic-gate { 14027c478bd9Sstevel@tonic-gate int index; 14037c478bd9Sstevel@tonic-gate char *guid; 14047c478bd9Sstevel@tonic-gate struct client_hash *head; 14057c478bd9Sstevel@tonic-gate mdi_client_t *next; 14067c478bd9Sstevel@tonic-gate mdi_client_t *last; 14077c478bd9Sstevel@tonic-gate 14085e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 14095e3986cbScth 14107c478bd9Sstevel@tonic-gate guid = ct->ct_guid; 14117c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 14127c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate last = NULL; 14157c478bd9Sstevel@tonic-gate next = (mdi_client_t *)head->ct_hash_head; 14167c478bd9Sstevel@tonic-gate while (next != NULL) { 14177c478bd9Sstevel@tonic-gate if (next == ct) { 14187c478bd9Sstevel@tonic-gate break; 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate last = next; 14217c478bd9Sstevel@tonic-gate next = next->ct_hnext; 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate if (next) { 14257c478bd9Sstevel@tonic-gate head->ct_hash_count--; 14267c478bd9Sstevel@tonic-gate if (last == NULL) { 14277c478bd9Sstevel@tonic-gate head->ct_hash_head = ct->ct_hnext; 14287c478bd9Sstevel@tonic-gate } else { 14297c478bd9Sstevel@tonic-gate last->ct_hnext = ct->ct_hnext; 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 14327c478bd9Sstevel@tonic-gate vh->vh_client_count--; 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate /* 14387c478bd9Sstevel@tonic-gate * i_mdi_client_free(): 14397c478bd9Sstevel@tonic-gate * Free a client component 14407c478bd9Sstevel@tonic-gate */ 14417c478bd9Sstevel@tonic-gate static int 14427c478bd9Sstevel@tonic-gate i_mdi_client_free(mdi_vhci_t *vh, mdi_client_t *ct) 14437c478bd9Sstevel@tonic-gate { 14447c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 14457c478bd9Sstevel@tonic-gate int flags = ct->ct_flags; 14467c478bd9Sstevel@tonic-gate dev_info_t *cdip; 14477c478bd9Sstevel@tonic-gate dev_info_t *vdip; 14487c478bd9Sstevel@tonic-gate 14495e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 14505e3986cbScth 14517c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 14527c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, MDI_CLIENT_GUID_PROP); 14557c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component &= ~MDI_COMPONENT_CLIENT; 14567c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = NULL; 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate /* 14597c478bd9Sstevel@tonic-gate * Clear out back ref. to dev_info_t node 14607c478bd9Sstevel@tonic-gate */ 14617c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate /* 14647c478bd9Sstevel@tonic-gate * Remove this client from our hash queue 14657c478bd9Sstevel@tonic-gate */ 14667c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(vh, ct); 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate /* 14697c478bd9Sstevel@tonic-gate * Uninitialize and free the component 14707c478bd9Sstevel@tonic-gate */ 14717c478bd9Sstevel@tonic-gate kmem_free(ct->ct_drvname, strlen(ct->ct_drvname) + 1); 14727c478bd9Sstevel@tonic-gate kmem_free(ct->ct_guid, strlen(ct->ct_guid) + 1); 14737c478bd9Sstevel@tonic-gate kmem_free(ct->ct_lb_args, sizeof (client_lb_args_t)); 14747c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_failover_cv); 14757c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_unstable_cv); 14767c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_powerchange_cv); 14777c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_mutex); 14787c478bd9Sstevel@tonic-gate kmem_free(ct, sizeof (*ct)); 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate if (cdip != NULL) { 14815e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 14827c478bd9Sstevel@tonic-gate (void) i_mdi_devinfo_remove(vdip, cdip, flags); 14835e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate return (rv); 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate /* 14897c478bd9Sstevel@tonic-gate * i_mdi_client_find(): 14907c478bd9Sstevel@tonic-gate * Find the client structure corresponding to a given guid 14915e3986cbScth * Caller should hold the vhci client lock. 14927c478bd9Sstevel@tonic-gate */ 14937c478bd9Sstevel@tonic-gate static mdi_client_t * 14943c34adc5Sramat i_mdi_client_find(mdi_vhci_t *vh, char *cname, char *guid) 14957c478bd9Sstevel@tonic-gate { 14967c478bd9Sstevel@tonic-gate int index; 14977c478bd9Sstevel@tonic-gate struct client_hash *head; 14987c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14997c478bd9Sstevel@tonic-gate 15005e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 15015e3986cbScth 15027c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 15037c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate ct = head->ct_hash_head; 15067c478bd9Sstevel@tonic-gate while (ct != NULL) { 15073c34adc5Sramat if (strcmp(ct->ct_guid, guid) == 0 && 15083c34adc5Sramat (cname == NULL || strcmp(ct->ct_drvname, cname) == 0)) { 15097c478bd9Sstevel@tonic-gate break; 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate ct = ct->ct_hnext; 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate return (ct); 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate /* 15177c478bd9Sstevel@tonic-gate * i_mdi_client_update_state(): 15187c478bd9Sstevel@tonic-gate * Compute and update client device state 15197c478bd9Sstevel@tonic-gate * Notes: 15207c478bd9Sstevel@tonic-gate * A client device can be in any of three possible states: 15217c478bd9Sstevel@tonic-gate * 15227c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_OPTIMAL - Client in optimal state with more 15237c478bd9Sstevel@tonic-gate * one online/standby paths. Can tolerate failures. 15247c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_DEGRADED - Client device in degraded state with 15257c478bd9Sstevel@tonic-gate * no alternate paths available as standby. A failure on the online 15267c478bd9Sstevel@tonic-gate * would result in loss of access to device data. 15277c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_FAILED - Client device in failed state with 15287c478bd9Sstevel@tonic-gate * no paths available to access the device. 15297c478bd9Sstevel@tonic-gate */ 15307c478bd9Sstevel@tonic-gate static void 15317c478bd9Sstevel@tonic-gate i_mdi_client_update_state(mdi_client_t *ct) 15327c478bd9Sstevel@tonic-gate { 15337c478bd9Sstevel@tonic-gate int state; 15345e3986cbScth 15355e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 15367c478bd9Sstevel@tonic-gate state = i_mdi_client_compute_state(ct, NULL); 15377c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_STATE(ct, state); 15387c478bd9Sstevel@tonic-gate } 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* 15417c478bd9Sstevel@tonic-gate * i_mdi_client_compute_state(): 15427c478bd9Sstevel@tonic-gate * Compute client device state 15437c478bd9Sstevel@tonic-gate * 15447c478bd9Sstevel@tonic-gate * mdi_phci_t * Pointer to pHCI structure which should 15457c478bd9Sstevel@tonic-gate * while computing the new value. Used by 15467c478bd9Sstevel@tonic-gate * i_mdi_phci_offline() to find the new 15477c478bd9Sstevel@tonic-gate * client state after DR of a pHCI. 15487c478bd9Sstevel@tonic-gate */ 15497c478bd9Sstevel@tonic-gate static int 15507c478bd9Sstevel@tonic-gate i_mdi_client_compute_state(mdi_client_t *ct, mdi_phci_t *ph) 15517c478bd9Sstevel@tonic-gate { 15527c478bd9Sstevel@tonic-gate int state; 15537c478bd9Sstevel@tonic-gate int online_count = 0; 15547c478bd9Sstevel@tonic-gate int standby_count = 0; 15557c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 15567c478bd9Sstevel@tonic-gate 15575e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 15587c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 15597c478bd9Sstevel@tonic-gate while (pip != NULL) { 15607c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 15617c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 15627c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 15637c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 15647c478bd9Sstevel@tonic-gate pip = next; 15657c478bd9Sstevel@tonic-gate continue; 15667c478bd9Sstevel@tonic-gate } 15675e3986cbScth 15687c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 15697c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_ONLINE) 15707c478bd9Sstevel@tonic-gate online_count++; 15717c478bd9Sstevel@tonic-gate else if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 15727c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_STANDBY) 15737c478bd9Sstevel@tonic-gate standby_count++; 15747c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 15757c478bd9Sstevel@tonic-gate pip = next; 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate if (online_count == 0) { 15797c478bd9Sstevel@tonic-gate if (standby_count == 0) { 15807c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_FAILED; 15814c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, ct->ct_dip, 15824c06356bSdh142964 "client state failed: ct = %p", (void *)ct)); 15837c478bd9Sstevel@tonic-gate } else if (standby_count == 1) { 15847c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 15857c478bd9Sstevel@tonic-gate } else { 15867c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate } else if (online_count == 1) { 15897c478bd9Sstevel@tonic-gate if (standby_count == 0) { 15907c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 15917c478bd9Sstevel@tonic-gate } else { 15927c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 15937c478bd9Sstevel@tonic-gate } 15947c478bd9Sstevel@tonic-gate } else { 15957c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 15967c478bd9Sstevel@tonic-gate } 15977c478bd9Sstevel@tonic-gate return (state); 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate /* 16017c478bd9Sstevel@tonic-gate * i_mdi_client2devinfo(): 16027c478bd9Sstevel@tonic-gate * Utility function 16037c478bd9Sstevel@tonic-gate */ 16047c478bd9Sstevel@tonic-gate dev_info_t * 16057c478bd9Sstevel@tonic-gate i_mdi_client2devinfo(mdi_client_t *ct) 16067c478bd9Sstevel@tonic-gate { 16077c478bd9Sstevel@tonic-gate return (ct->ct_dip); 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate /* 16117c478bd9Sstevel@tonic-gate * mdi_client_path2_devinfo(): 16127c478bd9Sstevel@tonic-gate * Given the parent devinfo and child devfs pathname, search for 16137c478bd9Sstevel@tonic-gate * a valid devfs node handle. 16147c478bd9Sstevel@tonic-gate */ 16157c478bd9Sstevel@tonic-gate dev_info_t * 16167c478bd9Sstevel@tonic-gate mdi_client_path2devinfo(dev_info_t *vdip, char *pathname) 16177c478bd9Sstevel@tonic-gate { 16187c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 16197c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 16207c478bd9Sstevel@tonic-gate char *temp_pathname; 16217c478bd9Sstevel@tonic-gate int circular; 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate /* 16247c478bd9Sstevel@tonic-gate * Allocate temp buffer 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate /* 16297c478bd9Sstevel@tonic-gate * Lock parent against changes 16307c478bd9Sstevel@tonic-gate */ 16317c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 16327c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vdip)->devi_child; 16337c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 16347c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 16357c478bd9Sstevel@tonic-gate 16367c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 16377c478bd9Sstevel@tonic-gate (void) ddi_pathname(cdip, temp_pathname); 16387c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 16397c478bd9Sstevel@tonic-gate break; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate /* 16437c478bd9Sstevel@tonic-gate * Release devinfo lock 16447c478bd9Sstevel@tonic-gate */ 16457c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* 16487c478bd9Sstevel@tonic-gate * Free the temp buffer 16497c478bd9Sstevel@tonic-gate */ 16507c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 16517c478bd9Sstevel@tonic-gate return (cdip); 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate /* 16557c478bd9Sstevel@tonic-gate * mdi_client_get_path_count(): 16567c478bd9Sstevel@tonic-gate * Utility function to get number of path information nodes 16577c478bd9Sstevel@tonic-gate * associated with a given client device. 16587c478bd9Sstevel@tonic-gate */ 16597c478bd9Sstevel@tonic-gate int 16607c478bd9Sstevel@tonic-gate mdi_client_get_path_count(dev_info_t *cdip) 16617c478bd9Sstevel@tonic-gate { 16627c478bd9Sstevel@tonic-gate mdi_client_t *ct; 16637c478bd9Sstevel@tonic-gate int count = 0; 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 16667c478bd9Sstevel@tonic-gate if (ct != NULL) { 16677c478bd9Sstevel@tonic-gate count = ct->ct_path_count; 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate return (count); 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate /* 16747c478bd9Sstevel@tonic-gate * i_mdi_get_hash_key(): 16757c478bd9Sstevel@tonic-gate * Create a hash using strings as keys 16767c478bd9Sstevel@tonic-gate * 16777c478bd9Sstevel@tonic-gate */ 16787c478bd9Sstevel@tonic-gate static int 16797c478bd9Sstevel@tonic-gate i_mdi_get_hash_key(char *str) 16807c478bd9Sstevel@tonic-gate { 16817c478bd9Sstevel@tonic-gate uint32_t g, hash = 0; 16827c478bd9Sstevel@tonic-gate char *p; 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate for (p = str; *p != '\0'; p++) { 16857c478bd9Sstevel@tonic-gate g = *p; 16867c478bd9Sstevel@tonic-gate hash += g; 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate return (hash % (CLIENT_HASH_TABLE_SIZE - 1)); 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate /* 16927c478bd9Sstevel@tonic-gate * mdi_get_lb_policy(): 16937c478bd9Sstevel@tonic-gate * Get current load balancing policy for a given client device 16947c478bd9Sstevel@tonic-gate */ 16957c478bd9Sstevel@tonic-gate client_lb_t 16967c478bd9Sstevel@tonic-gate mdi_get_lb_policy(dev_info_t *cdip) 16977c478bd9Sstevel@tonic-gate { 16987c478bd9Sstevel@tonic-gate client_lb_t lb = LOAD_BALANCE_NONE; 16997c478bd9Sstevel@tonic-gate mdi_client_t *ct; 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 17027c478bd9Sstevel@tonic-gate if (ct != NULL) { 17037c478bd9Sstevel@tonic-gate lb = ct->ct_lb; 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate return (lb); 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate /* 17097c478bd9Sstevel@tonic-gate * mdi_set_lb_region_size(): 17107c478bd9Sstevel@tonic-gate * Set current region size for the load-balance 17117c478bd9Sstevel@tonic-gate */ 17127c478bd9Sstevel@tonic-gate int 17137c478bd9Sstevel@tonic-gate mdi_set_lb_region_size(dev_info_t *cdip, int region_size) 17147c478bd9Sstevel@tonic-gate { 17157c478bd9Sstevel@tonic-gate mdi_client_t *ct; 17167c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 17197c478bd9Sstevel@tonic-gate if (ct != NULL && ct->ct_lb_args != NULL) { 17207c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = region_size; 17217c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate return (rv); 17247c478bd9Sstevel@tonic-gate } 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate /* 17277c478bd9Sstevel@tonic-gate * mdi_Set_lb_policy(): 17287c478bd9Sstevel@tonic-gate * Set current load balancing policy for a given client device 17297c478bd9Sstevel@tonic-gate */ 17307c478bd9Sstevel@tonic-gate int 17317c478bd9Sstevel@tonic-gate mdi_set_lb_policy(dev_info_t *cdip, client_lb_t lb) 17327c478bd9Sstevel@tonic-gate { 17337c478bd9Sstevel@tonic-gate mdi_client_t *ct; 17347c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 17377c478bd9Sstevel@tonic-gate if (ct != NULL) { 17387c478bd9Sstevel@tonic-gate ct->ct_lb = lb; 17397c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate return (rv); 17427c478bd9Sstevel@tonic-gate } 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate /* 17457c478bd9Sstevel@tonic-gate * mdi_failover(): 17467c478bd9Sstevel@tonic-gate * failover function called by the vHCI drivers to initiate 17477c478bd9Sstevel@tonic-gate * a failover operation. This is typically due to non-availability 17487c478bd9Sstevel@tonic-gate * of online paths to route I/O requests. Failover can be 17497c478bd9Sstevel@tonic-gate * triggered through user application also. 17507c478bd9Sstevel@tonic-gate * 17517c478bd9Sstevel@tonic-gate * The vHCI driver calls mdi_failover() to initiate a failover 17527c478bd9Sstevel@tonic-gate * operation. mdi_failover() calls back into the vHCI driver's 17537c478bd9Sstevel@tonic-gate * vo_failover() entry point to perform the actual failover 17547c478bd9Sstevel@tonic-gate * operation. The reason for requiring the vHCI driver to 17557c478bd9Sstevel@tonic-gate * initiate failover by calling mdi_failover(), instead of directly 17567c478bd9Sstevel@tonic-gate * executing vo_failover() itself, is to ensure that the mdi 17577c478bd9Sstevel@tonic-gate * framework can keep track of the client state properly. 17587c478bd9Sstevel@tonic-gate * Additionally, mdi_failover() provides as a convenience the 17597c478bd9Sstevel@tonic-gate * option of performing the failover operation synchronously or 17607c478bd9Sstevel@tonic-gate * asynchronously 17617c478bd9Sstevel@tonic-gate * 17627c478bd9Sstevel@tonic-gate * Upon successful completion of the failover operation, the 17637c478bd9Sstevel@tonic-gate * paths that were previously ONLINE will be in the STANDBY state, 17647c478bd9Sstevel@tonic-gate * and the newly activated paths will be in the ONLINE state. 17657c478bd9Sstevel@tonic-gate * 17667c478bd9Sstevel@tonic-gate * The flags modifier determines whether the activation is done 17677c478bd9Sstevel@tonic-gate * synchronously: MDI_FAILOVER_SYNC 17687c478bd9Sstevel@tonic-gate * Return Values: 17697c478bd9Sstevel@tonic-gate * MDI_SUCCESS 17707c478bd9Sstevel@tonic-gate * MDI_FAILURE 17717c478bd9Sstevel@tonic-gate * MDI_BUSY 17727c478bd9Sstevel@tonic-gate */ 17737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17747c478bd9Sstevel@tonic-gate int 17757c478bd9Sstevel@tonic-gate mdi_failover(dev_info_t *vdip, dev_info_t *cdip, int flags) 17767c478bd9Sstevel@tonic-gate { 17777c478bd9Sstevel@tonic-gate int rv; 17787c478bd9Sstevel@tonic-gate mdi_client_t *ct; 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 17817c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 17827c478bd9Sstevel@tonic-gate if (ct == NULL) { 17837c478bd9Sstevel@tonic-gate /* cdip is not a valid client device. Nothing more to do. */ 17847c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 17887c478bd9Sstevel@tonic-gate 17897c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_PATH_FREE_IN_PROGRESS(ct)) { 17907c478bd9Sstevel@tonic-gate /* A path to the client is being freed */ 17917c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 17927c478bd9Sstevel@tonic-gate return (MDI_BUSY); 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 17977c478bd9Sstevel@tonic-gate /* 17987c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 17997c478bd9Sstevel@tonic-gate */ 18007c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18017c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 18057c478bd9Sstevel@tonic-gate /* 18067c478bd9Sstevel@tonic-gate * Failover is already in progress; return BUSY 18077c478bd9Sstevel@tonic-gate */ 18087c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18097c478bd9Sstevel@tonic-gate return (MDI_BUSY); 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate /* 18127c478bd9Sstevel@tonic-gate * Make sure that mdi_pathinfo node state changes are processed. 18137c478bd9Sstevel@tonic-gate * We do not allow failovers to progress while client path state 18147c478bd9Sstevel@tonic-gate * changes are in progress 18157c478bd9Sstevel@tonic-gate */ 18167c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 18177c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 18187c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18197c478bd9Sstevel@tonic-gate return (MDI_BUSY); 18207c478bd9Sstevel@tonic-gate } else { 18217c478bd9Sstevel@tonic-gate while (ct->ct_unstable) 18227c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_unstable_cv, &ct->ct_mutex); 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate } 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* 18277c478bd9Sstevel@tonic-gate * Client device is in stable state. Before proceeding, perform sanity 18287c478bd9Sstevel@tonic-gate * checks again. 18297c478bd9Sstevel@tonic-gate */ 18307c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct)) || (MDI_CLIENT_IS_FAILED(ct)) || 1831*1b94a41bSChris Horne (!i_ddi_devi_attached(cdip))) { 18327c478bd9Sstevel@tonic-gate /* 18337c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 18347c478bd9Sstevel@tonic-gate */ 18357c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18367c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate /* 18407c478bd9Sstevel@tonic-gate * Set the client state as failover in progress. 18417c478bd9Sstevel@tonic-gate */ 18427c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_FAILOVER_IN_PROGRESS(ct); 18437c478bd9Sstevel@tonic-gate ct->ct_failover_flags = flags; 18447c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18457c478bd9Sstevel@tonic-gate 18467c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 18477c478bd9Sstevel@tonic-gate /* 18487c478bd9Sstevel@tonic-gate * Submit the initiate failover request via CPR safe 18497c478bd9Sstevel@tonic-gate * taskq threads. 18507c478bd9Sstevel@tonic-gate */ 18517c478bd9Sstevel@tonic-gate (void) taskq_dispatch(mdi_taskq, (task_func_t *)i_mdi_failover, 18527c478bd9Sstevel@tonic-gate ct, KM_SLEEP); 18537c478bd9Sstevel@tonic-gate return (MDI_ACCEPT); 18547c478bd9Sstevel@tonic-gate } else { 18557c478bd9Sstevel@tonic-gate /* 18567c478bd9Sstevel@tonic-gate * Synchronous failover mode. Typically invoked from the user 18577c478bd9Sstevel@tonic-gate * land. 18587c478bd9Sstevel@tonic-gate */ 18597c478bd9Sstevel@tonic-gate rv = i_mdi_failover(ct); 18607c478bd9Sstevel@tonic-gate } 18617c478bd9Sstevel@tonic-gate return (rv); 18627c478bd9Sstevel@tonic-gate } 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate /* 18657c478bd9Sstevel@tonic-gate * i_mdi_failover(): 18667c478bd9Sstevel@tonic-gate * internal failover function. Invokes vHCI drivers failover 18677c478bd9Sstevel@tonic-gate * callback function and process the failover status 18687c478bd9Sstevel@tonic-gate * Return Values: 18697c478bd9Sstevel@tonic-gate * None 18707c478bd9Sstevel@tonic-gate * 18717c478bd9Sstevel@tonic-gate * Note: A client device in failover state can not be detached or freed. 18727c478bd9Sstevel@tonic-gate */ 18737c478bd9Sstevel@tonic-gate static int 18747c478bd9Sstevel@tonic-gate i_mdi_failover(void *arg) 18757c478bd9Sstevel@tonic-gate { 18767c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 18777c478bd9Sstevel@tonic-gate mdi_client_t *ct = (mdi_client_t *)arg; 18787c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = ct->ct_vhci; 18797c478bd9Sstevel@tonic-gate 18805e3986cbScth ASSERT(!MDI_CLIENT_LOCKED(ct)); 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate if (vh->vh_ops->vo_failover != NULL) { 18837c478bd9Sstevel@tonic-gate /* 18847c478bd9Sstevel@tonic-gate * Call vHCI drivers callback routine 18857c478bd9Sstevel@tonic-gate */ 18867c478bd9Sstevel@tonic-gate rv = (*vh->vh_ops->vo_failover)(vh->vh_dip, ct->ct_dip, 18877c478bd9Sstevel@tonic-gate ct->ct_failover_flags); 18887c478bd9Sstevel@tonic-gate } 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 18917c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_FAILOVER_IN_PROGRESS(ct); 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate /* 18947c478bd9Sstevel@tonic-gate * Save the failover return status 18957c478bd9Sstevel@tonic-gate */ 18967c478bd9Sstevel@tonic-gate ct->ct_failover_status = rv; 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate /* 18997c478bd9Sstevel@tonic-gate * As a result of failover, client status would have been changed. 19007c478bd9Sstevel@tonic-gate * Update the client state and wake up anyone waiting on this client 19017c478bd9Sstevel@tonic-gate * device. 19027c478bd9Sstevel@tonic-gate */ 19037c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_failover_cv); 19067c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 19077c478bd9Sstevel@tonic-gate return (rv); 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate /* 19117c478bd9Sstevel@tonic-gate * Load balancing is logical block. 19127c478bd9Sstevel@tonic-gate * IOs within the range described by region_size 19137c478bd9Sstevel@tonic-gate * would go on the same path. This would improve the 19147c478bd9Sstevel@tonic-gate * performance by cache-hit on some of the RAID devices. 19157c478bd9Sstevel@tonic-gate * Search only for online paths(At some point we 19167c478bd9Sstevel@tonic-gate * may want to balance across target ports). 19177c478bd9Sstevel@tonic-gate * If no paths are found then default to round-robin. 19187c478bd9Sstevel@tonic-gate */ 19197c478bd9Sstevel@tonic-gate static int 19207c478bd9Sstevel@tonic-gate i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp) 19217c478bd9Sstevel@tonic-gate { 19227c478bd9Sstevel@tonic-gate int path_index = -1; 19237c478bd9Sstevel@tonic-gate int online_path_count = 0; 19247c478bd9Sstevel@tonic-gate int online_nonpref_path_count = 0; 19257c478bd9Sstevel@tonic-gate int region_size = ct->ct_lb_args->region_size; 19267c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 19277c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 19287c478bd9Sstevel@tonic-gate int preferred, path_cnt; 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 19317c478bd9Sstevel@tonic-gate while (pip) { 19327c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 19337c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_state == 19347c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && MDI_PI(pip)->pi_preferred) { 19357c478bd9Sstevel@tonic-gate online_path_count++; 19367c478bd9Sstevel@tonic-gate } else if (MDI_PI(pip)->pi_state == 19377c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && !MDI_PI(pip)->pi_preferred) { 19387c478bd9Sstevel@tonic-gate online_nonpref_path_count++; 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 19417c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 19427c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19437c478bd9Sstevel@tonic-gate pip = next; 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate /* if found any online/preferred then use this type */ 19467c478bd9Sstevel@tonic-gate if (online_path_count > 0) { 19477c478bd9Sstevel@tonic-gate path_cnt = online_path_count; 19487c478bd9Sstevel@tonic-gate preferred = 1; 19497c478bd9Sstevel@tonic-gate } else if (online_nonpref_path_count > 0) { 19507c478bd9Sstevel@tonic-gate path_cnt = online_nonpref_path_count; 19517c478bd9Sstevel@tonic-gate preferred = 0; 19527c478bd9Sstevel@tonic-gate } else { 19537c478bd9Sstevel@tonic-gate path_cnt = 0; 19547c478bd9Sstevel@tonic-gate } 19557c478bd9Sstevel@tonic-gate if (path_cnt) { 19567c478bd9Sstevel@tonic-gate path_index = (bp->b_blkno >> region_size) % path_cnt; 19577c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 19587c478bd9Sstevel@tonic-gate while (pip && path_index != -1) { 19597c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 19607c478bd9Sstevel@tonic-gate if (path_index == 0 && 19617c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 19627c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE) && 19637c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == preferred) { 19647c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 19657c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19667c478bd9Sstevel@tonic-gate *ret_pip = pip; 19677c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 19687c478bd9Sstevel@tonic-gate } 19697c478bd9Sstevel@tonic-gate path_index --; 19707c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 19717c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 19727c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19737c478bd9Sstevel@tonic-gate pip = next; 19747c478bd9Sstevel@tonic-gate } 19754c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip, 19764c06356bSdh142964 "lba %llx: path %s %p", 19774c06356bSdh142964 bp->b_lblkno, mdi_pi_spathname(pip), (void *)pip)); 19787c478bd9Sstevel@tonic-gate } 19797c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate /* 19837c478bd9Sstevel@tonic-gate * mdi_select_path(): 19847c478bd9Sstevel@tonic-gate * select a path to access a client device. 19857c478bd9Sstevel@tonic-gate * 19867c478bd9Sstevel@tonic-gate * mdi_select_path() function is called by the vHCI drivers to 19877c478bd9Sstevel@tonic-gate * select a path to route the I/O request to. The caller passes 19887c478bd9Sstevel@tonic-gate * the block I/O data transfer structure ("buf") as one of the 19897c478bd9Sstevel@tonic-gate * parameters. The mpxio framework uses the buf structure 19907c478bd9Sstevel@tonic-gate * contents to maintain per path statistics (total I/O size / 19917c478bd9Sstevel@tonic-gate * count pending). If more than one online paths are available to 19927c478bd9Sstevel@tonic-gate * select, the framework automatically selects a suitable path 19937c478bd9Sstevel@tonic-gate * for routing I/O request. If a failover operation is active for 19947c478bd9Sstevel@tonic-gate * this client device the call shall be failed with MDI_BUSY error 19957c478bd9Sstevel@tonic-gate * code. 19967c478bd9Sstevel@tonic-gate * 19977c478bd9Sstevel@tonic-gate * By default this function returns a suitable path in online 19987c478bd9Sstevel@tonic-gate * state based on the current load balancing policy. Currently 19997c478bd9Sstevel@tonic-gate * we support LOAD_BALANCE_NONE (Previously selected online path 20007c478bd9Sstevel@tonic-gate * will continue to be used till the path is usable) and 20017c478bd9Sstevel@tonic-gate * LOAD_BALANCE_RR (Online paths will be selected in a round 20027c478bd9Sstevel@tonic-gate * robin fashion), LOAD_BALANCE_LB(Online paths will be selected 20037c478bd9Sstevel@tonic-gate * based on the logical block). The load balancing 20047c478bd9Sstevel@tonic-gate * through vHCI drivers configuration file (driver.conf). 20057c478bd9Sstevel@tonic-gate * 20067c478bd9Sstevel@tonic-gate * vHCI drivers may override this default behavior by specifying 2007602ca9eaScth * appropriate flags. The meaning of the thrid argument depends 2008602ca9eaScth * on the flags specified. If MDI_SELECT_PATH_INSTANCE is set 2009602ca9eaScth * then the argument is the "path instance" of the path to select. 2010602ca9eaScth * If MDI_SELECT_PATH_INSTANCE is not set then the argument is 2011602ca9eaScth * "start_pip". A non NULL "start_pip" is the starting point to 2012602ca9eaScth * walk and find the next appropriate path. The following values 2013602ca9eaScth * are currently defined: MDI_SELECT_ONLINE_PATH (to select an 2014602ca9eaScth * ONLINE path) and/or MDI_SELECT_STANDBY_PATH (to select an 2015602ca9eaScth * STANDBY path). 20167c478bd9Sstevel@tonic-gate * 20177c478bd9Sstevel@tonic-gate * The non-standard behavior is used by the scsi_vhci driver, 20187c478bd9Sstevel@tonic-gate * whenever it has to use a STANDBY/FAULTED path. Eg. during 20197c478bd9Sstevel@tonic-gate * attach of client devices (to avoid an unnecessary failover 20207c478bd9Sstevel@tonic-gate * when the STANDBY path comes up first), during failover 20217c478bd9Sstevel@tonic-gate * (to activate a STANDBY path as ONLINE). 20227c478bd9Sstevel@tonic-gate * 20235e3986cbScth * The selected path is returned in a a mdi_hold_path() state 20245e3986cbScth * (pi_ref_cnt). Caller should release the hold by calling 20255e3986cbScth * mdi_rele_path(). 20267c478bd9Sstevel@tonic-gate * 20277c478bd9Sstevel@tonic-gate * Return Values: 20287c478bd9Sstevel@tonic-gate * MDI_SUCCESS - Completed successfully 20297c478bd9Sstevel@tonic-gate * MDI_BUSY - Client device is busy failing over 20307c478bd9Sstevel@tonic-gate * MDI_NOPATH - Client device is online, but no valid path are 20317c478bd9Sstevel@tonic-gate * available to access this client device 20327c478bd9Sstevel@tonic-gate * MDI_FAILURE - Invalid client device or state 20337c478bd9Sstevel@tonic-gate * MDI_DEVI_ONLINING 20347c478bd9Sstevel@tonic-gate * - Client device (struct dev_info state) is in 20357c478bd9Sstevel@tonic-gate * onlining state. 20367c478bd9Sstevel@tonic-gate */ 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20397c478bd9Sstevel@tonic-gate int 20407c478bd9Sstevel@tonic-gate mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags, 2041602ca9eaScth void *arg, mdi_pathinfo_t **ret_pip) 20427c478bd9Sstevel@tonic-gate { 20437c478bd9Sstevel@tonic-gate mdi_client_t *ct; 20447c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 20457c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 20467c478bd9Sstevel@tonic-gate mdi_pathinfo_t *head; 20477c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start; 20487c478bd9Sstevel@tonic-gate client_lb_t lbp; /* load balancing policy */ 20497c478bd9Sstevel@tonic-gate int sb = 1; /* standard behavior */ 20507c478bd9Sstevel@tonic-gate int preferred = 1; /* preferred path */ 20517c478bd9Sstevel@tonic-gate int cond, cont = 1; 20527c478bd9Sstevel@tonic-gate int retry = 0; 2053602ca9eaScth mdi_pathinfo_t *start_pip; /* request starting pathinfo */ 2054602ca9eaScth int path_instance; /* request specific path instance */ 2055602ca9eaScth 2056602ca9eaScth /* determine type of arg based on flags */ 2057602ca9eaScth if (flags & MDI_SELECT_PATH_INSTANCE) { 2058602ca9eaScth path_instance = (int)(intptr_t)arg; 2059602ca9eaScth start_pip = NULL; 2060602ca9eaScth } else { 2061602ca9eaScth path_instance = 0; 2062602ca9eaScth start_pip = (mdi_pathinfo_t *)arg; 2063602ca9eaScth } 20647c478bd9Sstevel@tonic-gate 20657c478bd9Sstevel@tonic-gate if (flags != 0) { 20667c478bd9Sstevel@tonic-gate /* 20677c478bd9Sstevel@tonic-gate * disable default behavior 20687c478bd9Sstevel@tonic-gate */ 20697c478bd9Sstevel@tonic-gate sb = 0; 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate *ret_pip = NULL; 20737c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 20747c478bd9Sstevel@tonic-gate if (ct == NULL) { 20757c478bd9Sstevel@tonic-gate /* mdi extensions are NULL, Nothing more to do */ 20767c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 20777c478bd9Sstevel@tonic-gate } 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 20807c478bd9Sstevel@tonic-gate 20817c478bd9Sstevel@tonic-gate if (sb) { 20827c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 20837c478bd9Sstevel@tonic-gate /* 20847c478bd9Sstevel@tonic-gate * Client is not ready to accept any I/O requests. 20857c478bd9Sstevel@tonic-gate * Fail this request. 20867c478bd9Sstevel@tonic-gate */ 20874c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, cdip, 20884c06356bSdh142964 "client state offline ct = %p", (void *)ct)); 20897c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 20907c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 20917c478bd9Sstevel@tonic-gate } 20927c478bd9Sstevel@tonic-gate 20937c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 20947c478bd9Sstevel@tonic-gate /* 20957c478bd9Sstevel@tonic-gate * Check for Failover is in progress. If so tell the 20967c478bd9Sstevel@tonic-gate * caller that this device is busy. 20977c478bd9Sstevel@tonic-gate */ 20984c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, cdip, 20994c06356bSdh142964 "client failover in progress ct = %p", 21005e3986cbScth (void *)ct)); 21017c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 21027c478bd9Sstevel@tonic-gate return (MDI_BUSY); 21037c478bd9Sstevel@tonic-gate } 21047c478bd9Sstevel@tonic-gate 21057c478bd9Sstevel@tonic-gate /* 21067c478bd9Sstevel@tonic-gate * Check to see whether the client device is attached. 21077c478bd9Sstevel@tonic-gate * If not so, let the vHCI driver manually select a path 21087c478bd9Sstevel@tonic-gate * (standby) and let the probe/attach process to continue. 21097c478bd9Sstevel@tonic-gate */ 2110737d277aScth if (MDI_CLIENT_IS_DETACHED(ct) || !i_ddi_devi_attached(cdip)) { 21114c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, cdip, 21124c06356bSdh142964 "devi is onlining ct = %p", (void *)ct)); 21137c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 21147c478bd9Sstevel@tonic-gate return (MDI_DEVI_ONLINING); 21157c478bd9Sstevel@tonic-gate } 21167c478bd9Sstevel@tonic-gate } 21177c478bd9Sstevel@tonic-gate 21187c478bd9Sstevel@tonic-gate /* 21197c478bd9Sstevel@tonic-gate * Cache in the client list head. If head of the list is NULL 21207c478bd9Sstevel@tonic-gate * return MDI_NOPATH 21217c478bd9Sstevel@tonic-gate */ 21227c478bd9Sstevel@tonic-gate head = ct->ct_path_head; 21237c478bd9Sstevel@tonic-gate if (head == NULL) { 21247c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 21257c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 21267c478bd9Sstevel@tonic-gate } 21277c478bd9Sstevel@tonic-gate 2128602ca9eaScth /* Caller is specifying a specific pathinfo path by path_instance */ 2129602ca9eaScth if (path_instance) { 2130602ca9eaScth /* search for pathinfo with correct path_instance */ 2131602ca9eaScth for (pip = head; 2132602ca9eaScth pip && (mdi_pi_get_path_instance(pip) != path_instance); 2133602ca9eaScth pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link) 2134602ca9eaScth ; 2135602ca9eaScth 2136ab412e72SSrikanth, Ramana /* If path can't be selected then MDI_NOPATH is returned. */ 2137602ca9eaScth if (pip == NULL) { 2138602ca9eaScth MDI_CLIENT_UNLOCK(ct); 2139ab412e72SSrikanth, Ramana return (MDI_NOPATH); 2140602ca9eaScth } 2141602ca9eaScth 21424c06356bSdh142964 /* 21434c06356bSdh142964 * Verify state of path. When asked to select a specific 21444c06356bSdh142964 * path_instance, we select the requested path in any 21454c06356bSdh142964 * state (ONLINE, OFFLINE, STANDBY, FAULT) other than INIT. 21464c06356bSdh142964 * We don't however select paths where the pHCI has detached. 21474c06356bSdh142964 * NOTE: last pathinfo node of an opened client device may 21484c06356bSdh142964 * exist in an OFFLINE state after the pHCI associated with 21494c06356bSdh142964 * that path has detached (but pi_phci will be NULL if that 21504c06356bSdh142964 * has occurred). 21514c06356bSdh142964 */ 2152602ca9eaScth MDI_PI_LOCK(pip); 21534c06356bSdh142964 if ((MDI_PI(pip)->pi_state == MDI_PATHINFO_STATE_INIT) || 21544c06356bSdh142964 (MDI_PI(pip)->pi_phci == NULL)) { 2155602ca9eaScth MDI_PI_UNLOCK(pip); 2156602ca9eaScth MDI_CLIENT_UNLOCK(ct); 2157602ca9eaScth return (MDI_FAILURE); 2158602ca9eaScth } 2159602ca9eaScth 2160ab412e72SSrikanth, Ramana /* Return MDI_BUSY if we have a transient condition */ 2161ab412e72SSrikanth, Ramana if (MDI_PI_IS_TRANSIENT(pip)) { 2162ab412e72SSrikanth, Ramana MDI_PI_UNLOCK(pip); 2163ab412e72SSrikanth, Ramana MDI_CLIENT_UNLOCK(ct); 2164ab412e72SSrikanth, Ramana return (MDI_BUSY); 2165ab412e72SSrikanth, Ramana } 2166ab412e72SSrikanth, Ramana 2167602ca9eaScth /* 2168602ca9eaScth * Return the path in hold state. Caller should release the 2169602ca9eaScth * lock by calling mdi_rele_path() 2170602ca9eaScth */ 2171602ca9eaScth MDI_PI_HOLD(pip); 2172602ca9eaScth MDI_PI_UNLOCK(pip); 2173602ca9eaScth *ret_pip = pip; 2174602ca9eaScth MDI_CLIENT_UNLOCK(ct); 2175602ca9eaScth return (MDI_SUCCESS); 2176602ca9eaScth } 2177602ca9eaScth 21787c478bd9Sstevel@tonic-gate /* 21797c478bd9Sstevel@tonic-gate * for non default behavior, bypass current 21807c478bd9Sstevel@tonic-gate * load balancing policy and always use LOAD_BALANCE_RR 21817c478bd9Sstevel@tonic-gate * except that the start point will be adjusted based 21827c478bd9Sstevel@tonic-gate * on the provided start_pip 21837c478bd9Sstevel@tonic-gate */ 21847c478bd9Sstevel@tonic-gate lbp = sb ? ct->ct_lb : LOAD_BALANCE_RR; 21857c478bd9Sstevel@tonic-gate 21867c478bd9Sstevel@tonic-gate switch (lbp) { 21877c478bd9Sstevel@tonic-gate case LOAD_BALANCE_NONE: 21887c478bd9Sstevel@tonic-gate /* 21897c478bd9Sstevel@tonic-gate * Load balancing is None or Alternate path mode 21907c478bd9Sstevel@tonic-gate * Start looking for a online mdi_pathinfo node starting from 21917c478bd9Sstevel@tonic-gate * last known selected path 21927c478bd9Sstevel@tonic-gate */ 21937c478bd9Sstevel@tonic-gate preferred = 1; 21947c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_last; 21957c478bd9Sstevel@tonic-gate if (pip == NULL) { 21967c478bd9Sstevel@tonic-gate pip = head; 21977c478bd9Sstevel@tonic-gate } 21987c478bd9Sstevel@tonic-gate start = pip; 21997c478bd9Sstevel@tonic-gate do { 22007c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22017c478bd9Sstevel@tonic-gate /* 22027c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 22037c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 220455e592a2SRandall Ralphs * same variable is used for DISABLE/ENABLE information. 22057c478bd9Sstevel@tonic-gate */ 2206ee28b439Scm136836 if ((MDI_PI(pip)->pi_state == 2207ee28b439Scm136836 MDI_PATHINFO_STATE_ONLINE) && 22087c478bd9Sstevel@tonic-gate preferred == MDI_PI(pip)->pi_preferred) { 22097c478bd9Sstevel@tonic-gate /* 22107c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 22117c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 22127c478bd9Sstevel@tonic-gate */ 22137c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 22147c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 22157c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 22167c478bd9Sstevel@tonic-gate *ret_pip = pip; 22177c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 22187c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 22197c478bd9Sstevel@tonic-gate } 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate /* 22227c478bd9Sstevel@tonic-gate * Path is busy. 22237c478bd9Sstevel@tonic-gate */ 22247c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 22257c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 22267c478bd9Sstevel@tonic-gate retry = 1; 22277c478bd9Sstevel@tonic-gate /* 22287c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 22297c478bd9Sstevel@tonic-gate */ 22307c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 22317c478bd9Sstevel@tonic-gate if (next == NULL) { 22327c478bd9Sstevel@tonic-gate next = head; 22337c478bd9Sstevel@tonic-gate } 22347c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 22357c478bd9Sstevel@tonic-gate pip = next; 22367c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 22377c478bd9Sstevel@tonic-gate preferred = 0; 22387c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 22397c478bd9Sstevel@tonic-gate cont = 0; 22407c478bd9Sstevel@tonic-gate } 22417c478bd9Sstevel@tonic-gate } while (cont); 22427c478bd9Sstevel@tonic-gate break; 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate case LOAD_BALANCE_LBA: 22457c478bd9Sstevel@tonic-gate /* 22467c478bd9Sstevel@tonic-gate * Make sure we are looking 22477c478bd9Sstevel@tonic-gate * for an online path. Otherwise, if it is for a STANDBY 22487c478bd9Sstevel@tonic-gate * path request, it will go through and fetch an ONLINE 22497c478bd9Sstevel@tonic-gate * path which is not desirable. 22507c478bd9Sstevel@tonic-gate */ 22517c478bd9Sstevel@tonic-gate if ((ct->ct_lb_args != NULL) && 22527c478bd9Sstevel@tonic-gate (ct->ct_lb_args->region_size) && bp && 22537c478bd9Sstevel@tonic-gate (sb || (flags == MDI_SELECT_ONLINE_PATH))) { 22547c478bd9Sstevel@tonic-gate if (i_mdi_lba_lb(ct, ret_pip, bp) 22557c478bd9Sstevel@tonic-gate == MDI_SUCCESS) { 22567c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 22577c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate } 22607c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 22617c478bd9Sstevel@tonic-gate case LOAD_BALANCE_RR: 22627c478bd9Sstevel@tonic-gate /* 22637c478bd9Sstevel@tonic-gate * Load balancing is Round Robin. Start looking for a online 22647c478bd9Sstevel@tonic-gate * mdi_pathinfo node starting from last known selected path 22657c478bd9Sstevel@tonic-gate * as the start point. If override flags are specified, 22667c478bd9Sstevel@tonic-gate * process accordingly. 22677c478bd9Sstevel@tonic-gate * If the search is already in effect(start_pip not null), 22687c478bd9Sstevel@tonic-gate * then lets just use the same path preference to continue the 22697c478bd9Sstevel@tonic-gate * traversal. 22707c478bd9Sstevel@tonic-gate */ 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate if (start_pip != NULL) { 22737c478bd9Sstevel@tonic-gate preferred = MDI_PI(start_pip)->pi_preferred; 22747c478bd9Sstevel@tonic-gate } else { 22757c478bd9Sstevel@tonic-gate preferred = 1; 22767c478bd9Sstevel@tonic-gate } 22777c478bd9Sstevel@tonic-gate 22787c478bd9Sstevel@tonic-gate start = sb ? (mdi_pathinfo_t *)ct->ct_path_last : start_pip; 22797c478bd9Sstevel@tonic-gate if (start == NULL) { 22807c478bd9Sstevel@tonic-gate pip = head; 22817c478bd9Sstevel@tonic-gate } else { 22827c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(start)->pi_client_link; 22837c478bd9Sstevel@tonic-gate if (pip == NULL) { 2284b08fdaf7SSheshadri Vasudevan if ( flags & MDI_SELECT_NO_PREFERRED) { 2285b08fdaf7SSheshadri Vasudevan /* 2286b08fdaf7SSheshadri Vasudevan * Return since we hit the end of list 2287b08fdaf7SSheshadri Vasudevan */ 2288b08fdaf7SSheshadri Vasudevan MDI_CLIENT_UNLOCK(ct); 2289b08fdaf7SSheshadri Vasudevan return (MDI_NOPATH); 2290b08fdaf7SSheshadri Vasudevan } 2291b08fdaf7SSheshadri Vasudevan 22927c478bd9Sstevel@tonic-gate if (!sb) { 22937c478bd9Sstevel@tonic-gate if (preferred == 0) { 22947c478bd9Sstevel@tonic-gate /* 22957c478bd9Sstevel@tonic-gate * Looks like we have completed 22967c478bd9Sstevel@tonic-gate * the traversal as preferred 22977c478bd9Sstevel@tonic-gate * value is 0. Time to bail out. 22987c478bd9Sstevel@tonic-gate */ 22997c478bd9Sstevel@tonic-gate *ret_pip = NULL; 23007c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 23017c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 23027c478bd9Sstevel@tonic-gate } else { 23037c478bd9Sstevel@tonic-gate /* 23047c478bd9Sstevel@tonic-gate * Looks like we reached the 23057c478bd9Sstevel@tonic-gate * end of the list. Lets enable 23067c478bd9Sstevel@tonic-gate * traversal of non preferred 23077c478bd9Sstevel@tonic-gate * paths. 23087c478bd9Sstevel@tonic-gate */ 23097c478bd9Sstevel@tonic-gate preferred = 0; 23107c478bd9Sstevel@tonic-gate } 23117c478bd9Sstevel@tonic-gate } 23127c478bd9Sstevel@tonic-gate pip = head; 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate } 23157c478bd9Sstevel@tonic-gate start = pip; 23167c478bd9Sstevel@tonic-gate do { 23177c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 23187c478bd9Sstevel@tonic-gate if (sb) { 23197c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 23207c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 23217c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 23227c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 23237c478bd9Sstevel@tonic-gate } else { 23247c478bd9Sstevel@tonic-gate if (flags == MDI_SELECT_ONLINE_PATH) { 23257c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 23267c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 23277c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 23287c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 23297c478bd9Sstevel@tonic-gate } else if (flags == MDI_SELECT_STANDBY_PATH) { 23307c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 23317c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY && 23327c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 23337c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 23347c478bd9Sstevel@tonic-gate } else if (flags == (MDI_SELECT_ONLINE_PATH | 23357c478bd9Sstevel@tonic-gate MDI_SELECT_STANDBY_PATH)) { 23367c478bd9Sstevel@tonic-gate cond = (((MDI_PI(pip)->pi_state == 23377c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE || 23387c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 23397c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY)) && 23407c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 23417c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 2342ee28b439Scm136836 } else if (flags == 2343ee28b439Scm136836 (MDI_SELECT_STANDBY_PATH | 2344ee28b439Scm136836 MDI_SELECT_ONLINE_PATH | 2345ee28b439Scm136836 MDI_SELECT_USER_DISABLE_PATH)) { 2346ee28b439Scm136836 cond = (((MDI_PI(pip)->pi_state == 2347ee28b439Scm136836 MDI_PATHINFO_STATE_ONLINE || 2348ee28b439Scm136836 (MDI_PI(pip)->pi_state == 2349ee28b439Scm136836 MDI_PATHINFO_STATE_STANDBY) || 2350ee28b439Scm136836 (MDI_PI(pip)->pi_state == 2351ee28b439Scm136836 (MDI_PATHINFO_STATE_ONLINE| 2352ee28b439Scm136836 MDI_PATHINFO_STATE_USER_DISABLE)) || 2353ee28b439Scm136836 (MDI_PI(pip)->pi_state == 2354ee28b439Scm136836 (MDI_PATHINFO_STATE_STANDBY | 2355ee28b439Scm136836 MDI_PATHINFO_STATE_USER_DISABLE)))&& 2356ee28b439Scm136836 MDI_PI(pip)->pi_preferred == 2357ee28b439Scm136836 preferred) ? 1 : 0); 2358b08fdaf7SSheshadri Vasudevan } else if (flags == 2359b08fdaf7SSheshadri Vasudevan (MDI_SELECT_STANDBY_PATH | 2360b08fdaf7SSheshadri Vasudevan MDI_SELECT_ONLINE_PATH | 2361b08fdaf7SSheshadri Vasudevan MDI_SELECT_NO_PREFERRED)) { 2362b08fdaf7SSheshadri Vasudevan cond = (((MDI_PI(pip)->pi_state == 2363b08fdaf7SSheshadri Vasudevan MDI_PATHINFO_STATE_ONLINE) || 2364b08fdaf7SSheshadri Vasudevan (MDI_PI(pip)->pi_state == 2365b08fdaf7SSheshadri Vasudevan MDI_PATHINFO_STATE_STANDBY)) 2366b08fdaf7SSheshadri Vasudevan ? 1 : 0); 23677c478bd9Sstevel@tonic-gate } else { 23687c478bd9Sstevel@tonic-gate cond = 0; 23697c478bd9Sstevel@tonic-gate } 23707c478bd9Sstevel@tonic-gate } 23717c478bd9Sstevel@tonic-gate /* 23727c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 23737c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 237455e592a2SRandall Ralphs * same variable is used for DISABLE/ENABLE information. 23757c478bd9Sstevel@tonic-gate */ 23767c478bd9Sstevel@tonic-gate if (cond) { 23777c478bd9Sstevel@tonic-gate /* 23787c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 23797c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 23807c478bd9Sstevel@tonic-gate */ 23817c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 23827c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 23837c478bd9Sstevel@tonic-gate if (sb) 23847c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 23857c478bd9Sstevel@tonic-gate *ret_pip = pip; 23867c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 23877c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 23887c478bd9Sstevel@tonic-gate } 23897c478bd9Sstevel@tonic-gate /* 23907c478bd9Sstevel@tonic-gate * Path is busy. 23917c478bd9Sstevel@tonic-gate */ 23927c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 23937c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 23947c478bd9Sstevel@tonic-gate retry = 1; 23957c478bd9Sstevel@tonic-gate 23967c478bd9Sstevel@tonic-gate /* 23977c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 23987c478bd9Sstevel@tonic-gate */ 23997c478bd9Sstevel@tonic-gate do_again: 24007c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 24017c478bd9Sstevel@tonic-gate if (next == NULL) { 2402b08fdaf7SSheshadri Vasudevan if ( flags & MDI_SELECT_NO_PREFERRED) { 2403b08fdaf7SSheshadri Vasudevan /* 2404b08fdaf7SSheshadri Vasudevan * Bail out since we hit the end of list 2405b08fdaf7SSheshadri Vasudevan */ 2406b08fdaf7SSheshadri Vasudevan MDI_PI_UNLOCK(pip); 2407b08fdaf7SSheshadri Vasudevan break; 2408b08fdaf7SSheshadri Vasudevan } 2409b08fdaf7SSheshadri Vasudevan 24107c478bd9Sstevel@tonic-gate if (!sb) { 24117c478bd9Sstevel@tonic-gate if (preferred == 1) { 24127c478bd9Sstevel@tonic-gate /* 24137c478bd9Sstevel@tonic-gate * Looks like we reached the 24147c478bd9Sstevel@tonic-gate * end of the list. Lets enable 24157c478bd9Sstevel@tonic-gate * traversal of non preferred 24167c478bd9Sstevel@tonic-gate * paths. 24177c478bd9Sstevel@tonic-gate */ 24187c478bd9Sstevel@tonic-gate preferred = 0; 24197c478bd9Sstevel@tonic-gate next = head; 24207c478bd9Sstevel@tonic-gate } else { 24217c478bd9Sstevel@tonic-gate /* 24227c478bd9Sstevel@tonic-gate * We have done both the passes 24237c478bd9Sstevel@tonic-gate * Preferred as well as for 24247c478bd9Sstevel@tonic-gate * Non-preferred. Bail out now. 24257c478bd9Sstevel@tonic-gate */ 24267c478bd9Sstevel@tonic-gate cont = 0; 24277c478bd9Sstevel@tonic-gate } 24287c478bd9Sstevel@tonic-gate } else { 24297c478bd9Sstevel@tonic-gate /* 24307c478bd9Sstevel@tonic-gate * Standard behavior case. 24317c478bd9Sstevel@tonic-gate */ 24327c478bd9Sstevel@tonic-gate next = head; 24337c478bd9Sstevel@tonic-gate } 24347c478bd9Sstevel@tonic-gate } 24357c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 24367c478bd9Sstevel@tonic-gate if (cont == 0) { 24377c478bd9Sstevel@tonic-gate break; 24387c478bd9Sstevel@tonic-gate } 24397c478bd9Sstevel@tonic-gate pip = next; 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate if (!sb) { 24427c478bd9Sstevel@tonic-gate /* 24437c478bd9Sstevel@tonic-gate * We need to handle the selection of 24447c478bd9Sstevel@tonic-gate * non-preferred path in the following 24457c478bd9Sstevel@tonic-gate * case: 24467c478bd9Sstevel@tonic-gate * 24477c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 24487c478bd9Sstevel@tonic-gate * | A : 1| - | B : 1| - | C : 0| - |NULL | 24497c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 24507c478bd9Sstevel@tonic-gate * 24517c478bd9Sstevel@tonic-gate * If we start the search with B, we need to 24527c478bd9Sstevel@tonic-gate * skip beyond B to pick C which is non - 24537c478bd9Sstevel@tonic-gate * preferred in the second pass. The following 24547c478bd9Sstevel@tonic-gate * test, if true, will allow us to skip over 24557c478bd9Sstevel@tonic-gate * the 'start'(B in the example) to select 24567c478bd9Sstevel@tonic-gate * other non preferred elements. 24577c478bd9Sstevel@tonic-gate */ 24587c478bd9Sstevel@tonic-gate if ((start_pip != NULL) && (start_pip == pip) && 24597c478bd9Sstevel@tonic-gate (MDI_PI(start_pip)->pi_preferred 24607c478bd9Sstevel@tonic-gate != preferred)) { 24617c478bd9Sstevel@tonic-gate /* 24627c478bd9Sstevel@tonic-gate * try again after going past the start 24637c478bd9Sstevel@tonic-gate * pip 24647c478bd9Sstevel@tonic-gate */ 24657c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 24667c478bd9Sstevel@tonic-gate goto do_again; 24677c478bd9Sstevel@tonic-gate } 24687c478bd9Sstevel@tonic-gate } else { 24697c478bd9Sstevel@tonic-gate /* 24707c478bd9Sstevel@tonic-gate * Standard behavior case 24717c478bd9Sstevel@tonic-gate */ 24727c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 24737c478bd9Sstevel@tonic-gate /* look for nonpreferred paths */ 24747c478bd9Sstevel@tonic-gate preferred = 0; 24757c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 24767c478bd9Sstevel@tonic-gate /* 24777c478bd9Sstevel@tonic-gate * Exit condition 24787c478bd9Sstevel@tonic-gate */ 24797c478bd9Sstevel@tonic-gate cont = 0; 24807c478bd9Sstevel@tonic-gate } 24817c478bd9Sstevel@tonic-gate } 24827c478bd9Sstevel@tonic-gate } while (cont); 24837c478bd9Sstevel@tonic-gate break; 24847c478bd9Sstevel@tonic-gate } 24857c478bd9Sstevel@tonic-gate 24867c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 24877c478bd9Sstevel@tonic-gate if (retry == 1) { 24887c478bd9Sstevel@tonic-gate return (MDI_BUSY); 24897c478bd9Sstevel@tonic-gate } else { 24907c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 24917c478bd9Sstevel@tonic-gate } 24927c478bd9Sstevel@tonic-gate } 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate /* 24957c478bd9Sstevel@tonic-gate * For a client, return the next available path to any phci 24967c478bd9Sstevel@tonic-gate * 24977c478bd9Sstevel@tonic-gate * Note: 24987c478bd9Sstevel@tonic-gate * Caller should hold the branch's devinfo node to get a consistent 24997c478bd9Sstevel@tonic-gate * snap shot of the mdi_pathinfo nodes. 25007c478bd9Sstevel@tonic-gate * 25017c478bd9Sstevel@tonic-gate * Please note that even the list is stable the mdi_pathinfo 25027c478bd9Sstevel@tonic-gate * node state and properties are volatile. The caller should lock 25037c478bd9Sstevel@tonic-gate * and unlock the nodes by calling mdi_pi_lock() and 25047c478bd9Sstevel@tonic-gate * mdi_pi_unlock() functions to get a stable properties. 25057c478bd9Sstevel@tonic-gate * 25067c478bd9Sstevel@tonic-gate * If there is a need to use the nodes beyond the hold of the 25077c478bd9Sstevel@tonic-gate * devinfo node period (For ex. I/O), then mdi_pathinfo node 25087c478bd9Sstevel@tonic-gate * need to be held against unexpected removal by calling 25097c478bd9Sstevel@tonic-gate * mdi_hold_path() and should be released by calling 25107c478bd9Sstevel@tonic-gate * mdi_rele_path() on completion. 25117c478bd9Sstevel@tonic-gate */ 25127c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 25137c478bd9Sstevel@tonic-gate mdi_get_next_phci_path(dev_info_t *ct_dip, mdi_pathinfo_t *pip) 25147c478bd9Sstevel@tonic-gate { 25157c478bd9Sstevel@tonic-gate mdi_client_t *ct; 25167c478bd9Sstevel@tonic-gate 25177c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(ct_dip)) 25187c478bd9Sstevel@tonic-gate return (NULL); 25197c478bd9Sstevel@tonic-gate 25207c478bd9Sstevel@tonic-gate /* 25217c478bd9Sstevel@tonic-gate * Walk through client link 25227c478bd9Sstevel@tonic-gate */ 25237c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(ct_dip)->devi_mdi_client; 25247c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 25257c478bd9Sstevel@tonic-gate 25267c478bd9Sstevel@tonic-gate if (pip == NULL) 25277c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ct->ct_path_head); 25287c478bd9Sstevel@tonic-gate 25297c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link); 25307c478bd9Sstevel@tonic-gate } 25317c478bd9Sstevel@tonic-gate 25327c478bd9Sstevel@tonic-gate /* 25337c478bd9Sstevel@tonic-gate * For a phci, return the next available path to any client 25347c478bd9Sstevel@tonic-gate * Note: ditto mdi_get_next_phci_path() 25357c478bd9Sstevel@tonic-gate */ 25367c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 25377c478bd9Sstevel@tonic-gate mdi_get_next_client_path(dev_info_t *ph_dip, mdi_pathinfo_t *pip) 25387c478bd9Sstevel@tonic-gate { 25397c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 25407c478bd9Sstevel@tonic-gate 25417c478bd9Sstevel@tonic-gate if (!MDI_PHCI(ph_dip)) 25427c478bd9Sstevel@tonic-gate return (NULL); 25437c478bd9Sstevel@tonic-gate 25447c478bd9Sstevel@tonic-gate /* 25457c478bd9Sstevel@tonic-gate * Walk through pHCI link 25467c478bd9Sstevel@tonic-gate */ 25477c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(ph_dip)->devi_mdi_xhci; 25487c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate if (pip == NULL) 25517c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ph->ph_path_head); 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link); 25547c478bd9Sstevel@tonic-gate } 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate /* 25577c478bd9Sstevel@tonic-gate * mdi_hold_path(): 25587c478bd9Sstevel@tonic-gate * Hold the mdi_pathinfo node against unwanted unexpected free. 25597c478bd9Sstevel@tonic-gate * Return Values: 25607c478bd9Sstevel@tonic-gate * None 25617c478bd9Sstevel@tonic-gate */ 25627c478bd9Sstevel@tonic-gate void 25637c478bd9Sstevel@tonic-gate mdi_hold_path(mdi_pathinfo_t *pip) 25647c478bd9Sstevel@tonic-gate { 25657c478bd9Sstevel@tonic-gate if (pip) { 25667c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 25677c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 25687c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 25697c478bd9Sstevel@tonic-gate } 25707c478bd9Sstevel@tonic-gate } 25717c478bd9Sstevel@tonic-gate 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate /* 25747c478bd9Sstevel@tonic-gate * mdi_rele_path(): 25757c478bd9Sstevel@tonic-gate * Release the mdi_pathinfo node which was selected 25767c478bd9Sstevel@tonic-gate * through mdi_select_path() mechanism or manually held by 25777c478bd9Sstevel@tonic-gate * calling mdi_hold_path(). 25787c478bd9Sstevel@tonic-gate * Return Values: 25797c478bd9Sstevel@tonic-gate * None 25807c478bd9Sstevel@tonic-gate */ 25817c478bd9Sstevel@tonic-gate void 25827c478bd9Sstevel@tonic-gate mdi_rele_path(mdi_pathinfo_t *pip) 25837c478bd9Sstevel@tonic-gate { 25847c478bd9Sstevel@tonic-gate if (pip) { 25857c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 25867c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 25877c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_ref_cnt == 0) { 25887c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_ref_cv); 25897c478bd9Sstevel@tonic-gate } 25907c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 25917c478bd9Sstevel@tonic-gate } 25927c478bd9Sstevel@tonic-gate } 25937c478bd9Sstevel@tonic-gate 25947c478bd9Sstevel@tonic-gate /* 25957c478bd9Sstevel@tonic-gate * mdi_pi_lock(): 25967c478bd9Sstevel@tonic-gate * Lock the mdi_pathinfo node. 25977c478bd9Sstevel@tonic-gate * Note: 25987c478bd9Sstevel@tonic-gate * The caller should release the lock by calling mdi_pi_unlock() 25997c478bd9Sstevel@tonic-gate */ 26007c478bd9Sstevel@tonic-gate void 26017c478bd9Sstevel@tonic-gate mdi_pi_lock(mdi_pathinfo_t *pip) 26027c478bd9Sstevel@tonic-gate { 26037c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 26047c478bd9Sstevel@tonic-gate if (pip) { 26057c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 26067c478bd9Sstevel@tonic-gate } 26077c478bd9Sstevel@tonic-gate } 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate 26107c478bd9Sstevel@tonic-gate /* 26117c478bd9Sstevel@tonic-gate * mdi_pi_unlock(): 26127c478bd9Sstevel@tonic-gate * Unlock the mdi_pathinfo node. 26137c478bd9Sstevel@tonic-gate * Note: 26147c478bd9Sstevel@tonic-gate * The mdi_pathinfo node should have been locked with mdi_pi_lock() 26157c478bd9Sstevel@tonic-gate */ 26167c478bd9Sstevel@tonic-gate void 26177c478bd9Sstevel@tonic-gate mdi_pi_unlock(mdi_pathinfo_t *pip) 26187c478bd9Sstevel@tonic-gate { 26197c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 26207c478bd9Sstevel@tonic-gate if (pip) { 26217c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 26227c478bd9Sstevel@tonic-gate } 26237c478bd9Sstevel@tonic-gate } 26247c478bd9Sstevel@tonic-gate 26257c478bd9Sstevel@tonic-gate /* 26267c478bd9Sstevel@tonic-gate * mdi_pi_find(): 26277c478bd9Sstevel@tonic-gate * Search the list of mdi_pathinfo nodes attached to the 26287c478bd9Sstevel@tonic-gate * pHCI/Client device node whose path address matches "paddr". 26297c478bd9Sstevel@tonic-gate * Returns a pointer to the mdi_pathinfo node if a matching node is 26307c478bd9Sstevel@tonic-gate * found. 26317c478bd9Sstevel@tonic-gate * Return Values: 26327c478bd9Sstevel@tonic-gate * mdi_pathinfo node handle 26337c478bd9Sstevel@tonic-gate * NULL 26347c478bd9Sstevel@tonic-gate * Notes: 26357c478bd9Sstevel@tonic-gate * Caller need not hold any locks to call this function. 26367c478bd9Sstevel@tonic-gate */ 26377c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 26387c478bd9Sstevel@tonic-gate mdi_pi_find(dev_info_t *pdip, char *caddr, char *paddr) 26397c478bd9Sstevel@tonic-gate { 26407c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 26417c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 26427c478bd9Sstevel@tonic-gate mdi_client_t *ct; 26437c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 26447c478bd9Sstevel@tonic-gate 26454c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, pdip, 26464c06356bSdh142964 "caddr@%s paddr@%s", caddr ? caddr : "", paddr ? paddr : "")); 26477c478bd9Sstevel@tonic-gate if ((pdip == NULL) || (paddr == NULL)) { 26487c478bd9Sstevel@tonic-gate return (NULL); 26497c478bd9Sstevel@tonic-gate } 26507c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 26517c478bd9Sstevel@tonic-gate if (ph == NULL) { 26527c478bd9Sstevel@tonic-gate /* 26537c478bd9Sstevel@tonic-gate * Invalid pHCI device, Nothing more to do. 26547c478bd9Sstevel@tonic-gate */ 26554c06356bSdh142964 MDI_DEBUG(2, (MDI_WARN, pdip, "invalid phci")); 26567c478bd9Sstevel@tonic-gate return (NULL); 26577c478bd9Sstevel@tonic-gate } 26587c478bd9Sstevel@tonic-gate 26597c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 26607c478bd9Sstevel@tonic-gate if (vh == NULL) { 26617c478bd9Sstevel@tonic-gate /* 26627c478bd9Sstevel@tonic-gate * Invalid vHCI device, Nothing more to do. 26637c478bd9Sstevel@tonic-gate */ 26644c06356bSdh142964 MDI_DEBUG(2, (MDI_WARN, pdip, "invalid vhci")); 26657c478bd9Sstevel@tonic-gate return (NULL); 26667c478bd9Sstevel@tonic-gate } 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate /* 26695e3986cbScth * Look for pathinfo node identified by paddr. 26707c478bd9Sstevel@tonic-gate */ 26717c478bd9Sstevel@tonic-gate if (caddr == NULL) { 26727c478bd9Sstevel@tonic-gate /* 26737c478bd9Sstevel@tonic-gate * Find a mdi_pathinfo node under pHCI list for a matching 26747c478bd9Sstevel@tonic-gate * unit address. 26757c478bd9Sstevel@tonic-gate */ 26765e3986cbScth MDI_PHCI_LOCK(ph); 26775e3986cbScth if (MDI_PHCI_IS_OFFLINE(ph)) { 26784c06356bSdh142964 MDI_DEBUG(2, (MDI_WARN, pdip, 26794c06356bSdh142964 "offline phci %p", (void *)ph)); 26805e3986cbScth MDI_PHCI_UNLOCK(ph); 26815e3986cbScth return (NULL); 26825e3986cbScth } 26837c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ph->ph_path_head; 26847c478bd9Sstevel@tonic-gate 26857c478bd9Sstevel@tonic-gate while (pip != NULL) { 26867c478bd9Sstevel@tonic-gate if (strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 26877c478bd9Sstevel@tonic-gate break; 26887c478bd9Sstevel@tonic-gate } 26897c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 26907c478bd9Sstevel@tonic-gate } 26915e3986cbScth MDI_PHCI_UNLOCK(ph); 26924c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, pdip, 26934c06356bSdh142964 "found %s %p", mdi_pi_spathname(pip), (void *)pip)); 26947c478bd9Sstevel@tonic-gate return (pip); 26957c478bd9Sstevel@tonic-gate } 26967c478bd9Sstevel@tonic-gate 26977c478bd9Sstevel@tonic-gate /* 26983c34adc5Sramat * XXX - Is the rest of the code in this function really necessary? 26993c34adc5Sramat * The consumers of mdi_pi_find() can search for the desired pathinfo 27003c34adc5Sramat * node by calling mdi_pi_find(pdip, NULL, paddr). Irrespective of 27013c34adc5Sramat * whether the search is based on the pathinfo nodes attached to 27023c34adc5Sramat * the pHCI or the client node, the result will be the same. 27033c34adc5Sramat */ 27043c34adc5Sramat 27053c34adc5Sramat /* 27067c478bd9Sstevel@tonic-gate * Find the client device corresponding to 'caddr' 27077c478bd9Sstevel@tonic-gate */ 27085e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 27093c34adc5Sramat 27103c34adc5Sramat /* 27113c34adc5Sramat * XXX - Passing NULL to the following function works as long as the 27123c34adc5Sramat * the client addresses (caddr) are unique per vhci basis. 27133c34adc5Sramat */ 27143c34adc5Sramat ct = i_mdi_client_find(vh, NULL, caddr); 27157c478bd9Sstevel@tonic-gate if (ct == NULL) { 27167c478bd9Sstevel@tonic-gate /* 27177c478bd9Sstevel@tonic-gate * Client not found, Obviously mdi_pathinfo node has not been 27187c478bd9Sstevel@tonic-gate * created yet. 27197c478bd9Sstevel@tonic-gate */ 27205e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 27214c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, pdip, 27224c06356bSdh142964 "client not found for caddr @%s", caddr ? caddr : "")); 27235e3986cbScth return (NULL); 27247c478bd9Sstevel@tonic-gate } 27257c478bd9Sstevel@tonic-gate 27267c478bd9Sstevel@tonic-gate /* 27277c478bd9Sstevel@tonic-gate * Hold the client lock and look for a mdi_pathinfo node with matching 27287c478bd9Sstevel@tonic-gate * pHCI and paddr 27297c478bd9Sstevel@tonic-gate */ 27307c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 27317c478bd9Sstevel@tonic-gate 27327c478bd9Sstevel@tonic-gate /* 27337c478bd9Sstevel@tonic-gate * Release the global mutex as it is no more needed. Note: We always 27347c478bd9Sstevel@tonic-gate * respect the locking order while acquiring. 27357c478bd9Sstevel@tonic-gate */ 27365e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 27377c478bd9Sstevel@tonic-gate 27387c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 27397c478bd9Sstevel@tonic-gate while (pip != NULL) { 27407c478bd9Sstevel@tonic-gate /* 27417c478bd9Sstevel@tonic-gate * Compare the unit address 27427c478bd9Sstevel@tonic-gate */ 27437c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 27447c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 27457c478bd9Sstevel@tonic-gate break; 27467c478bd9Sstevel@tonic-gate } 27477c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 27487c478bd9Sstevel@tonic-gate } 27497c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 27504c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, pdip, 27514c06356bSdh142964 "found: %s %p", mdi_pi_spathname(pip), (void *)pip)); 27527c478bd9Sstevel@tonic-gate return (pip); 27537c478bd9Sstevel@tonic-gate } 27547c478bd9Sstevel@tonic-gate 27557c478bd9Sstevel@tonic-gate /* 27567c478bd9Sstevel@tonic-gate * mdi_pi_alloc(): 27577c478bd9Sstevel@tonic-gate * Allocate and initialize a new instance of a mdi_pathinfo node. 27587c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function identifies a 27597c478bd9Sstevel@tonic-gate * unique device path is capable of having properties attached 27607c478bd9Sstevel@tonic-gate * and passed to mdi_pi_online() to fully attach and online the 27617c478bd9Sstevel@tonic-gate * path and client device node. 27627c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function must be 27637c478bd9Sstevel@tonic-gate * destroyed using mdi_pi_free() if the path is no longer 27647c478bd9Sstevel@tonic-gate * operational or if the caller fails to attach a client device 27657c478bd9Sstevel@tonic-gate * node when calling mdi_pi_online(). The framework will not free 27667c478bd9Sstevel@tonic-gate * the resources allocated. 27677c478bd9Sstevel@tonic-gate * This function can be called from both interrupt and kernel 27687c478bd9Sstevel@tonic-gate * contexts. DDI_NOSLEEP flag should be used while calling 27697c478bd9Sstevel@tonic-gate * from interrupt contexts. 27707c478bd9Sstevel@tonic-gate * Return Values: 27717c478bd9Sstevel@tonic-gate * MDI_SUCCESS 27727c478bd9Sstevel@tonic-gate * MDI_FAILURE 27737c478bd9Sstevel@tonic-gate * MDI_NOMEM 27747c478bd9Sstevel@tonic-gate */ 27757c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 27767c478bd9Sstevel@tonic-gate int 27777c478bd9Sstevel@tonic-gate mdi_pi_alloc_compatible(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 27787c478bd9Sstevel@tonic-gate char **compatible, int ncompatible, int flags, mdi_pathinfo_t **ret_pip) 27797c478bd9Sstevel@tonic-gate { 27807c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 27817c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 27827c478bd9Sstevel@tonic-gate mdi_client_t *ct; 27837c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 27847c478bd9Sstevel@tonic-gate dev_info_t *cdip; 27857c478bd9Sstevel@tonic-gate int rv = MDI_NOMEM; 27863c34adc5Sramat int path_allocated = 0; 27877c478bd9Sstevel@tonic-gate 27884c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, pdip, 27894c06356bSdh142964 "cname %s: caddr@%s paddr@%s", 27904c06356bSdh142964 cname ? cname : "", caddr ? caddr : "", paddr ? paddr : "")); 27915e3986cbScth 27927c478bd9Sstevel@tonic-gate if (pdip == NULL || cname == NULL || caddr == NULL || paddr == NULL || 27937c478bd9Sstevel@tonic-gate ret_pip == NULL) { 27947c478bd9Sstevel@tonic-gate /* Nothing more to do */ 27957c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27967c478bd9Sstevel@tonic-gate } 27977c478bd9Sstevel@tonic-gate 27987c478bd9Sstevel@tonic-gate *ret_pip = NULL; 27995e3986cbScth 28005e3986cbScth /* No allocations on detaching pHCI */ 28015e3986cbScth if (DEVI_IS_DETACHING(pdip)) { 28025e3986cbScth /* Invalid pHCI device, return failure */ 28034c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, pdip, 28044c06356bSdh142964 "!detaching pHCI=%p", (void *)pdip)); 28055e3986cbScth return (MDI_FAILURE); 28065e3986cbScth } 28075e3986cbScth 28087c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 28097c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 28107c478bd9Sstevel@tonic-gate if (ph == NULL) { 28117c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 28124c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, pdip, 28134c06356bSdh142964 "!invalid pHCI=%p", (void *)pdip)); 28147c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 28157c478bd9Sstevel@tonic-gate } 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 28187c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 28197c478bd9Sstevel@tonic-gate if (vh == NULL) { 28207c478bd9Sstevel@tonic-gate /* Invalid vHCI device, return failure */ 28214c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, pdip, 28224c06356bSdh142964 "!invalid vHCI=%p", (void *)pdip)); 28237c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 28247c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 28257c478bd9Sstevel@tonic-gate } 28267c478bd9Sstevel@tonic-gate 28277c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 28287c478bd9Sstevel@tonic-gate /* 28297c478bd9Sstevel@tonic-gate * Do not allow new node creation when pHCI is in 28307c478bd9Sstevel@tonic-gate * offline/suspended states 28317c478bd9Sstevel@tonic-gate */ 28324c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, pdip, 28334c06356bSdh142964 "pHCI=%p is not ready", (void *)ph)); 28347c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 28357c478bd9Sstevel@tonic-gate return (MDI_BUSY); 28367c478bd9Sstevel@tonic-gate } 28377c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 28387c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 28397c478bd9Sstevel@tonic-gate 28403c34adc5Sramat /* look for a matching client, create one if not found */ 28415e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 28423c34adc5Sramat ct = i_mdi_client_find(vh, cname, caddr); 28437c478bd9Sstevel@tonic-gate if (ct == NULL) { 28443c34adc5Sramat ct = i_mdi_client_alloc(vh, cname, caddr); 28453c34adc5Sramat ASSERT(ct != NULL); 28467c478bd9Sstevel@tonic-gate } 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 28497c478bd9Sstevel@tonic-gate /* 28507c478bd9Sstevel@tonic-gate * Allocate a devinfo node 28517c478bd9Sstevel@tonic-gate */ 28527c478bd9Sstevel@tonic-gate ct->ct_dip = i_mdi_devinfo_create(vh, cname, caddr, 28533c34adc5Sramat compatible, ncompatible); 28547c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 28557c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(vh, ct); 28567c478bd9Sstevel@tonic-gate goto fail; 28577c478bd9Sstevel@tonic-gate } 28587c478bd9Sstevel@tonic-gate } 28597c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 28607c478bd9Sstevel@tonic-gate 28617c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component |= MDI_COMPONENT_CLIENT; 28627c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = (caddr_t)ct; 28637c478bd9Sstevel@tonic-gate 28645e3986cbScth MDI_CLIENT_LOCK(ct); 28657c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 28667c478bd9Sstevel@tonic-gate while (pip != NULL) { 28677c478bd9Sstevel@tonic-gate /* 28687c478bd9Sstevel@tonic-gate * Compare the unit address 28697c478bd9Sstevel@tonic-gate */ 28707c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 28717c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 28727c478bd9Sstevel@tonic-gate break; 28737c478bd9Sstevel@tonic-gate } 28747c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 28757c478bd9Sstevel@tonic-gate } 28765e3986cbScth MDI_CLIENT_UNLOCK(ct); 28777c478bd9Sstevel@tonic-gate 28787c478bd9Sstevel@tonic-gate if (pip == NULL) { 28797c478bd9Sstevel@tonic-gate /* 28807c478bd9Sstevel@tonic-gate * This is a new path for this client device. Allocate and 28817c478bd9Sstevel@tonic-gate * initialize a new pathinfo node 28827c478bd9Sstevel@tonic-gate */ 28833c34adc5Sramat pip = i_mdi_pi_alloc(ph, paddr, ct); 28843c34adc5Sramat ASSERT(pip != NULL); 28853c34adc5Sramat path_allocated = 1; 28867c478bd9Sstevel@tonic-gate } 28877c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 28887c478bd9Sstevel@tonic-gate 28897c478bd9Sstevel@tonic-gate fail: 28907c478bd9Sstevel@tonic-gate /* 28917c478bd9Sstevel@tonic-gate * Release the global mutex. 28927c478bd9Sstevel@tonic-gate */ 28935e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate /* 28967c478bd9Sstevel@tonic-gate * Mark the pHCI as stable 28977c478bd9Sstevel@tonic-gate */ 28987c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 28997c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 29007c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 29017c478bd9Sstevel@tonic-gate *ret_pip = pip; 29023c34adc5Sramat 29034c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, pdip, 29044c06356bSdh142964 "alloc %s %p", mdi_pi_spathname(pip), (void *)pip)); 29055e3986cbScth 29063c34adc5Sramat if (path_allocated) 29073c34adc5Sramat vhcache_pi_add(vh->vh_config, MDI_PI(pip)); 29083c34adc5Sramat 29097c478bd9Sstevel@tonic-gate return (rv); 29107c478bd9Sstevel@tonic-gate } 29117c478bd9Sstevel@tonic-gate 29127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 29137c478bd9Sstevel@tonic-gate int 29147c478bd9Sstevel@tonic-gate mdi_pi_alloc(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 29157c478bd9Sstevel@tonic-gate int flags, mdi_pathinfo_t **ret_pip) 29167c478bd9Sstevel@tonic-gate { 29177c478bd9Sstevel@tonic-gate return (mdi_pi_alloc_compatible(pdip, cname, caddr, paddr, NULL, 0, 29187c478bd9Sstevel@tonic-gate flags, ret_pip)); 29197c478bd9Sstevel@tonic-gate } 29207c478bd9Sstevel@tonic-gate 29217c478bd9Sstevel@tonic-gate /* 29227c478bd9Sstevel@tonic-gate * i_mdi_pi_alloc(): 29237c478bd9Sstevel@tonic-gate * Allocate a mdi_pathinfo node and add to the pHCI path list 29247c478bd9Sstevel@tonic-gate * Return Values: 29257c478bd9Sstevel@tonic-gate * mdi_pathinfo 29267c478bd9Sstevel@tonic-gate */ 29277c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 29287c478bd9Sstevel@tonic-gate static mdi_pathinfo_t * 29293c34adc5Sramat i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct) 29307c478bd9Sstevel@tonic-gate { 29313c34adc5Sramat mdi_pathinfo_t *pip; 29327c478bd9Sstevel@tonic-gate int ct_circular; 29337c478bd9Sstevel@tonic-gate int ph_circular; 29344c06356bSdh142964 static char path[MAXPATHLEN]; /* mdi_pathmap_mutex protects */ 2935602ca9eaScth char *path_persistent; 2936602ca9eaScth int path_instance; 2937602ca9eaScth mod_hash_val_t hv; 29387c478bd9Sstevel@tonic-gate 29395e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(ph->ph_vhci)); 29405e3986cbScth 29413c34adc5Sramat pip = kmem_zalloc(sizeof (struct mdi_pathinfo), KM_SLEEP); 29427c478bd9Sstevel@tonic-gate mutex_init(&MDI_PI(pip)->pi_mutex, NULL, MUTEX_DEFAULT, NULL); 29437c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PATHINFO_STATE_INIT | 29447c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_TRANSIENT; 29457c478bd9Sstevel@tonic-gate 29467c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_USER_DISABLED(ph)) 29477c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 29487c478bd9Sstevel@tonic-gate 29497c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED_TRANSIENT(ph)) 29507c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 29517c478bd9Sstevel@tonic-gate 29527c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED(ph)) 29537c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 29547c478bd9Sstevel@tonic-gate 29557c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_old_state = MDI_PATHINFO_STATE_INIT; 29567c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_state_cv, NULL, CV_DEFAULT, NULL); 29577c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = ct; 29587c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = ph; 29593c34adc5Sramat MDI_PI(pip)->pi_addr = kmem_alloc(strlen(paddr) + 1, KM_SLEEP); 29607c478bd9Sstevel@tonic-gate (void) strcpy(MDI_PI(pip)->pi_addr, paddr); 2961602ca9eaScth 2962602ca9eaScth /* 2963602ca9eaScth * We form the "path" to the pathinfo node, and see if we have 2964602ca9eaScth * already allocated a 'path_instance' for that "path". If so, 2965602ca9eaScth * we use the already allocated 'path_instance'. If not, we 2966602ca9eaScth * allocate a new 'path_instance' and associate it with a copy of 2967602ca9eaScth * the "path" string (which is never freed). The association 2968602ca9eaScth * between a 'path_instance' this "path" string persists until 2969602ca9eaScth * reboot. 2970602ca9eaScth */ 2971602ca9eaScth mutex_enter(&mdi_pathmap_mutex); 2972602ca9eaScth (void) ddi_pathname(ph->ph_dip, path); 2973602ca9eaScth (void) sprintf(path + strlen(path), "/%s@%s", 297455e592a2SRandall Ralphs mdi_pi_get_node_name(pip), mdi_pi_get_addr(pip)); 2975602ca9eaScth if (mod_hash_find(mdi_pathmap_bypath, (mod_hash_key_t)path, &hv) == 0) { 2976602ca9eaScth path_instance = (uint_t)(intptr_t)hv; 2977602ca9eaScth } else { 2978602ca9eaScth /* allocate a new 'path_instance' and persistent "path" */ 2979602ca9eaScth path_instance = mdi_pathmap_instance++; 2980602ca9eaScth path_persistent = i_ddi_strdup(path, KM_SLEEP); 2981602ca9eaScth (void) mod_hash_insert(mdi_pathmap_bypath, 2982602ca9eaScth (mod_hash_key_t)path_persistent, 2983602ca9eaScth (mod_hash_val_t)(intptr_t)path_instance); 2984602ca9eaScth (void) mod_hash_insert(mdi_pathmap_byinstance, 2985602ca9eaScth (mod_hash_key_t)(intptr_t)path_instance, 2986602ca9eaScth (mod_hash_val_t)path_persistent); 29874c06356bSdh142964 29884c06356bSdh142964 /* create shortpath name */ 29894c06356bSdh142964 (void) snprintf(path, sizeof(path), "%s%d/%s@%s", 29904c06356bSdh142964 ddi_driver_name(ph->ph_dip), ddi_get_instance(ph->ph_dip), 29914c06356bSdh142964 mdi_pi_get_node_name(pip), mdi_pi_get_addr(pip)); 29924c06356bSdh142964 path_persistent = i_ddi_strdup(path, KM_SLEEP); 29934c06356bSdh142964 (void) mod_hash_insert(mdi_pathmap_sbyinstance, 29944c06356bSdh142964 (mod_hash_key_t)(intptr_t)path_instance, 29954c06356bSdh142964 (mod_hash_val_t)path_persistent); 2996602ca9eaScth } 2997602ca9eaScth mutex_exit(&mdi_pathmap_mutex); 2998602ca9eaScth MDI_PI(pip)->pi_path_instance = path_instance; 2999602ca9eaScth 30003c34adc5Sramat (void) nvlist_alloc(&MDI_PI(pip)->pi_prop, NV_UNIQUE_NAME, KM_SLEEP); 30013c34adc5Sramat ASSERT(MDI_PI(pip)->pi_prop != NULL); 30027c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = NULL; 30037c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = NULL; 30047c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = NULL; 30057c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 30067c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 30077c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt = 0; 30087c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 30097c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = 1; 30107c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_ref_cv, NULL, CV_DEFAULT, NULL); 30117c478bd9Sstevel@tonic-gate 30127c478bd9Sstevel@tonic-gate /* 30137c478bd9Sstevel@tonic-gate * Lock both dev_info nodes against changes in parallel. 30145e3986cbScth * 30155e3986cbScth * The ndi_devi_enter(Client), is atypical since the client is a leaf. 30165e3986cbScth * This atypical operation is done to synchronize pathinfo nodes 30175e3986cbScth * during devinfo snapshot (see di_register_pip) by 'pretending' that 30185e3986cbScth * the pathinfo nodes are children of the Client. 30197c478bd9Sstevel@tonic-gate */ 30207c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 30217c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 30227c478bd9Sstevel@tonic-gate 30237c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(ph, pip); 30247c478bd9Sstevel@tonic-gate i_mdi_client_add_path(ct, pip); 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 30277c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 30287c478bd9Sstevel@tonic-gate 30297c478bd9Sstevel@tonic-gate return (pip); 30307c478bd9Sstevel@tonic-gate } 30317c478bd9Sstevel@tonic-gate 30327c478bd9Sstevel@tonic-gate /* 3033602ca9eaScth * mdi_pi_pathname_by_instance(): 3034602ca9eaScth * Lookup of "path" by 'path_instance'. Return "path". 3035602ca9eaScth * NOTE: returned "path" remains valid forever (until reboot). 3036602ca9eaScth */ 3037602ca9eaScth char * 3038602ca9eaScth mdi_pi_pathname_by_instance(int path_instance) 3039602ca9eaScth { 3040602ca9eaScth char *path; 3041602ca9eaScth mod_hash_val_t hv; 3042602ca9eaScth 3043602ca9eaScth /* mdi_pathmap lookup of "path" by 'path_instance' */ 3044602ca9eaScth mutex_enter(&mdi_pathmap_mutex); 3045602ca9eaScth if (mod_hash_find(mdi_pathmap_byinstance, 3046602ca9eaScth (mod_hash_key_t)(intptr_t)path_instance, &hv) == 0) 3047602ca9eaScth path = (char *)hv; 3048602ca9eaScth else 3049602ca9eaScth path = NULL; 3050602ca9eaScth mutex_exit(&mdi_pathmap_mutex); 3051602ca9eaScth return (path); 3052602ca9eaScth } 3053602ca9eaScth 3054602ca9eaScth /* 30554c06356bSdh142964 * mdi_pi_spathname_by_instance(): 30564c06356bSdh142964 * Lookup of "shortpath" by 'path_instance'. Return "shortpath". 30574c06356bSdh142964 * NOTE: returned "shortpath" remains valid forever (until reboot). 30584c06356bSdh142964 */ 30594c06356bSdh142964 char * 30604c06356bSdh142964 mdi_pi_spathname_by_instance(int path_instance) 30614c06356bSdh142964 { 30624c06356bSdh142964 char *path; 30634c06356bSdh142964 mod_hash_val_t hv; 30644c06356bSdh142964 30654c06356bSdh142964 /* mdi_pathmap lookup of "path" by 'path_instance' */ 30664c06356bSdh142964 mutex_enter(&mdi_pathmap_mutex); 30674c06356bSdh142964 if (mod_hash_find(mdi_pathmap_sbyinstance, 30684c06356bSdh142964 (mod_hash_key_t)(intptr_t)path_instance, &hv) == 0) 30694c06356bSdh142964 path = (char *)hv; 30704c06356bSdh142964 else 30714c06356bSdh142964 path = NULL; 30724c06356bSdh142964 mutex_exit(&mdi_pathmap_mutex); 30734c06356bSdh142964 return (path); 30744c06356bSdh142964 } 30754c06356bSdh142964 30764c06356bSdh142964 30774c06356bSdh142964 /* 30787c478bd9Sstevel@tonic-gate * i_mdi_phci_add_path(): 30797c478bd9Sstevel@tonic-gate * Add a mdi_pathinfo node to pHCI list. 30807c478bd9Sstevel@tonic-gate * Notes: 30817c478bd9Sstevel@tonic-gate * Caller should per-pHCI mutex 30827c478bd9Sstevel@tonic-gate */ 30837c478bd9Sstevel@tonic-gate static void 30847c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 30857c478bd9Sstevel@tonic-gate { 30867c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 30877c478bd9Sstevel@tonic-gate 30885e3986cbScth MDI_PHCI_LOCK(ph); 30897c478bd9Sstevel@tonic-gate if (ph->ph_path_head == NULL) { 30907c478bd9Sstevel@tonic-gate ph->ph_path_head = pip; 30917c478bd9Sstevel@tonic-gate } else { 30927c478bd9Sstevel@tonic-gate MDI_PI(ph->ph_path_tail)->pi_phci_link = MDI_PI(pip); 30937c478bd9Sstevel@tonic-gate } 30947c478bd9Sstevel@tonic-gate ph->ph_path_tail = pip; 30957c478bd9Sstevel@tonic-gate ph->ph_path_count++; 30965e3986cbScth MDI_PHCI_UNLOCK(ph); 30977c478bd9Sstevel@tonic-gate } 30987c478bd9Sstevel@tonic-gate 30997c478bd9Sstevel@tonic-gate /* 31007c478bd9Sstevel@tonic-gate * i_mdi_client_add_path(): 31017c478bd9Sstevel@tonic-gate * Add mdi_pathinfo node to client list 31027c478bd9Sstevel@tonic-gate */ 31037c478bd9Sstevel@tonic-gate static void 31047c478bd9Sstevel@tonic-gate i_mdi_client_add_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 31057c478bd9Sstevel@tonic-gate { 31067c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 31077c478bd9Sstevel@tonic-gate 31085e3986cbScth MDI_CLIENT_LOCK(ct); 31097c478bd9Sstevel@tonic-gate if (ct->ct_path_head == NULL) { 31107c478bd9Sstevel@tonic-gate ct->ct_path_head = pip; 31117c478bd9Sstevel@tonic-gate } else { 31127c478bd9Sstevel@tonic-gate MDI_PI(ct->ct_path_tail)->pi_client_link = MDI_PI(pip); 31137c478bd9Sstevel@tonic-gate } 31147c478bd9Sstevel@tonic-gate ct->ct_path_tail = pip; 31157c478bd9Sstevel@tonic-gate ct->ct_path_count++; 31165e3986cbScth MDI_CLIENT_UNLOCK(ct); 31177c478bd9Sstevel@tonic-gate } 31187c478bd9Sstevel@tonic-gate 31197c478bd9Sstevel@tonic-gate /* 31207c478bd9Sstevel@tonic-gate * mdi_pi_free(): 31217c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node and also client device node if this 31227c478bd9Sstevel@tonic-gate * is the last path to the device 31237c478bd9Sstevel@tonic-gate * Return Values: 31247c478bd9Sstevel@tonic-gate * MDI_SUCCESS 31257c478bd9Sstevel@tonic-gate * MDI_FAILURE 31267c478bd9Sstevel@tonic-gate * MDI_BUSY 31277c478bd9Sstevel@tonic-gate */ 31287c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 31297c478bd9Sstevel@tonic-gate int 31307c478bd9Sstevel@tonic-gate mdi_pi_free(mdi_pathinfo_t *pip, int flags) 31317c478bd9Sstevel@tonic-gate { 31329aed1621SDavid Hollister int rv; 31337c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 31347c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 31357c478bd9Sstevel@tonic-gate mdi_client_t *ct; 31367c478bd9Sstevel@tonic-gate int (*f)(); 31377c478bd9Sstevel@tonic-gate int client_held = 0; 31387c478bd9Sstevel@tonic-gate 31397c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 31407c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 31417c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 31427c478bd9Sstevel@tonic-gate if (ph == NULL) { 31437c478bd9Sstevel@tonic-gate /* 31447c478bd9Sstevel@tonic-gate * Invalid pHCI device, return failure 31457c478bd9Sstevel@tonic-gate */ 31464c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, NULL, 31474c06356bSdh142964 "!invalid pHCI: pip %s %p", 31484c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 31497c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31507c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 31517c478bd9Sstevel@tonic-gate } 31527c478bd9Sstevel@tonic-gate 31537c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 31547c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 31557c478bd9Sstevel@tonic-gate if (vh == NULL) { 31567c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 31574c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, ph->ph_dip, 31584c06356bSdh142964 "!invalid vHCI: pip %s %p", 31594c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 31607c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31617c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 31627c478bd9Sstevel@tonic-gate } 31637c478bd9Sstevel@tonic-gate 31647c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 31657c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 31667c478bd9Sstevel@tonic-gate if (ct == NULL) { 31677c478bd9Sstevel@tonic-gate /* 31687c478bd9Sstevel@tonic-gate * Invalid Client device, return failure 31697c478bd9Sstevel@tonic-gate */ 31704c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, ph->ph_dip, 31714c06356bSdh142964 "!invalid client: pip %s %p", 31724c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 31737c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31747c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 31757c478bd9Sstevel@tonic-gate } 31767c478bd9Sstevel@tonic-gate 31777c478bd9Sstevel@tonic-gate /* 31787c478bd9Sstevel@tonic-gate * Check to see for busy condition. A mdi_pathinfo can only be freed 31797c478bd9Sstevel@tonic-gate * if the node state is either offline or init and the reference count 31807c478bd9Sstevel@tonic-gate * is zero. 31817c478bd9Sstevel@tonic-gate */ 31827c478bd9Sstevel@tonic-gate if (!(MDI_PI_IS_OFFLINE(pip) || MDI_PI_IS_INIT(pip) || 31837c478bd9Sstevel@tonic-gate MDI_PI_IS_INITING(pip))) { 31847c478bd9Sstevel@tonic-gate /* 31857c478bd9Sstevel@tonic-gate * Node is busy 31867c478bd9Sstevel@tonic-gate */ 31874c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, ct->ct_dip, 31884c06356bSdh142964 "!busy: pip %s %p", mdi_pi_spathname(pip), (void *)pip)); 31897c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31907c478bd9Sstevel@tonic-gate return (MDI_BUSY); 31917c478bd9Sstevel@tonic-gate } 31927c478bd9Sstevel@tonic-gate 31937c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 31947c478bd9Sstevel@tonic-gate /* 31957c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 31967c478bd9Sstevel@tonic-gate */ 31974c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip, 31984c06356bSdh142964 "!%d cmds still pending on path: %s %p", 31994c06356bSdh142964 MDI_PI(pip)->pi_ref_cnt, 32004c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 3201d3d50737SRafael Vanoni if (cv_reltimedwait(&MDI_PI(pip)->pi_ref_cv, 3202d3d50737SRafael Vanoni &MDI_PI(pip)->pi_mutex, drv_usectohz(60 * 1000000), 3203d3d50737SRafael Vanoni TR_CLOCK_TICK) == -1) { 32047c478bd9Sstevel@tonic-gate /* 32057c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 32067c478bd9Sstevel@tonic-gate * being signaled. 32077c478bd9Sstevel@tonic-gate */ 32084c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip, 32094c06356bSdh142964 "!Timeout reached on path %s %p without the cond", 32104c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 32114c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip, 32124c06356bSdh142964 "!%d cmds still pending on path %s %p", 32134c06356bSdh142964 MDI_PI(pip)->pi_ref_cnt, 32144c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 32157c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 32167c478bd9Sstevel@tonic-gate return (MDI_BUSY); 32177c478bd9Sstevel@tonic-gate } 32187c478bd9Sstevel@tonic-gate } 32197c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 32207c478bd9Sstevel@tonic-gate client_held = 1; 32217c478bd9Sstevel@tonic-gate } 32227c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 32237c478bd9Sstevel@tonic-gate 32243c34adc5Sramat vhcache_pi_remove(vh->vh_config, MDI_PI(pip)); 32253c34adc5Sramat 32267c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 32277c478bd9Sstevel@tonic-gate 32285e3986cbScth /* Prevent further failovers till MDI_VHCI_CLIENT_LOCK is held */ 32297c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_PATH_FREE_IN_PROGRESS(ct); 32307c478bd9Sstevel@tonic-gate 32317c478bd9Sstevel@tonic-gate /* 32327c478bd9Sstevel@tonic-gate * Wait till failover is complete before removing this node. 32337c478bd9Sstevel@tonic-gate */ 32347c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 32357c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 32367c478bd9Sstevel@tonic-gate 32377c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 32385e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 32397c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 32407c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_PATH_FREE_IN_PROGRESS(ct); 32417c478bd9Sstevel@tonic-gate 32427c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_INITING(pip)) { 32437c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_uninit; 32447c478bd9Sstevel@tonic-gate if (f != NULL) { 32457c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 32467c478bd9Sstevel@tonic-gate } 32479aed1621SDavid Hollister } else 32489aed1621SDavid Hollister rv = MDI_SUCCESS; 32499aed1621SDavid Hollister 32507c478bd9Sstevel@tonic-gate /* 32517c478bd9Sstevel@tonic-gate * If vo_pi_uninit() completed successfully. 32527c478bd9Sstevel@tonic-gate */ 32537c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 32547c478bd9Sstevel@tonic-gate if (client_held) { 32554c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip, 32567c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 32577c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 32587c478bd9Sstevel@tonic-gate } 32597c478bd9Sstevel@tonic-gate i_mdi_pi_free(ph, pip, ct); 32607c478bd9Sstevel@tonic-gate if (ct->ct_path_count == 0) { 32617c478bd9Sstevel@tonic-gate /* 32627c478bd9Sstevel@tonic-gate * Client lost its last path. 32637c478bd9Sstevel@tonic-gate * Clean up the client device 32647c478bd9Sstevel@tonic-gate */ 32657c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 32667c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(ct->ct_vhci, ct); 32675e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 32687c478bd9Sstevel@tonic-gate return (rv); 32697c478bd9Sstevel@tonic-gate } 32707c478bd9Sstevel@tonic-gate } 32717c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 32725e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 32733c34adc5Sramat 32743c34adc5Sramat if (rv == MDI_FAILURE) 32753c34adc5Sramat vhcache_pi_add(vh->vh_config, MDI_PI(pip)); 32763c34adc5Sramat 32777c478bd9Sstevel@tonic-gate return (rv); 32787c478bd9Sstevel@tonic-gate } 32797c478bd9Sstevel@tonic-gate 32807c478bd9Sstevel@tonic-gate /* 32817c478bd9Sstevel@tonic-gate * i_mdi_pi_free(): 32827c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node 32837c478bd9Sstevel@tonic-gate */ 32847c478bd9Sstevel@tonic-gate static void 32857c478bd9Sstevel@tonic-gate i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct) 32867c478bd9Sstevel@tonic-gate { 32877c478bd9Sstevel@tonic-gate int ct_circular; 32887c478bd9Sstevel@tonic-gate int ph_circular; 32897c478bd9Sstevel@tonic-gate 32905e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 32915e3986cbScth 32927c478bd9Sstevel@tonic-gate /* 32937c478bd9Sstevel@tonic-gate * remove any per-path kstats 32947c478bd9Sstevel@tonic-gate */ 32957c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(pip); 32967c478bd9Sstevel@tonic-gate 32975e3986cbScth /* See comments in i_mdi_pi_alloc() */ 32987c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 32997c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 33007c478bd9Sstevel@tonic-gate 33017c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(ct, pip); 33027c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(ph, pip); 33037c478bd9Sstevel@tonic-gate 33047c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 33057c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate mutex_destroy(&MDI_PI(pip)->pi_mutex); 33087c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_state_cv); 33097c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_ref_cv); 33107c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_addr) { 33117c478bd9Sstevel@tonic-gate kmem_free(MDI_PI(pip)->pi_addr, 33127c478bd9Sstevel@tonic-gate strlen(MDI_PI(pip)->pi_addr) + 1); 33137c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr = NULL; 33147c478bd9Sstevel@tonic-gate } 33157c478bd9Sstevel@tonic-gate 33167c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop) { 33177c478bd9Sstevel@tonic-gate (void) nvlist_free(MDI_PI(pip)->pi_prop); 33187c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_prop = NULL; 33197c478bd9Sstevel@tonic-gate } 33207c478bd9Sstevel@tonic-gate kmem_free(pip, sizeof (struct mdi_pathinfo)); 33217c478bd9Sstevel@tonic-gate } 33227c478bd9Sstevel@tonic-gate 33237c478bd9Sstevel@tonic-gate 33247c478bd9Sstevel@tonic-gate /* 33257c478bd9Sstevel@tonic-gate * i_mdi_phci_remove_path(): 33267c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from pHCI list. 33277c478bd9Sstevel@tonic-gate * Notes: 33287c478bd9Sstevel@tonic-gate * Caller should hold per-pHCI mutex 33297c478bd9Sstevel@tonic-gate */ 33307c478bd9Sstevel@tonic-gate static void 33317c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 33327c478bd9Sstevel@tonic-gate { 33337c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 33347c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path = NULL; 33357c478bd9Sstevel@tonic-gate 33367c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 33377c478bd9Sstevel@tonic-gate 33385e3986cbScth MDI_PHCI_LOCK(ph); 33397c478bd9Sstevel@tonic-gate path = ph->ph_path_head; 33407c478bd9Sstevel@tonic-gate while (path != NULL) { 33417c478bd9Sstevel@tonic-gate if (path == pip) { 33427c478bd9Sstevel@tonic-gate break; 33437c478bd9Sstevel@tonic-gate } 33447c478bd9Sstevel@tonic-gate prev = path; 33457c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 33467c478bd9Sstevel@tonic-gate } 33477c478bd9Sstevel@tonic-gate 33487c478bd9Sstevel@tonic-gate if (path) { 33497c478bd9Sstevel@tonic-gate ph->ph_path_count--; 33507c478bd9Sstevel@tonic-gate if (prev) { 33517c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_phci_link = MDI_PI(path)->pi_phci_link; 33527c478bd9Sstevel@tonic-gate } else { 33537c478bd9Sstevel@tonic-gate ph->ph_path_head = 33547c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 33557c478bd9Sstevel@tonic-gate } 33567c478bd9Sstevel@tonic-gate if (ph->ph_path_tail == path) { 33577c478bd9Sstevel@tonic-gate ph->ph_path_tail = prev; 33587c478bd9Sstevel@tonic-gate } 33597c478bd9Sstevel@tonic-gate } 33607c478bd9Sstevel@tonic-gate 33617c478bd9Sstevel@tonic-gate /* 33627c478bd9Sstevel@tonic-gate * Clear the pHCI link 33637c478bd9Sstevel@tonic-gate */ 33647c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 33657c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = NULL; 33665e3986cbScth MDI_PHCI_UNLOCK(ph); 33677c478bd9Sstevel@tonic-gate } 33687c478bd9Sstevel@tonic-gate 33697c478bd9Sstevel@tonic-gate /* 33707c478bd9Sstevel@tonic-gate * i_mdi_client_remove_path(): 33717c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from client path list. 33727c478bd9Sstevel@tonic-gate */ 33737c478bd9Sstevel@tonic-gate static void 33747c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 33757c478bd9Sstevel@tonic-gate { 33767c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 33777c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path; 33787c478bd9Sstevel@tonic-gate 33797c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 33807c478bd9Sstevel@tonic-gate 33815e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 33827c478bd9Sstevel@tonic-gate path = ct->ct_path_head; 33837c478bd9Sstevel@tonic-gate while (path != NULL) { 33847c478bd9Sstevel@tonic-gate if (path == pip) { 33857c478bd9Sstevel@tonic-gate break; 33867c478bd9Sstevel@tonic-gate } 33877c478bd9Sstevel@tonic-gate prev = path; 33887c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 33897c478bd9Sstevel@tonic-gate } 33907c478bd9Sstevel@tonic-gate 33917c478bd9Sstevel@tonic-gate if (path) { 33927c478bd9Sstevel@tonic-gate ct->ct_path_count--; 33937c478bd9Sstevel@tonic-gate if (prev) { 33947c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_client_link = 33957c478bd9Sstevel@tonic-gate MDI_PI(path)->pi_client_link; 33967c478bd9Sstevel@tonic-gate } else { 33977c478bd9Sstevel@tonic-gate ct->ct_path_head = 33987c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 33997c478bd9Sstevel@tonic-gate } 34007c478bd9Sstevel@tonic-gate if (ct->ct_path_tail == path) { 34017c478bd9Sstevel@tonic-gate ct->ct_path_tail = prev; 34027c478bd9Sstevel@tonic-gate } 34037c478bd9Sstevel@tonic-gate if (ct->ct_path_last == path) { 34047c478bd9Sstevel@tonic-gate ct->ct_path_last = ct->ct_path_head; 34057c478bd9Sstevel@tonic-gate } 34067c478bd9Sstevel@tonic-gate } 34077c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 34087c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = NULL; 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate 34117c478bd9Sstevel@tonic-gate /* 34127c478bd9Sstevel@tonic-gate * i_mdi_pi_state_change(): 34137c478bd9Sstevel@tonic-gate * online a mdi_pathinfo node 34147c478bd9Sstevel@tonic-gate * 34157c478bd9Sstevel@tonic-gate * Return Values: 34167c478bd9Sstevel@tonic-gate * MDI_SUCCESS 34177c478bd9Sstevel@tonic-gate * MDI_FAILURE 34187c478bd9Sstevel@tonic-gate */ 34197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 34207c478bd9Sstevel@tonic-gate static int 34217c478bd9Sstevel@tonic-gate i_mdi_pi_state_change(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state, int flag) 34227c478bd9Sstevel@tonic-gate { 34237c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 34247c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 34257c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 34267c478bd9Sstevel@tonic-gate mdi_client_t *ct; 34277c478bd9Sstevel@tonic-gate int (*f)(); 34287c478bd9Sstevel@tonic-gate dev_info_t *cdip; 34297c478bd9Sstevel@tonic-gate 34307c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34317c478bd9Sstevel@tonic-gate 34327c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 34337c478bd9Sstevel@tonic-gate ASSERT(ph); 34347c478bd9Sstevel@tonic-gate if (ph == NULL) { 34357c478bd9Sstevel@tonic-gate /* 34367c478bd9Sstevel@tonic-gate * Invalid pHCI device, fail the request 34377c478bd9Sstevel@tonic-gate */ 34387c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34394c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, NULL, 34404c06356bSdh142964 "!invalid phci: pip %s %p", 34414c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 34427c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 34437c478bd9Sstevel@tonic-gate } 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 34467c478bd9Sstevel@tonic-gate ASSERT(vh); 34477c478bd9Sstevel@tonic-gate if (vh == NULL) { 34487c478bd9Sstevel@tonic-gate /* 34497c478bd9Sstevel@tonic-gate * Invalid vHCI device, fail the request 34507c478bd9Sstevel@tonic-gate */ 34517c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34524c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, ph->ph_dip, 34534c06356bSdh142964 "!invalid vhci: pip %s %p", 34544c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 34557c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 34567c478bd9Sstevel@tonic-gate } 34577c478bd9Sstevel@tonic-gate 34587c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 34597c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 34607c478bd9Sstevel@tonic-gate if (ct == NULL) { 34617c478bd9Sstevel@tonic-gate /* 34627c478bd9Sstevel@tonic-gate * Invalid client device, fail the request 34637c478bd9Sstevel@tonic-gate */ 34647c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34654c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, ph->ph_dip, 34664c06356bSdh142964 "!invalid client: pip %s %p", 34674c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 34687c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 34697c478bd9Sstevel@tonic-gate } 34707c478bd9Sstevel@tonic-gate 34717c478bd9Sstevel@tonic-gate /* 34727c478bd9Sstevel@tonic-gate * If this path has not been initialized yet, Callback vHCI driver's 34737c478bd9Sstevel@tonic-gate * pathinfo node initialize entry point 34747c478bd9Sstevel@tonic-gate */ 34757c478bd9Sstevel@tonic-gate 34767c478bd9Sstevel@tonic-gate if (MDI_PI_IS_INITING(pip)) { 34777c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34787c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_init; 34797c478bd9Sstevel@tonic-gate if (f != NULL) { 34807c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 34817c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 34824c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, ct->ct_dip, 34834c06356bSdh142964 "!vo_pi_init failed: vHCI %p, pip %s %p", 34844c06356bSdh142964 (void *)vh, mdi_pi_spathname(pip), 34854c06356bSdh142964 (void *)pip)); 34867c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 34877c478bd9Sstevel@tonic-gate } 34887c478bd9Sstevel@tonic-gate } 34897c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34907c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 34917c478bd9Sstevel@tonic-gate } 34927c478bd9Sstevel@tonic-gate 34937c478bd9Sstevel@tonic-gate /* 34947c478bd9Sstevel@tonic-gate * Do not allow state transition when pHCI is in offline/suspended 34957c478bd9Sstevel@tonic-gate * states 34967c478bd9Sstevel@tonic-gate */ 34977c478bd9Sstevel@tonic-gate i_mdi_phci_lock(ph, pip); 34987c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 34994c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, ct->ct_dip, 35004c06356bSdh142964 "!pHCI not ready, pHCI=%p", (void *)ph)); 35017c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 35027c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 35037c478bd9Sstevel@tonic-gate return (MDI_BUSY); 35047c478bd9Sstevel@tonic-gate } 35057c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 35067c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 35077c478bd9Sstevel@tonic-gate 35087c478bd9Sstevel@tonic-gate /* 35097c478bd9Sstevel@tonic-gate * Check if mdi_pathinfo state is in transient state. 35107c478bd9Sstevel@tonic-gate * If yes, offlining is in progress and wait till transient state is 35117c478bd9Sstevel@tonic-gate * cleared. 35127c478bd9Sstevel@tonic-gate */ 35137c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 35147c478bd9Sstevel@tonic-gate while (MDI_PI_IS_TRANSIENT(pip)) { 35157c478bd9Sstevel@tonic-gate cv_wait(&MDI_PI(pip)->pi_state_cv, 35167c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex); 35177c478bd9Sstevel@tonic-gate } 35187c478bd9Sstevel@tonic-gate } 35197c478bd9Sstevel@tonic-gate 35207c478bd9Sstevel@tonic-gate /* 35217c478bd9Sstevel@tonic-gate * Grab the client lock in reverse order sequence and release the 35227c478bd9Sstevel@tonic-gate * mdi_pathinfo mutex. 35237c478bd9Sstevel@tonic-gate */ 35247c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 35257c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 35267c478bd9Sstevel@tonic-gate 35277c478bd9Sstevel@tonic-gate /* 35287c478bd9Sstevel@tonic-gate * Wait till failover state is cleared 35297c478bd9Sstevel@tonic-gate */ 35307c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 35317c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 35327c478bd9Sstevel@tonic-gate 35337c478bd9Sstevel@tonic-gate /* 35347c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 35357c478bd9Sstevel@tonic-gate */ 35367c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 35377c478bd9Sstevel@tonic-gate switch (state) { 35387c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_ONLINE: 35397c478bd9Sstevel@tonic-gate MDI_PI_SET_ONLINING(pip); 35407c478bd9Sstevel@tonic-gate break; 35417c478bd9Sstevel@tonic-gate 35427c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_STANDBY: 35437c478bd9Sstevel@tonic-gate MDI_PI_SET_STANDBYING(pip); 35447c478bd9Sstevel@tonic-gate break; 35457c478bd9Sstevel@tonic-gate 35467c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_FAULT: 35477c478bd9Sstevel@tonic-gate /* 35487c478bd9Sstevel@tonic-gate * Mark the pathinfo state as FAULTED 35497c478bd9Sstevel@tonic-gate */ 35507c478bd9Sstevel@tonic-gate MDI_PI_SET_FAULTING(pip); 35517c478bd9Sstevel@tonic-gate MDI_PI_ERRSTAT(pip, MDI_PI_HARDERR); 35527c478bd9Sstevel@tonic-gate break; 35537c478bd9Sstevel@tonic-gate 35547c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_OFFLINE: 35557c478bd9Sstevel@tonic-gate /* 35567c478bd9Sstevel@tonic-gate * ndi_devi_offline() cannot hold pip or ct locks. 35577c478bd9Sstevel@tonic-gate */ 35587c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 35594c06356bSdh142964 35607c478bd9Sstevel@tonic-gate /* 35614c06356bSdh142964 * If this is a user initiated path online->offline operation 35624c06356bSdh142964 * who's success would transition a client from DEGRADED to 35634c06356bSdh142964 * FAILED then only proceed if we can offline the client first. 35647c478bd9Sstevel@tonic-gate */ 35657c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 35664c06356bSdh142964 if ((flag & NDI_USER_REQ) && 35674c06356bSdh142964 MDI_PI_IS_ONLINE(pip) && 35684c06356bSdh142964 (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED)) { 35697c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 35704c06356bSdh142964 rv = ndi_devi_offline(cdip, NDI_DEVFS_CLEAN); 35717c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 35727c478bd9Sstevel@tonic-gate /* 35737c478bd9Sstevel@tonic-gate * Convert to MDI error code 35747c478bd9Sstevel@tonic-gate */ 35757c478bd9Sstevel@tonic-gate switch (rv) { 35767c478bd9Sstevel@tonic-gate case NDI_BUSY: 35777c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 35787c478bd9Sstevel@tonic-gate break; 35797c478bd9Sstevel@tonic-gate default: 35807c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 35817c478bd9Sstevel@tonic-gate break; 35827c478bd9Sstevel@tonic-gate } 35837c478bd9Sstevel@tonic-gate goto state_change_exit; 35847c478bd9Sstevel@tonic-gate } else { 35857c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 35867c478bd9Sstevel@tonic-gate } 35877c478bd9Sstevel@tonic-gate } 35887c478bd9Sstevel@tonic-gate /* 35897c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 35907c478bd9Sstevel@tonic-gate */ 35917c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 35927c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 35937c478bd9Sstevel@tonic-gate break; 35947c478bd9Sstevel@tonic-gate } 35957c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 35967c478bd9Sstevel@tonic-gate MDI_CLIENT_UNSTABLE(ct); 35977c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 35987c478bd9Sstevel@tonic-gate 35997c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 36005e3986cbScth if (f != NULL) 36017c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, state, 0, flag); 36025e3986cbScth 36035e3986cbScth MDI_CLIENT_LOCK(ct); 36045e3986cbScth MDI_PI_LOCK(pip); 36057c478bd9Sstevel@tonic-gate if (rv == MDI_NOT_SUPPORTED) { 36067c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DEV_NOT_SUPPORTED(ct); 36077c478bd9Sstevel@tonic-gate } 36087c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 36094c06356bSdh142964 MDI_DEBUG(2, (MDI_WARN, ct->ct_dip, 36104c06356bSdh142964 "vo_pi_state_change failed: rv %x", rv)); 36117c478bd9Sstevel@tonic-gate } 36127c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 36137c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 36147c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 36157c478bd9Sstevel@tonic-gate } else { 36167c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip); 36177c478bd9Sstevel@tonic-gate } 36187c478bd9Sstevel@tonic-gate } 36197c478bd9Sstevel@tonic-gate 36207c478bd9Sstevel@tonic-gate /* 36217c478bd9Sstevel@tonic-gate * Wake anyone waiting for this mdi_pathinfo node 36227c478bd9Sstevel@tonic-gate */ 36237c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 36247c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 36257c478bd9Sstevel@tonic-gate 36267c478bd9Sstevel@tonic-gate /* 36277c478bd9Sstevel@tonic-gate * Mark the client device as stable 36287c478bd9Sstevel@tonic-gate */ 36297c478bd9Sstevel@tonic-gate MDI_CLIENT_STABLE(ct); 36307c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 36317c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 36327c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 36337c478bd9Sstevel@tonic-gate 36347c478bd9Sstevel@tonic-gate /* 36357c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 36367c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 36377c478bd9Sstevel@tonic-gate * state accordingly 36387c478bd9Sstevel@tonic-gate */ 36397c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 36407c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 36417c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 36427c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 36437c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 3644737d277aScth if (cdip && !i_ddi_devi_attached(cdip) && 36457c478bd9Sstevel@tonic-gate ((state == MDI_PATHINFO_STATE_ONLINE) || 36467c478bd9Sstevel@tonic-gate (state == MDI_PATHINFO_STATE_STANDBY))) { 36477c478bd9Sstevel@tonic-gate 36487c478bd9Sstevel@tonic-gate /* 36497c478bd9Sstevel@tonic-gate * Must do ndi_devi_online() through 36507c478bd9Sstevel@tonic-gate * hotplug thread for deferred 36517c478bd9Sstevel@tonic-gate * attach mechanism to work 36527c478bd9Sstevel@tonic-gate */ 36535e3986cbScth MDI_CLIENT_UNLOCK(ct); 36547c478bd9Sstevel@tonic-gate rv = ndi_devi_online(cdip, 0); 36555e3986cbScth MDI_CLIENT_LOCK(ct); 36567c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && 36577c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == 36587c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_DEGRADED)) { 36597c478bd9Sstevel@tonic-gate /* 36607c478bd9Sstevel@tonic-gate * ndi_devi_online failed. 36617c478bd9Sstevel@tonic-gate * Reset client flags to 36627c478bd9Sstevel@tonic-gate * offline. 36637c478bd9Sstevel@tonic-gate */ 36644c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, cdip, 36654c06356bSdh142964 "!ndi_devi_online failed " 36664c06356bSdh142964 "error %x", rv)); 36677c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 36687c478bd9Sstevel@tonic-gate } 36697c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 36707c478bd9Sstevel@tonic-gate /* Reset the path state */ 36717c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 36727c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = 36737c478bd9Sstevel@tonic-gate MDI_PI_OLD_STATE(pip); 36747c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 36757c478bd9Sstevel@tonic-gate } 36767c478bd9Sstevel@tonic-gate } 36777c478bd9Sstevel@tonic-gate break; 36787c478bd9Sstevel@tonic-gate 36797c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 36807c478bd9Sstevel@tonic-gate /* 36817c478bd9Sstevel@tonic-gate * This is the last path case for 36827c478bd9Sstevel@tonic-gate * non-user initiated events. 36837c478bd9Sstevel@tonic-gate */ 36844c06356bSdh142964 if (((flag & NDI_USER_REQ) == 0) && 36857c478bd9Sstevel@tonic-gate cdip && (i_ddi_node_state(cdip) >= 36867c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 36875e3986cbScth MDI_CLIENT_UNLOCK(ct); 36884c06356bSdh142964 rv = ndi_devi_offline(cdip, 36894c06356bSdh142964 NDI_DEVFS_CLEAN); 36905e3986cbScth MDI_CLIENT_LOCK(ct); 36917c478bd9Sstevel@tonic-gate 36927c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 36937c478bd9Sstevel@tonic-gate /* 36947c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 36957c478bd9Sstevel@tonic-gate * Reset client flags to 36967c478bd9Sstevel@tonic-gate * online as the path could not 36977c478bd9Sstevel@tonic-gate * be offlined. 36987c478bd9Sstevel@tonic-gate */ 36994c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, cdip, 37004c06356bSdh142964 "!ndi_devi_offline failed: " 37014c06356bSdh142964 "error %x", rv)); 37027c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 37037c478bd9Sstevel@tonic-gate } 37047c478bd9Sstevel@tonic-gate } 37057c478bd9Sstevel@tonic-gate break; 37067c478bd9Sstevel@tonic-gate } 37077c478bd9Sstevel@tonic-gate /* 37087c478bd9Sstevel@tonic-gate * Convert to MDI error code 37097c478bd9Sstevel@tonic-gate */ 37107c478bd9Sstevel@tonic-gate switch (rv) { 37117c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 37127c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 37137c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 37147c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 37157c478bd9Sstevel@tonic-gate break; 37167c478bd9Sstevel@tonic-gate case NDI_BUSY: 37177c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 37187c478bd9Sstevel@tonic-gate break; 37197c478bd9Sstevel@tonic-gate default: 37207c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 37217c478bd9Sstevel@tonic-gate break; 37227c478bd9Sstevel@tonic-gate } 37237c478bd9Sstevel@tonic-gate } 37247c478bd9Sstevel@tonic-gate } 37257c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 37267c478bd9Sstevel@tonic-gate 37277c478bd9Sstevel@tonic-gate state_change_exit: 37287c478bd9Sstevel@tonic-gate /* 37297c478bd9Sstevel@tonic-gate * Mark the pHCI as stable again. 37307c478bd9Sstevel@tonic-gate */ 37317c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 37327c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 37337c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 37347c478bd9Sstevel@tonic-gate return (rv); 37357c478bd9Sstevel@tonic-gate } 37367c478bd9Sstevel@tonic-gate 37377c478bd9Sstevel@tonic-gate /* 37387c478bd9Sstevel@tonic-gate * mdi_pi_online(): 37397c478bd9Sstevel@tonic-gate * Place the path_info node in the online state. The path is 37407c478bd9Sstevel@tonic-gate * now available to be selected by mdi_select_path() for 37417c478bd9Sstevel@tonic-gate * transporting I/O requests to client devices. 37427c478bd9Sstevel@tonic-gate * Return Values: 37437c478bd9Sstevel@tonic-gate * MDI_SUCCESS 37447c478bd9Sstevel@tonic-gate * MDI_FAILURE 37457c478bd9Sstevel@tonic-gate */ 37467c478bd9Sstevel@tonic-gate int 37477c478bd9Sstevel@tonic-gate mdi_pi_online(mdi_pathinfo_t *pip, int flags) 37487c478bd9Sstevel@tonic-gate { 37497c478bd9Sstevel@tonic-gate mdi_client_t *ct = MDI_PI(pip)->pi_client; 37507c478bd9Sstevel@tonic-gate int client_held = 0; 37517c478bd9Sstevel@tonic-gate int rv; 37527c478bd9Sstevel@tonic-gate 37537c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 37547c478bd9Sstevel@tonic-gate rv = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_ONLINE, flags); 37557c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) 37567c478bd9Sstevel@tonic-gate return (rv); 37577c478bd9Sstevel@tonic-gate 37587c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 37597c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 37604c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip, 37614c06356bSdh142964 "i_mdi_pm_hold_pip %p", (void *)pip)); 37627c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 37637c478bd9Sstevel@tonic-gate client_held = 1; 37647c478bd9Sstevel@tonic-gate } 37657c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 37667c478bd9Sstevel@tonic-gate 37677c478bd9Sstevel@tonic-gate if (client_held) { 37687c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 37697c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 37707c478bd9Sstevel@tonic-gate rv = i_mdi_power_all_phci(ct); 37717c478bd9Sstevel@tonic-gate } 37727c478bd9Sstevel@tonic-gate 37734c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip, 37744c06356bSdh142964 "i_mdi_pm_hold_client %p", (void *)ct)); 37757c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 37767c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 37777c478bd9Sstevel@tonic-gate } 37787c478bd9Sstevel@tonic-gate 37797c478bd9Sstevel@tonic-gate return (rv); 37807c478bd9Sstevel@tonic-gate } 37817c478bd9Sstevel@tonic-gate 37827c478bd9Sstevel@tonic-gate /* 37837c478bd9Sstevel@tonic-gate * mdi_pi_standby(): 37847c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in standby state 37857c478bd9Sstevel@tonic-gate * 37867c478bd9Sstevel@tonic-gate * Return Values: 37877c478bd9Sstevel@tonic-gate * MDI_SUCCESS 37887c478bd9Sstevel@tonic-gate * MDI_FAILURE 37897c478bd9Sstevel@tonic-gate */ 37907c478bd9Sstevel@tonic-gate int 37917c478bd9Sstevel@tonic-gate mdi_pi_standby(mdi_pathinfo_t *pip, int flags) 37927c478bd9Sstevel@tonic-gate { 37937c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_STANDBY, flags)); 37947c478bd9Sstevel@tonic-gate } 37957c478bd9Sstevel@tonic-gate 37967c478bd9Sstevel@tonic-gate /* 37977c478bd9Sstevel@tonic-gate * mdi_pi_fault(): 37987c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in fault'ed state 37997c478bd9Sstevel@tonic-gate * Return Values: 38007c478bd9Sstevel@tonic-gate * MDI_SUCCESS 38017c478bd9Sstevel@tonic-gate * MDI_FAILURE 38027c478bd9Sstevel@tonic-gate */ 38037c478bd9Sstevel@tonic-gate int 38047c478bd9Sstevel@tonic-gate mdi_pi_fault(mdi_pathinfo_t *pip, int flags) 38057c478bd9Sstevel@tonic-gate { 38067c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_FAULT, flags)); 38077c478bd9Sstevel@tonic-gate } 38087c478bd9Sstevel@tonic-gate 38097c478bd9Sstevel@tonic-gate /* 38107c478bd9Sstevel@tonic-gate * mdi_pi_offline(): 38117c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node. 38127c478bd9Sstevel@tonic-gate * Return Values: 38137c478bd9Sstevel@tonic-gate * MDI_SUCCESS 38147c478bd9Sstevel@tonic-gate * MDI_FAILURE 38157c478bd9Sstevel@tonic-gate */ 38167c478bd9Sstevel@tonic-gate int 38177c478bd9Sstevel@tonic-gate mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 38187c478bd9Sstevel@tonic-gate { 38197c478bd9Sstevel@tonic-gate int ret, client_held = 0; 38207c478bd9Sstevel@tonic-gate mdi_client_t *ct; 38214c06356bSdh142964 38224c06356bSdh142964 /* 38234c06356bSdh142964 * Original code overloaded NDI_DEVI_REMOVE to this interface, and 38244c06356bSdh142964 * used it to mean "user initiated operation" (i.e. devctl). Callers 38254c06356bSdh142964 * should now just use NDI_USER_REQ. 38264c06356bSdh142964 */ 38274c06356bSdh142964 if (flags & NDI_DEVI_REMOVE) { 38284c06356bSdh142964 flags &= ~NDI_DEVI_REMOVE; 38294c06356bSdh142964 flags |= NDI_USER_REQ; 38304c06356bSdh142964 } 38317c478bd9Sstevel@tonic-gate 38327c478bd9Sstevel@tonic-gate ret = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_OFFLINE, flags); 38337c478bd9Sstevel@tonic-gate 38347c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) { 38357c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 38367c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 38377c478bd9Sstevel@tonic-gate client_held = 1; 38387c478bd9Sstevel@tonic-gate } 38397c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38407c478bd9Sstevel@tonic-gate 38417c478bd9Sstevel@tonic-gate if (client_held) { 38427c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 38437c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 38444c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip, 38454c06356bSdh142964 "i_mdi_pm_rele_client\n")); 38467c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 38477c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 38487c478bd9Sstevel@tonic-gate } 38497c478bd9Sstevel@tonic-gate } 38507c478bd9Sstevel@tonic-gate 38517c478bd9Sstevel@tonic-gate return (ret); 38527c478bd9Sstevel@tonic-gate } 38537c478bd9Sstevel@tonic-gate 38547c478bd9Sstevel@tonic-gate /* 38557c478bd9Sstevel@tonic-gate * i_mdi_pi_offline(): 38567c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node and call the vHCI driver's callback 38577c478bd9Sstevel@tonic-gate */ 38587c478bd9Sstevel@tonic-gate static int 38597c478bd9Sstevel@tonic-gate i_mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 38607c478bd9Sstevel@tonic-gate { 38617c478bd9Sstevel@tonic-gate dev_info_t *vdip = NULL; 38627c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 38637c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 38647c478bd9Sstevel@tonic-gate int (*f)(); 38657c478bd9Sstevel@tonic-gate int rv; 38667c478bd9Sstevel@tonic-gate 38677c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 38687c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 38697c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 38707c478bd9Sstevel@tonic-gate 38717c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 38727c478bd9Sstevel@tonic-gate /* 38737c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 38747c478bd9Sstevel@tonic-gate */ 38754c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip, 38764c06356bSdh142964 "!%d cmds still pending on path %s %p", 38774c06356bSdh142964 MDI_PI(pip)->pi_ref_cnt, mdi_pi_spathname(pip), 38784c06356bSdh142964 (void *)pip)); 3879d3d50737SRafael Vanoni if (cv_reltimedwait(&MDI_PI(pip)->pi_ref_cv, 3880d3d50737SRafael Vanoni &MDI_PI(pip)->pi_mutex, drv_usectohz(60 * 1000000), 3881d3d50737SRafael Vanoni TR_CLOCK_TICK) == -1) { 38827c478bd9Sstevel@tonic-gate /* 38837c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 38847c478bd9Sstevel@tonic-gate * being signaled. 38857c478bd9Sstevel@tonic-gate */ 38864c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip, 38874c06356bSdh142964 "!Timeout reached on path %s %p without the cond", 38884c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 38894c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, ct->ct_dip, 38904c06356bSdh142964 "!%d cmds still pending on path %s %p", 38914c06356bSdh142964 MDI_PI(pip)->pi_ref_cnt, 38924c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 38937c478bd9Sstevel@tonic-gate } 38947c478bd9Sstevel@tonic-gate } 38957c478bd9Sstevel@tonic-gate vh = ct->ct_vhci; 38967c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 38977c478bd9Sstevel@tonic-gate 38987c478bd9Sstevel@tonic-gate /* 38997c478bd9Sstevel@tonic-gate * Notify vHCI that has registered this event 39007c478bd9Sstevel@tonic-gate */ 39017c478bd9Sstevel@tonic-gate ASSERT(vh->vh_ops); 39027c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 39037c478bd9Sstevel@tonic-gate 39047c478bd9Sstevel@tonic-gate if (f != NULL) { 39057c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39067c478bd9Sstevel@tonic-gate if ((rv = (*f)(vdip, pip, MDI_PATHINFO_STATE_OFFLINE, 0, 39077c478bd9Sstevel@tonic-gate flags)) != MDI_SUCCESS) { 39084c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, ct->ct_dip, 39094c06356bSdh142964 "!vo_path_offline failed: vdip %s%d %p: path %s %p", 39104c06356bSdh142964 ddi_driver_name(vdip), ddi_get_instance(vdip), 39114c06356bSdh142964 (void *)vdip, mdi_pi_spathname(pip), (void *)pip)); 39127c478bd9Sstevel@tonic-gate } 39137c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39147c478bd9Sstevel@tonic-gate } 39157c478bd9Sstevel@tonic-gate 39167c478bd9Sstevel@tonic-gate /* 39177c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state and clear the transient condition 39187c478bd9Sstevel@tonic-gate */ 39197c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINE(pip); 39207c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 39217c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39227c478bd9Sstevel@tonic-gate 39237c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 39247c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 39257c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 39267c478bd9Sstevel@tonic-gate dev_info_t *cdip = ct->ct_dip; 39277c478bd9Sstevel@tonic-gate 39287c478bd9Sstevel@tonic-gate /* 39297c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 39307c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 39317c478bd9Sstevel@tonic-gate * state accordingly 39327c478bd9Sstevel@tonic-gate */ 39337c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 39347c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 39357c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 39367c478bd9Sstevel@tonic-gate if (cdip && 39377c478bd9Sstevel@tonic-gate (i_ddi_node_state(cdip) >= 39387c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 39397c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 39404c06356bSdh142964 rv = ndi_devi_offline(cdip, 39414c06356bSdh142964 NDI_DEVFS_CLEAN); 39427c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 39437c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 39447c478bd9Sstevel@tonic-gate /* 39457c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 39467c478bd9Sstevel@tonic-gate * Reset client flags to 39477c478bd9Sstevel@tonic-gate * online. 39487c478bd9Sstevel@tonic-gate */ 39494c06356bSdh142964 MDI_DEBUG(4, (MDI_WARN, cdip, 39504c06356bSdh142964 "ndi_devi_offline failed: " 39514c06356bSdh142964 "error %x", rv)); 39527c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 39537c478bd9Sstevel@tonic-gate } 39547c478bd9Sstevel@tonic-gate } 39557c478bd9Sstevel@tonic-gate } 39567c478bd9Sstevel@tonic-gate /* 39577c478bd9Sstevel@tonic-gate * Convert to MDI error code 39587c478bd9Sstevel@tonic-gate */ 39597c478bd9Sstevel@tonic-gate switch (rv) { 39607c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 39617c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 39627c478bd9Sstevel@tonic-gate break; 39637c478bd9Sstevel@tonic-gate case NDI_BUSY: 39647c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 39657c478bd9Sstevel@tonic-gate break; 39667c478bd9Sstevel@tonic-gate default: 39677c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 39687c478bd9Sstevel@tonic-gate break; 39697c478bd9Sstevel@tonic-gate } 39707c478bd9Sstevel@tonic-gate } 39717c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 39727c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 39737c478bd9Sstevel@tonic-gate } 39747c478bd9Sstevel@tonic-gate 39757c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 39767c478bd9Sstevel@tonic-gate 39777c478bd9Sstevel@tonic-gate /* 39787c478bd9Sstevel@tonic-gate * Change in the mdi_pathinfo node state will impact the client state 39797c478bd9Sstevel@tonic-gate */ 39804c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, ct->ct_dip, 39814c06356bSdh142964 "ct = %p pip = %p", (void *)ct, (void *)pip)); 39827c478bd9Sstevel@tonic-gate return (rv); 39837c478bd9Sstevel@tonic-gate } 39847c478bd9Sstevel@tonic-gate 398555e592a2SRandall Ralphs /* 3986f76de749SStephen Hanson * i_mdi_pi_online(): 3987f76de749SStephen Hanson * Online a mdi_pathinfo node and call the vHCI driver's callback 3988f76de749SStephen Hanson */ 3989f76de749SStephen Hanson static int 3990f76de749SStephen Hanson i_mdi_pi_online(mdi_pathinfo_t *pip, int flags) 3991f76de749SStephen Hanson { 3992f76de749SStephen Hanson mdi_vhci_t *vh = NULL; 3993f76de749SStephen Hanson mdi_client_t *ct = NULL; 3994f76de749SStephen Hanson mdi_phci_t *ph; 3995f76de749SStephen Hanson int (*f)(); 3996f76de749SStephen Hanson int rv; 3997f76de749SStephen Hanson 3998f76de749SStephen Hanson MDI_PI_LOCK(pip); 3999f76de749SStephen Hanson ph = MDI_PI(pip)->pi_phci; 4000f76de749SStephen Hanson vh = ph->ph_vhci; 4001f76de749SStephen Hanson ct = MDI_PI(pip)->pi_client; 4002f76de749SStephen Hanson MDI_PI_SET_ONLINING(pip) 4003f76de749SStephen Hanson MDI_PI_UNLOCK(pip); 4004f76de749SStephen Hanson f = vh->vh_ops->vo_pi_state_change; 4005f76de749SStephen Hanson if (f != NULL) 4006f76de749SStephen Hanson rv = (*f)(vh->vh_dip, pip, MDI_PATHINFO_STATE_ONLINE, 0, 4007f76de749SStephen Hanson flags); 4008f76de749SStephen Hanson MDI_CLIENT_LOCK(ct); 4009f76de749SStephen Hanson MDI_PI_LOCK(pip); 4010f76de749SStephen Hanson cv_broadcast(&MDI_PI(pip)->pi_state_cv); 4011f76de749SStephen Hanson MDI_PI_UNLOCK(pip); 4012f76de749SStephen Hanson if (rv == MDI_SUCCESS) { 4013f76de749SStephen Hanson dev_info_t *cdip = ct->ct_dip; 4014f76de749SStephen Hanson 4015f76de749SStephen Hanson rv = MDI_SUCCESS; 4016f76de749SStephen Hanson i_mdi_client_update_state(ct); 4017f76de749SStephen Hanson if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL || 4018f76de749SStephen Hanson MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) { 4019f76de749SStephen Hanson if (cdip && !i_ddi_devi_attached(cdip)) { 4020f76de749SStephen Hanson MDI_CLIENT_UNLOCK(ct); 4021f76de749SStephen Hanson rv = ndi_devi_online(cdip, 0); 4022f76de749SStephen Hanson MDI_CLIENT_LOCK(ct); 4023f76de749SStephen Hanson if ((rv != NDI_SUCCESS) && 4024f76de749SStephen Hanson (MDI_CLIENT_STATE(ct) == 4025f76de749SStephen Hanson MDI_CLIENT_STATE_DEGRADED)) { 4026f76de749SStephen Hanson MDI_CLIENT_SET_OFFLINE(ct); 4027f76de749SStephen Hanson } 4028f76de749SStephen Hanson if (rv != NDI_SUCCESS) { 4029f76de749SStephen Hanson /* Reset the path state */ 4030f76de749SStephen Hanson MDI_PI_LOCK(pip); 4031f76de749SStephen Hanson MDI_PI(pip)->pi_state = 4032f76de749SStephen Hanson MDI_PI_OLD_STATE(pip); 4033f76de749SStephen Hanson MDI_PI_UNLOCK(pip); 4034f76de749SStephen Hanson } 4035f76de749SStephen Hanson } 4036f76de749SStephen Hanson } 4037f76de749SStephen Hanson switch (rv) { 4038f76de749SStephen Hanson case NDI_SUCCESS: 4039f76de749SStephen Hanson MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 4040f76de749SStephen Hanson i_mdi_report_path_state(ct, pip); 4041f76de749SStephen Hanson rv = MDI_SUCCESS; 4042f76de749SStephen Hanson break; 4043f76de749SStephen Hanson case NDI_BUSY: 4044f76de749SStephen Hanson rv = MDI_BUSY; 4045f76de749SStephen Hanson break; 4046f76de749SStephen Hanson default: 4047f76de749SStephen Hanson rv = MDI_FAILURE; 4048f76de749SStephen Hanson break; 4049f76de749SStephen Hanson } 4050f76de749SStephen Hanson } else { 4051f76de749SStephen Hanson /* Reset the path state */ 4052f76de749SStephen Hanson MDI_PI_LOCK(pip); 4053f76de749SStephen Hanson MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip); 4054f76de749SStephen Hanson MDI_PI_UNLOCK(pip); 4055f76de749SStephen Hanson } 4056f76de749SStephen Hanson MDI_CLIENT_UNLOCK(ct); 4057f76de749SStephen Hanson return (rv); 4058f76de749SStephen Hanson } 4059f76de749SStephen Hanson 4060f76de749SStephen Hanson /* 406155e592a2SRandall Ralphs * mdi_pi_get_node_name(): 406255e592a2SRandall Ralphs * Get the name associated with a mdi_pathinfo node. 406355e592a2SRandall Ralphs * Since pathinfo nodes are not directly named, we 406455e592a2SRandall Ralphs * return the node_name of the client. 406555e592a2SRandall Ralphs * 406655e592a2SRandall Ralphs * Return Values: 406755e592a2SRandall Ralphs * char * 406855e592a2SRandall Ralphs */ 406955e592a2SRandall Ralphs char * 407055e592a2SRandall Ralphs mdi_pi_get_node_name(mdi_pathinfo_t *pip) 407155e592a2SRandall Ralphs { 407255e592a2SRandall Ralphs mdi_client_t *ct; 407355e592a2SRandall Ralphs 407455e592a2SRandall Ralphs if (pip == NULL) 407555e592a2SRandall Ralphs return (NULL); 407655e592a2SRandall Ralphs ct = MDI_PI(pip)->pi_client; 407755e592a2SRandall Ralphs if ((ct == NULL) || (ct->ct_dip == NULL)) 407855e592a2SRandall Ralphs return (NULL); 407955e592a2SRandall Ralphs return (ddi_node_name(ct->ct_dip)); 408055e592a2SRandall Ralphs } 40817c478bd9Sstevel@tonic-gate 40827c478bd9Sstevel@tonic-gate /* 40837c478bd9Sstevel@tonic-gate * mdi_pi_get_addr(): 40847c478bd9Sstevel@tonic-gate * Get the unit address associated with a mdi_pathinfo node 40857c478bd9Sstevel@tonic-gate * 40867c478bd9Sstevel@tonic-gate * Return Values: 40877c478bd9Sstevel@tonic-gate * char * 40887c478bd9Sstevel@tonic-gate */ 40897c478bd9Sstevel@tonic-gate char * 40907c478bd9Sstevel@tonic-gate mdi_pi_get_addr(mdi_pathinfo_t *pip) 40917c478bd9Sstevel@tonic-gate { 40927c478bd9Sstevel@tonic-gate if (pip == NULL) 40937c478bd9Sstevel@tonic-gate return (NULL); 40947c478bd9Sstevel@tonic-gate 409572a50065Scth return (MDI_PI(pip)->pi_addr); 40967c478bd9Sstevel@tonic-gate } 40977c478bd9Sstevel@tonic-gate 40987c478bd9Sstevel@tonic-gate /* 4099602ca9eaScth * mdi_pi_get_path_instance(): 4100602ca9eaScth * Get the 'path_instance' of a mdi_pathinfo node 4101602ca9eaScth * 4102602ca9eaScth * Return Values: 4103602ca9eaScth * path_instance 4104602ca9eaScth */ 4105602ca9eaScth int 4106602ca9eaScth mdi_pi_get_path_instance(mdi_pathinfo_t *pip) 4107602ca9eaScth { 4108602ca9eaScth if (pip == NULL) 4109602ca9eaScth return (0); 4110602ca9eaScth 4111602ca9eaScth return (MDI_PI(pip)->pi_path_instance); 4112602ca9eaScth } 4113602ca9eaScth 4114602ca9eaScth /* 4115602ca9eaScth * mdi_pi_pathname(): 4116602ca9eaScth * Return pointer to path to pathinfo node. 4117602ca9eaScth */ 4118602ca9eaScth char * 4119602ca9eaScth mdi_pi_pathname(mdi_pathinfo_t *pip) 4120602ca9eaScth { 4121602ca9eaScth if (pip == NULL) 4122602ca9eaScth return (NULL); 4123602ca9eaScth return (mdi_pi_pathname_by_instance(mdi_pi_get_path_instance(pip))); 4124602ca9eaScth } 4125602ca9eaScth 41264c06356bSdh142964 /* 41274c06356bSdh142964 * mdi_pi_spathname(): 41284c06356bSdh142964 * Return pointer to shortpath to pathinfo node. Used for debug 41294c06356bSdh142964 * messages, so return "" instead of NULL when unknown. 41304c06356bSdh142964 */ 41314c06356bSdh142964 char * 41324c06356bSdh142964 mdi_pi_spathname(mdi_pathinfo_t *pip) 41334c06356bSdh142964 { 41344c06356bSdh142964 char *spath = ""; 41354c06356bSdh142964 41364c06356bSdh142964 if (pip) { 41374c06356bSdh142964 spath = mdi_pi_spathname_by_instance( 41384c06356bSdh142964 mdi_pi_get_path_instance(pip)); 41394c06356bSdh142964 if (spath == NULL) 41404c06356bSdh142964 spath = ""; 41414c06356bSdh142964 } 41424c06356bSdh142964 return (spath); 41434c06356bSdh142964 } 41444c06356bSdh142964 414538c67cbdSjiang wu - Sun Microsystems - Beijing China char * 414638c67cbdSjiang wu - Sun Microsystems - Beijing China mdi_pi_pathname_obp(mdi_pathinfo_t *pip, char *path) 414738c67cbdSjiang wu - Sun Microsystems - Beijing China { 414838c67cbdSjiang wu - Sun Microsystems - Beijing China char *obp_path = NULL; 414938c67cbdSjiang wu - Sun Microsystems - Beijing China if ((pip == NULL) || (path == NULL)) 415038c67cbdSjiang wu - Sun Microsystems - Beijing China return (NULL); 415138c67cbdSjiang wu - Sun Microsystems - Beijing China 415238c67cbdSjiang wu - Sun Microsystems - Beijing China if (mdi_prop_lookup_string(pip, "obp-path", &obp_path) == MDI_SUCCESS) { 415338c67cbdSjiang wu - Sun Microsystems - Beijing China (void) strcpy(path, obp_path); 415438c67cbdSjiang wu - Sun Microsystems - Beijing China (void) mdi_prop_free(obp_path); 415538c67cbdSjiang wu - Sun Microsystems - Beijing China } else { 415638c67cbdSjiang wu - Sun Microsystems - Beijing China path = NULL; 415738c67cbdSjiang wu - Sun Microsystems - Beijing China } 415838c67cbdSjiang wu - Sun Microsystems - Beijing China return (path); 415938c67cbdSjiang wu - Sun Microsystems - Beijing China } 416038c67cbdSjiang wu - Sun Microsystems - Beijing China 416138c67cbdSjiang wu - Sun Microsystems - Beijing China int 416238c67cbdSjiang wu - Sun Microsystems - Beijing China mdi_pi_pathname_obp_set(mdi_pathinfo_t *pip, char *component) 416338c67cbdSjiang wu - Sun Microsystems - Beijing China { 416438c67cbdSjiang wu - Sun Microsystems - Beijing China dev_info_t *pdip; 4165caa9369fSjiang wu - Sun Microsystems - Beijing China char *obp_path = NULL; 4166caa9369fSjiang wu - Sun Microsystems - Beijing China int rc = MDI_FAILURE; 416738c67cbdSjiang wu - Sun Microsystems - Beijing China 416838c67cbdSjiang wu - Sun Microsystems - Beijing China if (pip == NULL) 416938c67cbdSjiang wu - Sun Microsystems - Beijing China return (MDI_FAILURE); 417038c67cbdSjiang wu - Sun Microsystems - Beijing China 417138c67cbdSjiang wu - Sun Microsystems - Beijing China pdip = mdi_pi_get_phci(pip); 417238c67cbdSjiang wu - Sun Microsystems - Beijing China if (pdip == NULL) 417338c67cbdSjiang wu - Sun Microsystems - Beijing China return (MDI_FAILURE); 417438c67cbdSjiang wu - Sun Microsystems - Beijing China 4175caa9369fSjiang wu - Sun Microsystems - Beijing China obp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4176caa9369fSjiang wu - Sun Microsystems - Beijing China 417738c67cbdSjiang wu - Sun Microsystems - Beijing China if (ddi_pathname_obp(pdip, obp_path) == NULL) { 417838c67cbdSjiang wu - Sun Microsystems - Beijing China (void) ddi_pathname(pdip, obp_path); 417938c67cbdSjiang wu - Sun Microsystems - Beijing China } 418038c67cbdSjiang wu - Sun Microsystems - Beijing China 418138c67cbdSjiang wu - Sun Microsystems - Beijing China if (component) { 4182caa9369fSjiang wu - Sun Microsystems - Beijing China (void) strncat(obp_path, "/", MAXPATHLEN); 4183caa9369fSjiang wu - Sun Microsystems - Beijing China (void) strncat(obp_path, component, MAXPATHLEN); 418438c67cbdSjiang wu - Sun Microsystems - Beijing China } 4185caa9369fSjiang wu - Sun Microsystems - Beijing China rc = mdi_prop_update_string(pip, "obp-path", obp_path); 418638c67cbdSjiang wu - Sun Microsystems - Beijing China 4187caa9369fSjiang wu - Sun Microsystems - Beijing China if (obp_path) 4188caa9369fSjiang wu - Sun Microsystems - Beijing China kmem_free(obp_path, MAXPATHLEN); 4189caa9369fSjiang wu - Sun Microsystems - Beijing China return (rc); 419038c67cbdSjiang wu - Sun Microsystems - Beijing China } 419138c67cbdSjiang wu - Sun Microsystems - Beijing China 4192602ca9eaScth /* 41937c478bd9Sstevel@tonic-gate * mdi_pi_get_client(): 41947c478bd9Sstevel@tonic-gate * Get the client devinfo associated with a mdi_pathinfo node 41957c478bd9Sstevel@tonic-gate * 41967c478bd9Sstevel@tonic-gate * Return Values: 41977c478bd9Sstevel@tonic-gate * Handle to client device dev_info node 41987c478bd9Sstevel@tonic-gate */ 41997c478bd9Sstevel@tonic-gate dev_info_t * 42007c478bd9Sstevel@tonic-gate mdi_pi_get_client(mdi_pathinfo_t *pip) 42017c478bd9Sstevel@tonic-gate { 42027c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 42037c478bd9Sstevel@tonic-gate if (pip) { 42047c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_client->ct_dip; 42057c478bd9Sstevel@tonic-gate } 42067c478bd9Sstevel@tonic-gate return (dip); 42077c478bd9Sstevel@tonic-gate } 42087c478bd9Sstevel@tonic-gate 42097c478bd9Sstevel@tonic-gate /* 42107c478bd9Sstevel@tonic-gate * mdi_pi_get_phci(): 42117c478bd9Sstevel@tonic-gate * Get the pHCI devinfo associated with the mdi_pathinfo node 42127c478bd9Sstevel@tonic-gate * Return Values: 42137c478bd9Sstevel@tonic-gate * Handle to dev_info node 42147c478bd9Sstevel@tonic-gate */ 42157c478bd9Sstevel@tonic-gate dev_info_t * 42167c478bd9Sstevel@tonic-gate mdi_pi_get_phci(mdi_pathinfo_t *pip) 42177c478bd9Sstevel@tonic-gate { 42187c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 42194c06356bSdh142964 mdi_phci_t *ph; 42204c06356bSdh142964 42217c478bd9Sstevel@tonic-gate if (pip) { 42224c06356bSdh142964 ph = MDI_PI(pip)->pi_phci; 42234c06356bSdh142964 if (ph) 42244c06356bSdh142964 dip = ph->ph_dip; 42257c478bd9Sstevel@tonic-gate } 42267c478bd9Sstevel@tonic-gate return (dip); 42277c478bd9Sstevel@tonic-gate } 42287c478bd9Sstevel@tonic-gate 42297c478bd9Sstevel@tonic-gate /* 42307c478bd9Sstevel@tonic-gate * mdi_pi_get_client_private(): 42317c478bd9Sstevel@tonic-gate * Get the client private information associated with the 42327c478bd9Sstevel@tonic-gate * mdi_pathinfo node 42337c478bd9Sstevel@tonic-gate */ 42347c478bd9Sstevel@tonic-gate void * 42357c478bd9Sstevel@tonic-gate mdi_pi_get_client_private(mdi_pathinfo_t *pip) 42367c478bd9Sstevel@tonic-gate { 42377c478bd9Sstevel@tonic-gate void *cprivate = NULL; 42387c478bd9Sstevel@tonic-gate if (pip) { 42397c478bd9Sstevel@tonic-gate cprivate = MDI_PI(pip)->pi_cprivate; 42407c478bd9Sstevel@tonic-gate } 42417c478bd9Sstevel@tonic-gate return (cprivate); 42427c478bd9Sstevel@tonic-gate } 42437c478bd9Sstevel@tonic-gate 42447c478bd9Sstevel@tonic-gate /* 42457c478bd9Sstevel@tonic-gate * mdi_pi_set_client_private(): 42467c478bd9Sstevel@tonic-gate * Set the client private information in the mdi_pathinfo node 42477c478bd9Sstevel@tonic-gate */ 42487c478bd9Sstevel@tonic-gate void 42497c478bd9Sstevel@tonic-gate mdi_pi_set_client_private(mdi_pathinfo_t *pip, void *priv) 42507c478bd9Sstevel@tonic-gate { 42517c478bd9Sstevel@tonic-gate if (pip) { 42527c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = priv; 42537c478bd9Sstevel@tonic-gate } 42547c478bd9Sstevel@tonic-gate } 42557c478bd9Sstevel@tonic-gate 42567c478bd9Sstevel@tonic-gate /* 42577c478bd9Sstevel@tonic-gate * mdi_pi_get_phci_private(): 42587c478bd9Sstevel@tonic-gate * Get the pHCI private information associated with the 42597c478bd9Sstevel@tonic-gate * mdi_pathinfo node 42607c478bd9Sstevel@tonic-gate */ 42617c478bd9Sstevel@tonic-gate caddr_t 42627c478bd9Sstevel@tonic-gate mdi_pi_get_phci_private(mdi_pathinfo_t *pip) 42637c478bd9Sstevel@tonic-gate { 42647c478bd9Sstevel@tonic-gate caddr_t pprivate = NULL; 42654c06356bSdh142964 42667c478bd9Sstevel@tonic-gate if (pip) { 42677c478bd9Sstevel@tonic-gate pprivate = MDI_PI(pip)->pi_pprivate; 42687c478bd9Sstevel@tonic-gate } 42697c478bd9Sstevel@tonic-gate return (pprivate); 42707c478bd9Sstevel@tonic-gate } 42717c478bd9Sstevel@tonic-gate 42727c478bd9Sstevel@tonic-gate /* 42737c478bd9Sstevel@tonic-gate * mdi_pi_set_phci_private(): 42747c478bd9Sstevel@tonic-gate * Set the pHCI private information in the mdi_pathinfo node 42757c478bd9Sstevel@tonic-gate */ 42767c478bd9Sstevel@tonic-gate void 42777c478bd9Sstevel@tonic-gate mdi_pi_set_phci_private(mdi_pathinfo_t *pip, caddr_t priv) 42787c478bd9Sstevel@tonic-gate { 42797c478bd9Sstevel@tonic-gate if (pip) { 42807c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = priv; 42817c478bd9Sstevel@tonic-gate } 42827c478bd9Sstevel@tonic-gate } 42837c478bd9Sstevel@tonic-gate 42847c478bd9Sstevel@tonic-gate /* 42857c478bd9Sstevel@tonic-gate * mdi_pi_get_state(): 42867c478bd9Sstevel@tonic-gate * Get the mdi_pathinfo node state. Transient states are internal 42877c478bd9Sstevel@tonic-gate * and not provided to the users 42887c478bd9Sstevel@tonic-gate */ 42897c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t 42907c478bd9Sstevel@tonic-gate mdi_pi_get_state(mdi_pathinfo_t *pip) 42917c478bd9Sstevel@tonic-gate { 42927c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t state = MDI_PATHINFO_STATE_INIT; 42937c478bd9Sstevel@tonic-gate 42947c478bd9Sstevel@tonic-gate if (pip) { 42957c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 42967c478bd9Sstevel@tonic-gate /* 42977c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 42987c478bd9Sstevel@tonic-gate * last good state. 42997c478bd9Sstevel@tonic-gate */ 43007c478bd9Sstevel@tonic-gate state = MDI_PI_OLD_STATE(pip); 43017c478bd9Sstevel@tonic-gate } else { 43027c478bd9Sstevel@tonic-gate state = MDI_PI_STATE(pip); 43037c478bd9Sstevel@tonic-gate } 43047c478bd9Sstevel@tonic-gate } 43057c478bd9Sstevel@tonic-gate return (state); 43067c478bd9Sstevel@tonic-gate } 43077c478bd9Sstevel@tonic-gate 43087c478bd9Sstevel@tonic-gate /* 43094c06356bSdh142964 * mdi_pi_get_flags(): 43104c06356bSdh142964 * Get the mdi_pathinfo node flags. 43114c06356bSdh142964 */ 43124c06356bSdh142964 uint_t 43134c06356bSdh142964 mdi_pi_get_flags(mdi_pathinfo_t *pip) 43144c06356bSdh142964 { 43154c06356bSdh142964 return (pip ? MDI_PI(pip)->pi_flags : 0); 43164c06356bSdh142964 } 43174c06356bSdh142964 43184c06356bSdh142964 /* 43197c478bd9Sstevel@tonic-gate * Note that the following function needs to be the new interface for 43207c478bd9Sstevel@tonic-gate * mdi_pi_get_state when mpxio gets integrated to ON. 43217c478bd9Sstevel@tonic-gate */ 43227c478bd9Sstevel@tonic-gate int 43237c478bd9Sstevel@tonic-gate mdi_pi_get_state2(mdi_pathinfo_t *pip, mdi_pathinfo_state_t *state, 43247c478bd9Sstevel@tonic-gate uint32_t *ext_state) 43257c478bd9Sstevel@tonic-gate { 43267c478bd9Sstevel@tonic-gate *state = MDI_PATHINFO_STATE_INIT; 43277c478bd9Sstevel@tonic-gate 43287c478bd9Sstevel@tonic-gate if (pip) { 43297c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 43307c478bd9Sstevel@tonic-gate /* 43317c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 43327c478bd9Sstevel@tonic-gate * last good state. 43337c478bd9Sstevel@tonic-gate */ 43347c478bd9Sstevel@tonic-gate *state = MDI_PI_OLD_STATE(pip); 43357c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_OLD_EXT_STATE(pip); 43367c478bd9Sstevel@tonic-gate } else { 43377c478bd9Sstevel@tonic-gate *state = MDI_PI_STATE(pip); 43387c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_EXT_STATE(pip); 43397c478bd9Sstevel@tonic-gate } 43407c478bd9Sstevel@tonic-gate } 43417c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 43427c478bd9Sstevel@tonic-gate } 43437c478bd9Sstevel@tonic-gate 43447c478bd9Sstevel@tonic-gate /* 43457c478bd9Sstevel@tonic-gate * mdi_pi_get_preferred: 43467c478bd9Sstevel@tonic-gate * Get the preferred path flag 43477c478bd9Sstevel@tonic-gate */ 43487c478bd9Sstevel@tonic-gate int 43497c478bd9Sstevel@tonic-gate mdi_pi_get_preferred(mdi_pathinfo_t *pip) 43507c478bd9Sstevel@tonic-gate { 43517c478bd9Sstevel@tonic-gate if (pip) { 43527c478bd9Sstevel@tonic-gate return (MDI_PI(pip)->pi_preferred); 43537c478bd9Sstevel@tonic-gate } 43547c478bd9Sstevel@tonic-gate return (0); 43557c478bd9Sstevel@tonic-gate } 43567c478bd9Sstevel@tonic-gate 43577c478bd9Sstevel@tonic-gate /* 43587c478bd9Sstevel@tonic-gate * mdi_pi_set_preferred: 43597c478bd9Sstevel@tonic-gate * Set the preferred path flag 43607c478bd9Sstevel@tonic-gate */ 43617c478bd9Sstevel@tonic-gate void 43627c478bd9Sstevel@tonic-gate mdi_pi_set_preferred(mdi_pathinfo_t *pip, int preferred) 43637c478bd9Sstevel@tonic-gate { 43647c478bd9Sstevel@tonic-gate if (pip) { 43657c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = preferred; 43667c478bd9Sstevel@tonic-gate } 43677c478bd9Sstevel@tonic-gate } 43687c478bd9Sstevel@tonic-gate 43697c478bd9Sstevel@tonic-gate /* 43707c478bd9Sstevel@tonic-gate * mdi_pi_set_state(): 43717c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state 43727c478bd9Sstevel@tonic-gate */ 43737c478bd9Sstevel@tonic-gate void 43747c478bd9Sstevel@tonic-gate mdi_pi_set_state(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state) 43757c478bd9Sstevel@tonic-gate { 43767c478bd9Sstevel@tonic-gate uint32_t ext_state; 43777c478bd9Sstevel@tonic-gate 43787c478bd9Sstevel@tonic-gate if (pip) { 43797c478bd9Sstevel@tonic-gate ext_state = MDI_PI(pip)->pi_state & MDI_PATHINFO_EXT_STATE_MASK; 43807c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = state; 43817c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state |= ext_state; 43824c06356bSdh142964 43834c06356bSdh142964 /* Path has changed state, invalidate DINFOCACHE snap shot. */ 43844c06356bSdh142964 i_ddi_di_cache_invalidate(); 43857c478bd9Sstevel@tonic-gate } 43867c478bd9Sstevel@tonic-gate } 43877c478bd9Sstevel@tonic-gate 43887c478bd9Sstevel@tonic-gate /* 43897c478bd9Sstevel@tonic-gate * Property functions: 43907c478bd9Sstevel@tonic-gate */ 43917c478bd9Sstevel@tonic-gate int 43927c478bd9Sstevel@tonic-gate i_map_nvlist_error_to_mdi(int val) 43937c478bd9Sstevel@tonic-gate { 43947c478bd9Sstevel@tonic-gate int rv; 43957c478bd9Sstevel@tonic-gate 43967c478bd9Sstevel@tonic-gate switch (val) { 43977c478bd9Sstevel@tonic-gate case 0: 43987c478bd9Sstevel@tonic-gate rv = DDI_PROP_SUCCESS; 43997c478bd9Sstevel@tonic-gate break; 44007c478bd9Sstevel@tonic-gate case EINVAL: 44017c478bd9Sstevel@tonic-gate case ENOTSUP: 44027c478bd9Sstevel@tonic-gate rv = DDI_PROP_INVAL_ARG; 44037c478bd9Sstevel@tonic-gate break; 44047c478bd9Sstevel@tonic-gate case ENOMEM: 44057c478bd9Sstevel@tonic-gate rv = DDI_PROP_NO_MEMORY; 44067c478bd9Sstevel@tonic-gate break; 44077c478bd9Sstevel@tonic-gate default: 44087c478bd9Sstevel@tonic-gate rv = DDI_PROP_NOT_FOUND; 44097c478bd9Sstevel@tonic-gate break; 44107c478bd9Sstevel@tonic-gate } 44117c478bd9Sstevel@tonic-gate return (rv); 44127c478bd9Sstevel@tonic-gate } 44137c478bd9Sstevel@tonic-gate 44147c478bd9Sstevel@tonic-gate /* 44157c478bd9Sstevel@tonic-gate * mdi_pi_get_next_prop(): 44167c478bd9Sstevel@tonic-gate * Property walk function. The caller should hold mdi_pi_lock() 44177c478bd9Sstevel@tonic-gate * and release by calling mdi_pi_unlock() at the end of walk to 44187c478bd9Sstevel@tonic-gate * get a consistent value. 44197c478bd9Sstevel@tonic-gate */ 44207c478bd9Sstevel@tonic-gate nvpair_t * 44217c478bd9Sstevel@tonic-gate mdi_pi_get_next_prop(mdi_pathinfo_t *pip, nvpair_t *prev) 44227c478bd9Sstevel@tonic-gate { 44237c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 44247c478bd9Sstevel@tonic-gate return (NULL); 44257c478bd9Sstevel@tonic-gate } 44265e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 44277c478bd9Sstevel@tonic-gate return (nvlist_next_nvpair(MDI_PI(pip)->pi_prop, prev)); 44287c478bd9Sstevel@tonic-gate } 44297c478bd9Sstevel@tonic-gate 44307c478bd9Sstevel@tonic-gate /* 44317c478bd9Sstevel@tonic-gate * mdi_prop_remove(): 44327c478bd9Sstevel@tonic-gate * Remove the named property from the named list. 44337c478bd9Sstevel@tonic-gate */ 44347c478bd9Sstevel@tonic-gate int 44357c478bd9Sstevel@tonic-gate mdi_prop_remove(mdi_pathinfo_t *pip, char *name) 44367c478bd9Sstevel@tonic-gate { 44377c478bd9Sstevel@tonic-gate if (pip == NULL) { 44387c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 44397c478bd9Sstevel@tonic-gate } 44405e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 44417c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 44427c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 44437c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44447c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 44457c478bd9Sstevel@tonic-gate } 44467c478bd9Sstevel@tonic-gate if (name) { 44477c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, name); 44487c478bd9Sstevel@tonic-gate } else { 44497c478bd9Sstevel@tonic-gate char nvp_name[MAXNAMELEN]; 44507c478bd9Sstevel@tonic-gate nvpair_t *nvp; 44517c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, NULL); 44527c478bd9Sstevel@tonic-gate while (nvp) { 44537c478bd9Sstevel@tonic-gate nvpair_t *next; 44547c478bd9Sstevel@tonic-gate next = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, nvp); 44554c06356bSdh142964 (void) snprintf(nvp_name, sizeof(nvp_name), "%s", 44567c478bd9Sstevel@tonic-gate nvpair_name(nvp)); 44577c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, 44587c478bd9Sstevel@tonic-gate nvp_name); 44597c478bd9Sstevel@tonic-gate nvp = next; 44607c478bd9Sstevel@tonic-gate } 44617c478bd9Sstevel@tonic-gate } 44627c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44637c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 44647c478bd9Sstevel@tonic-gate } 44657c478bd9Sstevel@tonic-gate 44667c478bd9Sstevel@tonic-gate /* 44677c478bd9Sstevel@tonic-gate * mdi_prop_size(): 44687c478bd9Sstevel@tonic-gate * Get buffer size needed to pack the property data. 44697c478bd9Sstevel@tonic-gate * Caller should hold the mdi_pathinfo_t lock to get a consistent 44707c478bd9Sstevel@tonic-gate * buffer size. 44717c478bd9Sstevel@tonic-gate */ 44727c478bd9Sstevel@tonic-gate int 44737c478bd9Sstevel@tonic-gate mdi_prop_size(mdi_pathinfo_t *pip, size_t *buflenp) 44747c478bd9Sstevel@tonic-gate { 44757c478bd9Sstevel@tonic-gate int rv; 44767c478bd9Sstevel@tonic-gate size_t bufsize; 44777c478bd9Sstevel@tonic-gate 44787c478bd9Sstevel@tonic-gate *buflenp = 0; 44797c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 44807c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 44817c478bd9Sstevel@tonic-gate } 44825e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 44837c478bd9Sstevel@tonic-gate rv = nvlist_size(MDI_PI(pip)->pi_prop, 44847c478bd9Sstevel@tonic-gate &bufsize, NV_ENCODE_NATIVE); 44857c478bd9Sstevel@tonic-gate *buflenp = bufsize; 44867c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 44877c478bd9Sstevel@tonic-gate } 44887c478bd9Sstevel@tonic-gate 44897c478bd9Sstevel@tonic-gate /* 44907c478bd9Sstevel@tonic-gate * mdi_prop_pack(): 44917c478bd9Sstevel@tonic-gate * pack the property list. The caller should hold the 44927c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node to get a consistent data 44937c478bd9Sstevel@tonic-gate */ 44947c478bd9Sstevel@tonic-gate int 44957c478bd9Sstevel@tonic-gate mdi_prop_pack(mdi_pathinfo_t *pip, char **bufp, uint_t buflen) 44967c478bd9Sstevel@tonic-gate { 44977c478bd9Sstevel@tonic-gate int rv; 44987c478bd9Sstevel@tonic-gate size_t bufsize; 44997c478bd9Sstevel@tonic-gate 45007c478bd9Sstevel@tonic-gate if ((pip == NULL) || MDI_PI(pip)->pi_prop == NULL) { 45017c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 45027c478bd9Sstevel@tonic-gate } 45037c478bd9Sstevel@tonic-gate 45045e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 45057c478bd9Sstevel@tonic-gate 45067c478bd9Sstevel@tonic-gate bufsize = buflen; 45077c478bd9Sstevel@tonic-gate rv = nvlist_pack(MDI_PI(pip)->pi_prop, bufp, (size_t *)&bufsize, 45087c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE, KM_SLEEP); 45097c478bd9Sstevel@tonic-gate 45107c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 45117c478bd9Sstevel@tonic-gate } 45127c478bd9Sstevel@tonic-gate 45137c478bd9Sstevel@tonic-gate /* 45147c478bd9Sstevel@tonic-gate * mdi_prop_update_byte(): 45157c478bd9Sstevel@tonic-gate * Create/Update a byte property 45167c478bd9Sstevel@tonic-gate */ 45177c478bd9Sstevel@tonic-gate int 45187c478bd9Sstevel@tonic-gate mdi_prop_update_byte(mdi_pathinfo_t *pip, char *name, uchar_t data) 45197c478bd9Sstevel@tonic-gate { 45207c478bd9Sstevel@tonic-gate int rv; 45217c478bd9Sstevel@tonic-gate 45227c478bd9Sstevel@tonic-gate if (pip == NULL) { 45237c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 45247c478bd9Sstevel@tonic-gate } 45255e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 45267c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45277c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 45287c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45297c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 45307c478bd9Sstevel@tonic-gate } 45317c478bd9Sstevel@tonic-gate rv = nvlist_add_byte(MDI_PI(pip)->pi_prop, name, data); 45327c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45337c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 45347c478bd9Sstevel@tonic-gate } 45357c478bd9Sstevel@tonic-gate 45367c478bd9Sstevel@tonic-gate /* 45377c478bd9Sstevel@tonic-gate * mdi_prop_update_byte_array(): 45387c478bd9Sstevel@tonic-gate * Create/Update a byte array property 45397c478bd9Sstevel@tonic-gate */ 45407c478bd9Sstevel@tonic-gate int 45417c478bd9Sstevel@tonic-gate mdi_prop_update_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t *data, 45427c478bd9Sstevel@tonic-gate uint_t nelements) 45437c478bd9Sstevel@tonic-gate { 45447c478bd9Sstevel@tonic-gate int rv; 45457c478bd9Sstevel@tonic-gate 45467c478bd9Sstevel@tonic-gate if (pip == NULL) { 45477c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 45487c478bd9Sstevel@tonic-gate } 45495e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 45507c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45517c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 45527c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45537c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 45547c478bd9Sstevel@tonic-gate } 45557c478bd9Sstevel@tonic-gate rv = nvlist_add_byte_array(MDI_PI(pip)->pi_prop, name, data, nelements); 45567c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45577c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 45587c478bd9Sstevel@tonic-gate } 45597c478bd9Sstevel@tonic-gate 45607c478bd9Sstevel@tonic-gate /* 45617c478bd9Sstevel@tonic-gate * mdi_prop_update_int(): 45627c478bd9Sstevel@tonic-gate * Create/Update a 32 bit integer property 45637c478bd9Sstevel@tonic-gate */ 45647c478bd9Sstevel@tonic-gate int 45657c478bd9Sstevel@tonic-gate mdi_prop_update_int(mdi_pathinfo_t *pip, char *name, int data) 45667c478bd9Sstevel@tonic-gate { 45677c478bd9Sstevel@tonic-gate int rv; 45687c478bd9Sstevel@tonic-gate 45697c478bd9Sstevel@tonic-gate if (pip == NULL) { 45707c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 45717c478bd9Sstevel@tonic-gate } 45725e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 45737c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45747c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 45757c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45767c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 45777c478bd9Sstevel@tonic-gate } 45787c478bd9Sstevel@tonic-gate rv = nvlist_add_int32(MDI_PI(pip)->pi_prop, name, (int32_t)data); 45797c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45807c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 45817c478bd9Sstevel@tonic-gate } 45827c478bd9Sstevel@tonic-gate 45837c478bd9Sstevel@tonic-gate /* 45847c478bd9Sstevel@tonic-gate * mdi_prop_update_int64(): 45857c478bd9Sstevel@tonic-gate * Create/Update a 64 bit integer property 45867c478bd9Sstevel@tonic-gate */ 45877c478bd9Sstevel@tonic-gate int 45887c478bd9Sstevel@tonic-gate mdi_prop_update_int64(mdi_pathinfo_t *pip, char *name, int64_t data) 45897c478bd9Sstevel@tonic-gate { 45907c478bd9Sstevel@tonic-gate int rv; 45917c478bd9Sstevel@tonic-gate 45927c478bd9Sstevel@tonic-gate if (pip == NULL) { 45937c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 45947c478bd9Sstevel@tonic-gate } 45955e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 45967c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45977c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 45987c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45997c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 46007c478bd9Sstevel@tonic-gate } 46017c478bd9Sstevel@tonic-gate rv = nvlist_add_int64(MDI_PI(pip)->pi_prop, name, data); 46027c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46037c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 46047c478bd9Sstevel@tonic-gate } 46057c478bd9Sstevel@tonic-gate 46067c478bd9Sstevel@tonic-gate /* 46077c478bd9Sstevel@tonic-gate * mdi_prop_update_int_array(): 46087c478bd9Sstevel@tonic-gate * Create/Update a int array property 46097c478bd9Sstevel@tonic-gate */ 46107c478bd9Sstevel@tonic-gate int 46117c478bd9Sstevel@tonic-gate mdi_prop_update_int_array(mdi_pathinfo_t *pip, char *name, int *data, 46127c478bd9Sstevel@tonic-gate uint_t nelements) 46137c478bd9Sstevel@tonic-gate { 46147c478bd9Sstevel@tonic-gate int rv; 46157c478bd9Sstevel@tonic-gate 46167c478bd9Sstevel@tonic-gate if (pip == NULL) { 46177c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 46187c478bd9Sstevel@tonic-gate } 46195e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 46207c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 46217c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 46227c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46237c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 46247c478bd9Sstevel@tonic-gate } 46257c478bd9Sstevel@tonic-gate rv = nvlist_add_int32_array(MDI_PI(pip)->pi_prop, name, (int32_t *)data, 46267c478bd9Sstevel@tonic-gate nelements); 46277c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46287c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 46297c478bd9Sstevel@tonic-gate } 46307c478bd9Sstevel@tonic-gate 46317c478bd9Sstevel@tonic-gate /* 46327c478bd9Sstevel@tonic-gate * mdi_prop_update_string(): 46337c478bd9Sstevel@tonic-gate * Create/Update a string property 46347c478bd9Sstevel@tonic-gate */ 46357c478bd9Sstevel@tonic-gate int 46367c478bd9Sstevel@tonic-gate mdi_prop_update_string(mdi_pathinfo_t *pip, char *name, char *data) 46377c478bd9Sstevel@tonic-gate { 46387c478bd9Sstevel@tonic-gate int rv; 46397c478bd9Sstevel@tonic-gate 46407c478bd9Sstevel@tonic-gate if (pip == NULL) { 46417c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 46427c478bd9Sstevel@tonic-gate } 46435e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 46447c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 46457c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 46467c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46477c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 46487c478bd9Sstevel@tonic-gate } 46497c478bd9Sstevel@tonic-gate rv = nvlist_add_string(MDI_PI(pip)->pi_prop, name, data); 46507c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46517c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 46527c478bd9Sstevel@tonic-gate } 46537c478bd9Sstevel@tonic-gate 46547c478bd9Sstevel@tonic-gate /* 46557c478bd9Sstevel@tonic-gate * mdi_prop_update_string_array(): 46567c478bd9Sstevel@tonic-gate * Create/Update a string array property 46577c478bd9Sstevel@tonic-gate */ 46587c478bd9Sstevel@tonic-gate int 46597c478bd9Sstevel@tonic-gate mdi_prop_update_string_array(mdi_pathinfo_t *pip, char *name, char **data, 46607c478bd9Sstevel@tonic-gate uint_t nelements) 46617c478bd9Sstevel@tonic-gate { 46627c478bd9Sstevel@tonic-gate int rv; 46637c478bd9Sstevel@tonic-gate 46647c478bd9Sstevel@tonic-gate if (pip == NULL) { 46657c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 46667c478bd9Sstevel@tonic-gate } 46675e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 46687c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 46697c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 46707c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46717c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 46727c478bd9Sstevel@tonic-gate } 46737c478bd9Sstevel@tonic-gate rv = nvlist_add_string_array(MDI_PI(pip)->pi_prop, name, data, 46747c478bd9Sstevel@tonic-gate nelements); 46757c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46767c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 46777c478bd9Sstevel@tonic-gate } 46787c478bd9Sstevel@tonic-gate 46797c478bd9Sstevel@tonic-gate /* 46807c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte(): 46817c478bd9Sstevel@tonic-gate * Look for byte property identified by name. The data returned 46827c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 46837c478bd9Sstevel@tonic-gate * is alive. 46847c478bd9Sstevel@tonic-gate */ 46857c478bd9Sstevel@tonic-gate int 46867c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte(mdi_pathinfo_t *pip, char *name, uchar_t *data) 46877c478bd9Sstevel@tonic-gate { 46887c478bd9Sstevel@tonic-gate int rv; 46897c478bd9Sstevel@tonic-gate 46907c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 46917c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 46927c478bd9Sstevel@tonic-gate } 46937c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte(MDI_PI(pip)->pi_prop, name, data); 46947c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 46957c478bd9Sstevel@tonic-gate } 46967c478bd9Sstevel@tonic-gate 46977c478bd9Sstevel@tonic-gate 46987c478bd9Sstevel@tonic-gate /* 46997c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte_array(): 47007c478bd9Sstevel@tonic-gate * Look for byte array property identified by name. The data 47017c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 47027c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 47037c478bd9Sstevel@tonic-gate */ 47047c478bd9Sstevel@tonic-gate int 47057c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t **data, 47067c478bd9Sstevel@tonic-gate uint_t *nelements) 47077c478bd9Sstevel@tonic-gate { 47087c478bd9Sstevel@tonic-gate int rv; 47097c478bd9Sstevel@tonic-gate 47107c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 47117c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 47127c478bd9Sstevel@tonic-gate } 47137c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte_array(MDI_PI(pip)->pi_prop, name, data, 47147c478bd9Sstevel@tonic-gate nelements); 47157c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 47167c478bd9Sstevel@tonic-gate } 47177c478bd9Sstevel@tonic-gate 47187c478bd9Sstevel@tonic-gate /* 47197c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int(): 47207c478bd9Sstevel@tonic-gate * Look for int property identified by name. The data returned 47217c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t 47227c478bd9Sstevel@tonic-gate * node is alive. 47237c478bd9Sstevel@tonic-gate */ 47247c478bd9Sstevel@tonic-gate int 47257c478bd9Sstevel@tonic-gate mdi_prop_lookup_int(mdi_pathinfo_t *pip, char *name, int *data) 47267c478bd9Sstevel@tonic-gate { 47277c478bd9Sstevel@tonic-gate int rv; 47287c478bd9Sstevel@tonic-gate 47297c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 47307c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 47317c478bd9Sstevel@tonic-gate } 47327c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32(MDI_PI(pip)->pi_prop, name, (int32_t *)data); 47337c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 47347c478bd9Sstevel@tonic-gate } 47357c478bd9Sstevel@tonic-gate 47367c478bd9Sstevel@tonic-gate /* 47377c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int64(): 47387c478bd9Sstevel@tonic-gate * Look for int64 property identified by name. The data returned 47397c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 47407c478bd9Sstevel@tonic-gate * is alive. 47417c478bd9Sstevel@tonic-gate */ 47427c478bd9Sstevel@tonic-gate int 47437c478bd9Sstevel@tonic-gate mdi_prop_lookup_int64(mdi_pathinfo_t *pip, char *name, int64_t *data) 47447c478bd9Sstevel@tonic-gate { 47457c478bd9Sstevel@tonic-gate int rv; 47467c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 47477c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 47487c478bd9Sstevel@tonic-gate } 47497c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int64(MDI_PI(pip)->pi_prop, name, data); 47507c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 47517c478bd9Sstevel@tonic-gate } 47527c478bd9Sstevel@tonic-gate 47537c478bd9Sstevel@tonic-gate /* 47547c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int_array(): 47557c478bd9Sstevel@tonic-gate * Look for int array property identified by name. The data 47567c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 47577c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 47587c478bd9Sstevel@tonic-gate */ 47597c478bd9Sstevel@tonic-gate int 47607c478bd9Sstevel@tonic-gate mdi_prop_lookup_int_array(mdi_pathinfo_t *pip, char *name, int **data, 47617c478bd9Sstevel@tonic-gate uint_t *nelements) 47627c478bd9Sstevel@tonic-gate { 47637c478bd9Sstevel@tonic-gate int rv; 47647c478bd9Sstevel@tonic-gate 47657c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 47667c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 47677c478bd9Sstevel@tonic-gate } 47687c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32_array(MDI_PI(pip)->pi_prop, name, 47697c478bd9Sstevel@tonic-gate (int32_t **)data, nelements); 47707c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 47717c478bd9Sstevel@tonic-gate } 47727c478bd9Sstevel@tonic-gate 47737c478bd9Sstevel@tonic-gate /* 47747c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string(): 47757c478bd9Sstevel@tonic-gate * Look for string property identified by name. The data 47767c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 47777c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 47787c478bd9Sstevel@tonic-gate */ 47797c478bd9Sstevel@tonic-gate int 47807c478bd9Sstevel@tonic-gate mdi_prop_lookup_string(mdi_pathinfo_t *pip, char *name, char **data) 47817c478bd9Sstevel@tonic-gate { 47827c478bd9Sstevel@tonic-gate int rv; 47837c478bd9Sstevel@tonic-gate 47847c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 47857c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 47867c478bd9Sstevel@tonic-gate } 47877c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string(MDI_PI(pip)->pi_prop, name, data); 47887c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 47897c478bd9Sstevel@tonic-gate } 47907c478bd9Sstevel@tonic-gate 47917c478bd9Sstevel@tonic-gate /* 47927c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string_array(): 47937c478bd9Sstevel@tonic-gate * Look for string array property identified by name. The data 47947c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 47957c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 47967c478bd9Sstevel@tonic-gate */ 47977c478bd9Sstevel@tonic-gate int 47987c478bd9Sstevel@tonic-gate mdi_prop_lookup_string_array(mdi_pathinfo_t *pip, char *name, char ***data, 47997c478bd9Sstevel@tonic-gate uint_t *nelements) 48007c478bd9Sstevel@tonic-gate { 48017c478bd9Sstevel@tonic-gate int rv; 48027c478bd9Sstevel@tonic-gate 48037c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 48047c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 48057c478bd9Sstevel@tonic-gate } 48067c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string_array(MDI_PI(pip)->pi_prop, name, data, 48077c478bd9Sstevel@tonic-gate nelements); 48087c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 48097c478bd9Sstevel@tonic-gate } 48107c478bd9Sstevel@tonic-gate 48117c478bd9Sstevel@tonic-gate /* 48127c478bd9Sstevel@tonic-gate * mdi_prop_free(): 48137c478bd9Sstevel@tonic-gate * Symmetrical function to ddi_prop_free(). nvlist_lookup_xx() 48147c478bd9Sstevel@tonic-gate * functions return the pointer to actual property data and not a 48157c478bd9Sstevel@tonic-gate * copy of it. So the data returned is valid as long as 48167c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is valid. 48177c478bd9Sstevel@tonic-gate */ 48187c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 48197c478bd9Sstevel@tonic-gate int 48207c478bd9Sstevel@tonic-gate mdi_prop_free(void *data) 48217c478bd9Sstevel@tonic-gate { 48227c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 48237c478bd9Sstevel@tonic-gate } 48247c478bd9Sstevel@tonic-gate 48257c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 48267c478bd9Sstevel@tonic-gate static void 48277c478bd9Sstevel@tonic-gate i_mdi_report_path_state(mdi_client_t *ct, mdi_pathinfo_t *pip) 48287c478bd9Sstevel@tonic-gate { 48294c06356bSdh142964 char *ct_path; 48307c478bd9Sstevel@tonic-gate char *ct_status; 48317c478bd9Sstevel@tonic-gate char *status; 48324c06356bSdh142964 dev_info_t *cdip = ct->ct_dip; 48337c478bd9Sstevel@tonic-gate char lb_buf[64]; 48344c06356bSdh142964 int report_lb_c = 0, report_lb_p = 0; 48357c478bd9Sstevel@tonic-gate 48365e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 48374c06356bSdh142964 if ((cdip == NULL) || (ddi_get_instance(cdip) == -1) || 48387c478bd9Sstevel@tonic-gate (MDI_CLIENT_IS_REPORT_DEV_NEEDED(ct) == 0)) { 48397c478bd9Sstevel@tonic-gate return; 48407c478bd9Sstevel@tonic-gate } 48417c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL) { 48427c478bd9Sstevel@tonic-gate ct_status = "optimal"; 48434c06356bSdh142964 report_lb_c = 1; 48447c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) { 48457c478bd9Sstevel@tonic-gate ct_status = "degraded"; 48467c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 48477c478bd9Sstevel@tonic-gate ct_status = "failed"; 48487c478bd9Sstevel@tonic-gate } else { 48497c478bd9Sstevel@tonic-gate ct_status = "unknown"; 48507c478bd9Sstevel@tonic-gate } 48517c478bd9Sstevel@tonic-gate 48524c06356bSdh142964 lb_buf[0] = 0; /* not interested in load balancing config */ 48534c06356bSdh142964 48544c06356bSdh142964 if (MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip)) { 48554c06356bSdh142964 status = "removed"; 48564c06356bSdh142964 } else if (MDI_PI_IS_OFFLINE(pip)) { 48577c478bd9Sstevel@tonic-gate status = "offline"; 48587c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_ONLINE(pip)) { 48597c478bd9Sstevel@tonic-gate status = "online"; 48604c06356bSdh142964 report_lb_p = 1; 48617c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_STANDBY(pip)) { 48627c478bd9Sstevel@tonic-gate status = "standby"; 48637c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_FAULT(pip)) { 48647c478bd9Sstevel@tonic-gate status = "faulted"; 48657c478bd9Sstevel@tonic-gate } else { 48667c478bd9Sstevel@tonic-gate status = "unknown"; 48677c478bd9Sstevel@tonic-gate } 48687c478bd9Sstevel@tonic-gate 48694c06356bSdh142964 if (cdip) { 48704c06356bSdh142964 ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 48714c06356bSdh142964 48724c06356bSdh142964 /* 48734c06356bSdh142964 * NOTE: Keeping "multipath status: %s" and 48744c06356bSdh142964 * "Load balancing: %s" format unchanged in case someone 48754c06356bSdh142964 * scrubs /var/adm/messages looking for these messages. 48764c06356bSdh142964 */ 48774c06356bSdh142964 if (report_lb_c && report_lb_p) { 48787c478bd9Sstevel@tonic-gate if (ct->ct_lb == LOAD_BALANCE_LBA) { 48797c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 48807c478bd9Sstevel@tonic-gate "%s, region-size: %d", mdi_load_balance_lba, 48817c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size); 48827c478bd9Sstevel@tonic-gate } else if (ct->ct_lb == LOAD_BALANCE_NONE) { 48837c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 48847c478bd9Sstevel@tonic-gate "%s", mdi_load_balance_none); 48857c478bd9Sstevel@tonic-gate } else { 48867c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), "%s", 48877c478bd9Sstevel@tonic-gate mdi_load_balance_rr); 48887c478bd9Sstevel@tonic-gate } 48897c478bd9Sstevel@tonic-gate 48904c06356bSdh142964 cmn_err(mdi_debug_consoleonly ? CE_NOTE : CE_CONT, 48914c06356bSdh142964 "?%s (%s%d) multipath status: %s: " 48924c06356bSdh142964 "path %d %s is %s: Load balancing: %s\n", 48934c06356bSdh142964 ddi_pathname(cdip, ct_path), ddi_driver_name(cdip), 48944c06356bSdh142964 ddi_get_instance(cdip), ct_status, 48954c06356bSdh142964 mdi_pi_get_path_instance(pip), 48964c06356bSdh142964 mdi_pi_spathname(pip), status, lb_buf); 48974c06356bSdh142964 } else { 48984c06356bSdh142964 cmn_err(mdi_debug_consoleonly ? CE_NOTE : CE_CONT, 48994c06356bSdh142964 "?%s (%s%d) multipath status: %s: " 49004c06356bSdh142964 "path %d %s is %s\n", 49014c06356bSdh142964 ddi_pathname(cdip, ct_path), ddi_driver_name(cdip), 49024c06356bSdh142964 ddi_get_instance(cdip), ct_status, 49034c06356bSdh142964 mdi_pi_get_path_instance(pip), 49044c06356bSdh142964 mdi_pi_spathname(pip), status); 49054c06356bSdh142964 } 49064c06356bSdh142964 49077c478bd9Sstevel@tonic-gate kmem_free(ct_path, MAXPATHLEN); 49087c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct); 49097c478bd9Sstevel@tonic-gate } 49107c478bd9Sstevel@tonic-gate } 49117c478bd9Sstevel@tonic-gate 49127c478bd9Sstevel@tonic-gate #ifdef DEBUG 49137c478bd9Sstevel@tonic-gate /* 49147c478bd9Sstevel@tonic-gate * i_mdi_log(): 49157c478bd9Sstevel@tonic-gate * Utility function for error message management 49167c478bd9Sstevel@tonic-gate * 49174c06356bSdh142964 * NOTE: Implementation takes care of trailing \n for cmn_err, 49184c06356bSdh142964 * MDI_DEBUG should not terminate fmt strings with \n. 49194c06356bSdh142964 * 49204c06356bSdh142964 * NOTE: If the level is >= 2, and there is no leading !?^ 49214c06356bSdh142964 * then a leading ! is implied (but can be overriden via 49224c06356bSdh142964 * mdi_debug_consoleonly). If you are using kmdb on the console, 49234c06356bSdh142964 * consider setting mdi_debug_consoleonly to 1 as an aid. 49247c478bd9Sstevel@tonic-gate */ 49254c06356bSdh142964 /*PRINTFLIKE4*/ 49267c478bd9Sstevel@tonic-gate static void 49274c06356bSdh142964 i_mdi_log(int level, const char *func, dev_info_t *dip, const char *fmt, ...) 49287c478bd9Sstevel@tonic-gate { 4929c73a93f2Sdm120769 char name[MAXNAMELEN]; 49304c06356bSdh142964 char buf[512]; 49315e3986cbScth char *bp; 49327c478bd9Sstevel@tonic-gate va_list ap; 49337c478bd9Sstevel@tonic-gate int log_only = 0; 49347c478bd9Sstevel@tonic-gate int boot_only = 0; 49357c478bd9Sstevel@tonic-gate int console_only = 0; 49367c478bd9Sstevel@tonic-gate 49377c478bd9Sstevel@tonic-gate if (dip) { 49384c06356bSdh142964 (void) snprintf(name, sizeof(name), "%s%d: ", 493955e592a2SRandall Ralphs ddi_driver_name(dip), ddi_get_instance(dip)); 4940c73a93f2Sdm120769 } else { 49415e3986cbScth name[0] = 0; 49427c478bd9Sstevel@tonic-gate } 49437c478bd9Sstevel@tonic-gate 49447c478bd9Sstevel@tonic-gate va_start(ap, fmt); 49454c06356bSdh142964 (void) vsnprintf(buf, sizeof(buf), fmt, ap); 49467c478bd9Sstevel@tonic-gate va_end(ap); 49477c478bd9Sstevel@tonic-gate 49487c478bd9Sstevel@tonic-gate switch (buf[0]) { 49497c478bd9Sstevel@tonic-gate case '!': 49505e3986cbScth bp = &buf[1]; 49517c478bd9Sstevel@tonic-gate log_only = 1; 49527c478bd9Sstevel@tonic-gate break; 49537c478bd9Sstevel@tonic-gate case '?': 49545e3986cbScth bp = &buf[1]; 49557c478bd9Sstevel@tonic-gate boot_only = 1; 49567c478bd9Sstevel@tonic-gate break; 49577c478bd9Sstevel@tonic-gate case '^': 49585e3986cbScth bp = &buf[1]; 49597c478bd9Sstevel@tonic-gate console_only = 1; 49607c478bd9Sstevel@tonic-gate break; 49615e3986cbScth default: 49624c06356bSdh142964 if (level >= 2) 49634c06356bSdh142964 log_only = 1; /* ! implied */ 49645e3986cbScth bp = buf; 49655e3986cbScth break; 49665e3986cbScth } 49675e3986cbScth if (mdi_debug_logonly) { 49685e3986cbScth log_only = 1; 49695e3986cbScth boot_only = 0; 49705e3986cbScth console_only = 0; 49717c478bd9Sstevel@tonic-gate } 49724c06356bSdh142964 if (mdi_debug_consoleonly) { 49734c06356bSdh142964 log_only = 0; 49744c06356bSdh142964 boot_only = 0; 49754c06356bSdh142964 console_only = 1; 49764c06356bSdh142964 level = CE_NOTE; 49774c06356bSdh142964 goto console; 49784c06356bSdh142964 } 49797c478bd9Sstevel@tonic-gate 49807c478bd9Sstevel@tonic-gate switch (level) { 49817c478bd9Sstevel@tonic-gate case CE_NOTE: 49827c478bd9Sstevel@tonic-gate level = CE_CONT; 49837c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 49847c478bd9Sstevel@tonic-gate case CE_CONT: 49854c06356bSdh142964 if (boot_only) { 49864c06356bSdh142964 cmn_err(level, "?mdi: %s%s: %s\n", name, func, bp); 49874c06356bSdh142964 } else if (console_only) { 49884c06356bSdh142964 cmn_err(level, "^mdi: %s%s: %s\n", name, func, bp); 49894c06356bSdh142964 } else if (log_only) { 49904c06356bSdh142964 cmn_err(level, "!mdi: %s%s: %s\n", name, func, bp); 49914c06356bSdh142964 } else { 49924c06356bSdh142964 cmn_err(level, "mdi: %s%s: %s\n", name, func, bp); 49934c06356bSdh142964 } 49944c06356bSdh142964 break; 49954c06356bSdh142964 49967c478bd9Sstevel@tonic-gate case CE_WARN: 49977c478bd9Sstevel@tonic-gate case CE_PANIC: 49984c06356bSdh142964 console: 49997c478bd9Sstevel@tonic-gate if (boot_only) { 50004c06356bSdh142964 cmn_err(level, "?mdi: %s%s: %s", name, func, bp); 50017c478bd9Sstevel@tonic-gate } else if (console_only) { 50024c06356bSdh142964 cmn_err(level, "^mdi: %s%s: %s", name, func, bp); 50037c478bd9Sstevel@tonic-gate } else if (log_only) { 50044c06356bSdh142964 cmn_err(level, "!mdi: %s%s: %s", name, func, bp); 50057c478bd9Sstevel@tonic-gate } else { 50064c06356bSdh142964 cmn_err(level, "mdi: %s%s: %s", name, func, bp); 50077c478bd9Sstevel@tonic-gate } 50087c478bd9Sstevel@tonic-gate break; 50097c478bd9Sstevel@tonic-gate default: 50105e3986cbScth cmn_err(level, "mdi: %s%s", name, bp); 50117c478bd9Sstevel@tonic-gate break; 50127c478bd9Sstevel@tonic-gate } 50137c478bd9Sstevel@tonic-gate } 50147c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 50157c478bd9Sstevel@tonic-gate 50167c478bd9Sstevel@tonic-gate void 50177c478bd9Sstevel@tonic-gate i_mdi_client_online(dev_info_t *ct_dip) 50187c478bd9Sstevel@tonic-gate { 50197c478bd9Sstevel@tonic-gate mdi_client_t *ct; 50207c478bd9Sstevel@tonic-gate 50217c478bd9Sstevel@tonic-gate /* 50227c478bd9Sstevel@tonic-gate * Client online notification. Mark client state as online 50237c478bd9Sstevel@tonic-gate * restore our binding with dev_info node 50247c478bd9Sstevel@tonic-gate */ 50257c478bd9Sstevel@tonic-gate ct = i_devi_get_client(ct_dip); 50267c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 50277c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 50287c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 50297c478bd9Sstevel@tonic-gate /* catch for any memory leaks */ 50307c478bd9Sstevel@tonic-gate ASSERT((ct->ct_dip == NULL) || (ct->ct_dip == ct_dip)); 50317c478bd9Sstevel@tonic-gate ct->ct_dip = ct_dip; 50327c478bd9Sstevel@tonic-gate 50337c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) 50347c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 50357c478bd9Sstevel@tonic-gate 50364c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ct_dip, 50374c06356bSdh142964 "i_mdi_pm_hold_client %p", (void *)ct)); 50387c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 50397c478bd9Sstevel@tonic-gate 50407c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 50417c478bd9Sstevel@tonic-gate } 50427c478bd9Sstevel@tonic-gate 50437c478bd9Sstevel@tonic-gate void 50447c478bd9Sstevel@tonic-gate i_mdi_phci_online(dev_info_t *ph_dip) 50457c478bd9Sstevel@tonic-gate { 50467c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 50477c478bd9Sstevel@tonic-gate 50487c478bd9Sstevel@tonic-gate /* pHCI online notification. Mark state accordingly */ 50497c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(ph_dip); 50507c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 50517c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 50527c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 50537c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 50547c478bd9Sstevel@tonic-gate } 50557c478bd9Sstevel@tonic-gate 50567c478bd9Sstevel@tonic-gate /* 50577c478bd9Sstevel@tonic-gate * mdi_devi_online(): 50587c478bd9Sstevel@tonic-gate * Online notification from NDI framework on pHCI/client 50597c478bd9Sstevel@tonic-gate * device online. 50607c478bd9Sstevel@tonic-gate * Return Values: 50617c478bd9Sstevel@tonic-gate * NDI_SUCCESS 50627c478bd9Sstevel@tonic-gate * MDI_FAILURE 50637c478bd9Sstevel@tonic-gate */ 50647c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 50657c478bd9Sstevel@tonic-gate int 50667c478bd9Sstevel@tonic-gate mdi_devi_online(dev_info_t *dip, uint_t flags) 50677c478bd9Sstevel@tonic-gate { 50687c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 50697c478bd9Sstevel@tonic-gate i_mdi_phci_online(dip); 50707c478bd9Sstevel@tonic-gate } 50717c478bd9Sstevel@tonic-gate 50727c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 50737c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 50747c478bd9Sstevel@tonic-gate } 50757c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 50767c478bd9Sstevel@tonic-gate } 50777c478bd9Sstevel@tonic-gate 50787c478bd9Sstevel@tonic-gate /* 50797c478bd9Sstevel@tonic-gate * mdi_devi_offline(): 50807c478bd9Sstevel@tonic-gate * Offline notification from NDI framework on pHCI/Client device 50817c478bd9Sstevel@tonic-gate * offline. 50827c478bd9Sstevel@tonic-gate * 50837c478bd9Sstevel@tonic-gate * Return Values: 50847c478bd9Sstevel@tonic-gate * NDI_SUCCESS 50857c478bd9Sstevel@tonic-gate * NDI_FAILURE 50867c478bd9Sstevel@tonic-gate */ 50877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 50887c478bd9Sstevel@tonic-gate int 50897c478bd9Sstevel@tonic-gate mdi_devi_offline(dev_info_t *dip, uint_t flags) 50907c478bd9Sstevel@tonic-gate { 50917c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 50927c478bd9Sstevel@tonic-gate 50937c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 50947c478bd9Sstevel@tonic-gate rv = i_mdi_client_offline(dip, flags); 50957c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) 50967c478bd9Sstevel@tonic-gate return (rv); 50977c478bd9Sstevel@tonic-gate } 50987c478bd9Sstevel@tonic-gate 50997c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 51007c478bd9Sstevel@tonic-gate rv = i_mdi_phci_offline(dip, flags); 51015e3986cbScth 51027c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && MDI_CLIENT(dip)) { 51037c478bd9Sstevel@tonic-gate /* set client back online */ 51047c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 51057c478bd9Sstevel@tonic-gate } 51067c478bd9Sstevel@tonic-gate } 51077c478bd9Sstevel@tonic-gate 51087c478bd9Sstevel@tonic-gate return (rv); 51097c478bd9Sstevel@tonic-gate } 51107c478bd9Sstevel@tonic-gate 51117c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 51127c478bd9Sstevel@tonic-gate static int 51137c478bd9Sstevel@tonic-gate i_mdi_phci_offline(dev_info_t *dip, uint_t flags) 51147c478bd9Sstevel@tonic-gate { 51157c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 51167c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 51177c478bd9Sstevel@tonic-gate mdi_client_t *ct; 51187c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 51197c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 51207c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 51217c478bd9Sstevel@tonic-gate dev_info_t *cdip; 51227c478bd9Sstevel@tonic-gate 51237c478bd9Sstevel@tonic-gate /* 51247c478bd9Sstevel@tonic-gate * pHCI component offline notification 51257c478bd9Sstevel@tonic-gate * Make sure that this pHCI instance is free to be offlined. 51267c478bd9Sstevel@tonic-gate * If it is OK to proceed, Offline and remove all the child 51277c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes. This process automatically offlines 51287c478bd9Sstevel@tonic-gate * corresponding client devices, for which this pHCI provides 51297c478bd9Sstevel@tonic-gate * critical services. 51307c478bd9Sstevel@tonic-gate */ 51317c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 51324c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 51334c06356bSdh142964 "called %p %p", (void *)dip, (void *)ph)); 51347c478bd9Sstevel@tonic-gate if (ph == NULL) { 51357c478bd9Sstevel@tonic-gate return (rv); 51367c478bd9Sstevel@tonic-gate } 51377c478bd9Sstevel@tonic-gate 51387c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 51397c478bd9Sstevel@tonic-gate 51407c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_OFFLINE(ph)) { 51414c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, dip, 51424c06356bSdh142964 "!pHCI already offlined: %p", (void *)dip)); 51437c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 51447c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 51457c478bd9Sstevel@tonic-gate } 51467c478bd9Sstevel@tonic-gate 51477c478bd9Sstevel@tonic-gate /* 51487c478bd9Sstevel@tonic-gate * Check to see if the pHCI can be offlined 51497c478bd9Sstevel@tonic-gate */ 51507c478bd9Sstevel@tonic-gate if (ph->ph_unstable) { 51514c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, dip, 51524c06356bSdh142964 "!One or more target devices are in transient state. " 51534c06356bSdh142964 "This device can not be removed at this moment. " 51544c06356bSdh142964 "Please try again later.")); 51557c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 51567c478bd9Sstevel@tonic-gate return (NDI_BUSY); 51577c478bd9Sstevel@tonic-gate } 51587c478bd9Sstevel@tonic-gate 51597c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 51607c478bd9Sstevel@tonic-gate while (pip != NULL) { 51617c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 51627c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 51635e3986cbScth 51647c478bd9Sstevel@tonic-gate /* 51657c478bd9Sstevel@tonic-gate * The mdi_pathinfo state is OK. Check the client state. 51667c478bd9Sstevel@tonic-gate * If failover in progress fail the pHCI from offlining 51677c478bd9Sstevel@tonic-gate */ 51687c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 51697c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 51707c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 51717c478bd9Sstevel@tonic-gate (ct->ct_unstable)) { 51727c478bd9Sstevel@tonic-gate /* 51737c478bd9Sstevel@tonic-gate * Failover is in progress, Fail the DR 51747c478bd9Sstevel@tonic-gate */ 51754c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, dip, 51764c06356bSdh142964 "!pHCI device is busy. " 51774c06356bSdh142964 "This device can not be removed at this moment. " 51784c06356bSdh142964 "Please try again later.")); 51797c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 51805e3986cbScth i_mdi_client_unlock(ct); 51817c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 51827c478bd9Sstevel@tonic-gate return (NDI_BUSY); 51837c478bd9Sstevel@tonic-gate } 51847c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 51857c478bd9Sstevel@tonic-gate 51867c478bd9Sstevel@tonic-gate /* 51877c478bd9Sstevel@tonic-gate * Check to see of we are removing the last path of this 51887c478bd9Sstevel@tonic-gate * client device... 51897c478bd9Sstevel@tonic-gate */ 51907c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 51917c478bd9Sstevel@tonic-gate if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 51927c478bd9Sstevel@tonic-gate (i_mdi_client_compute_state(ct, ph) == 51937c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_FAILED)) { 51947c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 51957c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 51964c06356bSdh142964 if (ndi_devi_offline(cdip, 51974c06356bSdh142964 NDI_DEVFS_CLEAN) != NDI_SUCCESS) { 51987c478bd9Sstevel@tonic-gate /* 51997c478bd9Sstevel@tonic-gate * ndi_devi_offline() failed. 52007c478bd9Sstevel@tonic-gate * This pHCI provides the critical path 52017c478bd9Sstevel@tonic-gate * to one or more client devices. 52027c478bd9Sstevel@tonic-gate * Return busy. 52037c478bd9Sstevel@tonic-gate */ 52047c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 52054c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, dip, 52064c06356bSdh142964 "!pHCI device is busy. " 52074c06356bSdh142964 "This device can not be removed at this " 52084c06356bSdh142964 "moment. Please try again later.")); 52097c478bd9Sstevel@tonic-gate failed_pip = pip; 52107c478bd9Sstevel@tonic-gate break; 52117c478bd9Sstevel@tonic-gate } else { 52127c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 52137c478bd9Sstevel@tonic-gate pip = next; 52147c478bd9Sstevel@tonic-gate } 52157c478bd9Sstevel@tonic-gate } else { 52167c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 52177c478bd9Sstevel@tonic-gate pip = next; 52187c478bd9Sstevel@tonic-gate } 52197c478bd9Sstevel@tonic-gate } 52207c478bd9Sstevel@tonic-gate 52217c478bd9Sstevel@tonic-gate if (failed_pip) { 52227c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 52237c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 52247c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 52257c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 52267c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 52277c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 52287c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 52297c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 52307c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 52317c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 52327c478bd9Sstevel@tonic-gate if (cdip) { 52337c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 52347c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 52357c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 52367c478bd9Sstevel@tonic-gate (void) ndi_devi_online(cdip, 0); 52377c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 52387c478bd9Sstevel@tonic-gate pip = next; 52397c478bd9Sstevel@tonic-gate continue; 52407c478bd9Sstevel@tonic-gate } 52417c478bd9Sstevel@tonic-gate break; 52427c478bd9Sstevel@tonic-gate 52437c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 52447c478bd9Sstevel@tonic-gate if (cdip) { 52457c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 52467c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 52477c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 52484c06356bSdh142964 (void) ndi_devi_offline(cdip, 52494c06356bSdh142964 NDI_DEVFS_CLEAN); 52507c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 52517c478bd9Sstevel@tonic-gate pip = next; 52527c478bd9Sstevel@tonic-gate continue; 52537c478bd9Sstevel@tonic-gate } 52547c478bd9Sstevel@tonic-gate break; 52557c478bd9Sstevel@tonic-gate } 52567c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 52577c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 52587c478bd9Sstevel@tonic-gate pip = next; 52597c478bd9Sstevel@tonic-gate } 52607c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 52617c478bd9Sstevel@tonic-gate return (NDI_BUSY); 52627c478bd9Sstevel@tonic-gate } 52637c478bd9Sstevel@tonic-gate 52647c478bd9Sstevel@tonic-gate /* 52657c478bd9Sstevel@tonic-gate * Mark the pHCI as offline 52667c478bd9Sstevel@tonic-gate */ 52677c478bd9Sstevel@tonic-gate MDI_PHCI_SET_OFFLINE(ph); 52687c478bd9Sstevel@tonic-gate 52697c478bd9Sstevel@tonic-gate /* 52707c478bd9Sstevel@tonic-gate * Mark the child mdi_pathinfo nodes as transient 52717c478bd9Sstevel@tonic-gate */ 52727c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 52737c478bd9Sstevel@tonic-gate while (pip != NULL) { 52747c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 52757c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 52767c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 52777c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 52787c478bd9Sstevel@tonic-gate pip = next; 52797c478bd9Sstevel@tonic-gate } 52807c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 52817c478bd9Sstevel@tonic-gate /* 52827c478bd9Sstevel@tonic-gate * Give a chance for any pending commands to execute 52837c478bd9Sstevel@tonic-gate */ 528496c4a178SChris Horne delay_random(mdi_delay); 52857c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 52867c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 52877c478bd9Sstevel@tonic-gate while (pip != NULL) { 52887c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 52897c478bd9Sstevel@tonic-gate (void) i_mdi_pi_offline(pip, flags); 52907c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 52917c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 52927c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_OFFLINE(pip)) { 52934c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, dip, 52944c06356bSdh142964 "!pHCI device is busy. " 52954c06356bSdh142964 "This device can not be removed at this moment. " 52964c06356bSdh142964 "Please try again later.")); 52977c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 52987c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 52997c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 53007c478bd9Sstevel@tonic-gate return (NDI_BUSY); 53017c478bd9Sstevel@tonic-gate } 53027c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 53037c478bd9Sstevel@tonic-gate pip = next; 53047c478bd9Sstevel@tonic-gate } 53057c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 53067c478bd9Sstevel@tonic-gate 53077c478bd9Sstevel@tonic-gate return (rv); 53087c478bd9Sstevel@tonic-gate } 53097c478bd9Sstevel@tonic-gate 531025e8c5aaSvikram void 531125e8c5aaSvikram mdi_phci_mark_retiring(dev_info_t *dip, char **cons_array) 531225e8c5aaSvikram { 531325e8c5aaSvikram mdi_phci_t *ph; 531425e8c5aaSvikram mdi_client_t *ct; 531525e8c5aaSvikram mdi_pathinfo_t *pip; 531625e8c5aaSvikram mdi_pathinfo_t *next; 531725e8c5aaSvikram dev_info_t *cdip; 531825e8c5aaSvikram 531925e8c5aaSvikram if (!MDI_PHCI(dip)) 532025e8c5aaSvikram return; 532125e8c5aaSvikram 532225e8c5aaSvikram ph = i_devi_get_phci(dip); 532325e8c5aaSvikram if (ph == NULL) { 532425e8c5aaSvikram return; 532525e8c5aaSvikram } 532625e8c5aaSvikram 532725e8c5aaSvikram MDI_PHCI_LOCK(ph); 532825e8c5aaSvikram 532925e8c5aaSvikram if (MDI_PHCI_IS_OFFLINE(ph)) { 533025e8c5aaSvikram /* has no last path */ 533125e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 533225e8c5aaSvikram return; 533325e8c5aaSvikram } 533425e8c5aaSvikram 533525e8c5aaSvikram pip = ph->ph_path_head; 533625e8c5aaSvikram while (pip != NULL) { 533725e8c5aaSvikram MDI_PI_LOCK(pip); 533825e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 533925e8c5aaSvikram 534025e8c5aaSvikram ct = MDI_PI(pip)->pi_client; 534125e8c5aaSvikram i_mdi_client_lock(ct, pip); 534225e8c5aaSvikram MDI_PI_UNLOCK(pip); 534325e8c5aaSvikram 534425e8c5aaSvikram cdip = ct->ct_dip; 534525e8c5aaSvikram if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 534625e8c5aaSvikram (i_mdi_client_compute_state(ct, ph) == 534725e8c5aaSvikram MDI_CLIENT_STATE_FAILED)) { 534825e8c5aaSvikram /* Last path. Mark client dip as retiring */ 534925e8c5aaSvikram i_mdi_client_unlock(ct); 535025e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 535125e8c5aaSvikram (void) e_ddi_mark_retiring(cdip, cons_array); 535225e8c5aaSvikram MDI_PHCI_LOCK(ph); 535325e8c5aaSvikram pip = next; 535425e8c5aaSvikram } else { 535525e8c5aaSvikram i_mdi_client_unlock(ct); 535625e8c5aaSvikram pip = next; 535725e8c5aaSvikram } 535825e8c5aaSvikram } 535925e8c5aaSvikram 536025e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 536125e8c5aaSvikram 536225e8c5aaSvikram return; 536325e8c5aaSvikram } 536425e8c5aaSvikram 536525e8c5aaSvikram void 536625e8c5aaSvikram mdi_phci_retire_notify(dev_info_t *dip, int *constraint) 536725e8c5aaSvikram { 536825e8c5aaSvikram mdi_phci_t *ph; 536925e8c5aaSvikram mdi_client_t *ct; 537025e8c5aaSvikram mdi_pathinfo_t *pip; 537125e8c5aaSvikram mdi_pathinfo_t *next; 537225e8c5aaSvikram dev_info_t *cdip; 537325e8c5aaSvikram 537425e8c5aaSvikram if (!MDI_PHCI(dip)) 537525e8c5aaSvikram return; 537625e8c5aaSvikram 537725e8c5aaSvikram ph = i_devi_get_phci(dip); 537825e8c5aaSvikram if (ph == NULL) 537925e8c5aaSvikram return; 538025e8c5aaSvikram 538125e8c5aaSvikram MDI_PHCI_LOCK(ph); 538225e8c5aaSvikram 538325e8c5aaSvikram if (MDI_PHCI_IS_OFFLINE(ph)) { 538425e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 538525e8c5aaSvikram /* not last path */ 538625e8c5aaSvikram return; 538725e8c5aaSvikram } 538825e8c5aaSvikram 538925e8c5aaSvikram if (ph->ph_unstable) { 539025e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 539125e8c5aaSvikram /* can't check for constraints */ 539225e8c5aaSvikram *constraint = 0; 539325e8c5aaSvikram return; 539425e8c5aaSvikram } 539525e8c5aaSvikram 539625e8c5aaSvikram pip = ph->ph_path_head; 539725e8c5aaSvikram while (pip != NULL) { 539825e8c5aaSvikram MDI_PI_LOCK(pip); 539925e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 540025e8c5aaSvikram 540125e8c5aaSvikram /* 540225e8c5aaSvikram * The mdi_pathinfo state is OK. Check the client state. 540325e8c5aaSvikram * If failover in progress fail the pHCI from offlining 540425e8c5aaSvikram */ 540525e8c5aaSvikram ct = MDI_PI(pip)->pi_client; 540625e8c5aaSvikram i_mdi_client_lock(ct, pip); 540725e8c5aaSvikram if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 540825e8c5aaSvikram (ct->ct_unstable)) { 540925e8c5aaSvikram /* 541025e8c5aaSvikram * Failover is in progress, can't check for constraints 541125e8c5aaSvikram */ 541225e8c5aaSvikram MDI_PI_UNLOCK(pip); 541325e8c5aaSvikram i_mdi_client_unlock(ct); 541425e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 541525e8c5aaSvikram *constraint = 0; 541625e8c5aaSvikram return; 541725e8c5aaSvikram } 541825e8c5aaSvikram MDI_PI_UNLOCK(pip); 541925e8c5aaSvikram 542025e8c5aaSvikram /* 542125e8c5aaSvikram * Check to see of we are retiring the last path of this 542225e8c5aaSvikram * client device... 542325e8c5aaSvikram */ 542425e8c5aaSvikram cdip = ct->ct_dip; 542525e8c5aaSvikram if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 542625e8c5aaSvikram (i_mdi_client_compute_state(ct, ph) == 542725e8c5aaSvikram MDI_CLIENT_STATE_FAILED)) { 542825e8c5aaSvikram i_mdi_client_unlock(ct); 542925e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 543025e8c5aaSvikram (void) e_ddi_retire_notify(cdip, constraint); 543125e8c5aaSvikram MDI_PHCI_LOCK(ph); 543225e8c5aaSvikram pip = next; 543325e8c5aaSvikram } else { 543425e8c5aaSvikram i_mdi_client_unlock(ct); 543525e8c5aaSvikram pip = next; 543625e8c5aaSvikram } 543725e8c5aaSvikram } 543825e8c5aaSvikram 543925e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 544025e8c5aaSvikram 544125e8c5aaSvikram return; 544225e8c5aaSvikram } 544325e8c5aaSvikram 544425e8c5aaSvikram /* 54454c06356bSdh142964 * offline the path(s) hanging off the pHCI. If the 544625e8c5aaSvikram * last path to any client, check that constraints 544725e8c5aaSvikram * have been applied. 5448bf002425SStephen Hanson * 5449bf002425SStephen Hanson * If constraint is 0, we aren't going to retire the 5450bf002425SStephen Hanson * pHCI. However we still need to go through the paths 5451bf002425SStephen Hanson * calling e_ddi_retire_finalize() to clear their 5452bf002425SStephen Hanson * contract barriers. 545325e8c5aaSvikram */ 545425e8c5aaSvikram void 5455bf002425SStephen Hanson mdi_phci_retire_finalize(dev_info_t *dip, int phci_only, void *constraint) 545625e8c5aaSvikram { 545725e8c5aaSvikram mdi_phci_t *ph; 545825e8c5aaSvikram mdi_client_t *ct; 545925e8c5aaSvikram mdi_pathinfo_t *pip; 546025e8c5aaSvikram mdi_pathinfo_t *next; 546125e8c5aaSvikram dev_info_t *cdip; 546225e8c5aaSvikram int unstable = 0; 5463bf002425SStephen Hanson int tmp_constraint; 546425e8c5aaSvikram 546525e8c5aaSvikram if (!MDI_PHCI(dip)) 546625e8c5aaSvikram return; 546725e8c5aaSvikram 546825e8c5aaSvikram ph = i_devi_get_phci(dip); 546925e8c5aaSvikram if (ph == NULL) { 547025e8c5aaSvikram /* no last path and no pips */ 547125e8c5aaSvikram return; 547225e8c5aaSvikram } 547325e8c5aaSvikram 547425e8c5aaSvikram MDI_PHCI_LOCK(ph); 547525e8c5aaSvikram 547625e8c5aaSvikram if (MDI_PHCI_IS_OFFLINE(ph)) { 547725e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 547825e8c5aaSvikram /* no last path and no pips */ 547925e8c5aaSvikram return; 548025e8c5aaSvikram } 548125e8c5aaSvikram 548225e8c5aaSvikram /* 548325e8c5aaSvikram * Check to see if the pHCI can be offlined 548425e8c5aaSvikram */ 548525e8c5aaSvikram if (ph->ph_unstable) { 548625e8c5aaSvikram unstable = 1; 548725e8c5aaSvikram } 548825e8c5aaSvikram 548925e8c5aaSvikram pip = ph->ph_path_head; 549025e8c5aaSvikram while (pip != NULL) { 549125e8c5aaSvikram MDI_PI_LOCK(pip); 549225e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 549325e8c5aaSvikram 549425e8c5aaSvikram /* 549525e8c5aaSvikram * if failover in progress fail the pHCI from offlining 549625e8c5aaSvikram */ 549725e8c5aaSvikram ct = MDI_PI(pip)->pi_client; 549825e8c5aaSvikram i_mdi_client_lock(ct, pip); 549925e8c5aaSvikram if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 550025e8c5aaSvikram (ct->ct_unstable)) { 550125e8c5aaSvikram unstable = 1; 550225e8c5aaSvikram } 550325e8c5aaSvikram MDI_PI_UNLOCK(pip); 550425e8c5aaSvikram 550525e8c5aaSvikram /* 550625e8c5aaSvikram * Check to see of we are removing the last path of this 550725e8c5aaSvikram * client device... 550825e8c5aaSvikram */ 550925e8c5aaSvikram cdip = ct->ct_dip; 551025e8c5aaSvikram if (!phci_only && cdip && 551125e8c5aaSvikram (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 551225e8c5aaSvikram (i_mdi_client_compute_state(ct, ph) == 551325e8c5aaSvikram MDI_CLIENT_STATE_FAILED)) { 551425e8c5aaSvikram i_mdi_client_unlock(ct); 551525e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 551625e8c5aaSvikram /* 5517bf002425SStephen Hanson * This is the last path to this client. 5518bf002425SStephen Hanson * 5519bf002425SStephen Hanson * Constraint will only be set to 1 if this client can 5520bf002425SStephen Hanson * be retired (as already determined by 5521bf002425SStephen Hanson * mdi_phci_retire_notify). However we don't actually 5522bf002425SStephen Hanson * need to retire the client (we just retire the last 5523bf002425SStephen Hanson * path - MPXIO will then fail all I/Os to the client). 5524bf002425SStephen Hanson * But we still need to call e_ddi_retire_finalize so 5525bf002425SStephen Hanson * the contract barriers can be cleared. Therefore we 5526bf002425SStephen Hanson * temporarily set constraint = 0 so that the client 5527bf002425SStephen Hanson * dip is not retired. 552825e8c5aaSvikram */ 5529bf002425SStephen Hanson tmp_constraint = 0; 5530bf002425SStephen Hanson (void) e_ddi_retire_finalize(cdip, &tmp_constraint); 553125e8c5aaSvikram MDI_PHCI_LOCK(ph); 553225e8c5aaSvikram pip = next; 553325e8c5aaSvikram } else { 553425e8c5aaSvikram i_mdi_client_unlock(ct); 553525e8c5aaSvikram pip = next; 553625e8c5aaSvikram } 553725e8c5aaSvikram } 553825e8c5aaSvikram 5539bf002425SStephen Hanson if (!phci_only && *((int *)constraint) == 0) { 5540bf002425SStephen Hanson MDI_PHCI_UNLOCK(ph); 5541bf002425SStephen Hanson return; 5542bf002425SStephen Hanson } 5543bf002425SStephen Hanson 554425e8c5aaSvikram /* 554525e8c5aaSvikram * Cannot offline pip(s) 554625e8c5aaSvikram */ 554725e8c5aaSvikram if (unstable) { 55484c06356bSdh142964 cmn_err(CE_WARN, "%s%d: mdi_phci_retire_finalize: " 55494c06356bSdh142964 "pHCI in transient state, cannot retire", 55504c06356bSdh142964 ddi_driver_name(dip), ddi_get_instance(dip)); 555125e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 555225e8c5aaSvikram return; 555325e8c5aaSvikram } 555425e8c5aaSvikram 555525e8c5aaSvikram /* 555625e8c5aaSvikram * Mark the pHCI as offline 555725e8c5aaSvikram */ 555825e8c5aaSvikram MDI_PHCI_SET_OFFLINE(ph); 555925e8c5aaSvikram 556025e8c5aaSvikram /* 556125e8c5aaSvikram * Mark the child mdi_pathinfo nodes as transient 556225e8c5aaSvikram */ 556325e8c5aaSvikram pip = ph->ph_path_head; 556425e8c5aaSvikram while (pip != NULL) { 556525e8c5aaSvikram MDI_PI_LOCK(pip); 556625e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 556725e8c5aaSvikram MDI_PI_SET_OFFLINING(pip); 556825e8c5aaSvikram MDI_PI_UNLOCK(pip); 556925e8c5aaSvikram pip = next; 557025e8c5aaSvikram } 557125e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 557225e8c5aaSvikram /* 557325e8c5aaSvikram * Give a chance for any pending commands to execute 557425e8c5aaSvikram */ 557596c4a178SChris Horne delay_random(mdi_delay); 557625e8c5aaSvikram MDI_PHCI_LOCK(ph); 557725e8c5aaSvikram pip = ph->ph_path_head; 557825e8c5aaSvikram while (pip != NULL) { 557925e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 558025e8c5aaSvikram (void) i_mdi_pi_offline(pip, 0); 558125e8c5aaSvikram MDI_PI_LOCK(pip); 558225e8c5aaSvikram ct = MDI_PI(pip)->pi_client; 558325e8c5aaSvikram if (!MDI_PI_IS_OFFLINE(pip)) { 55844c06356bSdh142964 cmn_err(CE_WARN, "mdi_phci_retire_finalize: " 55854c06356bSdh142964 "path %d %s busy, cannot offline", 55864c06356bSdh142964 mdi_pi_get_path_instance(pip), 55874c06356bSdh142964 mdi_pi_spathname(pip)); 558825e8c5aaSvikram MDI_PI_UNLOCK(pip); 558925e8c5aaSvikram MDI_PHCI_SET_ONLINE(ph); 559025e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 559125e8c5aaSvikram return; 559225e8c5aaSvikram } 559325e8c5aaSvikram MDI_PI_UNLOCK(pip); 559425e8c5aaSvikram pip = next; 559525e8c5aaSvikram } 559625e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 559725e8c5aaSvikram 559825e8c5aaSvikram return; 559925e8c5aaSvikram } 560025e8c5aaSvikram 560125e8c5aaSvikram void 560225e8c5aaSvikram mdi_phci_unretire(dev_info_t *dip) 560325e8c5aaSvikram { 5604f76de749SStephen Hanson mdi_phci_t *ph; 5605f76de749SStephen Hanson mdi_pathinfo_t *pip; 5606f76de749SStephen Hanson mdi_pathinfo_t *next; 5607f76de749SStephen Hanson 560825e8c5aaSvikram ASSERT(MDI_PHCI(dip)); 560925e8c5aaSvikram 561025e8c5aaSvikram /* 561125e8c5aaSvikram * Online the phci 561225e8c5aaSvikram */ 561325e8c5aaSvikram i_mdi_phci_online(dip); 5614f76de749SStephen Hanson 5615f76de749SStephen Hanson ph = i_devi_get_phci(dip); 5616f76de749SStephen Hanson MDI_PHCI_LOCK(ph); 5617f76de749SStephen Hanson pip = ph->ph_path_head; 5618f76de749SStephen Hanson while (pip != NULL) { 5619f76de749SStephen Hanson MDI_PI_LOCK(pip); 5620f76de749SStephen Hanson next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 5621f76de749SStephen Hanson MDI_PI_UNLOCK(pip); 5622f76de749SStephen Hanson (void) i_mdi_pi_online(pip, 0); 5623f76de749SStephen Hanson pip = next; 5624f76de749SStephen Hanson } 5625f76de749SStephen Hanson MDI_PHCI_UNLOCK(ph); 562625e8c5aaSvikram } 562725e8c5aaSvikram 56287c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 56297c478bd9Sstevel@tonic-gate static int 56307c478bd9Sstevel@tonic-gate i_mdi_client_offline(dev_info_t *dip, uint_t flags) 56317c478bd9Sstevel@tonic-gate { 56327c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 56337c478bd9Sstevel@tonic-gate mdi_client_t *ct; 56347c478bd9Sstevel@tonic-gate 56357c478bd9Sstevel@tonic-gate /* 56367c478bd9Sstevel@tonic-gate * Client component to go offline. Make sure that we are 56377c478bd9Sstevel@tonic-gate * not in failing over state and update client state 56387c478bd9Sstevel@tonic-gate * accordingly 56397c478bd9Sstevel@tonic-gate */ 56407c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 56414c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 56424c06356bSdh142964 "called %p %p", (void *)dip, (void *)ct)); 56437c478bd9Sstevel@tonic-gate if (ct != NULL) { 56447c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 56457c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 56467c478bd9Sstevel@tonic-gate /* 56477c478bd9Sstevel@tonic-gate * One or more paths are in transient state, 56487c478bd9Sstevel@tonic-gate * Dont allow offline of a client device 56497c478bd9Sstevel@tonic-gate */ 56504c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, dip, 56514c06356bSdh142964 "!One or more paths to " 56524c06356bSdh142964 "this device are in transient state. " 56534c06356bSdh142964 "This device can not be removed at this moment. " 56547c478bd9Sstevel@tonic-gate "Please try again later.")); 56557c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 56567c478bd9Sstevel@tonic-gate return (NDI_BUSY); 56577c478bd9Sstevel@tonic-gate } 56587c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 56597c478bd9Sstevel@tonic-gate /* 56607c478bd9Sstevel@tonic-gate * Failover is in progress, Dont allow DR of 56617c478bd9Sstevel@tonic-gate * a client device 56627c478bd9Sstevel@tonic-gate */ 56634c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, dip, 56644c06356bSdh142964 "!Client device is Busy. " 56654c06356bSdh142964 "This device can not be removed at this moment. " 56664c06356bSdh142964 "Please try again later.")); 56677c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 56687c478bd9Sstevel@tonic-gate return (NDI_BUSY); 56697c478bd9Sstevel@tonic-gate } 56707c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 56717c478bd9Sstevel@tonic-gate 56727c478bd9Sstevel@tonic-gate /* 56737c478bd9Sstevel@tonic-gate * Unbind our relationship with the dev_info node 56747c478bd9Sstevel@tonic-gate */ 56757c478bd9Sstevel@tonic-gate if (flags & NDI_DEVI_REMOVE) { 56767c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 56777c478bd9Sstevel@tonic-gate } 56787c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 56797c478bd9Sstevel@tonic-gate } 56807c478bd9Sstevel@tonic-gate return (rv); 56817c478bd9Sstevel@tonic-gate } 56827c478bd9Sstevel@tonic-gate 56837c478bd9Sstevel@tonic-gate /* 56847c478bd9Sstevel@tonic-gate * mdi_pre_attach(): 56857c478bd9Sstevel@tonic-gate * Pre attach() notification handler 56867c478bd9Sstevel@tonic-gate */ 56877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 56887c478bd9Sstevel@tonic-gate int 56897c478bd9Sstevel@tonic-gate mdi_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 56907c478bd9Sstevel@tonic-gate { 56917c478bd9Sstevel@tonic-gate /* don't support old DDI_PM_RESUME */ 56927c478bd9Sstevel@tonic-gate if ((DEVI(dip)->devi_mdi_component != MDI_COMPONENT_NONE) && 56937c478bd9Sstevel@tonic-gate (cmd == DDI_PM_RESUME)) 56947c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 56957c478bd9Sstevel@tonic-gate 56967c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 56977c478bd9Sstevel@tonic-gate } 56987c478bd9Sstevel@tonic-gate 56997c478bd9Sstevel@tonic-gate /* 57007c478bd9Sstevel@tonic-gate * mdi_post_attach(): 57017c478bd9Sstevel@tonic-gate * Post attach() notification handler 57027c478bd9Sstevel@tonic-gate */ 57037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 57047c478bd9Sstevel@tonic-gate void 57057c478bd9Sstevel@tonic-gate mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error) 57067c478bd9Sstevel@tonic-gate { 57077c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 57087c478bd9Sstevel@tonic-gate mdi_client_t *ct; 570937fbbce5Scth mdi_vhci_t *vh; 57107c478bd9Sstevel@tonic-gate 57117c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 57127c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 57137c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 57147c478bd9Sstevel@tonic-gate 57157c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 57167c478bd9Sstevel@tonic-gate switch (cmd) { 57177c478bd9Sstevel@tonic-gate case DDI_ATTACH: 57184c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 57194c06356bSdh142964 "phci post_attach called %p", (void *)ph)); 57207c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 57217c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 57227c478bd9Sstevel@tonic-gate } else { 57234c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, dip, 57244c06356bSdh142964 "!pHCI post_attach failed: error %d", 57257c478bd9Sstevel@tonic-gate error)); 57267c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 57277c478bd9Sstevel@tonic-gate } 57287c478bd9Sstevel@tonic-gate break; 57297c478bd9Sstevel@tonic-gate 57307c478bd9Sstevel@tonic-gate case DDI_RESUME: 57314c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 57324c06356bSdh142964 "pHCI post_resume: called %p", (void *)ph)); 57337c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 57347c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 57357c478bd9Sstevel@tonic-gate } else { 57364c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, dip, 57374c06356bSdh142964 "!pHCI post_resume failed: error %d", 57387c478bd9Sstevel@tonic-gate error)); 57397c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 57407c478bd9Sstevel@tonic-gate } 57417c478bd9Sstevel@tonic-gate break; 57427c478bd9Sstevel@tonic-gate } 57437c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 57447c478bd9Sstevel@tonic-gate } 57457c478bd9Sstevel@tonic-gate 57467c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 57477c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 57487c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 57497c478bd9Sstevel@tonic-gate 57507c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 57517c478bd9Sstevel@tonic-gate switch (cmd) { 57527c478bd9Sstevel@tonic-gate case DDI_ATTACH: 57534c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 57544c06356bSdh142964 "client post_attach called %p", (void *)ct)); 57557c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) { 57564c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, dip, 57574c06356bSdh142964 "!client post_attach failed: error %d", 57587c478bd9Sstevel@tonic-gate error)); 57597c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 57604c06356bSdh142964 MDI_DEBUG(4, (MDI_WARN, dip, 57614c06356bSdh142964 "i_mdi_pm_reset_client")); 57627c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 57637c478bd9Sstevel@tonic-gate break; 57647c478bd9Sstevel@tonic-gate } 57657c478bd9Sstevel@tonic-gate 57667c478bd9Sstevel@tonic-gate /* 576737fbbce5Scth * Client device has successfully attached, inform 576837fbbce5Scth * the vhci. 57697c478bd9Sstevel@tonic-gate */ 577037fbbce5Scth vh = ct->ct_vhci; 577137fbbce5Scth if (vh->vh_ops->vo_client_attached) 577237fbbce5Scth (*vh->vh_ops->vo_client_attached)(dip); 577337fbbce5Scth 57747c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 57757c478bd9Sstevel@tonic-gate break; 57767c478bd9Sstevel@tonic-gate 57777c478bd9Sstevel@tonic-gate case DDI_RESUME: 57784c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 57794c06356bSdh142964 "client post_attach: called %p", (void *)ct)); 57807c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 57817c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 57827c478bd9Sstevel@tonic-gate } else { 57834c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, dip, 57844c06356bSdh142964 "!client post_resume failed: error %d", 57857c478bd9Sstevel@tonic-gate error)); 57867c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 57877c478bd9Sstevel@tonic-gate } 57887c478bd9Sstevel@tonic-gate break; 57897c478bd9Sstevel@tonic-gate } 57907c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 57917c478bd9Sstevel@tonic-gate } 57927c478bd9Sstevel@tonic-gate } 57937c478bd9Sstevel@tonic-gate 57947c478bd9Sstevel@tonic-gate /* 57957c478bd9Sstevel@tonic-gate * mdi_pre_detach(): 57967c478bd9Sstevel@tonic-gate * Pre detach notification handler 57977c478bd9Sstevel@tonic-gate */ 57987c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 57997c478bd9Sstevel@tonic-gate int 58007c478bd9Sstevel@tonic-gate mdi_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 58017c478bd9Sstevel@tonic-gate { 58027c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 58037c478bd9Sstevel@tonic-gate 58047c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 58057c478bd9Sstevel@tonic-gate (void) i_mdi_client_pre_detach(dip, cmd); 58067c478bd9Sstevel@tonic-gate } 58077c478bd9Sstevel@tonic-gate 58087c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 58097c478bd9Sstevel@tonic-gate rv = i_mdi_phci_pre_detach(dip, cmd); 58107c478bd9Sstevel@tonic-gate } 58117c478bd9Sstevel@tonic-gate 58127c478bd9Sstevel@tonic-gate return (rv); 58137c478bd9Sstevel@tonic-gate } 58147c478bd9Sstevel@tonic-gate 58157c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 58167c478bd9Sstevel@tonic-gate static int 58177c478bd9Sstevel@tonic-gate i_mdi_phci_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 58187c478bd9Sstevel@tonic-gate { 58197c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 58207c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 58217c478bd9Sstevel@tonic-gate mdi_client_t *ct; 58227c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 58237c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 58247c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 58257c478bd9Sstevel@tonic-gate 58267c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 58277c478bd9Sstevel@tonic-gate if (ph == NULL) { 58287c478bd9Sstevel@tonic-gate return (rv); 58297c478bd9Sstevel@tonic-gate } 58307c478bd9Sstevel@tonic-gate 58317c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 58327c478bd9Sstevel@tonic-gate switch (cmd) { 58337c478bd9Sstevel@tonic-gate case DDI_DETACH: 58344c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 58354c06356bSdh142964 "pHCI pre_detach: called %p", (void *)ph)); 58367c478bd9Sstevel@tonic-gate if (!MDI_PHCI_IS_OFFLINE(ph)) { 58377c478bd9Sstevel@tonic-gate /* 58387c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes are still attached to 58397c478bd9Sstevel@tonic-gate * this pHCI. Fail the detach for this pHCI. 58407c478bd9Sstevel@tonic-gate */ 58414c06356bSdh142964 MDI_DEBUG(2, (MDI_WARN, dip, 58424c06356bSdh142964 "pHCI pre_detach: paths are still attached %p", 58434c06356bSdh142964 (void *)ph)); 58447c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 58457c478bd9Sstevel@tonic-gate break; 58467c478bd9Sstevel@tonic-gate } 58477c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 58487c478bd9Sstevel@tonic-gate break; 58497c478bd9Sstevel@tonic-gate 58507c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 58517c478bd9Sstevel@tonic-gate /* 58527c478bd9Sstevel@tonic-gate * pHCI is getting suspended. Since mpxio client 58537c478bd9Sstevel@tonic-gate * devices may not be suspended at this point, to avoid 58547c478bd9Sstevel@tonic-gate * a potential stack overflow, it is important to suspend 58557c478bd9Sstevel@tonic-gate * client devices before pHCI can be suspended. 58567c478bd9Sstevel@tonic-gate */ 58577c478bd9Sstevel@tonic-gate 58584c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 58594c06356bSdh142964 "pHCI pre_suspend: called %p", (void *)ph)); 58607c478bd9Sstevel@tonic-gate /* 58617c478bd9Sstevel@tonic-gate * Suspend all the client devices accessible through this pHCI 58627c478bd9Sstevel@tonic-gate */ 58637c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 58647c478bd9Sstevel@tonic-gate while (pip != NULL && rv == DDI_SUCCESS) { 58657c478bd9Sstevel@tonic-gate dev_info_t *cdip; 58667c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 58677c478bd9Sstevel@tonic-gate next = 58687c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 58697c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 58707c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 58717c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 58727c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 58737c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct) == 0) && 58747c478bd9Sstevel@tonic-gate MDI_CLIENT_IS_SUSPENDED(ct) == 0) { 58757c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 58767c478bd9Sstevel@tonic-gate if ((rv = devi_detach(cdip, DDI_SUSPEND)) != 58777c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 58787c478bd9Sstevel@tonic-gate /* 58797c478bd9Sstevel@tonic-gate * Suspend of one of the client 58807c478bd9Sstevel@tonic-gate * device has failed. 58817c478bd9Sstevel@tonic-gate */ 58824c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, dip, 58834c06356bSdh142964 "!suspend of device (%s%d) failed.", 58847c478bd9Sstevel@tonic-gate ddi_driver_name(cdip), 58857c478bd9Sstevel@tonic-gate ddi_get_instance(cdip))); 58867c478bd9Sstevel@tonic-gate failed_pip = pip; 58877c478bd9Sstevel@tonic-gate break; 58887c478bd9Sstevel@tonic-gate } 58897c478bd9Sstevel@tonic-gate } else { 58907c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 58917c478bd9Sstevel@tonic-gate } 58927c478bd9Sstevel@tonic-gate pip = next; 58937c478bd9Sstevel@tonic-gate } 58947c478bd9Sstevel@tonic-gate 58957c478bd9Sstevel@tonic-gate if (rv == DDI_SUCCESS) { 58967c478bd9Sstevel@tonic-gate /* 58977c478bd9Sstevel@tonic-gate * Suspend of client devices is complete. Proceed 58987c478bd9Sstevel@tonic-gate * with pHCI suspend. 58997c478bd9Sstevel@tonic-gate */ 59007c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 59017c478bd9Sstevel@tonic-gate } else { 59027c478bd9Sstevel@tonic-gate /* 59037c478bd9Sstevel@tonic-gate * Revert back all the suspended client device states 59047c478bd9Sstevel@tonic-gate * to converse. 59057c478bd9Sstevel@tonic-gate */ 59067c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 59077c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 59087c478bd9Sstevel@tonic-gate dev_info_t *cdip; 59097c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 59107c478bd9Sstevel@tonic-gate next = 59117c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 59127c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 59137c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 59147c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 59157c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 59167c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_SUSPENDED(ct)) { 59177c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 59187c478bd9Sstevel@tonic-gate (void) devi_attach(cdip, DDI_RESUME); 59197c478bd9Sstevel@tonic-gate } else { 59207c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 59217c478bd9Sstevel@tonic-gate } 59227c478bd9Sstevel@tonic-gate pip = next; 59237c478bd9Sstevel@tonic-gate } 59247c478bd9Sstevel@tonic-gate } 59257c478bd9Sstevel@tonic-gate break; 59267c478bd9Sstevel@tonic-gate 59277c478bd9Sstevel@tonic-gate default: 59287c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 59297c478bd9Sstevel@tonic-gate break; 59307c478bd9Sstevel@tonic-gate } 59317c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 59327c478bd9Sstevel@tonic-gate return (rv); 59337c478bd9Sstevel@tonic-gate } 59347c478bd9Sstevel@tonic-gate 59357c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 59367c478bd9Sstevel@tonic-gate static int 59377c478bd9Sstevel@tonic-gate i_mdi_client_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 59387c478bd9Sstevel@tonic-gate { 59397c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 59407c478bd9Sstevel@tonic-gate mdi_client_t *ct; 59417c478bd9Sstevel@tonic-gate 59427c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 59437c478bd9Sstevel@tonic-gate if (ct == NULL) { 59447c478bd9Sstevel@tonic-gate return (rv); 59457c478bd9Sstevel@tonic-gate } 59467c478bd9Sstevel@tonic-gate 59477c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 59487c478bd9Sstevel@tonic-gate switch (cmd) { 59497c478bd9Sstevel@tonic-gate case DDI_DETACH: 59504c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 59514c06356bSdh142964 "client pre_detach: called %p", 59524c06356bSdh142964 (void *)ct)); 59537c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 59547c478bd9Sstevel@tonic-gate break; 59557c478bd9Sstevel@tonic-gate 59567c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 59574c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 59584c06356bSdh142964 "client pre_suspend: called %p", 59594c06356bSdh142964 (void *)ct)); 59607c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 59617c478bd9Sstevel@tonic-gate break; 59627c478bd9Sstevel@tonic-gate 59637c478bd9Sstevel@tonic-gate default: 59647c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 59657c478bd9Sstevel@tonic-gate break; 59667c478bd9Sstevel@tonic-gate } 59677c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59687c478bd9Sstevel@tonic-gate return (rv); 59697c478bd9Sstevel@tonic-gate } 59707c478bd9Sstevel@tonic-gate 59717c478bd9Sstevel@tonic-gate /* 59727c478bd9Sstevel@tonic-gate * mdi_post_detach(): 59737c478bd9Sstevel@tonic-gate * Post detach notification handler 59747c478bd9Sstevel@tonic-gate */ 59757c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 59767c478bd9Sstevel@tonic-gate void 59777c478bd9Sstevel@tonic-gate mdi_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 59787c478bd9Sstevel@tonic-gate { 59797c478bd9Sstevel@tonic-gate /* 59807c478bd9Sstevel@tonic-gate * Detach/Suspend of mpxio component failed. Update our state 59817c478bd9Sstevel@tonic-gate * too 59827c478bd9Sstevel@tonic-gate */ 59837c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) 59847c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dip, cmd, error); 59857c478bd9Sstevel@tonic-gate 59867c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) 59877c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dip, cmd, error); 59887c478bd9Sstevel@tonic-gate } 59897c478bd9Sstevel@tonic-gate 59907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 59917c478bd9Sstevel@tonic-gate static void 59927c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 59937c478bd9Sstevel@tonic-gate { 59947c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 59957c478bd9Sstevel@tonic-gate 59967c478bd9Sstevel@tonic-gate /* 59977c478bd9Sstevel@tonic-gate * Detach/Suspend of phci component failed. Update our state 59987c478bd9Sstevel@tonic-gate * too 59997c478bd9Sstevel@tonic-gate */ 60007c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 60017c478bd9Sstevel@tonic-gate if (ph == NULL) { 60027c478bd9Sstevel@tonic-gate return; 60037c478bd9Sstevel@tonic-gate } 60047c478bd9Sstevel@tonic-gate 60057c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 60067c478bd9Sstevel@tonic-gate /* 60077c478bd9Sstevel@tonic-gate * Detach of pHCI failed. Restore back converse 60087c478bd9Sstevel@tonic-gate * state 60097c478bd9Sstevel@tonic-gate */ 60107c478bd9Sstevel@tonic-gate switch (cmd) { 60117c478bd9Sstevel@tonic-gate case DDI_DETACH: 60124c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 60134c06356bSdh142964 "pHCI post_detach: called %p", 60144c06356bSdh142964 (void *)ph)); 60157c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 60167c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 60177c478bd9Sstevel@tonic-gate break; 60187c478bd9Sstevel@tonic-gate 60197c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 60204c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 60214c06356bSdh142964 "pHCI post_suspend: called %p", 60224c06356bSdh142964 (void *)ph)); 60237c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 60247c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 60257c478bd9Sstevel@tonic-gate break; 60267c478bd9Sstevel@tonic-gate } 60277c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 60287c478bd9Sstevel@tonic-gate } 60297c478bd9Sstevel@tonic-gate 60307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 60317c478bd9Sstevel@tonic-gate static void 60327c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 60337c478bd9Sstevel@tonic-gate { 60347c478bd9Sstevel@tonic-gate mdi_client_t *ct; 60357c478bd9Sstevel@tonic-gate 60367c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 60377c478bd9Sstevel@tonic-gate if (ct == NULL) { 60387c478bd9Sstevel@tonic-gate return; 60397c478bd9Sstevel@tonic-gate } 60407c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 60417c478bd9Sstevel@tonic-gate /* 60427c478bd9Sstevel@tonic-gate * Detach of Client failed. Restore back converse 60437c478bd9Sstevel@tonic-gate * state 60447c478bd9Sstevel@tonic-gate */ 60457c478bd9Sstevel@tonic-gate switch (cmd) { 60467c478bd9Sstevel@tonic-gate case DDI_DETACH: 60474c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 60484c06356bSdh142964 "client post_detach: called %p", (void *)ct)); 6049*1b94a41bSChris Horne if (DEVI_IS_ATTACHING(dip)) { 60504c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, dip, 60517c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 60527c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 60537c478bd9Sstevel@tonic-gate } else { 60544c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, dip, 60557c478bd9Sstevel@tonic-gate "i_mdi_pm_reset_client\n")); 60567c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 60577c478bd9Sstevel@tonic-gate } 60587c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 60597c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 60607c478bd9Sstevel@tonic-gate break; 60617c478bd9Sstevel@tonic-gate 60627c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 60634c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, dip, 60644c06356bSdh142964 "called %p", (void *)ct)); 60657c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 60667c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 60677c478bd9Sstevel@tonic-gate break; 60687c478bd9Sstevel@tonic-gate } 60697c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60707c478bd9Sstevel@tonic-gate } 60717c478bd9Sstevel@tonic-gate 607237fbbce5Scth int 607337fbbce5Scth mdi_pi_kstat_exists(mdi_pathinfo_t *pip) 607437fbbce5Scth { 607537fbbce5Scth return (MDI_PI(pip)->pi_kstats ? 1 : 0); 607637fbbce5Scth } 607737fbbce5Scth 60787c478bd9Sstevel@tonic-gate /* 60797c478bd9Sstevel@tonic-gate * create and install per-path (client - pHCI) statistics 60807c478bd9Sstevel@tonic-gate * I/O stats supported: nread, nwritten, reads, and writes 60817c478bd9Sstevel@tonic-gate * Error stats - hard errors, soft errors, & transport errors 60827c478bd9Sstevel@tonic-gate */ 608337fbbce5Scth int 608437fbbce5Scth mdi_pi_kstat_create(mdi_pathinfo_t *pip, char *ksname) 60857c478bd9Sstevel@tonic-gate { 60867c478bd9Sstevel@tonic-gate kstat_t *kiosp, *kerrsp; 60877c478bd9Sstevel@tonic-gate struct pi_errs *nsp; 60887c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 60897c478bd9Sstevel@tonic-gate 60907c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_kstats != NULL) 60917c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 60927c478bd9Sstevel@tonic-gate 60937c478bd9Sstevel@tonic-gate if ((kiosp = kstat_create("mdi", 0, ksname, "iopath", 609437fbbce5Scth KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT)) == NULL) { 60957c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 60967c478bd9Sstevel@tonic-gate } 60977c478bd9Sstevel@tonic-gate 609837fbbce5Scth (void) strcat(ksname, ",err"); 60997c478bd9Sstevel@tonic-gate kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors", 61007c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, 61017c478bd9Sstevel@tonic-gate sizeof (struct pi_errs) / sizeof (kstat_named_t), 0); 61027c478bd9Sstevel@tonic-gate if (kerrsp == NULL) { 61037c478bd9Sstevel@tonic-gate kstat_delete(kiosp); 61047c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 61057c478bd9Sstevel@tonic-gate } 61067c478bd9Sstevel@tonic-gate 61077c478bd9Sstevel@tonic-gate nsp = (struct pi_errs *)kerrsp->ks_data; 61087c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32); 61097c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32); 61107c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_transerrs, "Transport Errors", 61117c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 61127c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy", 61137c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 61147c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors", 61157c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 61167c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources", 61177c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 61187c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors", 61197c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 61207c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State", 61217c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 61227c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedfrom, "Failed From", 61237c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 61247c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32); 61257c478bd9Sstevel@tonic-gate 61267c478bd9Sstevel@tonic-gate mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP); 61277c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_ref = 1; 61287c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_iostats = kiosp; 61297c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_errstats = kerrsp; 61307c478bd9Sstevel@tonic-gate kstat_install(kiosp); 61317c478bd9Sstevel@tonic-gate kstat_install(kerrsp); 61327c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = mdi_statp; 61337c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 61347c478bd9Sstevel@tonic-gate } 61357c478bd9Sstevel@tonic-gate 61367c478bd9Sstevel@tonic-gate /* 61377c478bd9Sstevel@tonic-gate * destroy per-path properties 61387c478bd9Sstevel@tonic-gate */ 61397c478bd9Sstevel@tonic-gate static void 61407c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip) 61417c478bd9Sstevel@tonic-gate { 61427c478bd9Sstevel@tonic-gate 61437c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 61447c478bd9Sstevel@tonic-gate 614537fbbce5Scth if (MDI_PI(pip)->pi_kstats == NULL) 614637fbbce5Scth return; 61477c478bd9Sstevel@tonic-gate if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL) 61487c478bd9Sstevel@tonic-gate return; 61497c478bd9Sstevel@tonic-gate 61507c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 61517c478bd9Sstevel@tonic-gate 61527c478bd9Sstevel@tonic-gate /* 61537c478bd9Sstevel@tonic-gate * the kstat may be shared between multiple pathinfo nodes 61547c478bd9Sstevel@tonic-gate * decrement this pathinfo's usage, removing the kstats 61557c478bd9Sstevel@tonic-gate * themselves when the last pathinfo reference is removed. 61567c478bd9Sstevel@tonic-gate */ 61577c478bd9Sstevel@tonic-gate ASSERT(mdi_statp->pi_kstat_ref > 0); 61587c478bd9Sstevel@tonic-gate if (--mdi_statp->pi_kstat_ref != 0) 61597c478bd9Sstevel@tonic-gate return; 61607c478bd9Sstevel@tonic-gate 61617c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_iostats); 61627c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_errstats); 61637c478bd9Sstevel@tonic-gate kmem_free(mdi_statp, sizeof (*mdi_statp)); 61647c478bd9Sstevel@tonic-gate } 61657c478bd9Sstevel@tonic-gate 61667c478bd9Sstevel@tonic-gate /* 61677c478bd9Sstevel@tonic-gate * update I/O paths KSTATS 61687c478bd9Sstevel@tonic-gate */ 61697c478bd9Sstevel@tonic-gate void 61707c478bd9Sstevel@tonic-gate mdi_pi_kstat_iosupdate(mdi_pathinfo_t *pip, struct buf *bp) 61717c478bd9Sstevel@tonic-gate { 61727c478bd9Sstevel@tonic-gate kstat_t *iostatp; 61737c478bd9Sstevel@tonic-gate size_t xfer_cnt; 61747c478bd9Sstevel@tonic-gate 61757c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 61767c478bd9Sstevel@tonic-gate 61777c478bd9Sstevel@tonic-gate /* 61787c478bd9Sstevel@tonic-gate * I/O can be driven across a path prior to having path 61797c478bd9Sstevel@tonic-gate * statistics available, i.e. probe(9e). 61807c478bd9Sstevel@tonic-gate */ 61817c478bd9Sstevel@tonic-gate if (bp != NULL && MDI_PI(pip)->pi_kstats != NULL) { 61827c478bd9Sstevel@tonic-gate iostatp = MDI_PI(pip)->pi_kstats->pi_kstat_iostats; 61837c478bd9Sstevel@tonic-gate xfer_cnt = bp->b_bcount - bp->b_resid; 61847c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 61857c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->reads++; 61867c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nread += xfer_cnt; 61877c478bd9Sstevel@tonic-gate } else { 61887c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->writes++; 61897c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nwritten += xfer_cnt; 61907c478bd9Sstevel@tonic-gate } 61917c478bd9Sstevel@tonic-gate } 61927c478bd9Sstevel@tonic-gate } 61937c478bd9Sstevel@tonic-gate 61947c478bd9Sstevel@tonic-gate /* 6195ee28b439Scm136836 * Enable the path(specific client/target/initiator) 6196ee28b439Scm136836 * Enabling a path means that MPxIO may select the enabled path for routing 6197ee28b439Scm136836 * future I/O requests, subject to other path state constraints. 6198ee28b439Scm136836 */ 6199ee28b439Scm136836 int 6200ee28b439Scm136836 mdi_pi_enable_path(mdi_pathinfo_t *pip, int flags) 6201ee28b439Scm136836 { 6202ee28b439Scm136836 mdi_phci_t *ph; 6203ee28b439Scm136836 62044c06356bSdh142964 ph = MDI_PI(pip)->pi_phci; 6205ee28b439Scm136836 if (ph == NULL) { 62064c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, mdi_pi_get_phci(pip), 62074c06356bSdh142964 "!failed: path %s %p: NULL ph", 62084c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 6209ee28b439Scm136836 return (MDI_FAILURE); 6210ee28b439Scm136836 } 6211ee28b439Scm136836 6212ee28b439Scm136836 (void) i_mdi_enable_disable_path(pip, ph->ph_vhci, flags, 6213ee28b439Scm136836 MDI_ENABLE_OP); 62144c06356bSdh142964 MDI_DEBUG(5, (MDI_NOTE, ph->ph_dip, 62154c06356bSdh142964 "!returning success pip = %p. ph = %p", 62165e3986cbScth (void *)pip, (void *)ph)); 6217ee28b439Scm136836 return (MDI_SUCCESS); 6218ee28b439Scm136836 6219ee28b439Scm136836 } 6220ee28b439Scm136836 6221ee28b439Scm136836 /* 6222ee28b439Scm136836 * Disable the path (specific client/target/initiator) 6223ee28b439Scm136836 * Disabling a path means that MPxIO will not select the disabled path for 6224ee28b439Scm136836 * routing any new I/O requests. 6225ee28b439Scm136836 */ 6226ee28b439Scm136836 int 6227ee28b439Scm136836 mdi_pi_disable_path(mdi_pathinfo_t *pip, int flags) 6228ee28b439Scm136836 { 6229ee28b439Scm136836 mdi_phci_t *ph; 6230ee28b439Scm136836 62314c06356bSdh142964 ph = MDI_PI(pip)->pi_phci; 6232ee28b439Scm136836 if (ph == NULL) { 62334c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, mdi_pi_get_phci(pip), 62344c06356bSdh142964 "!failed: path %s %p: NULL ph", 62354c06356bSdh142964 mdi_pi_spathname(pip), (void *)pip)); 6236ee28b439Scm136836 return (MDI_FAILURE); 6237ee28b439Scm136836 } 6238ee28b439Scm136836 6239ee28b439Scm136836 (void) i_mdi_enable_disable_path(pip, 6240ee28b439Scm136836 ph->ph_vhci, flags, MDI_DISABLE_OP); 62414c06356bSdh142964 MDI_DEBUG(5, (MDI_NOTE, ph->ph_dip, 62424c06356bSdh142964 "!returning success pip = %p. ph = %p", 62435e3986cbScth (void *)pip, (void *)ph)); 6244ee28b439Scm136836 return (MDI_SUCCESS); 6245ee28b439Scm136836 } 6246ee28b439Scm136836 6247ee28b439Scm136836 /* 62487c478bd9Sstevel@tonic-gate * disable the path to a particular pHCI (pHCI specified in the phci_path 62497c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 62507c478bd9Sstevel@tonic-gate * Disabling a path means that MPxIO will not select the disabled path for 62517c478bd9Sstevel@tonic-gate * routing any new I/O requests. 6252ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 6253ee28b439Scm136836 * mdi_{enable,disable}_path interfaces 62547c478bd9Sstevel@tonic-gate */ 62557c478bd9Sstevel@tonic-gate int 62567c478bd9Sstevel@tonic-gate mdi_pi_disable(dev_info_t *cdip, dev_info_t *pdip, int flags) 62577c478bd9Sstevel@tonic-gate { 62587c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_DISABLE_OP)); 62597c478bd9Sstevel@tonic-gate } 62607c478bd9Sstevel@tonic-gate 62617c478bd9Sstevel@tonic-gate /* 62627c478bd9Sstevel@tonic-gate * Enable the path to a particular pHCI (pHCI specified in the phci_path 62637c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 62647c478bd9Sstevel@tonic-gate * Enabling a path means that MPxIO may select the enabled path for routing 62657c478bd9Sstevel@tonic-gate * future I/O requests, subject to other path state constraints. 6266ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 6267ee28b439Scm136836 * mdi_{enable,disable}_path interfaces 62687c478bd9Sstevel@tonic-gate */ 62697c478bd9Sstevel@tonic-gate 62707c478bd9Sstevel@tonic-gate int 62717c478bd9Sstevel@tonic-gate mdi_pi_enable(dev_info_t *cdip, dev_info_t *pdip, int flags) 62727c478bd9Sstevel@tonic-gate { 62737c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_ENABLE_OP)); 62747c478bd9Sstevel@tonic-gate } 62757c478bd9Sstevel@tonic-gate 6276ee28b439Scm136836 /* 6277ee28b439Scm136836 * Common routine for doing enable/disable. 6278ee28b439Scm136836 */ 6279ee28b439Scm136836 static mdi_pathinfo_t * 6280ee28b439Scm136836 i_mdi_enable_disable_path(mdi_pathinfo_t *pip, mdi_vhci_t *vh, int flags, 6281ee28b439Scm136836 int op) 6282ee28b439Scm136836 { 6283ee28b439Scm136836 int sync_flag = 0; 6284ee28b439Scm136836 int rv; 6285ee28b439Scm136836 mdi_pathinfo_t *next; 6286ee28b439Scm136836 int (*f)() = NULL; 6287ee28b439Scm136836 62886c8e19d4SZach Kissel /* 62896c8e19d4SZach Kissel * Check to make sure the path is not already in the 62906c8e19d4SZach Kissel * requested state. If it is just return the next path 62916c8e19d4SZach Kissel * as we have nothing to do here. 62926c8e19d4SZach Kissel */ 62936c8e19d4SZach Kissel if ((MDI_PI_IS_DISABLE(pip) && op == MDI_DISABLE_OP) || 62946c8e19d4SZach Kissel (!MDI_PI_IS_DISABLE(pip) && op == MDI_ENABLE_OP)) { 62956c8e19d4SZach Kissel MDI_PI_LOCK(pip); 62966c8e19d4SZach Kissel next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 62976c8e19d4SZach Kissel MDI_PI_UNLOCK(pip); 62986c8e19d4SZach Kissel return (next); 62996c8e19d4SZach Kissel } 63006c8e19d4SZach Kissel 6301ee28b439Scm136836 f = vh->vh_ops->vo_pi_state_change; 6302ee28b439Scm136836 6303ee28b439Scm136836 sync_flag = (flags << 8) & 0xf00; 6304ee28b439Scm136836 6305ee28b439Scm136836 /* 6306ee28b439Scm136836 * Do a callback into the mdi consumer to let it 6307ee28b439Scm136836 * know that path is about to get enabled/disabled. 6308ee28b439Scm136836 */ 6309ee28b439Scm136836 if (f != NULL) { 6310ee28b439Scm136836 rv = (*f)(vh->vh_dip, pip, 0, 6311ee28b439Scm136836 MDI_PI_EXT_STATE(pip), 6312ee28b439Scm136836 MDI_EXT_STATE_CHANGE | sync_flag | 6313ee28b439Scm136836 op | MDI_BEFORE_STATE_CHANGE); 6314ee28b439Scm136836 if (rv != MDI_SUCCESS) { 63154c06356bSdh142964 MDI_DEBUG(2, (MDI_WARN, vh->vh_dip, 63164c06356bSdh142964 "vo_pi_state_change: failed rv = %x", rv)); 6317ee28b439Scm136836 } 6318ee28b439Scm136836 } 6319ee28b439Scm136836 MDI_PI_LOCK(pip); 6320ee28b439Scm136836 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 6321ee28b439Scm136836 6322ee28b439Scm136836 switch (flags) { 6323ee28b439Scm136836 case USER_DISABLE: 63245e3986cbScth if (op == MDI_DISABLE_OP) { 6325ee28b439Scm136836 MDI_PI_SET_USER_DISABLE(pip); 63265e3986cbScth } else { 6327ee28b439Scm136836 MDI_PI_SET_USER_ENABLE(pip); 63285e3986cbScth } 6329ee28b439Scm136836 break; 6330ee28b439Scm136836 case DRIVER_DISABLE: 63315e3986cbScth if (op == MDI_DISABLE_OP) { 6332ee28b439Scm136836 MDI_PI_SET_DRV_DISABLE(pip); 63335e3986cbScth } else { 6334ee28b439Scm136836 MDI_PI_SET_DRV_ENABLE(pip); 63355e3986cbScth } 6336ee28b439Scm136836 break; 6337ee28b439Scm136836 case DRIVER_DISABLE_TRANSIENT: 63385e3986cbScth if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) { 6339ee28b439Scm136836 MDI_PI_SET_DRV_DISABLE_TRANS(pip); 63405e3986cbScth } else { 6341ee28b439Scm136836 MDI_PI_SET_DRV_ENABLE_TRANS(pip); 63425e3986cbScth } 6343ee28b439Scm136836 break; 6344ee28b439Scm136836 } 6345ee28b439Scm136836 MDI_PI_UNLOCK(pip); 6346ee28b439Scm136836 /* 6347ee28b439Scm136836 * Do a callback into the mdi consumer to let it 6348ee28b439Scm136836 * know that path is now enabled/disabled. 6349ee28b439Scm136836 */ 6350ee28b439Scm136836 if (f != NULL) { 6351ee28b439Scm136836 rv = (*f)(vh->vh_dip, pip, 0, 6352ee28b439Scm136836 MDI_PI_EXT_STATE(pip), 6353ee28b439Scm136836 MDI_EXT_STATE_CHANGE | sync_flag | 6354ee28b439Scm136836 op | MDI_AFTER_STATE_CHANGE); 6355ee28b439Scm136836 if (rv != MDI_SUCCESS) { 63564c06356bSdh142964 MDI_DEBUG(2, (MDI_WARN, vh->vh_dip, 63574c06356bSdh142964 "vo_pi_state_change failed: rv = %x", rv)); 6358ee28b439Scm136836 } 6359ee28b439Scm136836 } 6360ee28b439Scm136836 return (next); 6361ee28b439Scm136836 } 63627c478bd9Sstevel@tonic-gate 63637c478bd9Sstevel@tonic-gate /* 63647c478bd9Sstevel@tonic-gate * Common routine for doing enable/disable. 6365ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 6366ee28b439Scm136836 * mdi_{enable,disable}_path has been putback 63677c478bd9Sstevel@tonic-gate */ 63687c478bd9Sstevel@tonic-gate int 63697c478bd9Sstevel@tonic-gate i_mdi_pi_enable_disable(dev_info_t *cdip, dev_info_t *pdip, int flags, int op) 63707c478bd9Sstevel@tonic-gate { 63717c478bd9Sstevel@tonic-gate 63727c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 63737c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 63747c478bd9Sstevel@tonic-gate mdi_client_t *ct; 63757c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next, *pip; 63767c478bd9Sstevel@tonic-gate int found_it; 63777c478bd9Sstevel@tonic-gate 63787c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 63794c06356bSdh142964 MDI_DEBUG(5, (MDI_NOTE, cdip ? cdip : pdip, 63804c06356bSdh142964 "!op = %d pdip = %p cdip = %p", op, (void *)pdip, 63815e3986cbScth (void *)cdip)); 63827c478bd9Sstevel@tonic-gate if (ph == NULL) { 63834c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip, 63844c06356bSdh142964 "!failed: operation %d: NULL ph", op)); 63857c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 63867c478bd9Sstevel@tonic-gate } 63877c478bd9Sstevel@tonic-gate 63887c478bd9Sstevel@tonic-gate if ((op != MDI_ENABLE_OP) && (op != MDI_DISABLE_OP)) { 63894c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip, 63904c06356bSdh142964 "!failed: invalid operation %d", op)); 63917c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 63927c478bd9Sstevel@tonic-gate } 63937c478bd9Sstevel@tonic-gate 63947c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 63957c478bd9Sstevel@tonic-gate 63967c478bd9Sstevel@tonic-gate if (cdip == NULL) { 63977c478bd9Sstevel@tonic-gate /* 63987c478bd9Sstevel@tonic-gate * Need to mark the Phci as enabled/disabled. 63997c478bd9Sstevel@tonic-gate */ 64004c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, cdip ? cdip : pdip, 64014c06356bSdh142964 "op %d for the phci", op)); 64027c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 64037c478bd9Sstevel@tonic-gate switch (flags) { 64047c478bd9Sstevel@tonic-gate case USER_DISABLE: 64055e3986cbScth if (op == MDI_DISABLE_OP) { 64067c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_DISABLE(ph); 64075e3986cbScth } else { 64087c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_ENABLE(ph); 64095e3986cbScth } 64107c478bd9Sstevel@tonic-gate break; 64117c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 64125e3986cbScth if (op == MDI_DISABLE_OP) { 64137c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE(ph); 64145e3986cbScth } else { 64157c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE(ph); 64165e3986cbScth } 64177c478bd9Sstevel@tonic-gate break; 64187c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 64195e3986cbScth if (op == MDI_DISABLE_OP) { 64207c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE_TRANSIENT(ph); 64215e3986cbScth } else { 64227c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE_TRANSIENT(ph); 64235e3986cbScth } 64247c478bd9Sstevel@tonic-gate break; 64257c478bd9Sstevel@tonic-gate default: 64267c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 64274c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip, 64284c06356bSdh142964 "!invalid flag argument= %d", flags)); 64297c478bd9Sstevel@tonic-gate } 64307c478bd9Sstevel@tonic-gate 64317c478bd9Sstevel@tonic-gate /* 64327c478bd9Sstevel@tonic-gate * Phci has been disabled. Now try to enable/disable 64337c478bd9Sstevel@tonic-gate * path info's to each client. 64347c478bd9Sstevel@tonic-gate */ 64357c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 64367c478bd9Sstevel@tonic-gate while (pip != NULL) { 6437ee28b439Scm136836 pip = i_mdi_enable_disable_path(pip, vh, flags, op); 64387c478bd9Sstevel@tonic-gate } 64397c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 64407c478bd9Sstevel@tonic-gate } else { 64417c478bd9Sstevel@tonic-gate 64427c478bd9Sstevel@tonic-gate /* 64437c478bd9Sstevel@tonic-gate * Disable a specific client. 64447c478bd9Sstevel@tonic-gate */ 64457c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 64467c478bd9Sstevel@tonic-gate if (ct == NULL) { 64474c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip, 64484c06356bSdh142964 "!failed: operation = %d: NULL ct", op)); 64497c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 64507c478bd9Sstevel@tonic-gate } 64517c478bd9Sstevel@tonic-gate 64527c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 64537c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 64547c478bd9Sstevel@tonic-gate found_it = 0; 64557c478bd9Sstevel@tonic-gate while (pip != NULL) { 64567c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 64577c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 64587c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 64597c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 64607c478bd9Sstevel@tonic-gate found_it = 1; 64617c478bd9Sstevel@tonic-gate break; 64627c478bd9Sstevel@tonic-gate } 64637c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 64647c478bd9Sstevel@tonic-gate pip = next; 64657c478bd9Sstevel@tonic-gate } 64667c478bd9Sstevel@tonic-gate 6467ee28b439Scm136836 64687c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 64697c478bd9Sstevel@tonic-gate if (found_it == 0) { 64704c06356bSdh142964 MDI_DEBUG(1, (MDI_NOTE, cdip ? cdip : pdip, 64714c06356bSdh142964 "!failed. Could not find corresponding pip\n")); 64727c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 64737c478bd9Sstevel@tonic-gate } 6474ee28b439Scm136836 6475ee28b439Scm136836 (void) i_mdi_enable_disable_path(pip, vh, flags, op); 64767c478bd9Sstevel@tonic-gate } 64777c478bd9Sstevel@tonic-gate 64784c06356bSdh142964 MDI_DEBUG(5, (MDI_NOTE, cdip ? cdip : pdip, 64794c06356bSdh142964 "!op %d returning success pdip = %p cdip = %p", 64805e3986cbScth op, (void *)pdip, (void *)cdip)); 64817c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 64827c478bd9Sstevel@tonic-gate } 64837c478bd9Sstevel@tonic-gate 64847c478bd9Sstevel@tonic-gate /* 64857c478bd9Sstevel@tonic-gate * Ensure phci powered up 64867c478bd9Sstevel@tonic-gate */ 64877c478bd9Sstevel@tonic-gate static void 64887c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(mdi_pathinfo_t *pip) 64897c478bd9Sstevel@tonic-gate { 64907c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 64917c478bd9Sstevel@tonic-gate 64927c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 64935e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 64947c478bd9Sstevel@tonic-gate 64957c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 64967c478bd9Sstevel@tonic-gate return; 64977c478bd9Sstevel@tonic-gate } 64987c478bd9Sstevel@tonic-gate 64997c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 65004c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ph_dip, 65014c06356bSdh142964 "%s %p", mdi_pi_spathname(pip), (void *)pip)); 65027c478bd9Sstevel@tonic-gate if (ph_dip == NULL) { 65037c478bd9Sstevel@tonic-gate return; 65047c478bd9Sstevel@tonic-gate } 65057c478bd9Sstevel@tonic-gate 65067c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 65074c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ph_dip, "kidsupcnt was %d", 65087c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 65097c478bd9Sstevel@tonic-gate pm_hold_power(ph_dip); 65104c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ph_dip, "kidsupcnt is %d", 65117c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 65127c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 65137c478bd9Sstevel@tonic-gate 65145e3986cbScth /* If PM_GET_PM_INFO is NULL the pm_hold_power above was a noop */ 65155e3986cbScth if (DEVI(ph_dip)->devi_pm_info) 65167c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 1; 65177c478bd9Sstevel@tonic-gate } 65187c478bd9Sstevel@tonic-gate 65197c478bd9Sstevel@tonic-gate /* 65207c478bd9Sstevel@tonic-gate * Allow phci powered down 65217c478bd9Sstevel@tonic-gate */ 65227c478bd9Sstevel@tonic-gate static void 65237c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(mdi_pathinfo_t *pip) 65247c478bd9Sstevel@tonic-gate { 65257c478bd9Sstevel@tonic-gate dev_info_t *ph_dip = NULL; 65267c478bd9Sstevel@tonic-gate 65277c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 65285e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 65297c478bd9Sstevel@tonic-gate 65307c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 65317c478bd9Sstevel@tonic-gate return; 65327c478bd9Sstevel@tonic-gate } 65337c478bd9Sstevel@tonic-gate 65347c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 65357c478bd9Sstevel@tonic-gate ASSERT(ph_dip != NULL); 65367c478bd9Sstevel@tonic-gate 65374c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ph_dip, 65384c06356bSdh142964 "%s %p", mdi_pi_spathname(pip), (void *)pip)); 65394c06356bSdh142964 65407c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 65414c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ph_dip, 65424c06356bSdh142964 "kidsupcnt was %d", DEVI(ph_dip)->devi_pm_kidsupcnt)); 65437c478bd9Sstevel@tonic-gate pm_rele_power(ph_dip); 65444c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ph_dip, 65454c06356bSdh142964 "kidsupcnt is %d", DEVI(ph_dip)->devi_pm_kidsupcnt)); 65467c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 65474c06356bSdh142964 65487c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 0; 65497c478bd9Sstevel@tonic-gate } 65507c478bd9Sstevel@tonic-gate 65517c478bd9Sstevel@tonic-gate static void 65527c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(mdi_client_t *ct, int incr) 65537c478bd9Sstevel@tonic-gate { 65545e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 65557c478bd9Sstevel@tonic-gate 65567c478bd9Sstevel@tonic-gate ct->ct_power_cnt += incr; 65574c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip, 65584c06356bSdh142964 "%p ct_power_cnt = %d incr = %d", 65594c06356bSdh142964 (void *)ct, ct->ct_power_cnt, incr)); 65607c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 65617c478bd9Sstevel@tonic-gate } 65627c478bd9Sstevel@tonic-gate 65637c478bd9Sstevel@tonic-gate static void 65647c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(mdi_client_t *ct) 65657c478bd9Sstevel@tonic-gate { 65667c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 65677c478bd9Sstevel@tonic-gate 65685e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 65697c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 65707c478bd9Sstevel@tonic-gate while (pip != NULL) { 65717c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 65727c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 65737c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 65747c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 65757c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 65767c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 65777c478bd9Sstevel@tonic-gate } 65787c478bd9Sstevel@tonic-gate } 65797c478bd9Sstevel@tonic-gate 65807c478bd9Sstevel@tonic-gate static void 65817c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(mdi_client_t *ct, int decr) 65827c478bd9Sstevel@tonic-gate { 65835e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 65847c478bd9Sstevel@tonic-gate 6585737d277aScth if (i_ddi_devi_attached(ct->ct_dip)) { 65867c478bd9Sstevel@tonic-gate ct->ct_power_cnt -= decr; 65874c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip, 65884c06356bSdh142964 "%p ct_power_cnt = %d decr = %d", 65895e3986cbScth (void *)ct, ct->ct_power_cnt, decr)); 65907c478bd9Sstevel@tonic-gate } 65917c478bd9Sstevel@tonic-gate 65927c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 65937c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 65947c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 65957c478bd9Sstevel@tonic-gate return; 65967c478bd9Sstevel@tonic-gate } 65977c478bd9Sstevel@tonic-gate } 65987c478bd9Sstevel@tonic-gate 65997c478bd9Sstevel@tonic-gate static void 66007c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(mdi_client_t *ct) 66017c478bd9Sstevel@tonic-gate { 66024c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ct->ct_dip, 66034c06356bSdh142964 "%p ct_power_cnt = %d", (void *)ct, ct->ct_power_cnt)); 66045e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 66057c478bd9Sstevel@tonic-gate ct->ct_power_cnt = 0; 66067c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 660778dc6db2Sllai1 ct->ct_powercnt_config = 0; 660878dc6db2Sllai1 ct->ct_powercnt_unconfig = 0; 66097c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 1; 66107c478bd9Sstevel@tonic-gate } 66117c478bd9Sstevel@tonic-gate 66127c478bd9Sstevel@tonic-gate static int 66137c478bd9Sstevel@tonic-gate i_mdi_power_one_phci(mdi_pathinfo_t *pip) 66147c478bd9Sstevel@tonic-gate { 66157c478bd9Sstevel@tonic-gate int ret; 66167c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 66177c478bd9Sstevel@tonic-gate 66187c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 66197c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 66207c478bd9Sstevel@tonic-gate 66217c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 66227c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 66237c478bd9Sstevel@tonic-gate 66247c478bd9Sstevel@tonic-gate /* bring all components of phci to full power */ 66254c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ph_dip, 66264c06356bSdh142964 "pm_powerup for %s%d %p", ddi_driver_name(ph_dip), 66275e3986cbScth ddi_get_instance(ph_dip), (void *)pip)); 66287c478bd9Sstevel@tonic-gate 66297c478bd9Sstevel@tonic-gate ret = pm_powerup(ph_dip); 66307c478bd9Sstevel@tonic-gate 66317c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 66324c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, ph_dip, 66334c06356bSdh142964 "pm_powerup FAILED for %s%d %p", 663455e592a2SRandall Ralphs ddi_driver_name(ph_dip), ddi_get_instance(ph_dip), 66355e3986cbScth (void *)pip)); 66367c478bd9Sstevel@tonic-gate 66377c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 66387c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 66397c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 66407c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 66417c478bd9Sstevel@tonic-gate } 66427c478bd9Sstevel@tonic-gate 66437c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 66447c478bd9Sstevel@tonic-gate } 66457c478bd9Sstevel@tonic-gate 66467c478bd9Sstevel@tonic-gate static int 66477c478bd9Sstevel@tonic-gate i_mdi_power_all_phci(mdi_client_t *ct) 66487c478bd9Sstevel@tonic-gate { 66497c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 66507c478bd9Sstevel@tonic-gate int succeeded = 0; 66517c478bd9Sstevel@tonic-gate 66525e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 66537c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 66547c478bd9Sstevel@tonic-gate while (pip != NULL) { 66555e3986cbScth /* 66565e3986cbScth * Don't power if MDI_PATHINFO_STATE_FAULT 66575e3986cbScth * or MDI_PATHINFO_STATE_OFFLINE. 66585e3986cbScth */ 66595e3986cbScth if (MDI_PI_IS_INIT(pip) || 66605e3986cbScth MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip)) { 66617c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 66627c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 66637c478bd9Sstevel@tonic-gate if (i_mdi_power_one_phci(pip) == MDI_SUCCESS) 66647c478bd9Sstevel@tonic-gate succeeded = 1; 66657c478bd9Sstevel@tonic-gate 66667c478bd9Sstevel@tonic-gate ASSERT(ct == MDI_PI(pip)->pi_client); 66677c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 66687c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 66695e3986cbScth } 66707c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 66717c478bd9Sstevel@tonic-gate } 66727c478bd9Sstevel@tonic-gate 66737c478bd9Sstevel@tonic-gate return (succeeded ? MDI_SUCCESS : MDI_FAILURE); 66747c478bd9Sstevel@tonic-gate } 66757c478bd9Sstevel@tonic-gate 66767c478bd9Sstevel@tonic-gate /* 66777c478bd9Sstevel@tonic-gate * mdi_bus_power(): 66787c478bd9Sstevel@tonic-gate * 1. Place the phci(s) into powered up state so that 66797c478bd9Sstevel@tonic-gate * client can do power management 66807c478bd9Sstevel@tonic-gate * 2. Ensure phci powered up as client power managing 66817c478bd9Sstevel@tonic-gate * Return Values: 66827c478bd9Sstevel@tonic-gate * MDI_SUCCESS 66837c478bd9Sstevel@tonic-gate * MDI_FAILURE 66847c478bd9Sstevel@tonic-gate */ 66857c478bd9Sstevel@tonic-gate int 66867c478bd9Sstevel@tonic-gate mdi_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op, 66877c478bd9Sstevel@tonic-gate void *arg, void *result) 66887c478bd9Sstevel@tonic-gate { 66897c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 66907c478bd9Sstevel@tonic-gate pm_bp_child_pwrchg_t *bpc; 66917c478bd9Sstevel@tonic-gate mdi_client_t *ct; 66927c478bd9Sstevel@tonic-gate dev_info_t *cdip; 66937c478bd9Sstevel@tonic-gate pm_bp_has_changed_t *bphc; 66947c478bd9Sstevel@tonic-gate 66957c478bd9Sstevel@tonic-gate /* 66967c478bd9Sstevel@tonic-gate * BUS_POWER_NOINVOL not supported 66977c478bd9Sstevel@tonic-gate */ 66987c478bd9Sstevel@tonic-gate if (op == BUS_POWER_NOINVOL) 66997c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 67007c478bd9Sstevel@tonic-gate 67017c478bd9Sstevel@tonic-gate /* 67027c478bd9Sstevel@tonic-gate * ignore other OPs. 67037c478bd9Sstevel@tonic-gate * return quickly to save cou cycles on the ct processing 67047c478bd9Sstevel@tonic-gate */ 67057c478bd9Sstevel@tonic-gate switch (op) { 67067c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 67077c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 67087c478bd9Sstevel@tonic-gate bpc = (pm_bp_child_pwrchg_t *)arg; 67097c478bd9Sstevel@tonic-gate cdip = bpc->bpc_dip; 67107c478bd9Sstevel@tonic-gate break; 67117c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 67127c478bd9Sstevel@tonic-gate bphc = (pm_bp_has_changed_t *)arg; 67137c478bd9Sstevel@tonic-gate cdip = bphc->bphc_dip; 67147c478bd9Sstevel@tonic-gate break; 67157c478bd9Sstevel@tonic-gate default: 67167c478bd9Sstevel@tonic-gate return (pm_busop_bus_power(parent, impl_arg, op, arg, result)); 67177c478bd9Sstevel@tonic-gate } 67187c478bd9Sstevel@tonic-gate 67197c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(cdip)); 67207c478bd9Sstevel@tonic-gate 67217c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 67227c478bd9Sstevel@tonic-gate if (ct == NULL) 67237c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 67247c478bd9Sstevel@tonic-gate 67257c478bd9Sstevel@tonic-gate /* 67267c478bd9Sstevel@tonic-gate * wait till the mdi_pathinfo node state change are processed 67277c478bd9Sstevel@tonic-gate */ 67287c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 67297c478bd9Sstevel@tonic-gate switch (op) { 67307c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 67314c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip, 67327c478bd9Sstevel@tonic-gate "BUS_POWER_PRE_NOTIFICATION:" 67334c06356bSdh142964 "%s@%s, olevel=%d, nlevel=%d, comp=%d", 67344c06356bSdh142964 ddi_node_name(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 67357c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp)); 67367c478bd9Sstevel@tonic-gate 67377c478bd9Sstevel@tonic-gate /* serialize power level change per client */ 67387c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 67397c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 67407c478bd9Sstevel@tonic-gate 67417c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_TRANSITION(ct); 67427c478bd9Sstevel@tonic-gate 67437c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 67447c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 67457c478bd9Sstevel@tonic-gate } 67467c478bd9Sstevel@tonic-gate 67477c478bd9Sstevel@tonic-gate /* 67487c478bd9Sstevel@tonic-gate * if new_level > 0: 67497c478bd9Sstevel@tonic-gate * - hold phci(s) 67507c478bd9Sstevel@tonic-gate * - power up phci(s) if not already 67517c478bd9Sstevel@tonic-gate * ignore power down 67527c478bd9Sstevel@tonic-gate */ 67537c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 67547c478bd9Sstevel@tonic-gate if (!DEVI_IS_ATTACHING(ct->ct_dip)) { 67554c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip, 67564c06356bSdh142964 "i_mdi_pm_hold_client\n")); 67577c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 67587c478bd9Sstevel@tonic-gate } 67597c478bd9Sstevel@tonic-gate } 67607c478bd9Sstevel@tonic-gate break; 67617c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 67624c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip, 67637c478bd9Sstevel@tonic-gate "BUS_POWER_POST_NOTIFICATION:" 67644c06356bSdh142964 "%s@%s, olevel=%d, nlevel=%d, comp=%d result=%d", 67654c06356bSdh142964 ddi_node_name(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 67667c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp, 67677c478bd9Sstevel@tonic-gate *(int *)result)); 67687c478bd9Sstevel@tonic-gate 67697c478bd9Sstevel@tonic-gate if (*(int *)result == DDI_SUCCESS) { 67707c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 67717c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 67727c478bd9Sstevel@tonic-gate } else { 67737c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_DOWN(ct); 67747c478bd9Sstevel@tonic-gate } 67757c478bd9Sstevel@tonic-gate } 67767c478bd9Sstevel@tonic-gate 67777c478bd9Sstevel@tonic-gate /* release the hold we did in pre-notification */ 67787c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0 && (*(int *)result != DDI_SUCCESS) && 67797c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) { 67804c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip, 67814c06356bSdh142964 "i_mdi_pm_rele_client\n")); 67827c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 67837c478bd9Sstevel@tonic-gate } 67847c478bd9Sstevel@tonic-gate 67857c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel == 0 && (*(int *)result == DDI_SUCCESS)) { 67867c478bd9Sstevel@tonic-gate /* another thread might started attaching */ 67877c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 67884c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip, 67894c06356bSdh142964 "i_mdi_pm_rele_client\n")); 67907c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 67917c478bd9Sstevel@tonic-gate /* detaching has been taken care in pm_post_unconfig */ 67927c478bd9Sstevel@tonic-gate } else if (!DEVI_IS_DETACHING(ct->ct_dip)) { 67934c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, bpc->bpc_dip, 67944c06356bSdh142964 "i_mdi_pm_reset_client\n")); 67957c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 67967c478bd9Sstevel@tonic-gate } 67977c478bd9Sstevel@tonic-gate } 67987c478bd9Sstevel@tonic-gate 67997c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_POWER_TRANSITION(ct); 68007c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_powerchange_cv); 68017c478bd9Sstevel@tonic-gate 68027c478bd9Sstevel@tonic-gate break; 68037c478bd9Sstevel@tonic-gate 68047c478bd9Sstevel@tonic-gate /* need to do more */ 68057c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 68064c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, bphc->bphc_dip, 68077c478bd9Sstevel@tonic-gate "BUS_POWER_HAS_CHANGED:" 68084c06356bSdh142964 "%s@%s, olevel=%d, nlevel=%d, comp=%d", 68094c06356bSdh142964 ddi_node_name(bphc->bphc_dip), PM_ADDR(bphc->bphc_dip), 68107c478bd9Sstevel@tonic-gate bphc->bphc_olevel, bphc->bphc_nlevel, bphc->bphc_comp)); 68117c478bd9Sstevel@tonic-gate 68127c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel > 0 && 68137c478bd9Sstevel@tonic-gate bphc->bphc_nlevel > bphc->bphc_olevel) { 68147c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 68157c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 68167c478bd9Sstevel@tonic-gate } 68174c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, bphc->bphc_dip, 68184c06356bSdh142964 "i_mdi_pm_hold_client\n")); 68197c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 68207c478bd9Sstevel@tonic-gate } 68217c478bd9Sstevel@tonic-gate 68227c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel == 0 && bphc->bphc_olevel != -1) { 68234c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, bphc->bphc_dip, 68244c06356bSdh142964 "i_mdi_pm_rele_client\n")); 68257c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 68267c478bd9Sstevel@tonic-gate } 68277c478bd9Sstevel@tonic-gate break; 68287c478bd9Sstevel@tonic-gate } 68297c478bd9Sstevel@tonic-gate 68307c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 68317c478bd9Sstevel@tonic-gate return (ret); 68327c478bd9Sstevel@tonic-gate } 68337c478bd9Sstevel@tonic-gate 68347c478bd9Sstevel@tonic-gate static int 68357c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config_one(dev_info_t *child) 68367c478bd9Sstevel@tonic-gate { 68377c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 68387c478bd9Sstevel@tonic-gate mdi_client_t *ct; 68397c478bd9Sstevel@tonic-gate 68407c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 68417c478bd9Sstevel@tonic-gate if (ct == NULL) 68427c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 68437c478bd9Sstevel@tonic-gate 68447c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 68457c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 68467c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 68477c478bd9Sstevel@tonic-gate 68487c478bd9Sstevel@tonic-gate if (!MDI_CLIENT_IS_FAILED(ct)) { 68497c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 68504c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "already configured\n")); 68517c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 68527c478bd9Sstevel@tonic-gate } 68537c478bd9Sstevel@tonic-gate 685478dc6db2Sllai1 if (ct->ct_powercnt_config) { 68557c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 68564c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "already held\n")); 68577c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 68587c478bd9Sstevel@tonic-gate } 68597c478bd9Sstevel@tonic-gate 68607c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 68617c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 68627c478bd9Sstevel@tonic-gate } 68634c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_hold_client\n")); 68647c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 686578dc6db2Sllai1 ct->ct_powercnt_config = 1; 68667c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 68677c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 68687c478bd9Sstevel@tonic-gate return (ret); 68697c478bd9Sstevel@tonic-gate } 68707c478bd9Sstevel@tonic-gate 68717c478bd9Sstevel@tonic-gate static int 68725e3986cbScth i_mdi_pm_pre_config(dev_info_t *vdip, dev_info_t *child) 68737c478bd9Sstevel@tonic-gate { 68747c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 68757c478bd9Sstevel@tonic-gate dev_info_t *cdip; 68767c478bd9Sstevel@tonic-gate int circ; 68777c478bd9Sstevel@tonic-gate 68785e3986cbScth ASSERT(MDI_VHCI(vdip)); 68797c478bd9Sstevel@tonic-gate 68807c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 68817c478bd9Sstevel@tonic-gate if (child) { 68825e3986cbScth ASSERT(DEVI_BUSY_OWNED(vdip)); 68837c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_config_one(child)); 68847c478bd9Sstevel@tonic-gate } 68857c478bd9Sstevel@tonic-gate 68867c478bd9Sstevel@tonic-gate /* devi_config_common */ 68875e3986cbScth ndi_devi_enter(vdip, &circ); 68885e3986cbScth cdip = ddi_get_child(vdip); 68897c478bd9Sstevel@tonic-gate while (cdip) { 68907c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 68917c478bd9Sstevel@tonic-gate 68927c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config_one(cdip); 68937c478bd9Sstevel@tonic-gate if (ret != MDI_SUCCESS) 68947c478bd9Sstevel@tonic-gate break; 68957c478bd9Sstevel@tonic-gate cdip = next; 68967c478bd9Sstevel@tonic-gate } 68975e3986cbScth ndi_devi_exit(vdip, circ); 68987c478bd9Sstevel@tonic-gate return (ret); 68997c478bd9Sstevel@tonic-gate } 69007c478bd9Sstevel@tonic-gate 69017c478bd9Sstevel@tonic-gate static int 69027c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig_one(dev_info_t *child, int *held, int flags) 69037c478bd9Sstevel@tonic-gate { 69047c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 69057c478bd9Sstevel@tonic-gate mdi_client_t *ct; 69067c478bd9Sstevel@tonic-gate 69077c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 69087c478bd9Sstevel@tonic-gate if (ct == NULL) 69097c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 69107c478bd9Sstevel@tonic-gate 69117c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 69127c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 69137c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 69147c478bd9Sstevel@tonic-gate 6915*1b94a41bSChris Horne if (!i_ddi_devi_attached(child)) { 69164c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "node detached already\n")); 69177c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 69187c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 69197c478bd9Sstevel@tonic-gate } 69207c478bd9Sstevel@tonic-gate 69217c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_POWERED_DOWN(ct) && 69227c478bd9Sstevel@tonic-gate (flags & NDI_AUTODETACH)) { 69234c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "auto-modunload\n")); 69247c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 69257c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 69267c478bd9Sstevel@tonic-gate } 69277c478bd9Sstevel@tonic-gate 692878dc6db2Sllai1 if (ct->ct_powercnt_unconfig) { 69294c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "ct_powercnt_held\n")); 69307c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 69317c478bd9Sstevel@tonic-gate *held = 1; 69327c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 69337c478bd9Sstevel@tonic-gate } 69347c478bd9Sstevel@tonic-gate 69357c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 69367c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 69377c478bd9Sstevel@tonic-gate } 69384c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_hold_client\n")); 69397c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 694078dc6db2Sllai1 ct->ct_powercnt_unconfig = 1; 69417c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 69427c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 69437c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) 69447c478bd9Sstevel@tonic-gate *held = 1; 69457c478bd9Sstevel@tonic-gate return (ret); 69467c478bd9Sstevel@tonic-gate } 69477c478bd9Sstevel@tonic-gate 69487c478bd9Sstevel@tonic-gate static int 69495e3986cbScth i_mdi_pm_pre_unconfig(dev_info_t *vdip, dev_info_t *child, int *held, 69507c478bd9Sstevel@tonic-gate int flags) 69517c478bd9Sstevel@tonic-gate { 69527c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 69537c478bd9Sstevel@tonic-gate dev_info_t *cdip; 69547c478bd9Sstevel@tonic-gate int circ; 69557c478bd9Sstevel@tonic-gate 69565e3986cbScth ASSERT(MDI_VHCI(vdip)); 69577c478bd9Sstevel@tonic-gate *held = 0; 69587c478bd9Sstevel@tonic-gate 69597c478bd9Sstevel@tonic-gate /* ndi_devi_unconfig_one */ 69607c478bd9Sstevel@tonic-gate if (child) { 69615e3986cbScth ASSERT(DEVI_BUSY_OWNED(vdip)); 69627c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_unconfig_one(child, held, flags)); 69637c478bd9Sstevel@tonic-gate } 69647c478bd9Sstevel@tonic-gate 69657c478bd9Sstevel@tonic-gate /* devi_unconfig_common */ 69665e3986cbScth ndi_devi_enter(vdip, &circ); 69675e3986cbScth cdip = ddi_get_child(vdip); 69687c478bd9Sstevel@tonic-gate while (cdip) { 69697c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 69707c478bd9Sstevel@tonic-gate 69717c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig_one(cdip, held, flags); 69727c478bd9Sstevel@tonic-gate cdip = next; 69737c478bd9Sstevel@tonic-gate } 69745e3986cbScth ndi_devi_exit(vdip, circ); 69757c478bd9Sstevel@tonic-gate 69767c478bd9Sstevel@tonic-gate if (*held) 69777c478bd9Sstevel@tonic-gate ret = MDI_SUCCESS; 69787c478bd9Sstevel@tonic-gate 69797c478bd9Sstevel@tonic-gate return (ret); 69807c478bd9Sstevel@tonic-gate } 69817c478bd9Sstevel@tonic-gate 69827c478bd9Sstevel@tonic-gate static void 69837c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(dev_info_t *child) 69847c478bd9Sstevel@tonic-gate { 69857c478bd9Sstevel@tonic-gate mdi_client_t *ct; 69867c478bd9Sstevel@tonic-gate 69877c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 69887c478bd9Sstevel@tonic-gate if (ct == NULL) 69897c478bd9Sstevel@tonic-gate return; 69907c478bd9Sstevel@tonic-gate 69917c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 69927c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 69937c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 69947c478bd9Sstevel@tonic-gate 699578dc6db2Sllai1 if (ct->ct_powercnt_reset || !ct->ct_powercnt_config) { 69964c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "not configured\n")); 69977c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 69987c478bd9Sstevel@tonic-gate return; 69997c478bd9Sstevel@tonic-gate } 70007c478bd9Sstevel@tonic-gate 70017c478bd9Sstevel@tonic-gate /* client has not been updated */ 70027c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 70034c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "client failed\n")); 70047c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 70057c478bd9Sstevel@tonic-gate return; 70067c478bd9Sstevel@tonic-gate } 70077c478bd9Sstevel@tonic-gate 70087c478bd9Sstevel@tonic-gate /* another thread might have powered it down or detached it */ 70097c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 7010*1b94a41bSChris Horne !DEVI_IS_ATTACHING(child)) || 7011*1b94a41bSChris Horne (!i_ddi_devi_attached(child) && 7012*1b94a41bSChris Horne !DEVI_IS_ATTACHING(child))) { 70134c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_reset_client\n")); 70147c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 70157c478bd9Sstevel@tonic-gate } else { 70167c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 70177c478bd9Sstevel@tonic-gate int valid_path_count = 0; 70187c478bd9Sstevel@tonic-gate 70194c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_rele_client\n")); 70207c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 70217c478bd9Sstevel@tonic-gate while (pip != NULL) { 70227c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 70237c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 702478dc6db2Sllai1 if (MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip)) 70257c478bd9Sstevel@tonic-gate valid_path_count ++; 70267c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 70277c478bd9Sstevel@tonic-gate pip = next; 70287c478bd9Sstevel@tonic-gate } 70297c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, valid_path_count); 70307c478bd9Sstevel@tonic-gate } 703178dc6db2Sllai1 ct->ct_powercnt_config = 0; 70327c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 70337c478bd9Sstevel@tonic-gate } 70347c478bd9Sstevel@tonic-gate 70357c478bd9Sstevel@tonic-gate static void 70365e3986cbScth i_mdi_pm_post_config(dev_info_t *vdip, dev_info_t *child) 70377c478bd9Sstevel@tonic-gate { 70387c478bd9Sstevel@tonic-gate int circ; 70397c478bd9Sstevel@tonic-gate dev_info_t *cdip; 70405e3986cbScth 70415e3986cbScth ASSERT(MDI_VHCI(vdip)); 70427c478bd9Sstevel@tonic-gate 70437c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 70447c478bd9Sstevel@tonic-gate if (child) { 70455e3986cbScth ASSERT(DEVI_BUSY_OWNED(vdip)); 70467c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(child); 70477c478bd9Sstevel@tonic-gate return; 70487c478bd9Sstevel@tonic-gate } 70497c478bd9Sstevel@tonic-gate 70507c478bd9Sstevel@tonic-gate /* devi_config_common */ 70515e3986cbScth ndi_devi_enter(vdip, &circ); 70525e3986cbScth cdip = ddi_get_child(vdip); 70537c478bd9Sstevel@tonic-gate while (cdip) { 70547c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 70557c478bd9Sstevel@tonic-gate 70567c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(cdip); 70577c478bd9Sstevel@tonic-gate cdip = next; 70587c478bd9Sstevel@tonic-gate } 70595e3986cbScth ndi_devi_exit(vdip, circ); 70607c478bd9Sstevel@tonic-gate } 70617c478bd9Sstevel@tonic-gate 70627c478bd9Sstevel@tonic-gate static void 70637c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(dev_info_t *child) 70647c478bd9Sstevel@tonic-gate { 70657c478bd9Sstevel@tonic-gate mdi_client_t *ct; 70667c478bd9Sstevel@tonic-gate 70677c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 70687c478bd9Sstevel@tonic-gate if (ct == NULL) 70697c478bd9Sstevel@tonic-gate return; 70707c478bd9Sstevel@tonic-gate 70717c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 70727c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 70737c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 70747c478bd9Sstevel@tonic-gate 707578dc6db2Sllai1 if (!ct->ct_powercnt_unconfig || ct->ct_powercnt_reset) { 70764c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "not held\n")); 70777c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 70787c478bd9Sstevel@tonic-gate return; 70797c478bd9Sstevel@tonic-gate } 70807c478bd9Sstevel@tonic-gate 70817c478bd9Sstevel@tonic-gate /* failure detaching or another thread just attached it */ 70827c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 7083*1b94a41bSChris Horne i_ddi_devi_attached(child)) || 7084*1b94a41bSChris Horne (!i_ddi_devi_attached(child) && 7085*1b94a41bSChris Horne !DEVI_IS_ATTACHING(child))) { 70864c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_reset_client\n")); 70877c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 708878dc6db2Sllai1 } else { 708978dc6db2Sllai1 mdi_pathinfo_t *pip, *next; 709078dc6db2Sllai1 int valid_path_count = 0; 70917c478bd9Sstevel@tonic-gate 70924c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, child, "i_mdi_pm_rele_client\n")); 709378dc6db2Sllai1 pip = ct->ct_path_head; 709478dc6db2Sllai1 while (pip != NULL) { 709578dc6db2Sllai1 MDI_PI_LOCK(pip); 709678dc6db2Sllai1 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 709778dc6db2Sllai1 if (MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip)) 709878dc6db2Sllai1 valid_path_count ++; 709978dc6db2Sllai1 MDI_PI_UNLOCK(pip); 710078dc6db2Sllai1 pip = next; 710178dc6db2Sllai1 } 710278dc6db2Sllai1 i_mdi_pm_rele_client(ct, valid_path_count); 710378dc6db2Sllai1 ct->ct_powercnt_unconfig = 0; 710478dc6db2Sllai1 } 710578dc6db2Sllai1 71067c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 71077c478bd9Sstevel@tonic-gate } 71087c478bd9Sstevel@tonic-gate 71097c478bd9Sstevel@tonic-gate static void 71105e3986cbScth i_mdi_pm_post_unconfig(dev_info_t *vdip, dev_info_t *child, int held) 71117c478bd9Sstevel@tonic-gate { 71127c478bd9Sstevel@tonic-gate int circ; 71137c478bd9Sstevel@tonic-gate dev_info_t *cdip; 71147c478bd9Sstevel@tonic-gate 71155e3986cbScth ASSERT(MDI_VHCI(vdip)); 71167c478bd9Sstevel@tonic-gate 71177c478bd9Sstevel@tonic-gate if (!held) { 71184c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, vdip, "held = %d", held)); 71197c478bd9Sstevel@tonic-gate return; 71207c478bd9Sstevel@tonic-gate } 71217c478bd9Sstevel@tonic-gate 71227c478bd9Sstevel@tonic-gate if (child) { 71235e3986cbScth ASSERT(DEVI_BUSY_OWNED(vdip)); 71247c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(child); 71257c478bd9Sstevel@tonic-gate return; 71267c478bd9Sstevel@tonic-gate } 71277c478bd9Sstevel@tonic-gate 71285e3986cbScth ndi_devi_enter(vdip, &circ); 71295e3986cbScth cdip = ddi_get_child(vdip); 71307c478bd9Sstevel@tonic-gate while (cdip) { 71317c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 71327c478bd9Sstevel@tonic-gate 71337c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(cdip); 71347c478bd9Sstevel@tonic-gate cdip = next; 71357c478bd9Sstevel@tonic-gate } 71365e3986cbScth ndi_devi_exit(vdip, circ); 71377c478bd9Sstevel@tonic-gate } 71387c478bd9Sstevel@tonic-gate 71397c478bd9Sstevel@tonic-gate int 71407c478bd9Sstevel@tonic-gate mdi_power(dev_info_t *vdip, mdi_pm_op_t op, void *args, char *devnm, int flags) 71417c478bd9Sstevel@tonic-gate { 71427c478bd9Sstevel@tonic-gate int circ, ret = MDI_SUCCESS; 71437c478bd9Sstevel@tonic-gate dev_info_t *client_dip = NULL; 71447c478bd9Sstevel@tonic-gate mdi_client_t *ct; 71457c478bd9Sstevel@tonic-gate 71467c478bd9Sstevel@tonic-gate /* 71477c478bd9Sstevel@tonic-gate * Handling ndi_devi_config_one and ndi_devi_unconfig_one. 71487c478bd9Sstevel@tonic-gate * Power up pHCI for the named client device. 71497c478bd9Sstevel@tonic-gate * Note: Before the client is enumerated under vhci by phci, 71507c478bd9Sstevel@tonic-gate * client_dip can be NULL. Then proceed to power up all the 71517c478bd9Sstevel@tonic-gate * pHCIs. 71527c478bd9Sstevel@tonic-gate */ 71537c478bd9Sstevel@tonic-gate if (devnm != NULL) { 71547c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circ); 71557c478bd9Sstevel@tonic-gate client_dip = ndi_devi_findchild(vdip, devnm); 71567c478bd9Sstevel@tonic-gate } 71577c478bd9Sstevel@tonic-gate 71584c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, vdip, 71594c06356bSdh142964 "op = %d %s %p", op, devnm ? devnm : "", (void *)client_dip)); 71607c478bd9Sstevel@tonic-gate 71617c478bd9Sstevel@tonic-gate switch (op) { 71627c478bd9Sstevel@tonic-gate case MDI_PM_PRE_CONFIG: 71637c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config(vdip, client_dip); 7164c73a93f2Sdm120769 break; 71655e3986cbScth 71667c478bd9Sstevel@tonic-gate case MDI_PM_PRE_UNCONFIG: 71677c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig(vdip, client_dip, (int *)args, 71687c478bd9Sstevel@tonic-gate flags); 7169c73a93f2Sdm120769 break; 71705e3986cbScth 71717c478bd9Sstevel@tonic-gate case MDI_PM_POST_CONFIG: 71727c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(vdip, client_dip); 7173c73a93f2Sdm120769 break; 71745e3986cbScth 71757c478bd9Sstevel@tonic-gate case MDI_PM_POST_UNCONFIG: 71767c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(vdip, client_dip, *(int *)args); 7177c73a93f2Sdm120769 break; 71785e3986cbScth 71797c478bd9Sstevel@tonic-gate case MDI_PM_HOLD_POWER: 71807c478bd9Sstevel@tonic-gate case MDI_PM_RELE_POWER: 71817c478bd9Sstevel@tonic-gate ASSERT(args); 71827c478bd9Sstevel@tonic-gate 71837c478bd9Sstevel@tonic-gate client_dip = (dev_info_t *)args; 71847c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(client_dip)); 71857c478bd9Sstevel@tonic-gate 71867c478bd9Sstevel@tonic-gate ct = i_devi_get_client(client_dip); 71877c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 71887c478bd9Sstevel@tonic-gate 71897c478bd9Sstevel@tonic-gate if (op == MDI_PM_HOLD_POWER) { 71907c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 71917c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 71924c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, client_dip, 71934c06356bSdh142964 "i_mdi_pm_hold_client\n")); 71947c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 71957c478bd9Sstevel@tonic-gate } 71967c478bd9Sstevel@tonic-gate } else { 7197*1b94a41bSChris Horne if (DEVI_IS_ATTACHING(client_dip)) { 71984c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, client_dip, 71994c06356bSdh142964 "i_mdi_pm_rele_client\n")); 72007c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 72017c478bd9Sstevel@tonic-gate } else { 72024c06356bSdh142964 MDI_DEBUG(4, (MDI_NOTE, client_dip, 72034c06356bSdh142964 "i_mdi_pm_reset_client\n")); 72047c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 72057c478bd9Sstevel@tonic-gate } 72067c478bd9Sstevel@tonic-gate } 72077c478bd9Sstevel@tonic-gate 72087c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 72097c478bd9Sstevel@tonic-gate break; 72105e3986cbScth 72117c478bd9Sstevel@tonic-gate default: 72127c478bd9Sstevel@tonic-gate break; 72137c478bd9Sstevel@tonic-gate } 72147c478bd9Sstevel@tonic-gate 72155e3986cbScth if (devnm) 72165e3986cbScth ndi_devi_exit(vdip, circ); 72175e3986cbScth 72187c478bd9Sstevel@tonic-gate return (ret); 72197c478bd9Sstevel@tonic-gate } 72207c478bd9Sstevel@tonic-gate 72217c478bd9Sstevel@tonic-gate int 72227c478bd9Sstevel@tonic-gate mdi_component_is_vhci(dev_info_t *dip, const char **mdi_class) 72237c478bd9Sstevel@tonic-gate { 72247c478bd9Sstevel@tonic-gate mdi_vhci_t *vhci; 72257c478bd9Sstevel@tonic-gate 72267c478bd9Sstevel@tonic-gate if (!MDI_VHCI(dip)) 72277c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 72287c478bd9Sstevel@tonic-gate 72297c478bd9Sstevel@tonic-gate if (mdi_class) { 72307c478bd9Sstevel@tonic-gate vhci = DEVI(dip)->devi_mdi_xhci; 72317c478bd9Sstevel@tonic-gate ASSERT(vhci); 72327c478bd9Sstevel@tonic-gate *mdi_class = vhci->vh_class; 72337c478bd9Sstevel@tonic-gate } 72347c478bd9Sstevel@tonic-gate 72357c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 72367c478bd9Sstevel@tonic-gate } 72377c478bd9Sstevel@tonic-gate 72387c478bd9Sstevel@tonic-gate int 72397c478bd9Sstevel@tonic-gate mdi_component_is_phci(dev_info_t *dip, const char **mdi_class) 72407c478bd9Sstevel@tonic-gate { 72417c478bd9Sstevel@tonic-gate mdi_phci_t *phci; 72427c478bd9Sstevel@tonic-gate 72437c478bd9Sstevel@tonic-gate if (!MDI_PHCI(dip)) 72447c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 72457c478bd9Sstevel@tonic-gate 72467c478bd9Sstevel@tonic-gate if (mdi_class) { 72477c478bd9Sstevel@tonic-gate phci = DEVI(dip)->devi_mdi_xhci; 72487c478bd9Sstevel@tonic-gate ASSERT(phci); 72497c478bd9Sstevel@tonic-gate *mdi_class = phci->ph_vhci->vh_class; 72507c478bd9Sstevel@tonic-gate } 72517c478bd9Sstevel@tonic-gate 72527c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 72537c478bd9Sstevel@tonic-gate } 72547c478bd9Sstevel@tonic-gate 72557c478bd9Sstevel@tonic-gate int 72567c478bd9Sstevel@tonic-gate mdi_component_is_client(dev_info_t *dip, const char **mdi_class) 72577c478bd9Sstevel@tonic-gate { 72587c478bd9Sstevel@tonic-gate mdi_client_t *client; 72597c478bd9Sstevel@tonic-gate 72607c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(dip)) 72617c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 72627c478bd9Sstevel@tonic-gate 72637c478bd9Sstevel@tonic-gate if (mdi_class) { 72647c478bd9Sstevel@tonic-gate client = DEVI(dip)->devi_mdi_client; 72657c478bd9Sstevel@tonic-gate ASSERT(client); 72667c478bd9Sstevel@tonic-gate *mdi_class = client->ct_vhci->vh_class; 72677c478bd9Sstevel@tonic-gate } 72687c478bd9Sstevel@tonic-gate 72697c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 72707c478bd9Sstevel@tonic-gate } 72717c478bd9Sstevel@tonic-gate 72727c478bd9Sstevel@tonic-gate void * 72737c478bd9Sstevel@tonic-gate mdi_client_get_vhci_private(dev_info_t *dip) 72747c478bd9Sstevel@tonic-gate { 72757c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 72767c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 72777c478bd9Sstevel@tonic-gate mdi_client_t *ct; 72787c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 72797c478bd9Sstevel@tonic-gate return (ct->ct_vprivate); 72807c478bd9Sstevel@tonic-gate } 72817c478bd9Sstevel@tonic-gate return (NULL); 72827c478bd9Sstevel@tonic-gate } 72837c478bd9Sstevel@tonic-gate 72847c478bd9Sstevel@tonic-gate void 72857c478bd9Sstevel@tonic-gate mdi_client_set_vhci_private(dev_info_t *dip, void *data) 72867c478bd9Sstevel@tonic-gate { 72877c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 72887c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 72897c478bd9Sstevel@tonic-gate mdi_client_t *ct; 72907c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 72917c478bd9Sstevel@tonic-gate ct->ct_vprivate = data; 72927c478bd9Sstevel@tonic-gate } 72937c478bd9Sstevel@tonic-gate } 72947c478bd9Sstevel@tonic-gate /* 72957c478bd9Sstevel@tonic-gate * mdi_pi_get_vhci_private(): 72967c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 72977c478bd9Sstevel@tonic-gate * mdi_pathinfo node 72987c478bd9Sstevel@tonic-gate */ 72997c478bd9Sstevel@tonic-gate void * 73007c478bd9Sstevel@tonic-gate mdi_pi_get_vhci_private(mdi_pathinfo_t *pip) 73017c478bd9Sstevel@tonic-gate { 73027c478bd9Sstevel@tonic-gate caddr_t vprivate = NULL; 73037c478bd9Sstevel@tonic-gate if (pip) { 73047c478bd9Sstevel@tonic-gate vprivate = MDI_PI(pip)->pi_vprivate; 73057c478bd9Sstevel@tonic-gate } 73067c478bd9Sstevel@tonic-gate return (vprivate); 73077c478bd9Sstevel@tonic-gate } 73087c478bd9Sstevel@tonic-gate 73097c478bd9Sstevel@tonic-gate /* 73107c478bd9Sstevel@tonic-gate * mdi_pi_set_vhci_private(): 73117c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_pathinfo node 73127c478bd9Sstevel@tonic-gate */ 73137c478bd9Sstevel@tonic-gate void 73147c478bd9Sstevel@tonic-gate mdi_pi_set_vhci_private(mdi_pathinfo_t *pip, void *priv) 73157c478bd9Sstevel@tonic-gate { 73167c478bd9Sstevel@tonic-gate if (pip) { 73177c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = priv; 73187c478bd9Sstevel@tonic-gate } 73197c478bd9Sstevel@tonic-gate } 73207c478bd9Sstevel@tonic-gate 73217c478bd9Sstevel@tonic-gate /* 73227c478bd9Sstevel@tonic-gate * mdi_phci_get_vhci_private(): 73237c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 73247c478bd9Sstevel@tonic-gate * mdi_phci node 73257c478bd9Sstevel@tonic-gate */ 73267c478bd9Sstevel@tonic-gate void * 73277c478bd9Sstevel@tonic-gate mdi_phci_get_vhci_private(dev_info_t *dip) 73287c478bd9Sstevel@tonic-gate { 73297c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 73307c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 73317c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 73327c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 73337c478bd9Sstevel@tonic-gate return (ph->ph_vprivate); 73347c478bd9Sstevel@tonic-gate } 73357c478bd9Sstevel@tonic-gate return (NULL); 73367c478bd9Sstevel@tonic-gate } 73377c478bd9Sstevel@tonic-gate 73387c478bd9Sstevel@tonic-gate /* 73397c478bd9Sstevel@tonic-gate * mdi_phci_set_vhci_private(): 73407c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_phci node 73417c478bd9Sstevel@tonic-gate */ 73427c478bd9Sstevel@tonic-gate void 73437c478bd9Sstevel@tonic-gate mdi_phci_set_vhci_private(dev_info_t *dip, void *priv) 73447c478bd9Sstevel@tonic-gate { 73457c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 73467c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 73477c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 73487c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 73497c478bd9Sstevel@tonic-gate ph->ph_vprivate = priv; 73507c478bd9Sstevel@tonic-gate } 73517c478bd9Sstevel@tonic-gate } 73523c34adc5Sramat 73534c06356bSdh142964 int 73544c06356bSdh142964 mdi_pi_ishidden(mdi_pathinfo_t *pip) 73554c06356bSdh142964 { 73564c06356bSdh142964 return (MDI_PI_FLAGS_IS_HIDDEN(pip)); 73574c06356bSdh142964 } 73584c06356bSdh142964 73594c06356bSdh142964 int 73604c06356bSdh142964 mdi_pi_device_isremoved(mdi_pathinfo_t *pip) 73614c06356bSdh142964 { 73624c06356bSdh142964 return (MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip)); 73634c06356bSdh142964 } 73644c06356bSdh142964 7365328d222bSChris Horne /* Return 1 if all client paths are device_removed */ 7366328d222bSChris Horne static int 7367328d222bSChris Horne i_mdi_client_all_devices_removed(mdi_client_t *ct) 7368328d222bSChris Horne { 7369328d222bSChris Horne mdi_pathinfo_t *pip; 7370328d222bSChris Horne int all_devices_removed = 1; 7371328d222bSChris Horne 7372328d222bSChris Horne MDI_CLIENT_LOCK(ct); 7373328d222bSChris Horne for (pip = ct->ct_path_head; pip; 7374328d222bSChris Horne pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link) { 7375328d222bSChris Horne if (!mdi_pi_device_isremoved(pip)) { 7376328d222bSChris Horne all_devices_removed = 0; 7377328d222bSChris Horne break; 7378328d222bSChris Horne } 7379328d222bSChris Horne } 7380328d222bSChris Horne MDI_CLIENT_UNLOCK(ct); 7381328d222bSChris Horne return (all_devices_removed); 7382328d222bSChris Horne } 7383328d222bSChris Horne 73844c06356bSdh142964 /* 7385328d222bSChris Horne * When processing path hotunplug, represent device removal. 73864c06356bSdh142964 */ 73874c06356bSdh142964 int 73884c06356bSdh142964 mdi_pi_device_remove(mdi_pathinfo_t *pip) 73894c06356bSdh142964 { 7390328d222bSChris Horne mdi_client_t *ct; 7391328d222bSChris Horne 73924c06356bSdh142964 MDI_PI_LOCK(pip); 73934c06356bSdh142964 if (mdi_pi_device_isremoved(pip)) { 73944c06356bSdh142964 MDI_PI_UNLOCK(pip); 73954c06356bSdh142964 return (0); 73964c06356bSdh142964 } 73974c06356bSdh142964 MDI_PI_FLAGS_SET_DEVICE_REMOVED(pip); 73984c06356bSdh142964 MDI_PI_FLAGS_SET_HIDDEN(pip); 73994c06356bSdh142964 MDI_PI_UNLOCK(pip); 74004c06356bSdh142964 7401328d222bSChris Horne /* 7402328d222bSChris Horne * If all paths associated with the client are now DEVICE_REMOVED, 7403328d222bSChris Horne * reflect DEVICE_REMOVED in the client. 7404328d222bSChris Horne */ 7405328d222bSChris Horne ct = MDI_PI(pip)->pi_client; 7406328d222bSChris Horne if (ct && ct->ct_dip && i_mdi_client_all_devices_removed(ct)) 7407328d222bSChris Horne (void) ndi_devi_device_remove(ct->ct_dip); 7408328d222bSChris Horne else 74094c06356bSdh142964 i_ddi_di_cache_invalidate(); 74104c06356bSdh142964 74114c06356bSdh142964 return (1); 74124c06356bSdh142964 } 74134c06356bSdh142964 74144c06356bSdh142964 /* 74154c06356bSdh142964 * When processing hotplug, if a path marked mdi_pi_device_isremoved() 74164c06356bSdh142964 * is now accessible then this interfaces is used to represent device insertion. 74174c06356bSdh142964 */ 74184c06356bSdh142964 int 74194c06356bSdh142964 mdi_pi_device_insert(mdi_pathinfo_t *pip) 74204c06356bSdh142964 { 74214c06356bSdh142964 MDI_PI_LOCK(pip); 74224c06356bSdh142964 if (!mdi_pi_device_isremoved(pip)) { 74234c06356bSdh142964 MDI_PI_UNLOCK(pip); 74244c06356bSdh142964 return (0); 74254c06356bSdh142964 } 74264c06356bSdh142964 MDI_PI_FLAGS_CLR_DEVICE_REMOVED(pip); 74274c06356bSdh142964 MDI_PI_FLAGS_CLR_HIDDEN(pip); 74284c06356bSdh142964 MDI_PI_UNLOCK(pip); 74294c06356bSdh142964 74304c06356bSdh142964 i_ddi_di_cache_invalidate(); 74314c06356bSdh142964 74324c06356bSdh142964 return (1); 74334c06356bSdh142964 } 74344c06356bSdh142964 74353c34adc5Sramat /* 74363c34adc5Sramat * List of vhci class names: 74373c34adc5Sramat * A vhci class name must be in this list only if the corresponding vhci 74383c34adc5Sramat * driver intends to use the mdi provided bus config implementation 74393c34adc5Sramat * (i.e., mdi_vhci_bus_config()). 74403c34adc5Sramat */ 74413c34adc5Sramat static char *vhci_class_list[] = { MDI_HCI_CLASS_SCSI, MDI_HCI_CLASS_IB }; 74423c34adc5Sramat #define N_VHCI_CLASSES (sizeof (vhci_class_list) / sizeof (char *)) 74433c34adc5Sramat 74443c34adc5Sramat /* 74453c34adc5Sramat * During boot time, the on-disk vhci cache for every vhci class is read 74463c34adc5Sramat * in the form of an nvlist and stored here. 74473c34adc5Sramat */ 74483c34adc5Sramat static nvlist_t *vhcache_nvl[N_VHCI_CLASSES]; 74493c34adc5Sramat 74503c34adc5Sramat /* nvpair names in vhci cache nvlist */ 74513c34adc5Sramat #define MDI_VHCI_CACHE_VERSION 1 74523c34adc5Sramat #define MDI_NVPNAME_VERSION "version" 74533c34adc5Sramat #define MDI_NVPNAME_PHCIS "phcis" 74543c34adc5Sramat #define MDI_NVPNAME_CTADDRMAP "clientaddrmap" 74553c34adc5Sramat 74563c34adc5Sramat /* 74573c34adc5Sramat * Given vhci class name, return its on-disk vhci cache filename. 74583c34adc5Sramat * Memory for the returned filename which includes the full path is allocated 74593c34adc5Sramat * by this function. 74603c34adc5Sramat */ 74613c34adc5Sramat static char * 74623c34adc5Sramat vhclass2vhcache_filename(char *vhclass) 74633c34adc5Sramat { 74643c34adc5Sramat char *filename; 74653c34adc5Sramat int len; 74663c34adc5Sramat static char *fmt = "/etc/devices/mdi_%s_cache"; 74673c34adc5Sramat 74683c34adc5Sramat /* 74693c34adc5Sramat * fmt contains the on-disk vhci cache file name format; 74703c34adc5Sramat * for scsi_vhci the filename is "/etc/devices/mdi_scsi_vhci_cache". 74713c34adc5Sramat */ 74723c34adc5Sramat 74733c34adc5Sramat /* the -1 below is to account for "%s" in the format string */ 74743c34adc5Sramat len = strlen(fmt) + strlen(vhclass) - 1; 74753c34adc5Sramat filename = kmem_alloc(len, KM_SLEEP); 74763c34adc5Sramat (void) snprintf(filename, len, fmt, vhclass); 74773c34adc5Sramat ASSERT(len == (strlen(filename) + 1)); 74783c34adc5Sramat return (filename); 74793c34adc5Sramat } 74803c34adc5Sramat 74813c34adc5Sramat /* 74823c34adc5Sramat * initialize the vhci cache related data structures and read the on-disk 74833c34adc5Sramat * vhci cached data into memory. 74843c34adc5Sramat */ 74853c34adc5Sramat static void 74863c34adc5Sramat setup_vhci_cache(mdi_vhci_t *vh) 74873c34adc5Sramat { 74883c34adc5Sramat mdi_vhci_config_t *vhc; 74893c34adc5Sramat mdi_vhci_cache_t *vhcache; 74903c34adc5Sramat int i; 74913c34adc5Sramat nvlist_t *nvl = NULL; 74923c34adc5Sramat 74933c34adc5Sramat vhc = kmem_zalloc(sizeof (mdi_vhci_config_t), KM_SLEEP); 74943c34adc5Sramat vh->vh_config = vhc; 74953c34adc5Sramat vhcache = &vhc->vhc_vhcache; 74963c34adc5Sramat 74973c34adc5Sramat vhc->vhc_vhcache_filename = vhclass2vhcache_filename(vh->vh_class); 74983c34adc5Sramat 74993c34adc5Sramat mutex_init(&vhc->vhc_lock, NULL, MUTEX_DEFAULT, NULL); 75003c34adc5Sramat cv_init(&vhc->vhc_cv, NULL, CV_DRIVER, NULL); 75013c34adc5Sramat 75023c34adc5Sramat rw_init(&vhcache->vhcache_lock, NULL, RW_DRIVER, NULL); 75033c34adc5Sramat 75043c34adc5Sramat /* 75053c34adc5Sramat * Create string hash; same as mod_hash_create_strhash() except that 75063c34adc5Sramat * we use NULL key destructor. 75073c34adc5Sramat */ 75083c34adc5Sramat vhcache->vhcache_client_hash = mod_hash_create_extended(vh->vh_class, 75093c34adc5Sramat mdi_bus_config_cache_hash_size, 75103c34adc5Sramat mod_hash_null_keydtor, mod_hash_null_valdtor, 75113c34adc5Sramat mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 75123c34adc5Sramat 75133c34adc5Sramat /* 75143c34adc5Sramat * The on-disk vhci cache is read during booting prior to the 75153c34adc5Sramat * lights-out period by mdi_read_devices_files(). 75163c34adc5Sramat */ 75173c34adc5Sramat for (i = 0; i < N_VHCI_CLASSES; i++) { 75183c34adc5Sramat if (strcmp(vhci_class_list[i], vh->vh_class) == 0) { 75193c34adc5Sramat nvl = vhcache_nvl[i]; 75203c34adc5Sramat vhcache_nvl[i] = NULL; 75213c34adc5Sramat break; 75223c34adc5Sramat } 75233c34adc5Sramat } 75243c34adc5Sramat 75253c34adc5Sramat /* 75263c34adc5Sramat * this is to cover the case of some one manually causing unloading 75273c34adc5Sramat * (or detaching) and reloading (or attaching) of a vhci driver. 75283c34adc5Sramat */ 75293c34adc5Sramat if (nvl == NULL && modrootloaded) 75303c34adc5Sramat nvl = read_on_disk_vhci_cache(vh->vh_class); 75313c34adc5Sramat 75323c34adc5Sramat if (nvl != NULL) { 75333c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 75343c34adc5Sramat if (mainnvl_to_vhcache(vhcache, nvl) == MDI_SUCCESS) 75353c34adc5Sramat vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE; 75363c34adc5Sramat else { 75373c34adc5Sramat cmn_err(CE_WARN, 75384c06356bSdh142964 "%s: data file corrupted, will recreate", 75393c34adc5Sramat vhc->vhc_vhcache_filename); 75403c34adc5Sramat } 75413c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 75423c34adc5Sramat nvlist_free(nvl); 75433c34adc5Sramat } 75443c34adc5Sramat 75453c34adc5Sramat vhc->vhc_cbid = callb_add(stop_vhcache_flush_thread, vhc, 75463c34adc5Sramat CB_CL_UADMIN_PRE_VFS, "mdi_vhcache_flush"); 754767e56d35Sramat 754867e56d35Sramat vhc->vhc_path_discovery_boot = mdi_path_discovery_boot; 754967e56d35Sramat vhc->vhc_path_discovery_postboot = mdi_path_discovery_postboot; 75503c34adc5Sramat } 75513c34adc5Sramat 75523c34adc5Sramat /* 75533c34adc5Sramat * free all vhci cache related resources 75543c34adc5Sramat */ 75553c34adc5Sramat static int 75563c34adc5Sramat destroy_vhci_cache(mdi_vhci_t *vh) 75573c34adc5Sramat { 75583c34adc5Sramat mdi_vhci_config_t *vhc = vh->vh_config; 75593c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 75603c34adc5Sramat mdi_vhcache_phci_t *cphci, *cphci_next; 75613c34adc5Sramat mdi_vhcache_client_t *cct, *cct_next; 75623c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_next; 75633c34adc5Sramat 75643c34adc5Sramat if (stop_vhcache_async_threads(vhc) != MDI_SUCCESS) 75653c34adc5Sramat return (MDI_FAILURE); 75663c34adc5Sramat 75673c34adc5Sramat kmem_free(vhc->vhc_vhcache_filename, 75683c34adc5Sramat strlen(vhc->vhc_vhcache_filename) + 1); 75693c34adc5Sramat 75703c34adc5Sramat mod_hash_destroy_strhash(vhcache->vhcache_client_hash); 75713c34adc5Sramat 75723c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 75733c34adc5Sramat cphci = cphci_next) { 75743c34adc5Sramat cphci_next = cphci->cphci_next; 75753c34adc5Sramat free_vhcache_phci(cphci); 75763c34adc5Sramat } 75773c34adc5Sramat 75783c34adc5Sramat for (cct = vhcache->vhcache_client_head; cct != NULL; cct = cct_next) { 75793c34adc5Sramat cct_next = cct->cct_next; 75803c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi_next) { 75813c34adc5Sramat cpi_next = cpi->cpi_next; 75823c34adc5Sramat free_vhcache_pathinfo(cpi); 75833c34adc5Sramat } 75843c34adc5Sramat free_vhcache_client(cct); 75853c34adc5Sramat } 75863c34adc5Sramat 75873c34adc5Sramat rw_destroy(&vhcache->vhcache_lock); 75883c34adc5Sramat 75893c34adc5Sramat mutex_destroy(&vhc->vhc_lock); 75903c34adc5Sramat cv_destroy(&vhc->vhc_cv); 75913c34adc5Sramat kmem_free(vhc, sizeof (mdi_vhci_config_t)); 75923c34adc5Sramat return (MDI_SUCCESS); 75933c34adc5Sramat } 75943c34adc5Sramat 75953c34adc5Sramat /* 75963c34adc5Sramat * Stop all vhci cache related async threads and free their resources. 75973c34adc5Sramat */ 75983c34adc5Sramat static int 75993c34adc5Sramat stop_vhcache_async_threads(mdi_vhci_config_t *vhc) 76003c34adc5Sramat { 76013c34adc5Sramat mdi_async_client_config_t *acc, *acc_next; 76023c34adc5Sramat 76033c34adc5Sramat mutex_enter(&vhc->vhc_lock); 76043c34adc5Sramat vhc->vhc_flags |= MDI_VHC_EXIT; 76053c34adc5Sramat ASSERT(vhc->vhc_acc_thrcount >= 0); 76063c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 76073c34adc5Sramat 76083c34adc5Sramat while ((vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) || 76093c34adc5Sramat vhc->vhc_acc_thrcount != 0) { 76103c34adc5Sramat mutex_exit(&vhc->vhc_lock); 761196c4a178SChris Horne delay_random(mdi_delay); 76123c34adc5Sramat mutex_enter(&vhc->vhc_lock); 76133c34adc5Sramat } 76143c34adc5Sramat 76153c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_EXIT; 76163c34adc5Sramat 76173c34adc5Sramat for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc_next) { 76183c34adc5Sramat acc_next = acc->acc_next; 76193c34adc5Sramat free_async_client_config(acc); 76203c34adc5Sramat } 76213c34adc5Sramat vhc->vhc_acc_list_head = NULL; 76223c34adc5Sramat vhc->vhc_acc_list_tail = NULL; 76233c34adc5Sramat vhc->vhc_acc_count = 0; 76243c34adc5Sramat 76253c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) { 76263c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 76273c34adc5Sramat mutex_exit(&vhc->vhc_lock); 76283c34adc5Sramat if (flush_vhcache(vhc, 0) != MDI_SUCCESS) { 76293c34adc5Sramat vhcache_dirty(vhc); 76303c34adc5Sramat return (MDI_FAILURE); 76313c34adc5Sramat } 76323c34adc5Sramat } else 76333c34adc5Sramat mutex_exit(&vhc->vhc_lock); 76343c34adc5Sramat 76353c34adc5Sramat if (callb_delete(vhc->vhc_cbid) != 0) 76363c34adc5Sramat return (MDI_FAILURE); 76373c34adc5Sramat 76383c34adc5Sramat return (MDI_SUCCESS); 76393c34adc5Sramat } 76403c34adc5Sramat 76413c34adc5Sramat /* 76423c34adc5Sramat * Stop vhci cache flush thread 76433c34adc5Sramat */ 76443c34adc5Sramat /* ARGSUSED */ 76453c34adc5Sramat static boolean_t 76463c34adc5Sramat stop_vhcache_flush_thread(void *arg, int code) 76473c34adc5Sramat { 76483c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 76493c34adc5Sramat 76503c34adc5Sramat mutex_enter(&vhc->vhc_lock); 76513c34adc5Sramat vhc->vhc_flags |= MDI_VHC_EXIT; 76523c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 76533c34adc5Sramat 76543c34adc5Sramat while (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) { 76553c34adc5Sramat mutex_exit(&vhc->vhc_lock); 765696c4a178SChris Horne delay_random(mdi_delay); 76573c34adc5Sramat mutex_enter(&vhc->vhc_lock); 76583c34adc5Sramat } 76593c34adc5Sramat 76603c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) { 76613c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 76623c34adc5Sramat mutex_exit(&vhc->vhc_lock); 76633c34adc5Sramat (void) flush_vhcache(vhc, 1); 76643c34adc5Sramat } else 76653c34adc5Sramat mutex_exit(&vhc->vhc_lock); 76663c34adc5Sramat 76673c34adc5Sramat return (B_TRUE); 76683c34adc5Sramat } 76693c34adc5Sramat 76703c34adc5Sramat /* 76713c34adc5Sramat * Enqueue the vhcache phci (cphci) at the tail of the list 76723c34adc5Sramat */ 76733c34adc5Sramat static void 76743c34adc5Sramat enqueue_vhcache_phci(mdi_vhci_cache_t *vhcache, mdi_vhcache_phci_t *cphci) 76753c34adc5Sramat { 76763c34adc5Sramat cphci->cphci_next = NULL; 76773c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) 76783c34adc5Sramat vhcache->vhcache_phci_head = cphci; 76793c34adc5Sramat else 76803c34adc5Sramat vhcache->vhcache_phci_tail->cphci_next = cphci; 76813c34adc5Sramat vhcache->vhcache_phci_tail = cphci; 76823c34adc5Sramat } 76833c34adc5Sramat 76843c34adc5Sramat /* 76853c34adc5Sramat * Enqueue the vhcache pathinfo (cpi) at the tail of the list 76863c34adc5Sramat */ 76873c34adc5Sramat static void 76883c34adc5Sramat enqueue_tail_vhcache_pathinfo(mdi_vhcache_client_t *cct, 76893c34adc5Sramat mdi_vhcache_pathinfo_t *cpi) 76903c34adc5Sramat { 76913c34adc5Sramat cpi->cpi_next = NULL; 76923c34adc5Sramat if (cct->cct_cpi_head == NULL) 76933c34adc5Sramat cct->cct_cpi_head = cpi; 76943c34adc5Sramat else 76953c34adc5Sramat cct->cct_cpi_tail->cpi_next = cpi; 76963c34adc5Sramat cct->cct_cpi_tail = cpi; 76973c34adc5Sramat } 76983c34adc5Sramat 76993c34adc5Sramat /* 77003c34adc5Sramat * Enqueue the vhcache pathinfo (cpi) at the correct location in the 77013c34adc5Sramat * ordered list. All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST 77023c34adc5Sramat * flag set come at the beginning of the list. All cpis which have this 77033c34adc5Sramat * flag set come at the end of the list. 77043c34adc5Sramat */ 77053c34adc5Sramat static void 77063c34adc5Sramat enqueue_vhcache_pathinfo(mdi_vhcache_client_t *cct, 77073c34adc5Sramat mdi_vhcache_pathinfo_t *newcpi) 77083c34adc5Sramat { 77093c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *prev_cpi; 77103c34adc5Sramat 77113c34adc5Sramat if (cct->cct_cpi_head == NULL || 77123c34adc5Sramat (newcpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST)) 77133c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, newcpi); 77143c34adc5Sramat else { 77153c34adc5Sramat for (cpi = cct->cct_cpi_head, prev_cpi = NULL; cpi != NULL && 77163c34adc5Sramat !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST); 77173c34adc5Sramat prev_cpi = cpi, cpi = cpi->cpi_next) 77183c34adc5Sramat ; 77193c34adc5Sramat 77203c34adc5Sramat if (prev_cpi == NULL) 77213c34adc5Sramat cct->cct_cpi_head = newcpi; 77223c34adc5Sramat else 77233c34adc5Sramat prev_cpi->cpi_next = newcpi; 77243c34adc5Sramat 77253c34adc5Sramat newcpi->cpi_next = cpi; 77263c34adc5Sramat 77273c34adc5Sramat if (cpi == NULL) 77283c34adc5Sramat cct->cct_cpi_tail = newcpi; 77293c34adc5Sramat } 77303c34adc5Sramat } 77313c34adc5Sramat 77323c34adc5Sramat /* 77333c34adc5Sramat * Enqueue the vhcache client (cct) at the tail of the list 77343c34adc5Sramat */ 77353c34adc5Sramat static void 77363c34adc5Sramat enqueue_vhcache_client(mdi_vhci_cache_t *vhcache, 77373c34adc5Sramat mdi_vhcache_client_t *cct) 77383c34adc5Sramat { 77393c34adc5Sramat cct->cct_next = NULL; 77403c34adc5Sramat if (vhcache->vhcache_client_head == NULL) 77413c34adc5Sramat vhcache->vhcache_client_head = cct; 77423c34adc5Sramat else 77433c34adc5Sramat vhcache->vhcache_client_tail->cct_next = cct; 77443c34adc5Sramat vhcache->vhcache_client_tail = cct; 77453c34adc5Sramat } 77463c34adc5Sramat 77473c34adc5Sramat static void 77483c34adc5Sramat free_string_array(char **str, int nelem) 77493c34adc5Sramat { 77503c34adc5Sramat int i; 77513c34adc5Sramat 77523c34adc5Sramat if (str) { 77533c34adc5Sramat for (i = 0; i < nelem; i++) { 77543c34adc5Sramat if (str[i]) 77553c34adc5Sramat kmem_free(str[i], strlen(str[i]) + 1); 77563c34adc5Sramat } 77573c34adc5Sramat kmem_free(str, sizeof (char *) * nelem); 77583c34adc5Sramat } 77593c34adc5Sramat } 77603c34adc5Sramat 77613c34adc5Sramat static void 77623c34adc5Sramat free_vhcache_phci(mdi_vhcache_phci_t *cphci) 77633c34adc5Sramat { 77643c34adc5Sramat kmem_free(cphci->cphci_path, strlen(cphci->cphci_path) + 1); 77653c34adc5Sramat kmem_free(cphci, sizeof (*cphci)); 77663c34adc5Sramat } 77673c34adc5Sramat 77683c34adc5Sramat static void 77693c34adc5Sramat free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *cpi) 77703c34adc5Sramat { 77713c34adc5Sramat kmem_free(cpi->cpi_addr, strlen(cpi->cpi_addr) + 1); 77723c34adc5Sramat kmem_free(cpi, sizeof (*cpi)); 77733c34adc5Sramat } 77743c34adc5Sramat 77753c34adc5Sramat static void 77763c34adc5Sramat free_vhcache_client(mdi_vhcache_client_t *cct) 77773c34adc5Sramat { 77783c34adc5Sramat kmem_free(cct->cct_name_addr, strlen(cct->cct_name_addr) + 1); 77793c34adc5Sramat kmem_free(cct, sizeof (*cct)); 77803c34adc5Sramat } 77813c34adc5Sramat 77823c34adc5Sramat static char * 77833c34adc5Sramat vhcache_mknameaddr(char *ct_name, char *ct_addr, int *ret_len) 77843c34adc5Sramat { 77853c34adc5Sramat char *name_addr; 77863c34adc5Sramat int len; 77873c34adc5Sramat 77883c34adc5Sramat len = strlen(ct_name) + strlen(ct_addr) + 2; 77893c34adc5Sramat name_addr = kmem_alloc(len, KM_SLEEP); 77903c34adc5Sramat (void) snprintf(name_addr, len, "%s@%s", ct_name, ct_addr); 77913c34adc5Sramat 77923c34adc5Sramat if (ret_len) 77933c34adc5Sramat *ret_len = len; 77943c34adc5Sramat return (name_addr); 77953c34adc5Sramat } 77963c34adc5Sramat 77973c34adc5Sramat /* 77983c34adc5Sramat * Copy the contents of paddrnvl to vhci cache. 77993c34adc5Sramat * paddrnvl nvlist contains path information for a vhci client. 78003c34adc5Sramat * See the comment in mainnvl_to_vhcache() for the format of this nvlist. 78013c34adc5Sramat */ 78023c34adc5Sramat static void 78033c34adc5Sramat paddrnvl_to_vhcache(nvlist_t *nvl, mdi_vhcache_phci_t *cphci_list[], 78043c34adc5Sramat mdi_vhcache_client_t *cct) 78053c34adc5Sramat { 78063c34adc5Sramat nvpair_t *nvp = NULL; 78073c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 78083c34adc5Sramat uint_t nelem; 78093c34adc5Sramat uint32_t *val; 78103c34adc5Sramat 78113c34adc5Sramat while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 78123c34adc5Sramat ASSERT(nvpair_type(nvp) == DATA_TYPE_UINT32_ARRAY); 78133c34adc5Sramat cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP); 78143c34adc5Sramat cpi->cpi_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP); 78153c34adc5Sramat (void) nvpair_value_uint32_array(nvp, &val, &nelem); 78163c34adc5Sramat ASSERT(nelem == 2); 78173c34adc5Sramat cpi->cpi_cphci = cphci_list[val[0]]; 78183c34adc5Sramat cpi->cpi_flags = val[1]; 78193c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, cpi); 78203c34adc5Sramat } 78213c34adc5Sramat } 78223c34adc5Sramat 78233c34adc5Sramat /* 78243c34adc5Sramat * Copy the contents of caddrmapnvl to vhci cache. 78253c34adc5Sramat * caddrmapnvl nvlist contains vhci client address to phci client address 78263c34adc5Sramat * mappings. See the comment in mainnvl_to_vhcache() for the format of 78273c34adc5Sramat * this nvlist. 78283c34adc5Sramat */ 78293c34adc5Sramat static void 78303c34adc5Sramat caddrmapnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl, 78313c34adc5Sramat mdi_vhcache_phci_t *cphci_list[]) 78323c34adc5Sramat { 78333c34adc5Sramat nvpair_t *nvp = NULL; 78343c34adc5Sramat nvlist_t *paddrnvl; 78353c34adc5Sramat mdi_vhcache_client_t *cct; 78363c34adc5Sramat 78373c34adc5Sramat while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 78383c34adc5Sramat ASSERT(nvpair_type(nvp) == DATA_TYPE_NVLIST); 78393c34adc5Sramat cct = kmem_zalloc(sizeof (*cct), KM_SLEEP); 78403c34adc5Sramat cct->cct_name_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP); 78413c34adc5Sramat (void) nvpair_value_nvlist(nvp, &paddrnvl); 78423c34adc5Sramat paddrnvl_to_vhcache(paddrnvl, cphci_list, cct); 78433c34adc5Sramat /* the client must contain at least one path */ 78443c34adc5Sramat ASSERT(cct->cct_cpi_head != NULL); 78453c34adc5Sramat 78463c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 78473c34adc5Sramat (void) mod_hash_insert(vhcache->vhcache_client_hash, 78483c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct); 78493c34adc5Sramat } 78503c34adc5Sramat } 78513c34adc5Sramat 78523c34adc5Sramat /* 78533c34adc5Sramat * Copy the contents of the main nvlist to vhci cache. 78543c34adc5Sramat * 78553c34adc5Sramat * VHCI busconfig cached data is stored in the form of a nvlist on the disk. 78563c34adc5Sramat * The nvlist contains the mappings between the vhci client addresses and 78573c34adc5Sramat * their corresponding phci client addresses. 78583c34adc5Sramat * 78593c34adc5Sramat * The structure of the nvlist is as follows: 78603c34adc5Sramat * 78613c34adc5Sramat * Main nvlist: 78623c34adc5Sramat * NAME TYPE DATA 78633c34adc5Sramat * version int32 version number 78643c34adc5Sramat * phcis string array array of phci paths 78653c34adc5Sramat * clientaddrmap nvlist_t c2paddrs_nvl (see below) 78663c34adc5Sramat * 78673c34adc5Sramat * structure of c2paddrs_nvl: 78683c34adc5Sramat * NAME TYPE DATA 78693c34adc5Sramat * caddr1 nvlist_t paddrs_nvl1 78703c34adc5Sramat * caddr2 nvlist_t paddrs_nvl2 78713c34adc5Sramat * ... 78723c34adc5Sramat * where caddr1, caddr2, ... are vhci client name and addresses in the 78733c34adc5Sramat * form of "<clientname>@<clientaddress>". 78743c34adc5Sramat * (for example: "ssd@2000002037cd9f72"); 78753c34adc5Sramat * paddrs_nvl1, paddrs_nvl2, .. are nvlists that contain path information. 78763c34adc5Sramat * 78773c34adc5Sramat * structure of paddrs_nvl: 78783c34adc5Sramat * NAME TYPE DATA 78793c34adc5Sramat * pi_addr1 uint32_array (phci-id, cpi_flags) 78803c34adc5Sramat * pi_addr2 uint32_array (phci-id, cpi_flags) 78813c34adc5Sramat * ... 78823c34adc5Sramat * where pi_addr1, pi_addr2, ... are bus specific addresses of pathinfo nodes 78833c34adc5Sramat * (so called pi_addrs, for example: "w2100002037cd9f72,0"); 78844c06356bSdh142964 * phci-ids are integers that identify pHCIs to which the 78853c34adc5Sramat * the bus specific address belongs to. These integers are used as an index 78864c06356bSdh142964 * into to the phcis string array in the main nvlist to get the pHCI path. 78873c34adc5Sramat */ 78883c34adc5Sramat static int 78893c34adc5Sramat mainnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl) 78903c34adc5Sramat { 78913c34adc5Sramat char **phcis, **phci_namep; 78923c34adc5Sramat uint_t nphcis; 78933c34adc5Sramat mdi_vhcache_phci_t *cphci, **cphci_list; 78943c34adc5Sramat nvlist_t *caddrmapnvl; 78953c34adc5Sramat int32_t ver; 78963c34adc5Sramat int i; 78973c34adc5Sramat size_t cphci_list_size; 78983c34adc5Sramat 78993c34adc5Sramat ASSERT(RW_WRITE_HELD(&vhcache->vhcache_lock)); 79003c34adc5Sramat 79013c34adc5Sramat if (nvlist_lookup_int32(nvl, MDI_NVPNAME_VERSION, &ver) != 0 || 79023c34adc5Sramat ver != MDI_VHCI_CACHE_VERSION) 79033c34adc5Sramat return (MDI_FAILURE); 79043c34adc5Sramat 79053c34adc5Sramat if (nvlist_lookup_string_array(nvl, MDI_NVPNAME_PHCIS, &phcis, 79063c34adc5Sramat &nphcis) != 0) 79073c34adc5Sramat return (MDI_SUCCESS); 79083c34adc5Sramat 79093c34adc5Sramat ASSERT(nphcis > 0); 79103c34adc5Sramat 79113c34adc5Sramat cphci_list_size = sizeof (mdi_vhcache_phci_t *) * nphcis; 79123c34adc5Sramat cphci_list = kmem_alloc(cphci_list_size, KM_SLEEP); 79133c34adc5Sramat for (i = 0, phci_namep = phcis; i < nphcis; i++, phci_namep++) { 79143c34adc5Sramat cphci = kmem_zalloc(sizeof (mdi_vhcache_phci_t), KM_SLEEP); 79153c34adc5Sramat cphci->cphci_path = i_ddi_strdup(*phci_namep, KM_SLEEP); 79163c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 79173c34adc5Sramat cphci_list[i] = cphci; 79183c34adc5Sramat } 79193c34adc5Sramat 79203c34adc5Sramat ASSERT(vhcache->vhcache_phci_head != NULL); 79213c34adc5Sramat 79223c34adc5Sramat if (nvlist_lookup_nvlist(nvl, MDI_NVPNAME_CTADDRMAP, &caddrmapnvl) == 0) 79233c34adc5Sramat caddrmapnvl_to_vhcache(vhcache, caddrmapnvl, cphci_list); 79243c34adc5Sramat 79253c34adc5Sramat kmem_free(cphci_list, cphci_list_size); 79263c34adc5Sramat return (MDI_SUCCESS); 79273c34adc5Sramat } 79283c34adc5Sramat 79293c34adc5Sramat /* 79303c34adc5Sramat * Build paddrnvl for the specified client using the information in the 79313c34adc5Sramat * vhci cache and add it to the caddrmapnnvl. 79323c34adc5Sramat * Returns 0 on success, errno on failure. 79333c34adc5Sramat */ 79343c34adc5Sramat static int 79353c34adc5Sramat vhcache_to_paddrnvl(mdi_vhci_cache_t *vhcache, mdi_vhcache_client_t *cct, 79363c34adc5Sramat nvlist_t *caddrmapnvl) 79373c34adc5Sramat { 79383c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 79393c34adc5Sramat nvlist_t *nvl; 79403c34adc5Sramat int err; 79413c34adc5Sramat uint32_t val[2]; 79423c34adc5Sramat 79433c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 79443c34adc5Sramat 79453c34adc5Sramat if ((err = nvlist_alloc(&nvl, 0, KM_SLEEP)) != 0) 79463c34adc5Sramat return (err); 79473c34adc5Sramat 79483c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 79493c34adc5Sramat val[0] = cpi->cpi_cphci->cphci_id; 79503c34adc5Sramat val[1] = cpi->cpi_flags; 79513c34adc5Sramat if ((err = nvlist_add_uint32_array(nvl, cpi->cpi_addr, val, 2)) 79523c34adc5Sramat != 0) 79533c34adc5Sramat goto out; 79543c34adc5Sramat } 79553c34adc5Sramat 79563c34adc5Sramat err = nvlist_add_nvlist(caddrmapnvl, cct->cct_name_addr, nvl); 79573c34adc5Sramat out: 79583c34adc5Sramat nvlist_free(nvl); 79593c34adc5Sramat return (err); 79603c34adc5Sramat } 79613c34adc5Sramat 79623c34adc5Sramat /* 79633c34adc5Sramat * Build caddrmapnvl using the information in the vhci cache 79643c34adc5Sramat * and add it to the mainnvl. 79653c34adc5Sramat * Returns 0 on success, errno on failure. 79663c34adc5Sramat */ 79673c34adc5Sramat static int 79683c34adc5Sramat vhcache_to_caddrmapnvl(mdi_vhci_cache_t *vhcache, nvlist_t *mainnvl) 79693c34adc5Sramat { 79703c34adc5Sramat mdi_vhcache_client_t *cct; 79713c34adc5Sramat nvlist_t *nvl; 79723c34adc5Sramat int err; 79733c34adc5Sramat 79743c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 79753c34adc5Sramat 79763c34adc5Sramat if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0) 79773c34adc5Sramat return (err); 79783c34adc5Sramat 79793c34adc5Sramat for (cct = vhcache->vhcache_client_head; cct != NULL; 79803c34adc5Sramat cct = cct->cct_next) { 79813c34adc5Sramat if ((err = vhcache_to_paddrnvl(vhcache, cct, nvl)) != 0) 79823c34adc5Sramat goto out; 79833c34adc5Sramat } 79843c34adc5Sramat 79853c34adc5Sramat err = nvlist_add_nvlist(mainnvl, MDI_NVPNAME_CTADDRMAP, nvl); 79863c34adc5Sramat out: 79873c34adc5Sramat nvlist_free(nvl); 79883c34adc5Sramat return (err); 79893c34adc5Sramat } 79903c34adc5Sramat 79913c34adc5Sramat /* 79923c34adc5Sramat * Build nvlist using the information in the vhci cache. 79933c34adc5Sramat * See the comment in mainnvl_to_vhcache() for the format of the nvlist. 79943c34adc5Sramat * Returns nvl on success, NULL on failure. 79953c34adc5Sramat */ 79963c34adc5Sramat static nvlist_t * 79973c34adc5Sramat vhcache_to_mainnvl(mdi_vhci_cache_t *vhcache) 79983c34adc5Sramat { 79993c34adc5Sramat mdi_vhcache_phci_t *cphci; 80003c34adc5Sramat uint_t phci_count; 80013c34adc5Sramat char **phcis; 80023c34adc5Sramat nvlist_t *nvl; 80033c34adc5Sramat int err, i; 80043c34adc5Sramat 80053c34adc5Sramat if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0) { 80063c34adc5Sramat nvl = NULL; 80073c34adc5Sramat goto out; 80083c34adc5Sramat } 80093c34adc5Sramat 80103c34adc5Sramat if ((err = nvlist_add_int32(nvl, MDI_NVPNAME_VERSION, 80113c34adc5Sramat MDI_VHCI_CACHE_VERSION)) != 0) 80123c34adc5Sramat goto out; 80133c34adc5Sramat 80143c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 80153c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) { 80163c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 80173c34adc5Sramat return (nvl); 80183c34adc5Sramat } 80193c34adc5Sramat 80203c34adc5Sramat phci_count = 0; 80213c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 80223c34adc5Sramat cphci = cphci->cphci_next) 80233c34adc5Sramat cphci->cphci_id = phci_count++; 80243c34adc5Sramat 80253c34adc5Sramat /* build phci pathname list */ 80263c34adc5Sramat phcis = kmem_alloc(sizeof (char *) * phci_count, KM_SLEEP); 80273c34adc5Sramat for (cphci = vhcache->vhcache_phci_head, i = 0; cphci != NULL; 80283c34adc5Sramat cphci = cphci->cphci_next, i++) 80293c34adc5Sramat phcis[i] = i_ddi_strdup(cphci->cphci_path, KM_SLEEP); 80303c34adc5Sramat 80313c34adc5Sramat err = nvlist_add_string_array(nvl, MDI_NVPNAME_PHCIS, phcis, 80323c34adc5Sramat phci_count); 80333c34adc5Sramat free_string_array(phcis, phci_count); 80343c34adc5Sramat 80353c34adc5Sramat if (err == 0 && 80363c34adc5Sramat (err = vhcache_to_caddrmapnvl(vhcache, nvl)) == 0) { 80373c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 80383c34adc5Sramat return (nvl); 80393c34adc5Sramat } 80403c34adc5Sramat 80413c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 80423c34adc5Sramat out: 80433c34adc5Sramat if (nvl) 80443c34adc5Sramat nvlist_free(nvl); 80453c34adc5Sramat return (NULL); 80463c34adc5Sramat } 80473c34adc5Sramat 80483c34adc5Sramat /* 80493c34adc5Sramat * Lookup vhcache phci structure for the specified phci path. 80503c34adc5Sramat */ 80513c34adc5Sramat static mdi_vhcache_phci_t * 80523c34adc5Sramat lookup_vhcache_phci_by_name(mdi_vhci_cache_t *vhcache, char *phci_path) 80533c34adc5Sramat { 80543c34adc5Sramat mdi_vhcache_phci_t *cphci; 80553c34adc5Sramat 80563c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 80573c34adc5Sramat 80583c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 80593c34adc5Sramat cphci = cphci->cphci_next) { 80603c34adc5Sramat if (strcmp(cphci->cphci_path, phci_path) == 0) 80613c34adc5Sramat return (cphci); 80623c34adc5Sramat } 80633c34adc5Sramat 80643c34adc5Sramat return (NULL); 80653c34adc5Sramat } 80663c34adc5Sramat 80673c34adc5Sramat /* 80683c34adc5Sramat * Lookup vhcache phci structure for the specified phci. 80693c34adc5Sramat */ 80703c34adc5Sramat static mdi_vhcache_phci_t * 80713c34adc5Sramat lookup_vhcache_phci_by_addr(mdi_vhci_cache_t *vhcache, mdi_phci_t *ph) 80723c34adc5Sramat { 80733c34adc5Sramat mdi_vhcache_phci_t *cphci; 80743c34adc5Sramat 80753c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 80763c34adc5Sramat 80773c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 80783c34adc5Sramat cphci = cphci->cphci_next) { 80793c34adc5Sramat if (cphci->cphci_phci == ph) 80803c34adc5Sramat return (cphci); 80813c34adc5Sramat } 80823c34adc5Sramat 80833c34adc5Sramat return (NULL); 80843c34adc5Sramat } 80853c34adc5Sramat 80863c34adc5Sramat /* 80873c34adc5Sramat * Add the specified phci to the vhci cache if not already present. 80883c34adc5Sramat */ 80893c34adc5Sramat static void 80903c34adc5Sramat vhcache_phci_add(mdi_vhci_config_t *vhc, mdi_phci_t *ph) 80913c34adc5Sramat { 80923c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 80933c34adc5Sramat mdi_vhcache_phci_t *cphci; 80943c34adc5Sramat char *pathname; 80953c34adc5Sramat int cache_updated; 80963c34adc5Sramat 80973c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 80983c34adc5Sramat 80993c34adc5Sramat pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 81003c34adc5Sramat (void) ddi_pathname(ph->ph_dip, pathname); 81013c34adc5Sramat if ((cphci = lookup_vhcache_phci_by_name(vhcache, pathname)) 81023c34adc5Sramat != NULL) { 81033c34adc5Sramat cphci->cphci_phci = ph; 81043c34adc5Sramat cache_updated = 0; 81053c34adc5Sramat } else { 81063c34adc5Sramat cphci = kmem_zalloc(sizeof (*cphci), KM_SLEEP); 81073c34adc5Sramat cphci->cphci_path = i_ddi_strdup(pathname, KM_SLEEP); 81083c34adc5Sramat cphci->cphci_phci = ph; 81093c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 81103c34adc5Sramat cache_updated = 1; 81113c34adc5Sramat } 811267e56d35Sramat 81133c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 81143c34adc5Sramat 811567e56d35Sramat /* 811667e56d35Sramat * Since a new phci has been added, reset 811767e56d35Sramat * vhc_path_discovery_cutoff_time to allow for discovery of paths 811867e56d35Sramat * during next vhcache_discover_paths(). 811967e56d35Sramat */ 812067e56d35Sramat mutex_enter(&vhc->vhc_lock); 812167e56d35Sramat vhc->vhc_path_discovery_cutoff_time = 0; 812267e56d35Sramat mutex_exit(&vhc->vhc_lock); 812367e56d35Sramat 81243c34adc5Sramat kmem_free(pathname, MAXPATHLEN); 81253c34adc5Sramat if (cache_updated) 81263c34adc5Sramat vhcache_dirty(vhc); 81273c34adc5Sramat } 81283c34adc5Sramat 81293c34adc5Sramat /* 81303c34adc5Sramat * Remove the reference to the specified phci from the vhci cache. 81313c34adc5Sramat */ 81323c34adc5Sramat static void 81333c34adc5Sramat vhcache_phci_remove(mdi_vhci_config_t *vhc, mdi_phci_t *ph) 81343c34adc5Sramat { 81353c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 81363c34adc5Sramat mdi_vhcache_phci_t *cphci; 81373c34adc5Sramat 81383c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 81393c34adc5Sramat if ((cphci = lookup_vhcache_phci_by_addr(vhcache, ph)) != NULL) { 81403c34adc5Sramat /* do not remove the actual mdi_vhcache_phci structure */ 81413c34adc5Sramat cphci->cphci_phci = NULL; 81423c34adc5Sramat } 81433c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 81443c34adc5Sramat } 81453c34adc5Sramat 81463c34adc5Sramat static void 81473c34adc5Sramat init_vhcache_lookup_token(mdi_vhcache_lookup_token_t *dst, 81483c34adc5Sramat mdi_vhcache_lookup_token_t *src) 81493c34adc5Sramat { 81503c34adc5Sramat if (src == NULL) { 81513c34adc5Sramat dst->lt_cct = NULL; 81523c34adc5Sramat dst->lt_cct_lookup_time = 0; 81533c34adc5Sramat } else { 81543c34adc5Sramat dst->lt_cct = src->lt_cct; 81553c34adc5Sramat dst->lt_cct_lookup_time = src->lt_cct_lookup_time; 81563c34adc5Sramat } 81573c34adc5Sramat } 81583c34adc5Sramat 81593c34adc5Sramat /* 81603c34adc5Sramat * Look up vhcache client for the specified client. 81613c34adc5Sramat */ 81623c34adc5Sramat static mdi_vhcache_client_t * 81633c34adc5Sramat lookup_vhcache_client(mdi_vhci_cache_t *vhcache, char *ct_name, char *ct_addr, 81643c34adc5Sramat mdi_vhcache_lookup_token_t *token) 81653c34adc5Sramat { 81663c34adc5Sramat mod_hash_val_t hv; 81673c34adc5Sramat char *name_addr; 81683c34adc5Sramat int len; 81693c34adc5Sramat 81703c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 81713c34adc5Sramat 81723c34adc5Sramat /* 81733c34adc5Sramat * If no vhcache clean occurred since the last lookup, we can 81743c34adc5Sramat * simply return the cct from the last lookup operation. 81753c34adc5Sramat * It works because ccts are never freed except during the vhcache 81763c34adc5Sramat * cleanup operation. 81773c34adc5Sramat */ 81783c34adc5Sramat if (token != NULL && 81793c34adc5Sramat vhcache->vhcache_clean_time < token->lt_cct_lookup_time) 81803c34adc5Sramat return (token->lt_cct); 81813c34adc5Sramat 81823c34adc5Sramat name_addr = vhcache_mknameaddr(ct_name, ct_addr, &len); 81833c34adc5Sramat if (mod_hash_find(vhcache->vhcache_client_hash, 81843c34adc5Sramat (mod_hash_key_t)name_addr, &hv) == 0) { 81853c34adc5Sramat if (token) { 81863c34adc5Sramat token->lt_cct = (mdi_vhcache_client_t *)hv; 8187d3d50737SRafael Vanoni token->lt_cct_lookup_time = ddi_get_lbolt64(); 81883c34adc5Sramat } 81893c34adc5Sramat } else { 81903c34adc5Sramat if (token) { 81913c34adc5Sramat token->lt_cct = NULL; 81923c34adc5Sramat token->lt_cct_lookup_time = 0; 81933c34adc5Sramat } 81943c34adc5Sramat hv = NULL; 81953c34adc5Sramat } 81963c34adc5Sramat kmem_free(name_addr, len); 81973c34adc5Sramat return ((mdi_vhcache_client_t *)hv); 81983c34adc5Sramat } 81993c34adc5Sramat 82003c34adc5Sramat /* 82013c34adc5Sramat * Add the specified path to the vhci cache if not already present. 82023c34adc5Sramat * Also add the vhcache client for the client corresponding to this path 82033c34adc5Sramat * if it doesn't already exist. 82043c34adc5Sramat */ 82053c34adc5Sramat static void 82063c34adc5Sramat vhcache_pi_add(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip) 82073c34adc5Sramat { 82083c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 82093c34adc5Sramat mdi_vhcache_client_t *cct; 82103c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 82113c34adc5Sramat mdi_phci_t *ph = pip->pi_phci; 82123c34adc5Sramat mdi_client_t *ct = pip->pi_client; 82133c34adc5Sramat int cache_updated = 0; 82143c34adc5Sramat 82153c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 82163c34adc5Sramat 82173c34adc5Sramat /* if vhcache client for this pip doesn't already exist, add it */ 82183c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid, 82193c34adc5Sramat NULL)) == NULL) { 82203c34adc5Sramat cct = kmem_zalloc(sizeof (*cct), KM_SLEEP); 82213c34adc5Sramat cct->cct_name_addr = vhcache_mknameaddr(ct->ct_drvname, 82223c34adc5Sramat ct->ct_guid, NULL); 82233c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 82243c34adc5Sramat (void) mod_hash_insert(vhcache->vhcache_client_hash, 82253c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct); 82263c34adc5Sramat cache_updated = 1; 82273c34adc5Sramat } 82283c34adc5Sramat 82293c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 82303c34adc5Sramat if (cpi->cpi_cphci->cphci_phci == ph && 82313c34adc5Sramat strcmp(cpi->cpi_addr, pip->pi_addr) == 0) { 82323c34adc5Sramat cpi->cpi_pip = pip; 82333c34adc5Sramat if (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST) { 82343c34adc5Sramat cpi->cpi_flags &= 82353c34adc5Sramat ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 82363c34adc5Sramat sort_vhcache_paths(cct); 82373c34adc5Sramat cache_updated = 1; 82383c34adc5Sramat } 82393c34adc5Sramat break; 82403c34adc5Sramat } 82413c34adc5Sramat } 82423c34adc5Sramat 82433c34adc5Sramat if (cpi == NULL) { 82443c34adc5Sramat cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP); 82453c34adc5Sramat cpi->cpi_addr = i_ddi_strdup(pip->pi_addr, KM_SLEEP); 82463c34adc5Sramat cpi->cpi_cphci = lookup_vhcache_phci_by_addr(vhcache, ph); 82473c34adc5Sramat ASSERT(cpi->cpi_cphci != NULL); 82483c34adc5Sramat cpi->cpi_pip = pip; 82493c34adc5Sramat enqueue_vhcache_pathinfo(cct, cpi); 82503c34adc5Sramat cache_updated = 1; 82513c34adc5Sramat } 82523c34adc5Sramat 82533c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 82543c34adc5Sramat 82553c34adc5Sramat if (cache_updated) 82563c34adc5Sramat vhcache_dirty(vhc); 82573c34adc5Sramat } 82583c34adc5Sramat 82593c34adc5Sramat /* 82603c34adc5Sramat * Remove the reference to the specified path from the vhci cache. 82613c34adc5Sramat */ 82623c34adc5Sramat static void 82633c34adc5Sramat vhcache_pi_remove(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip) 82643c34adc5Sramat { 82653c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 82663c34adc5Sramat mdi_client_t *ct = pip->pi_client; 82673c34adc5Sramat mdi_vhcache_client_t *cct; 82683c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 82693c34adc5Sramat 82703c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 82713c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid, 82723c34adc5Sramat NULL)) != NULL) { 82733c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; 82743c34adc5Sramat cpi = cpi->cpi_next) { 82753c34adc5Sramat if (cpi->cpi_pip == pip) { 82763c34adc5Sramat cpi->cpi_pip = NULL; 82773c34adc5Sramat break; 82783c34adc5Sramat } 82793c34adc5Sramat } 82803c34adc5Sramat } 82813c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 82823c34adc5Sramat } 82833c34adc5Sramat 82843c34adc5Sramat /* 82853c34adc5Sramat * Flush the vhci cache to disk. 82863c34adc5Sramat * Returns MDI_SUCCESS on success, MDI_FAILURE on failure. 82873c34adc5Sramat */ 82883c34adc5Sramat static int 82893c34adc5Sramat flush_vhcache(mdi_vhci_config_t *vhc, int force_flag) 82903c34adc5Sramat { 82913c34adc5Sramat nvlist_t *nvl; 82923c34adc5Sramat int err; 82933c34adc5Sramat int rv; 82943c34adc5Sramat 82953c34adc5Sramat /* 82963c34adc5Sramat * It is possible that the system may shutdown before 82973c34adc5Sramat * i_ddi_io_initialized (during stmsboot for example). To allow for 82983c34adc5Sramat * flushing the cache in this case do not check for 82993c34adc5Sramat * i_ddi_io_initialized when force flag is set. 83003c34adc5Sramat */ 83013c34adc5Sramat if (force_flag == 0 && !i_ddi_io_initialized()) 83023c34adc5Sramat return (MDI_FAILURE); 83033c34adc5Sramat 83043c34adc5Sramat if ((nvl = vhcache_to_mainnvl(&vhc->vhc_vhcache)) != NULL) { 83053c34adc5Sramat err = fwrite_nvlist(vhc->vhc_vhcache_filename, nvl); 83063c34adc5Sramat nvlist_free(nvl); 83073c34adc5Sramat } else 83083c34adc5Sramat err = EFAULT; 83093c34adc5Sramat 83103c34adc5Sramat rv = MDI_SUCCESS; 83113c34adc5Sramat mutex_enter(&vhc->vhc_lock); 83123c34adc5Sramat if (err != 0) { 83133c34adc5Sramat if (err == EROFS) { 83143c34adc5Sramat vhc->vhc_flags |= MDI_VHC_READONLY_FS; 83153c34adc5Sramat vhc->vhc_flags &= ~(MDI_VHC_VHCACHE_FLUSH_ERROR | 83163c34adc5Sramat MDI_VHC_VHCACHE_DIRTY); 83173c34adc5Sramat } else { 83183c34adc5Sramat if (!(vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR)) { 83193c34adc5Sramat cmn_err(CE_CONT, "%s: update failed\n", 83203c34adc5Sramat vhc->vhc_vhcache_filename); 83213c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_ERROR; 83223c34adc5Sramat } 83233c34adc5Sramat rv = MDI_FAILURE; 83243c34adc5Sramat } 83253c34adc5Sramat } else if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR) { 83263c34adc5Sramat cmn_err(CE_CONT, 83273c34adc5Sramat "%s: update now ok\n", vhc->vhc_vhcache_filename); 83283c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_ERROR; 83293c34adc5Sramat } 83303c34adc5Sramat mutex_exit(&vhc->vhc_lock); 83313c34adc5Sramat 83323c34adc5Sramat return (rv); 83333c34adc5Sramat } 83343c34adc5Sramat 83353c34adc5Sramat /* 83363c34adc5Sramat * Call flush_vhcache() to flush the vhci cache at the scheduled time. 83373c34adc5Sramat * Exits itself if left idle for the idle timeout period. 83383c34adc5Sramat */ 83393c34adc5Sramat static void 83403c34adc5Sramat vhcache_flush_thread(void *arg) 83413c34adc5Sramat { 83423c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 83433c34adc5Sramat clock_t idle_time, quit_at_ticks; 83443c34adc5Sramat callb_cpr_t cprinfo; 83453c34adc5Sramat 83463c34adc5Sramat /* number of seconds to sleep idle before exiting */ 83473c34adc5Sramat idle_time = mdi_vhcache_flush_daemon_idle_time * TICKS_PER_SECOND; 83483c34adc5Sramat 83493c34adc5Sramat CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr, 83503c34adc5Sramat "mdi_vhcache_flush"); 83513c34adc5Sramat mutex_enter(&vhc->vhc_lock); 83523c34adc5Sramat for (; ; ) { 83533c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 83543c34adc5Sramat (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY)) { 83553c34adc5Sramat if (ddi_get_lbolt() < vhc->vhc_flush_at_ticks) { 83563c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 83573c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, 83583c34adc5Sramat &vhc->vhc_lock, vhc->vhc_flush_at_ticks); 83593c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 83603c34adc5Sramat } else { 83613c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 83623c34adc5Sramat mutex_exit(&vhc->vhc_lock); 83633c34adc5Sramat 83643c34adc5Sramat if (flush_vhcache(vhc, 0) != MDI_SUCCESS) 83653c34adc5Sramat vhcache_dirty(vhc); 83663c34adc5Sramat 83673c34adc5Sramat mutex_enter(&vhc->vhc_lock); 83683c34adc5Sramat } 83693c34adc5Sramat } 83703c34adc5Sramat 83713c34adc5Sramat quit_at_ticks = ddi_get_lbolt() + idle_time; 83723c34adc5Sramat 83733c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 83743c34adc5Sramat !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) && 83753c34adc5Sramat ddi_get_lbolt() < quit_at_ticks) { 83763c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 83773c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock, 83783c34adc5Sramat quit_at_ticks); 83793c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 83803c34adc5Sramat } 83813c34adc5Sramat 83823c34adc5Sramat if ((vhc->vhc_flags & MDI_VHC_EXIT) || 83833c34adc5Sramat !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY)) 83843c34adc5Sramat goto out; 83853c34adc5Sramat } 83863c34adc5Sramat 83873c34adc5Sramat out: 83883c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_THREAD; 83893c34adc5Sramat /* CALLB_CPR_EXIT releases the vhc->vhc_lock */ 83903c34adc5Sramat CALLB_CPR_EXIT(&cprinfo); 83913c34adc5Sramat } 83923c34adc5Sramat 83933c34adc5Sramat /* 83943c34adc5Sramat * Make vhci cache dirty and schedule flushing by vhcache flush thread. 83953c34adc5Sramat */ 83963c34adc5Sramat static void 83973c34adc5Sramat vhcache_dirty(mdi_vhci_config_t *vhc) 83983c34adc5Sramat { 83993c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 84003c34adc5Sramat int create_thread; 84013c34adc5Sramat 84023c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 84033c34adc5Sramat /* do not flush cache until the cache is fully built */ 84043c34adc5Sramat if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) { 84053c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 84063c34adc5Sramat return; 84073c34adc5Sramat } 84083c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 84093c34adc5Sramat 84103c34adc5Sramat mutex_enter(&vhc->vhc_lock); 84113c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_READONLY_FS) { 84123c34adc5Sramat mutex_exit(&vhc->vhc_lock); 84133c34adc5Sramat return; 84143c34adc5Sramat } 84153c34adc5Sramat 84163c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_DIRTY; 84173c34adc5Sramat vhc->vhc_flush_at_ticks = ddi_get_lbolt() + 84183c34adc5Sramat mdi_vhcache_flush_delay * TICKS_PER_SECOND; 84193c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) { 84203c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 84213c34adc5Sramat create_thread = 0; 84223c34adc5Sramat } else { 84233c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_THREAD; 84243c34adc5Sramat create_thread = 1; 84253c34adc5Sramat } 84263c34adc5Sramat mutex_exit(&vhc->vhc_lock); 84273c34adc5Sramat 84283c34adc5Sramat if (create_thread) 84293c34adc5Sramat (void) thread_create(NULL, 0, vhcache_flush_thread, vhc, 84303c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 84313c34adc5Sramat } 84323c34adc5Sramat 84333c34adc5Sramat /* 84343c34adc5Sramat * phci bus config structure - one for for each phci bus config operation that 84353c34adc5Sramat * we initiate on behalf of a vhci. 84363c34adc5Sramat */ 84373c34adc5Sramat typedef struct mdi_phci_bus_config_s { 84383c34adc5Sramat char *phbc_phci_path; 84393c34adc5Sramat struct mdi_vhci_bus_config_s *phbc_vhbusconfig; /* vhci bus config */ 84403c34adc5Sramat struct mdi_phci_bus_config_s *phbc_next; 84413c34adc5Sramat } mdi_phci_bus_config_t; 84423c34adc5Sramat 84433c34adc5Sramat /* vhci bus config structure - one for each vhci bus config operation */ 84443c34adc5Sramat typedef struct mdi_vhci_bus_config_s { 84453c34adc5Sramat ddi_bus_config_op_t vhbc_op; /* bus config op */ 84463c34adc5Sramat major_t vhbc_op_major; /* bus config op major */ 84473c34adc5Sramat uint_t vhbc_op_flags; /* bus config op flags */ 84483c34adc5Sramat kmutex_t vhbc_lock; 84493c34adc5Sramat kcondvar_t vhbc_cv; 84503c34adc5Sramat int vhbc_thr_count; 84513c34adc5Sramat } mdi_vhci_bus_config_t; 84523c34adc5Sramat 84533c34adc5Sramat /* 84543c34adc5Sramat * bus config the specified phci 84553c34adc5Sramat */ 84563c34adc5Sramat static void 84573c34adc5Sramat bus_config_phci(void *arg) 84583c34adc5Sramat { 84593c34adc5Sramat mdi_phci_bus_config_t *phbc = (mdi_phci_bus_config_t *)arg; 84603c34adc5Sramat mdi_vhci_bus_config_t *vhbc = phbc->phbc_vhbusconfig; 84613c34adc5Sramat dev_info_t *ph_dip; 84623c34adc5Sramat 84633c34adc5Sramat /* 84643c34adc5Sramat * first configure all path components upto phci and then configure 84653c34adc5Sramat * the phci children. 84663c34adc5Sramat */ 84673c34adc5Sramat if ((ph_dip = e_ddi_hold_devi_by_path(phbc->phbc_phci_path, 0)) 84683c34adc5Sramat != NULL) { 84693c34adc5Sramat if (vhbc->vhbc_op == BUS_CONFIG_DRIVER || 84703c34adc5Sramat vhbc->vhbc_op == BUS_UNCONFIG_DRIVER) { 84713c34adc5Sramat (void) ndi_devi_config_driver(ph_dip, 84723c34adc5Sramat vhbc->vhbc_op_flags, 84733c34adc5Sramat vhbc->vhbc_op_major); 84743c34adc5Sramat } else 84753c34adc5Sramat (void) ndi_devi_config(ph_dip, 84763c34adc5Sramat vhbc->vhbc_op_flags); 84773c34adc5Sramat 84783c34adc5Sramat /* release the hold that e_ddi_hold_devi_by_path() placed */ 84793c34adc5Sramat ndi_rele_devi(ph_dip); 84803c34adc5Sramat } 84813c34adc5Sramat 84823c34adc5Sramat kmem_free(phbc->phbc_phci_path, strlen(phbc->phbc_phci_path) + 1); 84833c34adc5Sramat kmem_free(phbc, sizeof (*phbc)); 84843c34adc5Sramat 84853c34adc5Sramat mutex_enter(&vhbc->vhbc_lock); 84863c34adc5Sramat vhbc->vhbc_thr_count--; 84873c34adc5Sramat if (vhbc->vhbc_thr_count == 0) 84883c34adc5Sramat cv_broadcast(&vhbc->vhbc_cv); 84893c34adc5Sramat mutex_exit(&vhbc->vhbc_lock); 84903c34adc5Sramat } 84913c34adc5Sramat 84923c34adc5Sramat /* 84933c34adc5Sramat * Bus config all phcis associated with the vhci in parallel. 84943c34adc5Sramat * op must be BUS_CONFIG_DRIVER or BUS_CONFIG_ALL. 84953c34adc5Sramat */ 84963c34adc5Sramat static void 84973c34adc5Sramat bus_config_all_phcis(mdi_vhci_cache_t *vhcache, uint_t flags, 84983c34adc5Sramat ddi_bus_config_op_t op, major_t maj) 84993c34adc5Sramat { 85003c34adc5Sramat mdi_phci_bus_config_t *phbc_head = NULL, *phbc, *phbc_next; 85013c34adc5Sramat mdi_vhci_bus_config_t *vhbc; 85023c34adc5Sramat mdi_vhcache_phci_t *cphci; 85033c34adc5Sramat 85043c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 85053c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) { 85063c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 85073c34adc5Sramat return; 85083c34adc5Sramat } 85093c34adc5Sramat 85103c34adc5Sramat vhbc = kmem_zalloc(sizeof (*vhbc), KM_SLEEP); 85113c34adc5Sramat 85123c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 85133c34adc5Sramat cphci = cphci->cphci_next) { 8514273f4511Sgp87344 /* skip phcis that haven't attached before root is available */ 8515273f4511Sgp87344 if (!modrootloaded && (cphci->cphci_phci == NULL)) 8516273f4511Sgp87344 continue; 85173c34adc5Sramat phbc = kmem_zalloc(sizeof (*phbc), KM_SLEEP); 85183c34adc5Sramat phbc->phbc_phci_path = i_ddi_strdup(cphci->cphci_path, 85193c34adc5Sramat KM_SLEEP); 85203c34adc5Sramat phbc->phbc_vhbusconfig = vhbc; 85213c34adc5Sramat phbc->phbc_next = phbc_head; 85223c34adc5Sramat phbc_head = phbc; 85233c34adc5Sramat vhbc->vhbc_thr_count++; 85243c34adc5Sramat } 85253c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 85263c34adc5Sramat 85273c34adc5Sramat vhbc->vhbc_op = op; 85283c34adc5Sramat vhbc->vhbc_op_major = maj; 85293c34adc5Sramat vhbc->vhbc_op_flags = NDI_NO_EVENT | 85303c34adc5Sramat (flags & (NDI_CONFIG_REPROBE | NDI_DRV_CONF_REPROBE)); 85313c34adc5Sramat mutex_init(&vhbc->vhbc_lock, NULL, MUTEX_DEFAULT, NULL); 85323c34adc5Sramat cv_init(&vhbc->vhbc_cv, NULL, CV_DRIVER, NULL); 85333c34adc5Sramat 85343c34adc5Sramat /* now create threads to initiate bus config on all phcis in parallel */ 85353c34adc5Sramat for (phbc = phbc_head; phbc != NULL; phbc = phbc_next) { 85363c34adc5Sramat phbc_next = phbc->phbc_next; 85373c34adc5Sramat if (mdi_mtc_off) 85383c34adc5Sramat bus_config_phci((void *)phbc); 85393c34adc5Sramat else 85403c34adc5Sramat (void) thread_create(NULL, 0, bus_config_phci, phbc, 85413c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 85423c34adc5Sramat } 85433c34adc5Sramat 85443c34adc5Sramat mutex_enter(&vhbc->vhbc_lock); 85453c34adc5Sramat /* wait until all threads exit */ 85463c34adc5Sramat while (vhbc->vhbc_thr_count > 0) 85473c34adc5Sramat cv_wait(&vhbc->vhbc_cv, &vhbc->vhbc_lock); 85483c34adc5Sramat mutex_exit(&vhbc->vhbc_lock); 85493c34adc5Sramat 85503c34adc5Sramat mutex_destroy(&vhbc->vhbc_lock); 85513c34adc5Sramat cv_destroy(&vhbc->vhbc_cv); 85523c34adc5Sramat kmem_free(vhbc, sizeof (*vhbc)); 85533c34adc5Sramat } 85543c34adc5Sramat 85553c34adc5Sramat /* 855667e56d35Sramat * Single threaded version of bus_config_all_phcis() 855767e56d35Sramat */ 855867e56d35Sramat static void 855967e56d35Sramat st_bus_config_all_phcis(mdi_vhci_config_t *vhc, uint_t flags, 856067e56d35Sramat ddi_bus_config_op_t op, major_t maj) 856167e56d35Sramat { 856267e56d35Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 856367e56d35Sramat 856467e56d35Sramat single_threaded_vhconfig_enter(vhc); 856567e56d35Sramat bus_config_all_phcis(vhcache, flags, op, maj); 856667e56d35Sramat single_threaded_vhconfig_exit(vhc); 856767e56d35Sramat } 856867e56d35Sramat 856967e56d35Sramat /* 85703c34adc5Sramat * Perform BUS_CONFIG_ONE on the specified child of the phci. 85713c34adc5Sramat * The path includes the child component in addition to the phci path. 85723c34adc5Sramat */ 85733c34adc5Sramat static int 85743c34adc5Sramat bus_config_one_phci_child(char *path) 85753c34adc5Sramat { 85763c34adc5Sramat dev_info_t *ph_dip, *child; 85773c34adc5Sramat char *devnm; 85783c34adc5Sramat int rv = MDI_FAILURE; 85793c34adc5Sramat 85803c34adc5Sramat /* extract the child component of the phci */ 85813c34adc5Sramat devnm = strrchr(path, '/'); 85823c34adc5Sramat *devnm++ = '\0'; 85833c34adc5Sramat 85843c34adc5Sramat /* 85853c34adc5Sramat * first configure all path components upto phci and then 85863c34adc5Sramat * configure the phci child. 85873c34adc5Sramat */ 85883c34adc5Sramat if ((ph_dip = e_ddi_hold_devi_by_path(path, 0)) != NULL) { 85893c34adc5Sramat if (ndi_devi_config_one(ph_dip, devnm, &child, NDI_NO_EVENT) == 85903c34adc5Sramat NDI_SUCCESS) { 85913c34adc5Sramat /* 85923c34adc5Sramat * release the hold that ndi_devi_config_one() placed 85933c34adc5Sramat */ 85943c34adc5Sramat ndi_rele_devi(child); 85953c34adc5Sramat rv = MDI_SUCCESS; 85963c34adc5Sramat } 85973c34adc5Sramat 85983c34adc5Sramat /* release the hold that e_ddi_hold_devi_by_path() placed */ 85993c34adc5Sramat ndi_rele_devi(ph_dip); 86003c34adc5Sramat } 86013c34adc5Sramat 86023c34adc5Sramat devnm--; 86033c34adc5Sramat *devnm = '/'; 86043c34adc5Sramat return (rv); 86053c34adc5Sramat } 86063c34adc5Sramat 86073c34adc5Sramat /* 86083c34adc5Sramat * Build a list of phci client paths for the specified vhci client. 86093c34adc5Sramat * The list includes only those phci client paths which aren't configured yet. 86103c34adc5Sramat */ 86113c34adc5Sramat static mdi_phys_path_t * 86123c34adc5Sramat build_phclient_path_list(mdi_vhcache_client_t *cct, char *ct_name) 86133c34adc5Sramat { 86143c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 86153c34adc5Sramat mdi_phys_path_t *pp_head = NULL, *pp_tail = NULL, *pp; 86163c34adc5Sramat int config_path, len; 86173c34adc5Sramat 86183c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 86193c34adc5Sramat /* 86203c34adc5Sramat * include only those paths that aren't configured. 86213c34adc5Sramat */ 86223c34adc5Sramat config_path = 0; 86233c34adc5Sramat if (cpi->cpi_pip == NULL) 86243c34adc5Sramat config_path = 1; 86253c34adc5Sramat else { 86263c34adc5Sramat MDI_PI_LOCK(cpi->cpi_pip); 86273c34adc5Sramat if (MDI_PI_IS_INIT(cpi->cpi_pip)) 86283c34adc5Sramat config_path = 1; 86293c34adc5Sramat MDI_PI_UNLOCK(cpi->cpi_pip); 86303c34adc5Sramat } 86313c34adc5Sramat 86323c34adc5Sramat if (config_path) { 86333c34adc5Sramat pp = kmem_alloc(sizeof (*pp), KM_SLEEP); 86343c34adc5Sramat len = strlen(cpi->cpi_cphci->cphci_path) + 86353c34adc5Sramat strlen(ct_name) + strlen(cpi->cpi_addr) + 3; 86363c34adc5Sramat pp->phys_path = kmem_alloc(len, KM_SLEEP); 86373c34adc5Sramat (void) snprintf(pp->phys_path, len, "%s/%s@%s", 86383c34adc5Sramat cpi->cpi_cphci->cphci_path, ct_name, 86393c34adc5Sramat cpi->cpi_addr); 86403c34adc5Sramat pp->phys_path_next = NULL; 86413c34adc5Sramat 86423c34adc5Sramat if (pp_head == NULL) 86433c34adc5Sramat pp_head = pp; 86443c34adc5Sramat else 86453c34adc5Sramat pp_tail->phys_path_next = pp; 86463c34adc5Sramat pp_tail = pp; 86473c34adc5Sramat } 86483c34adc5Sramat } 86493c34adc5Sramat 86503c34adc5Sramat return (pp_head); 86513c34adc5Sramat } 86523c34adc5Sramat 86533c34adc5Sramat /* 86543c34adc5Sramat * Free the memory allocated for phci client path list. 86553c34adc5Sramat */ 86563c34adc5Sramat static void 86573c34adc5Sramat free_phclient_path_list(mdi_phys_path_t *pp_head) 86583c34adc5Sramat { 86593c34adc5Sramat mdi_phys_path_t *pp, *pp_next; 86603c34adc5Sramat 86613c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp_next) { 86623c34adc5Sramat pp_next = pp->phys_path_next; 86633c34adc5Sramat kmem_free(pp->phys_path, strlen(pp->phys_path) + 1); 86643c34adc5Sramat kmem_free(pp, sizeof (*pp)); 86653c34adc5Sramat } 86663c34adc5Sramat } 86673c34adc5Sramat 86683c34adc5Sramat /* 86693c34adc5Sramat * Allocated async client structure and initialize with the specified values. 86703c34adc5Sramat */ 86713c34adc5Sramat static mdi_async_client_config_t * 86723c34adc5Sramat alloc_async_client_config(char *ct_name, char *ct_addr, 86733c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 86743c34adc5Sramat { 86753c34adc5Sramat mdi_async_client_config_t *acc; 86763c34adc5Sramat 86773c34adc5Sramat acc = kmem_alloc(sizeof (*acc), KM_SLEEP); 86783c34adc5Sramat acc->acc_ct_name = i_ddi_strdup(ct_name, KM_SLEEP); 86793c34adc5Sramat acc->acc_ct_addr = i_ddi_strdup(ct_addr, KM_SLEEP); 86803c34adc5Sramat acc->acc_phclient_path_list_head = pp_head; 86813c34adc5Sramat init_vhcache_lookup_token(&acc->acc_token, tok); 86823c34adc5Sramat acc->acc_next = NULL; 86833c34adc5Sramat return (acc); 86843c34adc5Sramat } 86853c34adc5Sramat 86863c34adc5Sramat /* 86873c34adc5Sramat * Free the memory allocated for the async client structure and their members. 86883c34adc5Sramat */ 86893c34adc5Sramat static void 86903c34adc5Sramat free_async_client_config(mdi_async_client_config_t *acc) 86913c34adc5Sramat { 86923c34adc5Sramat if (acc->acc_phclient_path_list_head) 86933c34adc5Sramat free_phclient_path_list(acc->acc_phclient_path_list_head); 86943c34adc5Sramat kmem_free(acc->acc_ct_name, strlen(acc->acc_ct_name) + 1); 86953c34adc5Sramat kmem_free(acc->acc_ct_addr, strlen(acc->acc_ct_addr) + 1); 86963c34adc5Sramat kmem_free(acc, sizeof (*acc)); 86973c34adc5Sramat } 86983c34adc5Sramat 86993c34adc5Sramat /* 87003c34adc5Sramat * Sort vhcache pathinfos (cpis) of the specified client. 87013c34adc5Sramat * All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST 87023c34adc5Sramat * flag set come at the beginning of the list. All cpis which have this 87033c34adc5Sramat * flag set come at the end of the list. 87043c34adc5Sramat */ 87053c34adc5Sramat static void 87063c34adc5Sramat sort_vhcache_paths(mdi_vhcache_client_t *cct) 87073c34adc5Sramat { 87083c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_next, *cpi_head; 87093c34adc5Sramat 87103c34adc5Sramat cpi_head = cct->cct_cpi_head; 87113c34adc5Sramat cct->cct_cpi_head = cct->cct_cpi_tail = NULL; 87123c34adc5Sramat for (cpi = cpi_head; cpi != NULL; cpi = cpi_next) { 87133c34adc5Sramat cpi_next = cpi->cpi_next; 87143c34adc5Sramat enqueue_vhcache_pathinfo(cct, cpi); 87153c34adc5Sramat } 87163c34adc5Sramat } 87173c34adc5Sramat 87183c34adc5Sramat /* 87193c34adc5Sramat * Verify whether MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag setting is correct for 87203c34adc5Sramat * every vhcache pathinfo of the specified client. If not adjust the flag 87213c34adc5Sramat * setting appropriately. 87223c34adc5Sramat * 87233c34adc5Sramat * Note that MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag is persisted in the 87243c34adc5Sramat * on-disk vhci cache. So every time this flag is updated the cache must be 87253c34adc5Sramat * flushed. 87263c34adc5Sramat */ 87273c34adc5Sramat static void 87283c34adc5Sramat adjust_sort_vhcache_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 87293c34adc5Sramat mdi_vhcache_lookup_token_t *tok) 87303c34adc5Sramat { 87313c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 87323c34adc5Sramat mdi_vhcache_client_t *cct; 87333c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 87343c34adc5Sramat 87353c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 87363c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, tok)) 87373c34adc5Sramat == NULL) { 87383c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 87393c34adc5Sramat return; 87403c34adc5Sramat } 87413c34adc5Sramat 87423c34adc5Sramat /* 87433c34adc5Sramat * to avoid unnecessary on-disk cache updates, first check if an 87443c34adc5Sramat * update is really needed. If no update is needed simply return. 87453c34adc5Sramat */ 87463c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 87473c34adc5Sramat if ((cpi->cpi_pip != NULL && 87483c34adc5Sramat (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST)) || 87493c34adc5Sramat (cpi->cpi_pip == NULL && 87503c34adc5Sramat !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST))) { 87513c34adc5Sramat break; 87523c34adc5Sramat } 87533c34adc5Sramat } 87543c34adc5Sramat if (cpi == NULL) { 87553c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 87563c34adc5Sramat return; 87573c34adc5Sramat } 87583c34adc5Sramat 87593c34adc5Sramat if (rw_tryupgrade(&vhcache->vhcache_lock) == 0) { 87603c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 87613c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 87623c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, 87633c34adc5Sramat tok)) == NULL) { 87643c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 87653c34adc5Sramat return; 87663c34adc5Sramat } 87673c34adc5Sramat } 87683c34adc5Sramat 87693c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 87703c34adc5Sramat if (cpi->cpi_pip != NULL) 87713c34adc5Sramat cpi->cpi_flags &= ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 87723c34adc5Sramat else 87733c34adc5Sramat cpi->cpi_flags |= MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 87743c34adc5Sramat } 87753c34adc5Sramat sort_vhcache_paths(cct); 87763c34adc5Sramat 87773c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 87783c34adc5Sramat vhcache_dirty(vhc); 87793c34adc5Sramat } 87803c34adc5Sramat 87813c34adc5Sramat /* 87823c34adc5Sramat * Configure all specified paths of the client. 87833c34adc5Sramat */ 87843c34adc5Sramat static void 87853c34adc5Sramat config_client_paths_sync(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 87863c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 87873c34adc5Sramat { 87883c34adc5Sramat mdi_phys_path_t *pp; 87893c34adc5Sramat 87903c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp->phys_path_next) 87913c34adc5Sramat (void) bus_config_one_phci_child(pp->phys_path); 87923c34adc5Sramat adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, tok); 87933c34adc5Sramat } 87943c34adc5Sramat 87953c34adc5Sramat /* 87963c34adc5Sramat * Dequeue elements from vhci async client config list and bus configure 87973c34adc5Sramat * their corresponding phci clients. 87983c34adc5Sramat */ 87993c34adc5Sramat static void 88003c34adc5Sramat config_client_paths_thread(void *arg) 88013c34adc5Sramat { 88023c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 88033c34adc5Sramat mdi_async_client_config_t *acc; 88043c34adc5Sramat clock_t quit_at_ticks; 88053c34adc5Sramat clock_t idle_time = mdi_async_config_idle_time * TICKS_PER_SECOND; 88063c34adc5Sramat callb_cpr_t cprinfo; 88073c34adc5Sramat 88083c34adc5Sramat CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr, 88093c34adc5Sramat "mdi_config_client_paths"); 88103c34adc5Sramat 88113c34adc5Sramat for (; ; ) { 88123c34adc5Sramat quit_at_ticks = ddi_get_lbolt() + idle_time; 88133c34adc5Sramat 88143c34adc5Sramat mutex_enter(&vhc->vhc_lock); 88153c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 88163c34adc5Sramat vhc->vhc_acc_list_head == NULL && 88173c34adc5Sramat ddi_get_lbolt() < quit_at_ticks) { 88183c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 88193c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock, 88203c34adc5Sramat quit_at_ticks); 88213c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 88223c34adc5Sramat } 88233c34adc5Sramat 88243c34adc5Sramat if ((vhc->vhc_flags & MDI_VHC_EXIT) || 88253c34adc5Sramat vhc->vhc_acc_list_head == NULL) 88263c34adc5Sramat goto out; 88273c34adc5Sramat 88283c34adc5Sramat acc = vhc->vhc_acc_list_head; 88293c34adc5Sramat vhc->vhc_acc_list_head = acc->acc_next; 88303c34adc5Sramat if (vhc->vhc_acc_list_head == NULL) 88313c34adc5Sramat vhc->vhc_acc_list_tail = NULL; 88323c34adc5Sramat vhc->vhc_acc_count--; 88333c34adc5Sramat mutex_exit(&vhc->vhc_lock); 88343c34adc5Sramat 88353c34adc5Sramat config_client_paths_sync(vhc, acc->acc_ct_name, 88363c34adc5Sramat acc->acc_ct_addr, acc->acc_phclient_path_list_head, 88373c34adc5Sramat &acc->acc_token); 88383c34adc5Sramat 88393c34adc5Sramat free_async_client_config(acc); 88403c34adc5Sramat } 88413c34adc5Sramat 88423c34adc5Sramat out: 88433c34adc5Sramat vhc->vhc_acc_thrcount--; 88443c34adc5Sramat /* CALLB_CPR_EXIT releases the vhc->vhc_lock */ 88453c34adc5Sramat CALLB_CPR_EXIT(&cprinfo); 88463c34adc5Sramat } 88473c34adc5Sramat 88483c34adc5Sramat /* 88493c34adc5Sramat * Arrange for all the phci client paths (pp_head) for the specified client 88503c34adc5Sramat * to be bus configured asynchronously by a thread. 88513c34adc5Sramat */ 88523c34adc5Sramat static void 88533c34adc5Sramat config_client_paths_async(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 88543c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 88553c34adc5Sramat { 88563c34adc5Sramat mdi_async_client_config_t *acc, *newacc; 88573c34adc5Sramat int create_thread; 88583c34adc5Sramat 88593c34adc5Sramat if (pp_head == NULL) 88603c34adc5Sramat return; 88613c34adc5Sramat 88623c34adc5Sramat if (mdi_mtc_off) { 88633c34adc5Sramat config_client_paths_sync(vhc, ct_name, ct_addr, pp_head, tok); 88643c34adc5Sramat free_phclient_path_list(pp_head); 88653c34adc5Sramat return; 88663c34adc5Sramat } 88673c34adc5Sramat 88683c34adc5Sramat newacc = alloc_async_client_config(ct_name, ct_addr, pp_head, tok); 88693c34adc5Sramat ASSERT(newacc); 88703c34adc5Sramat 88713c34adc5Sramat mutex_enter(&vhc->vhc_lock); 88723c34adc5Sramat for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc->acc_next) { 88733c34adc5Sramat if (strcmp(ct_name, acc->acc_ct_name) == 0 && 88743c34adc5Sramat strcmp(ct_addr, acc->acc_ct_addr) == 0) { 88753c34adc5Sramat free_async_client_config(newacc); 88763c34adc5Sramat mutex_exit(&vhc->vhc_lock); 88773c34adc5Sramat return; 88783c34adc5Sramat } 88793c34adc5Sramat } 88803c34adc5Sramat 88813c34adc5Sramat if (vhc->vhc_acc_list_head == NULL) 88823c34adc5Sramat vhc->vhc_acc_list_head = newacc; 88833c34adc5Sramat else 88843c34adc5Sramat vhc->vhc_acc_list_tail->acc_next = newacc; 88853c34adc5Sramat vhc->vhc_acc_list_tail = newacc; 88863c34adc5Sramat vhc->vhc_acc_count++; 88873c34adc5Sramat if (vhc->vhc_acc_count <= vhc->vhc_acc_thrcount) { 88883c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 88893c34adc5Sramat create_thread = 0; 88903c34adc5Sramat } else { 88913c34adc5Sramat vhc->vhc_acc_thrcount++; 88923c34adc5Sramat create_thread = 1; 88933c34adc5Sramat } 88943c34adc5Sramat mutex_exit(&vhc->vhc_lock); 88953c34adc5Sramat 88963c34adc5Sramat if (create_thread) 88973c34adc5Sramat (void) thread_create(NULL, 0, config_client_paths_thread, vhc, 88983c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 88993c34adc5Sramat } 89003c34adc5Sramat 89013c34adc5Sramat /* 89023c34adc5Sramat * Return number of online paths for the specified client. 89033c34adc5Sramat */ 89043c34adc5Sramat static int 89053c34adc5Sramat nonline_paths(mdi_vhcache_client_t *cct) 89063c34adc5Sramat { 89073c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 89083c34adc5Sramat int online_count = 0; 89093c34adc5Sramat 89103c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 89113c34adc5Sramat if (cpi->cpi_pip != NULL) { 89123c34adc5Sramat MDI_PI_LOCK(cpi->cpi_pip); 89133c34adc5Sramat if (cpi->cpi_pip->pi_state == MDI_PATHINFO_STATE_ONLINE) 89143c34adc5Sramat online_count++; 89153c34adc5Sramat MDI_PI_UNLOCK(cpi->cpi_pip); 89163c34adc5Sramat } 89173c34adc5Sramat } 89183c34adc5Sramat 89193c34adc5Sramat return (online_count); 89203c34adc5Sramat } 89213c34adc5Sramat 89223c34adc5Sramat /* 89233c34adc5Sramat * Bus configure all paths for the specified vhci client. 89243c34adc5Sramat * If at least one path for the client is already online, the remaining paths 89253c34adc5Sramat * will be configured asynchronously. Otherwise, it synchronously configures 89263c34adc5Sramat * the paths until at least one path is online and then rest of the paths 89273c34adc5Sramat * will be configured asynchronously. 89283c34adc5Sramat */ 89293c34adc5Sramat static void 89303c34adc5Sramat config_client_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr) 89313c34adc5Sramat { 89323c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 89333c34adc5Sramat mdi_phys_path_t *pp_head, *pp; 89343c34adc5Sramat mdi_vhcache_client_t *cct; 89353c34adc5Sramat mdi_vhcache_lookup_token_t tok; 89363c34adc5Sramat 89373c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 89383c34adc5Sramat 89393c34adc5Sramat init_vhcache_lookup_token(&tok, NULL); 89403c34adc5Sramat 89413c34adc5Sramat if (ct_name == NULL || ct_addr == NULL || 89423c34adc5Sramat (cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, &tok)) 89433c34adc5Sramat == NULL || 89443c34adc5Sramat (pp_head = build_phclient_path_list(cct, ct_name)) == NULL) { 89453c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 89463c34adc5Sramat return; 89473c34adc5Sramat } 89483c34adc5Sramat 89493c34adc5Sramat /* if at least one path is online, configure the rest asynchronously */ 89503c34adc5Sramat if (nonline_paths(cct) > 0) { 89513c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 89523c34adc5Sramat config_client_paths_async(vhc, ct_name, ct_addr, pp_head, &tok); 89533c34adc5Sramat return; 89543c34adc5Sramat } 89553c34adc5Sramat 89563c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 89573c34adc5Sramat 89583c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp->phys_path_next) { 89593c34adc5Sramat if (bus_config_one_phci_child(pp->phys_path) == MDI_SUCCESS) { 89603c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 89613c34adc5Sramat 89623c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, 89633c34adc5Sramat ct_addr, &tok)) == NULL) { 89643c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 89653c34adc5Sramat goto out; 89663c34adc5Sramat } 89673c34adc5Sramat 89683c34adc5Sramat if (nonline_paths(cct) > 0 && 89693c34adc5Sramat pp->phys_path_next != NULL) { 89703c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 89713c34adc5Sramat config_client_paths_async(vhc, ct_name, ct_addr, 89723c34adc5Sramat pp->phys_path_next, &tok); 89733c34adc5Sramat pp->phys_path_next = NULL; 89743c34adc5Sramat goto out; 89753c34adc5Sramat } 89763c34adc5Sramat 89773c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 89783c34adc5Sramat } 89793c34adc5Sramat } 89803c34adc5Sramat 89813c34adc5Sramat adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, &tok); 89823c34adc5Sramat out: 89833c34adc5Sramat free_phclient_path_list(pp_head); 89843c34adc5Sramat } 89853c34adc5Sramat 89863c34adc5Sramat static void 89873c34adc5Sramat single_threaded_vhconfig_enter(mdi_vhci_config_t *vhc) 89883c34adc5Sramat { 89893c34adc5Sramat mutex_enter(&vhc->vhc_lock); 89903c34adc5Sramat while (vhc->vhc_flags & MDI_VHC_SINGLE_THREADED) 89913c34adc5Sramat cv_wait(&vhc->vhc_cv, &vhc->vhc_lock); 89923c34adc5Sramat vhc->vhc_flags |= MDI_VHC_SINGLE_THREADED; 89933c34adc5Sramat mutex_exit(&vhc->vhc_lock); 89943c34adc5Sramat } 89953c34adc5Sramat 89963c34adc5Sramat static void 89973c34adc5Sramat single_threaded_vhconfig_exit(mdi_vhci_config_t *vhc) 89983c34adc5Sramat { 89993c34adc5Sramat mutex_enter(&vhc->vhc_lock); 90003c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_SINGLE_THREADED; 90013c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 90023c34adc5Sramat mutex_exit(&vhc->vhc_lock); 90033c34adc5Sramat } 90043c34adc5Sramat 900552cac543Sramat typedef struct mdi_phci_driver_info { 900652cac543Sramat char *phdriver_name; /* name of the phci driver */ 900752cac543Sramat 900852cac543Sramat /* set to non zero if the phci driver supports root device */ 900952cac543Sramat int phdriver_root_support; 901052cac543Sramat } mdi_phci_driver_info_t; 901152cac543Sramat 90123c34adc5Sramat /* 901352cac543Sramat * vhci class and root support capability of a phci driver can be 901452cac543Sramat * specified using ddi-vhci-class and ddi-no-root-support properties in the 901552cac543Sramat * phci driver.conf file. The built-in tables below contain this information 901652cac543Sramat * for those phci drivers whose driver.conf files don't yet contain this info. 901752cac543Sramat * 901852cac543Sramat * All phci drivers expect iscsi have root device support. 901952cac543Sramat */ 902052cac543Sramat static mdi_phci_driver_info_t scsi_phci_driver_list[] = { 902152cac543Sramat { "fp", 1 }, 902252cac543Sramat { "iscsi", 0 }, 902352cac543Sramat { "ibsrp", 1 } 902452cac543Sramat }; 902552cac543Sramat 902652cac543Sramat static mdi_phci_driver_info_t ib_phci_driver_list[] = { "tavor", 1 }; 902752cac543Sramat 902852cac543Sramat static void * 902952cac543Sramat mdi_realloc(void *old_ptr, size_t old_size, size_t new_size) 903052cac543Sramat { 903152cac543Sramat void *new_ptr; 903252cac543Sramat 903352cac543Sramat new_ptr = kmem_zalloc(new_size, KM_SLEEP); 903452cac543Sramat if (old_ptr) { 9035f7209cf2Spramodbg bcopy(old_ptr, new_ptr, MIN(old_size, new_size)); 903652cac543Sramat kmem_free(old_ptr, old_size); 903752cac543Sramat } 903852cac543Sramat return (new_ptr); 903952cac543Sramat } 904052cac543Sramat 904152cac543Sramat static void 904252cac543Sramat add_to_phci_list(char ***driver_list, int **root_support_list, 904352cac543Sramat int *cur_elements, int *max_elements, char *driver_name, int root_support) 904452cac543Sramat { 904552cac543Sramat ASSERT(*cur_elements <= *max_elements); 904652cac543Sramat if (*cur_elements == *max_elements) { 904752cac543Sramat *max_elements += 10; 904852cac543Sramat *driver_list = mdi_realloc(*driver_list, 904952cac543Sramat sizeof (char *) * (*cur_elements), 905052cac543Sramat sizeof (char *) * (*max_elements)); 905152cac543Sramat *root_support_list = mdi_realloc(*root_support_list, 905252cac543Sramat sizeof (int) * (*cur_elements), 905352cac543Sramat sizeof (int) * (*max_elements)); 905452cac543Sramat } 905552cac543Sramat (*driver_list)[*cur_elements] = i_ddi_strdup(driver_name, KM_SLEEP); 905652cac543Sramat (*root_support_list)[*cur_elements] = root_support; 905752cac543Sramat (*cur_elements)++; 905852cac543Sramat } 905952cac543Sramat 906052cac543Sramat static void 906152cac543Sramat get_phci_driver_list(char *vhci_class, char ***driver_list, 906252cac543Sramat int **root_support_list, int *cur_elements, int *max_elements) 906352cac543Sramat { 906452cac543Sramat mdi_phci_driver_info_t *st_driver_list, *p; 906552cac543Sramat int st_ndrivers, root_support, i, j, driver_conf_count; 906652cac543Sramat major_t m; 906752cac543Sramat struct devnames *dnp; 906852cac543Sramat ddi_prop_t *propp; 906952cac543Sramat 907052cac543Sramat *driver_list = NULL; 907152cac543Sramat *root_support_list = NULL; 907252cac543Sramat *cur_elements = 0; 907352cac543Sramat *max_elements = 0; 907452cac543Sramat 907552cac543Sramat /* add the phci drivers derived from the phci driver.conf files */ 907652cac543Sramat for (m = 0; m < devcnt; m++) { 907752cac543Sramat dnp = &devnamesp[m]; 907852cac543Sramat 907952cac543Sramat if (dnp->dn_flags & DN_PHCI_DRIVER) { 908052cac543Sramat LOCK_DEV_OPS(&dnp->dn_lock); 908152cac543Sramat if (dnp->dn_global_prop_ptr != NULL && 908252cac543Sramat (propp = i_ddi_prop_search(DDI_DEV_T_ANY, 908352cac543Sramat DDI_VHCI_CLASS, DDI_PROP_TYPE_STRING, 908452cac543Sramat &dnp->dn_global_prop_ptr->prop_list)) != NULL && 908552cac543Sramat strcmp(propp->prop_val, vhci_class) == 0) { 908652cac543Sramat 908752cac543Sramat root_support = (i_ddi_prop_search(DDI_DEV_T_ANY, 908852cac543Sramat DDI_NO_ROOT_SUPPORT, DDI_PROP_TYPE_INT, 908952cac543Sramat &dnp->dn_global_prop_ptr->prop_list) 909052cac543Sramat == NULL) ? 1 : 0; 909152cac543Sramat 909252cac543Sramat add_to_phci_list(driver_list, root_support_list, 909352cac543Sramat cur_elements, max_elements, dnp->dn_name, 909452cac543Sramat root_support); 909552cac543Sramat 909652cac543Sramat UNLOCK_DEV_OPS(&dnp->dn_lock); 909752cac543Sramat } else 909852cac543Sramat UNLOCK_DEV_OPS(&dnp->dn_lock); 909952cac543Sramat } 910052cac543Sramat } 910152cac543Sramat 910252cac543Sramat driver_conf_count = *cur_elements; 910352cac543Sramat 910452cac543Sramat /* add the phci drivers specified in the built-in tables */ 910552cac543Sramat if (strcmp(vhci_class, MDI_HCI_CLASS_SCSI) == 0) { 910652cac543Sramat st_driver_list = scsi_phci_driver_list; 910752cac543Sramat st_ndrivers = sizeof (scsi_phci_driver_list) / 910852cac543Sramat sizeof (mdi_phci_driver_info_t); 910952cac543Sramat } else if (strcmp(vhci_class, MDI_HCI_CLASS_IB) == 0) { 911052cac543Sramat st_driver_list = ib_phci_driver_list; 911152cac543Sramat st_ndrivers = sizeof (ib_phci_driver_list) / 911252cac543Sramat sizeof (mdi_phci_driver_info_t); 911352cac543Sramat } else { 911452cac543Sramat st_driver_list = NULL; 911552cac543Sramat st_ndrivers = 0; 911652cac543Sramat } 911752cac543Sramat 911852cac543Sramat for (i = 0, p = st_driver_list; i < st_ndrivers; i++, p++) { 911952cac543Sramat /* add this phci driver if not already added before */ 912052cac543Sramat for (j = 0; j < driver_conf_count; j++) { 912152cac543Sramat if (strcmp((*driver_list)[j], p->phdriver_name) == 0) 912252cac543Sramat break; 912352cac543Sramat } 912452cac543Sramat if (j == driver_conf_count) { 912552cac543Sramat add_to_phci_list(driver_list, root_support_list, 912652cac543Sramat cur_elements, max_elements, p->phdriver_name, 912752cac543Sramat p->phdriver_root_support); 912852cac543Sramat } 912952cac543Sramat } 913052cac543Sramat } 913152cac543Sramat 913252cac543Sramat /* 913352cac543Sramat * Attach the phci driver instances associated with the specified vhci class. 91343c34adc5Sramat * If root is mounted attach all phci driver instances. 91353c34adc5Sramat * If root is not mounted, attach the instances of only those phci 91363c34adc5Sramat * drivers that have the root support. 91373c34adc5Sramat */ 91383c34adc5Sramat static void 913952cac543Sramat attach_phci_drivers(char *vhci_class) 91403c34adc5Sramat { 914152cac543Sramat char **driver_list, **p; 914252cac543Sramat int *root_support_list; 914352cac543Sramat int cur_elements, max_elements, i; 91443c34adc5Sramat major_t m; 91453c34adc5Sramat 914652cac543Sramat get_phci_driver_list(vhci_class, &driver_list, &root_support_list, 914752cac543Sramat &cur_elements, &max_elements); 91483c34adc5Sramat 914952cac543Sramat for (i = 0; i < cur_elements; i++) { 915052cac543Sramat if (modrootloaded || root_support_list[i]) { 915152cac543Sramat m = ddi_name_to_major(driver_list[i]); 9152a204de77Scth if (m != DDI_MAJOR_T_NONE && 9153a204de77Scth ddi_hold_installed_driver(m)) 91543c34adc5Sramat ddi_rele_driver(m); 91553c34adc5Sramat } 91563c34adc5Sramat } 915752cac543Sramat 915852cac543Sramat if (driver_list) { 915952cac543Sramat for (i = 0, p = driver_list; i < cur_elements; i++, p++) 916052cac543Sramat kmem_free(*p, strlen(*p) + 1); 916152cac543Sramat kmem_free(driver_list, sizeof (char *) * max_elements); 916252cac543Sramat kmem_free(root_support_list, sizeof (int) * max_elements); 916352cac543Sramat } 91643c34adc5Sramat } 91653c34adc5Sramat 91663c34adc5Sramat /* 91673c34adc5Sramat * Build vhci cache: 91683c34adc5Sramat * 91693c34adc5Sramat * Attach phci driver instances and then drive BUS_CONFIG_ALL on 91703c34adc5Sramat * the phci driver instances. During this process the cache gets built. 91713c34adc5Sramat * 917267e56d35Sramat * Cache is built fully if the root is mounted. 91733c34adc5Sramat * If the root is not mounted, phci drivers that do not have root support 91743c34adc5Sramat * are not attached. As a result the cache is built partially. The entries 91753c34adc5Sramat * in the cache reflect only those phci drivers that have root support. 91763c34adc5Sramat */ 917767e56d35Sramat static int 917852cac543Sramat build_vhci_cache(mdi_vhci_t *vh) 91793c34adc5Sramat { 918052cac543Sramat mdi_vhci_config_t *vhc = vh->vh_config; 91813c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 91823c34adc5Sramat 918367e56d35Sramat single_threaded_vhconfig_enter(vhc); 918467e56d35Sramat 91853c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 91863c34adc5Sramat if (vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE) { 91873c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 918867e56d35Sramat single_threaded_vhconfig_exit(vhc); 918967e56d35Sramat return (0); 91903c34adc5Sramat } 91913c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 91923c34adc5Sramat 919352cac543Sramat attach_phci_drivers(vh->vh_class); 91943c34adc5Sramat bus_config_all_phcis(vhcache, NDI_DRV_CONF_REPROBE | NDI_NO_EVENT, 9195a204de77Scth BUS_CONFIG_ALL, DDI_MAJOR_T_NONE); 91963c34adc5Sramat 91973c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 91983c34adc5Sramat vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE; 91993c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 920067e56d35Sramat 920167e56d35Sramat single_threaded_vhconfig_exit(vhc); 92023c34adc5Sramat vhcache_dirty(vhc); 920367e56d35Sramat return (1); 92043c34adc5Sramat } 92053c34adc5Sramat 92063c34adc5Sramat /* 920767e56d35Sramat * Determine if discovery of paths is needed. 92083c34adc5Sramat */ 92093c34adc5Sramat static int 921067e56d35Sramat vhcache_do_discovery(mdi_vhci_config_t *vhc) 92113c34adc5Sramat { 921267e56d35Sramat int rv = 1; 921367e56d35Sramat 921467e56d35Sramat mutex_enter(&vhc->vhc_lock); 921567e56d35Sramat if (i_ddi_io_initialized() == 0) { 921667e56d35Sramat if (vhc->vhc_path_discovery_boot > 0) { 921767e56d35Sramat vhc->vhc_path_discovery_boot--; 921867e56d35Sramat goto out; 921967e56d35Sramat } 922067e56d35Sramat } else { 922167e56d35Sramat if (vhc->vhc_path_discovery_postboot > 0) { 922267e56d35Sramat vhc->vhc_path_discovery_postboot--; 922367e56d35Sramat goto out; 922467e56d35Sramat } 922567e56d35Sramat } 922667e56d35Sramat 922767e56d35Sramat /* 922867e56d35Sramat * Do full path discovery at most once per mdi_path_discovery_interval. 922967e56d35Sramat * This is to avoid a series of full path discoveries when opening 923067e56d35Sramat * stale /dev/[r]dsk links. 923167e56d35Sramat */ 923267e56d35Sramat if (mdi_path_discovery_interval != -1 && 9233d3d50737SRafael Vanoni ddi_get_lbolt64() >= vhc->vhc_path_discovery_cutoff_time) 923467e56d35Sramat goto out; 923567e56d35Sramat 923667e56d35Sramat rv = 0; 923767e56d35Sramat out: 923867e56d35Sramat mutex_exit(&vhc->vhc_lock); 923967e56d35Sramat return (rv); 924067e56d35Sramat } 924167e56d35Sramat 924267e56d35Sramat /* 924367e56d35Sramat * Discover all paths: 924467e56d35Sramat * 924567e56d35Sramat * Attach phci driver instances and then drive BUS_CONFIG_ALL on all the phci 924667e56d35Sramat * driver instances. During this process all paths will be discovered. 924767e56d35Sramat */ 924867e56d35Sramat static int 924952cac543Sramat vhcache_discover_paths(mdi_vhci_t *vh) 925067e56d35Sramat { 925152cac543Sramat mdi_vhci_config_t *vhc = vh->vh_config; 925267e56d35Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 925367e56d35Sramat int rv = 0; 92543c34adc5Sramat 92553c34adc5Sramat single_threaded_vhconfig_enter(vhc); 92563c34adc5Sramat 925767e56d35Sramat if (vhcache_do_discovery(vhc)) { 925852cac543Sramat attach_phci_drivers(vh->vh_class); 925967e56d35Sramat bus_config_all_phcis(vhcache, NDI_DRV_CONF_REPROBE | 9260a204de77Scth NDI_NO_EVENT, BUS_CONFIG_ALL, DDI_MAJOR_T_NONE); 926167e56d35Sramat 92623c34adc5Sramat mutex_enter(&vhc->vhc_lock); 9263d3d50737SRafael Vanoni vhc->vhc_path_discovery_cutoff_time = ddi_get_lbolt64() + 926467e56d35Sramat mdi_path_discovery_interval * TICKS_PER_SECOND; 92653c34adc5Sramat mutex_exit(&vhc->vhc_lock); 926667e56d35Sramat rv = 1; 92673c34adc5Sramat } 92683c34adc5Sramat 92693c34adc5Sramat single_threaded_vhconfig_exit(vhc); 92703c34adc5Sramat return (rv); 92713c34adc5Sramat } 92723c34adc5Sramat 92733c34adc5Sramat /* 92743c34adc5Sramat * Generic vhci bus config implementation: 92753c34adc5Sramat * 92763c34adc5Sramat * Parameters 92773c34adc5Sramat * vdip vhci dip 92783c34adc5Sramat * flags bus config flags 92793c34adc5Sramat * op bus config operation 92803c34adc5Sramat * The remaining parameters are bus config operation specific 92813c34adc5Sramat * 92823c34adc5Sramat * for BUS_CONFIG_ONE 92833c34adc5Sramat * arg pointer to name@addr 92843c34adc5Sramat * child upon successful return from this function, *child will be 92853c34adc5Sramat * set to the configured and held devinfo child node of vdip. 92863c34adc5Sramat * ct_addr pointer to client address (i.e. GUID) 92873c34adc5Sramat * 92883c34adc5Sramat * for BUS_CONFIG_DRIVER 92893c34adc5Sramat * arg major number of the driver 92903c34adc5Sramat * child and ct_addr parameters are ignored 92913c34adc5Sramat * 92923c34adc5Sramat * for BUS_CONFIG_ALL 92933c34adc5Sramat * arg, child, and ct_addr parameters are ignored 92943c34adc5Sramat * 92953c34adc5Sramat * Note that for the rest of the bus config operations, this function simply 92963c34adc5Sramat * calls the framework provided default bus config routine. 92973c34adc5Sramat */ 92983c34adc5Sramat int 92993c34adc5Sramat mdi_vhci_bus_config(dev_info_t *vdip, uint_t flags, ddi_bus_config_op_t op, 93003c34adc5Sramat void *arg, dev_info_t **child, char *ct_addr) 93013c34adc5Sramat { 93023c34adc5Sramat mdi_vhci_t *vh = i_devi_get_vhci(vdip); 93033c34adc5Sramat mdi_vhci_config_t *vhc = vh->vh_config; 93043c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 930567e56d35Sramat int rv = 0; 930667e56d35Sramat int params_valid = 0; 93073c34adc5Sramat char *cp; 93083c34adc5Sramat 93093c34adc5Sramat /* 93105e3986cbScth * To bus config vhcis we relay operation, possibly using another 93115e3986cbScth * thread, to phcis. The phci driver then interacts with MDI to cause 93125e3986cbScth * vhci child nodes to be enumerated under the vhci node. Adding a 93135e3986cbScth * vhci child requires an ndi_devi_enter of the vhci. Since another 93145e3986cbScth * thread may be adding the child, to avoid deadlock we can't wait 93155e3986cbScth * for the relayed operations to complete if we have already entered 93165e3986cbScth * the vhci node. 93173c34adc5Sramat */ 93183c34adc5Sramat if (DEVI_BUSY_OWNED(vdip)) { 93194c06356bSdh142964 MDI_DEBUG(2, (MDI_NOTE, vdip, 93204c06356bSdh142964 "vhci dip is busy owned %p", (void *)vdip)); 93213c34adc5Sramat goto default_bus_config; 93223c34adc5Sramat } 93233c34adc5Sramat 93243c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 93253c34adc5Sramat if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) { 93263c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 932752cac543Sramat rv = build_vhci_cache(vh); 93283c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 93293c34adc5Sramat } 93303c34adc5Sramat 93313c34adc5Sramat switch (op) { 93323c34adc5Sramat case BUS_CONFIG_ONE: 933367e56d35Sramat if (arg != NULL && ct_addr != NULL) { 93343c34adc5Sramat /* extract node name */ 93353c34adc5Sramat cp = (char *)arg; 93363c34adc5Sramat while (*cp != '\0' && *cp != '@') 93373c34adc5Sramat cp++; 93383c34adc5Sramat if (*cp == '@') { 933967e56d35Sramat params_valid = 1; 93403c34adc5Sramat *cp = '\0'; 93413c34adc5Sramat config_client_paths(vhc, (char *)arg, ct_addr); 934267e56d35Sramat /* config_client_paths() releases cache_lock */ 93433c34adc5Sramat *cp = '@'; 934467e56d35Sramat break; 934567e56d35Sramat } 934667e56d35Sramat } 934767e56d35Sramat 93483c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 93493c34adc5Sramat break; 93503c34adc5Sramat 93513c34adc5Sramat case BUS_CONFIG_DRIVER: 93523c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 935367e56d35Sramat if (rv == 0) 935467e56d35Sramat st_bus_config_all_phcis(vhc, flags, op, 93553c34adc5Sramat (major_t)(uintptr_t)arg); 93563c34adc5Sramat break; 93573c34adc5Sramat 93583c34adc5Sramat case BUS_CONFIG_ALL: 93593c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 936067e56d35Sramat if (rv == 0) 936167e56d35Sramat st_bus_config_all_phcis(vhc, flags, op, -1); 93623c34adc5Sramat break; 93633c34adc5Sramat 93643c34adc5Sramat default: 93653c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 93663c34adc5Sramat break; 93673c34adc5Sramat } 93683c34adc5Sramat 93693c34adc5Sramat 93703c34adc5Sramat default_bus_config: 93713c34adc5Sramat /* 93723c34adc5Sramat * All requested child nodes are enumerated under the vhci. 93733c34adc5Sramat * Now configure them. 93743c34adc5Sramat */ 93753c34adc5Sramat if (ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 93763c34adc5Sramat NDI_SUCCESS) { 93773c34adc5Sramat return (MDI_SUCCESS); 937867e56d35Sramat } else if (op == BUS_CONFIG_ONE && rv == 0 && params_valid) { 937967e56d35Sramat /* discover all paths and try configuring again */ 938052cac543Sramat if (vhcache_discover_paths(vh) && 938167e56d35Sramat ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 938267e56d35Sramat NDI_SUCCESS) 938367e56d35Sramat return (MDI_SUCCESS); 93843c34adc5Sramat } 93853c34adc5Sramat 93863c34adc5Sramat return (MDI_FAILURE); 93873c34adc5Sramat } 93883c34adc5Sramat 93893c34adc5Sramat /* 93903c34adc5Sramat * Read the on-disk vhci cache into an nvlist for the specified vhci class. 93913c34adc5Sramat */ 93923c34adc5Sramat static nvlist_t * 93933c34adc5Sramat read_on_disk_vhci_cache(char *vhci_class) 93943c34adc5Sramat { 93953c34adc5Sramat nvlist_t *nvl; 93963c34adc5Sramat int err; 93973c34adc5Sramat char *filename; 93983c34adc5Sramat 93993c34adc5Sramat filename = vhclass2vhcache_filename(vhci_class); 94003c34adc5Sramat 94013c34adc5Sramat if ((err = fread_nvlist(filename, &nvl)) == 0) { 94023c34adc5Sramat kmem_free(filename, strlen(filename) + 1); 94033c34adc5Sramat return (nvl); 94043c34adc5Sramat } else if (err == EIO) 94054c06356bSdh142964 cmn_err(CE_WARN, "%s: I/O error, will recreate", filename); 94063c34adc5Sramat else if (err == EINVAL) 94073c34adc5Sramat cmn_err(CE_WARN, 94084c06356bSdh142964 "%s: data file corrupted, will recreate", filename); 94093c34adc5Sramat 94103c34adc5Sramat kmem_free(filename, strlen(filename) + 1); 94113c34adc5Sramat return (NULL); 94123c34adc5Sramat } 94133c34adc5Sramat 94143c34adc5Sramat /* 94153c34adc5Sramat * Read on-disk vhci cache into nvlists for all vhci classes. 94163c34adc5Sramat * Called during booting by i_ddi_read_devices_files(). 94173c34adc5Sramat */ 94183c34adc5Sramat void 94193c34adc5Sramat mdi_read_devices_files(void) 94203c34adc5Sramat { 94213c34adc5Sramat int i; 94223c34adc5Sramat 94233c34adc5Sramat for (i = 0; i < N_VHCI_CLASSES; i++) 94243c34adc5Sramat vhcache_nvl[i] = read_on_disk_vhci_cache(vhci_class_list[i]); 94253c34adc5Sramat } 94263c34adc5Sramat 94273c34adc5Sramat /* 94283c34adc5Sramat * Remove all stale entries from vhci cache. 94293c34adc5Sramat */ 94303c34adc5Sramat static void 94313c34adc5Sramat clean_vhcache(mdi_vhci_config_t *vhc) 94323c34adc5Sramat { 94333c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 943442353512SRandall Ralphs mdi_vhcache_phci_t *phci, *nxt_phci; 943542353512SRandall Ralphs mdi_vhcache_client_t *client, *nxt_client; 943642353512SRandall Ralphs mdi_vhcache_pathinfo_t *path, *nxt_path; 94373c34adc5Sramat 94383c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 94393c34adc5Sramat 944042353512SRandall Ralphs client = vhcache->vhcache_client_head; 94413c34adc5Sramat vhcache->vhcache_client_head = vhcache->vhcache_client_tail = NULL; 944242353512SRandall Ralphs for ( ; client != NULL; client = nxt_client) { 944342353512SRandall Ralphs nxt_client = client->cct_next; 94443c34adc5Sramat 944542353512SRandall Ralphs path = client->cct_cpi_head; 944642353512SRandall Ralphs client->cct_cpi_head = client->cct_cpi_tail = NULL; 944742353512SRandall Ralphs for ( ; path != NULL; path = nxt_path) { 944842353512SRandall Ralphs nxt_path = path->cpi_next; 944942353512SRandall Ralphs if ((path->cpi_cphci->cphci_phci != NULL) && 945042353512SRandall Ralphs (path->cpi_pip != NULL)) { 945142353512SRandall Ralphs enqueue_tail_vhcache_pathinfo(client, path); 945242353512SRandall Ralphs } else if (path->cpi_pip != NULL) { 945342353512SRandall Ralphs /* Not valid to have a path without a phci. */ 945442353512SRandall Ralphs free_vhcache_pathinfo(path); 945542353512SRandall Ralphs } 94563c34adc5Sramat } 94573c34adc5Sramat 945842353512SRandall Ralphs if (client->cct_cpi_head != NULL) 945942353512SRandall Ralphs enqueue_vhcache_client(vhcache, client); 94603c34adc5Sramat else { 94613c34adc5Sramat (void) mod_hash_destroy(vhcache->vhcache_client_hash, 946242353512SRandall Ralphs (mod_hash_key_t)client->cct_name_addr); 946342353512SRandall Ralphs free_vhcache_client(client); 94643c34adc5Sramat } 94653c34adc5Sramat } 94663c34adc5Sramat 946742353512SRandall Ralphs phci = vhcache->vhcache_phci_head; 94683c34adc5Sramat vhcache->vhcache_phci_head = vhcache->vhcache_phci_tail = NULL; 946942353512SRandall Ralphs for ( ; phci != NULL; phci = nxt_phci) { 947042353512SRandall Ralphs 947142353512SRandall Ralphs nxt_phci = phci->cphci_next; 947242353512SRandall Ralphs if (phci->cphci_phci != NULL) 947342353512SRandall Ralphs enqueue_vhcache_phci(vhcache, phci); 94743c34adc5Sramat else 947542353512SRandall Ralphs free_vhcache_phci(phci); 94763c34adc5Sramat } 94773c34adc5Sramat 9478d3d50737SRafael Vanoni vhcache->vhcache_clean_time = ddi_get_lbolt64(); 94793c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 94803c34adc5Sramat vhcache_dirty(vhc); 94813c34adc5Sramat } 94823c34adc5Sramat 94833c34adc5Sramat /* 94843c34adc5Sramat * Remove all stale entries from vhci cache. 94853c34adc5Sramat * Called by i_ddi_clean_devices_files() during the execution of devfsadm -C 94863c34adc5Sramat */ 94873c34adc5Sramat void 94883c34adc5Sramat mdi_clean_vhcache(void) 94893c34adc5Sramat { 94903c34adc5Sramat mdi_vhci_t *vh; 94913c34adc5Sramat 94923c34adc5Sramat mutex_enter(&mdi_mutex); 94933c34adc5Sramat for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 94943c34adc5Sramat vh->vh_refcnt++; 94953c34adc5Sramat mutex_exit(&mdi_mutex); 94963c34adc5Sramat clean_vhcache(vh->vh_config); 94973c34adc5Sramat mutex_enter(&mdi_mutex); 94983c34adc5Sramat vh->vh_refcnt--; 94993c34adc5Sramat } 95003c34adc5Sramat mutex_exit(&mdi_mutex); 95013c34adc5Sramat } 95028c4f8890Srs135747 95038c4f8890Srs135747 /* 95048c4f8890Srs135747 * mdi_vhci_walk_clients(): 95058c4f8890Srs135747 * Walker routine to traverse client dev_info nodes 95068c4f8890Srs135747 * ddi_walk_devs(ddi_get_child(vdip), f, arg) returns the entire tree 95078c4f8890Srs135747 * below the client, including nexus devices, which we dont want. 95088c4f8890Srs135747 * So we just traverse the immediate siblings, starting from 1st client. 95098c4f8890Srs135747 */ 95108c4f8890Srs135747 void 95118c4f8890Srs135747 mdi_vhci_walk_clients(dev_info_t *vdip, 95128c4f8890Srs135747 int (*f)(dev_info_t *, void *), void *arg) 95138c4f8890Srs135747 { 95145e3986cbScth mdi_vhci_t *vh = i_devi_get_vhci(vdip); 95158c4f8890Srs135747 dev_info_t *cdip; 95168c4f8890Srs135747 mdi_client_t *ct; 95178c4f8890Srs135747 95185e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 95198c4f8890Srs135747 cdip = ddi_get_child(vdip); 95208c4f8890Srs135747 while (cdip) { 95218c4f8890Srs135747 ct = i_devi_get_client(cdip); 95228c4f8890Srs135747 MDI_CLIENT_LOCK(ct); 95238c4f8890Srs135747 95245e3986cbScth if (((*f)(cdip, arg)) == DDI_WALK_CONTINUE) 95258c4f8890Srs135747 cdip = ddi_get_next_sibling(cdip); 95265e3986cbScth else 95275e3986cbScth cdip = NULL; 9528c73a93f2Sdm120769 9529c73a93f2Sdm120769 MDI_CLIENT_UNLOCK(ct); 95308c4f8890Srs135747 } 95315e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 95328c4f8890Srs135747 } 95338c4f8890Srs135747 95348c4f8890Srs135747 /* 95358c4f8890Srs135747 * mdi_vhci_walk_phcis(): 95368c4f8890Srs135747 * Walker routine to traverse phci dev_info nodes 95378c4f8890Srs135747 */ 95388c4f8890Srs135747 void 95398c4f8890Srs135747 mdi_vhci_walk_phcis(dev_info_t *vdip, 95408c4f8890Srs135747 int (*f)(dev_info_t *, void *), void *arg) 95418c4f8890Srs135747 { 95425e3986cbScth mdi_vhci_t *vh = i_devi_get_vhci(vdip); 95435e3986cbScth mdi_phci_t *ph, *next; 95448c4f8890Srs135747 95455e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 95468c4f8890Srs135747 ph = vh->vh_phci_head; 95478c4f8890Srs135747 while (ph) { 95488c4f8890Srs135747 MDI_PHCI_LOCK(ph); 95498c4f8890Srs135747 95505e3986cbScth if (((*f)(ph->ph_dip, arg)) == DDI_WALK_CONTINUE) 95515e3986cbScth next = ph->ph_next; 95525e3986cbScth else 95535e3986cbScth next = NULL; 9554c73a93f2Sdm120769 9555c73a93f2Sdm120769 MDI_PHCI_UNLOCK(ph); 95565e3986cbScth ph = next; 95578c4f8890Srs135747 } 95585e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 95598c4f8890Srs135747 } 95608c4f8890Srs135747 95618c4f8890Srs135747 95628c4f8890Srs135747 /* 95638c4f8890Srs135747 * mdi_walk_vhcis(): 95648c4f8890Srs135747 * Walker routine to traverse vhci dev_info nodes 95658c4f8890Srs135747 */ 95668c4f8890Srs135747 void 95678c4f8890Srs135747 mdi_walk_vhcis(int (*f)(dev_info_t *, void *), void *arg) 95688c4f8890Srs135747 { 95698c4f8890Srs135747 mdi_vhci_t *vh = NULL; 95708c4f8890Srs135747 95718c4f8890Srs135747 mutex_enter(&mdi_mutex); 95728c4f8890Srs135747 /* 95738c4f8890Srs135747 * Scan for already registered vhci 95748c4f8890Srs135747 */ 95758c4f8890Srs135747 for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 95768c4f8890Srs135747 vh->vh_refcnt++; 95778c4f8890Srs135747 mutex_exit(&mdi_mutex); 95788c4f8890Srs135747 if (((*f)(vh->vh_dip, arg)) != DDI_WALK_CONTINUE) { 95798c4f8890Srs135747 mutex_enter(&mdi_mutex); 95808c4f8890Srs135747 vh->vh_refcnt--; 95818c4f8890Srs135747 break; 95828c4f8890Srs135747 } else { 95838c4f8890Srs135747 mutex_enter(&mdi_mutex); 95848c4f8890Srs135747 vh->vh_refcnt--; 95858c4f8890Srs135747 } 95868c4f8890Srs135747 } 95878c4f8890Srs135747 95888c4f8890Srs135747 mutex_exit(&mdi_mutex); 95898c4f8890Srs135747 } 95908c4f8890Srs135747 95918c4f8890Srs135747 /* 95928c4f8890Srs135747 * i_mdi_log_sysevent(): 95938c4f8890Srs135747 * Logs events for pickup by syseventd 95948c4f8890Srs135747 */ 95958c4f8890Srs135747 static void 95968c4f8890Srs135747 i_mdi_log_sysevent(dev_info_t *dip, char *ph_vh_class, char *subclass) 95978c4f8890Srs135747 { 95988c4f8890Srs135747 char *path_name; 95998c4f8890Srs135747 nvlist_t *attr_list; 96008c4f8890Srs135747 96018c4f8890Srs135747 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 96028c4f8890Srs135747 KM_SLEEP) != DDI_SUCCESS) { 96038c4f8890Srs135747 goto alloc_failed; 96048c4f8890Srs135747 } 96058c4f8890Srs135747 96068c4f8890Srs135747 path_name = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 96078c4f8890Srs135747 (void) ddi_pathname(dip, path_name); 96088c4f8890Srs135747 96098c4f8890Srs135747 if (nvlist_add_string(attr_list, DDI_DRIVER_NAME, 96108c4f8890Srs135747 ddi_driver_name(dip)) != DDI_SUCCESS) { 96118c4f8890Srs135747 goto error; 96128c4f8890Srs135747 } 96138c4f8890Srs135747 96148c4f8890Srs135747 if (nvlist_add_int32(attr_list, DDI_DRIVER_MAJOR, 96158c4f8890Srs135747 (int32_t)ddi_driver_major(dip)) != DDI_SUCCESS) { 96168c4f8890Srs135747 goto error; 96178c4f8890Srs135747 } 96188c4f8890Srs135747 96198c4f8890Srs135747 if (nvlist_add_int32(attr_list, DDI_INSTANCE, 96208c4f8890Srs135747 (int32_t)ddi_get_instance(dip)) != DDI_SUCCESS) { 96218c4f8890Srs135747 goto error; 96228c4f8890Srs135747 } 96238c4f8890Srs135747 96248c4f8890Srs135747 if (nvlist_add_string(attr_list, DDI_PATHNAME, 96258c4f8890Srs135747 path_name) != DDI_SUCCESS) { 96268c4f8890Srs135747 goto error; 96278c4f8890Srs135747 } 96288c4f8890Srs135747 96298c4f8890Srs135747 if (nvlist_add_string(attr_list, DDI_CLASS, 96308c4f8890Srs135747 ph_vh_class) != DDI_SUCCESS) { 96318c4f8890Srs135747 goto error; 96328c4f8890Srs135747 } 96338c4f8890Srs135747 96348c4f8890Srs135747 (void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_DDI, subclass, 96358c4f8890Srs135747 attr_list, NULL, DDI_SLEEP); 96368c4f8890Srs135747 96378c4f8890Srs135747 error: 96388c4f8890Srs135747 kmem_free(path_name, MAXPATHLEN); 96398c4f8890Srs135747 nvlist_free(attr_list); 96408c4f8890Srs135747 return; 96418c4f8890Srs135747 96428c4f8890Srs135747 alloc_failed: 96434c06356bSdh142964 MDI_DEBUG(1, (MDI_WARN, dip, "!unable to send sysevent")); 96448c4f8890Srs135747 } 9645f7209cf2Spramodbg 9646f7209cf2Spramodbg char ** 9647f7209cf2Spramodbg mdi_get_phci_driver_list(char *vhci_class, int *ndrivers) 9648f7209cf2Spramodbg { 9649f7209cf2Spramodbg char **driver_list, **ret_driver_list = NULL; 9650f7209cf2Spramodbg int *root_support_list; 9651f7209cf2Spramodbg int cur_elements, max_elements; 9652f7209cf2Spramodbg 9653f7209cf2Spramodbg get_phci_driver_list(vhci_class, &driver_list, &root_support_list, 9654f7209cf2Spramodbg &cur_elements, &max_elements); 9655f7209cf2Spramodbg 9656f7209cf2Spramodbg 9657f7209cf2Spramodbg if (driver_list) { 9658f7209cf2Spramodbg kmem_free(root_support_list, sizeof (int) * max_elements); 9659f7209cf2Spramodbg ret_driver_list = mdi_realloc(driver_list, sizeof (char *) 9660f7209cf2Spramodbg * max_elements, sizeof (char *) * cur_elements); 9661f7209cf2Spramodbg } 9662f7209cf2Spramodbg *ndrivers = cur_elements; 9663f7209cf2Spramodbg 9664f7209cf2Spramodbg return (ret_driver_list); 9665f7209cf2Spramodbg 9666f7209cf2Spramodbg } 9667f7209cf2Spramodbg 9668f7209cf2Spramodbg void 9669f7209cf2Spramodbg mdi_free_phci_driver_list(char **driver_list, int ndrivers) 9670f7209cf2Spramodbg { 9671f7209cf2Spramodbg char **p; 9672f7209cf2Spramodbg int i; 9673f7209cf2Spramodbg 9674f7209cf2Spramodbg if (driver_list) { 9675f7209cf2Spramodbg for (i = 0, p = driver_list; i < ndrivers; i++, p++) 9676f7209cf2Spramodbg kmem_free(*p, strlen(*p) + 1); 9677f7209cf2Spramodbg kmem_free(driver_list, sizeof (char *) * ndrivers); 9678f7209cf2Spramodbg } 9679f7209cf2Spramodbg } 968055e592a2SRandall Ralphs 968155e592a2SRandall Ralphs /* 968255e592a2SRandall Ralphs * mdi_is_dev_supported(): 968355e592a2SRandall Ralphs * function called by pHCI bus config operation to determine if a 968455e592a2SRandall Ralphs * device should be represented as a child of the vHCI or the 968555e592a2SRandall Ralphs * pHCI. This decision is made by the vHCI, using cinfo idenity 968655e592a2SRandall Ralphs * information passed by the pHCI - specifics of the cinfo 968755e592a2SRandall Ralphs * representation are by agreement between the pHCI and vHCI. 968855e592a2SRandall Ralphs * Return Values: 968955e592a2SRandall Ralphs * MDI_SUCCESS 969055e592a2SRandall Ralphs * MDI_FAILURE 969155e592a2SRandall Ralphs */ 969255e592a2SRandall Ralphs int 969355e592a2SRandall Ralphs mdi_is_dev_supported(char *class, dev_info_t *pdip, void *cinfo) 969455e592a2SRandall Ralphs { 969555e592a2SRandall Ralphs mdi_vhci_t *vh; 969655e592a2SRandall Ralphs 969755e592a2SRandall Ralphs ASSERT(class && pdip); 969855e592a2SRandall Ralphs 969955e592a2SRandall Ralphs /* 970055e592a2SRandall Ralphs * For dev_supported, mdi_phci_register() must have established pdip as 970155e592a2SRandall Ralphs * a pHCI. 970255e592a2SRandall Ralphs * 970355e592a2SRandall Ralphs * NOTE: mdi_phci_register() does "mpxio-disable" processing, and 970455e592a2SRandall Ralphs * MDI_PHCI(pdip) will return false if mpxio is disabled. 970555e592a2SRandall Ralphs */ 970655e592a2SRandall Ralphs if (!MDI_PHCI(pdip)) 970755e592a2SRandall Ralphs return (MDI_FAILURE); 970855e592a2SRandall Ralphs 970955e592a2SRandall Ralphs /* Return MDI_FAILURE if vHCI does not support asking the question. */ 971055e592a2SRandall Ralphs vh = (mdi_vhci_t *)i_mdi_vhci_class2vhci(class); 971155e592a2SRandall Ralphs if ((vh == NULL) || (vh->vh_ops->vo_is_dev_supported == NULL)) { 971255e592a2SRandall Ralphs return (MDI_FAILURE); 971355e592a2SRandall Ralphs } 971455e592a2SRandall Ralphs 971555e592a2SRandall Ralphs /* Return vHCI answer */ 971655e592a2SRandall Ralphs return (vh->vh_ops->vo_is_dev_supported(vh->vh_dip, pdip, cinfo)); 971755e592a2SRandall Ralphs } 971855e592a2SRandall Ralphs 971955e592a2SRandall Ralphs int 972055e592a2SRandall Ralphs mdi_dc_return_dev_state(mdi_pathinfo_t *pip, struct devctl_iocdata *dcp) 972155e592a2SRandall Ralphs { 972255e592a2SRandall Ralphs uint_t devstate = 0; 972355e592a2SRandall Ralphs dev_info_t *cdip; 972455e592a2SRandall Ralphs 972555e592a2SRandall Ralphs if ((pip == NULL) || (dcp == NULL)) 972655e592a2SRandall Ralphs return (MDI_FAILURE); 972755e592a2SRandall Ralphs 972855e592a2SRandall Ralphs cdip = mdi_pi_get_client(pip); 972955e592a2SRandall Ralphs 973055e592a2SRandall Ralphs switch (mdi_pi_get_state(pip)) { 973155e592a2SRandall Ralphs case MDI_PATHINFO_STATE_INIT: 973255e592a2SRandall Ralphs devstate = DEVICE_DOWN; 973355e592a2SRandall Ralphs break; 973455e592a2SRandall Ralphs case MDI_PATHINFO_STATE_ONLINE: 973555e592a2SRandall Ralphs devstate = DEVICE_ONLINE; 973655e592a2SRandall Ralphs if ((cdip) && (devi_stillreferenced(cdip) == DEVI_REFERENCED)) 973755e592a2SRandall Ralphs devstate |= DEVICE_BUSY; 973855e592a2SRandall Ralphs break; 973955e592a2SRandall Ralphs case MDI_PATHINFO_STATE_STANDBY: 974055e592a2SRandall Ralphs devstate = DEVICE_ONLINE; 974155e592a2SRandall Ralphs break; 974255e592a2SRandall Ralphs case MDI_PATHINFO_STATE_FAULT: 974355e592a2SRandall Ralphs devstate = DEVICE_DOWN; 974455e592a2SRandall Ralphs break; 974555e592a2SRandall Ralphs case MDI_PATHINFO_STATE_OFFLINE: 974655e592a2SRandall Ralphs devstate = DEVICE_OFFLINE; 974755e592a2SRandall Ralphs break; 974855e592a2SRandall Ralphs default: 974955e592a2SRandall Ralphs ASSERT(MDI_PI(pip)->pi_state); 975055e592a2SRandall Ralphs } 975155e592a2SRandall Ralphs 975255e592a2SRandall Ralphs if (copyout(&devstate, dcp->cpyout_buf, sizeof (uint_t)) != 0) 975355e592a2SRandall Ralphs return (MDI_FAILURE); 975455e592a2SRandall Ralphs 975555e592a2SRandall Ralphs return (MDI_SUCCESS); 975655e592a2SRandall Ralphs } 9757