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 /* 22602ca9eaScth * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Multipath driver interface (MDI) implementation; see mdi_impl.h for a more 287c478bd9Sstevel@tonic-gate * detailed discussion of the overall mpxio architecture. 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * Default locking order: 317c478bd9Sstevel@tonic-gate * 325e3986cbScth * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_phci_mutex); 335e3986cbScth * _NOTE(LOCK_ORDER(mdi_mutex, mdi_vhci:vh_client_mutex); 345e3986cbScth * _NOTE(LOCK_ORDER(mdi_vhci:vh_phci_mutex, mdi_phci::ph_mutex); 355e3986cbScth * _NOTE(LOCK_ORDER(mdi_vhci:vh_client_mutex, mdi_client::ct_mutex); 367c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 377c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex)) 387c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <sys/note.h> 427c478bd9Sstevel@tonic-gate #include <sys/types.h> 437c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 447c478bd9Sstevel@tonic-gate #include <sys/param.h> 457c478bd9Sstevel@tonic-gate #include <sys/errno.h> 467c478bd9Sstevel@tonic-gate #include <sys/uio.h> 477c478bd9Sstevel@tonic-gate #include <sys/buf.h> 487c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 497c478bd9Sstevel@tonic-gate #include <sys/open.h> 507c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 517c478bd9Sstevel@tonic-gate #include <sys/poll.h> 527c478bd9Sstevel@tonic-gate #include <sys/conf.h> 537c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 557c478bd9Sstevel@tonic-gate #include <sys/stat.h> 567c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 577c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 587c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h> 597c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 607c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 617c478bd9Sstevel@tonic-gate #include <sys/promif.h> 627c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h> 637c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h> 647c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 657c478bd9Sstevel@tonic-gate #include <sys/epm.h> 667c478bd9Sstevel@tonic-gate #include <sys/sunpm.h> 673c34adc5Sramat #include <sys/modhash.h> 688c4f8890Srs135747 #include <sys/disp.h> 698c4f8890Srs135747 #include <sys/autoconf.h> 70f7209cf2Spramodbg #include <sys/sysmacros.h> 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #ifdef DEBUG 737c478bd9Sstevel@tonic-gate #include <sys/debug.h> 747c478bd9Sstevel@tonic-gate int mdi_debug = 1; 755e3986cbScth int mdi_debug_logonly = 0; 767c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) \ 777c478bd9Sstevel@tonic-gate if (mdi_debug >= (level)) i_mdi_log stmnt 787c478bd9Sstevel@tonic-gate static void i_mdi_log(int, dev_info_t *, const char *fmt, ...); 797c478bd9Sstevel@tonic-gate #else /* !DEBUG */ 807c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) 817c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; 847c478bd9Sstevel@tonic-gate extern int modrootloaded; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * Global mutex: 885e3986cbScth * Protects vHCI list and structure members. 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate kmutex_t mdi_mutex; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * Registered vHCI class driver lists 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate int mdi_vhci_count; 967c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_head; 977c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_tail; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate /* 1007c478bd9Sstevel@tonic-gate * Client Hash Table size 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate static int mdi_client_table_size = CLIENT_HASH_TABLE_SIZE; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* 1057c478bd9Sstevel@tonic-gate * taskq interface definitions 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate #define MDI_TASKQ_N_THREADS 8 1087c478bd9Sstevel@tonic-gate #define MDI_TASKQ_PRI minclsyspri 1097c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MINALLOC (4*mdi_taskq_n_threads) 1107c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MAXALLOC (500*mdi_taskq_n_threads) 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate taskq_t *mdi_taskq; 1137c478bd9Sstevel@tonic-gate static uint_t mdi_taskq_n_threads = MDI_TASKQ_N_THREADS; 1147c478bd9Sstevel@tonic-gate 1153c34adc5Sramat #define TICKS_PER_SECOND (drv_usectohz(1000000)) 1163c34adc5Sramat 1177c478bd9Sstevel@tonic-gate /* 1183c34adc5Sramat * The data should be "quiet" for this interval (in seconds) before the 1193c34adc5Sramat * vhci cached data is flushed to the disk. 1207c478bd9Sstevel@tonic-gate */ 1213c34adc5Sramat static int mdi_vhcache_flush_delay = 10; 1223c34adc5Sramat 1233c34adc5Sramat /* number of seconds the vhcache flush daemon will sleep idle before exiting */ 1243c34adc5Sramat static int mdi_vhcache_flush_daemon_idle_time = 60; 1253c34adc5Sramat 1263c34adc5Sramat /* 12767e56d35Sramat * MDI falls back to discovery of all paths when a bus_config_one fails. 12867e56d35Sramat * The following parameters can be used to tune this operation. 12967e56d35Sramat * 13067e56d35Sramat * mdi_path_discovery_boot 13167e56d35Sramat * Number of times path discovery will be attempted during early boot. 13267e56d35Sramat * Probably there is no reason to ever set this value to greater than one. 13367e56d35Sramat * 13467e56d35Sramat * mdi_path_discovery_postboot 13567e56d35Sramat * Number of times path discovery will be attempted after early boot. 13667e56d35Sramat * Set it to a minimum of two to allow for discovery of iscsi paths which 13767e56d35Sramat * may happen very late during booting. 13867e56d35Sramat * 13967e56d35Sramat * mdi_path_discovery_interval 14067e56d35Sramat * Minimum number of seconds MDI will wait between successive discovery 14167e56d35Sramat * of all paths. Set it to -1 to disable discovery of all paths. 14267e56d35Sramat */ 14367e56d35Sramat static int mdi_path_discovery_boot = 1; 14467e56d35Sramat static int mdi_path_discovery_postboot = 2; 14567e56d35Sramat static int mdi_path_discovery_interval = 10; 14667e56d35Sramat 14767e56d35Sramat /* 1483c34adc5Sramat * number of seconds the asynchronous configuration thread will sleep idle 1493c34adc5Sramat * before exiting. 1503c34adc5Sramat */ 1513c34adc5Sramat static int mdi_async_config_idle_time = 600; 1523c34adc5Sramat 1533c34adc5Sramat static int mdi_bus_config_cache_hash_size = 256; 1543c34adc5Sramat 1553c34adc5Sramat /* turns off multithreaded configuration for certain operations */ 1563c34adc5Sramat static int mdi_mtc_off = 0; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* 159602ca9eaScth * The "path" to a pathinfo node is identical to the /devices path to a 160602ca9eaScth * devinfo node had the device been enumerated under a pHCI instead of 161602ca9eaScth * a vHCI. This pathinfo "path" is associated with a 'path_instance'. 162602ca9eaScth * This association persists across create/delete of the pathinfo nodes, 163602ca9eaScth * but not across reboot. 164602ca9eaScth */ 165602ca9eaScth static uint_t mdi_pathmap_instance = 1; /* 0 -> any path */ 166602ca9eaScth static int mdi_pathmap_hash_size = 256; 167602ca9eaScth static kmutex_t mdi_pathmap_mutex; 168602ca9eaScth static mod_hash_t *mdi_pathmap_bypath; /* "path"->instance */ 169602ca9eaScth static mod_hash_t *mdi_pathmap_byinstance; /* instance->"path" */ 170602ca9eaScth 171602ca9eaScth /* 1727c478bd9Sstevel@tonic-gate * MDI component property name/value string definitions 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate const char *mdi_component_prop = "mpxio-component"; 1757c478bd9Sstevel@tonic-gate const char *mdi_component_prop_vhci = "vhci"; 1767c478bd9Sstevel@tonic-gate const char *mdi_component_prop_phci = "phci"; 1777c478bd9Sstevel@tonic-gate const char *mdi_component_prop_client = "client"; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * MDI client global unique identifier property name 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate const char *mdi_client_guid_prop = "client-guid"; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * MDI client load balancing property name/value string definitions 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate const char *mdi_load_balance = "load-balance"; 1887c478bd9Sstevel@tonic-gate const char *mdi_load_balance_none = "none"; 1897c478bd9Sstevel@tonic-gate const char *mdi_load_balance_rr = "round-robin"; 1907c478bd9Sstevel@tonic-gate const char *mdi_load_balance_lba = "logical-block"; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * Obsolete vHCI class definition; to be removed after Leadville update 1947c478bd9Sstevel@tonic-gate */ 1957c478bd9Sstevel@tonic-gate const char *mdi_vhci_class_scsi = MDI_HCI_CLASS_SCSI; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate static char vhci_greeting[] = 1987c478bd9Sstevel@tonic-gate "\tThere already exists one vHCI driver for class %s\n" 1997c478bd9Sstevel@tonic-gate "\tOnly one vHCI driver for each class is allowed\n"; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * Static function prototypes 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate static int i_mdi_phci_offline(dev_info_t *, uint_t); 2057c478bd9Sstevel@tonic-gate static int i_mdi_client_offline(dev_info_t *, uint_t); 2067c478bd9Sstevel@tonic-gate static int i_mdi_phci_pre_detach(dev_info_t *, ddi_detach_cmd_t); 2077c478bd9Sstevel@tonic-gate static void i_mdi_phci_post_detach(dev_info_t *, 2087c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 2097c478bd9Sstevel@tonic-gate static int i_mdi_client_pre_detach(dev_info_t *, 2107c478bd9Sstevel@tonic-gate ddi_detach_cmd_t); 2117c478bd9Sstevel@tonic-gate static void i_mdi_client_post_detach(dev_info_t *, 2127c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 2137c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_pip(mdi_pathinfo_t *); 2147c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_pip(mdi_pathinfo_t *); 2157c478bd9Sstevel@tonic-gate static int i_mdi_lba_lb(mdi_client_t *ct, 2167c478bd9Sstevel@tonic-gate mdi_pathinfo_t **ret_pip, struct buf *buf); 2177c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_client(mdi_client_t *, int); 2187c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_client(mdi_client_t *, int); 2197c478bd9Sstevel@tonic-gate static void i_mdi_pm_reset_client(mdi_client_t *); 2207c478bd9Sstevel@tonic-gate static int i_mdi_power_all_phci(mdi_client_t *); 2218c4f8890Srs135747 static void i_mdi_log_sysevent(dev_info_t *, char *, char *); 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Internal mdi_pathinfo node functions 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate static void i_mdi_pi_kstat_destroy(mdi_pathinfo_t *); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_mdi_vhci_class2vhci(char *); 2307c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_devi_get_vhci(dev_info_t *); 2317c478bd9Sstevel@tonic-gate static mdi_phci_t *i_devi_get_phci(dev_info_t *); 2327c478bd9Sstevel@tonic-gate static void i_mdi_phci_lock(mdi_phci_t *, mdi_pathinfo_t *); 2337c478bd9Sstevel@tonic-gate static void i_mdi_phci_unlock(mdi_phci_t *); 2343c34adc5Sramat static mdi_pathinfo_t *i_mdi_pi_alloc(mdi_phci_t *, char *, mdi_client_t *); 2357c478bd9Sstevel@tonic-gate static void i_mdi_phci_add_path(mdi_phci_t *, mdi_pathinfo_t *); 2367c478bd9Sstevel@tonic-gate static void i_mdi_client_add_path(mdi_client_t *, mdi_pathinfo_t *); 2377c478bd9Sstevel@tonic-gate static void i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *, 2387c478bd9Sstevel@tonic-gate mdi_client_t *); 2397c478bd9Sstevel@tonic-gate static void i_mdi_phci_remove_path(mdi_phci_t *, mdi_pathinfo_t *); 2407c478bd9Sstevel@tonic-gate static void i_mdi_client_remove_path(mdi_client_t *, 2417c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate static int i_mdi_pi_state_change(mdi_pathinfo_t *, 2447c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t, int); 2457c478bd9Sstevel@tonic-gate static int i_mdi_pi_offline(mdi_pathinfo_t *, int); 2467c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_create(mdi_vhci_t *, char *, char *, 2473c34adc5Sramat char **, int); 2487c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_find(mdi_vhci_t *, char *, char *); 2497c478bd9Sstevel@tonic-gate static int i_mdi_devinfo_remove(dev_info_t *, dev_info_t *, int); 2507c478bd9Sstevel@tonic-gate static int i_mdi_is_child_present(dev_info_t *, dev_info_t *); 2513c34adc5Sramat static mdi_client_t *i_mdi_client_alloc(mdi_vhci_t *, char *, char *); 2527c478bd9Sstevel@tonic-gate static void i_mdi_client_enlist_table(mdi_vhci_t *, mdi_client_t *); 2537c478bd9Sstevel@tonic-gate static void i_mdi_client_delist_table(mdi_vhci_t *, mdi_client_t *); 2543c34adc5Sramat static mdi_client_t *i_mdi_client_find(mdi_vhci_t *, char *, char *); 2557c478bd9Sstevel@tonic-gate static void i_mdi_client_update_state(mdi_client_t *); 2567c478bd9Sstevel@tonic-gate static int i_mdi_client_compute_state(mdi_client_t *, 2577c478bd9Sstevel@tonic-gate mdi_phci_t *); 2587c478bd9Sstevel@tonic-gate static void i_mdi_client_lock(mdi_client_t *, mdi_pathinfo_t *); 2597c478bd9Sstevel@tonic-gate static void i_mdi_client_unlock(mdi_client_t *); 2607c478bd9Sstevel@tonic-gate static int i_mdi_client_free(mdi_vhci_t *, mdi_client_t *); 2617c478bd9Sstevel@tonic-gate static mdi_client_t *i_devi_get_client(dev_info_t *); 262ee28b439Scm136836 /* 263ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 264ee28b439Scm136836 * mdi_{enable,disable}_path interfaces 265ee28b439Scm136836 */ 266ee28b439Scm136836 static int i_mdi_pi_enable_disable(dev_info_t *, dev_info_t *, 267ee28b439Scm136836 int, int); 268ee28b439Scm136836 static mdi_pathinfo_t *i_mdi_enable_disable_path(mdi_pathinfo_t *pip, 269ee28b439Scm136836 mdi_vhci_t *vh, int flags, int op); 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * Failover related function prototypes 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate static int i_mdi_failover(void *); 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * misc internal functions 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate static int i_mdi_get_hash_key(char *); 2797c478bd9Sstevel@tonic-gate static int i_map_nvlist_error_to_mdi(int); 2807c478bd9Sstevel@tonic-gate static void i_mdi_report_path_state(mdi_client_t *, 2817c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 2827c478bd9Sstevel@tonic-gate 2833c34adc5Sramat static void setup_vhci_cache(mdi_vhci_t *); 2843c34adc5Sramat static int destroy_vhci_cache(mdi_vhci_t *); 2853c34adc5Sramat static int stop_vhcache_async_threads(mdi_vhci_config_t *); 2863c34adc5Sramat static boolean_t stop_vhcache_flush_thread(void *, int); 2873c34adc5Sramat static void free_string_array(char **, int); 2883c34adc5Sramat static void free_vhcache_phci(mdi_vhcache_phci_t *); 2893c34adc5Sramat static void free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *); 2903c34adc5Sramat static void free_vhcache_client(mdi_vhcache_client_t *); 2913c34adc5Sramat static int mainnvl_to_vhcache(mdi_vhci_cache_t *, nvlist_t *); 2923c34adc5Sramat static nvlist_t *vhcache_to_mainnvl(mdi_vhci_cache_t *); 2933c34adc5Sramat static void vhcache_phci_add(mdi_vhci_config_t *, mdi_phci_t *); 2943c34adc5Sramat static void vhcache_phci_remove(mdi_vhci_config_t *, mdi_phci_t *); 2953c34adc5Sramat static void vhcache_pi_add(mdi_vhci_config_t *, 2963c34adc5Sramat struct mdi_pathinfo *); 2973c34adc5Sramat static void vhcache_pi_remove(mdi_vhci_config_t *, 2983c34adc5Sramat struct mdi_pathinfo *); 2993c34adc5Sramat static void free_phclient_path_list(mdi_phys_path_t *); 3003c34adc5Sramat static void sort_vhcache_paths(mdi_vhcache_client_t *); 3013c34adc5Sramat static int flush_vhcache(mdi_vhci_config_t *, int); 3023c34adc5Sramat static void vhcache_dirty(mdi_vhci_config_t *); 3033c34adc5Sramat static void free_async_client_config(mdi_async_client_config_t *); 30467e56d35Sramat static void single_threaded_vhconfig_enter(mdi_vhci_config_t *); 30567e56d35Sramat static void single_threaded_vhconfig_exit(mdi_vhci_config_t *); 3063c34adc5Sramat static nvlist_t *read_on_disk_vhci_cache(char *); 3073c34adc5Sramat extern int fread_nvlist(char *, nvlist_t **); 3083c34adc5Sramat extern int fwrite_nvlist(char *, nvlist_t *); 3093c34adc5Sramat 3107c478bd9Sstevel@tonic-gate /* called once when first vhci registers with mdi */ 3117c478bd9Sstevel@tonic-gate static void 3127c478bd9Sstevel@tonic-gate i_mdi_init() 3137c478bd9Sstevel@tonic-gate { 3147c478bd9Sstevel@tonic-gate static int initialized = 0; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate if (initialized) 3177c478bd9Sstevel@tonic-gate return; 3187c478bd9Sstevel@tonic-gate initialized = 1; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate mutex_init(&mdi_mutex, NULL, MUTEX_DEFAULT, NULL); 321602ca9eaScth 322602ca9eaScth /* Create our taskq resources */ 3237c478bd9Sstevel@tonic-gate mdi_taskq = taskq_create("mdi_taskq", mdi_taskq_n_threads, 3247c478bd9Sstevel@tonic-gate MDI_TASKQ_PRI, MDI_TASKQ_MINALLOC, MDI_TASKQ_MAXALLOC, 3257c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE | TASKQ_CPR_SAFE); 3267c478bd9Sstevel@tonic-gate ASSERT(mdi_taskq != NULL); /* taskq_create never fails */ 327602ca9eaScth 328602ca9eaScth /* Allocate ['path_instance' <-> "path"] maps */ 329602ca9eaScth mutex_init(&mdi_pathmap_mutex, NULL, MUTEX_DRIVER, NULL); 330602ca9eaScth mdi_pathmap_bypath = mod_hash_create_strhash( 331602ca9eaScth "mdi_pathmap_bypath", mdi_pathmap_hash_size, 332602ca9eaScth mod_hash_null_valdtor); 333602ca9eaScth mdi_pathmap_byinstance = mod_hash_create_idhash( 334602ca9eaScth "mdi_pathmap_byinstance", mdi_pathmap_hash_size, 335602ca9eaScth mod_hash_null_valdtor); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * mdi_get_component_type(): 3407c478bd9Sstevel@tonic-gate * Return mpxio component type 3417c478bd9Sstevel@tonic-gate * Return Values: 3427c478bd9Sstevel@tonic-gate * MDI_COMPONENT_NONE 3437c478bd9Sstevel@tonic-gate * MDI_COMPONENT_VHCI 3447c478bd9Sstevel@tonic-gate * MDI_COMPONENT_PHCI 3457c478bd9Sstevel@tonic-gate * MDI_COMPONENT_CLIENT 3467c478bd9Sstevel@tonic-gate * XXX This doesn't work under multi-level MPxIO and should be 3475e3986cbScth * removed when clients migrate mdi_component_is_*() interfaces. 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate int 3507c478bd9Sstevel@tonic-gate mdi_get_component_type(dev_info_t *dip) 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate return (DEVI(dip)->devi_mdi_component); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * mdi_vhci_register(): 3577c478bd9Sstevel@tonic-gate * Register a vHCI module with the mpxio framework 3587c478bd9Sstevel@tonic-gate * mdi_vhci_register() is called by vHCI drivers to register the 3597c478bd9Sstevel@tonic-gate * 'class_driver' vHCI driver and its MDI entrypoints with the 3607c478bd9Sstevel@tonic-gate * mpxio framework. The vHCI driver must call this interface as 3617c478bd9Sstevel@tonic-gate * part of its attach(9e) handler. 3627c478bd9Sstevel@tonic-gate * Competing threads may try to attach mdi_vhci_register() as 3637c478bd9Sstevel@tonic-gate * the vHCI drivers are loaded and attached as a result of pHCI 3647c478bd9Sstevel@tonic-gate * driver instance registration (mdi_phci_register()) with the 3657c478bd9Sstevel@tonic-gate * framework. 3667c478bd9Sstevel@tonic-gate * Return Values: 3677c478bd9Sstevel@tonic-gate * MDI_SUCCESS 3687c478bd9Sstevel@tonic-gate * MDI_FAILURE 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3717c478bd9Sstevel@tonic-gate int 3727c478bd9Sstevel@tonic-gate mdi_vhci_register(char *class, dev_info_t *vdip, mdi_vhci_ops_t *vops, 3737c478bd9Sstevel@tonic-gate int flags) 3747c478bd9Sstevel@tonic-gate { 3757c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate ASSERT(vops->vo_revision == MDI_VHCI_OPS_REV); 378*00a3eaf3SRamaswamy Tummala #ifdef DEBUG 379*00a3eaf3SRamaswamy Tummala /* 380*00a3eaf3SRamaswamy Tummala * IB nexus driver is loaded only when IB hardware is present. 381*00a3eaf3SRamaswamy Tummala * In order to be able to do this there is a need to drive the loading 382*00a3eaf3SRamaswamy Tummala * and attaching of the IB nexus driver (especially when an IB hardware 383*00a3eaf3SRamaswamy Tummala * is dynamically plugged in) when an IB HCA driver (PHCI) 384*00a3eaf3SRamaswamy Tummala * is being attached. Unfortunately this gets into the limitations 385*00a3eaf3SRamaswamy Tummala * of devfs as there seems to be no clean way to drive configuration 386*00a3eaf3SRamaswamy Tummala * of a subtree from another subtree of a devfs. Hence, do not ASSERT 387*00a3eaf3SRamaswamy Tummala * for IB. 388*00a3eaf3SRamaswamy Tummala */ 389*00a3eaf3SRamaswamy Tummala if (strcmp(class, MDI_HCI_CLASS_IB) != 0) 3905e3986cbScth ASSERT(DEVI_BUSY_OWNED(ddi_get_parent(vdip))); 391*00a3eaf3SRamaswamy Tummala #endif 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate i_mdi_init(); 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * Scan for already registered vhci 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 4007c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * vHCI has already been created. Check for valid 4037c478bd9Sstevel@tonic-gate * vHCI ops registration. We only support one vHCI 4047c478bd9Sstevel@tonic-gate * module per class 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate if (vh->vh_ops != NULL) { 4077c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4087c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, vhci_greeting, class); 4097c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate break; 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* 4167c478bd9Sstevel@tonic-gate * if not yet created, create the vHCI component 4177c478bd9Sstevel@tonic-gate */ 4187c478bd9Sstevel@tonic-gate if (vh == NULL) { 4197c478bd9Sstevel@tonic-gate struct client_hash *hash = NULL; 4207c478bd9Sstevel@tonic-gate char *load_balance; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* 4237c478bd9Sstevel@tonic-gate * Allocate and initialize the mdi extensions 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate vh = kmem_zalloc(sizeof (mdi_vhci_t), KM_SLEEP); 4267c478bd9Sstevel@tonic-gate hash = kmem_zalloc(mdi_client_table_size * sizeof (*hash), 4277c478bd9Sstevel@tonic-gate KM_SLEEP); 4287c478bd9Sstevel@tonic-gate vh->vh_client_table = hash; 4297c478bd9Sstevel@tonic-gate vh->vh_class = kmem_zalloc(strlen(class) + 1, KM_SLEEP); 4307c478bd9Sstevel@tonic-gate (void) strcpy(vh->vh_class, class); 4317c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_RR; 4327c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vdip, 4337c478bd9Sstevel@tonic-gate 0, LOAD_BALANCE_PROP, &load_balance) == DDI_SUCCESS) { 4347c478bd9Sstevel@tonic-gate if (strcmp(load_balance, LOAD_BALANCE_PROP_NONE) == 0) { 4357c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_NONE; 4367c478bd9Sstevel@tonic-gate } else if (strcmp(load_balance, LOAD_BALANCE_PROP_LBA) 4377c478bd9Sstevel@tonic-gate == 0) { 4387c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_LBA; 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate ddi_prop_free(load_balance); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4435e3986cbScth mutex_init(&vh->vh_phci_mutex, NULL, MUTEX_DEFAULT, NULL); 4445e3986cbScth mutex_init(&vh->vh_client_mutex, NULL, MUTEX_DEFAULT, NULL); 4455e3986cbScth 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * Store the vHCI ops vectors 4487c478bd9Sstevel@tonic-gate */ 4497c478bd9Sstevel@tonic-gate vh->vh_dip = vdip; 4507c478bd9Sstevel@tonic-gate vh->vh_ops = vops; 4517c478bd9Sstevel@tonic-gate 4523c34adc5Sramat setup_vhci_cache(vh); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if (mdi_vhci_head == NULL) { 4557c478bd9Sstevel@tonic-gate mdi_vhci_head = vh; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate if (mdi_vhci_tail) { 4587c478bd9Sstevel@tonic-gate mdi_vhci_tail->vh_next = vh; 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate mdi_vhci_tail = vh; 4617c478bd9Sstevel@tonic-gate mdi_vhci_count++; 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * Claim the devfs node as a vhci component 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component |= MDI_COMPONENT_VHCI; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* 4707c478bd9Sstevel@tonic-gate * Initialize our back reference from dev_info node 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = (caddr_t)vh; 4737c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4747c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * mdi_vhci_unregister(): 4797c478bd9Sstevel@tonic-gate * Unregister a vHCI module from mpxio framework 4807c478bd9Sstevel@tonic-gate * mdi_vhci_unregister() is called from the detach(9E) entrypoint 4817c478bd9Sstevel@tonic-gate * of a vhci to unregister it from the framework. 4827c478bd9Sstevel@tonic-gate * Return Values: 4837c478bd9Sstevel@tonic-gate * MDI_SUCCESS 4847c478bd9Sstevel@tonic-gate * MDI_FAILURE 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4877c478bd9Sstevel@tonic-gate int 4887c478bd9Sstevel@tonic-gate mdi_vhci_unregister(dev_info_t *vdip, int flags) 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate mdi_vhci_t *found, *vh, *prev = NULL; 4917c478bd9Sstevel@tonic-gate 4925e3986cbScth ASSERT(DEVI_BUSY_OWNED(ddi_get_parent(vdip))); 4935e3986cbScth 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * Check for invalid VHCI 4967c478bd9Sstevel@tonic-gate */ 4977c478bd9Sstevel@tonic-gate if ((vh = i_devi_get_vhci(vdip)) == NULL) 4987c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Scan the list of registered vHCIs for a match 5027c478bd9Sstevel@tonic-gate */ 5035e3986cbScth mutex_enter(&mdi_mutex); 5047c478bd9Sstevel@tonic-gate for (found = mdi_vhci_head; found != NULL; found = found->vh_next) { 5057c478bd9Sstevel@tonic-gate if (found == vh) 5067c478bd9Sstevel@tonic-gate break; 5077c478bd9Sstevel@tonic-gate prev = found; 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate if (found == NULL) { 5117c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5127c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* 5168c4f8890Srs135747 * Check the vHCI, pHCI and client count. All the pHCIs and clients 5177c478bd9Sstevel@tonic-gate * should have been unregistered, before a vHCI can be 5187c478bd9Sstevel@tonic-gate * unregistered. 5197c478bd9Sstevel@tonic-gate */ 5205e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 5215e3986cbScth if (vh->vh_refcnt || vh->vh_phci_count || vh->vh_client_count) { 5225e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 5235e3986cbScth mutex_exit(&mdi_mutex); 5245e3986cbScth return (MDI_FAILURE); 5255e3986cbScth } 5265e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 5275e3986cbScth 5285e3986cbScth if (destroy_vhci_cache(vh) != MDI_SUCCESS) { 5297c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5307c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* 5347c478bd9Sstevel@tonic-gate * Remove the vHCI from the global list 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_head) { 5377c478bd9Sstevel@tonic-gate mdi_vhci_head = vh->vh_next; 5387c478bd9Sstevel@tonic-gate } else { 5397c478bd9Sstevel@tonic-gate prev->vh_next = vh->vh_next; 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_tail) { 5427c478bd9Sstevel@tonic-gate mdi_vhci_tail = prev; 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate mdi_vhci_count--; 5457c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5463c34adc5Sramat 5473c34adc5Sramat vh->vh_ops = NULL; 5487c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component &= ~MDI_COMPONENT_VHCI; 5497c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = NULL; 5507c478bd9Sstevel@tonic-gate kmem_free(vh->vh_class, strlen(vh->vh_class)+1); 5517c478bd9Sstevel@tonic-gate kmem_free(vh->vh_client_table, 5527c478bd9Sstevel@tonic-gate mdi_client_table_size * sizeof (struct client_hash)); 5535e3986cbScth mutex_destroy(&vh->vh_phci_mutex); 5545e3986cbScth mutex_destroy(&vh->vh_client_mutex); 55578dc6db2Sllai1 5567c478bd9Sstevel@tonic-gate kmem_free(vh, sizeof (mdi_vhci_t)); 5577c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate /* 5617c478bd9Sstevel@tonic-gate * i_mdi_vhci_class2vhci(): 5627c478bd9Sstevel@tonic-gate * Look for a matching vHCI module given a vHCI class name 5637c478bd9Sstevel@tonic-gate * Return Values: 5647c478bd9Sstevel@tonic-gate * Handle to a vHCI component 5657c478bd9Sstevel@tonic-gate * NULL 5667c478bd9Sstevel@tonic-gate */ 5677c478bd9Sstevel@tonic-gate static mdi_vhci_t * 5687c478bd9Sstevel@tonic-gate i_mdi_vhci_class2vhci(char *class) 5697c478bd9Sstevel@tonic-gate { 5707c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&mdi_mutex)); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 5757c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 5767c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 5777c478bd9Sstevel@tonic-gate break; 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5817c478bd9Sstevel@tonic-gate return (vh); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * i_devi_get_vhci(): 5867c478bd9Sstevel@tonic-gate * Utility function to get the handle to a vHCI component 5877c478bd9Sstevel@tonic-gate * Return Values: 5887c478bd9Sstevel@tonic-gate * Handle to a vHCI component 5897c478bd9Sstevel@tonic-gate * NULL 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate mdi_vhci_t * 5927c478bd9Sstevel@tonic-gate i_devi_get_vhci(dev_info_t *vdip) 5937c478bd9Sstevel@tonic-gate { 5947c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 5957c478bd9Sstevel@tonic-gate if (MDI_VHCI(vdip)) { 5967c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci; 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate return (vh); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * mdi_phci_register(): 6037c478bd9Sstevel@tonic-gate * Register a pHCI module with mpxio framework 6047c478bd9Sstevel@tonic-gate * mdi_phci_register() is called by pHCI drivers to register with 6057c478bd9Sstevel@tonic-gate * the mpxio framework and a specific 'class_driver' vHCI. The 6067c478bd9Sstevel@tonic-gate * pHCI driver must call this interface as part of its attach(9e) 6077c478bd9Sstevel@tonic-gate * handler. 6087c478bd9Sstevel@tonic-gate * Return Values: 6097c478bd9Sstevel@tonic-gate * MDI_SUCCESS 6107c478bd9Sstevel@tonic-gate * MDI_FAILURE 6117c478bd9Sstevel@tonic-gate */ 6127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6137c478bd9Sstevel@tonic-gate int 6147c478bd9Sstevel@tonic-gate mdi_phci_register(char *class, dev_info_t *pdip, int flags) 6157c478bd9Sstevel@tonic-gate { 6167c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 6177c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 6187c478bd9Sstevel@tonic-gate char *data; 6197c478bd9Sstevel@tonic-gate char *pathname; 6207c478bd9Sstevel@tonic-gate 6215e3986cbScth /* 6225e3986cbScth * Some subsystems, like fcp, perform pHCI registration from a 6235e3986cbScth * different thread than the one doing the pHCI attach(9E) - the 6245e3986cbScth * driver attach code is waiting for this other thread to complete. 6255e3986cbScth * This means we can only ASSERT DEVI_BUSY_CHANGING of parent 6265e3986cbScth * (indicating that some thread has done an ndi_devi_enter of parent) 6275e3986cbScth * not DEVI_BUSY_OWNED (which would indicate that we did the enter). 6285e3986cbScth */ 6295e3986cbScth ASSERT(DEVI_BUSY_CHANGING(ddi_get_parent(pdip))); 6305e3986cbScth 6317c478bd9Sstevel@tonic-gate pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 6327c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, pathname); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* 6357c478bd9Sstevel@tonic-gate * Check for mpxio-disable property. Enable mpxio if the property is 6367c478bd9Sstevel@tonic-gate * missing or not set to "yes". 6377c478bd9Sstevel@tonic-gate * If the property is set to "yes" then emit a brief message. 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0, "mpxio-disable", 6407c478bd9Sstevel@tonic-gate &data) == DDI_SUCCESS)) { 6417c478bd9Sstevel@tonic-gate if (strcmp(data, "yes") == 0) { 6427c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_CONT, pdip, 6437c478bd9Sstevel@tonic-gate "?%s (%s%d) multipath capabilities " 6447c478bd9Sstevel@tonic-gate "disabled via %s.conf.\n", pathname, 6457c478bd9Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip), 6467c478bd9Sstevel@tonic-gate ddi_driver_name(pdip))); 6477c478bd9Sstevel@tonic-gate ddi_prop_free(data); 6487c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 6497c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate ddi_prop_free(data); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 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; 7147c478bd9Sstevel@tonic-gate 7155e3986cbScth ASSERT(DEVI_BUSY_CHANGING(ddi_get_parent(pdip))); 7165e3986cbScth 7177c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 7187c478bd9Sstevel@tonic-gate if (ph == NULL) { 7197c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 7207c478bd9Sstevel@tonic-gate "!pHCI unregister: 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) { 7277c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 7287c478bd9Sstevel@tonic-gate "!pHCI unregister: Not a valid vHCI")); 7297c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate 7325e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 7337c478bd9Sstevel@tonic-gate tmp = vh->vh_phci_head; 7347c478bd9Sstevel@tonic-gate while (tmp) { 7357c478bd9Sstevel@tonic-gate if (tmp == ph) { 7367c478bd9Sstevel@tonic-gate break; 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate prev = tmp; 7397c478bd9Sstevel@tonic-gate tmp = tmp->ph_next; 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_head) { 7437c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph->ph_next; 7447c478bd9Sstevel@tonic-gate } else { 7457c478bd9Sstevel@tonic-gate prev->ph_next = ph->ph_next; 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_tail) { 7497c478bd9Sstevel@tonic-gate vh->vh_phci_tail = prev; 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate vh->vh_phci_count--; 7535e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 7547c478bd9Sstevel@tonic-gate 7558c4f8890Srs135747 i_mdi_log_sysevent(pdip, ph->ph_vhci->vh_class, 7568c4f8890Srs135747 ESC_DDI_INITIATOR_UNREGISTER); 7573c34adc5Sramat vhcache_phci_remove(vh->vh_config, ph); 7587c478bd9Sstevel@tonic-gate cv_destroy(&ph->ph_unstable_cv); 7597c478bd9Sstevel@tonic-gate mutex_destroy(&ph->ph_mutex); 7607c478bd9Sstevel@tonic-gate kmem_free(ph, sizeof (mdi_phci_t)); 7617c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component &= ~MDI_COMPONENT_PHCI; 7627c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = NULL; 7637c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate /* 7677c478bd9Sstevel@tonic-gate * i_devi_get_phci(): 7687c478bd9Sstevel@tonic-gate * Utility function to return the phci extensions. 7697c478bd9Sstevel@tonic-gate */ 7707c478bd9Sstevel@tonic-gate static mdi_phci_t * 7717c478bd9Sstevel@tonic-gate i_devi_get_phci(dev_info_t *pdip) 7727c478bd9Sstevel@tonic-gate { 7737c478bd9Sstevel@tonic-gate mdi_phci_t *ph = NULL; 7747c478bd9Sstevel@tonic-gate if (MDI_PHCI(pdip)) { 7757c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(pdip)->devi_mdi_xhci; 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate return (ph); 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate /* 7815e3986cbScth * Single thread mdi entry into devinfo node for modifying its children. 7825e3986cbScth * If necessary we perform an ndi_devi_enter of the vHCI before doing 7835e3986cbScth * an ndi_devi_enter of 'dip'. We maintain circular in two parts: one 7845e3986cbScth * for the vHCI and one for the pHCI. 7855e3986cbScth */ 7865e3986cbScth void 7875e3986cbScth mdi_devi_enter(dev_info_t *phci_dip, int *circular) 7885e3986cbScth { 7895e3986cbScth dev_info_t *vdip; 7905e3986cbScth int vcircular, pcircular; 7915e3986cbScth 7925e3986cbScth /* Verify calling context */ 7935e3986cbScth ASSERT(MDI_PHCI(phci_dip)); 7945e3986cbScth vdip = mdi_devi_get_vdip(phci_dip); 7955e3986cbScth ASSERT(vdip); /* A pHCI always has a vHCI */ 7965e3986cbScth 7975e3986cbScth /* 7985e3986cbScth * If pHCI is detaching then the framework has already entered the 7995e3986cbScth * vHCI on a threads that went down the code path leading to 8005e3986cbScth * detach_node(). This framework enter of the vHCI during pHCI 8015e3986cbScth * detach is done to avoid deadlock with vHCI power management 8025e3986cbScth * operations which enter the vHCI and the enter down the path 8035e3986cbScth * to the pHCI. If pHCI is detaching then we piggyback this calls 8045e3986cbScth * enter of the vHCI on frameworks vHCI enter that has already 8055e3986cbScth * occurred - this is OK because we know that the framework thread 8065e3986cbScth * doing detach is waiting for our completion. 8075e3986cbScth * 8085e3986cbScth * We should DEVI_IS_DETACHING under an enter of the parent to avoid 8095e3986cbScth * race with detach - but we can't do that because the framework has 8105e3986cbScth * already entered the parent, so we have some complexity instead. 8115e3986cbScth */ 8125e3986cbScth for (;;) { 8135e3986cbScth if (ndi_devi_tryenter(vdip, &vcircular)) { 8145e3986cbScth ASSERT(vcircular != -1); 8155e3986cbScth if (DEVI_IS_DETACHING(phci_dip)) { 8165e3986cbScth ndi_devi_exit(vdip, vcircular); 8175e3986cbScth vcircular = -1; 8185e3986cbScth } 8195e3986cbScth break; 8205e3986cbScth } else if (DEVI_IS_DETACHING(phci_dip)) { 8215e3986cbScth vcircular = -1; 8225e3986cbScth break; 8235e3986cbScth } else { 8245e3986cbScth delay(1); 8255e3986cbScth } 8265e3986cbScth } 8275e3986cbScth 8285e3986cbScth ndi_devi_enter(phci_dip, &pcircular); 8295e3986cbScth *circular = (vcircular << 16) | (pcircular & 0xFFFF); 8305e3986cbScth } 8315e3986cbScth 8325e3986cbScth /* 8335e3986cbScth * Release mdi_devi_enter or successful mdi_devi_tryenter. 8345e3986cbScth */ 8355e3986cbScth void 8365e3986cbScth mdi_devi_exit(dev_info_t *phci_dip, int circular) 8375e3986cbScth { 8385e3986cbScth dev_info_t *vdip; 8395e3986cbScth int vcircular, pcircular; 8405e3986cbScth 8415e3986cbScth /* Verify calling context */ 8425e3986cbScth ASSERT(MDI_PHCI(phci_dip)); 8435e3986cbScth vdip = mdi_devi_get_vdip(phci_dip); 8445e3986cbScth ASSERT(vdip); /* A pHCI always has a vHCI */ 8455e3986cbScth 8465e3986cbScth /* extract two circular recursion values from single int */ 8475e3986cbScth pcircular = (short)(circular & 0xFFFF); 8485e3986cbScth vcircular = (short)((circular >> 16) & 0xFFFF); 8495e3986cbScth 8505e3986cbScth ndi_devi_exit(phci_dip, pcircular); 8515e3986cbScth if (vcircular != -1) 8525e3986cbScth ndi_devi_exit(vdip, vcircular); 8535e3986cbScth } 8545e3986cbScth 8555e3986cbScth /* 8565e3986cbScth * The functions mdi_devi_exit_phci() and mdi_devi_enter_phci() are used 8575e3986cbScth * around a pHCI drivers calls to mdi_pi_online/offline, after holding 8585e3986cbScth * the pathinfo node via mdi_hold_path/mdi_rele_path, to avoid deadlock 8595e3986cbScth * with vHCI power management code during path online/offline. Each 8605e3986cbScth * mdi_devi_exit_phci must have a matching mdi_devi_enter_phci, and both must 8615e3986cbScth * occur within the scope of an active mdi_devi_enter that establishes the 8625e3986cbScth * circular value. 8635e3986cbScth */ 8645e3986cbScth void 8655e3986cbScth mdi_devi_exit_phci(dev_info_t *phci_dip, int circular) 8665e3986cbScth { 8675e3986cbScth int pcircular; 8685e3986cbScth 8695e3986cbScth /* Verify calling context */ 8705e3986cbScth ASSERT(MDI_PHCI(phci_dip)); 8715e3986cbScth 8725e3986cbScth pcircular = (short)(circular & 0xFFFF); 8735e3986cbScth ndi_devi_exit(phci_dip, pcircular); 8745e3986cbScth } 8755e3986cbScth 8765e3986cbScth void 8775e3986cbScth mdi_devi_enter_phci(dev_info_t *phci_dip, int *circular) 8785e3986cbScth { 8795e3986cbScth int pcircular; 8805e3986cbScth 8815e3986cbScth /* Verify calling context */ 8825e3986cbScth ASSERT(MDI_PHCI(phci_dip)); 8835e3986cbScth 8845e3986cbScth ndi_devi_enter(phci_dip, &pcircular); 8855e3986cbScth 8865e3986cbScth /* verify matching mdi_devi_exit_phci/mdi_devi_enter_phci use */ 8875e3986cbScth ASSERT(pcircular == ((short)(*circular & 0xFFFF))); 8885e3986cbScth } 8895e3986cbScth 8905e3986cbScth /* 8915e3986cbScth * mdi_devi_get_vdip(): 8925e3986cbScth * given a pHCI dip return vHCI dip 8935e3986cbScth */ 8945e3986cbScth dev_info_t * 8955e3986cbScth mdi_devi_get_vdip(dev_info_t *pdip) 8965e3986cbScth { 8975e3986cbScth mdi_phci_t *ph; 8985e3986cbScth 8995e3986cbScth ph = i_devi_get_phci(pdip); 9005e3986cbScth if (ph && ph->ph_vhci) 9015e3986cbScth return (ph->ph_vhci->vh_dip); 9025e3986cbScth return (NULL); 9035e3986cbScth } 9045e3986cbScth 9055e3986cbScth /* 9065e3986cbScth * mdi_devi_pdip_entered(): 9075e3986cbScth * Return 1 if we are vHCI and have done an ndi_devi_enter 9085e3986cbScth * of a pHCI 9095e3986cbScth */ 9105e3986cbScth int 9115e3986cbScth mdi_devi_pdip_entered(dev_info_t *vdip) 9125e3986cbScth { 9135e3986cbScth mdi_vhci_t *vh; 9145e3986cbScth mdi_phci_t *ph; 9155e3986cbScth 9165e3986cbScth vh = i_devi_get_vhci(vdip); 9175e3986cbScth if (vh == NULL) 9185e3986cbScth return (0); 9195e3986cbScth 9205e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 9215e3986cbScth ph = vh->vh_phci_head; 9225e3986cbScth while (ph) { 9235e3986cbScth if (ph->ph_dip && DEVI_BUSY_OWNED(ph->ph_dip)) { 9245e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 9255e3986cbScth return (1); 9265e3986cbScth } 9275e3986cbScth ph = ph->ph_next; 9285e3986cbScth } 9295e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 9305e3986cbScth return (0); 9315e3986cbScth } 9325e3986cbScth 9335e3986cbScth /* 9347c478bd9Sstevel@tonic-gate * mdi_phci_path2devinfo(): 9357c478bd9Sstevel@tonic-gate * Utility function to search for a valid phci device given 9367c478bd9Sstevel@tonic-gate * the devfs pathname. 9377c478bd9Sstevel@tonic-gate */ 9387c478bd9Sstevel@tonic-gate dev_info_t * 9397c478bd9Sstevel@tonic-gate mdi_phci_path2devinfo(dev_info_t *vdip, caddr_t pathname) 9407c478bd9Sstevel@tonic-gate { 9417c478bd9Sstevel@tonic-gate char *temp_pathname; 9427c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 9437c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 9447c478bd9Sstevel@tonic-gate dev_info_t *pdip = NULL; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate vh = i_devi_get_vhci(vdip); 9477c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate if (vh == NULL) { 9507c478bd9Sstevel@tonic-gate /* 9517c478bd9Sstevel@tonic-gate * Invalid vHCI component, return failure 9527c478bd9Sstevel@tonic-gate */ 9537c478bd9Sstevel@tonic-gate return (NULL); 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 9575e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 9587c478bd9Sstevel@tonic-gate ph = vh->vh_phci_head; 9597c478bd9Sstevel@tonic-gate while (ph != NULL) { 9607c478bd9Sstevel@tonic-gate pdip = ph->ph_dip; 9617c478bd9Sstevel@tonic-gate ASSERT(pdip != NULL); 9627c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 9637c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, temp_pathname); 9647c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 9657c478bd9Sstevel@tonic-gate break; 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate ph = ph->ph_next; 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate if (ph == NULL) { 9707c478bd9Sstevel@tonic-gate pdip = NULL; 9717c478bd9Sstevel@tonic-gate } 9725e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 9737c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 9747c478bd9Sstevel@tonic-gate return (pdip); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* 9787c478bd9Sstevel@tonic-gate * mdi_phci_get_path_count(): 9797c478bd9Sstevel@tonic-gate * get number of path information nodes associated with a given 9807c478bd9Sstevel@tonic-gate * pHCI device. 9817c478bd9Sstevel@tonic-gate */ 9827c478bd9Sstevel@tonic-gate int 9837c478bd9Sstevel@tonic-gate mdi_phci_get_path_count(dev_info_t *pdip) 9847c478bd9Sstevel@tonic-gate { 9857c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 9867c478bd9Sstevel@tonic-gate int count = 0; 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 9897c478bd9Sstevel@tonic-gate if (ph != NULL) { 9907c478bd9Sstevel@tonic-gate count = ph->ph_path_count; 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate return (count); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate /* 9967c478bd9Sstevel@tonic-gate * i_mdi_phci_lock(): 9977c478bd9Sstevel@tonic-gate * Lock a pHCI device 9987c478bd9Sstevel@tonic-gate * Return Values: 9997c478bd9Sstevel@tonic-gate * None 10007c478bd9Sstevel@tonic-gate * Note: 10017c478bd9Sstevel@tonic-gate * The default locking order is: 10027c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 10037c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 10047c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 10057c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate static void 10087c478bd9Sstevel@tonic-gate i_mdi_phci_lock(mdi_phci_t *ph, mdi_pathinfo_t *pip) 10097c478bd9Sstevel@tonic-gate { 10107c478bd9Sstevel@tonic-gate if (pip) { 10117c478bd9Sstevel@tonic-gate /* Reverse locking is requested. */ 10127c478bd9Sstevel@tonic-gate while (MDI_PHCI_TRYLOCK(ph) == 0) { 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 10157c478bd9Sstevel@tonic-gate * after a small delay 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 10187c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 10197c478bd9Sstevel@tonic-gate delay(1); 10207c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 10217c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate } else { 10247c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate /* 10297c478bd9Sstevel@tonic-gate * i_mdi_phci_unlock(): 10307c478bd9Sstevel@tonic-gate * Unlock the pHCI component 10317c478bd9Sstevel@tonic-gate */ 10327c478bd9Sstevel@tonic-gate static void 10337c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(mdi_phci_t *ph) 10347c478bd9Sstevel@tonic-gate { 10357c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate /* 10397c478bd9Sstevel@tonic-gate * i_mdi_devinfo_create(): 10407c478bd9Sstevel@tonic-gate * create client device's devinfo node 10417c478bd9Sstevel@tonic-gate * Return Values: 10427c478bd9Sstevel@tonic-gate * dev_info 10437c478bd9Sstevel@tonic-gate * NULL 10447c478bd9Sstevel@tonic-gate * Notes: 10457c478bd9Sstevel@tonic-gate */ 10467c478bd9Sstevel@tonic-gate static dev_info_t * 10477c478bd9Sstevel@tonic-gate i_mdi_devinfo_create(mdi_vhci_t *vh, char *name, char *guid, 10483c34adc5Sramat char **compatible, int ncompatible) 10497c478bd9Sstevel@tonic-gate { 10507c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 10517c478bd9Sstevel@tonic-gate 10525e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate /* Verify for duplicate entry */ 10557c478bd9Sstevel@tonic-gate cdip = i_mdi_devinfo_find(vh, name, guid); 10567c478bd9Sstevel@tonic-gate ASSERT(cdip == NULL); 10577c478bd9Sstevel@tonic-gate if (cdip) { 10587c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 10597c478bd9Sstevel@tonic-gate "i_mdi_devinfo_create: client dip %p already exists", 10607c478bd9Sstevel@tonic-gate (void *)cdip); 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate 10633c34adc5Sramat ndi_devi_alloc_sleep(vh->vh_dip, name, DEVI_SID_NODEID, &cdip); 10647c478bd9Sstevel@tonic-gate if (cdip == NULL) 10657c478bd9Sstevel@tonic-gate goto fail; 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate /* 10687c478bd9Sstevel@tonic-gate * Create component type and Global unique identifier 10697c478bd9Sstevel@tonic-gate * properties 10707c478bd9Sstevel@tonic-gate */ 10717c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, 10727c478bd9Sstevel@tonic-gate MDI_CLIENT_GUID_PROP, guid) != DDI_PROP_SUCCESS) { 10737c478bd9Sstevel@tonic-gate goto fail; 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate /* Decorate the node with compatible property */ 10777c478bd9Sstevel@tonic-gate if (compatible && 10787c478bd9Sstevel@tonic-gate (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip, 10797c478bd9Sstevel@tonic-gate "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS)) { 10807c478bd9Sstevel@tonic-gate goto fail; 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate return (cdip); 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate fail: 10867c478bd9Sstevel@tonic-gate if (cdip) { 10877c478bd9Sstevel@tonic-gate (void) ndi_prop_remove_all(cdip); 10887c478bd9Sstevel@tonic-gate (void) ndi_devi_free(cdip); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate return (NULL); 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate /* 10947c478bd9Sstevel@tonic-gate * i_mdi_devinfo_find(): 10957c478bd9Sstevel@tonic-gate * Find a matching devinfo node for given client node name 10967c478bd9Sstevel@tonic-gate * and its guid. 10977c478bd9Sstevel@tonic-gate * Return Values: 10987c478bd9Sstevel@tonic-gate * Handle to a dev_info node or NULL 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate static dev_info_t * 11017c478bd9Sstevel@tonic-gate i_mdi_devinfo_find(mdi_vhci_t *vh, caddr_t name, char *guid) 11027c478bd9Sstevel@tonic-gate { 11037c478bd9Sstevel@tonic-gate char *data; 11047c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 11057c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 11067c478bd9Sstevel@tonic-gate int circular; 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate ndi_devi_enter(vh->vh_dip, &circular); 11097c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vh->vh_dip)->devi_child; 11107c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 11117c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate if (strcmp(DEVI(cdip)->devi_node_name, name)) { 11147c478bd9Sstevel@tonic-gate continue; 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip, 11187c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, MDI_CLIENT_GUID_PROP, 11197c478bd9Sstevel@tonic-gate &data) != DDI_PROP_SUCCESS) { 11207c478bd9Sstevel@tonic-gate continue; 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate if (strcmp(data, guid) != 0) { 11247c478bd9Sstevel@tonic-gate ddi_prop_free(data); 11257c478bd9Sstevel@tonic-gate continue; 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate ddi_prop_free(data); 11287c478bd9Sstevel@tonic-gate break; 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate ndi_devi_exit(vh->vh_dip, circular); 11317c478bd9Sstevel@tonic-gate return (cdip); 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate /* 11357c478bd9Sstevel@tonic-gate * i_mdi_devinfo_remove(): 11367c478bd9Sstevel@tonic-gate * Remove a client device node 11377c478bd9Sstevel@tonic-gate */ 11387c478bd9Sstevel@tonic-gate static int 11397c478bd9Sstevel@tonic-gate i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags) 11407c478bd9Sstevel@tonic-gate { 11417c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 11425e3986cbScth 11437c478bd9Sstevel@tonic-gate if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS || 11447c478bd9Sstevel@tonic-gate (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) { 11457c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 11467c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 11477c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_devinfo_remove:" 11485e3986cbScth " failed. cdip = %p\n", (void *)cdip)); 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate /* 11517c478bd9Sstevel@tonic-gate * Convert to MDI error code 11527c478bd9Sstevel@tonic-gate */ 11537c478bd9Sstevel@tonic-gate switch (rv) { 11547c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 11557c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 11567c478bd9Sstevel@tonic-gate break; 11577c478bd9Sstevel@tonic-gate case NDI_BUSY: 11587c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 11597c478bd9Sstevel@tonic-gate break; 11607c478bd9Sstevel@tonic-gate default: 11617c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 11627c478bd9Sstevel@tonic-gate break; 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate return (rv); 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate /* 11697c478bd9Sstevel@tonic-gate * i_devi_get_client() 11707c478bd9Sstevel@tonic-gate * Utility function to get mpxio component extensions 11717c478bd9Sstevel@tonic-gate */ 11727c478bd9Sstevel@tonic-gate static mdi_client_t * 11737c478bd9Sstevel@tonic-gate i_devi_get_client(dev_info_t *cdip) 11747c478bd9Sstevel@tonic-gate { 11757c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 11765e3986cbScth 11777c478bd9Sstevel@tonic-gate if (MDI_CLIENT(cdip)) { 11787c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(cdip)->devi_mdi_client; 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate return (ct); 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate /* 11847c478bd9Sstevel@tonic-gate * i_mdi_is_child_present(): 11857c478bd9Sstevel@tonic-gate * Search for the presence of client device dev_info node 11867c478bd9Sstevel@tonic-gate */ 11877c478bd9Sstevel@tonic-gate static int 11887c478bd9Sstevel@tonic-gate i_mdi_is_child_present(dev_info_t *vdip, dev_info_t *cdip) 11897c478bd9Sstevel@tonic-gate { 11907c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 11917c478bd9Sstevel@tonic-gate struct dev_info *dip; 11927c478bd9Sstevel@tonic-gate int circular; 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 11957c478bd9Sstevel@tonic-gate dip = DEVI(vdip)->devi_child; 11967c478bd9Sstevel@tonic-gate while (dip) { 11977c478bd9Sstevel@tonic-gate if (dip == DEVI(cdip)) { 11987c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 11997c478bd9Sstevel@tonic-gate break; 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate dip = dip->devi_sibling; 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 12047c478bd9Sstevel@tonic-gate return (rv); 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate /* 12097c478bd9Sstevel@tonic-gate * i_mdi_client_lock(): 12107c478bd9Sstevel@tonic-gate * Grab client component lock 12117c478bd9Sstevel@tonic-gate * Return Values: 12127c478bd9Sstevel@tonic-gate * None 12137c478bd9Sstevel@tonic-gate * Note: 12147c478bd9Sstevel@tonic-gate * The default locking order is: 12157c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 12167c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 12177c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 12187c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 12197c478bd9Sstevel@tonic-gate */ 12207c478bd9Sstevel@tonic-gate static void 12217c478bd9Sstevel@tonic-gate i_mdi_client_lock(mdi_client_t *ct, mdi_pathinfo_t *pip) 12227c478bd9Sstevel@tonic-gate { 12237c478bd9Sstevel@tonic-gate if (pip) { 12247c478bd9Sstevel@tonic-gate /* 12257c478bd9Sstevel@tonic-gate * Reverse locking is requested. 12267c478bd9Sstevel@tonic-gate */ 12277c478bd9Sstevel@tonic-gate while (MDI_CLIENT_TRYLOCK(ct) == 0) { 12287c478bd9Sstevel@tonic-gate /* 12297c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 12307c478bd9Sstevel@tonic-gate * after a small delay 12317c478bd9Sstevel@tonic-gate */ 12327c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 12337c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 12347c478bd9Sstevel@tonic-gate delay(1); 12357c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 12367c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate } else { 12397c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate /* 12447c478bd9Sstevel@tonic-gate * i_mdi_client_unlock(): 12457c478bd9Sstevel@tonic-gate * Unlock a client component 12467c478bd9Sstevel@tonic-gate */ 12477c478bd9Sstevel@tonic-gate static void 12487c478bd9Sstevel@tonic-gate i_mdi_client_unlock(mdi_client_t *ct) 12497c478bd9Sstevel@tonic-gate { 12507c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate /* 12547c478bd9Sstevel@tonic-gate * i_mdi_client_alloc(): 12557c478bd9Sstevel@tonic-gate * Allocate and initialize a client structure. Caller should 12565e3986cbScth * hold the vhci client lock. 12577c478bd9Sstevel@tonic-gate * Return Values: 12587c478bd9Sstevel@tonic-gate * Handle to a client component 12597c478bd9Sstevel@tonic-gate */ 12607c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12617c478bd9Sstevel@tonic-gate static mdi_client_t * 12623c34adc5Sramat i_mdi_client_alloc(mdi_vhci_t *vh, char *name, char *lguid) 12637c478bd9Sstevel@tonic-gate { 12647c478bd9Sstevel@tonic-gate mdi_client_t *ct; 12657c478bd9Sstevel@tonic-gate 12665e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate /* 12697c478bd9Sstevel@tonic-gate * Allocate and initialize a component structure. 12707c478bd9Sstevel@tonic-gate */ 12713c34adc5Sramat ct = kmem_zalloc(sizeof (*ct), KM_SLEEP); 12727c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); 12737c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 12747c478bd9Sstevel@tonic-gate ct->ct_hprev = NULL; 12757c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 12767c478bd9Sstevel@tonic-gate ct->ct_vhci = vh; 12773c34adc5Sramat ct->ct_drvname = kmem_alloc(strlen(name) + 1, KM_SLEEP); 12787c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_drvname, name); 12793c34adc5Sramat ct->ct_guid = kmem_alloc(strlen(lguid) + 1, KM_SLEEP); 12807c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_guid, lguid); 12817c478bd9Sstevel@tonic-gate ct->ct_cprivate = NULL; 12827c478bd9Sstevel@tonic-gate ct->ct_vprivate = NULL; 12837c478bd9Sstevel@tonic-gate ct->ct_flags = 0; 12847c478bd9Sstevel@tonic-gate ct->ct_state = MDI_CLIENT_STATE_FAILED; 12855e3986cbScth MDI_CLIENT_LOCK(ct); 12867c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 12877c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 12887c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 12895e3986cbScth MDI_CLIENT_UNLOCK(ct); 12907c478bd9Sstevel@tonic-gate ct->ct_failover_flags = 0; 12917c478bd9Sstevel@tonic-gate ct->ct_failover_status = 0; 12927c478bd9Sstevel@tonic-gate cv_init(&ct->ct_failover_cv, NULL, CV_DRIVER, NULL); 12937c478bd9Sstevel@tonic-gate ct->ct_unstable = 0; 12947c478bd9Sstevel@tonic-gate cv_init(&ct->ct_unstable_cv, NULL, CV_DRIVER, NULL); 12957c478bd9Sstevel@tonic-gate cv_init(&ct->ct_powerchange_cv, NULL, CV_DRIVER, NULL); 12967c478bd9Sstevel@tonic-gate ct->ct_lb = vh->vh_lb; 12973c34adc5Sramat ct->ct_lb_args = kmem_zalloc(sizeof (client_lb_args_t), KM_SLEEP); 12987c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = LOAD_BALANCE_DEFAULT_REGION_SIZE; 12997c478bd9Sstevel@tonic-gate ct->ct_path_count = 0; 13007c478bd9Sstevel@tonic-gate ct->ct_path_head = NULL; 13017c478bd9Sstevel@tonic-gate ct->ct_path_tail = NULL; 13027c478bd9Sstevel@tonic-gate ct->ct_path_last = NULL; 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate /* 13057c478bd9Sstevel@tonic-gate * Add this client component to our client hash queue 13067c478bd9Sstevel@tonic-gate */ 13077c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(vh, ct); 13087c478bd9Sstevel@tonic-gate return (ct); 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate /* 13127c478bd9Sstevel@tonic-gate * i_mdi_client_enlist_table(): 13137c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. Caller 13145e3986cbScth * should hold the vhci client lock. 13157c478bd9Sstevel@tonic-gate */ 13167c478bd9Sstevel@tonic-gate static void 13177c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(mdi_vhci_t *vh, mdi_client_t *ct) 13187c478bd9Sstevel@tonic-gate { 13197c478bd9Sstevel@tonic-gate int index; 13207c478bd9Sstevel@tonic-gate struct client_hash *head; 13217c478bd9Sstevel@tonic-gate 13225e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 13235e3986cbScth 13247c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(ct->ct_guid); 13257c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 13267c478bd9Sstevel@tonic-gate ct->ct_hnext = (mdi_client_t *)head->ct_hash_head; 13277c478bd9Sstevel@tonic-gate head->ct_hash_head = ct; 13287c478bd9Sstevel@tonic-gate head->ct_hash_count++; 13297c478bd9Sstevel@tonic-gate vh->vh_client_count++; 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate /* 13337c478bd9Sstevel@tonic-gate * i_mdi_client_delist_table(): 13347c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. 13355e3986cbScth * Caller should hold the vhci client lock. 13367c478bd9Sstevel@tonic-gate */ 13377c478bd9Sstevel@tonic-gate static void 13387c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(mdi_vhci_t *vh, mdi_client_t *ct) 13397c478bd9Sstevel@tonic-gate { 13407c478bd9Sstevel@tonic-gate int index; 13417c478bd9Sstevel@tonic-gate char *guid; 13427c478bd9Sstevel@tonic-gate struct client_hash *head; 13437c478bd9Sstevel@tonic-gate mdi_client_t *next; 13447c478bd9Sstevel@tonic-gate mdi_client_t *last; 13457c478bd9Sstevel@tonic-gate 13465e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 13475e3986cbScth 13487c478bd9Sstevel@tonic-gate guid = ct->ct_guid; 13497c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 13507c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate last = NULL; 13537c478bd9Sstevel@tonic-gate next = (mdi_client_t *)head->ct_hash_head; 13547c478bd9Sstevel@tonic-gate while (next != NULL) { 13557c478bd9Sstevel@tonic-gate if (next == ct) { 13567c478bd9Sstevel@tonic-gate break; 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate last = next; 13597c478bd9Sstevel@tonic-gate next = next->ct_hnext; 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate if (next) { 13637c478bd9Sstevel@tonic-gate head->ct_hash_count--; 13647c478bd9Sstevel@tonic-gate if (last == NULL) { 13657c478bd9Sstevel@tonic-gate head->ct_hash_head = ct->ct_hnext; 13667c478bd9Sstevel@tonic-gate } else { 13677c478bd9Sstevel@tonic-gate last->ct_hnext = ct->ct_hnext; 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 13707c478bd9Sstevel@tonic-gate vh->vh_client_count--; 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate /* 13767c478bd9Sstevel@tonic-gate * i_mdi_client_free(): 13777c478bd9Sstevel@tonic-gate * Free a client component 13787c478bd9Sstevel@tonic-gate */ 13797c478bd9Sstevel@tonic-gate static int 13807c478bd9Sstevel@tonic-gate i_mdi_client_free(mdi_vhci_t *vh, mdi_client_t *ct) 13817c478bd9Sstevel@tonic-gate { 13827c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 13837c478bd9Sstevel@tonic-gate int flags = ct->ct_flags; 13847c478bd9Sstevel@tonic-gate dev_info_t *cdip; 13857c478bd9Sstevel@tonic-gate dev_info_t *vdip; 13867c478bd9Sstevel@tonic-gate 13875e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 13885e3986cbScth 13897c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 13907c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, MDI_CLIENT_GUID_PROP); 13937c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component &= ~MDI_COMPONENT_CLIENT; 13947c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = NULL; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* 13977c478bd9Sstevel@tonic-gate * Clear out back ref. to dev_info_t node 13987c478bd9Sstevel@tonic-gate */ 13997c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate /* 14027c478bd9Sstevel@tonic-gate * Remove this client from our hash queue 14037c478bd9Sstevel@tonic-gate */ 14047c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(vh, ct); 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate /* 14077c478bd9Sstevel@tonic-gate * Uninitialize and free the component 14087c478bd9Sstevel@tonic-gate */ 14097c478bd9Sstevel@tonic-gate kmem_free(ct->ct_drvname, strlen(ct->ct_drvname) + 1); 14107c478bd9Sstevel@tonic-gate kmem_free(ct->ct_guid, strlen(ct->ct_guid) + 1); 14117c478bd9Sstevel@tonic-gate kmem_free(ct->ct_lb_args, sizeof (client_lb_args_t)); 14127c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_failover_cv); 14137c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_unstable_cv); 14147c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_powerchange_cv); 14157c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_mutex); 14167c478bd9Sstevel@tonic-gate kmem_free(ct, sizeof (*ct)); 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate if (cdip != NULL) { 14195e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 14207c478bd9Sstevel@tonic-gate (void) i_mdi_devinfo_remove(vdip, cdip, flags); 14215e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate return (rv); 14247c478bd9Sstevel@tonic-gate } 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate /* 14277c478bd9Sstevel@tonic-gate * i_mdi_client_find(): 14287c478bd9Sstevel@tonic-gate * Find the client structure corresponding to a given guid 14295e3986cbScth * Caller should hold the vhci client lock. 14307c478bd9Sstevel@tonic-gate */ 14317c478bd9Sstevel@tonic-gate static mdi_client_t * 14323c34adc5Sramat i_mdi_client_find(mdi_vhci_t *vh, char *cname, char *guid) 14337c478bd9Sstevel@tonic-gate { 14347c478bd9Sstevel@tonic-gate int index; 14357c478bd9Sstevel@tonic-gate struct client_hash *head; 14367c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14377c478bd9Sstevel@tonic-gate 14385e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(vh)); 14395e3986cbScth 14407c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 14417c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate ct = head->ct_hash_head; 14447c478bd9Sstevel@tonic-gate while (ct != NULL) { 14453c34adc5Sramat if (strcmp(ct->ct_guid, guid) == 0 && 14463c34adc5Sramat (cname == NULL || strcmp(ct->ct_drvname, cname) == 0)) { 14477c478bd9Sstevel@tonic-gate break; 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate ct = ct->ct_hnext; 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate return (ct); 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate /* 14557c478bd9Sstevel@tonic-gate * i_mdi_client_update_state(): 14567c478bd9Sstevel@tonic-gate * Compute and update client device state 14577c478bd9Sstevel@tonic-gate * Notes: 14587c478bd9Sstevel@tonic-gate * A client device can be in any of three possible states: 14597c478bd9Sstevel@tonic-gate * 14607c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_OPTIMAL - Client in optimal state with more 14617c478bd9Sstevel@tonic-gate * one online/standby paths. Can tolerate failures. 14627c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_DEGRADED - Client device in degraded state with 14637c478bd9Sstevel@tonic-gate * no alternate paths available as standby. A failure on the online 14647c478bd9Sstevel@tonic-gate * would result in loss of access to device data. 14657c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_FAILED - Client device in failed state with 14667c478bd9Sstevel@tonic-gate * no paths available to access the device. 14677c478bd9Sstevel@tonic-gate */ 14687c478bd9Sstevel@tonic-gate static void 14697c478bd9Sstevel@tonic-gate i_mdi_client_update_state(mdi_client_t *ct) 14707c478bd9Sstevel@tonic-gate { 14717c478bd9Sstevel@tonic-gate int state; 14725e3986cbScth 14735e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 14747c478bd9Sstevel@tonic-gate state = i_mdi_client_compute_state(ct, NULL); 14757c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_STATE(ct, state); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate /* 14797c478bd9Sstevel@tonic-gate * i_mdi_client_compute_state(): 14807c478bd9Sstevel@tonic-gate * Compute client device state 14817c478bd9Sstevel@tonic-gate * 14827c478bd9Sstevel@tonic-gate * mdi_phci_t * Pointer to pHCI structure which should 14837c478bd9Sstevel@tonic-gate * while computing the new value. Used by 14847c478bd9Sstevel@tonic-gate * i_mdi_phci_offline() to find the new 14857c478bd9Sstevel@tonic-gate * client state after DR of a pHCI. 14867c478bd9Sstevel@tonic-gate */ 14877c478bd9Sstevel@tonic-gate static int 14887c478bd9Sstevel@tonic-gate i_mdi_client_compute_state(mdi_client_t *ct, mdi_phci_t *ph) 14897c478bd9Sstevel@tonic-gate { 14907c478bd9Sstevel@tonic-gate int state; 14917c478bd9Sstevel@tonic-gate int online_count = 0; 14927c478bd9Sstevel@tonic-gate int standby_count = 0; 14937c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 14947c478bd9Sstevel@tonic-gate 14955e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 14967c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 14977c478bd9Sstevel@tonic-gate while (pip != NULL) { 14987c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 14997c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 15007c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 15017c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 15027c478bd9Sstevel@tonic-gate pip = next; 15037c478bd9Sstevel@tonic-gate continue; 15047c478bd9Sstevel@tonic-gate } 15055e3986cbScth 15067c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 15077c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_ONLINE) 15087c478bd9Sstevel@tonic-gate online_count++; 15097c478bd9Sstevel@tonic-gate else if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 15107c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_STANDBY) 15117c478bd9Sstevel@tonic-gate standby_count++; 15127c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 15137c478bd9Sstevel@tonic-gate pip = next; 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate if (online_count == 0) { 15177c478bd9Sstevel@tonic-gate if (standby_count == 0) { 15187c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_FAILED; 15197c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!client state: failed" 15205e3986cbScth " ct = %p\n", (void *)ct)); 15217c478bd9Sstevel@tonic-gate } else if (standby_count == 1) { 15227c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 15237c478bd9Sstevel@tonic-gate } else { 15247c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate } else if (online_count == 1) { 15277c478bd9Sstevel@tonic-gate if (standby_count == 0) { 15287c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 15297c478bd9Sstevel@tonic-gate } else { 15307c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate } else { 15337c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate return (state); 15367c478bd9Sstevel@tonic-gate } 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate /* 15397c478bd9Sstevel@tonic-gate * i_mdi_client2devinfo(): 15407c478bd9Sstevel@tonic-gate * Utility function 15417c478bd9Sstevel@tonic-gate */ 15427c478bd9Sstevel@tonic-gate dev_info_t * 15437c478bd9Sstevel@tonic-gate i_mdi_client2devinfo(mdi_client_t *ct) 15447c478bd9Sstevel@tonic-gate { 15457c478bd9Sstevel@tonic-gate return (ct->ct_dip); 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate /* 15497c478bd9Sstevel@tonic-gate * mdi_client_path2_devinfo(): 15507c478bd9Sstevel@tonic-gate * Given the parent devinfo and child devfs pathname, search for 15517c478bd9Sstevel@tonic-gate * a valid devfs node handle. 15527c478bd9Sstevel@tonic-gate */ 15537c478bd9Sstevel@tonic-gate dev_info_t * 15547c478bd9Sstevel@tonic-gate mdi_client_path2devinfo(dev_info_t *vdip, char *pathname) 15557c478bd9Sstevel@tonic-gate { 15567c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 15577c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 15587c478bd9Sstevel@tonic-gate char *temp_pathname; 15597c478bd9Sstevel@tonic-gate int circular; 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate /* 15627c478bd9Sstevel@tonic-gate * Allocate temp buffer 15637c478bd9Sstevel@tonic-gate */ 15647c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate /* 15677c478bd9Sstevel@tonic-gate * Lock parent against changes 15687c478bd9Sstevel@tonic-gate */ 15697c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 15707c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vdip)->devi_child; 15717c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 15727c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 15757c478bd9Sstevel@tonic-gate (void) ddi_pathname(cdip, temp_pathname); 15767c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 15777c478bd9Sstevel@tonic-gate break; 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * Release devinfo lock 15827c478bd9Sstevel@tonic-gate */ 15837c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate * Free the temp buffer 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 15897c478bd9Sstevel@tonic-gate return (cdip); 15907c478bd9Sstevel@tonic-gate } 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate /* 15937c478bd9Sstevel@tonic-gate * mdi_client_get_path_count(): 15947c478bd9Sstevel@tonic-gate * Utility function to get number of path information nodes 15957c478bd9Sstevel@tonic-gate * associated with a given client device. 15967c478bd9Sstevel@tonic-gate */ 15977c478bd9Sstevel@tonic-gate int 15987c478bd9Sstevel@tonic-gate mdi_client_get_path_count(dev_info_t *cdip) 15997c478bd9Sstevel@tonic-gate { 16007c478bd9Sstevel@tonic-gate mdi_client_t *ct; 16017c478bd9Sstevel@tonic-gate int count = 0; 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 16047c478bd9Sstevel@tonic-gate if (ct != NULL) { 16057c478bd9Sstevel@tonic-gate count = ct->ct_path_count; 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate return (count); 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * i_mdi_get_hash_key(): 16137c478bd9Sstevel@tonic-gate * Create a hash using strings as keys 16147c478bd9Sstevel@tonic-gate * 16157c478bd9Sstevel@tonic-gate */ 16167c478bd9Sstevel@tonic-gate static int 16177c478bd9Sstevel@tonic-gate i_mdi_get_hash_key(char *str) 16187c478bd9Sstevel@tonic-gate { 16197c478bd9Sstevel@tonic-gate uint32_t g, hash = 0; 16207c478bd9Sstevel@tonic-gate char *p; 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate for (p = str; *p != '\0'; p++) { 16237c478bd9Sstevel@tonic-gate g = *p; 16247c478bd9Sstevel@tonic-gate hash += g; 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate return (hash % (CLIENT_HASH_TABLE_SIZE - 1)); 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate /* 16307c478bd9Sstevel@tonic-gate * mdi_get_lb_policy(): 16317c478bd9Sstevel@tonic-gate * Get current load balancing policy for a given client device 16327c478bd9Sstevel@tonic-gate */ 16337c478bd9Sstevel@tonic-gate client_lb_t 16347c478bd9Sstevel@tonic-gate mdi_get_lb_policy(dev_info_t *cdip) 16357c478bd9Sstevel@tonic-gate { 16367c478bd9Sstevel@tonic-gate client_lb_t lb = LOAD_BALANCE_NONE; 16377c478bd9Sstevel@tonic-gate mdi_client_t *ct; 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 16407c478bd9Sstevel@tonic-gate if (ct != NULL) { 16417c478bd9Sstevel@tonic-gate lb = ct->ct_lb; 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate return (lb); 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate /* 16477c478bd9Sstevel@tonic-gate * mdi_set_lb_region_size(): 16487c478bd9Sstevel@tonic-gate * Set current region size for the load-balance 16497c478bd9Sstevel@tonic-gate */ 16507c478bd9Sstevel@tonic-gate int 16517c478bd9Sstevel@tonic-gate mdi_set_lb_region_size(dev_info_t *cdip, int region_size) 16527c478bd9Sstevel@tonic-gate { 16537c478bd9Sstevel@tonic-gate mdi_client_t *ct; 16547c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 16577c478bd9Sstevel@tonic-gate if (ct != NULL && ct->ct_lb_args != NULL) { 16587c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = region_size; 16597c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 16607c478bd9Sstevel@tonic-gate } 16617c478bd9Sstevel@tonic-gate return (rv); 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate 16647c478bd9Sstevel@tonic-gate /* 16657c478bd9Sstevel@tonic-gate * mdi_Set_lb_policy(): 16667c478bd9Sstevel@tonic-gate * Set current load balancing policy for a given client device 16677c478bd9Sstevel@tonic-gate */ 16687c478bd9Sstevel@tonic-gate int 16697c478bd9Sstevel@tonic-gate mdi_set_lb_policy(dev_info_t *cdip, client_lb_t lb) 16707c478bd9Sstevel@tonic-gate { 16717c478bd9Sstevel@tonic-gate mdi_client_t *ct; 16727c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 16757c478bd9Sstevel@tonic-gate if (ct != NULL) { 16767c478bd9Sstevel@tonic-gate ct->ct_lb = lb; 16777c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate return (rv); 16807c478bd9Sstevel@tonic-gate } 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate /* 16837c478bd9Sstevel@tonic-gate * mdi_failover(): 16847c478bd9Sstevel@tonic-gate * failover function called by the vHCI drivers to initiate 16857c478bd9Sstevel@tonic-gate * a failover operation. This is typically due to non-availability 16867c478bd9Sstevel@tonic-gate * of online paths to route I/O requests. Failover can be 16877c478bd9Sstevel@tonic-gate * triggered through user application also. 16887c478bd9Sstevel@tonic-gate * 16897c478bd9Sstevel@tonic-gate * The vHCI driver calls mdi_failover() to initiate a failover 16907c478bd9Sstevel@tonic-gate * operation. mdi_failover() calls back into the vHCI driver's 16917c478bd9Sstevel@tonic-gate * vo_failover() entry point to perform the actual failover 16927c478bd9Sstevel@tonic-gate * operation. The reason for requiring the vHCI driver to 16937c478bd9Sstevel@tonic-gate * initiate failover by calling mdi_failover(), instead of directly 16947c478bd9Sstevel@tonic-gate * executing vo_failover() itself, is to ensure that the mdi 16957c478bd9Sstevel@tonic-gate * framework can keep track of the client state properly. 16967c478bd9Sstevel@tonic-gate * Additionally, mdi_failover() provides as a convenience the 16977c478bd9Sstevel@tonic-gate * option of performing the failover operation synchronously or 16987c478bd9Sstevel@tonic-gate * asynchronously 16997c478bd9Sstevel@tonic-gate * 17007c478bd9Sstevel@tonic-gate * Upon successful completion of the failover operation, the 17017c478bd9Sstevel@tonic-gate * paths that were previously ONLINE will be in the STANDBY state, 17027c478bd9Sstevel@tonic-gate * and the newly activated paths will be in the ONLINE state. 17037c478bd9Sstevel@tonic-gate * 17047c478bd9Sstevel@tonic-gate * The flags modifier determines whether the activation is done 17057c478bd9Sstevel@tonic-gate * synchronously: MDI_FAILOVER_SYNC 17067c478bd9Sstevel@tonic-gate * Return Values: 17077c478bd9Sstevel@tonic-gate * MDI_SUCCESS 17087c478bd9Sstevel@tonic-gate * MDI_FAILURE 17097c478bd9Sstevel@tonic-gate * MDI_BUSY 17107c478bd9Sstevel@tonic-gate */ 17117c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17127c478bd9Sstevel@tonic-gate int 17137c478bd9Sstevel@tonic-gate mdi_failover(dev_info_t *vdip, dev_info_t *cdip, int flags) 17147c478bd9Sstevel@tonic-gate { 17157c478bd9Sstevel@tonic-gate int rv; 17167c478bd9Sstevel@tonic-gate mdi_client_t *ct; 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 17197c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 17207c478bd9Sstevel@tonic-gate if (ct == NULL) { 17217c478bd9Sstevel@tonic-gate /* cdip is not a valid client device. Nothing more to do. */ 17227c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 17237c478bd9Sstevel@tonic-gate } 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_PATH_FREE_IN_PROGRESS(ct)) { 17287c478bd9Sstevel@tonic-gate /* A path to the client is being freed */ 17297c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 17307c478bd9Sstevel@tonic-gate return (MDI_BUSY); 17317c478bd9Sstevel@tonic-gate } 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 17357c478bd9Sstevel@tonic-gate /* 17367c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 17377c478bd9Sstevel@tonic-gate */ 17387c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 17397c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 17437c478bd9Sstevel@tonic-gate /* 17447c478bd9Sstevel@tonic-gate * Failover is already in progress; return BUSY 17457c478bd9Sstevel@tonic-gate */ 17467c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 17477c478bd9Sstevel@tonic-gate return (MDI_BUSY); 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate /* 17507c478bd9Sstevel@tonic-gate * Make sure that mdi_pathinfo node state changes are processed. 17517c478bd9Sstevel@tonic-gate * We do not allow failovers to progress while client path state 17527c478bd9Sstevel@tonic-gate * changes are in progress 17537c478bd9Sstevel@tonic-gate */ 17547c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 17557c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 17567c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 17577c478bd9Sstevel@tonic-gate return (MDI_BUSY); 17587c478bd9Sstevel@tonic-gate } else { 17597c478bd9Sstevel@tonic-gate while (ct->ct_unstable) 17607c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_unstable_cv, &ct->ct_mutex); 17617c478bd9Sstevel@tonic-gate } 17627c478bd9Sstevel@tonic-gate } 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate /* 17657c478bd9Sstevel@tonic-gate * Client device is in stable state. Before proceeding, perform sanity 17667c478bd9Sstevel@tonic-gate * checks again. 17677c478bd9Sstevel@tonic-gate */ 17687c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct)) || (MDI_CLIENT_IS_FAILED(ct)) || 1769737d277aScth (!i_ddi_devi_attached(ct->ct_dip))) { 17707c478bd9Sstevel@tonic-gate /* 17717c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 17727c478bd9Sstevel@tonic-gate */ 17737c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 17747c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 17757c478bd9Sstevel@tonic-gate } 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate /* 17787c478bd9Sstevel@tonic-gate * Set the client state as failover in progress. 17797c478bd9Sstevel@tonic-gate */ 17807c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_FAILOVER_IN_PROGRESS(ct); 17817c478bd9Sstevel@tonic-gate ct->ct_failover_flags = flags; 17827c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 17857c478bd9Sstevel@tonic-gate /* 17867c478bd9Sstevel@tonic-gate * Submit the initiate failover request via CPR safe 17877c478bd9Sstevel@tonic-gate * taskq threads. 17887c478bd9Sstevel@tonic-gate */ 17897c478bd9Sstevel@tonic-gate (void) taskq_dispatch(mdi_taskq, (task_func_t *)i_mdi_failover, 17907c478bd9Sstevel@tonic-gate ct, KM_SLEEP); 17917c478bd9Sstevel@tonic-gate return (MDI_ACCEPT); 17927c478bd9Sstevel@tonic-gate } else { 17937c478bd9Sstevel@tonic-gate /* 17947c478bd9Sstevel@tonic-gate * Synchronous failover mode. Typically invoked from the user 17957c478bd9Sstevel@tonic-gate * land. 17967c478bd9Sstevel@tonic-gate */ 17977c478bd9Sstevel@tonic-gate rv = i_mdi_failover(ct); 17987c478bd9Sstevel@tonic-gate } 17997c478bd9Sstevel@tonic-gate return (rv); 18007c478bd9Sstevel@tonic-gate } 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate /* 18037c478bd9Sstevel@tonic-gate * i_mdi_failover(): 18047c478bd9Sstevel@tonic-gate * internal failover function. Invokes vHCI drivers failover 18057c478bd9Sstevel@tonic-gate * callback function and process the failover status 18067c478bd9Sstevel@tonic-gate * Return Values: 18077c478bd9Sstevel@tonic-gate * None 18087c478bd9Sstevel@tonic-gate * 18097c478bd9Sstevel@tonic-gate * Note: A client device in failover state can not be detached or freed. 18107c478bd9Sstevel@tonic-gate */ 18117c478bd9Sstevel@tonic-gate static int 18127c478bd9Sstevel@tonic-gate i_mdi_failover(void *arg) 18137c478bd9Sstevel@tonic-gate { 18147c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 18157c478bd9Sstevel@tonic-gate mdi_client_t *ct = (mdi_client_t *)arg; 18167c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = ct->ct_vhci; 18177c478bd9Sstevel@tonic-gate 18185e3986cbScth ASSERT(!MDI_CLIENT_LOCKED(ct)); 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate if (vh->vh_ops->vo_failover != NULL) { 18217c478bd9Sstevel@tonic-gate /* 18227c478bd9Sstevel@tonic-gate * Call vHCI drivers callback routine 18237c478bd9Sstevel@tonic-gate */ 18247c478bd9Sstevel@tonic-gate rv = (*vh->vh_ops->vo_failover)(vh->vh_dip, ct->ct_dip, 18257c478bd9Sstevel@tonic-gate ct->ct_failover_flags); 18267c478bd9Sstevel@tonic-gate } 18277c478bd9Sstevel@tonic-gate 18287c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 18297c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_FAILOVER_IN_PROGRESS(ct); 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate /* 18327c478bd9Sstevel@tonic-gate * Save the failover return status 18337c478bd9Sstevel@tonic-gate */ 18347c478bd9Sstevel@tonic-gate ct->ct_failover_status = rv; 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate /* 18377c478bd9Sstevel@tonic-gate * As a result of failover, client status would have been changed. 18387c478bd9Sstevel@tonic-gate * Update the client state and wake up anyone waiting on this client 18397c478bd9Sstevel@tonic-gate * device. 18407c478bd9Sstevel@tonic-gate */ 18417c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_failover_cv); 18447c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18457c478bd9Sstevel@tonic-gate return (rv); 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate /* 18497c478bd9Sstevel@tonic-gate * Load balancing is logical block. 18507c478bd9Sstevel@tonic-gate * IOs within the range described by region_size 18517c478bd9Sstevel@tonic-gate * would go on the same path. This would improve the 18527c478bd9Sstevel@tonic-gate * performance by cache-hit on some of the RAID devices. 18537c478bd9Sstevel@tonic-gate * Search only for online paths(At some point we 18547c478bd9Sstevel@tonic-gate * may want to balance across target ports). 18557c478bd9Sstevel@tonic-gate * If no paths are found then default to round-robin. 18567c478bd9Sstevel@tonic-gate */ 18577c478bd9Sstevel@tonic-gate static int 18587c478bd9Sstevel@tonic-gate i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp) 18597c478bd9Sstevel@tonic-gate { 18607c478bd9Sstevel@tonic-gate int path_index = -1; 18617c478bd9Sstevel@tonic-gate int online_path_count = 0; 18627c478bd9Sstevel@tonic-gate int online_nonpref_path_count = 0; 18637c478bd9Sstevel@tonic-gate int region_size = ct->ct_lb_args->region_size; 18647c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 18657c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 18667c478bd9Sstevel@tonic-gate int preferred, path_cnt; 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 18697c478bd9Sstevel@tonic-gate while (pip) { 18707c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 18717c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_state == 18727c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && MDI_PI(pip)->pi_preferred) { 18737c478bd9Sstevel@tonic-gate online_path_count++; 18747c478bd9Sstevel@tonic-gate } else if (MDI_PI(pip)->pi_state == 18757c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && !MDI_PI(pip)->pi_preferred) { 18767c478bd9Sstevel@tonic-gate online_nonpref_path_count++; 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 18797c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 18807c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 18817c478bd9Sstevel@tonic-gate pip = next; 18827c478bd9Sstevel@tonic-gate } 18837c478bd9Sstevel@tonic-gate /* if found any online/preferred then use this type */ 18847c478bd9Sstevel@tonic-gate if (online_path_count > 0) { 18857c478bd9Sstevel@tonic-gate path_cnt = online_path_count; 18867c478bd9Sstevel@tonic-gate preferred = 1; 18877c478bd9Sstevel@tonic-gate } else if (online_nonpref_path_count > 0) { 18887c478bd9Sstevel@tonic-gate path_cnt = online_nonpref_path_count; 18897c478bd9Sstevel@tonic-gate preferred = 0; 18907c478bd9Sstevel@tonic-gate } else { 18917c478bd9Sstevel@tonic-gate path_cnt = 0; 18927c478bd9Sstevel@tonic-gate } 18937c478bd9Sstevel@tonic-gate if (path_cnt) { 18947c478bd9Sstevel@tonic-gate path_index = (bp->b_blkno >> region_size) % path_cnt; 18957c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 18967c478bd9Sstevel@tonic-gate while (pip && path_index != -1) { 18977c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 18987c478bd9Sstevel@tonic-gate if (path_index == 0 && 18997c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 19007c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE) && 19017c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == preferred) { 19027c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 19037c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19047c478bd9Sstevel@tonic-gate *ret_pip = pip; 19057c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate path_index --; 19087c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 19097c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 19107c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19117c478bd9Sstevel@tonic-gate pip = next; 19127c478bd9Sstevel@tonic-gate } 19137c478bd9Sstevel@tonic-gate if (pip == NULL) { 19147c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 19155e3986cbScth "!lba %llx, no pip !!\n", 19165e3986cbScth bp->b_lblkno)); 19177c478bd9Sstevel@tonic-gate } else { 19187c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 19195e3986cbScth "!lba %llx, no pip for path_index, " 19205e3986cbScth "pip %p\n", bp->b_lblkno, (void *)pip)); 19217c478bd9Sstevel@tonic-gate } 19227c478bd9Sstevel@tonic-gate } 19237c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate /* 19277c478bd9Sstevel@tonic-gate * mdi_select_path(): 19287c478bd9Sstevel@tonic-gate * select a path to access a client device. 19297c478bd9Sstevel@tonic-gate * 19307c478bd9Sstevel@tonic-gate * mdi_select_path() function is called by the vHCI drivers to 19317c478bd9Sstevel@tonic-gate * select a path to route the I/O request to. The caller passes 19327c478bd9Sstevel@tonic-gate * the block I/O data transfer structure ("buf") as one of the 19337c478bd9Sstevel@tonic-gate * parameters. The mpxio framework uses the buf structure 19347c478bd9Sstevel@tonic-gate * contents to maintain per path statistics (total I/O size / 19357c478bd9Sstevel@tonic-gate * count pending). If more than one online paths are available to 19367c478bd9Sstevel@tonic-gate * select, the framework automatically selects a suitable path 19377c478bd9Sstevel@tonic-gate * for routing I/O request. If a failover operation is active for 19387c478bd9Sstevel@tonic-gate * this client device the call shall be failed with MDI_BUSY error 19397c478bd9Sstevel@tonic-gate * code. 19407c478bd9Sstevel@tonic-gate * 19417c478bd9Sstevel@tonic-gate * By default this function returns a suitable path in online 19427c478bd9Sstevel@tonic-gate * state based on the current load balancing policy. Currently 19437c478bd9Sstevel@tonic-gate * we support LOAD_BALANCE_NONE (Previously selected online path 19447c478bd9Sstevel@tonic-gate * will continue to be used till the path is usable) and 19457c478bd9Sstevel@tonic-gate * LOAD_BALANCE_RR (Online paths will be selected in a round 19467c478bd9Sstevel@tonic-gate * robin fashion), LOAD_BALANCE_LB(Online paths will be selected 19477c478bd9Sstevel@tonic-gate * based on the logical block). The load balancing 19487c478bd9Sstevel@tonic-gate * through vHCI drivers configuration file (driver.conf). 19497c478bd9Sstevel@tonic-gate * 19507c478bd9Sstevel@tonic-gate * vHCI drivers may override this default behavior by specifying 1951602ca9eaScth * appropriate flags. The meaning of the thrid argument depends 1952602ca9eaScth * on the flags specified. If MDI_SELECT_PATH_INSTANCE is set 1953602ca9eaScth * then the argument is the "path instance" of the path to select. 1954602ca9eaScth * If MDI_SELECT_PATH_INSTANCE is not set then the argument is 1955602ca9eaScth * "start_pip". A non NULL "start_pip" is the starting point to 1956602ca9eaScth * walk and find the next appropriate path. The following values 1957602ca9eaScth * are currently defined: MDI_SELECT_ONLINE_PATH (to select an 1958602ca9eaScth * ONLINE path) and/or MDI_SELECT_STANDBY_PATH (to select an 1959602ca9eaScth * STANDBY path). 19607c478bd9Sstevel@tonic-gate * 19617c478bd9Sstevel@tonic-gate * The non-standard behavior is used by the scsi_vhci driver, 19627c478bd9Sstevel@tonic-gate * whenever it has to use a STANDBY/FAULTED path. Eg. during 19637c478bd9Sstevel@tonic-gate * attach of client devices (to avoid an unnecessary failover 19647c478bd9Sstevel@tonic-gate * when the STANDBY path comes up first), during failover 19657c478bd9Sstevel@tonic-gate * (to activate a STANDBY path as ONLINE). 19667c478bd9Sstevel@tonic-gate * 19675e3986cbScth * The selected path is returned in a a mdi_hold_path() state 19685e3986cbScth * (pi_ref_cnt). Caller should release the hold by calling 19695e3986cbScth * mdi_rele_path(). 19707c478bd9Sstevel@tonic-gate * 19717c478bd9Sstevel@tonic-gate * Return Values: 19727c478bd9Sstevel@tonic-gate * MDI_SUCCESS - Completed successfully 19737c478bd9Sstevel@tonic-gate * MDI_BUSY - Client device is busy failing over 19747c478bd9Sstevel@tonic-gate * MDI_NOPATH - Client device is online, but no valid path are 19757c478bd9Sstevel@tonic-gate * available to access this client device 19767c478bd9Sstevel@tonic-gate * MDI_FAILURE - Invalid client device or state 19777c478bd9Sstevel@tonic-gate * MDI_DEVI_ONLINING 19787c478bd9Sstevel@tonic-gate * - Client device (struct dev_info state) is in 19797c478bd9Sstevel@tonic-gate * onlining state. 19807c478bd9Sstevel@tonic-gate */ 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19837c478bd9Sstevel@tonic-gate int 19847c478bd9Sstevel@tonic-gate mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags, 1985602ca9eaScth void *arg, mdi_pathinfo_t **ret_pip) 19867c478bd9Sstevel@tonic-gate { 19877c478bd9Sstevel@tonic-gate mdi_client_t *ct; 19887c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 19897c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 19907c478bd9Sstevel@tonic-gate mdi_pathinfo_t *head; 19917c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start; 19927c478bd9Sstevel@tonic-gate client_lb_t lbp; /* load balancing policy */ 19937c478bd9Sstevel@tonic-gate int sb = 1; /* standard behavior */ 19947c478bd9Sstevel@tonic-gate int preferred = 1; /* preferred path */ 19957c478bd9Sstevel@tonic-gate int cond, cont = 1; 19967c478bd9Sstevel@tonic-gate int retry = 0; 1997602ca9eaScth mdi_pathinfo_t *start_pip; /* request starting pathinfo */ 1998602ca9eaScth int path_instance; /* request specific path instance */ 1999602ca9eaScth 2000602ca9eaScth /* determine type of arg based on flags */ 2001602ca9eaScth if (flags & MDI_SELECT_PATH_INSTANCE) { 2002602ca9eaScth flags &= ~MDI_SELECT_PATH_INSTANCE; 2003602ca9eaScth path_instance = (int)(intptr_t)arg; 2004602ca9eaScth start_pip = NULL; 2005602ca9eaScth } else { 2006602ca9eaScth path_instance = 0; 2007602ca9eaScth start_pip = (mdi_pathinfo_t *)arg; 2008602ca9eaScth } 20097c478bd9Sstevel@tonic-gate 20107c478bd9Sstevel@tonic-gate if (flags != 0) { 20117c478bd9Sstevel@tonic-gate /* 20127c478bd9Sstevel@tonic-gate * disable default behavior 20137c478bd9Sstevel@tonic-gate */ 20147c478bd9Sstevel@tonic-gate sb = 0; 20157c478bd9Sstevel@tonic-gate } 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate *ret_pip = NULL; 20187c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 20197c478bd9Sstevel@tonic-gate if (ct == NULL) { 20207c478bd9Sstevel@tonic-gate /* mdi extensions are NULL, Nothing more to do */ 20217c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 20227c478bd9Sstevel@tonic-gate } 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate if (sb) { 20277c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 20287c478bd9Sstevel@tonic-gate /* 20297c478bd9Sstevel@tonic-gate * Client is not ready to accept any I/O requests. 20307c478bd9Sstevel@tonic-gate * Fail this request. 20317c478bd9Sstevel@tonic-gate */ 20327c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 20335e3986cbScth "client state offline ct = %p\n", (void *)ct)); 20347c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 20357c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 20367c478bd9Sstevel@tonic-gate } 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 20397c478bd9Sstevel@tonic-gate /* 20407c478bd9Sstevel@tonic-gate * Check for Failover is in progress. If so tell the 20417c478bd9Sstevel@tonic-gate * caller that this device is busy. 20427c478bd9Sstevel@tonic-gate */ 20437c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 20445e3986cbScth "client failover in progress ct = %p\n", 20455e3986cbScth (void *)ct)); 20467c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 20477c478bd9Sstevel@tonic-gate return (MDI_BUSY); 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate /* 20517c478bd9Sstevel@tonic-gate * Check to see whether the client device is attached. 20527c478bd9Sstevel@tonic-gate * If not so, let the vHCI driver manually select a path 20537c478bd9Sstevel@tonic-gate * (standby) and let the probe/attach process to continue. 20547c478bd9Sstevel@tonic-gate */ 2055737d277aScth if (MDI_CLIENT_IS_DETACHED(ct) || !i_ddi_devi_attached(cdip)) { 20565e3986cbScth MDI_DEBUG(4, (CE_NOTE, cdip, "!Devi is onlining " 20575e3986cbScth "ct = %p\n", (void *)ct)); 20587c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 20597c478bd9Sstevel@tonic-gate return (MDI_DEVI_ONLINING); 20607c478bd9Sstevel@tonic-gate } 20617c478bd9Sstevel@tonic-gate } 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate /* 20647c478bd9Sstevel@tonic-gate * Cache in the client list head. If head of the list is NULL 20657c478bd9Sstevel@tonic-gate * return MDI_NOPATH 20667c478bd9Sstevel@tonic-gate */ 20677c478bd9Sstevel@tonic-gate head = ct->ct_path_head; 20687c478bd9Sstevel@tonic-gate if (head == NULL) { 20697c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 20707c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 20717c478bd9Sstevel@tonic-gate } 20727c478bd9Sstevel@tonic-gate 2073602ca9eaScth /* Caller is specifying a specific pathinfo path by path_instance */ 2074602ca9eaScth if (path_instance) { 2075602ca9eaScth /* search for pathinfo with correct path_instance */ 2076602ca9eaScth for (pip = head; 2077602ca9eaScth pip && (mdi_pi_get_path_instance(pip) != path_instance); 2078602ca9eaScth pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link) 2079602ca9eaScth ; 2080602ca9eaScth 2081602ca9eaScth /* If path can't be selected then MDI_FAILURE is returned. */ 2082602ca9eaScth if (pip == NULL) { 2083602ca9eaScth MDI_CLIENT_UNLOCK(ct); 2084602ca9eaScth return (MDI_FAILURE); 2085602ca9eaScth } 2086602ca9eaScth 2087602ca9eaScth /* verify state of path */ 2088602ca9eaScth MDI_PI_LOCK(pip); 2089602ca9eaScth if (MDI_PI(pip)->pi_state != MDI_PATHINFO_STATE_ONLINE) { 2090602ca9eaScth MDI_PI_UNLOCK(pip); 2091602ca9eaScth MDI_CLIENT_UNLOCK(ct); 2092602ca9eaScth return (MDI_FAILURE); 2093602ca9eaScth } 2094602ca9eaScth 2095602ca9eaScth /* 2096602ca9eaScth * Return the path in hold state. Caller should release the 2097602ca9eaScth * lock by calling mdi_rele_path() 2098602ca9eaScth */ 2099602ca9eaScth MDI_PI_HOLD(pip); 2100602ca9eaScth MDI_PI_UNLOCK(pip); 2101602ca9eaScth ct->ct_path_last = pip; 2102602ca9eaScth *ret_pip = pip; 2103602ca9eaScth MDI_CLIENT_UNLOCK(ct); 2104602ca9eaScth return (MDI_SUCCESS); 2105602ca9eaScth } 2106602ca9eaScth 21077c478bd9Sstevel@tonic-gate /* 21087c478bd9Sstevel@tonic-gate * for non default behavior, bypass current 21097c478bd9Sstevel@tonic-gate * load balancing policy and always use LOAD_BALANCE_RR 21107c478bd9Sstevel@tonic-gate * except that the start point will be adjusted based 21117c478bd9Sstevel@tonic-gate * on the provided start_pip 21127c478bd9Sstevel@tonic-gate */ 21137c478bd9Sstevel@tonic-gate lbp = sb ? ct->ct_lb : LOAD_BALANCE_RR; 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate switch (lbp) { 21167c478bd9Sstevel@tonic-gate case LOAD_BALANCE_NONE: 21177c478bd9Sstevel@tonic-gate /* 21187c478bd9Sstevel@tonic-gate * Load balancing is None or Alternate path mode 21197c478bd9Sstevel@tonic-gate * Start looking for a online mdi_pathinfo node starting from 21207c478bd9Sstevel@tonic-gate * last known selected path 21217c478bd9Sstevel@tonic-gate */ 21227c478bd9Sstevel@tonic-gate preferred = 1; 21237c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_last; 21247c478bd9Sstevel@tonic-gate if (pip == NULL) { 21257c478bd9Sstevel@tonic-gate pip = head; 21267c478bd9Sstevel@tonic-gate } 21277c478bd9Sstevel@tonic-gate start = pip; 21287c478bd9Sstevel@tonic-gate do { 21297c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 21307c478bd9Sstevel@tonic-gate /* 21317c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 21327c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 21337c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 21347c478bd9Sstevel@tonic-gate */ 2135ee28b439Scm136836 if ((MDI_PI(pip)->pi_state == 2136ee28b439Scm136836 MDI_PATHINFO_STATE_ONLINE) && 21377c478bd9Sstevel@tonic-gate preferred == MDI_PI(pip)->pi_preferred) { 21387c478bd9Sstevel@tonic-gate /* 21397c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 21407c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 21417c478bd9Sstevel@tonic-gate */ 21427c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 21437c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 21447c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 21457c478bd9Sstevel@tonic-gate *ret_pip = pip; 21467c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 21477c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 21487c478bd9Sstevel@tonic-gate } 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate /* 21517c478bd9Sstevel@tonic-gate * Path is busy. 21527c478bd9Sstevel@tonic-gate */ 21537c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 21547c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 21557c478bd9Sstevel@tonic-gate retry = 1; 21567c478bd9Sstevel@tonic-gate /* 21577c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 21587c478bd9Sstevel@tonic-gate */ 21597c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 21607c478bd9Sstevel@tonic-gate if (next == NULL) { 21617c478bd9Sstevel@tonic-gate next = head; 21627c478bd9Sstevel@tonic-gate } 21637c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 21647c478bd9Sstevel@tonic-gate pip = next; 21657c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 21667c478bd9Sstevel@tonic-gate preferred = 0; 21677c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 21687c478bd9Sstevel@tonic-gate cont = 0; 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate } while (cont); 21717c478bd9Sstevel@tonic-gate break; 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate case LOAD_BALANCE_LBA: 21747c478bd9Sstevel@tonic-gate /* 21757c478bd9Sstevel@tonic-gate * Make sure we are looking 21767c478bd9Sstevel@tonic-gate * for an online path. Otherwise, if it is for a STANDBY 21777c478bd9Sstevel@tonic-gate * path request, it will go through and fetch an ONLINE 21787c478bd9Sstevel@tonic-gate * path which is not desirable. 21797c478bd9Sstevel@tonic-gate */ 21807c478bd9Sstevel@tonic-gate if ((ct->ct_lb_args != NULL) && 21817c478bd9Sstevel@tonic-gate (ct->ct_lb_args->region_size) && bp && 21827c478bd9Sstevel@tonic-gate (sb || (flags == MDI_SELECT_ONLINE_PATH))) { 21837c478bd9Sstevel@tonic-gate if (i_mdi_lba_lb(ct, ret_pip, bp) 21847c478bd9Sstevel@tonic-gate == MDI_SUCCESS) { 21857c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 21867c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 21877c478bd9Sstevel@tonic-gate } 21887c478bd9Sstevel@tonic-gate } 21897c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 21907c478bd9Sstevel@tonic-gate case LOAD_BALANCE_RR: 21917c478bd9Sstevel@tonic-gate /* 21927c478bd9Sstevel@tonic-gate * Load balancing is Round Robin. Start looking for a online 21937c478bd9Sstevel@tonic-gate * mdi_pathinfo node starting from last known selected path 21947c478bd9Sstevel@tonic-gate * as the start point. If override flags are specified, 21957c478bd9Sstevel@tonic-gate * process accordingly. 21967c478bd9Sstevel@tonic-gate * If the search is already in effect(start_pip not null), 21977c478bd9Sstevel@tonic-gate * then lets just use the same path preference to continue the 21987c478bd9Sstevel@tonic-gate * traversal. 21997c478bd9Sstevel@tonic-gate */ 22007c478bd9Sstevel@tonic-gate 22017c478bd9Sstevel@tonic-gate if (start_pip != NULL) { 22027c478bd9Sstevel@tonic-gate preferred = MDI_PI(start_pip)->pi_preferred; 22037c478bd9Sstevel@tonic-gate } else { 22047c478bd9Sstevel@tonic-gate preferred = 1; 22057c478bd9Sstevel@tonic-gate } 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate start = sb ? (mdi_pathinfo_t *)ct->ct_path_last : start_pip; 22087c478bd9Sstevel@tonic-gate if (start == NULL) { 22097c478bd9Sstevel@tonic-gate pip = head; 22107c478bd9Sstevel@tonic-gate } else { 22117c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(start)->pi_client_link; 22127c478bd9Sstevel@tonic-gate if (pip == NULL) { 2213b08fdaf7SSheshadri Vasudevan if ( flags & MDI_SELECT_NO_PREFERRED) { 2214b08fdaf7SSheshadri Vasudevan /* 2215b08fdaf7SSheshadri Vasudevan * Return since we hit the end of list 2216b08fdaf7SSheshadri Vasudevan */ 2217b08fdaf7SSheshadri Vasudevan MDI_CLIENT_UNLOCK(ct); 2218b08fdaf7SSheshadri Vasudevan return (MDI_NOPATH); 2219b08fdaf7SSheshadri Vasudevan } 2220b08fdaf7SSheshadri Vasudevan 22217c478bd9Sstevel@tonic-gate if (!sb) { 22227c478bd9Sstevel@tonic-gate if (preferred == 0) { 22237c478bd9Sstevel@tonic-gate /* 22247c478bd9Sstevel@tonic-gate * Looks like we have completed 22257c478bd9Sstevel@tonic-gate * the traversal as preferred 22267c478bd9Sstevel@tonic-gate * value is 0. Time to bail out. 22277c478bd9Sstevel@tonic-gate */ 22287c478bd9Sstevel@tonic-gate *ret_pip = NULL; 22297c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 22307c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 22317c478bd9Sstevel@tonic-gate } else { 22327c478bd9Sstevel@tonic-gate /* 22337c478bd9Sstevel@tonic-gate * Looks like we reached the 22347c478bd9Sstevel@tonic-gate * end of the list. Lets enable 22357c478bd9Sstevel@tonic-gate * traversal of non preferred 22367c478bd9Sstevel@tonic-gate * paths. 22377c478bd9Sstevel@tonic-gate */ 22387c478bd9Sstevel@tonic-gate preferred = 0; 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate } 22417c478bd9Sstevel@tonic-gate pip = head; 22427c478bd9Sstevel@tonic-gate } 22437c478bd9Sstevel@tonic-gate } 22447c478bd9Sstevel@tonic-gate start = pip; 22457c478bd9Sstevel@tonic-gate do { 22467c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22477c478bd9Sstevel@tonic-gate if (sb) { 22487c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 22497c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 22507c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 22517c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 22527c478bd9Sstevel@tonic-gate } else { 22537c478bd9Sstevel@tonic-gate if (flags == MDI_SELECT_ONLINE_PATH) { 22547c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 22557c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 22567c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 22577c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 22587c478bd9Sstevel@tonic-gate } else if (flags == MDI_SELECT_STANDBY_PATH) { 22597c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 22607c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY && 22617c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 22627c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 22637c478bd9Sstevel@tonic-gate } else if (flags == (MDI_SELECT_ONLINE_PATH | 22647c478bd9Sstevel@tonic-gate MDI_SELECT_STANDBY_PATH)) { 22657c478bd9Sstevel@tonic-gate cond = (((MDI_PI(pip)->pi_state == 22667c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE || 22677c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 22687c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY)) && 22697c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 22707c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 2271ee28b439Scm136836 } else if (flags == 2272ee28b439Scm136836 (MDI_SELECT_STANDBY_PATH | 2273ee28b439Scm136836 MDI_SELECT_ONLINE_PATH | 2274ee28b439Scm136836 MDI_SELECT_USER_DISABLE_PATH)) { 2275ee28b439Scm136836 cond = (((MDI_PI(pip)->pi_state == 2276ee28b439Scm136836 MDI_PATHINFO_STATE_ONLINE || 2277ee28b439Scm136836 (MDI_PI(pip)->pi_state == 2278ee28b439Scm136836 MDI_PATHINFO_STATE_STANDBY) || 2279ee28b439Scm136836 (MDI_PI(pip)->pi_state == 2280ee28b439Scm136836 (MDI_PATHINFO_STATE_ONLINE| 2281ee28b439Scm136836 MDI_PATHINFO_STATE_USER_DISABLE)) || 2282ee28b439Scm136836 (MDI_PI(pip)->pi_state == 2283ee28b439Scm136836 (MDI_PATHINFO_STATE_STANDBY | 2284ee28b439Scm136836 MDI_PATHINFO_STATE_USER_DISABLE)))&& 2285ee28b439Scm136836 MDI_PI(pip)->pi_preferred == 2286ee28b439Scm136836 preferred) ? 1 : 0); 2287b08fdaf7SSheshadri Vasudevan } else if (flags == 2288b08fdaf7SSheshadri Vasudevan (MDI_SELECT_STANDBY_PATH | 2289b08fdaf7SSheshadri Vasudevan MDI_SELECT_ONLINE_PATH | 2290b08fdaf7SSheshadri Vasudevan MDI_SELECT_NO_PREFERRED)) { 2291b08fdaf7SSheshadri Vasudevan cond = (((MDI_PI(pip)->pi_state == 2292b08fdaf7SSheshadri Vasudevan MDI_PATHINFO_STATE_ONLINE) || 2293b08fdaf7SSheshadri Vasudevan (MDI_PI(pip)->pi_state == 2294b08fdaf7SSheshadri Vasudevan MDI_PATHINFO_STATE_STANDBY)) 2295b08fdaf7SSheshadri Vasudevan ? 1 : 0); 22967c478bd9Sstevel@tonic-gate } else { 22977c478bd9Sstevel@tonic-gate cond = 0; 22987c478bd9Sstevel@tonic-gate } 22997c478bd9Sstevel@tonic-gate } 23007c478bd9Sstevel@tonic-gate /* 23017c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 23027c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 23037c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 23047c478bd9Sstevel@tonic-gate */ 23057c478bd9Sstevel@tonic-gate if (cond) { 23067c478bd9Sstevel@tonic-gate /* 23077c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 23087c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 23097c478bd9Sstevel@tonic-gate */ 23107c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 23117c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 23127c478bd9Sstevel@tonic-gate if (sb) 23137c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 23147c478bd9Sstevel@tonic-gate *ret_pip = pip; 23157c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 23167c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 23177c478bd9Sstevel@tonic-gate } 23187c478bd9Sstevel@tonic-gate /* 23197c478bd9Sstevel@tonic-gate * Path is busy. 23207c478bd9Sstevel@tonic-gate */ 23217c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 23227c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 23237c478bd9Sstevel@tonic-gate retry = 1; 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate /* 23267c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 23277c478bd9Sstevel@tonic-gate */ 23287c478bd9Sstevel@tonic-gate do_again: 23297c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 23307c478bd9Sstevel@tonic-gate if (next == NULL) { 2331b08fdaf7SSheshadri Vasudevan if ( flags & MDI_SELECT_NO_PREFERRED) { 2332b08fdaf7SSheshadri Vasudevan /* 2333b08fdaf7SSheshadri Vasudevan * Bail out since we hit the end of list 2334b08fdaf7SSheshadri Vasudevan */ 2335b08fdaf7SSheshadri Vasudevan MDI_PI_UNLOCK(pip); 2336b08fdaf7SSheshadri Vasudevan break; 2337b08fdaf7SSheshadri Vasudevan } 2338b08fdaf7SSheshadri Vasudevan 23397c478bd9Sstevel@tonic-gate if (!sb) { 23407c478bd9Sstevel@tonic-gate if (preferred == 1) { 23417c478bd9Sstevel@tonic-gate /* 23427c478bd9Sstevel@tonic-gate * Looks like we reached the 23437c478bd9Sstevel@tonic-gate * end of the list. Lets enable 23447c478bd9Sstevel@tonic-gate * traversal of non preferred 23457c478bd9Sstevel@tonic-gate * paths. 23467c478bd9Sstevel@tonic-gate */ 23477c478bd9Sstevel@tonic-gate preferred = 0; 23487c478bd9Sstevel@tonic-gate next = head; 23497c478bd9Sstevel@tonic-gate } else { 23507c478bd9Sstevel@tonic-gate /* 23517c478bd9Sstevel@tonic-gate * We have done both the passes 23527c478bd9Sstevel@tonic-gate * Preferred as well as for 23537c478bd9Sstevel@tonic-gate * Non-preferred. Bail out now. 23547c478bd9Sstevel@tonic-gate */ 23557c478bd9Sstevel@tonic-gate cont = 0; 23567c478bd9Sstevel@tonic-gate } 23577c478bd9Sstevel@tonic-gate } else { 23587c478bd9Sstevel@tonic-gate /* 23597c478bd9Sstevel@tonic-gate * Standard behavior case. 23607c478bd9Sstevel@tonic-gate */ 23617c478bd9Sstevel@tonic-gate next = head; 23627c478bd9Sstevel@tonic-gate } 23637c478bd9Sstevel@tonic-gate } 23647c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 23657c478bd9Sstevel@tonic-gate if (cont == 0) { 23667c478bd9Sstevel@tonic-gate break; 23677c478bd9Sstevel@tonic-gate } 23687c478bd9Sstevel@tonic-gate pip = next; 23697c478bd9Sstevel@tonic-gate 23707c478bd9Sstevel@tonic-gate if (!sb) { 23717c478bd9Sstevel@tonic-gate /* 23727c478bd9Sstevel@tonic-gate * We need to handle the selection of 23737c478bd9Sstevel@tonic-gate * non-preferred path in the following 23747c478bd9Sstevel@tonic-gate * case: 23757c478bd9Sstevel@tonic-gate * 23767c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 23777c478bd9Sstevel@tonic-gate * | A : 1| - | B : 1| - | C : 0| - |NULL | 23787c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 23797c478bd9Sstevel@tonic-gate * 23807c478bd9Sstevel@tonic-gate * If we start the search with B, we need to 23817c478bd9Sstevel@tonic-gate * skip beyond B to pick C which is non - 23827c478bd9Sstevel@tonic-gate * preferred in the second pass. The following 23837c478bd9Sstevel@tonic-gate * test, if true, will allow us to skip over 23847c478bd9Sstevel@tonic-gate * the 'start'(B in the example) to select 23857c478bd9Sstevel@tonic-gate * other non preferred elements. 23867c478bd9Sstevel@tonic-gate */ 23877c478bd9Sstevel@tonic-gate if ((start_pip != NULL) && (start_pip == pip) && 23887c478bd9Sstevel@tonic-gate (MDI_PI(start_pip)->pi_preferred 23897c478bd9Sstevel@tonic-gate != preferred)) { 23907c478bd9Sstevel@tonic-gate /* 23917c478bd9Sstevel@tonic-gate * try again after going past the start 23927c478bd9Sstevel@tonic-gate * pip 23937c478bd9Sstevel@tonic-gate */ 23947c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 23957c478bd9Sstevel@tonic-gate goto do_again; 23967c478bd9Sstevel@tonic-gate } 23977c478bd9Sstevel@tonic-gate } else { 23987c478bd9Sstevel@tonic-gate /* 23997c478bd9Sstevel@tonic-gate * Standard behavior case 24007c478bd9Sstevel@tonic-gate */ 24017c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 24027c478bd9Sstevel@tonic-gate /* look for nonpreferred paths */ 24037c478bd9Sstevel@tonic-gate preferred = 0; 24047c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 24057c478bd9Sstevel@tonic-gate /* 24067c478bd9Sstevel@tonic-gate * Exit condition 24077c478bd9Sstevel@tonic-gate */ 24087c478bd9Sstevel@tonic-gate cont = 0; 24097c478bd9Sstevel@tonic-gate } 24107c478bd9Sstevel@tonic-gate } 24117c478bd9Sstevel@tonic-gate } while (cont); 24127c478bd9Sstevel@tonic-gate break; 24137c478bd9Sstevel@tonic-gate } 24147c478bd9Sstevel@tonic-gate 24157c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 24167c478bd9Sstevel@tonic-gate if (retry == 1) { 24177c478bd9Sstevel@tonic-gate return (MDI_BUSY); 24187c478bd9Sstevel@tonic-gate } else { 24197c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 24207c478bd9Sstevel@tonic-gate } 24217c478bd9Sstevel@tonic-gate } 24227c478bd9Sstevel@tonic-gate 24237c478bd9Sstevel@tonic-gate /* 24247c478bd9Sstevel@tonic-gate * For a client, return the next available path to any phci 24257c478bd9Sstevel@tonic-gate * 24267c478bd9Sstevel@tonic-gate * Note: 24277c478bd9Sstevel@tonic-gate * Caller should hold the branch's devinfo node to get a consistent 24287c478bd9Sstevel@tonic-gate * snap shot of the mdi_pathinfo nodes. 24297c478bd9Sstevel@tonic-gate * 24307c478bd9Sstevel@tonic-gate * Please note that even the list is stable the mdi_pathinfo 24317c478bd9Sstevel@tonic-gate * node state and properties are volatile. The caller should lock 24327c478bd9Sstevel@tonic-gate * and unlock the nodes by calling mdi_pi_lock() and 24337c478bd9Sstevel@tonic-gate * mdi_pi_unlock() functions to get a stable properties. 24347c478bd9Sstevel@tonic-gate * 24357c478bd9Sstevel@tonic-gate * If there is a need to use the nodes beyond the hold of the 24367c478bd9Sstevel@tonic-gate * devinfo node period (For ex. I/O), then mdi_pathinfo node 24377c478bd9Sstevel@tonic-gate * need to be held against unexpected removal by calling 24387c478bd9Sstevel@tonic-gate * mdi_hold_path() and should be released by calling 24397c478bd9Sstevel@tonic-gate * mdi_rele_path() on completion. 24407c478bd9Sstevel@tonic-gate */ 24417c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 24427c478bd9Sstevel@tonic-gate mdi_get_next_phci_path(dev_info_t *ct_dip, mdi_pathinfo_t *pip) 24437c478bd9Sstevel@tonic-gate { 24447c478bd9Sstevel@tonic-gate mdi_client_t *ct; 24457c478bd9Sstevel@tonic-gate 24467c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(ct_dip)) 24477c478bd9Sstevel@tonic-gate return (NULL); 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate /* 24507c478bd9Sstevel@tonic-gate * Walk through client link 24517c478bd9Sstevel@tonic-gate */ 24527c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(ct_dip)->devi_mdi_client; 24537c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 24547c478bd9Sstevel@tonic-gate 24557c478bd9Sstevel@tonic-gate if (pip == NULL) 24567c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ct->ct_path_head); 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link); 24597c478bd9Sstevel@tonic-gate } 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate /* 24627c478bd9Sstevel@tonic-gate * For a phci, return the next available path to any client 24637c478bd9Sstevel@tonic-gate * Note: ditto mdi_get_next_phci_path() 24647c478bd9Sstevel@tonic-gate */ 24657c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 24667c478bd9Sstevel@tonic-gate mdi_get_next_client_path(dev_info_t *ph_dip, mdi_pathinfo_t *pip) 24677c478bd9Sstevel@tonic-gate { 24687c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 24697c478bd9Sstevel@tonic-gate 24707c478bd9Sstevel@tonic-gate if (!MDI_PHCI(ph_dip)) 24717c478bd9Sstevel@tonic-gate return (NULL); 24727c478bd9Sstevel@tonic-gate 24737c478bd9Sstevel@tonic-gate /* 24747c478bd9Sstevel@tonic-gate * Walk through pHCI link 24757c478bd9Sstevel@tonic-gate */ 24767c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(ph_dip)->devi_mdi_xhci; 24777c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate if (pip == NULL) 24807c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ph->ph_path_head); 24817c478bd9Sstevel@tonic-gate 24827c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link); 24837c478bd9Sstevel@tonic-gate } 24847c478bd9Sstevel@tonic-gate 24857c478bd9Sstevel@tonic-gate /* 24867c478bd9Sstevel@tonic-gate * mdi_hold_path(): 24877c478bd9Sstevel@tonic-gate * Hold the mdi_pathinfo node against unwanted unexpected free. 24887c478bd9Sstevel@tonic-gate * Return Values: 24897c478bd9Sstevel@tonic-gate * None 24907c478bd9Sstevel@tonic-gate */ 24917c478bd9Sstevel@tonic-gate void 24927c478bd9Sstevel@tonic-gate mdi_hold_path(mdi_pathinfo_t *pip) 24937c478bd9Sstevel@tonic-gate { 24947c478bd9Sstevel@tonic-gate if (pip) { 24957c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 24967c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 24977c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 24987c478bd9Sstevel@tonic-gate } 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate 25027c478bd9Sstevel@tonic-gate /* 25037c478bd9Sstevel@tonic-gate * mdi_rele_path(): 25047c478bd9Sstevel@tonic-gate * Release the mdi_pathinfo node which was selected 25057c478bd9Sstevel@tonic-gate * through mdi_select_path() mechanism or manually held by 25067c478bd9Sstevel@tonic-gate * calling mdi_hold_path(). 25077c478bd9Sstevel@tonic-gate * Return Values: 25087c478bd9Sstevel@tonic-gate * None 25097c478bd9Sstevel@tonic-gate */ 25107c478bd9Sstevel@tonic-gate void 25117c478bd9Sstevel@tonic-gate mdi_rele_path(mdi_pathinfo_t *pip) 25127c478bd9Sstevel@tonic-gate { 25137c478bd9Sstevel@tonic-gate if (pip) { 25147c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 25157c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 25167c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_ref_cnt == 0) { 25177c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_ref_cv); 25187c478bd9Sstevel@tonic-gate } 25197c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 25207c478bd9Sstevel@tonic-gate } 25217c478bd9Sstevel@tonic-gate } 25227c478bd9Sstevel@tonic-gate 25237c478bd9Sstevel@tonic-gate /* 25247c478bd9Sstevel@tonic-gate * mdi_pi_lock(): 25257c478bd9Sstevel@tonic-gate * Lock the mdi_pathinfo node. 25267c478bd9Sstevel@tonic-gate * Note: 25277c478bd9Sstevel@tonic-gate * The caller should release the lock by calling mdi_pi_unlock() 25287c478bd9Sstevel@tonic-gate */ 25297c478bd9Sstevel@tonic-gate void 25307c478bd9Sstevel@tonic-gate mdi_pi_lock(mdi_pathinfo_t *pip) 25317c478bd9Sstevel@tonic-gate { 25327c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 25337c478bd9Sstevel@tonic-gate if (pip) { 25347c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 25357c478bd9Sstevel@tonic-gate } 25367c478bd9Sstevel@tonic-gate } 25377c478bd9Sstevel@tonic-gate 25387c478bd9Sstevel@tonic-gate 25397c478bd9Sstevel@tonic-gate /* 25407c478bd9Sstevel@tonic-gate * mdi_pi_unlock(): 25417c478bd9Sstevel@tonic-gate * Unlock the mdi_pathinfo node. 25427c478bd9Sstevel@tonic-gate * Note: 25437c478bd9Sstevel@tonic-gate * The mdi_pathinfo node should have been locked with mdi_pi_lock() 25447c478bd9Sstevel@tonic-gate */ 25457c478bd9Sstevel@tonic-gate void 25467c478bd9Sstevel@tonic-gate mdi_pi_unlock(mdi_pathinfo_t *pip) 25477c478bd9Sstevel@tonic-gate { 25487c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 25497c478bd9Sstevel@tonic-gate if (pip) { 25507c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 25517c478bd9Sstevel@tonic-gate } 25527c478bd9Sstevel@tonic-gate } 25537c478bd9Sstevel@tonic-gate 25547c478bd9Sstevel@tonic-gate /* 25557c478bd9Sstevel@tonic-gate * mdi_pi_find(): 25567c478bd9Sstevel@tonic-gate * Search the list of mdi_pathinfo nodes attached to the 25577c478bd9Sstevel@tonic-gate * pHCI/Client device node whose path address matches "paddr". 25587c478bd9Sstevel@tonic-gate * Returns a pointer to the mdi_pathinfo node if a matching node is 25597c478bd9Sstevel@tonic-gate * found. 25607c478bd9Sstevel@tonic-gate * Return Values: 25617c478bd9Sstevel@tonic-gate * mdi_pathinfo node handle 25627c478bd9Sstevel@tonic-gate * NULL 25637c478bd9Sstevel@tonic-gate * Notes: 25647c478bd9Sstevel@tonic-gate * Caller need not hold any locks to call this function. 25657c478bd9Sstevel@tonic-gate */ 25667c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 25677c478bd9Sstevel@tonic-gate mdi_pi_find(dev_info_t *pdip, char *caddr, char *paddr) 25687c478bd9Sstevel@tonic-gate { 25697c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 25707c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 25717c478bd9Sstevel@tonic-gate mdi_client_t *ct; 25727c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 25737c478bd9Sstevel@tonic-gate 25745e3986cbScth MDI_DEBUG(2, (CE_NOTE, pdip, "!mdi_pi_find: %s %s", 25755e3986cbScth caddr ? caddr : "NULL", paddr ? paddr : "NULL")); 25767c478bd9Sstevel@tonic-gate if ((pdip == NULL) || (paddr == NULL)) { 25777c478bd9Sstevel@tonic-gate return (NULL); 25787c478bd9Sstevel@tonic-gate } 25797c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 25807c478bd9Sstevel@tonic-gate if (ph == NULL) { 25817c478bd9Sstevel@tonic-gate /* 25827c478bd9Sstevel@tonic-gate * Invalid pHCI device, Nothing more to do. 25837c478bd9Sstevel@tonic-gate */ 25845e3986cbScth MDI_DEBUG(2, (CE_WARN, pdip, 25857c478bd9Sstevel@tonic-gate "!mdi_pi_find: invalid phci")); 25867c478bd9Sstevel@tonic-gate return (NULL); 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 25907c478bd9Sstevel@tonic-gate if (vh == NULL) { 25917c478bd9Sstevel@tonic-gate /* 25927c478bd9Sstevel@tonic-gate * Invalid vHCI device, Nothing more to do. 25937c478bd9Sstevel@tonic-gate */ 25945e3986cbScth MDI_DEBUG(2, (CE_WARN, pdip, 25955e3986cbScth "!mdi_pi_find: invalid vhci")); 25967c478bd9Sstevel@tonic-gate return (NULL); 25977c478bd9Sstevel@tonic-gate } 25987c478bd9Sstevel@tonic-gate 25997c478bd9Sstevel@tonic-gate /* 26005e3986cbScth * Look for pathinfo node identified by paddr. 26017c478bd9Sstevel@tonic-gate */ 26027c478bd9Sstevel@tonic-gate if (caddr == NULL) { 26037c478bd9Sstevel@tonic-gate /* 26047c478bd9Sstevel@tonic-gate * Find a mdi_pathinfo node under pHCI list for a matching 26057c478bd9Sstevel@tonic-gate * unit address. 26067c478bd9Sstevel@tonic-gate */ 26075e3986cbScth MDI_PHCI_LOCK(ph); 26085e3986cbScth if (MDI_PHCI_IS_OFFLINE(ph)) { 26095e3986cbScth MDI_DEBUG(2, (CE_WARN, pdip, 26105e3986cbScth "!mdi_pi_find: offline phci %p", (void *)ph)); 26115e3986cbScth MDI_PHCI_UNLOCK(ph); 26125e3986cbScth return (NULL); 26135e3986cbScth } 26147c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ph->ph_path_head; 26157c478bd9Sstevel@tonic-gate 26167c478bd9Sstevel@tonic-gate while (pip != NULL) { 26177c478bd9Sstevel@tonic-gate if (strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 26187c478bd9Sstevel@tonic-gate break; 26197c478bd9Sstevel@tonic-gate } 26207c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 26217c478bd9Sstevel@tonic-gate } 26225e3986cbScth MDI_PHCI_UNLOCK(ph); 26235e3986cbScth MDI_DEBUG(2, (CE_NOTE, pdip, "!mdi_pi_find: found %p", 26245e3986cbScth (void *)pip)); 26257c478bd9Sstevel@tonic-gate return (pip); 26267c478bd9Sstevel@tonic-gate } 26277c478bd9Sstevel@tonic-gate 26287c478bd9Sstevel@tonic-gate /* 26293c34adc5Sramat * XXX - Is the rest of the code in this function really necessary? 26303c34adc5Sramat * The consumers of mdi_pi_find() can search for the desired pathinfo 26313c34adc5Sramat * node by calling mdi_pi_find(pdip, NULL, paddr). Irrespective of 26323c34adc5Sramat * whether the search is based on the pathinfo nodes attached to 26333c34adc5Sramat * the pHCI or the client node, the result will be the same. 26343c34adc5Sramat */ 26353c34adc5Sramat 26363c34adc5Sramat /* 26377c478bd9Sstevel@tonic-gate * Find the client device corresponding to 'caddr' 26387c478bd9Sstevel@tonic-gate */ 26395e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 26403c34adc5Sramat 26413c34adc5Sramat /* 26423c34adc5Sramat * XXX - Passing NULL to the following function works as long as the 26433c34adc5Sramat * the client addresses (caddr) are unique per vhci basis. 26443c34adc5Sramat */ 26453c34adc5Sramat ct = i_mdi_client_find(vh, NULL, caddr); 26467c478bd9Sstevel@tonic-gate if (ct == NULL) { 26477c478bd9Sstevel@tonic-gate /* 26487c478bd9Sstevel@tonic-gate * Client not found, Obviously mdi_pathinfo node has not been 26497c478bd9Sstevel@tonic-gate * created yet. 26507c478bd9Sstevel@tonic-gate */ 26515e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 26525e3986cbScth MDI_DEBUG(2, (CE_NOTE, pdip, "!mdi_pi_find: client not " 26535e3986cbScth "found for caddr %s", caddr ? caddr : "NULL")); 26545e3986cbScth return (NULL); 26557c478bd9Sstevel@tonic-gate } 26567c478bd9Sstevel@tonic-gate 26577c478bd9Sstevel@tonic-gate /* 26587c478bd9Sstevel@tonic-gate * Hold the client lock and look for a mdi_pathinfo node with matching 26597c478bd9Sstevel@tonic-gate * pHCI and paddr 26607c478bd9Sstevel@tonic-gate */ 26617c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate /* 26647c478bd9Sstevel@tonic-gate * Release the global mutex as it is no more needed. Note: We always 26657c478bd9Sstevel@tonic-gate * respect the locking order while acquiring. 26667c478bd9Sstevel@tonic-gate */ 26675e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 26687c478bd9Sstevel@tonic-gate 26697c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 26707c478bd9Sstevel@tonic-gate while (pip != NULL) { 26717c478bd9Sstevel@tonic-gate /* 26727c478bd9Sstevel@tonic-gate * Compare the unit address 26737c478bd9Sstevel@tonic-gate */ 26747c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 26757c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 26767c478bd9Sstevel@tonic-gate break; 26777c478bd9Sstevel@tonic-gate } 26787c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 26797c478bd9Sstevel@tonic-gate } 26807c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 26815e3986cbScth MDI_DEBUG(2, (CE_NOTE, pdip, "!mdi_pi_find: found:: %p", (void *)pip)); 26827c478bd9Sstevel@tonic-gate return (pip); 26837c478bd9Sstevel@tonic-gate } 26847c478bd9Sstevel@tonic-gate 26857c478bd9Sstevel@tonic-gate /* 26867c478bd9Sstevel@tonic-gate * mdi_pi_alloc(): 26877c478bd9Sstevel@tonic-gate * Allocate and initialize a new instance of a mdi_pathinfo node. 26887c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function identifies a 26897c478bd9Sstevel@tonic-gate * unique device path is capable of having properties attached 26907c478bd9Sstevel@tonic-gate * and passed to mdi_pi_online() to fully attach and online the 26917c478bd9Sstevel@tonic-gate * path and client device node. 26927c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function must be 26937c478bd9Sstevel@tonic-gate * destroyed using mdi_pi_free() if the path is no longer 26947c478bd9Sstevel@tonic-gate * operational or if the caller fails to attach a client device 26957c478bd9Sstevel@tonic-gate * node when calling mdi_pi_online(). The framework will not free 26967c478bd9Sstevel@tonic-gate * the resources allocated. 26977c478bd9Sstevel@tonic-gate * This function can be called from both interrupt and kernel 26987c478bd9Sstevel@tonic-gate * contexts. DDI_NOSLEEP flag should be used while calling 26997c478bd9Sstevel@tonic-gate * from interrupt contexts. 27007c478bd9Sstevel@tonic-gate * Return Values: 27017c478bd9Sstevel@tonic-gate * MDI_SUCCESS 27027c478bd9Sstevel@tonic-gate * MDI_FAILURE 27037c478bd9Sstevel@tonic-gate * MDI_NOMEM 27047c478bd9Sstevel@tonic-gate */ 27057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 27067c478bd9Sstevel@tonic-gate int 27077c478bd9Sstevel@tonic-gate mdi_pi_alloc_compatible(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 27087c478bd9Sstevel@tonic-gate char **compatible, int ncompatible, int flags, mdi_pathinfo_t **ret_pip) 27097c478bd9Sstevel@tonic-gate { 27107c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 27117c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 27127c478bd9Sstevel@tonic-gate mdi_client_t *ct; 27137c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 27147c478bd9Sstevel@tonic-gate dev_info_t *cdip; 27157c478bd9Sstevel@tonic-gate int rv = MDI_NOMEM; 27163c34adc5Sramat int path_allocated = 0; 27177c478bd9Sstevel@tonic-gate 27185e3986cbScth MDI_DEBUG(2, (CE_NOTE, pdip, "!mdi_pi_alloc_compatible: %s %s %s", 27195e3986cbScth cname ? cname : "NULL", caddr ? caddr : "NULL", 27205e3986cbScth paddr ? paddr : "NULL")); 27215e3986cbScth 27227c478bd9Sstevel@tonic-gate if (pdip == NULL || cname == NULL || caddr == NULL || paddr == NULL || 27237c478bd9Sstevel@tonic-gate ret_pip == NULL) { 27247c478bd9Sstevel@tonic-gate /* Nothing more to do */ 27257c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27267c478bd9Sstevel@tonic-gate } 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate *ret_pip = NULL; 27295e3986cbScth 27305e3986cbScth /* No allocations on detaching pHCI */ 27315e3986cbScth if (DEVI_IS_DETACHING(pdip)) { 27325e3986cbScth /* Invalid pHCI device, return failure */ 27335e3986cbScth MDI_DEBUG(1, (CE_WARN, pdip, 27345e3986cbScth "!mdi_pi_alloc: detaching pHCI=%p", (void *)pdip)); 27355e3986cbScth return (MDI_FAILURE); 27365e3986cbScth } 27375e3986cbScth 27387c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 27397c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 27407c478bd9Sstevel@tonic-gate if (ph == NULL) { 27417c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 27425e3986cbScth MDI_DEBUG(1, (CE_WARN, pdip, 27435e3986cbScth "!mdi_pi_alloc: invalid pHCI=%p", (void *)pdip)); 27447c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27457c478bd9Sstevel@tonic-gate } 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 27487c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 27497c478bd9Sstevel@tonic-gate if (vh == NULL) { 27507c478bd9Sstevel@tonic-gate /* Invalid vHCI device, return failure */ 27515e3986cbScth MDI_DEBUG(1, (CE_WARN, pdip, 27525e3986cbScth "!mdi_pi_alloc: invalid vHCI=%p", (void *)pdip)); 27537c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 27547c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27557c478bd9Sstevel@tonic-gate } 27567c478bd9Sstevel@tonic-gate 27577c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 27587c478bd9Sstevel@tonic-gate /* 27597c478bd9Sstevel@tonic-gate * Do not allow new node creation when pHCI is in 27607c478bd9Sstevel@tonic-gate * offline/suspended states 27617c478bd9Sstevel@tonic-gate */ 27625e3986cbScth MDI_DEBUG(1, (CE_WARN, pdip, 27635e3986cbScth "mdi_pi_alloc: pHCI=%p is not ready", (void *)ph)); 27647c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 27657c478bd9Sstevel@tonic-gate return (MDI_BUSY); 27667c478bd9Sstevel@tonic-gate } 27677c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 27687c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 27697c478bd9Sstevel@tonic-gate 27703c34adc5Sramat /* look for a matching client, create one if not found */ 27715e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 27723c34adc5Sramat ct = i_mdi_client_find(vh, cname, caddr); 27737c478bd9Sstevel@tonic-gate if (ct == NULL) { 27743c34adc5Sramat ct = i_mdi_client_alloc(vh, cname, caddr); 27753c34adc5Sramat ASSERT(ct != NULL); 27767c478bd9Sstevel@tonic-gate } 27777c478bd9Sstevel@tonic-gate 27787c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 27797c478bd9Sstevel@tonic-gate /* 27807c478bd9Sstevel@tonic-gate * Allocate a devinfo node 27817c478bd9Sstevel@tonic-gate */ 27827c478bd9Sstevel@tonic-gate ct->ct_dip = i_mdi_devinfo_create(vh, cname, caddr, 27833c34adc5Sramat compatible, ncompatible); 27847c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 27857c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(vh, ct); 27867c478bd9Sstevel@tonic-gate goto fail; 27877c478bd9Sstevel@tonic-gate } 27887c478bd9Sstevel@tonic-gate } 27897c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component |= MDI_COMPONENT_CLIENT; 27927c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = (caddr_t)ct; 27937c478bd9Sstevel@tonic-gate 27945e3986cbScth MDI_CLIENT_LOCK(ct); 27957c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 27967c478bd9Sstevel@tonic-gate while (pip != NULL) { 27977c478bd9Sstevel@tonic-gate /* 27987c478bd9Sstevel@tonic-gate * Compare the unit address 27997c478bd9Sstevel@tonic-gate */ 28007c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 28017c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 28027c478bd9Sstevel@tonic-gate break; 28037c478bd9Sstevel@tonic-gate } 28047c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 28057c478bd9Sstevel@tonic-gate } 28065e3986cbScth MDI_CLIENT_UNLOCK(ct); 28077c478bd9Sstevel@tonic-gate 28087c478bd9Sstevel@tonic-gate if (pip == NULL) { 28097c478bd9Sstevel@tonic-gate /* 28107c478bd9Sstevel@tonic-gate * This is a new path for this client device. Allocate and 28117c478bd9Sstevel@tonic-gate * initialize a new pathinfo node 28127c478bd9Sstevel@tonic-gate */ 28133c34adc5Sramat pip = i_mdi_pi_alloc(ph, paddr, ct); 28143c34adc5Sramat ASSERT(pip != NULL); 28153c34adc5Sramat path_allocated = 1; 28167c478bd9Sstevel@tonic-gate } 28177c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 28187c478bd9Sstevel@tonic-gate 28197c478bd9Sstevel@tonic-gate fail: 28207c478bd9Sstevel@tonic-gate /* 28217c478bd9Sstevel@tonic-gate * Release the global mutex. 28227c478bd9Sstevel@tonic-gate */ 28235e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate /* 28267c478bd9Sstevel@tonic-gate * Mark the pHCI as stable 28277c478bd9Sstevel@tonic-gate */ 28287c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 28297c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 28307c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 28317c478bd9Sstevel@tonic-gate *ret_pip = pip; 28323c34adc5Sramat 28335e3986cbScth MDI_DEBUG(2, (CE_NOTE, pdip, 28345e3986cbScth "!mdi_pi_alloc_compatible: alloc %p", (void *)pip)); 28355e3986cbScth 28363c34adc5Sramat if (path_allocated) 28373c34adc5Sramat vhcache_pi_add(vh->vh_config, MDI_PI(pip)); 28383c34adc5Sramat 28397c478bd9Sstevel@tonic-gate return (rv); 28407c478bd9Sstevel@tonic-gate } 28417c478bd9Sstevel@tonic-gate 28427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 28437c478bd9Sstevel@tonic-gate int 28447c478bd9Sstevel@tonic-gate mdi_pi_alloc(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 28457c478bd9Sstevel@tonic-gate int flags, mdi_pathinfo_t **ret_pip) 28467c478bd9Sstevel@tonic-gate { 28477c478bd9Sstevel@tonic-gate return (mdi_pi_alloc_compatible(pdip, cname, caddr, paddr, NULL, 0, 28487c478bd9Sstevel@tonic-gate flags, ret_pip)); 28497c478bd9Sstevel@tonic-gate } 28507c478bd9Sstevel@tonic-gate 28517c478bd9Sstevel@tonic-gate /* 28527c478bd9Sstevel@tonic-gate * i_mdi_pi_alloc(): 28537c478bd9Sstevel@tonic-gate * Allocate a mdi_pathinfo node and add to the pHCI path list 28547c478bd9Sstevel@tonic-gate * Return Values: 28557c478bd9Sstevel@tonic-gate * mdi_pathinfo 28567c478bd9Sstevel@tonic-gate */ 28577c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 28587c478bd9Sstevel@tonic-gate static mdi_pathinfo_t * 28593c34adc5Sramat i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct) 28607c478bd9Sstevel@tonic-gate { 28613c34adc5Sramat mdi_pathinfo_t *pip; 28627c478bd9Sstevel@tonic-gate int ct_circular; 28637c478bd9Sstevel@tonic-gate int ph_circular; 2864602ca9eaScth static char path[MAXPATHLEN]; 2865602ca9eaScth char *path_persistent; 2866602ca9eaScth int path_instance; 2867602ca9eaScth mod_hash_val_t hv; 28687c478bd9Sstevel@tonic-gate 28695e3986cbScth ASSERT(MDI_VHCI_CLIENT_LOCKED(ph->ph_vhci)); 28705e3986cbScth 28713c34adc5Sramat pip = kmem_zalloc(sizeof (struct mdi_pathinfo), KM_SLEEP); 28727c478bd9Sstevel@tonic-gate mutex_init(&MDI_PI(pip)->pi_mutex, NULL, MUTEX_DEFAULT, NULL); 28737c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PATHINFO_STATE_INIT | 28747c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_TRANSIENT; 28757c478bd9Sstevel@tonic-gate 28767c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_USER_DISABLED(ph)) 28777c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 28787c478bd9Sstevel@tonic-gate 28797c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED_TRANSIENT(ph)) 28807c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 28817c478bd9Sstevel@tonic-gate 28827c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED(ph)) 28837c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 28847c478bd9Sstevel@tonic-gate 28857c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_old_state = MDI_PATHINFO_STATE_INIT; 28867c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_state_cv, NULL, CV_DEFAULT, NULL); 28877c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = ct; 28887c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = ph; 28893c34adc5Sramat MDI_PI(pip)->pi_addr = kmem_alloc(strlen(paddr) + 1, KM_SLEEP); 28907c478bd9Sstevel@tonic-gate (void) strcpy(MDI_PI(pip)->pi_addr, paddr); 2891602ca9eaScth 2892602ca9eaScth /* 2893602ca9eaScth * We form the "path" to the pathinfo node, and see if we have 2894602ca9eaScth * already allocated a 'path_instance' for that "path". If so, 2895602ca9eaScth * we use the already allocated 'path_instance'. If not, we 2896602ca9eaScth * allocate a new 'path_instance' and associate it with a copy of 2897602ca9eaScth * the "path" string (which is never freed). The association 2898602ca9eaScth * between a 'path_instance' this "path" string persists until 2899602ca9eaScth * reboot. 2900602ca9eaScth */ 2901602ca9eaScth mutex_enter(&mdi_pathmap_mutex); 2902602ca9eaScth (void) ddi_pathname(ph->ph_dip, path); 2903602ca9eaScth (void) sprintf(path + strlen(path), "/%s@%s", 2904602ca9eaScth ddi_node_name(ct->ct_dip), MDI_PI(pip)->pi_addr); 2905602ca9eaScth if (mod_hash_find(mdi_pathmap_bypath, (mod_hash_key_t)path, &hv) == 0) { 2906602ca9eaScth path_instance = (uint_t)(intptr_t)hv; 2907602ca9eaScth } else { 2908602ca9eaScth /* allocate a new 'path_instance' and persistent "path" */ 2909602ca9eaScth path_instance = mdi_pathmap_instance++; 2910602ca9eaScth path_persistent = i_ddi_strdup(path, KM_SLEEP); 2911602ca9eaScth (void) mod_hash_insert(mdi_pathmap_bypath, 2912602ca9eaScth (mod_hash_key_t)path_persistent, 2913602ca9eaScth (mod_hash_val_t)(intptr_t)path_instance); 2914602ca9eaScth (void) mod_hash_insert(mdi_pathmap_byinstance, 2915602ca9eaScth (mod_hash_key_t)(intptr_t)path_instance, 2916602ca9eaScth (mod_hash_val_t)path_persistent); 2917602ca9eaScth } 2918602ca9eaScth mutex_exit(&mdi_pathmap_mutex); 2919602ca9eaScth MDI_PI(pip)->pi_path_instance = path_instance; 2920602ca9eaScth 29213c34adc5Sramat (void) nvlist_alloc(&MDI_PI(pip)->pi_prop, NV_UNIQUE_NAME, KM_SLEEP); 29223c34adc5Sramat ASSERT(MDI_PI(pip)->pi_prop != NULL); 29237c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = NULL; 29247c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = NULL; 29257c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = NULL; 29267c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 29277c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 29287c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt = 0; 29297c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 29307c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = 1; 29317c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_ref_cv, NULL, CV_DEFAULT, NULL); 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate /* 29347c478bd9Sstevel@tonic-gate * Lock both dev_info nodes against changes in parallel. 29355e3986cbScth * 29365e3986cbScth * The ndi_devi_enter(Client), is atypical since the client is a leaf. 29375e3986cbScth * This atypical operation is done to synchronize pathinfo nodes 29385e3986cbScth * during devinfo snapshot (see di_register_pip) by 'pretending' that 29395e3986cbScth * the pathinfo nodes are children of the Client. 29407c478bd9Sstevel@tonic-gate */ 29417c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 29427c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 29437c478bd9Sstevel@tonic-gate 29447c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(ph, pip); 29457c478bd9Sstevel@tonic-gate i_mdi_client_add_path(ct, pip); 29467c478bd9Sstevel@tonic-gate 29477c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 29487c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 29497c478bd9Sstevel@tonic-gate 29507c478bd9Sstevel@tonic-gate return (pip); 29517c478bd9Sstevel@tonic-gate } 29527c478bd9Sstevel@tonic-gate 29537c478bd9Sstevel@tonic-gate /* 2954602ca9eaScth * mdi_pi_pathname_by_instance(): 2955602ca9eaScth * Lookup of "path" by 'path_instance'. Return "path". 2956602ca9eaScth * NOTE: returned "path" remains valid forever (until reboot). 2957602ca9eaScth */ 2958602ca9eaScth char * 2959602ca9eaScth mdi_pi_pathname_by_instance(int path_instance) 2960602ca9eaScth { 2961602ca9eaScth char *path; 2962602ca9eaScth mod_hash_val_t hv; 2963602ca9eaScth 2964602ca9eaScth /* mdi_pathmap lookup of "path" by 'path_instance' */ 2965602ca9eaScth mutex_enter(&mdi_pathmap_mutex); 2966602ca9eaScth if (mod_hash_find(mdi_pathmap_byinstance, 2967602ca9eaScth (mod_hash_key_t)(intptr_t)path_instance, &hv) == 0) 2968602ca9eaScth path = (char *)hv; 2969602ca9eaScth else 2970602ca9eaScth path = NULL; 2971602ca9eaScth mutex_exit(&mdi_pathmap_mutex); 2972602ca9eaScth return (path); 2973602ca9eaScth } 2974602ca9eaScth 2975602ca9eaScth /* 29767c478bd9Sstevel@tonic-gate * i_mdi_phci_add_path(): 29777c478bd9Sstevel@tonic-gate * Add a mdi_pathinfo node to pHCI list. 29787c478bd9Sstevel@tonic-gate * Notes: 29797c478bd9Sstevel@tonic-gate * Caller should per-pHCI mutex 29807c478bd9Sstevel@tonic-gate */ 29817c478bd9Sstevel@tonic-gate static void 29827c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 29837c478bd9Sstevel@tonic-gate { 29847c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 29857c478bd9Sstevel@tonic-gate 29865e3986cbScth MDI_PHCI_LOCK(ph); 29877c478bd9Sstevel@tonic-gate if (ph->ph_path_head == NULL) { 29887c478bd9Sstevel@tonic-gate ph->ph_path_head = pip; 29897c478bd9Sstevel@tonic-gate } else { 29907c478bd9Sstevel@tonic-gate MDI_PI(ph->ph_path_tail)->pi_phci_link = MDI_PI(pip); 29917c478bd9Sstevel@tonic-gate } 29927c478bd9Sstevel@tonic-gate ph->ph_path_tail = pip; 29937c478bd9Sstevel@tonic-gate ph->ph_path_count++; 29945e3986cbScth MDI_PHCI_UNLOCK(ph); 29957c478bd9Sstevel@tonic-gate } 29967c478bd9Sstevel@tonic-gate 29977c478bd9Sstevel@tonic-gate /* 29987c478bd9Sstevel@tonic-gate * i_mdi_client_add_path(): 29997c478bd9Sstevel@tonic-gate * Add mdi_pathinfo node to client list 30007c478bd9Sstevel@tonic-gate */ 30017c478bd9Sstevel@tonic-gate static void 30027c478bd9Sstevel@tonic-gate i_mdi_client_add_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 30037c478bd9Sstevel@tonic-gate { 30047c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 30057c478bd9Sstevel@tonic-gate 30065e3986cbScth MDI_CLIENT_LOCK(ct); 30077c478bd9Sstevel@tonic-gate if (ct->ct_path_head == NULL) { 30087c478bd9Sstevel@tonic-gate ct->ct_path_head = pip; 30097c478bd9Sstevel@tonic-gate } else { 30107c478bd9Sstevel@tonic-gate MDI_PI(ct->ct_path_tail)->pi_client_link = MDI_PI(pip); 30117c478bd9Sstevel@tonic-gate } 30127c478bd9Sstevel@tonic-gate ct->ct_path_tail = pip; 30137c478bd9Sstevel@tonic-gate ct->ct_path_count++; 30145e3986cbScth MDI_CLIENT_UNLOCK(ct); 30157c478bd9Sstevel@tonic-gate } 30167c478bd9Sstevel@tonic-gate 30177c478bd9Sstevel@tonic-gate /* 30187c478bd9Sstevel@tonic-gate * mdi_pi_free(): 30197c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node and also client device node if this 30207c478bd9Sstevel@tonic-gate * is the last path to the device 30217c478bd9Sstevel@tonic-gate * Return Values: 30227c478bd9Sstevel@tonic-gate * MDI_SUCCESS 30237c478bd9Sstevel@tonic-gate * MDI_FAILURE 30247c478bd9Sstevel@tonic-gate * MDI_BUSY 30257c478bd9Sstevel@tonic-gate */ 30267c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 30277c478bd9Sstevel@tonic-gate int 30287c478bd9Sstevel@tonic-gate mdi_pi_free(mdi_pathinfo_t *pip, int flags) 30297c478bd9Sstevel@tonic-gate { 3030e9b79356Srs135747 int rv = MDI_FAILURE; 30317c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 30327c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 30337c478bd9Sstevel@tonic-gate mdi_client_t *ct; 30347c478bd9Sstevel@tonic-gate int (*f)(); 30357c478bd9Sstevel@tonic-gate int client_held = 0; 30367c478bd9Sstevel@tonic-gate 30377c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 30387c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 30397c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 30407c478bd9Sstevel@tonic-gate if (ph == NULL) { 30417c478bd9Sstevel@tonic-gate /* 30427c478bd9Sstevel@tonic-gate * Invalid pHCI device, return failure 30437c478bd9Sstevel@tonic-gate */ 30447c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 30455e3986cbScth "!mdi_pi_free: invalid pHCI pip=%p", (void *)pip)); 30467c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30477c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30487c478bd9Sstevel@tonic-gate } 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 30517c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 30527c478bd9Sstevel@tonic-gate if (vh == NULL) { 30537c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 30547c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 30555e3986cbScth "!mdi_pi_free: invalid vHCI pip=%p", (void *)pip)); 30567c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30577c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30587c478bd9Sstevel@tonic-gate } 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 30617c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 30627c478bd9Sstevel@tonic-gate if (ct == NULL) { 30637c478bd9Sstevel@tonic-gate /* 30647c478bd9Sstevel@tonic-gate * Invalid Client device, return failure 30657c478bd9Sstevel@tonic-gate */ 30667c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 30675e3986cbScth "!mdi_pi_free: invalid client pip=%p", (void *)pip)); 30687c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30697c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30707c478bd9Sstevel@tonic-gate } 30717c478bd9Sstevel@tonic-gate 30727c478bd9Sstevel@tonic-gate /* 30737c478bd9Sstevel@tonic-gate * Check to see for busy condition. A mdi_pathinfo can only be freed 30747c478bd9Sstevel@tonic-gate * if the node state is either offline or init and the reference count 30757c478bd9Sstevel@tonic-gate * is zero. 30767c478bd9Sstevel@tonic-gate */ 30777c478bd9Sstevel@tonic-gate if (!(MDI_PI_IS_OFFLINE(pip) || MDI_PI_IS_INIT(pip) || 30787c478bd9Sstevel@tonic-gate MDI_PI_IS_INITING(pip))) { 30797c478bd9Sstevel@tonic-gate /* 30807c478bd9Sstevel@tonic-gate * Node is busy 30817c478bd9Sstevel@tonic-gate */ 30825e3986cbScth MDI_DEBUG(1, (CE_WARN, ct->ct_dip, 30835e3986cbScth "!mdi_pi_free: pathinfo node is busy pip=%p", (void *)pip)); 30847c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30857c478bd9Sstevel@tonic-gate return (MDI_BUSY); 30867c478bd9Sstevel@tonic-gate } 30877c478bd9Sstevel@tonic-gate 30887c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 30897c478bd9Sstevel@tonic-gate /* 30907c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 30917c478bd9Sstevel@tonic-gate */ 30925e3986cbScth MDI_DEBUG(1, (CE_NOTE, ct->ct_dip, "!mdi_pi_free: " 30937c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 30945e3986cbScth MDI_PI(pip)->pi_ref_cnt, (void *)pip)); 30957c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 30967c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 30977c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 30987c478bd9Sstevel@tonic-gate /* 30997c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 31007c478bd9Sstevel@tonic-gate * being signaled. 31017c478bd9Sstevel@tonic-gate */ 31025e3986cbScth MDI_DEBUG(1, (CE_NOTE, ct->ct_dip, 31038c4f8890Srs135747 "!mdi_pi_free: " 31047c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 31055e3986cbScth (void *)pip)); 31065e3986cbScth MDI_DEBUG(1, (CE_NOTE, ct->ct_dip, 31078c4f8890Srs135747 "!mdi_pi_free: " 31087c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 31095e3986cbScth MDI_PI(pip)->pi_ref_cnt, (void *)pip)); 31107c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31117c478bd9Sstevel@tonic-gate return (MDI_BUSY); 31127c478bd9Sstevel@tonic-gate } 31137c478bd9Sstevel@tonic-gate } 31147c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 31157c478bd9Sstevel@tonic-gate client_held = 1; 31167c478bd9Sstevel@tonic-gate } 31177c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31187c478bd9Sstevel@tonic-gate 31193c34adc5Sramat vhcache_pi_remove(vh->vh_config, MDI_PI(pip)); 31203c34adc5Sramat 31217c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 31227c478bd9Sstevel@tonic-gate 31235e3986cbScth /* Prevent further failovers till MDI_VHCI_CLIENT_LOCK is held */ 31247c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_PATH_FREE_IN_PROGRESS(ct); 31257c478bd9Sstevel@tonic-gate 31267c478bd9Sstevel@tonic-gate /* 31277c478bd9Sstevel@tonic-gate * Wait till failover is complete before removing this node. 31287c478bd9Sstevel@tonic-gate */ 31297c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 31307c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 31317c478bd9Sstevel@tonic-gate 31327c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 31335e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 31347c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 31357c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_PATH_FREE_IN_PROGRESS(ct); 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_INITING(pip)) { 31387c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_uninit; 31397c478bd9Sstevel@tonic-gate if (f != NULL) { 31407c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 31417c478bd9Sstevel@tonic-gate } 31427c478bd9Sstevel@tonic-gate } 31437c478bd9Sstevel@tonic-gate /* 31447c478bd9Sstevel@tonic-gate * If vo_pi_uninit() completed successfully. 31457c478bd9Sstevel@tonic-gate */ 31467c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 31477c478bd9Sstevel@tonic-gate if (client_held) { 31487c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_free " 31497c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 31507c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 31517c478bd9Sstevel@tonic-gate } 31527c478bd9Sstevel@tonic-gate i_mdi_pi_free(ph, pip, ct); 31537c478bd9Sstevel@tonic-gate if (ct->ct_path_count == 0) { 31547c478bd9Sstevel@tonic-gate /* 31557c478bd9Sstevel@tonic-gate * Client lost its last path. 31567c478bd9Sstevel@tonic-gate * Clean up the client device 31577c478bd9Sstevel@tonic-gate */ 31587c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 31597c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(ct->ct_vhci, ct); 31605e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 31617c478bd9Sstevel@tonic-gate return (rv); 31627c478bd9Sstevel@tonic-gate } 31637c478bd9Sstevel@tonic-gate } 31647c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 31655e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 31663c34adc5Sramat 31673c34adc5Sramat if (rv == MDI_FAILURE) 31683c34adc5Sramat vhcache_pi_add(vh->vh_config, MDI_PI(pip)); 31693c34adc5Sramat 31707c478bd9Sstevel@tonic-gate return (rv); 31717c478bd9Sstevel@tonic-gate } 31727c478bd9Sstevel@tonic-gate 31737c478bd9Sstevel@tonic-gate /* 31747c478bd9Sstevel@tonic-gate * i_mdi_pi_free(): 31757c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node 31767c478bd9Sstevel@tonic-gate */ 31777c478bd9Sstevel@tonic-gate static void 31787c478bd9Sstevel@tonic-gate i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct) 31797c478bd9Sstevel@tonic-gate { 31807c478bd9Sstevel@tonic-gate int ct_circular; 31817c478bd9Sstevel@tonic-gate int ph_circular; 31827c478bd9Sstevel@tonic-gate 31835e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 31845e3986cbScth 31857c478bd9Sstevel@tonic-gate /* 31867c478bd9Sstevel@tonic-gate * remove any per-path kstats 31877c478bd9Sstevel@tonic-gate */ 31887c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(pip); 31897c478bd9Sstevel@tonic-gate 31905e3986cbScth /* See comments in i_mdi_pi_alloc() */ 31917c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 31927c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(ct, pip); 31957c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(ph, pip); 31967c478bd9Sstevel@tonic-gate 31977c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 31987c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 31997c478bd9Sstevel@tonic-gate 32007c478bd9Sstevel@tonic-gate mutex_destroy(&MDI_PI(pip)->pi_mutex); 32017c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_state_cv); 32027c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_ref_cv); 32037c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_addr) { 32047c478bd9Sstevel@tonic-gate kmem_free(MDI_PI(pip)->pi_addr, 32057c478bd9Sstevel@tonic-gate strlen(MDI_PI(pip)->pi_addr) + 1); 32067c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr = NULL; 32077c478bd9Sstevel@tonic-gate } 32087c478bd9Sstevel@tonic-gate 32097c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop) { 32107c478bd9Sstevel@tonic-gate (void) nvlist_free(MDI_PI(pip)->pi_prop); 32117c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_prop = NULL; 32127c478bd9Sstevel@tonic-gate } 32137c478bd9Sstevel@tonic-gate kmem_free(pip, sizeof (struct mdi_pathinfo)); 32147c478bd9Sstevel@tonic-gate } 32157c478bd9Sstevel@tonic-gate 32167c478bd9Sstevel@tonic-gate 32177c478bd9Sstevel@tonic-gate /* 32187c478bd9Sstevel@tonic-gate * i_mdi_phci_remove_path(): 32197c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from pHCI list. 32207c478bd9Sstevel@tonic-gate * Notes: 32217c478bd9Sstevel@tonic-gate * Caller should hold per-pHCI mutex 32227c478bd9Sstevel@tonic-gate */ 32237c478bd9Sstevel@tonic-gate static void 32247c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 32257c478bd9Sstevel@tonic-gate { 32267c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 32277c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path = NULL; 32287c478bd9Sstevel@tonic-gate 32297c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 32307c478bd9Sstevel@tonic-gate 32315e3986cbScth MDI_PHCI_LOCK(ph); 32327c478bd9Sstevel@tonic-gate path = ph->ph_path_head; 32337c478bd9Sstevel@tonic-gate while (path != NULL) { 32347c478bd9Sstevel@tonic-gate if (path == pip) { 32357c478bd9Sstevel@tonic-gate break; 32367c478bd9Sstevel@tonic-gate } 32377c478bd9Sstevel@tonic-gate prev = path; 32387c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 32397c478bd9Sstevel@tonic-gate } 32407c478bd9Sstevel@tonic-gate 32417c478bd9Sstevel@tonic-gate if (path) { 32427c478bd9Sstevel@tonic-gate ph->ph_path_count--; 32437c478bd9Sstevel@tonic-gate if (prev) { 32447c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_phci_link = MDI_PI(path)->pi_phci_link; 32457c478bd9Sstevel@tonic-gate } else { 32467c478bd9Sstevel@tonic-gate ph->ph_path_head = 32477c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 32487c478bd9Sstevel@tonic-gate } 32497c478bd9Sstevel@tonic-gate if (ph->ph_path_tail == path) { 32507c478bd9Sstevel@tonic-gate ph->ph_path_tail = prev; 32517c478bd9Sstevel@tonic-gate } 32527c478bd9Sstevel@tonic-gate } 32537c478bd9Sstevel@tonic-gate 32547c478bd9Sstevel@tonic-gate /* 32557c478bd9Sstevel@tonic-gate * Clear the pHCI link 32567c478bd9Sstevel@tonic-gate */ 32577c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 32587c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = NULL; 32595e3986cbScth MDI_PHCI_UNLOCK(ph); 32607c478bd9Sstevel@tonic-gate } 32617c478bd9Sstevel@tonic-gate 32627c478bd9Sstevel@tonic-gate /* 32637c478bd9Sstevel@tonic-gate * i_mdi_client_remove_path(): 32647c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from client path list. 32657c478bd9Sstevel@tonic-gate */ 32667c478bd9Sstevel@tonic-gate static void 32677c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 32687c478bd9Sstevel@tonic-gate { 32697c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 32707c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path; 32717c478bd9Sstevel@tonic-gate 32727c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 32737c478bd9Sstevel@tonic-gate 32745e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 32757c478bd9Sstevel@tonic-gate path = ct->ct_path_head; 32767c478bd9Sstevel@tonic-gate while (path != NULL) { 32777c478bd9Sstevel@tonic-gate if (path == pip) { 32787c478bd9Sstevel@tonic-gate break; 32797c478bd9Sstevel@tonic-gate } 32807c478bd9Sstevel@tonic-gate prev = path; 32817c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 32827c478bd9Sstevel@tonic-gate } 32837c478bd9Sstevel@tonic-gate 32847c478bd9Sstevel@tonic-gate if (path) { 32857c478bd9Sstevel@tonic-gate ct->ct_path_count--; 32867c478bd9Sstevel@tonic-gate if (prev) { 32877c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_client_link = 32887c478bd9Sstevel@tonic-gate MDI_PI(path)->pi_client_link; 32897c478bd9Sstevel@tonic-gate } else { 32907c478bd9Sstevel@tonic-gate ct->ct_path_head = 32917c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 32927c478bd9Sstevel@tonic-gate } 32937c478bd9Sstevel@tonic-gate if (ct->ct_path_tail == path) { 32947c478bd9Sstevel@tonic-gate ct->ct_path_tail = prev; 32957c478bd9Sstevel@tonic-gate } 32967c478bd9Sstevel@tonic-gate if (ct->ct_path_last == path) { 32977c478bd9Sstevel@tonic-gate ct->ct_path_last = ct->ct_path_head; 32987c478bd9Sstevel@tonic-gate } 32997c478bd9Sstevel@tonic-gate } 33007c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 33017c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = NULL; 33027c478bd9Sstevel@tonic-gate } 33037c478bd9Sstevel@tonic-gate 33047c478bd9Sstevel@tonic-gate /* 33057c478bd9Sstevel@tonic-gate * i_mdi_pi_state_change(): 33067c478bd9Sstevel@tonic-gate * online a mdi_pathinfo node 33077c478bd9Sstevel@tonic-gate * 33087c478bd9Sstevel@tonic-gate * Return Values: 33097c478bd9Sstevel@tonic-gate * MDI_SUCCESS 33107c478bd9Sstevel@tonic-gate * MDI_FAILURE 33117c478bd9Sstevel@tonic-gate */ 33127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 33137c478bd9Sstevel@tonic-gate static int 33147c478bd9Sstevel@tonic-gate i_mdi_pi_state_change(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state, int flag) 33157c478bd9Sstevel@tonic-gate { 33167c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 33177c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 33187c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 33197c478bd9Sstevel@tonic-gate mdi_client_t *ct; 33207c478bd9Sstevel@tonic-gate int (*f)(); 33217c478bd9Sstevel@tonic-gate dev_info_t *cdip; 33227c478bd9Sstevel@tonic-gate 33237c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 33247c478bd9Sstevel@tonic-gate 33257c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 33267c478bd9Sstevel@tonic-gate ASSERT(ph); 33277c478bd9Sstevel@tonic-gate if (ph == NULL) { 33287c478bd9Sstevel@tonic-gate /* 33297c478bd9Sstevel@tonic-gate * Invalid pHCI device, fail the request 33307c478bd9Sstevel@tonic-gate */ 33317c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 33327c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 33335e3986cbScth "!mdi_pi_state_change: invalid phci pip=%p", (void *)pip)); 33347c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 33357c478bd9Sstevel@tonic-gate } 33367c478bd9Sstevel@tonic-gate 33377c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 33387c478bd9Sstevel@tonic-gate ASSERT(vh); 33397c478bd9Sstevel@tonic-gate if (vh == NULL) { 33407c478bd9Sstevel@tonic-gate /* 33417c478bd9Sstevel@tonic-gate * Invalid vHCI device, fail the request 33427c478bd9Sstevel@tonic-gate */ 33437c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 33447c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 33455e3986cbScth "!mdi_pi_state_change: invalid vhci pip=%p", (void *)pip)); 33467c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 33477c478bd9Sstevel@tonic-gate } 33487c478bd9Sstevel@tonic-gate 33497c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 33507c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 33517c478bd9Sstevel@tonic-gate if (ct == NULL) { 33527c478bd9Sstevel@tonic-gate /* 33537c478bd9Sstevel@tonic-gate * Invalid client device, fail the request 33547c478bd9Sstevel@tonic-gate */ 33557c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 33567c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 33575e3986cbScth "!mdi_pi_state_change: invalid client pip=%p", 33585e3986cbScth (void *)pip)); 33597c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 33607c478bd9Sstevel@tonic-gate } 33617c478bd9Sstevel@tonic-gate 33627c478bd9Sstevel@tonic-gate /* 33637c478bd9Sstevel@tonic-gate * If this path has not been initialized yet, Callback vHCI driver's 33647c478bd9Sstevel@tonic-gate * pathinfo node initialize entry point 33657c478bd9Sstevel@tonic-gate */ 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate if (MDI_PI_IS_INITING(pip)) { 33687c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 33697c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_init; 33707c478bd9Sstevel@tonic-gate if (f != NULL) { 33717c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 33727c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 33735e3986cbScth MDI_DEBUG(1, (CE_WARN, ct->ct_dip, 33747c478bd9Sstevel@tonic-gate "!vo_pi_init: failed vHCI=0x%p, pip=0x%p", 33755e3986cbScth (void *)vh, (void *)pip)); 33767c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 33777c478bd9Sstevel@tonic-gate } 33787c478bd9Sstevel@tonic-gate } 33797c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 33807c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 33817c478bd9Sstevel@tonic-gate } 33827c478bd9Sstevel@tonic-gate 33837c478bd9Sstevel@tonic-gate /* 33847c478bd9Sstevel@tonic-gate * Do not allow state transition when pHCI is in offline/suspended 33857c478bd9Sstevel@tonic-gate * states 33867c478bd9Sstevel@tonic-gate */ 33877c478bd9Sstevel@tonic-gate i_mdi_phci_lock(ph, pip); 33887c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 33895e3986cbScth MDI_DEBUG(1, (CE_WARN, ct->ct_dip, 33905e3986cbScth "!mdi_pi_state_change: pHCI not ready, pHCI=%p", 33915e3986cbScth (void *)ph)); 33927c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 33937c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 33947c478bd9Sstevel@tonic-gate return (MDI_BUSY); 33957c478bd9Sstevel@tonic-gate } 33967c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 33977c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 33987c478bd9Sstevel@tonic-gate 33997c478bd9Sstevel@tonic-gate /* 34007c478bd9Sstevel@tonic-gate * Check if mdi_pathinfo state is in transient state. 34017c478bd9Sstevel@tonic-gate * If yes, offlining is in progress and wait till transient state is 34027c478bd9Sstevel@tonic-gate * cleared. 34037c478bd9Sstevel@tonic-gate */ 34047c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 34057c478bd9Sstevel@tonic-gate while (MDI_PI_IS_TRANSIENT(pip)) { 34067c478bd9Sstevel@tonic-gate cv_wait(&MDI_PI(pip)->pi_state_cv, 34077c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex); 34087c478bd9Sstevel@tonic-gate } 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate 34117c478bd9Sstevel@tonic-gate /* 34127c478bd9Sstevel@tonic-gate * Grab the client lock in reverse order sequence and release the 34137c478bd9Sstevel@tonic-gate * mdi_pathinfo mutex. 34147c478bd9Sstevel@tonic-gate */ 34157c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 34167c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate /* 34197c478bd9Sstevel@tonic-gate * Wait till failover state is cleared 34207c478bd9Sstevel@tonic-gate */ 34217c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 34227c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 34237c478bd9Sstevel@tonic-gate 34247c478bd9Sstevel@tonic-gate /* 34257c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 34267c478bd9Sstevel@tonic-gate */ 34277c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34287c478bd9Sstevel@tonic-gate switch (state) { 34297c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_ONLINE: 34307c478bd9Sstevel@tonic-gate MDI_PI_SET_ONLINING(pip); 34317c478bd9Sstevel@tonic-gate break; 34327c478bd9Sstevel@tonic-gate 34337c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_STANDBY: 34347c478bd9Sstevel@tonic-gate MDI_PI_SET_STANDBYING(pip); 34357c478bd9Sstevel@tonic-gate break; 34367c478bd9Sstevel@tonic-gate 34377c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_FAULT: 34387c478bd9Sstevel@tonic-gate /* 34397c478bd9Sstevel@tonic-gate * Mark the pathinfo state as FAULTED 34407c478bd9Sstevel@tonic-gate */ 34417c478bd9Sstevel@tonic-gate MDI_PI_SET_FAULTING(pip); 34427c478bd9Sstevel@tonic-gate MDI_PI_ERRSTAT(pip, MDI_PI_HARDERR); 34437c478bd9Sstevel@tonic-gate break; 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_OFFLINE: 34467c478bd9Sstevel@tonic-gate /* 34477c478bd9Sstevel@tonic-gate * ndi_devi_offline() cannot hold pip or ct locks. 34487c478bd9Sstevel@tonic-gate */ 34497c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34507c478bd9Sstevel@tonic-gate /* 3451fb3838e9Srb150246 * Don't offline the client dev_info node unless we have 3452fb3838e9Srb150246 * no available paths left at all. 34537c478bd9Sstevel@tonic-gate */ 34547c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 34557c478bd9Sstevel@tonic-gate if ((flag & NDI_DEVI_REMOVE) && 3456fb3838e9Srb150246 (ct->ct_path_count == 1)) { 34577c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 34587c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 34597c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 34607c478bd9Sstevel@tonic-gate /* 34617c478bd9Sstevel@tonic-gate * Convert to MDI error code 34627c478bd9Sstevel@tonic-gate */ 34637c478bd9Sstevel@tonic-gate switch (rv) { 34647c478bd9Sstevel@tonic-gate case NDI_BUSY: 34657c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 34667c478bd9Sstevel@tonic-gate break; 34677c478bd9Sstevel@tonic-gate default: 34687c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 34697c478bd9Sstevel@tonic-gate break; 34707c478bd9Sstevel@tonic-gate } 34717c478bd9Sstevel@tonic-gate goto state_change_exit; 34727c478bd9Sstevel@tonic-gate } else { 34737c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 34747c478bd9Sstevel@tonic-gate } 34757c478bd9Sstevel@tonic-gate } 34767c478bd9Sstevel@tonic-gate /* 34777c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 34787c478bd9Sstevel@tonic-gate */ 34797c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34807c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 34817c478bd9Sstevel@tonic-gate break; 34827c478bd9Sstevel@tonic-gate } 34837c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34847c478bd9Sstevel@tonic-gate MDI_CLIENT_UNSTABLE(ct); 34857c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 34867c478bd9Sstevel@tonic-gate 34877c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 34885e3986cbScth if (f != NULL) 34897c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, state, 0, flag); 34905e3986cbScth 34915e3986cbScth MDI_CLIENT_LOCK(ct); 34925e3986cbScth MDI_PI_LOCK(pip); 34937c478bd9Sstevel@tonic-gate if (rv == MDI_NOT_SUPPORTED) { 34947c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DEV_NOT_SUPPORTED(ct); 34957c478bd9Sstevel@tonic-gate } 34967c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 34975e3986cbScth MDI_DEBUG(2, (CE_WARN, ct->ct_dip, 34987c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 34997c478bd9Sstevel@tonic-gate } 35007c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 35017c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 35027c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 35037c478bd9Sstevel@tonic-gate } else { 35047c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip); 35057c478bd9Sstevel@tonic-gate } 35067c478bd9Sstevel@tonic-gate } 35077c478bd9Sstevel@tonic-gate 35087c478bd9Sstevel@tonic-gate /* 35097c478bd9Sstevel@tonic-gate * Wake anyone waiting for this mdi_pathinfo node 35107c478bd9Sstevel@tonic-gate */ 35117c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 35127c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 35137c478bd9Sstevel@tonic-gate 35147c478bd9Sstevel@tonic-gate /* 35157c478bd9Sstevel@tonic-gate * Mark the client device as stable 35167c478bd9Sstevel@tonic-gate */ 35177c478bd9Sstevel@tonic-gate MDI_CLIENT_STABLE(ct); 35187c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 35197c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 35207c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 35217c478bd9Sstevel@tonic-gate 35227c478bd9Sstevel@tonic-gate /* 35237c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 35247c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 35257c478bd9Sstevel@tonic-gate * state accordingly 35267c478bd9Sstevel@tonic-gate */ 35277c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 35287c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 35297c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 35307c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 35317c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 3532737d277aScth if (cdip && !i_ddi_devi_attached(cdip) && 35337c478bd9Sstevel@tonic-gate ((state == MDI_PATHINFO_STATE_ONLINE) || 35347c478bd9Sstevel@tonic-gate (state == MDI_PATHINFO_STATE_STANDBY))) { 35357c478bd9Sstevel@tonic-gate 35367c478bd9Sstevel@tonic-gate /* 35377c478bd9Sstevel@tonic-gate * Must do ndi_devi_online() through 35387c478bd9Sstevel@tonic-gate * hotplug thread for deferred 35397c478bd9Sstevel@tonic-gate * attach mechanism to work 35407c478bd9Sstevel@tonic-gate */ 35415e3986cbScth MDI_CLIENT_UNLOCK(ct); 35427c478bd9Sstevel@tonic-gate rv = ndi_devi_online(cdip, 0); 35435e3986cbScth MDI_CLIENT_LOCK(ct); 35447c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && 35457c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == 35467c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_DEGRADED)) { 35477c478bd9Sstevel@tonic-gate /* 35487c478bd9Sstevel@tonic-gate * ndi_devi_online failed. 35497c478bd9Sstevel@tonic-gate * Reset client flags to 35507c478bd9Sstevel@tonic-gate * offline. 35517c478bd9Sstevel@tonic-gate */ 35527c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 35537c478bd9Sstevel@tonic-gate "!ndi_devi_online: failed " 35547c478bd9Sstevel@tonic-gate " Error: %x", rv)); 35557c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 35567c478bd9Sstevel@tonic-gate } 35577c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 35587c478bd9Sstevel@tonic-gate /* Reset the path state */ 35597c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 35607c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = 35617c478bd9Sstevel@tonic-gate MDI_PI_OLD_STATE(pip); 35627c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 35637c478bd9Sstevel@tonic-gate } 35647c478bd9Sstevel@tonic-gate } 35657c478bd9Sstevel@tonic-gate break; 35667c478bd9Sstevel@tonic-gate 35677c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 35687c478bd9Sstevel@tonic-gate /* 35697c478bd9Sstevel@tonic-gate * This is the last path case for 35707c478bd9Sstevel@tonic-gate * non-user initiated events. 35717c478bd9Sstevel@tonic-gate */ 35727c478bd9Sstevel@tonic-gate if (((flag & NDI_DEVI_REMOVE) == 0) && 35737c478bd9Sstevel@tonic-gate cdip && (i_ddi_node_state(cdip) >= 35747c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 35755e3986cbScth MDI_CLIENT_UNLOCK(ct); 35767c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 35775e3986cbScth MDI_CLIENT_LOCK(ct); 35787c478bd9Sstevel@tonic-gate 35797c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 35807c478bd9Sstevel@tonic-gate /* 35817c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 35827c478bd9Sstevel@tonic-gate * Reset client flags to 35837c478bd9Sstevel@tonic-gate * online as the path could not 35847c478bd9Sstevel@tonic-gate * be offlined. 35857c478bd9Sstevel@tonic-gate */ 35867c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 35877c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 35887c478bd9Sstevel@tonic-gate " Error: %x", rv)); 35897c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 35907c478bd9Sstevel@tonic-gate } 35917c478bd9Sstevel@tonic-gate } 35927c478bd9Sstevel@tonic-gate break; 35937c478bd9Sstevel@tonic-gate } 35947c478bd9Sstevel@tonic-gate /* 35957c478bd9Sstevel@tonic-gate * Convert to MDI error code 35967c478bd9Sstevel@tonic-gate */ 35977c478bd9Sstevel@tonic-gate switch (rv) { 35987c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 35997c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 36007c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 36017c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 36027c478bd9Sstevel@tonic-gate break; 36037c478bd9Sstevel@tonic-gate case NDI_BUSY: 36047c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 36057c478bd9Sstevel@tonic-gate break; 36067c478bd9Sstevel@tonic-gate default: 36077c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 36087c478bd9Sstevel@tonic-gate break; 36097c478bd9Sstevel@tonic-gate } 36107c478bd9Sstevel@tonic-gate } 36117c478bd9Sstevel@tonic-gate } 36127c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 36137c478bd9Sstevel@tonic-gate 36147c478bd9Sstevel@tonic-gate state_change_exit: 36157c478bd9Sstevel@tonic-gate /* 36167c478bd9Sstevel@tonic-gate * Mark the pHCI as stable again. 36177c478bd9Sstevel@tonic-gate */ 36187c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 36197c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 36207c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 36217c478bd9Sstevel@tonic-gate return (rv); 36227c478bd9Sstevel@tonic-gate } 36237c478bd9Sstevel@tonic-gate 36247c478bd9Sstevel@tonic-gate /* 36257c478bd9Sstevel@tonic-gate * mdi_pi_online(): 36267c478bd9Sstevel@tonic-gate * Place the path_info node in the online state. The path is 36277c478bd9Sstevel@tonic-gate * now available to be selected by mdi_select_path() for 36287c478bd9Sstevel@tonic-gate * transporting I/O requests to client devices. 36297c478bd9Sstevel@tonic-gate * Return Values: 36307c478bd9Sstevel@tonic-gate * MDI_SUCCESS 36317c478bd9Sstevel@tonic-gate * MDI_FAILURE 36327c478bd9Sstevel@tonic-gate */ 36337c478bd9Sstevel@tonic-gate int 36347c478bd9Sstevel@tonic-gate mdi_pi_online(mdi_pathinfo_t *pip, int flags) 36357c478bd9Sstevel@tonic-gate { 36367c478bd9Sstevel@tonic-gate mdi_client_t *ct = MDI_PI(pip)->pi_client; 36377c478bd9Sstevel@tonic-gate int client_held = 0; 36387c478bd9Sstevel@tonic-gate int rv; 3639571aae37Shtk int se_flag; 3640571aae37Shtk int kmem_flag; 36417c478bd9Sstevel@tonic-gate 36427c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 36437c478bd9Sstevel@tonic-gate rv = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_ONLINE, flags); 36447c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) 36457c478bd9Sstevel@tonic-gate return (rv); 36467c478bd9Sstevel@tonic-gate 36477c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 36487c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 36497c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 36505e3986cbScth "i_mdi_pm_hold_pip %p\n", (void *)pip)); 36517c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 36527c478bd9Sstevel@tonic-gate client_held = 1; 36537c478bd9Sstevel@tonic-gate } 36547c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 36557c478bd9Sstevel@tonic-gate 36567c478bd9Sstevel@tonic-gate if (client_held) { 36577c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 36587c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 36597c478bd9Sstevel@tonic-gate rv = i_mdi_power_all_phci(ct); 36607c478bd9Sstevel@tonic-gate } 36617c478bd9Sstevel@tonic-gate 36627c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 36635e3986cbScth "i_mdi_pm_hold_client %p\n", (void *)ct)); 36647c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 36657c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 36667c478bd9Sstevel@tonic-gate } 36677c478bd9Sstevel@tonic-gate 3668571aae37Shtk /* determine interrupt context */ 3669571aae37Shtk se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP; 3670571aae37Shtk kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 3671571aae37Shtk 3672571aae37Shtk /* A new path is online. Invalidate DINFOCACHE snap shot. */ 3673571aae37Shtk i_ddi_di_cache_invalidate(kmem_flag); 3674571aae37Shtk 36757c478bd9Sstevel@tonic-gate return (rv); 36767c478bd9Sstevel@tonic-gate } 36777c478bd9Sstevel@tonic-gate 36787c478bd9Sstevel@tonic-gate /* 36797c478bd9Sstevel@tonic-gate * mdi_pi_standby(): 36807c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in standby state 36817c478bd9Sstevel@tonic-gate * 36827c478bd9Sstevel@tonic-gate * Return Values: 36837c478bd9Sstevel@tonic-gate * MDI_SUCCESS 36847c478bd9Sstevel@tonic-gate * MDI_FAILURE 36857c478bd9Sstevel@tonic-gate */ 36867c478bd9Sstevel@tonic-gate int 36877c478bd9Sstevel@tonic-gate mdi_pi_standby(mdi_pathinfo_t *pip, int flags) 36887c478bd9Sstevel@tonic-gate { 36897c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_STANDBY, flags)); 36907c478bd9Sstevel@tonic-gate } 36917c478bd9Sstevel@tonic-gate 36927c478bd9Sstevel@tonic-gate /* 36937c478bd9Sstevel@tonic-gate * mdi_pi_fault(): 36947c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in fault'ed state 36957c478bd9Sstevel@tonic-gate * Return Values: 36967c478bd9Sstevel@tonic-gate * MDI_SUCCESS 36977c478bd9Sstevel@tonic-gate * MDI_FAILURE 36987c478bd9Sstevel@tonic-gate */ 36997c478bd9Sstevel@tonic-gate int 37007c478bd9Sstevel@tonic-gate mdi_pi_fault(mdi_pathinfo_t *pip, int flags) 37017c478bd9Sstevel@tonic-gate { 37027c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_FAULT, flags)); 37037c478bd9Sstevel@tonic-gate } 37047c478bd9Sstevel@tonic-gate 37057c478bd9Sstevel@tonic-gate /* 37067c478bd9Sstevel@tonic-gate * mdi_pi_offline(): 37077c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node. 37087c478bd9Sstevel@tonic-gate * Return Values: 37097c478bd9Sstevel@tonic-gate * MDI_SUCCESS 37107c478bd9Sstevel@tonic-gate * MDI_FAILURE 37117c478bd9Sstevel@tonic-gate */ 37127c478bd9Sstevel@tonic-gate int 37137c478bd9Sstevel@tonic-gate mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 37147c478bd9Sstevel@tonic-gate { 37157c478bd9Sstevel@tonic-gate int ret, client_held = 0; 37167c478bd9Sstevel@tonic-gate mdi_client_t *ct; 3717571aae37Shtk int se_flag; 3718571aae37Shtk int kmem_flag; 37197c478bd9Sstevel@tonic-gate 37207c478bd9Sstevel@tonic-gate ret = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_OFFLINE, flags); 37217c478bd9Sstevel@tonic-gate 37227c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) { 37237c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 37247c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 37257c478bd9Sstevel@tonic-gate client_held = 1; 37267c478bd9Sstevel@tonic-gate } 37277c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate if (client_held) { 37307c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 37317c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 37327c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, 37337c478bd9Sstevel@tonic-gate "mdi_pi_offline i_mdi_pm_rele_client\n")); 37347c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 37357c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 37367c478bd9Sstevel@tonic-gate } 3737571aae37Shtk 3738571aae37Shtk /* determine interrupt context */ 3739571aae37Shtk se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP; 3740571aae37Shtk kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 3741571aae37Shtk 3742571aae37Shtk /* pathinfo is offlined. update DINFOCACHE. */ 3743571aae37Shtk i_ddi_di_cache_invalidate(kmem_flag); 37447c478bd9Sstevel@tonic-gate } 37457c478bd9Sstevel@tonic-gate 37467c478bd9Sstevel@tonic-gate return (ret); 37477c478bd9Sstevel@tonic-gate } 37487c478bd9Sstevel@tonic-gate 37497c478bd9Sstevel@tonic-gate /* 37507c478bd9Sstevel@tonic-gate * i_mdi_pi_offline(): 37517c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node and call the vHCI driver's callback 37527c478bd9Sstevel@tonic-gate */ 37537c478bd9Sstevel@tonic-gate static int 37547c478bd9Sstevel@tonic-gate i_mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 37557c478bd9Sstevel@tonic-gate { 37567c478bd9Sstevel@tonic-gate dev_info_t *vdip = NULL; 37577c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 37587c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 37597c478bd9Sstevel@tonic-gate int (*f)(); 37607c478bd9Sstevel@tonic-gate int rv; 37617c478bd9Sstevel@tonic-gate 37627c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 37637c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 37647c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 37657c478bd9Sstevel@tonic-gate 37667c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 37677c478bd9Sstevel@tonic-gate /* 37687c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 37697c478bd9Sstevel@tonic-gate */ 37705e3986cbScth MDI_DEBUG(1, (CE_NOTE, ct->ct_dip, "!i_mdi_pi_offline: " 37717c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 37725e3986cbScth MDI_PI(pip)->pi_ref_cnt, (void *)pip)); 37737c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 37747c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 37757c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 37767c478bd9Sstevel@tonic-gate /* 37777c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 37787c478bd9Sstevel@tonic-gate * being signaled. 37797c478bd9Sstevel@tonic-gate */ 37805e3986cbScth MDI_DEBUG(1, (CE_NOTE, ct->ct_dip, "!i_mdi_pi_offline: " 37817c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 37825e3986cbScth (void *)pip)); 37835e3986cbScth MDI_DEBUG(1, (CE_NOTE, ct->ct_dip, "!i_mdi_pi_offline: " 37847c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 37855e3986cbScth MDI_PI(pip)->pi_ref_cnt, (void *)pip)); 37867c478bd9Sstevel@tonic-gate } 37877c478bd9Sstevel@tonic-gate } 37887c478bd9Sstevel@tonic-gate vh = ct->ct_vhci; 37897c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 37907c478bd9Sstevel@tonic-gate 37917c478bd9Sstevel@tonic-gate /* 37927c478bd9Sstevel@tonic-gate * Notify vHCI that has registered this event 37937c478bd9Sstevel@tonic-gate */ 37947c478bd9Sstevel@tonic-gate ASSERT(vh->vh_ops); 37957c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 37967c478bd9Sstevel@tonic-gate 37977c478bd9Sstevel@tonic-gate if (f != NULL) { 37987c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 37997c478bd9Sstevel@tonic-gate if ((rv = (*f)(vdip, pip, MDI_PATHINFO_STATE_OFFLINE, 0, 38007c478bd9Sstevel@tonic-gate flags)) != MDI_SUCCESS) { 38015e3986cbScth MDI_DEBUG(1, (CE_WARN, ct->ct_dip, 38025e3986cbScth "!vo_path_offline failed " 38035e3986cbScth "vdip %p, pip %p", (void *)vdip, (void *)pip)); 38047c478bd9Sstevel@tonic-gate } 38057c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 38067c478bd9Sstevel@tonic-gate } 38077c478bd9Sstevel@tonic-gate 38087c478bd9Sstevel@tonic-gate /* 38097c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state and clear the transient condition 38107c478bd9Sstevel@tonic-gate */ 38117c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINE(pip); 38127c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 38137c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38147c478bd9Sstevel@tonic-gate 38157c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 38167c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 38177c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 38187c478bd9Sstevel@tonic-gate dev_info_t *cdip = ct->ct_dip; 38197c478bd9Sstevel@tonic-gate 38207c478bd9Sstevel@tonic-gate /* 38217c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 38227c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 38237c478bd9Sstevel@tonic-gate * state accordingly 38247c478bd9Sstevel@tonic-gate */ 38257c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 38267c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 38277c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 38287c478bd9Sstevel@tonic-gate if (cdip && 38297c478bd9Sstevel@tonic-gate (i_ddi_node_state(cdip) >= 38307c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 38317c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 38327c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 38337c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 38347c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 38357c478bd9Sstevel@tonic-gate /* 38367c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 38377c478bd9Sstevel@tonic-gate * Reset client flags to 38387c478bd9Sstevel@tonic-gate * online. 38397c478bd9Sstevel@tonic-gate */ 38407c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, cdip, 38417c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 38427c478bd9Sstevel@tonic-gate " Error: %x", rv)); 38437c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 38447c478bd9Sstevel@tonic-gate } 38457c478bd9Sstevel@tonic-gate } 38467c478bd9Sstevel@tonic-gate } 38477c478bd9Sstevel@tonic-gate /* 38487c478bd9Sstevel@tonic-gate * Convert to MDI error code 38497c478bd9Sstevel@tonic-gate */ 38507c478bd9Sstevel@tonic-gate switch (rv) { 38517c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 38527c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 38537c478bd9Sstevel@tonic-gate break; 38547c478bd9Sstevel@tonic-gate case NDI_BUSY: 38557c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 38567c478bd9Sstevel@tonic-gate break; 38577c478bd9Sstevel@tonic-gate default: 38587c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 38597c478bd9Sstevel@tonic-gate break; 38607c478bd9Sstevel@tonic-gate } 38617c478bd9Sstevel@tonic-gate } 38627c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 38637c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 38647c478bd9Sstevel@tonic-gate } 38657c478bd9Sstevel@tonic-gate 38667c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 38677c478bd9Sstevel@tonic-gate 38687c478bd9Sstevel@tonic-gate /* 38697c478bd9Sstevel@tonic-gate * Change in the mdi_pathinfo node state will impact the client state 38707c478bd9Sstevel@tonic-gate */ 38717c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!i_mdi_pi_offline ct = %p pip = %p", 38725e3986cbScth (void *)ct, (void *)pip)); 38737c478bd9Sstevel@tonic-gate return (rv); 38747c478bd9Sstevel@tonic-gate } 38757c478bd9Sstevel@tonic-gate 38767c478bd9Sstevel@tonic-gate 38777c478bd9Sstevel@tonic-gate /* 38787c478bd9Sstevel@tonic-gate * mdi_pi_get_addr(): 38797c478bd9Sstevel@tonic-gate * Get the unit address associated with a mdi_pathinfo node 38807c478bd9Sstevel@tonic-gate * 38817c478bd9Sstevel@tonic-gate * Return Values: 38827c478bd9Sstevel@tonic-gate * char * 38837c478bd9Sstevel@tonic-gate */ 38847c478bd9Sstevel@tonic-gate char * 38857c478bd9Sstevel@tonic-gate mdi_pi_get_addr(mdi_pathinfo_t *pip) 38867c478bd9Sstevel@tonic-gate { 38877c478bd9Sstevel@tonic-gate if (pip == NULL) 38887c478bd9Sstevel@tonic-gate return (NULL); 38897c478bd9Sstevel@tonic-gate 389072a50065Scth return (MDI_PI(pip)->pi_addr); 38917c478bd9Sstevel@tonic-gate } 38927c478bd9Sstevel@tonic-gate 38937c478bd9Sstevel@tonic-gate /* 3894602ca9eaScth * mdi_pi_get_path_instance(): 3895602ca9eaScth * Get the 'path_instance' of a mdi_pathinfo node 3896602ca9eaScth * 3897602ca9eaScth * Return Values: 3898602ca9eaScth * path_instance 3899602ca9eaScth */ 3900602ca9eaScth int 3901602ca9eaScth mdi_pi_get_path_instance(mdi_pathinfo_t *pip) 3902602ca9eaScth { 3903602ca9eaScth if (pip == NULL) 3904602ca9eaScth return (0); 3905602ca9eaScth 3906602ca9eaScth return (MDI_PI(pip)->pi_path_instance); 3907602ca9eaScth } 3908602ca9eaScth 3909602ca9eaScth /* 3910602ca9eaScth * mdi_pi_pathname(): 3911602ca9eaScth * Return pointer to path to pathinfo node. 3912602ca9eaScth */ 3913602ca9eaScth char * 3914602ca9eaScth mdi_pi_pathname(mdi_pathinfo_t *pip) 3915602ca9eaScth { 3916602ca9eaScth if (pip == NULL) 3917602ca9eaScth return (NULL); 3918602ca9eaScth return (mdi_pi_pathname_by_instance(mdi_pi_get_path_instance(pip))); 3919602ca9eaScth } 3920602ca9eaScth 392138c67cbdSjiang wu - Sun Microsystems - Beijing China char * 392238c67cbdSjiang wu - Sun Microsystems - Beijing China mdi_pi_pathname_obp(mdi_pathinfo_t *pip, char *path) 392338c67cbdSjiang wu - Sun Microsystems - Beijing China { 392438c67cbdSjiang wu - Sun Microsystems - Beijing China char *obp_path = NULL; 392538c67cbdSjiang wu - Sun Microsystems - Beijing China if ((pip == NULL) || (path == NULL)) 392638c67cbdSjiang wu - Sun Microsystems - Beijing China return (NULL); 392738c67cbdSjiang wu - Sun Microsystems - Beijing China 392838c67cbdSjiang wu - Sun Microsystems - Beijing China if (mdi_prop_lookup_string(pip, "obp-path", &obp_path) == MDI_SUCCESS) { 392938c67cbdSjiang wu - Sun Microsystems - Beijing China (void) strcpy(path, obp_path); 393038c67cbdSjiang wu - Sun Microsystems - Beijing China (void) mdi_prop_free(obp_path); 393138c67cbdSjiang wu - Sun Microsystems - Beijing China } else { 393238c67cbdSjiang wu - Sun Microsystems - Beijing China path = NULL; 393338c67cbdSjiang wu - Sun Microsystems - Beijing China } 393438c67cbdSjiang wu - Sun Microsystems - Beijing China return (path); 393538c67cbdSjiang wu - Sun Microsystems - Beijing China } 393638c67cbdSjiang wu - Sun Microsystems - Beijing China 393738c67cbdSjiang wu - Sun Microsystems - Beijing China int 393838c67cbdSjiang wu - Sun Microsystems - Beijing China mdi_pi_pathname_obp_set(mdi_pathinfo_t *pip, char *component) 393938c67cbdSjiang wu - Sun Microsystems - Beijing China { 394038c67cbdSjiang wu - Sun Microsystems - Beijing China dev_info_t *pdip; 3941caa9369fSjiang wu - Sun Microsystems - Beijing China char *obp_path = NULL; 3942caa9369fSjiang wu - Sun Microsystems - Beijing China int rc = MDI_FAILURE; 394338c67cbdSjiang wu - Sun Microsystems - Beijing China 394438c67cbdSjiang wu - Sun Microsystems - Beijing China if (pip == NULL) 394538c67cbdSjiang wu - Sun Microsystems - Beijing China return (MDI_FAILURE); 394638c67cbdSjiang wu - Sun Microsystems - Beijing China 394738c67cbdSjiang wu - Sun Microsystems - Beijing China pdip = mdi_pi_get_phci(pip); 394838c67cbdSjiang wu - Sun Microsystems - Beijing China if (pdip == NULL) 394938c67cbdSjiang wu - Sun Microsystems - Beijing China return (MDI_FAILURE); 395038c67cbdSjiang wu - Sun Microsystems - Beijing China 3951caa9369fSjiang wu - Sun Microsystems - Beijing China obp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 3952caa9369fSjiang wu - Sun Microsystems - Beijing China 395338c67cbdSjiang wu - Sun Microsystems - Beijing China if (ddi_pathname_obp(pdip, obp_path) == NULL) { 395438c67cbdSjiang wu - Sun Microsystems - Beijing China (void) ddi_pathname(pdip, obp_path); 395538c67cbdSjiang wu - Sun Microsystems - Beijing China } 395638c67cbdSjiang wu - Sun Microsystems - Beijing China 395738c67cbdSjiang wu - Sun Microsystems - Beijing China if (component) { 3958caa9369fSjiang wu - Sun Microsystems - Beijing China (void) strncat(obp_path, "/", MAXPATHLEN); 3959caa9369fSjiang wu - Sun Microsystems - Beijing China (void) strncat(obp_path, component, MAXPATHLEN); 396038c67cbdSjiang wu - Sun Microsystems - Beijing China } 3961caa9369fSjiang wu - Sun Microsystems - Beijing China rc = mdi_prop_update_string(pip, "obp-path", obp_path); 396238c67cbdSjiang wu - Sun Microsystems - Beijing China 3963caa9369fSjiang wu - Sun Microsystems - Beijing China if (obp_path) 3964caa9369fSjiang wu - Sun Microsystems - Beijing China kmem_free(obp_path, MAXPATHLEN); 3965caa9369fSjiang wu - Sun Microsystems - Beijing China return (rc); 396638c67cbdSjiang wu - Sun Microsystems - Beijing China } 396738c67cbdSjiang wu - Sun Microsystems - Beijing China 3968602ca9eaScth /* 39697c478bd9Sstevel@tonic-gate * mdi_pi_get_client(): 39707c478bd9Sstevel@tonic-gate * Get the client devinfo associated with a mdi_pathinfo node 39717c478bd9Sstevel@tonic-gate * 39727c478bd9Sstevel@tonic-gate * Return Values: 39737c478bd9Sstevel@tonic-gate * Handle to client device dev_info node 39747c478bd9Sstevel@tonic-gate */ 39757c478bd9Sstevel@tonic-gate dev_info_t * 39767c478bd9Sstevel@tonic-gate mdi_pi_get_client(mdi_pathinfo_t *pip) 39777c478bd9Sstevel@tonic-gate { 39787c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 39797c478bd9Sstevel@tonic-gate if (pip) { 39807c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_client->ct_dip; 39817c478bd9Sstevel@tonic-gate } 39827c478bd9Sstevel@tonic-gate return (dip); 39837c478bd9Sstevel@tonic-gate } 39847c478bd9Sstevel@tonic-gate 39857c478bd9Sstevel@tonic-gate /* 39867c478bd9Sstevel@tonic-gate * mdi_pi_get_phci(): 39877c478bd9Sstevel@tonic-gate * Get the pHCI devinfo associated with the mdi_pathinfo node 39887c478bd9Sstevel@tonic-gate * Return Values: 39897c478bd9Sstevel@tonic-gate * Handle to dev_info node 39907c478bd9Sstevel@tonic-gate */ 39917c478bd9Sstevel@tonic-gate dev_info_t * 39927c478bd9Sstevel@tonic-gate mdi_pi_get_phci(mdi_pathinfo_t *pip) 39937c478bd9Sstevel@tonic-gate { 39947c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 39957c478bd9Sstevel@tonic-gate if (pip) { 39967c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_phci->ph_dip; 39977c478bd9Sstevel@tonic-gate } 39987c478bd9Sstevel@tonic-gate return (dip); 39997c478bd9Sstevel@tonic-gate } 40007c478bd9Sstevel@tonic-gate 40017c478bd9Sstevel@tonic-gate /* 40027c478bd9Sstevel@tonic-gate * mdi_pi_get_client_private(): 40037c478bd9Sstevel@tonic-gate * Get the client private information associated with the 40047c478bd9Sstevel@tonic-gate * mdi_pathinfo node 40057c478bd9Sstevel@tonic-gate */ 40067c478bd9Sstevel@tonic-gate void * 40077c478bd9Sstevel@tonic-gate mdi_pi_get_client_private(mdi_pathinfo_t *pip) 40087c478bd9Sstevel@tonic-gate { 40097c478bd9Sstevel@tonic-gate void *cprivate = NULL; 40107c478bd9Sstevel@tonic-gate if (pip) { 40117c478bd9Sstevel@tonic-gate cprivate = MDI_PI(pip)->pi_cprivate; 40127c478bd9Sstevel@tonic-gate } 40137c478bd9Sstevel@tonic-gate return (cprivate); 40147c478bd9Sstevel@tonic-gate } 40157c478bd9Sstevel@tonic-gate 40167c478bd9Sstevel@tonic-gate /* 40177c478bd9Sstevel@tonic-gate * mdi_pi_set_client_private(): 40187c478bd9Sstevel@tonic-gate * Set the client private information in the mdi_pathinfo node 40197c478bd9Sstevel@tonic-gate */ 40207c478bd9Sstevel@tonic-gate void 40217c478bd9Sstevel@tonic-gate mdi_pi_set_client_private(mdi_pathinfo_t *pip, void *priv) 40227c478bd9Sstevel@tonic-gate { 40237c478bd9Sstevel@tonic-gate if (pip) { 40247c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = priv; 40257c478bd9Sstevel@tonic-gate } 40267c478bd9Sstevel@tonic-gate } 40277c478bd9Sstevel@tonic-gate 40287c478bd9Sstevel@tonic-gate /* 40297c478bd9Sstevel@tonic-gate * mdi_pi_get_phci_private(): 40307c478bd9Sstevel@tonic-gate * Get the pHCI private information associated with the 40317c478bd9Sstevel@tonic-gate * mdi_pathinfo node 40327c478bd9Sstevel@tonic-gate */ 40337c478bd9Sstevel@tonic-gate caddr_t 40347c478bd9Sstevel@tonic-gate mdi_pi_get_phci_private(mdi_pathinfo_t *pip) 40357c478bd9Sstevel@tonic-gate { 40367c478bd9Sstevel@tonic-gate caddr_t pprivate = NULL; 40377c478bd9Sstevel@tonic-gate if (pip) { 40387c478bd9Sstevel@tonic-gate pprivate = MDI_PI(pip)->pi_pprivate; 40397c478bd9Sstevel@tonic-gate } 40407c478bd9Sstevel@tonic-gate return (pprivate); 40417c478bd9Sstevel@tonic-gate } 40427c478bd9Sstevel@tonic-gate 40437c478bd9Sstevel@tonic-gate /* 40447c478bd9Sstevel@tonic-gate * mdi_pi_set_phci_private(): 40457c478bd9Sstevel@tonic-gate * Set the pHCI private information in the mdi_pathinfo node 40467c478bd9Sstevel@tonic-gate */ 40477c478bd9Sstevel@tonic-gate void 40487c478bd9Sstevel@tonic-gate mdi_pi_set_phci_private(mdi_pathinfo_t *pip, caddr_t priv) 40497c478bd9Sstevel@tonic-gate { 40507c478bd9Sstevel@tonic-gate if (pip) { 40517c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = priv; 40527c478bd9Sstevel@tonic-gate } 40537c478bd9Sstevel@tonic-gate } 40547c478bd9Sstevel@tonic-gate 40557c478bd9Sstevel@tonic-gate /* 40567c478bd9Sstevel@tonic-gate * mdi_pi_get_state(): 40577c478bd9Sstevel@tonic-gate * Get the mdi_pathinfo node state. Transient states are internal 40587c478bd9Sstevel@tonic-gate * and not provided to the users 40597c478bd9Sstevel@tonic-gate */ 40607c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t 40617c478bd9Sstevel@tonic-gate mdi_pi_get_state(mdi_pathinfo_t *pip) 40627c478bd9Sstevel@tonic-gate { 40637c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t state = MDI_PATHINFO_STATE_INIT; 40647c478bd9Sstevel@tonic-gate 40657c478bd9Sstevel@tonic-gate if (pip) { 40667c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 40677c478bd9Sstevel@tonic-gate /* 40687c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 40697c478bd9Sstevel@tonic-gate * last good state. 40707c478bd9Sstevel@tonic-gate */ 40717c478bd9Sstevel@tonic-gate state = MDI_PI_OLD_STATE(pip); 40727c478bd9Sstevel@tonic-gate } else { 40737c478bd9Sstevel@tonic-gate state = MDI_PI_STATE(pip); 40747c478bd9Sstevel@tonic-gate } 40757c478bd9Sstevel@tonic-gate } 40767c478bd9Sstevel@tonic-gate return (state); 40777c478bd9Sstevel@tonic-gate } 40787c478bd9Sstevel@tonic-gate 40797c478bd9Sstevel@tonic-gate /* 40807c478bd9Sstevel@tonic-gate * Note that the following function needs to be the new interface for 40817c478bd9Sstevel@tonic-gate * mdi_pi_get_state when mpxio gets integrated to ON. 40827c478bd9Sstevel@tonic-gate */ 40837c478bd9Sstevel@tonic-gate int 40847c478bd9Sstevel@tonic-gate mdi_pi_get_state2(mdi_pathinfo_t *pip, mdi_pathinfo_state_t *state, 40857c478bd9Sstevel@tonic-gate uint32_t *ext_state) 40867c478bd9Sstevel@tonic-gate { 40877c478bd9Sstevel@tonic-gate *state = MDI_PATHINFO_STATE_INIT; 40887c478bd9Sstevel@tonic-gate 40897c478bd9Sstevel@tonic-gate if (pip) { 40907c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 40917c478bd9Sstevel@tonic-gate /* 40927c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 40937c478bd9Sstevel@tonic-gate * last good state. 40947c478bd9Sstevel@tonic-gate */ 40957c478bd9Sstevel@tonic-gate *state = MDI_PI_OLD_STATE(pip); 40967c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_OLD_EXT_STATE(pip); 40977c478bd9Sstevel@tonic-gate } else { 40987c478bd9Sstevel@tonic-gate *state = MDI_PI_STATE(pip); 40997c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_EXT_STATE(pip); 41007c478bd9Sstevel@tonic-gate } 41017c478bd9Sstevel@tonic-gate } 41027c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 41037c478bd9Sstevel@tonic-gate } 41047c478bd9Sstevel@tonic-gate 41057c478bd9Sstevel@tonic-gate /* 41067c478bd9Sstevel@tonic-gate * mdi_pi_get_preferred: 41077c478bd9Sstevel@tonic-gate * Get the preferred path flag 41087c478bd9Sstevel@tonic-gate */ 41097c478bd9Sstevel@tonic-gate int 41107c478bd9Sstevel@tonic-gate mdi_pi_get_preferred(mdi_pathinfo_t *pip) 41117c478bd9Sstevel@tonic-gate { 41127c478bd9Sstevel@tonic-gate if (pip) { 41137c478bd9Sstevel@tonic-gate return (MDI_PI(pip)->pi_preferred); 41147c478bd9Sstevel@tonic-gate } 41157c478bd9Sstevel@tonic-gate return (0); 41167c478bd9Sstevel@tonic-gate } 41177c478bd9Sstevel@tonic-gate 41187c478bd9Sstevel@tonic-gate /* 41197c478bd9Sstevel@tonic-gate * mdi_pi_set_preferred: 41207c478bd9Sstevel@tonic-gate * Set the preferred path flag 41217c478bd9Sstevel@tonic-gate */ 41227c478bd9Sstevel@tonic-gate void 41237c478bd9Sstevel@tonic-gate mdi_pi_set_preferred(mdi_pathinfo_t *pip, int preferred) 41247c478bd9Sstevel@tonic-gate { 41257c478bd9Sstevel@tonic-gate if (pip) { 41267c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = preferred; 41277c478bd9Sstevel@tonic-gate } 41287c478bd9Sstevel@tonic-gate } 41297c478bd9Sstevel@tonic-gate 41307c478bd9Sstevel@tonic-gate /* 41317c478bd9Sstevel@tonic-gate * mdi_pi_set_state(): 41327c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state 41337c478bd9Sstevel@tonic-gate */ 41347c478bd9Sstevel@tonic-gate void 41357c478bd9Sstevel@tonic-gate mdi_pi_set_state(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state) 41367c478bd9Sstevel@tonic-gate { 41377c478bd9Sstevel@tonic-gate uint32_t ext_state; 41387c478bd9Sstevel@tonic-gate 41397c478bd9Sstevel@tonic-gate if (pip) { 41407c478bd9Sstevel@tonic-gate ext_state = MDI_PI(pip)->pi_state & MDI_PATHINFO_EXT_STATE_MASK; 41417c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = state; 41427c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state |= ext_state; 41437c478bd9Sstevel@tonic-gate } 41447c478bd9Sstevel@tonic-gate } 41457c478bd9Sstevel@tonic-gate 41467c478bd9Sstevel@tonic-gate /* 41477c478bd9Sstevel@tonic-gate * Property functions: 41487c478bd9Sstevel@tonic-gate */ 41497c478bd9Sstevel@tonic-gate int 41507c478bd9Sstevel@tonic-gate i_map_nvlist_error_to_mdi(int val) 41517c478bd9Sstevel@tonic-gate { 41527c478bd9Sstevel@tonic-gate int rv; 41537c478bd9Sstevel@tonic-gate 41547c478bd9Sstevel@tonic-gate switch (val) { 41557c478bd9Sstevel@tonic-gate case 0: 41567c478bd9Sstevel@tonic-gate rv = DDI_PROP_SUCCESS; 41577c478bd9Sstevel@tonic-gate break; 41587c478bd9Sstevel@tonic-gate case EINVAL: 41597c478bd9Sstevel@tonic-gate case ENOTSUP: 41607c478bd9Sstevel@tonic-gate rv = DDI_PROP_INVAL_ARG; 41617c478bd9Sstevel@tonic-gate break; 41627c478bd9Sstevel@tonic-gate case ENOMEM: 41637c478bd9Sstevel@tonic-gate rv = DDI_PROP_NO_MEMORY; 41647c478bd9Sstevel@tonic-gate break; 41657c478bd9Sstevel@tonic-gate default: 41667c478bd9Sstevel@tonic-gate rv = DDI_PROP_NOT_FOUND; 41677c478bd9Sstevel@tonic-gate break; 41687c478bd9Sstevel@tonic-gate } 41697c478bd9Sstevel@tonic-gate return (rv); 41707c478bd9Sstevel@tonic-gate } 41717c478bd9Sstevel@tonic-gate 41727c478bd9Sstevel@tonic-gate /* 41737c478bd9Sstevel@tonic-gate * mdi_pi_get_next_prop(): 41747c478bd9Sstevel@tonic-gate * Property walk function. The caller should hold mdi_pi_lock() 41757c478bd9Sstevel@tonic-gate * and release by calling mdi_pi_unlock() at the end of walk to 41767c478bd9Sstevel@tonic-gate * get a consistent value. 41777c478bd9Sstevel@tonic-gate */ 41787c478bd9Sstevel@tonic-gate nvpair_t * 41797c478bd9Sstevel@tonic-gate mdi_pi_get_next_prop(mdi_pathinfo_t *pip, nvpair_t *prev) 41807c478bd9Sstevel@tonic-gate { 41817c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41827c478bd9Sstevel@tonic-gate return (NULL); 41837c478bd9Sstevel@tonic-gate } 41845e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 41857c478bd9Sstevel@tonic-gate return (nvlist_next_nvpair(MDI_PI(pip)->pi_prop, prev)); 41867c478bd9Sstevel@tonic-gate } 41877c478bd9Sstevel@tonic-gate 41887c478bd9Sstevel@tonic-gate /* 41897c478bd9Sstevel@tonic-gate * mdi_prop_remove(): 41907c478bd9Sstevel@tonic-gate * Remove the named property from the named list. 41917c478bd9Sstevel@tonic-gate */ 41927c478bd9Sstevel@tonic-gate int 41937c478bd9Sstevel@tonic-gate mdi_prop_remove(mdi_pathinfo_t *pip, char *name) 41947c478bd9Sstevel@tonic-gate { 41957c478bd9Sstevel@tonic-gate if (pip == NULL) { 41967c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41977c478bd9Sstevel@tonic-gate } 41985e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 41997c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 42007c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 42017c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 42027c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 42037c478bd9Sstevel@tonic-gate } 42047c478bd9Sstevel@tonic-gate if (name) { 42057c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, name); 42067c478bd9Sstevel@tonic-gate } else { 42077c478bd9Sstevel@tonic-gate char nvp_name[MAXNAMELEN]; 42087c478bd9Sstevel@tonic-gate nvpair_t *nvp; 42097c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, NULL); 42107c478bd9Sstevel@tonic-gate while (nvp) { 42117c478bd9Sstevel@tonic-gate nvpair_t *next; 42127c478bd9Sstevel@tonic-gate next = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, nvp); 42137c478bd9Sstevel@tonic-gate (void) snprintf(nvp_name, MAXNAMELEN, "%s", 42147c478bd9Sstevel@tonic-gate nvpair_name(nvp)); 42157c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, 42167c478bd9Sstevel@tonic-gate nvp_name); 42177c478bd9Sstevel@tonic-gate nvp = next; 42187c478bd9Sstevel@tonic-gate } 42197c478bd9Sstevel@tonic-gate } 42207c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 42217c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 42227c478bd9Sstevel@tonic-gate } 42237c478bd9Sstevel@tonic-gate 42247c478bd9Sstevel@tonic-gate /* 42257c478bd9Sstevel@tonic-gate * mdi_prop_size(): 42267c478bd9Sstevel@tonic-gate * Get buffer size needed to pack the property data. 42277c478bd9Sstevel@tonic-gate * Caller should hold the mdi_pathinfo_t lock to get a consistent 42287c478bd9Sstevel@tonic-gate * buffer size. 42297c478bd9Sstevel@tonic-gate */ 42307c478bd9Sstevel@tonic-gate int 42317c478bd9Sstevel@tonic-gate mdi_prop_size(mdi_pathinfo_t *pip, size_t *buflenp) 42327c478bd9Sstevel@tonic-gate { 42337c478bd9Sstevel@tonic-gate int rv; 42347c478bd9Sstevel@tonic-gate size_t bufsize; 42357c478bd9Sstevel@tonic-gate 42367c478bd9Sstevel@tonic-gate *buflenp = 0; 42377c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 42387c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 42397c478bd9Sstevel@tonic-gate } 42405e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 42417c478bd9Sstevel@tonic-gate rv = nvlist_size(MDI_PI(pip)->pi_prop, 42427c478bd9Sstevel@tonic-gate &bufsize, NV_ENCODE_NATIVE); 42437c478bd9Sstevel@tonic-gate *buflenp = bufsize; 42447c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 42457c478bd9Sstevel@tonic-gate } 42467c478bd9Sstevel@tonic-gate 42477c478bd9Sstevel@tonic-gate /* 42487c478bd9Sstevel@tonic-gate * mdi_prop_pack(): 42497c478bd9Sstevel@tonic-gate * pack the property list. The caller should hold the 42507c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node to get a consistent data 42517c478bd9Sstevel@tonic-gate */ 42527c478bd9Sstevel@tonic-gate int 42537c478bd9Sstevel@tonic-gate mdi_prop_pack(mdi_pathinfo_t *pip, char **bufp, uint_t buflen) 42547c478bd9Sstevel@tonic-gate { 42557c478bd9Sstevel@tonic-gate int rv; 42567c478bd9Sstevel@tonic-gate size_t bufsize; 42577c478bd9Sstevel@tonic-gate 42587c478bd9Sstevel@tonic-gate if ((pip == NULL) || MDI_PI(pip)->pi_prop == NULL) { 42597c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 42607c478bd9Sstevel@tonic-gate } 42617c478bd9Sstevel@tonic-gate 42625e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 42637c478bd9Sstevel@tonic-gate 42647c478bd9Sstevel@tonic-gate bufsize = buflen; 42657c478bd9Sstevel@tonic-gate rv = nvlist_pack(MDI_PI(pip)->pi_prop, bufp, (size_t *)&bufsize, 42667c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE, KM_SLEEP); 42677c478bd9Sstevel@tonic-gate 42687c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 42697c478bd9Sstevel@tonic-gate } 42707c478bd9Sstevel@tonic-gate 42717c478bd9Sstevel@tonic-gate /* 42727c478bd9Sstevel@tonic-gate * mdi_prop_update_byte(): 42737c478bd9Sstevel@tonic-gate * Create/Update a byte property 42747c478bd9Sstevel@tonic-gate */ 42757c478bd9Sstevel@tonic-gate int 42767c478bd9Sstevel@tonic-gate mdi_prop_update_byte(mdi_pathinfo_t *pip, char *name, uchar_t data) 42777c478bd9Sstevel@tonic-gate { 42787c478bd9Sstevel@tonic-gate int rv; 42797c478bd9Sstevel@tonic-gate 42807c478bd9Sstevel@tonic-gate if (pip == NULL) { 42817c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 42827c478bd9Sstevel@tonic-gate } 42835e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 42847c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 42857c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 42867c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 42877c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 42887c478bd9Sstevel@tonic-gate } 42897c478bd9Sstevel@tonic-gate rv = nvlist_add_byte(MDI_PI(pip)->pi_prop, name, data); 42907c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 42917c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 42927c478bd9Sstevel@tonic-gate } 42937c478bd9Sstevel@tonic-gate 42947c478bd9Sstevel@tonic-gate /* 42957c478bd9Sstevel@tonic-gate * mdi_prop_update_byte_array(): 42967c478bd9Sstevel@tonic-gate * Create/Update a byte array property 42977c478bd9Sstevel@tonic-gate */ 42987c478bd9Sstevel@tonic-gate int 42997c478bd9Sstevel@tonic-gate mdi_prop_update_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t *data, 43007c478bd9Sstevel@tonic-gate uint_t nelements) 43017c478bd9Sstevel@tonic-gate { 43027c478bd9Sstevel@tonic-gate int rv; 43037c478bd9Sstevel@tonic-gate 43047c478bd9Sstevel@tonic-gate if (pip == NULL) { 43057c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 43067c478bd9Sstevel@tonic-gate } 43075e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 43087c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 43097c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 43107c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 43117c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 43127c478bd9Sstevel@tonic-gate } 43137c478bd9Sstevel@tonic-gate rv = nvlist_add_byte_array(MDI_PI(pip)->pi_prop, name, data, nelements); 43147c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 43157c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 43167c478bd9Sstevel@tonic-gate } 43177c478bd9Sstevel@tonic-gate 43187c478bd9Sstevel@tonic-gate /* 43197c478bd9Sstevel@tonic-gate * mdi_prop_update_int(): 43207c478bd9Sstevel@tonic-gate * Create/Update a 32 bit integer property 43217c478bd9Sstevel@tonic-gate */ 43227c478bd9Sstevel@tonic-gate int 43237c478bd9Sstevel@tonic-gate mdi_prop_update_int(mdi_pathinfo_t *pip, char *name, int data) 43247c478bd9Sstevel@tonic-gate { 43257c478bd9Sstevel@tonic-gate int rv; 43267c478bd9Sstevel@tonic-gate 43277c478bd9Sstevel@tonic-gate if (pip == NULL) { 43287c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 43297c478bd9Sstevel@tonic-gate } 43305e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 43317c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 43327c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 43337c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 43347c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 43357c478bd9Sstevel@tonic-gate } 43367c478bd9Sstevel@tonic-gate rv = nvlist_add_int32(MDI_PI(pip)->pi_prop, name, (int32_t)data); 43377c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 43387c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 43397c478bd9Sstevel@tonic-gate } 43407c478bd9Sstevel@tonic-gate 43417c478bd9Sstevel@tonic-gate /* 43427c478bd9Sstevel@tonic-gate * mdi_prop_update_int64(): 43437c478bd9Sstevel@tonic-gate * Create/Update a 64 bit integer property 43447c478bd9Sstevel@tonic-gate */ 43457c478bd9Sstevel@tonic-gate int 43467c478bd9Sstevel@tonic-gate mdi_prop_update_int64(mdi_pathinfo_t *pip, char *name, int64_t data) 43477c478bd9Sstevel@tonic-gate { 43487c478bd9Sstevel@tonic-gate int rv; 43497c478bd9Sstevel@tonic-gate 43507c478bd9Sstevel@tonic-gate if (pip == NULL) { 43517c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 43527c478bd9Sstevel@tonic-gate } 43535e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 43547c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 43557c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 43567c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 43577c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 43587c478bd9Sstevel@tonic-gate } 43597c478bd9Sstevel@tonic-gate rv = nvlist_add_int64(MDI_PI(pip)->pi_prop, name, data); 43607c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 43617c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 43627c478bd9Sstevel@tonic-gate } 43637c478bd9Sstevel@tonic-gate 43647c478bd9Sstevel@tonic-gate /* 43657c478bd9Sstevel@tonic-gate * mdi_prop_update_int_array(): 43667c478bd9Sstevel@tonic-gate * Create/Update a int array property 43677c478bd9Sstevel@tonic-gate */ 43687c478bd9Sstevel@tonic-gate int 43697c478bd9Sstevel@tonic-gate mdi_prop_update_int_array(mdi_pathinfo_t *pip, char *name, int *data, 43707c478bd9Sstevel@tonic-gate uint_t nelements) 43717c478bd9Sstevel@tonic-gate { 43727c478bd9Sstevel@tonic-gate int rv; 43737c478bd9Sstevel@tonic-gate 43747c478bd9Sstevel@tonic-gate if (pip == NULL) { 43757c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 43767c478bd9Sstevel@tonic-gate } 43775e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 43787c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 43797c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 43807c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 43817c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 43827c478bd9Sstevel@tonic-gate } 43837c478bd9Sstevel@tonic-gate rv = nvlist_add_int32_array(MDI_PI(pip)->pi_prop, name, (int32_t *)data, 43847c478bd9Sstevel@tonic-gate nelements); 43857c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 43867c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 43877c478bd9Sstevel@tonic-gate } 43887c478bd9Sstevel@tonic-gate 43897c478bd9Sstevel@tonic-gate /* 43907c478bd9Sstevel@tonic-gate * mdi_prop_update_string(): 43917c478bd9Sstevel@tonic-gate * Create/Update a string property 43927c478bd9Sstevel@tonic-gate */ 43937c478bd9Sstevel@tonic-gate int 43947c478bd9Sstevel@tonic-gate mdi_prop_update_string(mdi_pathinfo_t *pip, char *name, char *data) 43957c478bd9Sstevel@tonic-gate { 43967c478bd9Sstevel@tonic-gate int rv; 43977c478bd9Sstevel@tonic-gate 43987c478bd9Sstevel@tonic-gate if (pip == NULL) { 43997c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 44007c478bd9Sstevel@tonic-gate } 44015e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 44027c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 44037c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 44047c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44057c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 44067c478bd9Sstevel@tonic-gate } 44077c478bd9Sstevel@tonic-gate rv = nvlist_add_string(MDI_PI(pip)->pi_prop, name, data); 44087c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44097c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 44107c478bd9Sstevel@tonic-gate } 44117c478bd9Sstevel@tonic-gate 44127c478bd9Sstevel@tonic-gate /* 44137c478bd9Sstevel@tonic-gate * mdi_prop_update_string_array(): 44147c478bd9Sstevel@tonic-gate * Create/Update a string array property 44157c478bd9Sstevel@tonic-gate */ 44167c478bd9Sstevel@tonic-gate int 44177c478bd9Sstevel@tonic-gate mdi_prop_update_string_array(mdi_pathinfo_t *pip, char *name, char **data, 44187c478bd9Sstevel@tonic-gate uint_t nelements) 44197c478bd9Sstevel@tonic-gate { 44207c478bd9Sstevel@tonic-gate int rv; 44217c478bd9Sstevel@tonic-gate 44227c478bd9Sstevel@tonic-gate if (pip == NULL) { 44237c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 44247c478bd9Sstevel@tonic-gate } 44255e3986cbScth ASSERT(!MDI_PI_LOCKED(pip)); 44267c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 44277c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 44287c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44297c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 44307c478bd9Sstevel@tonic-gate } 44317c478bd9Sstevel@tonic-gate rv = nvlist_add_string_array(MDI_PI(pip)->pi_prop, name, data, 44327c478bd9Sstevel@tonic-gate nelements); 44337c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44347c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 44357c478bd9Sstevel@tonic-gate } 44367c478bd9Sstevel@tonic-gate 44377c478bd9Sstevel@tonic-gate /* 44387c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte(): 44397c478bd9Sstevel@tonic-gate * Look for byte property identified by name. The data returned 44407c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 44417c478bd9Sstevel@tonic-gate * is alive. 44427c478bd9Sstevel@tonic-gate */ 44437c478bd9Sstevel@tonic-gate int 44447c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte(mdi_pathinfo_t *pip, char *name, uchar_t *data) 44457c478bd9Sstevel@tonic-gate { 44467c478bd9Sstevel@tonic-gate int rv; 44477c478bd9Sstevel@tonic-gate 44487c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 44497c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 44507c478bd9Sstevel@tonic-gate } 44517c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte(MDI_PI(pip)->pi_prop, name, data); 44527c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 44537c478bd9Sstevel@tonic-gate } 44547c478bd9Sstevel@tonic-gate 44557c478bd9Sstevel@tonic-gate 44567c478bd9Sstevel@tonic-gate /* 44577c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte_array(): 44587c478bd9Sstevel@tonic-gate * Look for byte array property identified by name. The data 44597c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 44607c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 44617c478bd9Sstevel@tonic-gate */ 44627c478bd9Sstevel@tonic-gate int 44637c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t **data, 44647c478bd9Sstevel@tonic-gate uint_t *nelements) 44657c478bd9Sstevel@tonic-gate { 44667c478bd9Sstevel@tonic-gate int rv; 44677c478bd9Sstevel@tonic-gate 44687c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 44697c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 44707c478bd9Sstevel@tonic-gate } 44717c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte_array(MDI_PI(pip)->pi_prop, name, data, 44727c478bd9Sstevel@tonic-gate nelements); 44737c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 44747c478bd9Sstevel@tonic-gate } 44757c478bd9Sstevel@tonic-gate 44767c478bd9Sstevel@tonic-gate /* 44777c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int(): 44787c478bd9Sstevel@tonic-gate * Look for int property identified by name. The data returned 44797c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t 44807c478bd9Sstevel@tonic-gate * node is alive. 44817c478bd9Sstevel@tonic-gate */ 44827c478bd9Sstevel@tonic-gate int 44837c478bd9Sstevel@tonic-gate mdi_prop_lookup_int(mdi_pathinfo_t *pip, char *name, int *data) 44847c478bd9Sstevel@tonic-gate { 44857c478bd9Sstevel@tonic-gate int rv; 44867c478bd9Sstevel@tonic-gate 44877c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 44887c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 44897c478bd9Sstevel@tonic-gate } 44907c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32(MDI_PI(pip)->pi_prop, name, (int32_t *)data); 44917c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 44927c478bd9Sstevel@tonic-gate } 44937c478bd9Sstevel@tonic-gate 44947c478bd9Sstevel@tonic-gate /* 44957c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int64(): 44967c478bd9Sstevel@tonic-gate * Look for int64 property identified by name. The data returned 44977c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 44987c478bd9Sstevel@tonic-gate * is alive. 44997c478bd9Sstevel@tonic-gate */ 45007c478bd9Sstevel@tonic-gate int 45017c478bd9Sstevel@tonic-gate mdi_prop_lookup_int64(mdi_pathinfo_t *pip, char *name, int64_t *data) 45027c478bd9Sstevel@tonic-gate { 45037c478bd9Sstevel@tonic-gate int rv; 45047c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 45057c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 45067c478bd9Sstevel@tonic-gate } 45077c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int64(MDI_PI(pip)->pi_prop, name, data); 45087c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 45097c478bd9Sstevel@tonic-gate } 45107c478bd9Sstevel@tonic-gate 45117c478bd9Sstevel@tonic-gate /* 45127c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int_array(): 45137c478bd9Sstevel@tonic-gate * Look for int array property identified by name. The data 45147c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 45157c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 45167c478bd9Sstevel@tonic-gate */ 45177c478bd9Sstevel@tonic-gate int 45187c478bd9Sstevel@tonic-gate mdi_prop_lookup_int_array(mdi_pathinfo_t *pip, char *name, int **data, 45197c478bd9Sstevel@tonic-gate uint_t *nelements) 45207c478bd9Sstevel@tonic-gate { 45217c478bd9Sstevel@tonic-gate int rv; 45227c478bd9Sstevel@tonic-gate 45237c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 45247c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 45257c478bd9Sstevel@tonic-gate } 45267c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32_array(MDI_PI(pip)->pi_prop, name, 45277c478bd9Sstevel@tonic-gate (int32_t **)data, nelements); 45287c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 45297c478bd9Sstevel@tonic-gate } 45307c478bd9Sstevel@tonic-gate 45317c478bd9Sstevel@tonic-gate /* 45327c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string(): 45337c478bd9Sstevel@tonic-gate * Look for string property identified by name. The data 45347c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 45357c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 45367c478bd9Sstevel@tonic-gate */ 45377c478bd9Sstevel@tonic-gate int 45387c478bd9Sstevel@tonic-gate mdi_prop_lookup_string(mdi_pathinfo_t *pip, char *name, char **data) 45397c478bd9Sstevel@tonic-gate { 45407c478bd9Sstevel@tonic-gate int rv; 45417c478bd9Sstevel@tonic-gate 45427c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 45437c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 45447c478bd9Sstevel@tonic-gate } 45457c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string(MDI_PI(pip)->pi_prop, name, data); 45467c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 45477c478bd9Sstevel@tonic-gate } 45487c478bd9Sstevel@tonic-gate 45497c478bd9Sstevel@tonic-gate /* 45507c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string_array(): 45517c478bd9Sstevel@tonic-gate * Look for string array property identified by name. The data 45527c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 45537c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 45547c478bd9Sstevel@tonic-gate */ 45557c478bd9Sstevel@tonic-gate int 45567c478bd9Sstevel@tonic-gate mdi_prop_lookup_string_array(mdi_pathinfo_t *pip, char *name, char ***data, 45577c478bd9Sstevel@tonic-gate uint_t *nelements) 45587c478bd9Sstevel@tonic-gate { 45597c478bd9Sstevel@tonic-gate int rv; 45607c478bd9Sstevel@tonic-gate 45617c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 45627c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 45637c478bd9Sstevel@tonic-gate } 45647c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string_array(MDI_PI(pip)->pi_prop, name, data, 45657c478bd9Sstevel@tonic-gate nelements); 45667c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 45677c478bd9Sstevel@tonic-gate } 45687c478bd9Sstevel@tonic-gate 45697c478bd9Sstevel@tonic-gate /* 45707c478bd9Sstevel@tonic-gate * mdi_prop_free(): 45717c478bd9Sstevel@tonic-gate * Symmetrical function to ddi_prop_free(). nvlist_lookup_xx() 45727c478bd9Sstevel@tonic-gate * functions return the pointer to actual property data and not a 45737c478bd9Sstevel@tonic-gate * copy of it. So the data returned is valid as long as 45747c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is valid. 45757c478bd9Sstevel@tonic-gate */ 45767c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 45777c478bd9Sstevel@tonic-gate int 45787c478bd9Sstevel@tonic-gate mdi_prop_free(void *data) 45797c478bd9Sstevel@tonic-gate { 45807c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 45817c478bd9Sstevel@tonic-gate } 45827c478bd9Sstevel@tonic-gate 45837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 45847c478bd9Sstevel@tonic-gate static void 45857c478bd9Sstevel@tonic-gate i_mdi_report_path_state(mdi_client_t *ct, mdi_pathinfo_t *pip) 45867c478bd9Sstevel@tonic-gate { 45877c478bd9Sstevel@tonic-gate char *phci_path, *ct_path; 45887c478bd9Sstevel@tonic-gate char *ct_status; 45897c478bd9Sstevel@tonic-gate char *status; 45907c478bd9Sstevel@tonic-gate dev_info_t *dip = ct->ct_dip; 45917c478bd9Sstevel@tonic-gate char lb_buf[64]; 45927c478bd9Sstevel@tonic-gate 45935e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 45947c478bd9Sstevel@tonic-gate if ((dip == NULL) || (ddi_get_instance(dip) == -1) || 45957c478bd9Sstevel@tonic-gate (MDI_CLIENT_IS_REPORT_DEV_NEEDED(ct) == 0)) { 45967c478bd9Sstevel@tonic-gate return; 45977c478bd9Sstevel@tonic-gate } 45987c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL) { 45997c478bd9Sstevel@tonic-gate ct_status = "optimal"; 46007c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) { 46017c478bd9Sstevel@tonic-gate ct_status = "degraded"; 46027c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 46037c478bd9Sstevel@tonic-gate ct_status = "failed"; 46047c478bd9Sstevel@tonic-gate } else { 46057c478bd9Sstevel@tonic-gate ct_status = "unknown"; 46067c478bd9Sstevel@tonic-gate } 46077c478bd9Sstevel@tonic-gate 46087c478bd9Sstevel@tonic-gate if (MDI_PI_IS_OFFLINE(pip)) { 46097c478bd9Sstevel@tonic-gate status = "offline"; 46107c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_ONLINE(pip)) { 46117c478bd9Sstevel@tonic-gate status = "online"; 46127c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_STANDBY(pip)) { 46137c478bd9Sstevel@tonic-gate status = "standby"; 46147c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_FAULT(pip)) { 46157c478bd9Sstevel@tonic-gate status = "faulted"; 46167c478bd9Sstevel@tonic-gate } else { 46177c478bd9Sstevel@tonic-gate status = "unknown"; 46187c478bd9Sstevel@tonic-gate } 46197c478bd9Sstevel@tonic-gate 46207c478bd9Sstevel@tonic-gate if (ct->ct_lb == LOAD_BALANCE_LBA) { 46217c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 46227c478bd9Sstevel@tonic-gate "%s, region-size: %d", mdi_load_balance_lba, 46237c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size); 46247c478bd9Sstevel@tonic-gate } else if (ct->ct_lb == LOAD_BALANCE_NONE) { 46257c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 46267c478bd9Sstevel@tonic-gate "%s", mdi_load_balance_none); 46277c478bd9Sstevel@tonic-gate } else { 46287c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), "%s", 46297c478bd9Sstevel@tonic-gate mdi_load_balance_rr); 46307c478bd9Sstevel@tonic-gate } 46317c478bd9Sstevel@tonic-gate 46327c478bd9Sstevel@tonic-gate if (dip) { 46337c478bd9Sstevel@tonic-gate ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 46347c478bd9Sstevel@tonic-gate phci_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 46357c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s (%s%d) multipath status: %s, " 46367c478bd9Sstevel@tonic-gate "path %s (%s%d) to target address: %s is %s" 46377c478bd9Sstevel@tonic-gate " Load balancing: %s\n", 46387c478bd9Sstevel@tonic-gate ddi_pathname(dip, ct_path), ddi_driver_name(dip), 46397c478bd9Sstevel@tonic-gate ddi_get_instance(dip), ct_status, 46407c478bd9Sstevel@tonic-gate ddi_pathname(MDI_PI(pip)->pi_phci->ph_dip, phci_path), 46417c478bd9Sstevel@tonic-gate ddi_driver_name(MDI_PI(pip)->pi_phci->ph_dip), 46427c478bd9Sstevel@tonic-gate ddi_get_instance(MDI_PI(pip)->pi_phci->ph_dip), 46437c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr, status, lb_buf); 46447c478bd9Sstevel@tonic-gate kmem_free(phci_path, MAXPATHLEN); 46457c478bd9Sstevel@tonic-gate kmem_free(ct_path, MAXPATHLEN); 46467c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct); 46477c478bd9Sstevel@tonic-gate } 46487c478bd9Sstevel@tonic-gate } 46497c478bd9Sstevel@tonic-gate 46507c478bd9Sstevel@tonic-gate #ifdef DEBUG 46517c478bd9Sstevel@tonic-gate /* 46527c478bd9Sstevel@tonic-gate * i_mdi_log(): 46537c478bd9Sstevel@tonic-gate * Utility function for error message management 46547c478bd9Sstevel@tonic-gate * 46557c478bd9Sstevel@tonic-gate */ 46565e3986cbScth /*PRINTFLIKE3*/ 46577c478bd9Sstevel@tonic-gate static void 46587c478bd9Sstevel@tonic-gate i_mdi_log(int level, dev_info_t *dip, const char *fmt, ...) 46597c478bd9Sstevel@tonic-gate { 4660c73a93f2Sdm120769 char name[MAXNAMELEN]; 46615e3986cbScth char buf[MAXNAMELEN]; 46625e3986cbScth char *bp; 46637c478bd9Sstevel@tonic-gate va_list ap; 46647c478bd9Sstevel@tonic-gate int log_only = 0; 46657c478bd9Sstevel@tonic-gate int boot_only = 0; 46667c478bd9Sstevel@tonic-gate int console_only = 0; 46677c478bd9Sstevel@tonic-gate 46687c478bd9Sstevel@tonic-gate if (dip) { 4669c73a93f2Sdm120769 (void) snprintf(name, MAXNAMELEN, "%s%d: ", 4670c73a93f2Sdm120769 ddi_node_name(dip), ddi_get_instance(dip)); 4671c73a93f2Sdm120769 } else { 46725e3986cbScth name[0] = 0; 46737c478bd9Sstevel@tonic-gate } 46747c478bd9Sstevel@tonic-gate 46757c478bd9Sstevel@tonic-gate va_start(ap, fmt); 46767c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, MAXNAMELEN, fmt, ap); 46777c478bd9Sstevel@tonic-gate va_end(ap); 46787c478bd9Sstevel@tonic-gate 46797c478bd9Sstevel@tonic-gate switch (buf[0]) { 46807c478bd9Sstevel@tonic-gate case '!': 46815e3986cbScth bp = &buf[1]; 46827c478bd9Sstevel@tonic-gate log_only = 1; 46837c478bd9Sstevel@tonic-gate break; 46847c478bd9Sstevel@tonic-gate case '?': 46855e3986cbScth bp = &buf[1]; 46867c478bd9Sstevel@tonic-gate boot_only = 1; 46877c478bd9Sstevel@tonic-gate break; 46887c478bd9Sstevel@tonic-gate case '^': 46895e3986cbScth bp = &buf[1]; 46907c478bd9Sstevel@tonic-gate console_only = 1; 46917c478bd9Sstevel@tonic-gate break; 46925e3986cbScth default: 46935e3986cbScth bp = buf; 46945e3986cbScth break; 46955e3986cbScth } 46965e3986cbScth if (mdi_debug_logonly) { 46975e3986cbScth log_only = 1; 46985e3986cbScth boot_only = 0; 46995e3986cbScth console_only = 0; 47007c478bd9Sstevel@tonic-gate } 47017c478bd9Sstevel@tonic-gate 47027c478bd9Sstevel@tonic-gate switch (level) { 47037c478bd9Sstevel@tonic-gate case CE_NOTE: 47047c478bd9Sstevel@tonic-gate level = CE_CONT; 47057c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 47067c478bd9Sstevel@tonic-gate case CE_CONT: 47077c478bd9Sstevel@tonic-gate case CE_WARN: 47087c478bd9Sstevel@tonic-gate case CE_PANIC: 47097c478bd9Sstevel@tonic-gate if (boot_only) { 47105e3986cbScth cmn_err(level, "?mdi: %s%s", name, bp); 47117c478bd9Sstevel@tonic-gate } else if (console_only) { 47125e3986cbScth cmn_err(level, "^mdi: %s%s", name, bp); 47137c478bd9Sstevel@tonic-gate } else if (log_only) { 47145e3986cbScth cmn_err(level, "!mdi: %s%s", name, bp); 47157c478bd9Sstevel@tonic-gate } else { 47165e3986cbScth cmn_err(level, "mdi: %s%s", name, bp); 47177c478bd9Sstevel@tonic-gate } 47187c478bd9Sstevel@tonic-gate break; 47197c478bd9Sstevel@tonic-gate default: 47205e3986cbScth cmn_err(level, "mdi: %s%s", name, bp); 47217c478bd9Sstevel@tonic-gate break; 47227c478bd9Sstevel@tonic-gate } 47237c478bd9Sstevel@tonic-gate } 47247c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 47257c478bd9Sstevel@tonic-gate 47267c478bd9Sstevel@tonic-gate void 47277c478bd9Sstevel@tonic-gate i_mdi_client_online(dev_info_t *ct_dip) 47287c478bd9Sstevel@tonic-gate { 47297c478bd9Sstevel@tonic-gate mdi_client_t *ct; 47307c478bd9Sstevel@tonic-gate 47317c478bd9Sstevel@tonic-gate /* 47327c478bd9Sstevel@tonic-gate * Client online notification. Mark client state as online 47337c478bd9Sstevel@tonic-gate * restore our binding with dev_info node 47347c478bd9Sstevel@tonic-gate */ 47357c478bd9Sstevel@tonic-gate ct = i_devi_get_client(ct_dip); 47367c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 47377c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 47387c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 47397c478bd9Sstevel@tonic-gate /* catch for any memory leaks */ 47407c478bd9Sstevel@tonic-gate ASSERT((ct->ct_dip == NULL) || (ct->ct_dip == ct_dip)); 47417c478bd9Sstevel@tonic-gate ct->ct_dip = ct_dip; 47427c478bd9Sstevel@tonic-gate 47437c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) 47447c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 47457c478bd9Sstevel@tonic-gate 47467c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct_dip, "i_mdi_client_online " 47475e3986cbScth "i_mdi_pm_hold_client %p\n", (void *)ct)); 47487c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 47497c478bd9Sstevel@tonic-gate 47507c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 47517c478bd9Sstevel@tonic-gate } 47527c478bd9Sstevel@tonic-gate 47537c478bd9Sstevel@tonic-gate void 47547c478bd9Sstevel@tonic-gate i_mdi_phci_online(dev_info_t *ph_dip) 47557c478bd9Sstevel@tonic-gate { 47567c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 47577c478bd9Sstevel@tonic-gate 47587c478bd9Sstevel@tonic-gate /* pHCI online notification. Mark state accordingly */ 47597c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(ph_dip); 47607c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 47617c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 47627c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 47637c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 47647c478bd9Sstevel@tonic-gate } 47657c478bd9Sstevel@tonic-gate 47667c478bd9Sstevel@tonic-gate /* 47677c478bd9Sstevel@tonic-gate * mdi_devi_online(): 47687c478bd9Sstevel@tonic-gate * Online notification from NDI framework on pHCI/client 47697c478bd9Sstevel@tonic-gate * device online. 47707c478bd9Sstevel@tonic-gate * Return Values: 47717c478bd9Sstevel@tonic-gate * NDI_SUCCESS 47727c478bd9Sstevel@tonic-gate * MDI_FAILURE 47737c478bd9Sstevel@tonic-gate */ 47747c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47757c478bd9Sstevel@tonic-gate int 47767c478bd9Sstevel@tonic-gate mdi_devi_online(dev_info_t *dip, uint_t flags) 47777c478bd9Sstevel@tonic-gate { 47787c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 47797c478bd9Sstevel@tonic-gate i_mdi_phci_online(dip); 47807c478bd9Sstevel@tonic-gate } 47817c478bd9Sstevel@tonic-gate 47827c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 47837c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 47847c478bd9Sstevel@tonic-gate } 47857c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 47867c478bd9Sstevel@tonic-gate } 47877c478bd9Sstevel@tonic-gate 47887c478bd9Sstevel@tonic-gate /* 47897c478bd9Sstevel@tonic-gate * mdi_devi_offline(): 47907c478bd9Sstevel@tonic-gate * Offline notification from NDI framework on pHCI/Client device 47917c478bd9Sstevel@tonic-gate * offline. 47927c478bd9Sstevel@tonic-gate * 47937c478bd9Sstevel@tonic-gate * Return Values: 47947c478bd9Sstevel@tonic-gate * NDI_SUCCESS 47957c478bd9Sstevel@tonic-gate * NDI_FAILURE 47967c478bd9Sstevel@tonic-gate */ 47977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47987c478bd9Sstevel@tonic-gate int 47997c478bd9Sstevel@tonic-gate mdi_devi_offline(dev_info_t *dip, uint_t flags) 48007c478bd9Sstevel@tonic-gate { 48017c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 48027c478bd9Sstevel@tonic-gate 48037c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 48047c478bd9Sstevel@tonic-gate rv = i_mdi_client_offline(dip, flags); 48057c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) 48067c478bd9Sstevel@tonic-gate return (rv); 48077c478bd9Sstevel@tonic-gate } 48087c478bd9Sstevel@tonic-gate 48097c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 48107c478bd9Sstevel@tonic-gate rv = i_mdi_phci_offline(dip, flags); 48115e3986cbScth 48127c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && MDI_CLIENT(dip)) { 48137c478bd9Sstevel@tonic-gate /* set client back online */ 48147c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 48157c478bd9Sstevel@tonic-gate } 48167c478bd9Sstevel@tonic-gate } 48177c478bd9Sstevel@tonic-gate 48187c478bd9Sstevel@tonic-gate return (rv); 48197c478bd9Sstevel@tonic-gate } 48207c478bd9Sstevel@tonic-gate 48217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 48227c478bd9Sstevel@tonic-gate static int 48237c478bd9Sstevel@tonic-gate i_mdi_phci_offline(dev_info_t *dip, uint_t flags) 48247c478bd9Sstevel@tonic-gate { 48257c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 48267c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 48277c478bd9Sstevel@tonic-gate mdi_client_t *ct; 48287c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 48297c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 48307c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 48317c478bd9Sstevel@tonic-gate dev_info_t *cdip; 48327c478bd9Sstevel@tonic-gate 48337c478bd9Sstevel@tonic-gate /* 48347c478bd9Sstevel@tonic-gate * pHCI component offline notification 48357c478bd9Sstevel@tonic-gate * Make sure that this pHCI instance is free to be offlined. 48367c478bd9Sstevel@tonic-gate * If it is OK to proceed, Offline and remove all the child 48377c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes. This process automatically offlines 48387c478bd9Sstevel@tonic-gate * corresponding client devices, for which this pHCI provides 48397c478bd9Sstevel@tonic-gate * critical services. 48407c478bd9Sstevel@tonic-gate */ 48417c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 48425e3986cbScth MDI_DEBUG(2, (CE_NOTE, dip, "!mdi_phci_offline called %p %p\n", 48435e3986cbScth (void *)dip, (void *)ph)); 48447c478bd9Sstevel@tonic-gate if (ph == NULL) { 48457c478bd9Sstevel@tonic-gate return (rv); 48467c478bd9Sstevel@tonic-gate } 48477c478bd9Sstevel@tonic-gate 48487c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 48497c478bd9Sstevel@tonic-gate 48507c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_OFFLINE(ph)) { 48515e3986cbScth MDI_DEBUG(1, (CE_WARN, dip, "!pHCI %p already offlined", 48525e3986cbScth (void *)ph)); 48537c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 48547c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 48557c478bd9Sstevel@tonic-gate } 48567c478bd9Sstevel@tonic-gate 48577c478bd9Sstevel@tonic-gate /* 48587c478bd9Sstevel@tonic-gate * Check to see if the pHCI can be offlined 48597c478bd9Sstevel@tonic-gate */ 48607c478bd9Sstevel@tonic-gate if (ph->ph_unstable) { 48617c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 48627c478bd9Sstevel@tonic-gate "!One or more target devices are in transient " 48637c478bd9Sstevel@tonic-gate "state. This device can not be removed at " 48647c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 48657c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 48667c478bd9Sstevel@tonic-gate return (NDI_BUSY); 48677c478bd9Sstevel@tonic-gate } 48687c478bd9Sstevel@tonic-gate 48697c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 48707c478bd9Sstevel@tonic-gate while (pip != NULL) { 48717c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 48727c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 48735e3986cbScth 48747c478bd9Sstevel@tonic-gate /* 48757c478bd9Sstevel@tonic-gate * The mdi_pathinfo state is OK. Check the client state. 48767c478bd9Sstevel@tonic-gate * If failover in progress fail the pHCI from offlining 48777c478bd9Sstevel@tonic-gate */ 48787c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 48797c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 48807c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 48817c478bd9Sstevel@tonic-gate (ct->ct_unstable)) { 48827c478bd9Sstevel@tonic-gate /* 48837c478bd9Sstevel@tonic-gate * Failover is in progress, Fail the DR 48847c478bd9Sstevel@tonic-gate */ 48857c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 48867c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 48877c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 48887c478bd9Sstevel@tonic-gate "This device can not be removed at " 48897c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 48907c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 48915e3986cbScth i_mdi_client_unlock(ct); 48927c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 48937c478bd9Sstevel@tonic-gate return (NDI_BUSY); 48947c478bd9Sstevel@tonic-gate } 48957c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 48967c478bd9Sstevel@tonic-gate 48977c478bd9Sstevel@tonic-gate /* 48987c478bd9Sstevel@tonic-gate * Check to see of we are removing the last path of this 48997c478bd9Sstevel@tonic-gate * client device... 49007c478bd9Sstevel@tonic-gate */ 49017c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 49027c478bd9Sstevel@tonic-gate if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 49037c478bd9Sstevel@tonic-gate (i_mdi_client_compute_state(ct, ph) == 49047c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_FAILED)) { 49057c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49067c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 49077c478bd9Sstevel@tonic-gate if (ndi_devi_offline(cdip, 0) != NDI_SUCCESS) { 49087c478bd9Sstevel@tonic-gate /* 49097c478bd9Sstevel@tonic-gate * ndi_devi_offline() failed. 49107c478bd9Sstevel@tonic-gate * This pHCI provides the critical path 49117c478bd9Sstevel@tonic-gate * to one or more client devices. 49127c478bd9Sstevel@tonic-gate * Return busy. 49137c478bd9Sstevel@tonic-gate */ 49147c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 49157c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 49167c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 49177c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 49187c478bd9Sstevel@tonic-gate "This device can not be removed at " 49197c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 49207c478bd9Sstevel@tonic-gate failed_pip = pip; 49217c478bd9Sstevel@tonic-gate break; 49227c478bd9Sstevel@tonic-gate } else { 49237c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 49247c478bd9Sstevel@tonic-gate pip = next; 49257c478bd9Sstevel@tonic-gate } 49267c478bd9Sstevel@tonic-gate } else { 49277c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49287c478bd9Sstevel@tonic-gate pip = next; 49297c478bd9Sstevel@tonic-gate } 49307c478bd9Sstevel@tonic-gate } 49317c478bd9Sstevel@tonic-gate 49327c478bd9Sstevel@tonic-gate if (failed_pip) { 49337c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 49347c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 49357c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 49367c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 49377c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 49387c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 49397c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 49407c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 49417c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 49427c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 49437c478bd9Sstevel@tonic-gate if (cdip) { 49447c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 49457c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49467c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 49477c478bd9Sstevel@tonic-gate (void) ndi_devi_online(cdip, 0); 49487c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 49497c478bd9Sstevel@tonic-gate pip = next; 49507c478bd9Sstevel@tonic-gate continue; 49517c478bd9Sstevel@tonic-gate } 49527c478bd9Sstevel@tonic-gate break; 49537c478bd9Sstevel@tonic-gate 49547c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 49557c478bd9Sstevel@tonic-gate if (cdip) { 49567c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 49577c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49587c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 49597c478bd9Sstevel@tonic-gate (void) ndi_devi_offline(cdip, 0); 49607c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 49617c478bd9Sstevel@tonic-gate pip = next; 49627c478bd9Sstevel@tonic-gate continue; 49637c478bd9Sstevel@tonic-gate } 49647c478bd9Sstevel@tonic-gate break; 49657c478bd9Sstevel@tonic-gate } 49667c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 49677c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49687c478bd9Sstevel@tonic-gate pip = next; 49697c478bd9Sstevel@tonic-gate } 49707c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 49717c478bd9Sstevel@tonic-gate return (NDI_BUSY); 49727c478bd9Sstevel@tonic-gate } 49737c478bd9Sstevel@tonic-gate 49747c478bd9Sstevel@tonic-gate /* 49757c478bd9Sstevel@tonic-gate * Mark the pHCI as offline 49767c478bd9Sstevel@tonic-gate */ 49777c478bd9Sstevel@tonic-gate MDI_PHCI_SET_OFFLINE(ph); 49787c478bd9Sstevel@tonic-gate 49797c478bd9Sstevel@tonic-gate /* 49807c478bd9Sstevel@tonic-gate * Mark the child mdi_pathinfo nodes as transient 49817c478bd9Sstevel@tonic-gate */ 49827c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 49837c478bd9Sstevel@tonic-gate while (pip != NULL) { 49847c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 49857c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 49867c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 49877c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 49887c478bd9Sstevel@tonic-gate pip = next; 49897c478bd9Sstevel@tonic-gate } 49907c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 49917c478bd9Sstevel@tonic-gate /* 49927c478bd9Sstevel@tonic-gate * Give a chance for any pending commands to execute 49937c478bd9Sstevel@tonic-gate */ 49947c478bd9Sstevel@tonic-gate delay(1); 49957c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 49967c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 49977c478bd9Sstevel@tonic-gate while (pip != NULL) { 49987c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 49997c478bd9Sstevel@tonic-gate (void) i_mdi_pi_offline(pip, flags); 50007c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 50017c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 50027c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_OFFLINE(pip)) { 50037c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 50047c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 50057c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 50067c478bd9Sstevel@tonic-gate "This device can not be removed at " 50077c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 50087c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 50097c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 50107c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 50117c478bd9Sstevel@tonic-gate return (NDI_BUSY); 50127c478bd9Sstevel@tonic-gate } 50137c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 50147c478bd9Sstevel@tonic-gate pip = next; 50157c478bd9Sstevel@tonic-gate } 50167c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 50177c478bd9Sstevel@tonic-gate 50187c478bd9Sstevel@tonic-gate return (rv); 50197c478bd9Sstevel@tonic-gate } 50207c478bd9Sstevel@tonic-gate 502125e8c5aaSvikram void 502225e8c5aaSvikram mdi_phci_mark_retiring(dev_info_t *dip, char **cons_array) 502325e8c5aaSvikram { 502425e8c5aaSvikram mdi_phci_t *ph; 502525e8c5aaSvikram mdi_client_t *ct; 502625e8c5aaSvikram mdi_pathinfo_t *pip; 502725e8c5aaSvikram mdi_pathinfo_t *next; 502825e8c5aaSvikram dev_info_t *cdip; 502925e8c5aaSvikram 503025e8c5aaSvikram if (!MDI_PHCI(dip)) 503125e8c5aaSvikram return; 503225e8c5aaSvikram 503325e8c5aaSvikram ph = i_devi_get_phci(dip); 503425e8c5aaSvikram if (ph == NULL) { 503525e8c5aaSvikram return; 503625e8c5aaSvikram } 503725e8c5aaSvikram 503825e8c5aaSvikram MDI_PHCI_LOCK(ph); 503925e8c5aaSvikram 504025e8c5aaSvikram if (MDI_PHCI_IS_OFFLINE(ph)) { 504125e8c5aaSvikram /* has no last path */ 504225e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 504325e8c5aaSvikram return; 504425e8c5aaSvikram } 504525e8c5aaSvikram 504625e8c5aaSvikram pip = ph->ph_path_head; 504725e8c5aaSvikram while (pip != NULL) { 504825e8c5aaSvikram MDI_PI_LOCK(pip); 504925e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 505025e8c5aaSvikram 505125e8c5aaSvikram ct = MDI_PI(pip)->pi_client; 505225e8c5aaSvikram i_mdi_client_lock(ct, pip); 505325e8c5aaSvikram MDI_PI_UNLOCK(pip); 505425e8c5aaSvikram 505525e8c5aaSvikram cdip = ct->ct_dip; 505625e8c5aaSvikram if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 505725e8c5aaSvikram (i_mdi_client_compute_state(ct, ph) == 505825e8c5aaSvikram MDI_CLIENT_STATE_FAILED)) { 505925e8c5aaSvikram /* Last path. Mark client dip as retiring */ 506025e8c5aaSvikram i_mdi_client_unlock(ct); 506125e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 506225e8c5aaSvikram (void) e_ddi_mark_retiring(cdip, cons_array); 506325e8c5aaSvikram MDI_PHCI_LOCK(ph); 506425e8c5aaSvikram pip = next; 506525e8c5aaSvikram } else { 506625e8c5aaSvikram i_mdi_client_unlock(ct); 506725e8c5aaSvikram pip = next; 506825e8c5aaSvikram } 506925e8c5aaSvikram } 507025e8c5aaSvikram 507125e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 507225e8c5aaSvikram 507325e8c5aaSvikram return; 507425e8c5aaSvikram } 507525e8c5aaSvikram 507625e8c5aaSvikram void 507725e8c5aaSvikram mdi_phci_retire_notify(dev_info_t *dip, int *constraint) 507825e8c5aaSvikram { 507925e8c5aaSvikram mdi_phci_t *ph; 508025e8c5aaSvikram mdi_client_t *ct; 508125e8c5aaSvikram mdi_pathinfo_t *pip; 508225e8c5aaSvikram mdi_pathinfo_t *next; 508325e8c5aaSvikram dev_info_t *cdip; 508425e8c5aaSvikram 508525e8c5aaSvikram if (!MDI_PHCI(dip)) 508625e8c5aaSvikram return; 508725e8c5aaSvikram 508825e8c5aaSvikram ph = i_devi_get_phci(dip); 508925e8c5aaSvikram if (ph == NULL) 509025e8c5aaSvikram return; 509125e8c5aaSvikram 509225e8c5aaSvikram MDI_PHCI_LOCK(ph); 509325e8c5aaSvikram 509425e8c5aaSvikram if (MDI_PHCI_IS_OFFLINE(ph)) { 509525e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 509625e8c5aaSvikram /* not last path */ 509725e8c5aaSvikram return; 509825e8c5aaSvikram } 509925e8c5aaSvikram 510025e8c5aaSvikram if (ph->ph_unstable) { 510125e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 510225e8c5aaSvikram /* can't check for constraints */ 510325e8c5aaSvikram *constraint = 0; 510425e8c5aaSvikram return; 510525e8c5aaSvikram } 510625e8c5aaSvikram 510725e8c5aaSvikram pip = ph->ph_path_head; 510825e8c5aaSvikram while (pip != NULL) { 510925e8c5aaSvikram MDI_PI_LOCK(pip); 511025e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 511125e8c5aaSvikram 511225e8c5aaSvikram /* 511325e8c5aaSvikram * The mdi_pathinfo state is OK. Check the client state. 511425e8c5aaSvikram * If failover in progress fail the pHCI from offlining 511525e8c5aaSvikram */ 511625e8c5aaSvikram ct = MDI_PI(pip)->pi_client; 511725e8c5aaSvikram i_mdi_client_lock(ct, pip); 511825e8c5aaSvikram if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 511925e8c5aaSvikram (ct->ct_unstable)) { 512025e8c5aaSvikram /* 512125e8c5aaSvikram * Failover is in progress, can't check for constraints 512225e8c5aaSvikram */ 512325e8c5aaSvikram MDI_PI_UNLOCK(pip); 512425e8c5aaSvikram i_mdi_client_unlock(ct); 512525e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 512625e8c5aaSvikram *constraint = 0; 512725e8c5aaSvikram return; 512825e8c5aaSvikram } 512925e8c5aaSvikram MDI_PI_UNLOCK(pip); 513025e8c5aaSvikram 513125e8c5aaSvikram /* 513225e8c5aaSvikram * Check to see of we are retiring the last path of this 513325e8c5aaSvikram * client device... 513425e8c5aaSvikram */ 513525e8c5aaSvikram cdip = ct->ct_dip; 513625e8c5aaSvikram if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 513725e8c5aaSvikram (i_mdi_client_compute_state(ct, ph) == 513825e8c5aaSvikram MDI_CLIENT_STATE_FAILED)) { 513925e8c5aaSvikram i_mdi_client_unlock(ct); 514025e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 514125e8c5aaSvikram (void) e_ddi_retire_notify(cdip, constraint); 514225e8c5aaSvikram MDI_PHCI_LOCK(ph); 514325e8c5aaSvikram pip = next; 514425e8c5aaSvikram } else { 514525e8c5aaSvikram i_mdi_client_unlock(ct); 514625e8c5aaSvikram pip = next; 514725e8c5aaSvikram } 514825e8c5aaSvikram } 514925e8c5aaSvikram 515025e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 515125e8c5aaSvikram 515225e8c5aaSvikram return; 515325e8c5aaSvikram } 515425e8c5aaSvikram 515525e8c5aaSvikram /* 515625e8c5aaSvikram * offline the path(s) hanging off the PHCI. If the 515725e8c5aaSvikram * last path to any client, check that constraints 515825e8c5aaSvikram * have been applied. 515925e8c5aaSvikram */ 516025e8c5aaSvikram void 516125e8c5aaSvikram mdi_phci_retire_finalize(dev_info_t *dip, int phci_only) 516225e8c5aaSvikram { 516325e8c5aaSvikram mdi_phci_t *ph; 516425e8c5aaSvikram mdi_client_t *ct; 516525e8c5aaSvikram mdi_pathinfo_t *pip; 516625e8c5aaSvikram mdi_pathinfo_t *next; 516725e8c5aaSvikram dev_info_t *cdip; 516825e8c5aaSvikram int unstable = 0; 516925e8c5aaSvikram int constraint; 517025e8c5aaSvikram 517125e8c5aaSvikram if (!MDI_PHCI(dip)) 517225e8c5aaSvikram return; 517325e8c5aaSvikram 517425e8c5aaSvikram ph = i_devi_get_phci(dip); 517525e8c5aaSvikram if (ph == NULL) { 517625e8c5aaSvikram /* no last path and no pips */ 517725e8c5aaSvikram return; 517825e8c5aaSvikram } 517925e8c5aaSvikram 518025e8c5aaSvikram MDI_PHCI_LOCK(ph); 518125e8c5aaSvikram 518225e8c5aaSvikram if (MDI_PHCI_IS_OFFLINE(ph)) { 518325e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 518425e8c5aaSvikram /* no last path and no pips */ 518525e8c5aaSvikram return; 518625e8c5aaSvikram } 518725e8c5aaSvikram 518825e8c5aaSvikram /* 518925e8c5aaSvikram * Check to see if the pHCI can be offlined 519025e8c5aaSvikram */ 519125e8c5aaSvikram if (ph->ph_unstable) { 519225e8c5aaSvikram unstable = 1; 519325e8c5aaSvikram } 519425e8c5aaSvikram 519525e8c5aaSvikram pip = ph->ph_path_head; 519625e8c5aaSvikram while (pip != NULL) { 519725e8c5aaSvikram MDI_PI_LOCK(pip); 519825e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 519925e8c5aaSvikram 520025e8c5aaSvikram /* 520125e8c5aaSvikram * if failover in progress fail the pHCI from offlining 520225e8c5aaSvikram */ 520325e8c5aaSvikram ct = MDI_PI(pip)->pi_client; 520425e8c5aaSvikram i_mdi_client_lock(ct, pip); 520525e8c5aaSvikram if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 520625e8c5aaSvikram (ct->ct_unstable)) { 520725e8c5aaSvikram unstable = 1; 520825e8c5aaSvikram } 520925e8c5aaSvikram MDI_PI_UNLOCK(pip); 521025e8c5aaSvikram 521125e8c5aaSvikram /* 521225e8c5aaSvikram * Check to see of we are removing the last path of this 521325e8c5aaSvikram * client device... 521425e8c5aaSvikram */ 521525e8c5aaSvikram cdip = ct->ct_dip; 521625e8c5aaSvikram if (!phci_only && cdip && 521725e8c5aaSvikram (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 521825e8c5aaSvikram (i_mdi_client_compute_state(ct, ph) == 521925e8c5aaSvikram MDI_CLIENT_STATE_FAILED)) { 522025e8c5aaSvikram i_mdi_client_unlock(ct); 522125e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 522225e8c5aaSvikram /* 522325e8c5aaSvikram * We don't retire clients we just retire the 522425e8c5aaSvikram * path to a client. If it is the last path 522525e8c5aaSvikram * to a client, constraints are checked and 522625e8c5aaSvikram * if we pass the last path is offlined. MPXIO will 522725e8c5aaSvikram * then fail all I/Os to the client. Since we don't 522825e8c5aaSvikram * want to retire the client on a path error 522925e8c5aaSvikram * set constraint = 0 so that the client dip 523025e8c5aaSvikram * is not retired. 523125e8c5aaSvikram */ 523225e8c5aaSvikram constraint = 0; 523325e8c5aaSvikram (void) e_ddi_retire_finalize(cdip, &constraint); 523425e8c5aaSvikram MDI_PHCI_LOCK(ph); 523525e8c5aaSvikram pip = next; 523625e8c5aaSvikram } else { 523725e8c5aaSvikram i_mdi_client_unlock(ct); 523825e8c5aaSvikram pip = next; 523925e8c5aaSvikram } 524025e8c5aaSvikram } 524125e8c5aaSvikram 524225e8c5aaSvikram /* 524325e8c5aaSvikram * Cannot offline pip(s) 524425e8c5aaSvikram */ 524525e8c5aaSvikram if (unstable) { 524625e8c5aaSvikram cmn_err(CE_WARN, "PHCI in transient state, cannot " 524725e8c5aaSvikram "retire, dip = %p", (void *)dip); 524825e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 524925e8c5aaSvikram return; 525025e8c5aaSvikram } 525125e8c5aaSvikram 525225e8c5aaSvikram /* 525325e8c5aaSvikram * Mark the pHCI as offline 525425e8c5aaSvikram */ 525525e8c5aaSvikram MDI_PHCI_SET_OFFLINE(ph); 525625e8c5aaSvikram 525725e8c5aaSvikram /* 525825e8c5aaSvikram * Mark the child mdi_pathinfo nodes as transient 525925e8c5aaSvikram */ 526025e8c5aaSvikram pip = ph->ph_path_head; 526125e8c5aaSvikram while (pip != NULL) { 526225e8c5aaSvikram MDI_PI_LOCK(pip); 526325e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 526425e8c5aaSvikram MDI_PI_SET_OFFLINING(pip); 526525e8c5aaSvikram MDI_PI_UNLOCK(pip); 526625e8c5aaSvikram pip = next; 526725e8c5aaSvikram } 526825e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 526925e8c5aaSvikram /* 527025e8c5aaSvikram * Give a chance for any pending commands to execute 527125e8c5aaSvikram */ 527225e8c5aaSvikram delay(1); 527325e8c5aaSvikram MDI_PHCI_LOCK(ph); 527425e8c5aaSvikram pip = ph->ph_path_head; 527525e8c5aaSvikram while (pip != NULL) { 527625e8c5aaSvikram next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 527725e8c5aaSvikram (void) i_mdi_pi_offline(pip, 0); 527825e8c5aaSvikram MDI_PI_LOCK(pip); 527925e8c5aaSvikram ct = MDI_PI(pip)->pi_client; 528025e8c5aaSvikram if (!MDI_PI_IS_OFFLINE(pip)) { 528125e8c5aaSvikram cmn_err(CE_WARN, "PHCI busy, cannot offline path: " 528225e8c5aaSvikram "PHCI dip = %p", (void *)dip); 528325e8c5aaSvikram MDI_PI_UNLOCK(pip); 528425e8c5aaSvikram MDI_PHCI_SET_ONLINE(ph); 528525e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 528625e8c5aaSvikram return; 528725e8c5aaSvikram } 528825e8c5aaSvikram MDI_PI_UNLOCK(pip); 528925e8c5aaSvikram pip = next; 529025e8c5aaSvikram } 529125e8c5aaSvikram MDI_PHCI_UNLOCK(ph); 529225e8c5aaSvikram 529325e8c5aaSvikram return; 529425e8c5aaSvikram } 529525e8c5aaSvikram 529625e8c5aaSvikram void 529725e8c5aaSvikram mdi_phci_unretire(dev_info_t *dip) 529825e8c5aaSvikram { 529925e8c5aaSvikram ASSERT(MDI_PHCI(dip)); 530025e8c5aaSvikram 530125e8c5aaSvikram /* 530225e8c5aaSvikram * Online the phci 530325e8c5aaSvikram */ 530425e8c5aaSvikram i_mdi_phci_online(dip); 530525e8c5aaSvikram } 530625e8c5aaSvikram 53077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 53087c478bd9Sstevel@tonic-gate static int 53097c478bd9Sstevel@tonic-gate i_mdi_client_offline(dev_info_t *dip, uint_t flags) 53107c478bd9Sstevel@tonic-gate { 53117c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 53127c478bd9Sstevel@tonic-gate mdi_client_t *ct; 53137c478bd9Sstevel@tonic-gate 53147c478bd9Sstevel@tonic-gate /* 53157c478bd9Sstevel@tonic-gate * Client component to go offline. Make sure that we are 53167c478bd9Sstevel@tonic-gate * not in failing over state and update client state 53177c478bd9Sstevel@tonic-gate * accordingly 53187c478bd9Sstevel@tonic-gate */ 53197c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 53205e3986cbScth MDI_DEBUG(2, (CE_NOTE, dip, "!i_mdi_client_offline called %p %p\n", 53215e3986cbScth (void *)dip, (void *)ct)); 53227c478bd9Sstevel@tonic-gate if (ct != NULL) { 53237c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 53247c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 53257c478bd9Sstevel@tonic-gate /* 53267c478bd9Sstevel@tonic-gate * One or more paths are in transient state, 53277c478bd9Sstevel@tonic-gate * Dont allow offline of a client device 53287c478bd9Sstevel@tonic-gate */ 53297c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 53307c478bd9Sstevel@tonic-gate "!One or more paths to this device is " 53317c478bd9Sstevel@tonic-gate "in transient state. This device can not " 53327c478bd9Sstevel@tonic-gate "be removed at this moment. " 53337c478bd9Sstevel@tonic-gate "Please try again later.")); 53347c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 53357c478bd9Sstevel@tonic-gate return (NDI_BUSY); 53367c478bd9Sstevel@tonic-gate } 53377c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 53387c478bd9Sstevel@tonic-gate /* 53397c478bd9Sstevel@tonic-gate * Failover is in progress, Dont allow DR of 53407c478bd9Sstevel@tonic-gate * a client device 53417c478bd9Sstevel@tonic-gate */ 53427c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 53437c478bd9Sstevel@tonic-gate "!Client device (%s%d) is Busy. %s", 53447c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 53457c478bd9Sstevel@tonic-gate "This device can not be removed at " 53467c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 53477c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 53487c478bd9Sstevel@tonic-gate return (NDI_BUSY); 53497c478bd9Sstevel@tonic-gate } 53507c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 53517c478bd9Sstevel@tonic-gate 53527c478bd9Sstevel@tonic-gate /* 53537c478bd9Sstevel@tonic-gate * Unbind our relationship with the dev_info node 53547c478bd9Sstevel@tonic-gate */ 53557c478bd9Sstevel@tonic-gate if (flags & NDI_DEVI_REMOVE) { 53567c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 53577c478bd9Sstevel@tonic-gate } 53587c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 53597c478bd9Sstevel@tonic-gate } 53607c478bd9Sstevel@tonic-gate return (rv); 53617c478bd9Sstevel@tonic-gate } 53627c478bd9Sstevel@tonic-gate 53637c478bd9Sstevel@tonic-gate /* 53647c478bd9Sstevel@tonic-gate * mdi_pre_attach(): 53657c478bd9Sstevel@tonic-gate * Pre attach() notification handler 53667c478bd9Sstevel@tonic-gate */ 53677c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 53687c478bd9Sstevel@tonic-gate int 53697c478bd9Sstevel@tonic-gate mdi_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 53707c478bd9Sstevel@tonic-gate { 53717c478bd9Sstevel@tonic-gate /* don't support old DDI_PM_RESUME */ 53727c478bd9Sstevel@tonic-gate if ((DEVI(dip)->devi_mdi_component != MDI_COMPONENT_NONE) && 53737c478bd9Sstevel@tonic-gate (cmd == DDI_PM_RESUME)) 53747c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 53757c478bd9Sstevel@tonic-gate 53767c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 53777c478bd9Sstevel@tonic-gate } 53787c478bd9Sstevel@tonic-gate 53797c478bd9Sstevel@tonic-gate /* 53807c478bd9Sstevel@tonic-gate * mdi_post_attach(): 53817c478bd9Sstevel@tonic-gate * Post attach() notification handler 53827c478bd9Sstevel@tonic-gate */ 53837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 53847c478bd9Sstevel@tonic-gate void 53857c478bd9Sstevel@tonic-gate mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error) 53867c478bd9Sstevel@tonic-gate { 53877c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 53887c478bd9Sstevel@tonic-gate mdi_client_t *ct; 538937fbbce5Scth mdi_vhci_t *vh; 53907c478bd9Sstevel@tonic-gate 53917c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 53927c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 53937c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 53947c478bd9Sstevel@tonic-gate 53957c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 53967c478bd9Sstevel@tonic-gate switch (cmd) { 53977c478bd9Sstevel@tonic-gate case DDI_ATTACH: 53987c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 53995e3986cbScth "!pHCI post_attach: called %p\n", (void *)ph)); 54007c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 54017c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 54027c478bd9Sstevel@tonic-gate } else { 54037c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 54047c478bd9Sstevel@tonic-gate "!pHCI post_attach: failed error=%d\n", 54057c478bd9Sstevel@tonic-gate error)); 54067c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 54077c478bd9Sstevel@tonic-gate } 54087c478bd9Sstevel@tonic-gate break; 54097c478bd9Sstevel@tonic-gate 54107c478bd9Sstevel@tonic-gate case DDI_RESUME: 54117c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 54125e3986cbScth "!pHCI post_resume: called %p\n", (void *)ph)); 54137c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 54147c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 54157c478bd9Sstevel@tonic-gate } else { 54167c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 54177c478bd9Sstevel@tonic-gate "!pHCI post_resume: failed error=%d\n", 54187c478bd9Sstevel@tonic-gate error)); 54197c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 54207c478bd9Sstevel@tonic-gate } 54217c478bd9Sstevel@tonic-gate break; 54227c478bd9Sstevel@tonic-gate } 54237c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 54247c478bd9Sstevel@tonic-gate } 54257c478bd9Sstevel@tonic-gate 54267c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 54277c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 54287c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 54297c478bd9Sstevel@tonic-gate 54307c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 54317c478bd9Sstevel@tonic-gate switch (cmd) { 54327c478bd9Sstevel@tonic-gate case DDI_ATTACH: 54337c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 54345e3986cbScth "!Client post_attach: called %p\n", (void *)ct)); 54357c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) { 54367c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 54377c478bd9Sstevel@tonic-gate "!Client post_attach: failed error=%d\n", 54387c478bd9Sstevel@tonic-gate error)); 54397c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 54407c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, dip, 54417c478bd9Sstevel@tonic-gate "mdi_post_attach i_mdi_pm_reset_client\n")); 54427c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 54437c478bd9Sstevel@tonic-gate break; 54447c478bd9Sstevel@tonic-gate } 54457c478bd9Sstevel@tonic-gate 54467c478bd9Sstevel@tonic-gate /* 544737fbbce5Scth * Client device has successfully attached, inform 544837fbbce5Scth * the vhci. 54497c478bd9Sstevel@tonic-gate */ 545037fbbce5Scth vh = ct->ct_vhci; 545137fbbce5Scth if (vh->vh_ops->vo_client_attached) 545237fbbce5Scth (*vh->vh_ops->vo_client_attached)(dip); 545337fbbce5Scth 54547c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 54557c478bd9Sstevel@tonic-gate break; 54567c478bd9Sstevel@tonic-gate 54577c478bd9Sstevel@tonic-gate case DDI_RESUME: 54587c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 54595e3986cbScth "!Client post_attach: called %p\n", (void *)ct)); 54607c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 54617c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 54627c478bd9Sstevel@tonic-gate } else { 54637c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 54647c478bd9Sstevel@tonic-gate "!Client post_resume: failed error=%d\n", 54657c478bd9Sstevel@tonic-gate error)); 54667c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 54677c478bd9Sstevel@tonic-gate } 54687c478bd9Sstevel@tonic-gate break; 54697c478bd9Sstevel@tonic-gate } 54707c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 54717c478bd9Sstevel@tonic-gate } 54727c478bd9Sstevel@tonic-gate } 54737c478bd9Sstevel@tonic-gate 54747c478bd9Sstevel@tonic-gate /* 54757c478bd9Sstevel@tonic-gate * mdi_pre_detach(): 54767c478bd9Sstevel@tonic-gate * Pre detach notification handler 54777c478bd9Sstevel@tonic-gate */ 54787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 54797c478bd9Sstevel@tonic-gate int 54807c478bd9Sstevel@tonic-gate mdi_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 54817c478bd9Sstevel@tonic-gate { 54827c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 54837c478bd9Sstevel@tonic-gate 54847c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 54857c478bd9Sstevel@tonic-gate (void) i_mdi_client_pre_detach(dip, cmd); 54867c478bd9Sstevel@tonic-gate } 54877c478bd9Sstevel@tonic-gate 54887c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 54897c478bd9Sstevel@tonic-gate rv = i_mdi_phci_pre_detach(dip, cmd); 54907c478bd9Sstevel@tonic-gate } 54917c478bd9Sstevel@tonic-gate 54927c478bd9Sstevel@tonic-gate return (rv); 54937c478bd9Sstevel@tonic-gate } 54947c478bd9Sstevel@tonic-gate 54957c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 54967c478bd9Sstevel@tonic-gate static int 54977c478bd9Sstevel@tonic-gate i_mdi_phci_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 54987c478bd9Sstevel@tonic-gate { 54997c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 55007c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 55017c478bd9Sstevel@tonic-gate mdi_client_t *ct; 55027c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 55037c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 55047c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 55057c478bd9Sstevel@tonic-gate 55067c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 55077c478bd9Sstevel@tonic-gate if (ph == NULL) { 55087c478bd9Sstevel@tonic-gate return (rv); 55097c478bd9Sstevel@tonic-gate } 55107c478bd9Sstevel@tonic-gate 55117c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 55127c478bd9Sstevel@tonic-gate switch (cmd) { 55137c478bd9Sstevel@tonic-gate case DDI_DETACH: 55147c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 55155e3986cbScth "!pHCI pre_detach: called %p\n", (void *)ph)); 55167c478bd9Sstevel@tonic-gate if (!MDI_PHCI_IS_OFFLINE(ph)) { 55177c478bd9Sstevel@tonic-gate /* 55187c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes are still attached to 55197c478bd9Sstevel@tonic-gate * this pHCI. Fail the detach for this pHCI. 55207c478bd9Sstevel@tonic-gate */ 55217c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, dip, 55227c478bd9Sstevel@tonic-gate "!pHCI pre_detach: " 55237c478bd9Sstevel@tonic-gate "mdi_pathinfo nodes are still attached " 55245e3986cbScth "%p\n", (void *)ph)); 55257c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 55267c478bd9Sstevel@tonic-gate break; 55277c478bd9Sstevel@tonic-gate } 55287c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 55297c478bd9Sstevel@tonic-gate break; 55307c478bd9Sstevel@tonic-gate 55317c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 55327c478bd9Sstevel@tonic-gate /* 55337c478bd9Sstevel@tonic-gate * pHCI is getting suspended. Since mpxio client 55347c478bd9Sstevel@tonic-gate * devices may not be suspended at this point, to avoid 55357c478bd9Sstevel@tonic-gate * a potential stack overflow, it is important to suspend 55367c478bd9Sstevel@tonic-gate * client devices before pHCI can be suspended. 55377c478bd9Sstevel@tonic-gate */ 55387c478bd9Sstevel@tonic-gate 55397c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 55405e3986cbScth "!pHCI pre_suspend: called %p\n", (void *)ph)); 55417c478bd9Sstevel@tonic-gate /* 55427c478bd9Sstevel@tonic-gate * Suspend all the client devices accessible through this pHCI 55437c478bd9Sstevel@tonic-gate */ 55447c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 55457c478bd9Sstevel@tonic-gate while (pip != NULL && rv == DDI_SUCCESS) { 55467c478bd9Sstevel@tonic-gate dev_info_t *cdip; 55477c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 55487c478bd9Sstevel@tonic-gate next = 55497c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 55507c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 55517c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 55527c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 55537c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 55547c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct) == 0) && 55557c478bd9Sstevel@tonic-gate MDI_CLIENT_IS_SUSPENDED(ct) == 0) { 55567c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 55577c478bd9Sstevel@tonic-gate if ((rv = devi_detach(cdip, DDI_SUSPEND)) != 55587c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 55597c478bd9Sstevel@tonic-gate /* 55607c478bd9Sstevel@tonic-gate * Suspend of one of the client 55617c478bd9Sstevel@tonic-gate * device has failed. 55627c478bd9Sstevel@tonic-gate */ 55637c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 55647c478bd9Sstevel@tonic-gate "!Suspend of device (%s%d) failed.", 55657c478bd9Sstevel@tonic-gate ddi_driver_name(cdip), 55667c478bd9Sstevel@tonic-gate ddi_get_instance(cdip))); 55677c478bd9Sstevel@tonic-gate failed_pip = pip; 55687c478bd9Sstevel@tonic-gate break; 55697c478bd9Sstevel@tonic-gate } 55707c478bd9Sstevel@tonic-gate } else { 55717c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 55727c478bd9Sstevel@tonic-gate } 55737c478bd9Sstevel@tonic-gate pip = next; 55747c478bd9Sstevel@tonic-gate } 55757c478bd9Sstevel@tonic-gate 55767c478bd9Sstevel@tonic-gate if (rv == DDI_SUCCESS) { 55777c478bd9Sstevel@tonic-gate /* 55787c478bd9Sstevel@tonic-gate * Suspend of client devices is complete. Proceed 55797c478bd9Sstevel@tonic-gate * with pHCI suspend. 55807c478bd9Sstevel@tonic-gate */ 55817c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 55827c478bd9Sstevel@tonic-gate } else { 55837c478bd9Sstevel@tonic-gate /* 55847c478bd9Sstevel@tonic-gate * Revert back all the suspended client device states 55857c478bd9Sstevel@tonic-gate * to converse. 55867c478bd9Sstevel@tonic-gate */ 55877c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 55887c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 55897c478bd9Sstevel@tonic-gate dev_info_t *cdip; 55907c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 55917c478bd9Sstevel@tonic-gate next = 55927c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 55937c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 55947c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 55957c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 55967c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 55977c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_SUSPENDED(ct)) { 55987c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 55997c478bd9Sstevel@tonic-gate (void) devi_attach(cdip, DDI_RESUME); 56007c478bd9Sstevel@tonic-gate } else { 56017c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 56027c478bd9Sstevel@tonic-gate } 56037c478bd9Sstevel@tonic-gate pip = next; 56047c478bd9Sstevel@tonic-gate } 56057c478bd9Sstevel@tonic-gate } 56067c478bd9Sstevel@tonic-gate break; 56077c478bd9Sstevel@tonic-gate 56087c478bd9Sstevel@tonic-gate default: 56097c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 56107c478bd9Sstevel@tonic-gate break; 56117c478bd9Sstevel@tonic-gate } 56127c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 56137c478bd9Sstevel@tonic-gate return (rv); 56147c478bd9Sstevel@tonic-gate } 56157c478bd9Sstevel@tonic-gate 56167c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 56177c478bd9Sstevel@tonic-gate static int 56187c478bd9Sstevel@tonic-gate i_mdi_client_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 56197c478bd9Sstevel@tonic-gate { 56207c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 56217c478bd9Sstevel@tonic-gate mdi_client_t *ct; 56227c478bd9Sstevel@tonic-gate 56237c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 56247c478bd9Sstevel@tonic-gate if (ct == NULL) { 56257c478bd9Sstevel@tonic-gate return (rv); 56267c478bd9Sstevel@tonic-gate } 56277c478bd9Sstevel@tonic-gate 56287c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 56297c478bd9Sstevel@tonic-gate switch (cmd) { 56307c478bd9Sstevel@tonic-gate case DDI_DETACH: 56317c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 56325e3986cbScth "!Client pre_detach: called %p\n", (void *)ct)); 56337c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 56347c478bd9Sstevel@tonic-gate break; 56357c478bd9Sstevel@tonic-gate 56367c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 56377c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 56385e3986cbScth "!Client pre_suspend: called %p\n", (void *)ct)); 56397c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 56407c478bd9Sstevel@tonic-gate break; 56417c478bd9Sstevel@tonic-gate 56427c478bd9Sstevel@tonic-gate default: 56437c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 56447c478bd9Sstevel@tonic-gate break; 56457c478bd9Sstevel@tonic-gate } 56467c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 56477c478bd9Sstevel@tonic-gate return (rv); 56487c478bd9Sstevel@tonic-gate } 56497c478bd9Sstevel@tonic-gate 56507c478bd9Sstevel@tonic-gate /* 56517c478bd9Sstevel@tonic-gate * mdi_post_detach(): 56527c478bd9Sstevel@tonic-gate * Post detach notification handler 56537c478bd9Sstevel@tonic-gate */ 56547c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 56557c478bd9Sstevel@tonic-gate void 56567c478bd9Sstevel@tonic-gate mdi_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 56577c478bd9Sstevel@tonic-gate { 56587c478bd9Sstevel@tonic-gate /* 56597c478bd9Sstevel@tonic-gate * Detach/Suspend of mpxio component failed. Update our state 56607c478bd9Sstevel@tonic-gate * too 56617c478bd9Sstevel@tonic-gate */ 56627c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) 56637c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dip, cmd, error); 56647c478bd9Sstevel@tonic-gate 56657c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) 56667c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dip, cmd, error); 56677c478bd9Sstevel@tonic-gate } 56687c478bd9Sstevel@tonic-gate 56697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 56707c478bd9Sstevel@tonic-gate static void 56717c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 56727c478bd9Sstevel@tonic-gate { 56737c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 56747c478bd9Sstevel@tonic-gate 56757c478bd9Sstevel@tonic-gate /* 56767c478bd9Sstevel@tonic-gate * Detach/Suspend of phci component failed. Update our state 56777c478bd9Sstevel@tonic-gate * too 56787c478bd9Sstevel@tonic-gate */ 56797c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 56807c478bd9Sstevel@tonic-gate if (ph == NULL) { 56817c478bd9Sstevel@tonic-gate return; 56827c478bd9Sstevel@tonic-gate } 56837c478bd9Sstevel@tonic-gate 56847c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 56857c478bd9Sstevel@tonic-gate /* 56867c478bd9Sstevel@tonic-gate * Detach of pHCI failed. Restore back converse 56877c478bd9Sstevel@tonic-gate * state 56887c478bd9Sstevel@tonic-gate */ 56897c478bd9Sstevel@tonic-gate switch (cmd) { 56907c478bd9Sstevel@tonic-gate case DDI_DETACH: 56917c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 56925e3986cbScth "!pHCI post_detach: called %p\n", (void *)ph)); 56937c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 56947c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 56957c478bd9Sstevel@tonic-gate break; 56967c478bd9Sstevel@tonic-gate 56977c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 56987c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 56995e3986cbScth "!pHCI post_suspend: called %p\n", (void *)ph)); 57007c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 57017c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 57027c478bd9Sstevel@tonic-gate break; 57037c478bd9Sstevel@tonic-gate } 57047c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 57057c478bd9Sstevel@tonic-gate } 57067c478bd9Sstevel@tonic-gate 57077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 57087c478bd9Sstevel@tonic-gate static void 57097c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 57107c478bd9Sstevel@tonic-gate { 57117c478bd9Sstevel@tonic-gate mdi_client_t *ct; 57127c478bd9Sstevel@tonic-gate 57137c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 57147c478bd9Sstevel@tonic-gate if (ct == NULL) { 57157c478bd9Sstevel@tonic-gate return; 57167c478bd9Sstevel@tonic-gate } 57177c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 57187c478bd9Sstevel@tonic-gate /* 57197c478bd9Sstevel@tonic-gate * Detach of Client failed. Restore back converse 57207c478bd9Sstevel@tonic-gate * state 57217c478bd9Sstevel@tonic-gate */ 57227c478bd9Sstevel@tonic-gate switch (cmd) { 57237c478bd9Sstevel@tonic-gate case DDI_DETACH: 57247c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 57255e3986cbScth "!Client post_detach: called %p\n", (void *)ct)); 57267c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 57277c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 57287c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 57297c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 57307c478bd9Sstevel@tonic-gate } else { 57317c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 57327c478bd9Sstevel@tonic-gate "i_mdi_pm_reset_client\n")); 57337c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 57347c478bd9Sstevel@tonic-gate } 57357c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 57367c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 57377c478bd9Sstevel@tonic-gate break; 57387c478bd9Sstevel@tonic-gate 57397c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 57407c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 57415e3986cbScth "!Client post_suspend: called %p\n", (void *)ct)); 57427c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 57437c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 57447c478bd9Sstevel@tonic-gate break; 57457c478bd9Sstevel@tonic-gate } 57467c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 57477c478bd9Sstevel@tonic-gate } 57487c478bd9Sstevel@tonic-gate 574937fbbce5Scth int 575037fbbce5Scth mdi_pi_kstat_exists(mdi_pathinfo_t *pip) 575137fbbce5Scth { 575237fbbce5Scth return (MDI_PI(pip)->pi_kstats ? 1 : 0); 575337fbbce5Scth } 575437fbbce5Scth 57557c478bd9Sstevel@tonic-gate /* 57567c478bd9Sstevel@tonic-gate * create and install per-path (client - pHCI) statistics 57577c478bd9Sstevel@tonic-gate * I/O stats supported: nread, nwritten, reads, and writes 57587c478bd9Sstevel@tonic-gate * Error stats - hard errors, soft errors, & transport errors 57597c478bd9Sstevel@tonic-gate */ 576037fbbce5Scth int 576137fbbce5Scth mdi_pi_kstat_create(mdi_pathinfo_t *pip, char *ksname) 57627c478bd9Sstevel@tonic-gate { 57637c478bd9Sstevel@tonic-gate kstat_t *kiosp, *kerrsp; 57647c478bd9Sstevel@tonic-gate struct pi_errs *nsp; 57657c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 57667c478bd9Sstevel@tonic-gate 57677c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_kstats != NULL) 57687c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 57697c478bd9Sstevel@tonic-gate 57707c478bd9Sstevel@tonic-gate if ((kiosp = kstat_create("mdi", 0, ksname, "iopath", 577137fbbce5Scth KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT)) == NULL) { 57727c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 57737c478bd9Sstevel@tonic-gate } 57747c478bd9Sstevel@tonic-gate 577537fbbce5Scth (void) strcat(ksname, ",err"); 57767c478bd9Sstevel@tonic-gate kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors", 57777c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, 57787c478bd9Sstevel@tonic-gate sizeof (struct pi_errs) / sizeof (kstat_named_t), 0); 57797c478bd9Sstevel@tonic-gate if (kerrsp == NULL) { 57807c478bd9Sstevel@tonic-gate kstat_delete(kiosp); 57817c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 57827c478bd9Sstevel@tonic-gate } 57837c478bd9Sstevel@tonic-gate 57847c478bd9Sstevel@tonic-gate nsp = (struct pi_errs *)kerrsp->ks_data; 57857c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32); 57867c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32); 57877c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_transerrs, "Transport Errors", 57887c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 57897c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy", 57907c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 57917c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors", 57927c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 57937c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources", 57947c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 57957c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors", 57967c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 57977c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State", 57987c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 57997c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedfrom, "Failed From", 58007c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 58017c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32); 58027c478bd9Sstevel@tonic-gate 58037c478bd9Sstevel@tonic-gate mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP); 58047c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_ref = 1; 58057c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_iostats = kiosp; 58067c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_errstats = kerrsp; 58077c478bd9Sstevel@tonic-gate kstat_install(kiosp); 58087c478bd9Sstevel@tonic-gate kstat_install(kerrsp); 58097c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = mdi_statp; 58107c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 58117c478bd9Sstevel@tonic-gate } 58127c478bd9Sstevel@tonic-gate 58137c478bd9Sstevel@tonic-gate /* 58147c478bd9Sstevel@tonic-gate * destroy per-path properties 58157c478bd9Sstevel@tonic-gate */ 58167c478bd9Sstevel@tonic-gate static void 58177c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip) 58187c478bd9Sstevel@tonic-gate { 58197c478bd9Sstevel@tonic-gate 58207c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 58217c478bd9Sstevel@tonic-gate 582237fbbce5Scth if (MDI_PI(pip)->pi_kstats == NULL) 582337fbbce5Scth return; 58247c478bd9Sstevel@tonic-gate if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL) 58257c478bd9Sstevel@tonic-gate return; 58267c478bd9Sstevel@tonic-gate 58277c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 58287c478bd9Sstevel@tonic-gate 58297c478bd9Sstevel@tonic-gate /* 58307c478bd9Sstevel@tonic-gate * the kstat may be shared between multiple pathinfo nodes 58317c478bd9Sstevel@tonic-gate * decrement this pathinfo's usage, removing the kstats 58327c478bd9Sstevel@tonic-gate * themselves when the last pathinfo reference is removed. 58337c478bd9Sstevel@tonic-gate */ 58347c478bd9Sstevel@tonic-gate ASSERT(mdi_statp->pi_kstat_ref > 0); 58357c478bd9Sstevel@tonic-gate if (--mdi_statp->pi_kstat_ref != 0) 58367c478bd9Sstevel@tonic-gate return; 58377c478bd9Sstevel@tonic-gate 58387c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_iostats); 58397c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_errstats); 58407c478bd9Sstevel@tonic-gate kmem_free(mdi_statp, sizeof (*mdi_statp)); 58417c478bd9Sstevel@tonic-gate } 58427c478bd9Sstevel@tonic-gate 58437c478bd9Sstevel@tonic-gate /* 58447c478bd9Sstevel@tonic-gate * update I/O paths KSTATS 58457c478bd9Sstevel@tonic-gate */ 58467c478bd9Sstevel@tonic-gate void 58477c478bd9Sstevel@tonic-gate mdi_pi_kstat_iosupdate(mdi_pathinfo_t *pip, struct buf *bp) 58487c478bd9Sstevel@tonic-gate { 58497c478bd9Sstevel@tonic-gate kstat_t *iostatp; 58507c478bd9Sstevel@tonic-gate size_t xfer_cnt; 58517c478bd9Sstevel@tonic-gate 58527c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 58537c478bd9Sstevel@tonic-gate 58547c478bd9Sstevel@tonic-gate /* 58557c478bd9Sstevel@tonic-gate * I/O can be driven across a path prior to having path 58567c478bd9Sstevel@tonic-gate * statistics available, i.e. probe(9e). 58577c478bd9Sstevel@tonic-gate */ 58587c478bd9Sstevel@tonic-gate if (bp != NULL && MDI_PI(pip)->pi_kstats != NULL) { 58597c478bd9Sstevel@tonic-gate iostatp = MDI_PI(pip)->pi_kstats->pi_kstat_iostats; 58607c478bd9Sstevel@tonic-gate xfer_cnt = bp->b_bcount - bp->b_resid; 58617c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 58627c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->reads++; 58637c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nread += xfer_cnt; 58647c478bd9Sstevel@tonic-gate } else { 58657c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->writes++; 58667c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nwritten += xfer_cnt; 58677c478bd9Sstevel@tonic-gate } 58687c478bd9Sstevel@tonic-gate } 58697c478bd9Sstevel@tonic-gate } 58707c478bd9Sstevel@tonic-gate 58717c478bd9Sstevel@tonic-gate /* 5872ee28b439Scm136836 * Enable the path(specific client/target/initiator) 5873ee28b439Scm136836 * Enabling a path means that MPxIO may select the enabled path for routing 5874ee28b439Scm136836 * future I/O requests, subject to other path state constraints. 5875ee28b439Scm136836 */ 5876ee28b439Scm136836 int 5877ee28b439Scm136836 mdi_pi_enable_path(mdi_pathinfo_t *pip, int flags) 5878ee28b439Scm136836 { 5879ee28b439Scm136836 mdi_phci_t *ph; 5880ee28b439Scm136836 5881ee28b439Scm136836 ph = i_devi_get_phci(mdi_pi_get_phci(pip)); 5882ee28b439Scm136836 if (ph == NULL) { 5883ee28b439Scm136836 MDI_DEBUG(1, (CE_NOTE, NULL, "!mdi_pi_enable_path:" 58845e3986cbScth " failed. pip: %p ph = NULL\n", (void *)pip)); 5885ee28b439Scm136836 return (MDI_FAILURE); 5886ee28b439Scm136836 } 5887ee28b439Scm136836 5888ee28b439Scm136836 (void) i_mdi_enable_disable_path(pip, ph->ph_vhci, flags, 5889ee28b439Scm136836 MDI_ENABLE_OP); 5890ee28b439Scm136836 MDI_DEBUG(5, (CE_NOTE, NULL, "!mdi_pi_enable_path:" 58915e3986cbScth " Returning success pip = %p. ph = %p\n", 58925e3986cbScth (void *)pip, (void *)ph)); 5893ee28b439Scm136836 return (MDI_SUCCESS); 5894ee28b439Scm136836 5895ee28b439Scm136836 } 5896ee28b439Scm136836 5897ee28b439Scm136836 /* 5898ee28b439Scm136836 * Disable the path (specific client/target/initiator) 5899ee28b439Scm136836 * Disabling a path means that MPxIO will not select the disabled path for 5900ee28b439Scm136836 * routing any new I/O requests. 5901ee28b439Scm136836 */ 5902ee28b439Scm136836 int 5903ee28b439Scm136836 mdi_pi_disable_path(mdi_pathinfo_t *pip, int flags) 5904ee28b439Scm136836 { 5905ee28b439Scm136836 mdi_phci_t *ph; 5906ee28b439Scm136836 5907ee28b439Scm136836 ph = i_devi_get_phci(mdi_pi_get_phci(pip)); 5908ee28b439Scm136836 if (ph == NULL) { 5909ee28b439Scm136836 MDI_DEBUG(1, (CE_NOTE, NULL, "!mdi_pi_disable_path:" 59105e3986cbScth " failed. pip: %p ph = NULL\n", (void *)pip)); 5911ee28b439Scm136836 return (MDI_FAILURE); 5912ee28b439Scm136836 } 5913ee28b439Scm136836 5914ee28b439Scm136836 (void) i_mdi_enable_disable_path(pip, 5915ee28b439Scm136836 ph->ph_vhci, flags, MDI_DISABLE_OP); 5916ee28b439Scm136836 MDI_DEBUG(5, (CE_NOTE, NULL, "!mdi_pi_disable_path:" 59175e3986cbScth "Returning success pip = %p. ph = %p", 59185e3986cbScth (void *)pip, (void *)ph)); 5919ee28b439Scm136836 return (MDI_SUCCESS); 5920ee28b439Scm136836 } 5921ee28b439Scm136836 5922ee28b439Scm136836 /* 59237c478bd9Sstevel@tonic-gate * disable the path to a particular pHCI (pHCI specified in the phci_path 59247c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 59257c478bd9Sstevel@tonic-gate * Disabling a path means that MPxIO will not select the disabled path for 59267c478bd9Sstevel@tonic-gate * routing any new I/O requests. 5927ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 5928ee28b439Scm136836 * mdi_{enable,disable}_path interfaces 59297c478bd9Sstevel@tonic-gate */ 59307c478bd9Sstevel@tonic-gate int 59317c478bd9Sstevel@tonic-gate mdi_pi_disable(dev_info_t *cdip, dev_info_t *pdip, int flags) 59327c478bd9Sstevel@tonic-gate { 59337c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_DISABLE_OP)); 59347c478bd9Sstevel@tonic-gate } 59357c478bd9Sstevel@tonic-gate 59367c478bd9Sstevel@tonic-gate /* 59377c478bd9Sstevel@tonic-gate * Enable the path to a particular pHCI (pHCI specified in the phci_path 59387c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 59397c478bd9Sstevel@tonic-gate * Enabling a path means that MPxIO may select the enabled path for routing 59407c478bd9Sstevel@tonic-gate * future I/O requests, subject to other path state constraints. 5941ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 5942ee28b439Scm136836 * mdi_{enable,disable}_path interfaces 59437c478bd9Sstevel@tonic-gate */ 59447c478bd9Sstevel@tonic-gate 59457c478bd9Sstevel@tonic-gate int 59467c478bd9Sstevel@tonic-gate mdi_pi_enable(dev_info_t *cdip, dev_info_t *pdip, int flags) 59477c478bd9Sstevel@tonic-gate { 59487c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_ENABLE_OP)); 59497c478bd9Sstevel@tonic-gate } 59507c478bd9Sstevel@tonic-gate 5951ee28b439Scm136836 /* 5952ee28b439Scm136836 * Common routine for doing enable/disable. 5953ee28b439Scm136836 */ 5954ee28b439Scm136836 static mdi_pathinfo_t * 5955ee28b439Scm136836 i_mdi_enable_disable_path(mdi_pathinfo_t *pip, mdi_vhci_t *vh, int flags, 5956ee28b439Scm136836 int op) 5957ee28b439Scm136836 { 5958ee28b439Scm136836 int sync_flag = 0; 5959ee28b439Scm136836 int rv; 5960ee28b439Scm136836 mdi_pathinfo_t *next; 5961ee28b439Scm136836 int (*f)() = NULL; 5962ee28b439Scm136836 5963ee28b439Scm136836 f = vh->vh_ops->vo_pi_state_change; 5964ee28b439Scm136836 5965ee28b439Scm136836 sync_flag = (flags << 8) & 0xf00; 5966ee28b439Scm136836 5967ee28b439Scm136836 /* 5968ee28b439Scm136836 * Do a callback into the mdi consumer to let it 5969ee28b439Scm136836 * know that path is about to get enabled/disabled. 5970ee28b439Scm136836 */ 5971ee28b439Scm136836 if (f != NULL) { 5972ee28b439Scm136836 rv = (*f)(vh->vh_dip, pip, 0, 5973ee28b439Scm136836 MDI_PI_EXT_STATE(pip), 5974ee28b439Scm136836 MDI_EXT_STATE_CHANGE | sync_flag | 5975ee28b439Scm136836 op | MDI_BEFORE_STATE_CHANGE); 5976ee28b439Scm136836 if (rv != MDI_SUCCESS) { 5977ee28b439Scm136836 MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 5978ee28b439Scm136836 "!vo_pi_state_change: failed rv = %x", rv)); 5979ee28b439Scm136836 } 5980ee28b439Scm136836 } 5981ee28b439Scm136836 MDI_PI_LOCK(pip); 5982ee28b439Scm136836 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 5983ee28b439Scm136836 5984ee28b439Scm136836 switch (flags) { 5985ee28b439Scm136836 case USER_DISABLE: 59865e3986cbScth if (op == MDI_DISABLE_OP) { 5987ee28b439Scm136836 MDI_PI_SET_USER_DISABLE(pip); 59885e3986cbScth } else { 5989ee28b439Scm136836 MDI_PI_SET_USER_ENABLE(pip); 59905e3986cbScth } 5991ee28b439Scm136836 break; 5992ee28b439Scm136836 case DRIVER_DISABLE: 59935e3986cbScth if (op == MDI_DISABLE_OP) { 5994ee28b439Scm136836 MDI_PI_SET_DRV_DISABLE(pip); 59955e3986cbScth } else { 5996ee28b439Scm136836 MDI_PI_SET_DRV_ENABLE(pip); 59975e3986cbScth } 5998ee28b439Scm136836 break; 5999ee28b439Scm136836 case DRIVER_DISABLE_TRANSIENT: 60005e3986cbScth if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) { 6001ee28b439Scm136836 MDI_PI_SET_DRV_DISABLE_TRANS(pip); 60025e3986cbScth } else { 6003ee28b439Scm136836 MDI_PI_SET_DRV_ENABLE_TRANS(pip); 60045e3986cbScth } 6005ee28b439Scm136836 break; 6006ee28b439Scm136836 } 6007ee28b439Scm136836 MDI_PI_UNLOCK(pip); 6008ee28b439Scm136836 /* 6009ee28b439Scm136836 * Do a callback into the mdi consumer to let it 6010ee28b439Scm136836 * know that path is now enabled/disabled. 6011ee28b439Scm136836 */ 6012ee28b439Scm136836 if (f != NULL) { 6013ee28b439Scm136836 rv = (*f)(vh->vh_dip, pip, 0, 6014ee28b439Scm136836 MDI_PI_EXT_STATE(pip), 6015ee28b439Scm136836 MDI_EXT_STATE_CHANGE | sync_flag | 6016ee28b439Scm136836 op | MDI_AFTER_STATE_CHANGE); 6017ee28b439Scm136836 if (rv != MDI_SUCCESS) { 6018ee28b439Scm136836 MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 6019ee28b439Scm136836 "!vo_pi_state_change: failed rv = %x", rv)); 6020ee28b439Scm136836 } 6021ee28b439Scm136836 } 6022ee28b439Scm136836 return (next); 6023ee28b439Scm136836 } 60247c478bd9Sstevel@tonic-gate 60257c478bd9Sstevel@tonic-gate /* 60267c478bd9Sstevel@tonic-gate * Common routine for doing enable/disable. 6027ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 6028ee28b439Scm136836 * mdi_{enable,disable}_path has been putback 60297c478bd9Sstevel@tonic-gate */ 60307c478bd9Sstevel@tonic-gate int 60317c478bd9Sstevel@tonic-gate i_mdi_pi_enable_disable(dev_info_t *cdip, dev_info_t *pdip, int flags, int op) 60327c478bd9Sstevel@tonic-gate { 60337c478bd9Sstevel@tonic-gate 60347c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 60357c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 60367c478bd9Sstevel@tonic-gate mdi_client_t *ct; 60377c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next, *pip; 60387c478bd9Sstevel@tonic-gate int found_it; 60397c478bd9Sstevel@tonic-gate 60407c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 60417c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable: " 60425e3986cbScth "Op = %d pdip = %p cdip = %p\n", op, (void *)pdip, 60435e3986cbScth (void *)cdip)); 60447c478bd9Sstevel@tonic-gate if (ph == NULL) { 60457c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 60465e3986cbScth "Op %d failed. ph = NULL\n", op)); 60477c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 60487c478bd9Sstevel@tonic-gate } 60497c478bd9Sstevel@tonic-gate 60507c478bd9Sstevel@tonic-gate if ((op != MDI_ENABLE_OP) && (op != MDI_DISABLE_OP)) { 60517c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable: " 60525e3986cbScth "Op Invalid operation = %d\n", op)); 60537c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 60547c478bd9Sstevel@tonic-gate } 60557c478bd9Sstevel@tonic-gate 60567c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 60577c478bd9Sstevel@tonic-gate 60587c478bd9Sstevel@tonic-gate if (cdip == NULL) { 60597c478bd9Sstevel@tonic-gate /* 60607c478bd9Sstevel@tonic-gate * Need to mark the Phci as enabled/disabled. 60617c478bd9Sstevel@tonic-gate */ 60627c478bd9Sstevel@tonic-gate MDI_DEBUG(3, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable: " 60635e3986cbScth "Op %d for the phci\n", op)); 60647c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 60657c478bd9Sstevel@tonic-gate switch (flags) { 60667c478bd9Sstevel@tonic-gate case USER_DISABLE: 60675e3986cbScth if (op == MDI_DISABLE_OP) { 60687c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_DISABLE(ph); 60695e3986cbScth } else { 60707c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_ENABLE(ph); 60715e3986cbScth } 60727c478bd9Sstevel@tonic-gate break; 60737c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 60745e3986cbScth if (op == MDI_DISABLE_OP) { 60757c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE(ph); 60765e3986cbScth } else { 60777c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE(ph); 60785e3986cbScth } 60797c478bd9Sstevel@tonic-gate break; 60807c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 60815e3986cbScth if (op == MDI_DISABLE_OP) { 60827c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE_TRANSIENT(ph); 60835e3986cbScth } else { 60847c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE_TRANSIENT(ph); 60855e3986cbScth } 60867c478bd9Sstevel@tonic-gate break; 60877c478bd9Sstevel@tonic-gate default: 60887c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 60897c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 60907c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 60917c478bd9Sstevel@tonic-gate " Invalid flag argument= %d\n", flags)); 60927c478bd9Sstevel@tonic-gate } 60937c478bd9Sstevel@tonic-gate 60947c478bd9Sstevel@tonic-gate /* 60957c478bd9Sstevel@tonic-gate * Phci has been disabled. Now try to enable/disable 60967c478bd9Sstevel@tonic-gate * path info's to each client. 60977c478bd9Sstevel@tonic-gate */ 60987c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 60997c478bd9Sstevel@tonic-gate while (pip != NULL) { 6100ee28b439Scm136836 pip = i_mdi_enable_disable_path(pip, vh, flags, op); 61017c478bd9Sstevel@tonic-gate } 61027c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 61037c478bd9Sstevel@tonic-gate } else { 61047c478bd9Sstevel@tonic-gate 61057c478bd9Sstevel@tonic-gate /* 61067c478bd9Sstevel@tonic-gate * Disable a specific client. 61077c478bd9Sstevel@tonic-gate */ 61087c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 61097c478bd9Sstevel@tonic-gate if (ct == NULL) { 61107c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 61117c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 61127c478bd9Sstevel@tonic-gate " failed. ct = NULL operation = %d\n", op)); 61137c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 61147c478bd9Sstevel@tonic-gate } 61157c478bd9Sstevel@tonic-gate 61167c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 61177c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 61187c478bd9Sstevel@tonic-gate found_it = 0; 61197c478bd9Sstevel@tonic-gate while (pip != NULL) { 61207c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 61217c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 61227c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 61237c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 61247c478bd9Sstevel@tonic-gate found_it = 1; 61257c478bd9Sstevel@tonic-gate break; 61267c478bd9Sstevel@tonic-gate } 61277c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 61287c478bd9Sstevel@tonic-gate pip = next; 61297c478bd9Sstevel@tonic-gate } 61307c478bd9Sstevel@tonic-gate 6131ee28b439Scm136836 61327c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 61337c478bd9Sstevel@tonic-gate if (found_it == 0) { 61347c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 61357c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 61367c478bd9Sstevel@tonic-gate " failed. Could not find corresponding pip\n")); 61377c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 61387c478bd9Sstevel@tonic-gate } 6139ee28b439Scm136836 6140ee28b439Scm136836 (void) i_mdi_enable_disable_path(pip, vh, flags, op); 61417c478bd9Sstevel@tonic-gate } 61427c478bd9Sstevel@tonic-gate 61437c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable: " 61445e3986cbScth "Op %d Returning success pdip = %p cdip = %p\n", 61455e3986cbScth op, (void *)pdip, (void *)cdip)); 61467c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 61477c478bd9Sstevel@tonic-gate } 61487c478bd9Sstevel@tonic-gate 61497c478bd9Sstevel@tonic-gate /* 61507c478bd9Sstevel@tonic-gate * Ensure phci powered up 61517c478bd9Sstevel@tonic-gate */ 61527c478bd9Sstevel@tonic-gate static void 61537c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(mdi_pathinfo_t *pip) 61547c478bd9Sstevel@tonic-gate { 61557c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 61567c478bd9Sstevel@tonic-gate 61577c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 61585e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 61597c478bd9Sstevel@tonic-gate 61607c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 61617c478bd9Sstevel@tonic-gate return; 61627c478bd9Sstevel@tonic-gate } 61637c478bd9Sstevel@tonic-gate 61647c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 61655e3986cbScth MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_hold_pip for %s%d %p\n", 61665e3986cbScth ddi_get_name(ph_dip), ddi_get_instance(ph_dip), (void *)pip)); 61677c478bd9Sstevel@tonic-gate if (ph_dip == NULL) { 61687c478bd9Sstevel@tonic-gate return; 61697c478bd9Sstevel@tonic-gate } 61707c478bd9Sstevel@tonic-gate 61717c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 61727c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 61737c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 61745e3986cbScth 61757c478bd9Sstevel@tonic-gate pm_hold_power(ph_dip); 61765e3986cbScth 61777c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 61787c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 61797c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 61807c478bd9Sstevel@tonic-gate 61815e3986cbScth /* If PM_GET_PM_INFO is NULL the pm_hold_power above was a noop */ 61825e3986cbScth if (DEVI(ph_dip)->devi_pm_info) 61837c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 1; 61847c478bd9Sstevel@tonic-gate } 61857c478bd9Sstevel@tonic-gate 61867c478bd9Sstevel@tonic-gate /* 61877c478bd9Sstevel@tonic-gate * Allow phci powered down 61887c478bd9Sstevel@tonic-gate */ 61897c478bd9Sstevel@tonic-gate static void 61907c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(mdi_pathinfo_t *pip) 61917c478bd9Sstevel@tonic-gate { 61927c478bd9Sstevel@tonic-gate dev_info_t *ph_dip = NULL; 61937c478bd9Sstevel@tonic-gate 61947c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 61955e3986cbScth ASSERT(MDI_PI_LOCKED(pip)); 61967c478bd9Sstevel@tonic-gate 61977c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 61987c478bd9Sstevel@tonic-gate return; 61997c478bd9Sstevel@tonic-gate } 62007c478bd9Sstevel@tonic-gate 62017c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 62027c478bd9Sstevel@tonic-gate ASSERT(ph_dip != NULL); 62037c478bd9Sstevel@tonic-gate 62047c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 62055e3986cbScth MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_rele_pip for %s%d %p\n", 62065e3986cbScth ddi_get_name(ph_dip), ddi_get_instance(ph_dip), (void *)pip)); 62077c478bd9Sstevel@tonic-gate 62087c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 62097c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 62107c478bd9Sstevel@tonic-gate pm_rele_power(ph_dip); 62117c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 62127c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 62137c478bd9Sstevel@tonic-gate 62147c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 62157c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 0; 62167c478bd9Sstevel@tonic-gate } 62177c478bd9Sstevel@tonic-gate 62187c478bd9Sstevel@tonic-gate static void 62197c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(mdi_client_t *ct, int incr) 62207c478bd9Sstevel@tonic-gate { 62215e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 62227c478bd9Sstevel@tonic-gate 62237c478bd9Sstevel@tonic-gate ct->ct_power_cnt += incr; 62245e3986cbScth MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_hold_client %p " 62255e3986cbScth "ct_power_cnt = %d incr = %d\n", (void *)ct, 62265e3986cbScth ct->ct_power_cnt, incr)); 62277c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 62287c478bd9Sstevel@tonic-gate } 62297c478bd9Sstevel@tonic-gate 62307c478bd9Sstevel@tonic-gate static void 62317c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(mdi_client_t *ct) 62327c478bd9Sstevel@tonic-gate { 62337c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 62347c478bd9Sstevel@tonic-gate 62355e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 62367c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 62377c478bd9Sstevel@tonic-gate while (pip != NULL) { 62387c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 62397c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 62407c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 62417c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 62427c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 62437c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 62447c478bd9Sstevel@tonic-gate } 62457c478bd9Sstevel@tonic-gate } 62467c478bd9Sstevel@tonic-gate 62477c478bd9Sstevel@tonic-gate static void 62487c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(mdi_client_t *ct, int decr) 62497c478bd9Sstevel@tonic-gate { 62505e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 62517c478bd9Sstevel@tonic-gate 6252737d277aScth if (i_ddi_devi_attached(ct->ct_dip)) { 62537c478bd9Sstevel@tonic-gate ct->ct_power_cnt -= decr; 62545e3986cbScth MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_rele_client %p " 62555e3986cbScth "ct_power_cnt = %d decr = %d\n", 62565e3986cbScth (void *)ct, ct->ct_power_cnt, decr)); 62577c478bd9Sstevel@tonic-gate } 62587c478bd9Sstevel@tonic-gate 62597c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 62607c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 62617c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 62627c478bd9Sstevel@tonic-gate return; 62637c478bd9Sstevel@tonic-gate } 62647c478bd9Sstevel@tonic-gate } 62657c478bd9Sstevel@tonic-gate 62667c478bd9Sstevel@tonic-gate static void 62677c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(mdi_client_t *ct) 62687c478bd9Sstevel@tonic-gate { 62695e3986cbScth MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_reset_client %p " 62705e3986cbScth "ct_power_cnt = %d\n", (void *)ct, ct->ct_power_cnt)); 62715e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 62727c478bd9Sstevel@tonic-gate ct->ct_power_cnt = 0; 62737c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 627478dc6db2Sllai1 ct->ct_powercnt_config = 0; 627578dc6db2Sllai1 ct->ct_powercnt_unconfig = 0; 62767c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 1; 62777c478bd9Sstevel@tonic-gate } 62787c478bd9Sstevel@tonic-gate 62797c478bd9Sstevel@tonic-gate static int 62807c478bd9Sstevel@tonic-gate i_mdi_power_one_phci(mdi_pathinfo_t *pip) 62817c478bd9Sstevel@tonic-gate { 62827c478bd9Sstevel@tonic-gate int ret; 62837c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 62847c478bd9Sstevel@tonic-gate 62857c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 62867c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 62877c478bd9Sstevel@tonic-gate 62887c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 62897c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 62907c478bd9Sstevel@tonic-gate 62917c478bd9Sstevel@tonic-gate /* bring all components of phci to full power */ 62927c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 62935e3986cbScth "pm_powerup for %s%d %p\n", ddi_get_name(ph_dip), 62945e3986cbScth ddi_get_instance(ph_dip), (void *)pip)); 62957c478bd9Sstevel@tonic-gate 62967c478bd9Sstevel@tonic-gate ret = pm_powerup(ph_dip); 62977c478bd9Sstevel@tonic-gate 62987c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 62997c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 63005e3986cbScth "pm_powerup FAILED for %s%d %p\n", 63015e3986cbScth ddi_get_name(ph_dip), ddi_get_instance(ph_dip), 63025e3986cbScth (void *)pip)); 63037c478bd9Sstevel@tonic-gate 63047c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 63057c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 63067c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 63077c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 63087c478bd9Sstevel@tonic-gate } 63097c478bd9Sstevel@tonic-gate 63107c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 63117c478bd9Sstevel@tonic-gate } 63127c478bd9Sstevel@tonic-gate 63137c478bd9Sstevel@tonic-gate static int 63147c478bd9Sstevel@tonic-gate i_mdi_power_all_phci(mdi_client_t *ct) 63157c478bd9Sstevel@tonic-gate { 63167c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 63177c478bd9Sstevel@tonic-gate int succeeded = 0; 63187c478bd9Sstevel@tonic-gate 63195e3986cbScth ASSERT(MDI_CLIENT_LOCKED(ct)); 63207c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 63217c478bd9Sstevel@tonic-gate while (pip != NULL) { 63225e3986cbScth /* 63235e3986cbScth * Don't power if MDI_PATHINFO_STATE_FAULT 63245e3986cbScth * or MDI_PATHINFO_STATE_OFFLINE. 63255e3986cbScth */ 63265e3986cbScth if (MDI_PI_IS_INIT(pip) || 63275e3986cbScth MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip)) { 63287c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 63297c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 63307c478bd9Sstevel@tonic-gate if (i_mdi_power_one_phci(pip) == MDI_SUCCESS) 63317c478bd9Sstevel@tonic-gate succeeded = 1; 63327c478bd9Sstevel@tonic-gate 63337c478bd9Sstevel@tonic-gate ASSERT(ct == MDI_PI(pip)->pi_client); 63347c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 63357c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 63365e3986cbScth } 63377c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 63387c478bd9Sstevel@tonic-gate } 63397c478bd9Sstevel@tonic-gate 63407c478bd9Sstevel@tonic-gate return (succeeded ? MDI_SUCCESS : MDI_FAILURE); 63417c478bd9Sstevel@tonic-gate } 63427c478bd9Sstevel@tonic-gate 63437c478bd9Sstevel@tonic-gate /* 63447c478bd9Sstevel@tonic-gate * mdi_bus_power(): 63457c478bd9Sstevel@tonic-gate * 1. Place the phci(s) into powered up state so that 63467c478bd9Sstevel@tonic-gate * client can do power management 63477c478bd9Sstevel@tonic-gate * 2. Ensure phci powered up as client power managing 63487c478bd9Sstevel@tonic-gate * Return Values: 63497c478bd9Sstevel@tonic-gate * MDI_SUCCESS 63507c478bd9Sstevel@tonic-gate * MDI_FAILURE 63517c478bd9Sstevel@tonic-gate */ 63527c478bd9Sstevel@tonic-gate int 63537c478bd9Sstevel@tonic-gate mdi_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op, 63547c478bd9Sstevel@tonic-gate void *arg, void *result) 63557c478bd9Sstevel@tonic-gate { 63567c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 63577c478bd9Sstevel@tonic-gate pm_bp_child_pwrchg_t *bpc; 63587c478bd9Sstevel@tonic-gate mdi_client_t *ct; 63597c478bd9Sstevel@tonic-gate dev_info_t *cdip; 63607c478bd9Sstevel@tonic-gate pm_bp_has_changed_t *bphc; 63617c478bd9Sstevel@tonic-gate 63627c478bd9Sstevel@tonic-gate /* 63637c478bd9Sstevel@tonic-gate * BUS_POWER_NOINVOL not supported 63647c478bd9Sstevel@tonic-gate */ 63657c478bd9Sstevel@tonic-gate if (op == BUS_POWER_NOINVOL) 63667c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 63677c478bd9Sstevel@tonic-gate 63687c478bd9Sstevel@tonic-gate /* 63697c478bd9Sstevel@tonic-gate * ignore other OPs. 63707c478bd9Sstevel@tonic-gate * return quickly to save cou cycles on the ct processing 63717c478bd9Sstevel@tonic-gate */ 63727c478bd9Sstevel@tonic-gate switch (op) { 63737c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 63747c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 63757c478bd9Sstevel@tonic-gate bpc = (pm_bp_child_pwrchg_t *)arg; 63767c478bd9Sstevel@tonic-gate cdip = bpc->bpc_dip; 63777c478bd9Sstevel@tonic-gate break; 63787c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 63797c478bd9Sstevel@tonic-gate bphc = (pm_bp_has_changed_t *)arg; 63807c478bd9Sstevel@tonic-gate cdip = bphc->bphc_dip; 63817c478bd9Sstevel@tonic-gate break; 63827c478bd9Sstevel@tonic-gate default: 63837c478bd9Sstevel@tonic-gate return (pm_busop_bus_power(parent, impl_arg, op, arg, result)); 63847c478bd9Sstevel@tonic-gate } 63857c478bd9Sstevel@tonic-gate 63867c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(cdip)); 63877c478bd9Sstevel@tonic-gate 63887c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 63897c478bd9Sstevel@tonic-gate if (ct == NULL) 63907c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 63917c478bd9Sstevel@tonic-gate 63927c478bd9Sstevel@tonic-gate /* 63937c478bd9Sstevel@tonic-gate * wait till the mdi_pathinfo node state change are processed 63947c478bd9Sstevel@tonic-gate */ 63957c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 63967c478bd9Sstevel@tonic-gate switch (op) { 63977c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 63987c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 63997c478bd9Sstevel@tonic-gate "BUS_POWER_PRE_NOTIFICATION:" 64007c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 64017c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 64027c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp)); 64037c478bd9Sstevel@tonic-gate 64047c478bd9Sstevel@tonic-gate /* serialize power level change per client */ 64057c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 64067c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 64077c478bd9Sstevel@tonic-gate 64087c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_TRANSITION(ct); 64097c478bd9Sstevel@tonic-gate 64107c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 64117c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 64127c478bd9Sstevel@tonic-gate } 64137c478bd9Sstevel@tonic-gate 64147c478bd9Sstevel@tonic-gate /* 64157c478bd9Sstevel@tonic-gate * if new_level > 0: 64167c478bd9Sstevel@tonic-gate * - hold phci(s) 64177c478bd9Sstevel@tonic-gate * - power up phci(s) if not already 64187c478bd9Sstevel@tonic-gate * ignore power down 64197c478bd9Sstevel@tonic-gate */ 64207c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 64217c478bd9Sstevel@tonic-gate if (!DEVI_IS_ATTACHING(ct->ct_dip)) { 64227c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 64237c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 64247c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 64257c478bd9Sstevel@tonic-gate } 64267c478bd9Sstevel@tonic-gate } 64277c478bd9Sstevel@tonic-gate break; 64287c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 64297c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 64307c478bd9Sstevel@tonic-gate "BUS_POWER_POST_NOTIFICATION:" 64317c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d result=%d\n", 64327c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 64337c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp, 64347c478bd9Sstevel@tonic-gate *(int *)result)); 64357c478bd9Sstevel@tonic-gate 64367c478bd9Sstevel@tonic-gate if (*(int *)result == DDI_SUCCESS) { 64377c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 64387c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 64397c478bd9Sstevel@tonic-gate } else { 64407c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_DOWN(ct); 64417c478bd9Sstevel@tonic-gate } 64427c478bd9Sstevel@tonic-gate } 64437c478bd9Sstevel@tonic-gate 64447c478bd9Sstevel@tonic-gate /* release the hold we did in pre-notification */ 64457c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0 && (*(int *)result != DDI_SUCCESS) && 64467c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) { 64477c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 64487c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 64497c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 64507c478bd9Sstevel@tonic-gate } 64517c478bd9Sstevel@tonic-gate 64527c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel == 0 && (*(int *)result == DDI_SUCCESS)) { 64537c478bd9Sstevel@tonic-gate /* another thread might started attaching */ 64547c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 64557c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 64567c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 64577c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 64587c478bd9Sstevel@tonic-gate /* detaching has been taken care in pm_post_unconfig */ 64597c478bd9Sstevel@tonic-gate } else if (!DEVI_IS_DETACHING(ct->ct_dip)) { 64607c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 64617c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_reset_client\n")); 64627c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 64637c478bd9Sstevel@tonic-gate } 64647c478bd9Sstevel@tonic-gate } 64657c478bd9Sstevel@tonic-gate 64667c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_POWER_TRANSITION(ct); 64677c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_powerchange_cv); 64687c478bd9Sstevel@tonic-gate 64697c478bd9Sstevel@tonic-gate break; 64707c478bd9Sstevel@tonic-gate 64717c478bd9Sstevel@tonic-gate /* need to do more */ 64727c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 64737c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, "mdi_bus_power " 64747c478bd9Sstevel@tonic-gate "BUS_POWER_HAS_CHANGED:" 64757c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 64767c478bd9Sstevel@tonic-gate PM_NAME(bphc->bphc_dip), PM_ADDR(bphc->bphc_dip), 64777c478bd9Sstevel@tonic-gate bphc->bphc_olevel, bphc->bphc_nlevel, bphc->bphc_comp)); 64787c478bd9Sstevel@tonic-gate 64797c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel > 0 && 64807c478bd9Sstevel@tonic-gate bphc->bphc_nlevel > bphc->bphc_olevel) { 64817c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 64827c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 64837c478bd9Sstevel@tonic-gate } 64847c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 64857c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 64867c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 64877c478bd9Sstevel@tonic-gate } 64887c478bd9Sstevel@tonic-gate 64897c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel == 0 && bphc->bphc_olevel != -1) { 64907c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 64917c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 64927c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 64937c478bd9Sstevel@tonic-gate } 64947c478bd9Sstevel@tonic-gate break; 64957c478bd9Sstevel@tonic-gate } 64967c478bd9Sstevel@tonic-gate 64977c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 64987c478bd9Sstevel@tonic-gate return (ret); 64997c478bd9Sstevel@tonic-gate } 65007c478bd9Sstevel@tonic-gate 65017c478bd9Sstevel@tonic-gate static int 65027c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config_one(dev_info_t *child) 65037c478bd9Sstevel@tonic-gate { 65047c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 65057c478bd9Sstevel@tonic-gate mdi_client_t *ct; 65067c478bd9Sstevel@tonic-gate 65077c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 65087c478bd9Sstevel@tonic-gate if (ct == NULL) 65097c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 65107c478bd9Sstevel@tonic-gate 65117c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 65127c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 65137c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 65147c478bd9Sstevel@tonic-gate 65157c478bd9Sstevel@tonic-gate if (!MDI_CLIENT_IS_FAILED(ct)) { 65167c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 65177c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 65187c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one already configured\n")); 65197c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 65207c478bd9Sstevel@tonic-gate } 65217c478bd9Sstevel@tonic-gate 652278dc6db2Sllai1 if (ct->ct_powercnt_config) { 65237c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 65247c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 65257c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one ALREADY held\n")); 65267c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 65277c478bd9Sstevel@tonic-gate } 65287c478bd9Sstevel@tonic-gate 65297c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 65307c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 65317c478bd9Sstevel@tonic-gate } 65327c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 65337c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one i_mdi_pm_hold_client\n")); 65347c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 653578dc6db2Sllai1 ct->ct_powercnt_config = 1; 65367c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 65377c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 65387c478bd9Sstevel@tonic-gate return (ret); 65397c478bd9Sstevel@tonic-gate } 65407c478bd9Sstevel@tonic-gate 65417c478bd9Sstevel@tonic-gate static int 65425e3986cbScth i_mdi_pm_pre_config(dev_info_t *vdip, dev_info_t *child) 65437c478bd9Sstevel@tonic-gate { 65447c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 65457c478bd9Sstevel@tonic-gate dev_info_t *cdip; 65467c478bd9Sstevel@tonic-gate int circ; 65477c478bd9Sstevel@tonic-gate 65485e3986cbScth ASSERT(MDI_VHCI(vdip)); 65497c478bd9Sstevel@tonic-gate 65507c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 65517c478bd9Sstevel@tonic-gate if (child) { 65525e3986cbScth ASSERT(DEVI_BUSY_OWNED(vdip)); 65537c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_config_one(child)); 65547c478bd9Sstevel@tonic-gate } 65557c478bd9Sstevel@tonic-gate 65567c478bd9Sstevel@tonic-gate /* devi_config_common */ 65575e3986cbScth ndi_devi_enter(vdip, &circ); 65585e3986cbScth cdip = ddi_get_child(vdip); 65597c478bd9Sstevel@tonic-gate while (cdip) { 65607c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 65617c478bd9Sstevel@tonic-gate 65627c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config_one(cdip); 65637c478bd9Sstevel@tonic-gate if (ret != MDI_SUCCESS) 65647c478bd9Sstevel@tonic-gate break; 65657c478bd9Sstevel@tonic-gate cdip = next; 65667c478bd9Sstevel@tonic-gate } 65675e3986cbScth ndi_devi_exit(vdip, circ); 65687c478bd9Sstevel@tonic-gate return (ret); 65697c478bd9Sstevel@tonic-gate } 65707c478bd9Sstevel@tonic-gate 65717c478bd9Sstevel@tonic-gate static int 65727c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig_one(dev_info_t *child, int *held, int flags) 65737c478bd9Sstevel@tonic-gate { 65747c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 65757c478bd9Sstevel@tonic-gate mdi_client_t *ct; 65767c478bd9Sstevel@tonic-gate 65777c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 65787c478bd9Sstevel@tonic-gate if (ct == NULL) 65797c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 65807c478bd9Sstevel@tonic-gate 65817c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 65827c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 65837c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 65847c478bd9Sstevel@tonic-gate 6585737d277aScth if (!i_ddi_devi_attached(ct->ct_dip)) { 65867c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 65877c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig node detached already\n")); 65887c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 65897c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 65907c478bd9Sstevel@tonic-gate } 65917c478bd9Sstevel@tonic-gate 65927c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_POWERED_DOWN(ct) && 65937c478bd9Sstevel@tonic-gate (flags & NDI_AUTODETACH)) { 65947c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 65957c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig auto-modunload\n")); 65967c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 65977c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 65987c478bd9Sstevel@tonic-gate } 65997c478bd9Sstevel@tonic-gate 660078dc6db2Sllai1 if (ct->ct_powercnt_unconfig) { 66017c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 66027c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig ct_powercnt_held\n")); 66037c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 66047c478bd9Sstevel@tonic-gate *held = 1; 66057c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 66067c478bd9Sstevel@tonic-gate } 66077c478bd9Sstevel@tonic-gate 66087c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 66097c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 66107c478bd9Sstevel@tonic-gate } 66117c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 66127c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig i_mdi_pm_hold_client\n")); 66137c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 661478dc6db2Sllai1 ct->ct_powercnt_unconfig = 1; 66157c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 66167c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 66177c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) 66187c478bd9Sstevel@tonic-gate *held = 1; 66197c478bd9Sstevel@tonic-gate return (ret); 66207c478bd9Sstevel@tonic-gate } 66217c478bd9Sstevel@tonic-gate 66227c478bd9Sstevel@tonic-gate static int 66235e3986cbScth i_mdi_pm_pre_unconfig(dev_info_t *vdip, dev_info_t *child, int *held, 66247c478bd9Sstevel@tonic-gate int flags) 66257c478bd9Sstevel@tonic-gate { 66267c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 66277c478bd9Sstevel@tonic-gate dev_info_t *cdip; 66287c478bd9Sstevel@tonic-gate int circ; 66297c478bd9Sstevel@tonic-gate 66305e3986cbScth ASSERT(MDI_VHCI(vdip)); 66317c478bd9Sstevel@tonic-gate *held = 0; 66327c478bd9Sstevel@tonic-gate 66337c478bd9Sstevel@tonic-gate /* ndi_devi_unconfig_one */ 66347c478bd9Sstevel@tonic-gate if (child) { 66355e3986cbScth ASSERT(DEVI_BUSY_OWNED(vdip)); 66367c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_unconfig_one(child, held, flags)); 66377c478bd9Sstevel@tonic-gate } 66387c478bd9Sstevel@tonic-gate 66397c478bd9Sstevel@tonic-gate /* devi_unconfig_common */ 66405e3986cbScth ndi_devi_enter(vdip, &circ); 66415e3986cbScth cdip = ddi_get_child(vdip); 66427c478bd9Sstevel@tonic-gate while (cdip) { 66437c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 66447c478bd9Sstevel@tonic-gate 66457c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig_one(cdip, held, flags); 66467c478bd9Sstevel@tonic-gate cdip = next; 66477c478bd9Sstevel@tonic-gate } 66485e3986cbScth ndi_devi_exit(vdip, circ); 66497c478bd9Sstevel@tonic-gate 66507c478bd9Sstevel@tonic-gate if (*held) 66517c478bd9Sstevel@tonic-gate ret = MDI_SUCCESS; 66527c478bd9Sstevel@tonic-gate 66537c478bd9Sstevel@tonic-gate return (ret); 66547c478bd9Sstevel@tonic-gate } 66557c478bd9Sstevel@tonic-gate 66567c478bd9Sstevel@tonic-gate static void 66577c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(dev_info_t *child) 66587c478bd9Sstevel@tonic-gate { 66597c478bd9Sstevel@tonic-gate mdi_client_t *ct; 66607c478bd9Sstevel@tonic-gate 66617c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 66627c478bd9Sstevel@tonic-gate if (ct == NULL) 66637c478bd9Sstevel@tonic-gate return; 66647c478bd9Sstevel@tonic-gate 66657c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 66667c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 66677c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 66687c478bd9Sstevel@tonic-gate 666978dc6db2Sllai1 if (ct->ct_powercnt_reset || !ct->ct_powercnt_config) { 66707c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 667178dc6db2Sllai1 "i_mdi_pm_post_config_one NOT configured\n")); 66727c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 66737c478bd9Sstevel@tonic-gate return; 66747c478bd9Sstevel@tonic-gate } 66757c478bd9Sstevel@tonic-gate 66767c478bd9Sstevel@tonic-gate /* client has not been updated */ 66777c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 66787c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 66797c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config_one NOT configured\n")); 66807c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 66817c478bd9Sstevel@tonic-gate return; 66827c478bd9Sstevel@tonic-gate } 66837c478bd9Sstevel@tonic-gate 66847c478bd9Sstevel@tonic-gate /* another thread might have powered it down or detached it */ 66857c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 66867c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) || 6687737d277aScth (!i_ddi_devi_attached(ct->ct_dip) && 66887c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 66897c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 66907c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_reset_client\n")); 66917c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 66927c478bd9Sstevel@tonic-gate } else { 66937c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 66947c478bd9Sstevel@tonic-gate int valid_path_count = 0; 66957c478bd9Sstevel@tonic-gate 66967c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 66977c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_rele_client\n")); 66987c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 66997c478bd9Sstevel@tonic-gate while (pip != NULL) { 67007c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 67017c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 670278dc6db2Sllai1 if (MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip)) 67037c478bd9Sstevel@tonic-gate valid_path_count ++; 67047c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 67057c478bd9Sstevel@tonic-gate pip = next; 67067c478bd9Sstevel@tonic-gate } 67077c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, valid_path_count); 67087c478bd9Sstevel@tonic-gate } 670978dc6db2Sllai1 ct->ct_powercnt_config = 0; 67107c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 67117c478bd9Sstevel@tonic-gate } 67127c478bd9Sstevel@tonic-gate 67137c478bd9Sstevel@tonic-gate static void 67145e3986cbScth i_mdi_pm_post_config(dev_info_t *vdip, dev_info_t *child) 67157c478bd9Sstevel@tonic-gate { 67167c478bd9Sstevel@tonic-gate int circ; 67177c478bd9Sstevel@tonic-gate dev_info_t *cdip; 67185e3986cbScth 67195e3986cbScth ASSERT(MDI_VHCI(vdip)); 67207c478bd9Sstevel@tonic-gate 67217c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 67227c478bd9Sstevel@tonic-gate if (child) { 67235e3986cbScth ASSERT(DEVI_BUSY_OWNED(vdip)); 67247c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(child); 67257c478bd9Sstevel@tonic-gate return; 67267c478bd9Sstevel@tonic-gate } 67277c478bd9Sstevel@tonic-gate 67287c478bd9Sstevel@tonic-gate /* devi_config_common */ 67295e3986cbScth ndi_devi_enter(vdip, &circ); 67305e3986cbScth cdip = ddi_get_child(vdip); 67317c478bd9Sstevel@tonic-gate while (cdip) { 67327c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 67337c478bd9Sstevel@tonic-gate 67347c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(cdip); 67357c478bd9Sstevel@tonic-gate cdip = next; 67367c478bd9Sstevel@tonic-gate } 67375e3986cbScth ndi_devi_exit(vdip, circ); 67387c478bd9Sstevel@tonic-gate } 67397c478bd9Sstevel@tonic-gate 67407c478bd9Sstevel@tonic-gate static void 67417c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(dev_info_t *child) 67427c478bd9Sstevel@tonic-gate { 67437c478bd9Sstevel@tonic-gate mdi_client_t *ct; 67447c478bd9Sstevel@tonic-gate 67457c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 67467c478bd9Sstevel@tonic-gate if (ct == NULL) 67477c478bd9Sstevel@tonic-gate return; 67487c478bd9Sstevel@tonic-gate 67497c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 67507c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 67517c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 67527c478bd9Sstevel@tonic-gate 675378dc6db2Sllai1 if (!ct->ct_powercnt_unconfig || ct->ct_powercnt_reset) { 67547c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 67557c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig NOT held\n")); 67567c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 67577c478bd9Sstevel@tonic-gate return; 67587c478bd9Sstevel@tonic-gate } 67597c478bd9Sstevel@tonic-gate 67607c478bd9Sstevel@tonic-gate /* failure detaching or another thread just attached it */ 67617c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 6762737d277aScth i_ddi_devi_attached(ct->ct_dip)) || 6763737d277aScth (!i_ddi_devi_attached(ct->ct_dip) && 67647c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 67657c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 67667c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig i_mdi_pm_reset_client\n")); 67677c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 676878dc6db2Sllai1 } else { 676978dc6db2Sllai1 mdi_pathinfo_t *pip, *next; 677078dc6db2Sllai1 int valid_path_count = 0; 67717c478bd9Sstevel@tonic-gate 67727c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 677378dc6db2Sllai1 "i_mdi_pm_post_unconfig i_mdi_pm_rele_client\n")); 677478dc6db2Sllai1 pip = ct->ct_path_head; 677578dc6db2Sllai1 while (pip != NULL) { 677678dc6db2Sllai1 MDI_PI_LOCK(pip); 677778dc6db2Sllai1 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 677878dc6db2Sllai1 if (MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip)) 677978dc6db2Sllai1 valid_path_count ++; 678078dc6db2Sllai1 MDI_PI_UNLOCK(pip); 678178dc6db2Sllai1 pip = next; 678278dc6db2Sllai1 } 678378dc6db2Sllai1 i_mdi_pm_rele_client(ct, valid_path_count); 678478dc6db2Sllai1 ct->ct_powercnt_unconfig = 0; 678578dc6db2Sllai1 } 678678dc6db2Sllai1 67877c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 67887c478bd9Sstevel@tonic-gate } 67897c478bd9Sstevel@tonic-gate 67907c478bd9Sstevel@tonic-gate static void 67915e3986cbScth i_mdi_pm_post_unconfig(dev_info_t *vdip, dev_info_t *child, int held) 67927c478bd9Sstevel@tonic-gate { 67937c478bd9Sstevel@tonic-gate int circ; 67947c478bd9Sstevel@tonic-gate dev_info_t *cdip; 67957c478bd9Sstevel@tonic-gate 67965e3986cbScth ASSERT(MDI_VHCI(vdip)); 67977c478bd9Sstevel@tonic-gate 67987c478bd9Sstevel@tonic-gate if (!held) { 67995e3986cbScth MDI_DEBUG(4, (CE_NOTE, vdip, 68007c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig held = %d\n", held)); 68017c478bd9Sstevel@tonic-gate return; 68027c478bd9Sstevel@tonic-gate } 68037c478bd9Sstevel@tonic-gate 68047c478bd9Sstevel@tonic-gate if (child) { 68055e3986cbScth ASSERT(DEVI_BUSY_OWNED(vdip)); 68067c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(child); 68077c478bd9Sstevel@tonic-gate return; 68087c478bd9Sstevel@tonic-gate } 68097c478bd9Sstevel@tonic-gate 68105e3986cbScth ndi_devi_enter(vdip, &circ); 68115e3986cbScth cdip = ddi_get_child(vdip); 68127c478bd9Sstevel@tonic-gate while (cdip) { 68137c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 68147c478bd9Sstevel@tonic-gate 68157c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(cdip); 68167c478bd9Sstevel@tonic-gate cdip = next; 68177c478bd9Sstevel@tonic-gate } 68185e3986cbScth ndi_devi_exit(vdip, circ); 68197c478bd9Sstevel@tonic-gate } 68207c478bd9Sstevel@tonic-gate 68217c478bd9Sstevel@tonic-gate int 68227c478bd9Sstevel@tonic-gate mdi_power(dev_info_t *vdip, mdi_pm_op_t op, void *args, char *devnm, int flags) 68237c478bd9Sstevel@tonic-gate { 68247c478bd9Sstevel@tonic-gate int circ, ret = MDI_SUCCESS; 68257c478bd9Sstevel@tonic-gate dev_info_t *client_dip = NULL; 68267c478bd9Sstevel@tonic-gate mdi_client_t *ct; 68277c478bd9Sstevel@tonic-gate 68287c478bd9Sstevel@tonic-gate /* 68297c478bd9Sstevel@tonic-gate * Handling ndi_devi_config_one and ndi_devi_unconfig_one. 68307c478bd9Sstevel@tonic-gate * Power up pHCI for the named client device. 68317c478bd9Sstevel@tonic-gate * Note: Before the client is enumerated under vhci by phci, 68327c478bd9Sstevel@tonic-gate * client_dip can be NULL. Then proceed to power up all the 68337c478bd9Sstevel@tonic-gate * pHCIs. 68347c478bd9Sstevel@tonic-gate */ 68357c478bd9Sstevel@tonic-gate if (devnm != NULL) { 68367c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circ); 68377c478bd9Sstevel@tonic-gate client_dip = ndi_devi_findchild(vdip, devnm); 68387c478bd9Sstevel@tonic-gate } 68397c478bd9Sstevel@tonic-gate 68405e3986cbScth MDI_DEBUG(4, (CE_NOTE, vdip, "mdi_power op = %d %s %p\n", 68415e3986cbScth op, devnm ? devnm : "NULL", (void *)client_dip)); 68427c478bd9Sstevel@tonic-gate 68437c478bd9Sstevel@tonic-gate switch (op) { 68447c478bd9Sstevel@tonic-gate case MDI_PM_PRE_CONFIG: 68457c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config(vdip, client_dip); 6846c73a93f2Sdm120769 break; 68475e3986cbScth 68487c478bd9Sstevel@tonic-gate case MDI_PM_PRE_UNCONFIG: 68497c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig(vdip, client_dip, (int *)args, 68507c478bd9Sstevel@tonic-gate flags); 6851c73a93f2Sdm120769 break; 68525e3986cbScth 68537c478bd9Sstevel@tonic-gate case MDI_PM_POST_CONFIG: 68547c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(vdip, client_dip); 6855c73a93f2Sdm120769 break; 68565e3986cbScth 68577c478bd9Sstevel@tonic-gate case MDI_PM_POST_UNCONFIG: 68587c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(vdip, client_dip, *(int *)args); 6859c73a93f2Sdm120769 break; 68605e3986cbScth 68617c478bd9Sstevel@tonic-gate case MDI_PM_HOLD_POWER: 68627c478bd9Sstevel@tonic-gate case MDI_PM_RELE_POWER: 68637c478bd9Sstevel@tonic-gate ASSERT(args); 68647c478bd9Sstevel@tonic-gate 68657c478bd9Sstevel@tonic-gate client_dip = (dev_info_t *)args; 68667c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(client_dip)); 68677c478bd9Sstevel@tonic-gate 68687c478bd9Sstevel@tonic-gate ct = i_devi_get_client(client_dip); 68697c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 68707c478bd9Sstevel@tonic-gate 68717c478bd9Sstevel@tonic-gate if (op == MDI_PM_HOLD_POWER) { 68727c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 68737c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 68747c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 68757c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_hold_client\n")); 68767c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 68777c478bd9Sstevel@tonic-gate } 68787c478bd9Sstevel@tonic-gate } else { 68797c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 68807c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 68817c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_rele_client\n")); 68827c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 68837c478bd9Sstevel@tonic-gate } else { 68847c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 68857c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_reset_client\n")); 68867c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 68877c478bd9Sstevel@tonic-gate } 68887c478bd9Sstevel@tonic-gate } 68897c478bd9Sstevel@tonic-gate 68907c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 68917c478bd9Sstevel@tonic-gate break; 68925e3986cbScth 68937c478bd9Sstevel@tonic-gate default: 68947c478bd9Sstevel@tonic-gate break; 68957c478bd9Sstevel@tonic-gate } 68967c478bd9Sstevel@tonic-gate 68975e3986cbScth if (devnm) 68985e3986cbScth ndi_devi_exit(vdip, circ); 68995e3986cbScth 69007c478bd9Sstevel@tonic-gate return (ret); 69017c478bd9Sstevel@tonic-gate } 69027c478bd9Sstevel@tonic-gate 69037c478bd9Sstevel@tonic-gate int 69047c478bd9Sstevel@tonic-gate mdi_component_is_vhci(dev_info_t *dip, const char **mdi_class) 69057c478bd9Sstevel@tonic-gate { 69067c478bd9Sstevel@tonic-gate mdi_vhci_t *vhci; 69077c478bd9Sstevel@tonic-gate 69087c478bd9Sstevel@tonic-gate if (!MDI_VHCI(dip)) 69097c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 69107c478bd9Sstevel@tonic-gate 69117c478bd9Sstevel@tonic-gate if (mdi_class) { 69127c478bd9Sstevel@tonic-gate vhci = DEVI(dip)->devi_mdi_xhci; 69137c478bd9Sstevel@tonic-gate ASSERT(vhci); 69147c478bd9Sstevel@tonic-gate *mdi_class = vhci->vh_class; 69157c478bd9Sstevel@tonic-gate } 69167c478bd9Sstevel@tonic-gate 69177c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 69187c478bd9Sstevel@tonic-gate } 69197c478bd9Sstevel@tonic-gate 69207c478bd9Sstevel@tonic-gate int 69217c478bd9Sstevel@tonic-gate mdi_component_is_phci(dev_info_t *dip, const char **mdi_class) 69227c478bd9Sstevel@tonic-gate { 69237c478bd9Sstevel@tonic-gate mdi_phci_t *phci; 69247c478bd9Sstevel@tonic-gate 69257c478bd9Sstevel@tonic-gate if (!MDI_PHCI(dip)) 69267c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 69277c478bd9Sstevel@tonic-gate 69287c478bd9Sstevel@tonic-gate if (mdi_class) { 69297c478bd9Sstevel@tonic-gate phci = DEVI(dip)->devi_mdi_xhci; 69307c478bd9Sstevel@tonic-gate ASSERT(phci); 69317c478bd9Sstevel@tonic-gate *mdi_class = phci->ph_vhci->vh_class; 69327c478bd9Sstevel@tonic-gate } 69337c478bd9Sstevel@tonic-gate 69347c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 69357c478bd9Sstevel@tonic-gate } 69367c478bd9Sstevel@tonic-gate 69377c478bd9Sstevel@tonic-gate int 69387c478bd9Sstevel@tonic-gate mdi_component_is_client(dev_info_t *dip, const char **mdi_class) 69397c478bd9Sstevel@tonic-gate { 69407c478bd9Sstevel@tonic-gate mdi_client_t *client; 69417c478bd9Sstevel@tonic-gate 69427c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(dip)) 69437c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 69447c478bd9Sstevel@tonic-gate 69457c478bd9Sstevel@tonic-gate if (mdi_class) { 69467c478bd9Sstevel@tonic-gate client = DEVI(dip)->devi_mdi_client; 69477c478bd9Sstevel@tonic-gate ASSERT(client); 69487c478bd9Sstevel@tonic-gate *mdi_class = client->ct_vhci->vh_class; 69497c478bd9Sstevel@tonic-gate } 69507c478bd9Sstevel@tonic-gate 69517c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 69527c478bd9Sstevel@tonic-gate } 69537c478bd9Sstevel@tonic-gate 69547c478bd9Sstevel@tonic-gate void * 69557c478bd9Sstevel@tonic-gate mdi_client_get_vhci_private(dev_info_t *dip) 69567c478bd9Sstevel@tonic-gate { 69577c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 69587c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 69597c478bd9Sstevel@tonic-gate mdi_client_t *ct; 69607c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 69617c478bd9Sstevel@tonic-gate return (ct->ct_vprivate); 69627c478bd9Sstevel@tonic-gate } 69637c478bd9Sstevel@tonic-gate return (NULL); 69647c478bd9Sstevel@tonic-gate } 69657c478bd9Sstevel@tonic-gate 69667c478bd9Sstevel@tonic-gate void 69677c478bd9Sstevel@tonic-gate mdi_client_set_vhci_private(dev_info_t *dip, void *data) 69687c478bd9Sstevel@tonic-gate { 69697c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 69707c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 69717c478bd9Sstevel@tonic-gate mdi_client_t *ct; 69727c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 69737c478bd9Sstevel@tonic-gate ct->ct_vprivate = data; 69747c478bd9Sstevel@tonic-gate } 69757c478bd9Sstevel@tonic-gate } 69767c478bd9Sstevel@tonic-gate /* 69777c478bd9Sstevel@tonic-gate * mdi_pi_get_vhci_private(): 69787c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 69797c478bd9Sstevel@tonic-gate * mdi_pathinfo node 69807c478bd9Sstevel@tonic-gate */ 69817c478bd9Sstevel@tonic-gate void * 69827c478bd9Sstevel@tonic-gate mdi_pi_get_vhci_private(mdi_pathinfo_t *pip) 69837c478bd9Sstevel@tonic-gate { 69847c478bd9Sstevel@tonic-gate caddr_t vprivate = NULL; 69857c478bd9Sstevel@tonic-gate if (pip) { 69867c478bd9Sstevel@tonic-gate vprivate = MDI_PI(pip)->pi_vprivate; 69877c478bd9Sstevel@tonic-gate } 69887c478bd9Sstevel@tonic-gate return (vprivate); 69897c478bd9Sstevel@tonic-gate } 69907c478bd9Sstevel@tonic-gate 69917c478bd9Sstevel@tonic-gate /* 69927c478bd9Sstevel@tonic-gate * mdi_pi_set_vhci_private(): 69937c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_pathinfo node 69947c478bd9Sstevel@tonic-gate */ 69957c478bd9Sstevel@tonic-gate void 69967c478bd9Sstevel@tonic-gate mdi_pi_set_vhci_private(mdi_pathinfo_t *pip, void *priv) 69977c478bd9Sstevel@tonic-gate { 69987c478bd9Sstevel@tonic-gate if (pip) { 69997c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = priv; 70007c478bd9Sstevel@tonic-gate } 70017c478bd9Sstevel@tonic-gate } 70027c478bd9Sstevel@tonic-gate 70037c478bd9Sstevel@tonic-gate /* 70047c478bd9Sstevel@tonic-gate * mdi_phci_get_vhci_private(): 70057c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 70067c478bd9Sstevel@tonic-gate * mdi_phci node 70077c478bd9Sstevel@tonic-gate */ 70087c478bd9Sstevel@tonic-gate void * 70097c478bd9Sstevel@tonic-gate mdi_phci_get_vhci_private(dev_info_t *dip) 70107c478bd9Sstevel@tonic-gate { 70117c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 70127c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 70137c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 70147c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 70157c478bd9Sstevel@tonic-gate return (ph->ph_vprivate); 70167c478bd9Sstevel@tonic-gate } 70177c478bd9Sstevel@tonic-gate return (NULL); 70187c478bd9Sstevel@tonic-gate } 70197c478bd9Sstevel@tonic-gate 70207c478bd9Sstevel@tonic-gate /* 70217c478bd9Sstevel@tonic-gate * mdi_phci_set_vhci_private(): 70227c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_phci node 70237c478bd9Sstevel@tonic-gate */ 70247c478bd9Sstevel@tonic-gate void 70257c478bd9Sstevel@tonic-gate mdi_phci_set_vhci_private(dev_info_t *dip, void *priv) 70267c478bd9Sstevel@tonic-gate { 70277c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 70287c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 70297c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 70307c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 70317c478bd9Sstevel@tonic-gate ph->ph_vprivate = priv; 70327c478bd9Sstevel@tonic-gate } 70337c478bd9Sstevel@tonic-gate } 70343c34adc5Sramat 70353c34adc5Sramat /* 70363c34adc5Sramat * List of vhci class names: 70373c34adc5Sramat * A vhci class name must be in this list only if the corresponding vhci 70383c34adc5Sramat * driver intends to use the mdi provided bus config implementation 70393c34adc5Sramat * (i.e., mdi_vhci_bus_config()). 70403c34adc5Sramat */ 70413c34adc5Sramat static char *vhci_class_list[] = { MDI_HCI_CLASS_SCSI, MDI_HCI_CLASS_IB }; 70423c34adc5Sramat #define N_VHCI_CLASSES (sizeof (vhci_class_list) / sizeof (char *)) 70433c34adc5Sramat 70443c34adc5Sramat /* 70453c34adc5Sramat * During boot time, the on-disk vhci cache for every vhci class is read 70463c34adc5Sramat * in the form of an nvlist and stored here. 70473c34adc5Sramat */ 70483c34adc5Sramat static nvlist_t *vhcache_nvl[N_VHCI_CLASSES]; 70493c34adc5Sramat 70503c34adc5Sramat /* nvpair names in vhci cache nvlist */ 70513c34adc5Sramat #define MDI_VHCI_CACHE_VERSION 1 70523c34adc5Sramat #define MDI_NVPNAME_VERSION "version" 70533c34adc5Sramat #define MDI_NVPNAME_PHCIS "phcis" 70543c34adc5Sramat #define MDI_NVPNAME_CTADDRMAP "clientaddrmap" 70553c34adc5Sramat 70563c34adc5Sramat /* 70573c34adc5Sramat * Given vhci class name, return its on-disk vhci cache filename. 70583c34adc5Sramat * Memory for the returned filename which includes the full path is allocated 70593c34adc5Sramat * by this function. 70603c34adc5Sramat */ 70613c34adc5Sramat static char * 70623c34adc5Sramat vhclass2vhcache_filename(char *vhclass) 70633c34adc5Sramat { 70643c34adc5Sramat char *filename; 70653c34adc5Sramat int len; 70663c34adc5Sramat static char *fmt = "/etc/devices/mdi_%s_cache"; 70673c34adc5Sramat 70683c34adc5Sramat /* 70693c34adc5Sramat * fmt contains the on-disk vhci cache file name format; 70703c34adc5Sramat * for scsi_vhci the filename is "/etc/devices/mdi_scsi_vhci_cache". 70713c34adc5Sramat */ 70723c34adc5Sramat 70733c34adc5Sramat /* the -1 below is to account for "%s" in the format string */ 70743c34adc5Sramat len = strlen(fmt) + strlen(vhclass) - 1; 70753c34adc5Sramat filename = kmem_alloc(len, KM_SLEEP); 70763c34adc5Sramat (void) snprintf(filename, len, fmt, vhclass); 70773c34adc5Sramat ASSERT(len == (strlen(filename) + 1)); 70783c34adc5Sramat return (filename); 70793c34adc5Sramat } 70803c34adc5Sramat 70813c34adc5Sramat /* 70823c34adc5Sramat * initialize the vhci cache related data structures and read the on-disk 70833c34adc5Sramat * vhci cached data into memory. 70843c34adc5Sramat */ 70853c34adc5Sramat static void 70863c34adc5Sramat setup_vhci_cache(mdi_vhci_t *vh) 70873c34adc5Sramat { 70883c34adc5Sramat mdi_vhci_config_t *vhc; 70893c34adc5Sramat mdi_vhci_cache_t *vhcache; 70903c34adc5Sramat int i; 70913c34adc5Sramat nvlist_t *nvl = NULL; 70923c34adc5Sramat 70933c34adc5Sramat vhc = kmem_zalloc(sizeof (mdi_vhci_config_t), KM_SLEEP); 70943c34adc5Sramat vh->vh_config = vhc; 70953c34adc5Sramat vhcache = &vhc->vhc_vhcache; 70963c34adc5Sramat 70973c34adc5Sramat vhc->vhc_vhcache_filename = vhclass2vhcache_filename(vh->vh_class); 70983c34adc5Sramat 70993c34adc5Sramat mutex_init(&vhc->vhc_lock, NULL, MUTEX_DEFAULT, NULL); 71003c34adc5Sramat cv_init(&vhc->vhc_cv, NULL, CV_DRIVER, NULL); 71013c34adc5Sramat 71023c34adc5Sramat rw_init(&vhcache->vhcache_lock, NULL, RW_DRIVER, NULL); 71033c34adc5Sramat 71043c34adc5Sramat /* 71053c34adc5Sramat * Create string hash; same as mod_hash_create_strhash() except that 71063c34adc5Sramat * we use NULL key destructor. 71073c34adc5Sramat */ 71083c34adc5Sramat vhcache->vhcache_client_hash = mod_hash_create_extended(vh->vh_class, 71093c34adc5Sramat mdi_bus_config_cache_hash_size, 71103c34adc5Sramat mod_hash_null_keydtor, mod_hash_null_valdtor, 71113c34adc5Sramat mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 71123c34adc5Sramat 71133c34adc5Sramat /* 71143c34adc5Sramat * The on-disk vhci cache is read during booting prior to the 71153c34adc5Sramat * lights-out period by mdi_read_devices_files(). 71163c34adc5Sramat */ 71173c34adc5Sramat for (i = 0; i < N_VHCI_CLASSES; i++) { 71183c34adc5Sramat if (strcmp(vhci_class_list[i], vh->vh_class) == 0) { 71193c34adc5Sramat nvl = vhcache_nvl[i]; 71203c34adc5Sramat vhcache_nvl[i] = NULL; 71213c34adc5Sramat break; 71223c34adc5Sramat } 71233c34adc5Sramat } 71243c34adc5Sramat 71253c34adc5Sramat /* 71263c34adc5Sramat * this is to cover the case of some one manually causing unloading 71273c34adc5Sramat * (or detaching) and reloading (or attaching) of a vhci driver. 71283c34adc5Sramat */ 71293c34adc5Sramat if (nvl == NULL && modrootloaded) 71303c34adc5Sramat nvl = read_on_disk_vhci_cache(vh->vh_class); 71313c34adc5Sramat 71323c34adc5Sramat if (nvl != NULL) { 71333c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 71343c34adc5Sramat if (mainnvl_to_vhcache(vhcache, nvl) == MDI_SUCCESS) 71353c34adc5Sramat vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE; 71363c34adc5Sramat else { 71373c34adc5Sramat cmn_err(CE_WARN, 71383c34adc5Sramat "%s: data file corrupted, will recreate\n", 71393c34adc5Sramat vhc->vhc_vhcache_filename); 71403c34adc5Sramat } 71413c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 71423c34adc5Sramat nvlist_free(nvl); 71433c34adc5Sramat } 71443c34adc5Sramat 71453c34adc5Sramat vhc->vhc_cbid = callb_add(stop_vhcache_flush_thread, vhc, 71463c34adc5Sramat CB_CL_UADMIN_PRE_VFS, "mdi_vhcache_flush"); 714767e56d35Sramat 714867e56d35Sramat vhc->vhc_path_discovery_boot = mdi_path_discovery_boot; 714967e56d35Sramat vhc->vhc_path_discovery_postboot = mdi_path_discovery_postboot; 71503c34adc5Sramat } 71513c34adc5Sramat 71523c34adc5Sramat /* 71533c34adc5Sramat * free all vhci cache related resources 71543c34adc5Sramat */ 71553c34adc5Sramat static int 71563c34adc5Sramat destroy_vhci_cache(mdi_vhci_t *vh) 71573c34adc5Sramat { 71583c34adc5Sramat mdi_vhci_config_t *vhc = vh->vh_config; 71593c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 71603c34adc5Sramat mdi_vhcache_phci_t *cphci, *cphci_next; 71613c34adc5Sramat mdi_vhcache_client_t *cct, *cct_next; 71623c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_next; 71633c34adc5Sramat 71643c34adc5Sramat if (stop_vhcache_async_threads(vhc) != MDI_SUCCESS) 71653c34adc5Sramat return (MDI_FAILURE); 71663c34adc5Sramat 71673c34adc5Sramat kmem_free(vhc->vhc_vhcache_filename, 71683c34adc5Sramat strlen(vhc->vhc_vhcache_filename) + 1); 71693c34adc5Sramat 71703c34adc5Sramat mod_hash_destroy_strhash(vhcache->vhcache_client_hash); 71713c34adc5Sramat 71723c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 71733c34adc5Sramat cphci = cphci_next) { 71743c34adc5Sramat cphci_next = cphci->cphci_next; 71753c34adc5Sramat free_vhcache_phci(cphci); 71763c34adc5Sramat } 71773c34adc5Sramat 71783c34adc5Sramat for (cct = vhcache->vhcache_client_head; cct != NULL; cct = cct_next) { 71793c34adc5Sramat cct_next = cct->cct_next; 71803c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi_next) { 71813c34adc5Sramat cpi_next = cpi->cpi_next; 71823c34adc5Sramat free_vhcache_pathinfo(cpi); 71833c34adc5Sramat } 71843c34adc5Sramat free_vhcache_client(cct); 71853c34adc5Sramat } 71863c34adc5Sramat 71873c34adc5Sramat rw_destroy(&vhcache->vhcache_lock); 71883c34adc5Sramat 71893c34adc5Sramat mutex_destroy(&vhc->vhc_lock); 71903c34adc5Sramat cv_destroy(&vhc->vhc_cv); 71913c34adc5Sramat kmem_free(vhc, sizeof (mdi_vhci_config_t)); 71923c34adc5Sramat return (MDI_SUCCESS); 71933c34adc5Sramat } 71943c34adc5Sramat 71953c34adc5Sramat /* 71963c34adc5Sramat * Stop all vhci cache related async threads and free their resources. 71973c34adc5Sramat */ 71983c34adc5Sramat static int 71993c34adc5Sramat stop_vhcache_async_threads(mdi_vhci_config_t *vhc) 72003c34adc5Sramat { 72013c34adc5Sramat mdi_async_client_config_t *acc, *acc_next; 72023c34adc5Sramat 72033c34adc5Sramat mutex_enter(&vhc->vhc_lock); 72043c34adc5Sramat vhc->vhc_flags |= MDI_VHC_EXIT; 72053c34adc5Sramat ASSERT(vhc->vhc_acc_thrcount >= 0); 72063c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 72073c34adc5Sramat 72083c34adc5Sramat while ((vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) || 72093c34adc5Sramat vhc->vhc_acc_thrcount != 0) { 72103c34adc5Sramat mutex_exit(&vhc->vhc_lock); 72113c34adc5Sramat delay(1); 72123c34adc5Sramat mutex_enter(&vhc->vhc_lock); 72133c34adc5Sramat } 72143c34adc5Sramat 72153c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_EXIT; 72163c34adc5Sramat 72173c34adc5Sramat for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc_next) { 72183c34adc5Sramat acc_next = acc->acc_next; 72193c34adc5Sramat free_async_client_config(acc); 72203c34adc5Sramat } 72213c34adc5Sramat vhc->vhc_acc_list_head = NULL; 72223c34adc5Sramat vhc->vhc_acc_list_tail = NULL; 72233c34adc5Sramat vhc->vhc_acc_count = 0; 72243c34adc5Sramat 72253c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) { 72263c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 72273c34adc5Sramat mutex_exit(&vhc->vhc_lock); 72283c34adc5Sramat if (flush_vhcache(vhc, 0) != MDI_SUCCESS) { 72293c34adc5Sramat vhcache_dirty(vhc); 72303c34adc5Sramat return (MDI_FAILURE); 72313c34adc5Sramat } 72323c34adc5Sramat } else 72333c34adc5Sramat mutex_exit(&vhc->vhc_lock); 72343c34adc5Sramat 72353c34adc5Sramat if (callb_delete(vhc->vhc_cbid) != 0) 72363c34adc5Sramat return (MDI_FAILURE); 72373c34adc5Sramat 72383c34adc5Sramat return (MDI_SUCCESS); 72393c34adc5Sramat } 72403c34adc5Sramat 72413c34adc5Sramat /* 72423c34adc5Sramat * Stop vhci cache flush thread 72433c34adc5Sramat */ 72443c34adc5Sramat /* ARGSUSED */ 72453c34adc5Sramat static boolean_t 72463c34adc5Sramat stop_vhcache_flush_thread(void *arg, int code) 72473c34adc5Sramat { 72483c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 72493c34adc5Sramat 72503c34adc5Sramat mutex_enter(&vhc->vhc_lock); 72513c34adc5Sramat vhc->vhc_flags |= MDI_VHC_EXIT; 72523c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 72533c34adc5Sramat 72543c34adc5Sramat while (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) { 72553c34adc5Sramat mutex_exit(&vhc->vhc_lock); 72563c34adc5Sramat delay(1); 72573c34adc5Sramat mutex_enter(&vhc->vhc_lock); 72583c34adc5Sramat } 72593c34adc5Sramat 72603c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) { 72613c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 72623c34adc5Sramat mutex_exit(&vhc->vhc_lock); 72633c34adc5Sramat (void) flush_vhcache(vhc, 1); 72643c34adc5Sramat } else 72653c34adc5Sramat mutex_exit(&vhc->vhc_lock); 72663c34adc5Sramat 72673c34adc5Sramat return (B_TRUE); 72683c34adc5Sramat } 72693c34adc5Sramat 72703c34adc5Sramat /* 72713c34adc5Sramat * Enqueue the vhcache phci (cphci) at the tail of the list 72723c34adc5Sramat */ 72733c34adc5Sramat static void 72743c34adc5Sramat enqueue_vhcache_phci(mdi_vhci_cache_t *vhcache, mdi_vhcache_phci_t *cphci) 72753c34adc5Sramat { 72763c34adc5Sramat cphci->cphci_next = NULL; 72773c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) 72783c34adc5Sramat vhcache->vhcache_phci_head = cphci; 72793c34adc5Sramat else 72803c34adc5Sramat vhcache->vhcache_phci_tail->cphci_next = cphci; 72813c34adc5Sramat vhcache->vhcache_phci_tail = cphci; 72823c34adc5Sramat } 72833c34adc5Sramat 72843c34adc5Sramat /* 72853c34adc5Sramat * Enqueue the vhcache pathinfo (cpi) at the tail of the list 72863c34adc5Sramat */ 72873c34adc5Sramat static void 72883c34adc5Sramat enqueue_tail_vhcache_pathinfo(mdi_vhcache_client_t *cct, 72893c34adc5Sramat mdi_vhcache_pathinfo_t *cpi) 72903c34adc5Sramat { 72913c34adc5Sramat cpi->cpi_next = NULL; 72923c34adc5Sramat if (cct->cct_cpi_head == NULL) 72933c34adc5Sramat cct->cct_cpi_head = cpi; 72943c34adc5Sramat else 72953c34adc5Sramat cct->cct_cpi_tail->cpi_next = cpi; 72963c34adc5Sramat cct->cct_cpi_tail = cpi; 72973c34adc5Sramat } 72983c34adc5Sramat 72993c34adc5Sramat /* 73003c34adc5Sramat * Enqueue the vhcache pathinfo (cpi) at the correct location in the 73013c34adc5Sramat * ordered list. All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST 73023c34adc5Sramat * flag set come at the beginning of the list. All cpis which have this 73033c34adc5Sramat * flag set come at the end of the list. 73043c34adc5Sramat */ 73053c34adc5Sramat static void 73063c34adc5Sramat enqueue_vhcache_pathinfo(mdi_vhcache_client_t *cct, 73073c34adc5Sramat mdi_vhcache_pathinfo_t *newcpi) 73083c34adc5Sramat { 73093c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *prev_cpi; 73103c34adc5Sramat 73113c34adc5Sramat if (cct->cct_cpi_head == NULL || 73123c34adc5Sramat (newcpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST)) 73133c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, newcpi); 73143c34adc5Sramat else { 73153c34adc5Sramat for (cpi = cct->cct_cpi_head, prev_cpi = NULL; cpi != NULL && 73163c34adc5Sramat !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST); 73173c34adc5Sramat prev_cpi = cpi, cpi = cpi->cpi_next) 73183c34adc5Sramat ; 73193c34adc5Sramat 73203c34adc5Sramat if (prev_cpi == NULL) 73213c34adc5Sramat cct->cct_cpi_head = newcpi; 73223c34adc5Sramat else 73233c34adc5Sramat prev_cpi->cpi_next = newcpi; 73243c34adc5Sramat 73253c34adc5Sramat newcpi->cpi_next = cpi; 73263c34adc5Sramat 73273c34adc5Sramat if (cpi == NULL) 73283c34adc5Sramat cct->cct_cpi_tail = newcpi; 73293c34adc5Sramat } 73303c34adc5Sramat } 73313c34adc5Sramat 73323c34adc5Sramat /* 73333c34adc5Sramat * Enqueue the vhcache client (cct) at the tail of the list 73343c34adc5Sramat */ 73353c34adc5Sramat static void 73363c34adc5Sramat enqueue_vhcache_client(mdi_vhci_cache_t *vhcache, 73373c34adc5Sramat mdi_vhcache_client_t *cct) 73383c34adc5Sramat { 73393c34adc5Sramat cct->cct_next = NULL; 73403c34adc5Sramat if (vhcache->vhcache_client_head == NULL) 73413c34adc5Sramat vhcache->vhcache_client_head = cct; 73423c34adc5Sramat else 73433c34adc5Sramat vhcache->vhcache_client_tail->cct_next = cct; 73443c34adc5Sramat vhcache->vhcache_client_tail = cct; 73453c34adc5Sramat } 73463c34adc5Sramat 73473c34adc5Sramat static void 73483c34adc5Sramat free_string_array(char **str, int nelem) 73493c34adc5Sramat { 73503c34adc5Sramat int i; 73513c34adc5Sramat 73523c34adc5Sramat if (str) { 73533c34adc5Sramat for (i = 0; i < nelem; i++) { 73543c34adc5Sramat if (str[i]) 73553c34adc5Sramat kmem_free(str[i], strlen(str[i]) + 1); 73563c34adc5Sramat } 73573c34adc5Sramat kmem_free(str, sizeof (char *) * nelem); 73583c34adc5Sramat } 73593c34adc5Sramat } 73603c34adc5Sramat 73613c34adc5Sramat static void 73623c34adc5Sramat free_vhcache_phci(mdi_vhcache_phci_t *cphci) 73633c34adc5Sramat { 73643c34adc5Sramat kmem_free(cphci->cphci_path, strlen(cphci->cphci_path) + 1); 73653c34adc5Sramat kmem_free(cphci, sizeof (*cphci)); 73663c34adc5Sramat } 73673c34adc5Sramat 73683c34adc5Sramat static void 73693c34adc5Sramat free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *cpi) 73703c34adc5Sramat { 73713c34adc5Sramat kmem_free(cpi->cpi_addr, strlen(cpi->cpi_addr) + 1); 73723c34adc5Sramat kmem_free(cpi, sizeof (*cpi)); 73733c34adc5Sramat } 73743c34adc5Sramat 73753c34adc5Sramat static void 73763c34adc5Sramat free_vhcache_client(mdi_vhcache_client_t *cct) 73773c34adc5Sramat { 73783c34adc5Sramat kmem_free(cct->cct_name_addr, strlen(cct->cct_name_addr) + 1); 73793c34adc5Sramat kmem_free(cct, sizeof (*cct)); 73803c34adc5Sramat } 73813c34adc5Sramat 73823c34adc5Sramat static char * 73833c34adc5Sramat vhcache_mknameaddr(char *ct_name, char *ct_addr, int *ret_len) 73843c34adc5Sramat { 73853c34adc5Sramat char *name_addr; 73863c34adc5Sramat int len; 73873c34adc5Sramat 73883c34adc5Sramat len = strlen(ct_name) + strlen(ct_addr) + 2; 73893c34adc5Sramat name_addr = kmem_alloc(len, KM_SLEEP); 73903c34adc5Sramat (void) snprintf(name_addr, len, "%s@%s", ct_name, ct_addr); 73913c34adc5Sramat 73923c34adc5Sramat if (ret_len) 73933c34adc5Sramat *ret_len = len; 73943c34adc5Sramat return (name_addr); 73953c34adc5Sramat } 73963c34adc5Sramat 73973c34adc5Sramat /* 73983c34adc5Sramat * Copy the contents of paddrnvl to vhci cache. 73993c34adc5Sramat * paddrnvl nvlist contains path information for a vhci client. 74003c34adc5Sramat * See the comment in mainnvl_to_vhcache() for the format of this nvlist. 74013c34adc5Sramat */ 74023c34adc5Sramat static void 74033c34adc5Sramat paddrnvl_to_vhcache(nvlist_t *nvl, mdi_vhcache_phci_t *cphci_list[], 74043c34adc5Sramat mdi_vhcache_client_t *cct) 74053c34adc5Sramat { 74063c34adc5Sramat nvpair_t *nvp = NULL; 74073c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 74083c34adc5Sramat uint_t nelem; 74093c34adc5Sramat uint32_t *val; 74103c34adc5Sramat 74113c34adc5Sramat while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 74123c34adc5Sramat ASSERT(nvpair_type(nvp) == DATA_TYPE_UINT32_ARRAY); 74133c34adc5Sramat cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP); 74143c34adc5Sramat cpi->cpi_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP); 74153c34adc5Sramat (void) nvpair_value_uint32_array(nvp, &val, &nelem); 74163c34adc5Sramat ASSERT(nelem == 2); 74173c34adc5Sramat cpi->cpi_cphci = cphci_list[val[0]]; 74183c34adc5Sramat cpi->cpi_flags = val[1]; 74193c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, cpi); 74203c34adc5Sramat } 74213c34adc5Sramat } 74223c34adc5Sramat 74233c34adc5Sramat /* 74243c34adc5Sramat * Copy the contents of caddrmapnvl to vhci cache. 74253c34adc5Sramat * caddrmapnvl nvlist contains vhci client address to phci client address 74263c34adc5Sramat * mappings. See the comment in mainnvl_to_vhcache() for the format of 74273c34adc5Sramat * this nvlist. 74283c34adc5Sramat */ 74293c34adc5Sramat static void 74303c34adc5Sramat caddrmapnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl, 74313c34adc5Sramat mdi_vhcache_phci_t *cphci_list[]) 74323c34adc5Sramat { 74333c34adc5Sramat nvpair_t *nvp = NULL; 74343c34adc5Sramat nvlist_t *paddrnvl; 74353c34adc5Sramat mdi_vhcache_client_t *cct; 74363c34adc5Sramat 74373c34adc5Sramat while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 74383c34adc5Sramat ASSERT(nvpair_type(nvp) == DATA_TYPE_NVLIST); 74393c34adc5Sramat cct = kmem_zalloc(sizeof (*cct), KM_SLEEP); 74403c34adc5Sramat cct->cct_name_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP); 74413c34adc5Sramat (void) nvpair_value_nvlist(nvp, &paddrnvl); 74423c34adc5Sramat paddrnvl_to_vhcache(paddrnvl, cphci_list, cct); 74433c34adc5Sramat /* the client must contain at least one path */ 74443c34adc5Sramat ASSERT(cct->cct_cpi_head != NULL); 74453c34adc5Sramat 74463c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 74473c34adc5Sramat (void) mod_hash_insert(vhcache->vhcache_client_hash, 74483c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct); 74493c34adc5Sramat } 74503c34adc5Sramat } 74513c34adc5Sramat 74523c34adc5Sramat /* 74533c34adc5Sramat * Copy the contents of the main nvlist to vhci cache. 74543c34adc5Sramat * 74553c34adc5Sramat * VHCI busconfig cached data is stored in the form of a nvlist on the disk. 74563c34adc5Sramat * The nvlist contains the mappings between the vhci client addresses and 74573c34adc5Sramat * their corresponding phci client addresses. 74583c34adc5Sramat * 74593c34adc5Sramat * The structure of the nvlist is as follows: 74603c34adc5Sramat * 74613c34adc5Sramat * Main nvlist: 74623c34adc5Sramat * NAME TYPE DATA 74633c34adc5Sramat * version int32 version number 74643c34adc5Sramat * phcis string array array of phci paths 74653c34adc5Sramat * clientaddrmap nvlist_t c2paddrs_nvl (see below) 74663c34adc5Sramat * 74673c34adc5Sramat * structure of c2paddrs_nvl: 74683c34adc5Sramat * NAME TYPE DATA 74693c34adc5Sramat * caddr1 nvlist_t paddrs_nvl1 74703c34adc5Sramat * caddr2 nvlist_t paddrs_nvl2 74713c34adc5Sramat * ... 74723c34adc5Sramat * where caddr1, caddr2, ... are vhci client name and addresses in the 74733c34adc5Sramat * form of "<clientname>@<clientaddress>". 74743c34adc5Sramat * (for example: "ssd@2000002037cd9f72"); 74753c34adc5Sramat * paddrs_nvl1, paddrs_nvl2, .. are nvlists that contain path information. 74763c34adc5Sramat * 74773c34adc5Sramat * structure of paddrs_nvl: 74783c34adc5Sramat * NAME TYPE DATA 74793c34adc5Sramat * pi_addr1 uint32_array (phci-id, cpi_flags) 74803c34adc5Sramat * pi_addr2 uint32_array (phci-id, cpi_flags) 74813c34adc5Sramat * ... 74823c34adc5Sramat * where pi_addr1, pi_addr2, ... are bus specific addresses of pathinfo nodes 74833c34adc5Sramat * (so called pi_addrs, for example: "w2100002037cd9f72,0"); 74843c34adc5Sramat * phci-ids are integers that identify PHCIs to which the 74853c34adc5Sramat * the bus specific address belongs to. These integers are used as an index 74863c34adc5Sramat * into to the phcis string array in the main nvlist to get the PHCI path. 74873c34adc5Sramat */ 74883c34adc5Sramat static int 74893c34adc5Sramat mainnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl) 74903c34adc5Sramat { 74913c34adc5Sramat char **phcis, **phci_namep; 74923c34adc5Sramat uint_t nphcis; 74933c34adc5Sramat mdi_vhcache_phci_t *cphci, **cphci_list; 74943c34adc5Sramat nvlist_t *caddrmapnvl; 74953c34adc5Sramat int32_t ver; 74963c34adc5Sramat int i; 74973c34adc5Sramat size_t cphci_list_size; 74983c34adc5Sramat 74993c34adc5Sramat ASSERT(RW_WRITE_HELD(&vhcache->vhcache_lock)); 75003c34adc5Sramat 75013c34adc5Sramat if (nvlist_lookup_int32(nvl, MDI_NVPNAME_VERSION, &ver) != 0 || 75023c34adc5Sramat ver != MDI_VHCI_CACHE_VERSION) 75033c34adc5Sramat return (MDI_FAILURE); 75043c34adc5Sramat 75053c34adc5Sramat if (nvlist_lookup_string_array(nvl, MDI_NVPNAME_PHCIS, &phcis, 75063c34adc5Sramat &nphcis) != 0) 75073c34adc5Sramat return (MDI_SUCCESS); 75083c34adc5Sramat 75093c34adc5Sramat ASSERT(nphcis > 0); 75103c34adc5Sramat 75113c34adc5Sramat cphci_list_size = sizeof (mdi_vhcache_phci_t *) * nphcis; 75123c34adc5Sramat cphci_list = kmem_alloc(cphci_list_size, KM_SLEEP); 75133c34adc5Sramat for (i = 0, phci_namep = phcis; i < nphcis; i++, phci_namep++) { 75143c34adc5Sramat cphci = kmem_zalloc(sizeof (mdi_vhcache_phci_t), KM_SLEEP); 75153c34adc5Sramat cphci->cphci_path = i_ddi_strdup(*phci_namep, KM_SLEEP); 75163c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 75173c34adc5Sramat cphci_list[i] = cphci; 75183c34adc5Sramat } 75193c34adc5Sramat 75203c34adc5Sramat ASSERT(vhcache->vhcache_phci_head != NULL); 75213c34adc5Sramat 75223c34adc5Sramat if (nvlist_lookup_nvlist(nvl, MDI_NVPNAME_CTADDRMAP, &caddrmapnvl) == 0) 75233c34adc5Sramat caddrmapnvl_to_vhcache(vhcache, caddrmapnvl, cphci_list); 75243c34adc5Sramat 75253c34adc5Sramat kmem_free(cphci_list, cphci_list_size); 75263c34adc5Sramat return (MDI_SUCCESS); 75273c34adc5Sramat } 75283c34adc5Sramat 75293c34adc5Sramat /* 75303c34adc5Sramat * Build paddrnvl for the specified client using the information in the 75313c34adc5Sramat * vhci cache and add it to the caddrmapnnvl. 75323c34adc5Sramat * Returns 0 on success, errno on failure. 75333c34adc5Sramat */ 75343c34adc5Sramat static int 75353c34adc5Sramat vhcache_to_paddrnvl(mdi_vhci_cache_t *vhcache, mdi_vhcache_client_t *cct, 75363c34adc5Sramat nvlist_t *caddrmapnvl) 75373c34adc5Sramat { 75383c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 75393c34adc5Sramat nvlist_t *nvl; 75403c34adc5Sramat int err; 75413c34adc5Sramat uint32_t val[2]; 75423c34adc5Sramat 75433c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 75443c34adc5Sramat 75453c34adc5Sramat if ((err = nvlist_alloc(&nvl, 0, KM_SLEEP)) != 0) 75463c34adc5Sramat return (err); 75473c34adc5Sramat 75483c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 75493c34adc5Sramat val[0] = cpi->cpi_cphci->cphci_id; 75503c34adc5Sramat val[1] = cpi->cpi_flags; 75513c34adc5Sramat if ((err = nvlist_add_uint32_array(nvl, cpi->cpi_addr, val, 2)) 75523c34adc5Sramat != 0) 75533c34adc5Sramat goto out; 75543c34adc5Sramat } 75553c34adc5Sramat 75563c34adc5Sramat err = nvlist_add_nvlist(caddrmapnvl, cct->cct_name_addr, nvl); 75573c34adc5Sramat out: 75583c34adc5Sramat nvlist_free(nvl); 75593c34adc5Sramat return (err); 75603c34adc5Sramat } 75613c34adc5Sramat 75623c34adc5Sramat /* 75633c34adc5Sramat * Build caddrmapnvl using the information in the vhci cache 75643c34adc5Sramat * and add it to the mainnvl. 75653c34adc5Sramat * Returns 0 on success, errno on failure. 75663c34adc5Sramat */ 75673c34adc5Sramat static int 75683c34adc5Sramat vhcache_to_caddrmapnvl(mdi_vhci_cache_t *vhcache, nvlist_t *mainnvl) 75693c34adc5Sramat { 75703c34adc5Sramat mdi_vhcache_client_t *cct; 75713c34adc5Sramat nvlist_t *nvl; 75723c34adc5Sramat int err; 75733c34adc5Sramat 75743c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 75753c34adc5Sramat 75763c34adc5Sramat if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0) 75773c34adc5Sramat return (err); 75783c34adc5Sramat 75793c34adc5Sramat for (cct = vhcache->vhcache_client_head; cct != NULL; 75803c34adc5Sramat cct = cct->cct_next) { 75813c34adc5Sramat if ((err = vhcache_to_paddrnvl(vhcache, cct, nvl)) != 0) 75823c34adc5Sramat goto out; 75833c34adc5Sramat } 75843c34adc5Sramat 75853c34adc5Sramat err = nvlist_add_nvlist(mainnvl, MDI_NVPNAME_CTADDRMAP, nvl); 75863c34adc5Sramat out: 75873c34adc5Sramat nvlist_free(nvl); 75883c34adc5Sramat return (err); 75893c34adc5Sramat } 75903c34adc5Sramat 75913c34adc5Sramat /* 75923c34adc5Sramat * Build nvlist using the information in the vhci cache. 75933c34adc5Sramat * See the comment in mainnvl_to_vhcache() for the format of the nvlist. 75943c34adc5Sramat * Returns nvl on success, NULL on failure. 75953c34adc5Sramat */ 75963c34adc5Sramat static nvlist_t * 75973c34adc5Sramat vhcache_to_mainnvl(mdi_vhci_cache_t *vhcache) 75983c34adc5Sramat { 75993c34adc5Sramat mdi_vhcache_phci_t *cphci; 76003c34adc5Sramat uint_t phci_count; 76013c34adc5Sramat char **phcis; 76023c34adc5Sramat nvlist_t *nvl; 76033c34adc5Sramat int err, i; 76043c34adc5Sramat 76053c34adc5Sramat if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0) { 76063c34adc5Sramat nvl = NULL; 76073c34adc5Sramat goto out; 76083c34adc5Sramat } 76093c34adc5Sramat 76103c34adc5Sramat if ((err = nvlist_add_int32(nvl, MDI_NVPNAME_VERSION, 76113c34adc5Sramat MDI_VHCI_CACHE_VERSION)) != 0) 76123c34adc5Sramat goto out; 76133c34adc5Sramat 76143c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 76153c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) { 76163c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 76173c34adc5Sramat return (nvl); 76183c34adc5Sramat } 76193c34adc5Sramat 76203c34adc5Sramat phci_count = 0; 76213c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 76223c34adc5Sramat cphci = cphci->cphci_next) 76233c34adc5Sramat cphci->cphci_id = phci_count++; 76243c34adc5Sramat 76253c34adc5Sramat /* build phci pathname list */ 76263c34adc5Sramat phcis = kmem_alloc(sizeof (char *) * phci_count, KM_SLEEP); 76273c34adc5Sramat for (cphci = vhcache->vhcache_phci_head, i = 0; cphci != NULL; 76283c34adc5Sramat cphci = cphci->cphci_next, i++) 76293c34adc5Sramat phcis[i] = i_ddi_strdup(cphci->cphci_path, KM_SLEEP); 76303c34adc5Sramat 76313c34adc5Sramat err = nvlist_add_string_array(nvl, MDI_NVPNAME_PHCIS, phcis, 76323c34adc5Sramat phci_count); 76333c34adc5Sramat free_string_array(phcis, phci_count); 76343c34adc5Sramat 76353c34adc5Sramat if (err == 0 && 76363c34adc5Sramat (err = vhcache_to_caddrmapnvl(vhcache, nvl)) == 0) { 76373c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 76383c34adc5Sramat return (nvl); 76393c34adc5Sramat } 76403c34adc5Sramat 76413c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 76423c34adc5Sramat out: 76433c34adc5Sramat if (nvl) 76443c34adc5Sramat nvlist_free(nvl); 76453c34adc5Sramat return (NULL); 76463c34adc5Sramat } 76473c34adc5Sramat 76483c34adc5Sramat /* 76493c34adc5Sramat * Lookup vhcache phci structure for the specified phci path. 76503c34adc5Sramat */ 76513c34adc5Sramat static mdi_vhcache_phci_t * 76523c34adc5Sramat lookup_vhcache_phci_by_name(mdi_vhci_cache_t *vhcache, char *phci_path) 76533c34adc5Sramat { 76543c34adc5Sramat mdi_vhcache_phci_t *cphci; 76553c34adc5Sramat 76563c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 76573c34adc5Sramat 76583c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 76593c34adc5Sramat cphci = cphci->cphci_next) { 76603c34adc5Sramat if (strcmp(cphci->cphci_path, phci_path) == 0) 76613c34adc5Sramat return (cphci); 76623c34adc5Sramat } 76633c34adc5Sramat 76643c34adc5Sramat return (NULL); 76653c34adc5Sramat } 76663c34adc5Sramat 76673c34adc5Sramat /* 76683c34adc5Sramat * Lookup vhcache phci structure for the specified phci. 76693c34adc5Sramat */ 76703c34adc5Sramat static mdi_vhcache_phci_t * 76713c34adc5Sramat lookup_vhcache_phci_by_addr(mdi_vhci_cache_t *vhcache, mdi_phci_t *ph) 76723c34adc5Sramat { 76733c34adc5Sramat mdi_vhcache_phci_t *cphci; 76743c34adc5Sramat 76753c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 76763c34adc5Sramat 76773c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 76783c34adc5Sramat cphci = cphci->cphci_next) { 76793c34adc5Sramat if (cphci->cphci_phci == ph) 76803c34adc5Sramat return (cphci); 76813c34adc5Sramat } 76823c34adc5Sramat 76833c34adc5Sramat return (NULL); 76843c34adc5Sramat } 76853c34adc5Sramat 76863c34adc5Sramat /* 76873c34adc5Sramat * Add the specified phci to the vhci cache if not already present. 76883c34adc5Sramat */ 76893c34adc5Sramat static void 76903c34adc5Sramat vhcache_phci_add(mdi_vhci_config_t *vhc, mdi_phci_t *ph) 76913c34adc5Sramat { 76923c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 76933c34adc5Sramat mdi_vhcache_phci_t *cphci; 76943c34adc5Sramat char *pathname; 76953c34adc5Sramat int cache_updated; 76963c34adc5Sramat 76973c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 76983c34adc5Sramat 76993c34adc5Sramat pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 77003c34adc5Sramat (void) ddi_pathname(ph->ph_dip, pathname); 77013c34adc5Sramat if ((cphci = lookup_vhcache_phci_by_name(vhcache, pathname)) 77023c34adc5Sramat != NULL) { 77033c34adc5Sramat cphci->cphci_phci = ph; 77043c34adc5Sramat cache_updated = 0; 77053c34adc5Sramat } else { 77063c34adc5Sramat cphci = kmem_zalloc(sizeof (*cphci), KM_SLEEP); 77073c34adc5Sramat cphci->cphci_path = i_ddi_strdup(pathname, KM_SLEEP); 77083c34adc5Sramat cphci->cphci_phci = ph; 77093c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 77103c34adc5Sramat cache_updated = 1; 77113c34adc5Sramat } 771267e56d35Sramat 77133c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 77143c34adc5Sramat 771567e56d35Sramat /* 771667e56d35Sramat * Since a new phci has been added, reset 771767e56d35Sramat * vhc_path_discovery_cutoff_time to allow for discovery of paths 771867e56d35Sramat * during next vhcache_discover_paths(). 771967e56d35Sramat */ 772067e56d35Sramat mutex_enter(&vhc->vhc_lock); 772167e56d35Sramat vhc->vhc_path_discovery_cutoff_time = 0; 772267e56d35Sramat mutex_exit(&vhc->vhc_lock); 772367e56d35Sramat 77243c34adc5Sramat kmem_free(pathname, MAXPATHLEN); 77253c34adc5Sramat if (cache_updated) 77263c34adc5Sramat vhcache_dirty(vhc); 77273c34adc5Sramat } 77283c34adc5Sramat 77293c34adc5Sramat /* 77303c34adc5Sramat * Remove the reference to the specified phci from the vhci cache. 77313c34adc5Sramat */ 77323c34adc5Sramat static void 77333c34adc5Sramat vhcache_phci_remove(mdi_vhci_config_t *vhc, mdi_phci_t *ph) 77343c34adc5Sramat { 77353c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 77363c34adc5Sramat mdi_vhcache_phci_t *cphci; 77373c34adc5Sramat 77383c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 77393c34adc5Sramat if ((cphci = lookup_vhcache_phci_by_addr(vhcache, ph)) != NULL) { 77403c34adc5Sramat /* do not remove the actual mdi_vhcache_phci structure */ 77413c34adc5Sramat cphci->cphci_phci = NULL; 77423c34adc5Sramat } 77433c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 77443c34adc5Sramat } 77453c34adc5Sramat 77463c34adc5Sramat static void 77473c34adc5Sramat init_vhcache_lookup_token(mdi_vhcache_lookup_token_t *dst, 77483c34adc5Sramat mdi_vhcache_lookup_token_t *src) 77493c34adc5Sramat { 77503c34adc5Sramat if (src == NULL) { 77513c34adc5Sramat dst->lt_cct = NULL; 77523c34adc5Sramat dst->lt_cct_lookup_time = 0; 77533c34adc5Sramat } else { 77543c34adc5Sramat dst->lt_cct = src->lt_cct; 77553c34adc5Sramat dst->lt_cct_lookup_time = src->lt_cct_lookup_time; 77563c34adc5Sramat } 77573c34adc5Sramat } 77583c34adc5Sramat 77593c34adc5Sramat /* 77603c34adc5Sramat * Look up vhcache client for the specified client. 77613c34adc5Sramat */ 77623c34adc5Sramat static mdi_vhcache_client_t * 77633c34adc5Sramat lookup_vhcache_client(mdi_vhci_cache_t *vhcache, char *ct_name, char *ct_addr, 77643c34adc5Sramat mdi_vhcache_lookup_token_t *token) 77653c34adc5Sramat { 77663c34adc5Sramat mod_hash_val_t hv; 77673c34adc5Sramat char *name_addr; 77683c34adc5Sramat int len; 77693c34adc5Sramat 77703c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 77713c34adc5Sramat 77723c34adc5Sramat /* 77733c34adc5Sramat * If no vhcache clean occurred since the last lookup, we can 77743c34adc5Sramat * simply return the cct from the last lookup operation. 77753c34adc5Sramat * It works because ccts are never freed except during the vhcache 77763c34adc5Sramat * cleanup operation. 77773c34adc5Sramat */ 77783c34adc5Sramat if (token != NULL && 77793c34adc5Sramat vhcache->vhcache_clean_time < token->lt_cct_lookup_time) 77803c34adc5Sramat return (token->lt_cct); 77813c34adc5Sramat 77823c34adc5Sramat name_addr = vhcache_mknameaddr(ct_name, ct_addr, &len); 77833c34adc5Sramat if (mod_hash_find(vhcache->vhcache_client_hash, 77843c34adc5Sramat (mod_hash_key_t)name_addr, &hv) == 0) { 77853c34adc5Sramat if (token) { 77863c34adc5Sramat token->lt_cct = (mdi_vhcache_client_t *)hv; 77873c34adc5Sramat token->lt_cct_lookup_time = lbolt64; 77883c34adc5Sramat } 77893c34adc5Sramat } else { 77903c34adc5Sramat if (token) { 77913c34adc5Sramat token->lt_cct = NULL; 77923c34adc5Sramat token->lt_cct_lookup_time = 0; 77933c34adc5Sramat } 77943c34adc5Sramat hv = NULL; 77953c34adc5Sramat } 77963c34adc5Sramat kmem_free(name_addr, len); 77973c34adc5Sramat return ((mdi_vhcache_client_t *)hv); 77983c34adc5Sramat } 77993c34adc5Sramat 78003c34adc5Sramat /* 78013c34adc5Sramat * Add the specified path to the vhci cache if not already present. 78023c34adc5Sramat * Also add the vhcache client for the client corresponding to this path 78033c34adc5Sramat * if it doesn't already exist. 78043c34adc5Sramat */ 78053c34adc5Sramat static void 78063c34adc5Sramat vhcache_pi_add(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip) 78073c34adc5Sramat { 78083c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 78093c34adc5Sramat mdi_vhcache_client_t *cct; 78103c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 78113c34adc5Sramat mdi_phci_t *ph = pip->pi_phci; 78123c34adc5Sramat mdi_client_t *ct = pip->pi_client; 78133c34adc5Sramat int cache_updated = 0; 78143c34adc5Sramat 78153c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 78163c34adc5Sramat 78173c34adc5Sramat /* if vhcache client for this pip doesn't already exist, add it */ 78183c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid, 78193c34adc5Sramat NULL)) == NULL) { 78203c34adc5Sramat cct = kmem_zalloc(sizeof (*cct), KM_SLEEP); 78213c34adc5Sramat cct->cct_name_addr = vhcache_mknameaddr(ct->ct_drvname, 78223c34adc5Sramat ct->ct_guid, NULL); 78233c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 78243c34adc5Sramat (void) mod_hash_insert(vhcache->vhcache_client_hash, 78253c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct); 78263c34adc5Sramat cache_updated = 1; 78273c34adc5Sramat } 78283c34adc5Sramat 78293c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 78303c34adc5Sramat if (cpi->cpi_cphci->cphci_phci == ph && 78313c34adc5Sramat strcmp(cpi->cpi_addr, pip->pi_addr) == 0) { 78323c34adc5Sramat cpi->cpi_pip = pip; 78333c34adc5Sramat if (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST) { 78343c34adc5Sramat cpi->cpi_flags &= 78353c34adc5Sramat ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 78363c34adc5Sramat sort_vhcache_paths(cct); 78373c34adc5Sramat cache_updated = 1; 78383c34adc5Sramat } 78393c34adc5Sramat break; 78403c34adc5Sramat } 78413c34adc5Sramat } 78423c34adc5Sramat 78433c34adc5Sramat if (cpi == NULL) { 78443c34adc5Sramat cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP); 78453c34adc5Sramat cpi->cpi_addr = i_ddi_strdup(pip->pi_addr, KM_SLEEP); 78463c34adc5Sramat cpi->cpi_cphci = lookup_vhcache_phci_by_addr(vhcache, ph); 78473c34adc5Sramat ASSERT(cpi->cpi_cphci != NULL); 78483c34adc5Sramat cpi->cpi_pip = pip; 78493c34adc5Sramat enqueue_vhcache_pathinfo(cct, cpi); 78503c34adc5Sramat cache_updated = 1; 78513c34adc5Sramat } 78523c34adc5Sramat 78533c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 78543c34adc5Sramat 78553c34adc5Sramat if (cache_updated) 78563c34adc5Sramat vhcache_dirty(vhc); 78573c34adc5Sramat } 78583c34adc5Sramat 78593c34adc5Sramat /* 78603c34adc5Sramat * Remove the reference to the specified path from the vhci cache. 78613c34adc5Sramat */ 78623c34adc5Sramat static void 78633c34adc5Sramat vhcache_pi_remove(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip) 78643c34adc5Sramat { 78653c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 78663c34adc5Sramat mdi_client_t *ct = pip->pi_client; 78673c34adc5Sramat mdi_vhcache_client_t *cct; 78683c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 78693c34adc5Sramat 78703c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 78713c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid, 78723c34adc5Sramat NULL)) != NULL) { 78733c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; 78743c34adc5Sramat cpi = cpi->cpi_next) { 78753c34adc5Sramat if (cpi->cpi_pip == pip) { 78763c34adc5Sramat cpi->cpi_pip = NULL; 78773c34adc5Sramat break; 78783c34adc5Sramat } 78793c34adc5Sramat } 78803c34adc5Sramat } 78813c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 78823c34adc5Sramat } 78833c34adc5Sramat 78843c34adc5Sramat /* 78853c34adc5Sramat * Flush the vhci cache to disk. 78863c34adc5Sramat * Returns MDI_SUCCESS on success, MDI_FAILURE on failure. 78873c34adc5Sramat */ 78883c34adc5Sramat static int 78893c34adc5Sramat flush_vhcache(mdi_vhci_config_t *vhc, int force_flag) 78903c34adc5Sramat { 78913c34adc5Sramat nvlist_t *nvl; 78923c34adc5Sramat int err; 78933c34adc5Sramat int rv; 78943c34adc5Sramat 78953c34adc5Sramat /* 78963c34adc5Sramat * It is possible that the system may shutdown before 78973c34adc5Sramat * i_ddi_io_initialized (during stmsboot for example). To allow for 78983c34adc5Sramat * flushing the cache in this case do not check for 78993c34adc5Sramat * i_ddi_io_initialized when force flag is set. 79003c34adc5Sramat */ 79013c34adc5Sramat if (force_flag == 0 && !i_ddi_io_initialized()) 79023c34adc5Sramat return (MDI_FAILURE); 79033c34adc5Sramat 79043c34adc5Sramat if ((nvl = vhcache_to_mainnvl(&vhc->vhc_vhcache)) != NULL) { 79053c34adc5Sramat err = fwrite_nvlist(vhc->vhc_vhcache_filename, nvl); 79063c34adc5Sramat nvlist_free(nvl); 79073c34adc5Sramat } else 79083c34adc5Sramat err = EFAULT; 79093c34adc5Sramat 79103c34adc5Sramat rv = MDI_SUCCESS; 79113c34adc5Sramat mutex_enter(&vhc->vhc_lock); 79123c34adc5Sramat if (err != 0) { 79133c34adc5Sramat if (err == EROFS) { 79143c34adc5Sramat vhc->vhc_flags |= MDI_VHC_READONLY_FS; 79153c34adc5Sramat vhc->vhc_flags &= ~(MDI_VHC_VHCACHE_FLUSH_ERROR | 79163c34adc5Sramat MDI_VHC_VHCACHE_DIRTY); 79173c34adc5Sramat } else { 79183c34adc5Sramat if (!(vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR)) { 79193c34adc5Sramat cmn_err(CE_CONT, "%s: update failed\n", 79203c34adc5Sramat vhc->vhc_vhcache_filename); 79213c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_ERROR; 79223c34adc5Sramat } 79233c34adc5Sramat rv = MDI_FAILURE; 79243c34adc5Sramat } 79253c34adc5Sramat } else if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR) { 79263c34adc5Sramat cmn_err(CE_CONT, 79273c34adc5Sramat "%s: update now ok\n", vhc->vhc_vhcache_filename); 79283c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_ERROR; 79293c34adc5Sramat } 79303c34adc5Sramat mutex_exit(&vhc->vhc_lock); 79313c34adc5Sramat 79323c34adc5Sramat return (rv); 79333c34adc5Sramat } 79343c34adc5Sramat 79353c34adc5Sramat /* 79363c34adc5Sramat * Call flush_vhcache() to flush the vhci cache at the scheduled time. 79373c34adc5Sramat * Exits itself if left idle for the idle timeout period. 79383c34adc5Sramat */ 79393c34adc5Sramat static void 79403c34adc5Sramat vhcache_flush_thread(void *arg) 79413c34adc5Sramat { 79423c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 79433c34adc5Sramat clock_t idle_time, quit_at_ticks; 79443c34adc5Sramat callb_cpr_t cprinfo; 79453c34adc5Sramat 79463c34adc5Sramat /* number of seconds to sleep idle before exiting */ 79473c34adc5Sramat idle_time = mdi_vhcache_flush_daemon_idle_time * TICKS_PER_SECOND; 79483c34adc5Sramat 79493c34adc5Sramat CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr, 79503c34adc5Sramat "mdi_vhcache_flush"); 79513c34adc5Sramat mutex_enter(&vhc->vhc_lock); 79523c34adc5Sramat for (; ; ) { 79533c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 79543c34adc5Sramat (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY)) { 79553c34adc5Sramat if (ddi_get_lbolt() < vhc->vhc_flush_at_ticks) { 79563c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 79573c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, 79583c34adc5Sramat &vhc->vhc_lock, vhc->vhc_flush_at_ticks); 79593c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 79603c34adc5Sramat } else { 79613c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 79623c34adc5Sramat mutex_exit(&vhc->vhc_lock); 79633c34adc5Sramat 79643c34adc5Sramat if (flush_vhcache(vhc, 0) != MDI_SUCCESS) 79653c34adc5Sramat vhcache_dirty(vhc); 79663c34adc5Sramat 79673c34adc5Sramat mutex_enter(&vhc->vhc_lock); 79683c34adc5Sramat } 79693c34adc5Sramat } 79703c34adc5Sramat 79713c34adc5Sramat quit_at_ticks = ddi_get_lbolt() + idle_time; 79723c34adc5Sramat 79733c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 79743c34adc5Sramat !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) && 79753c34adc5Sramat ddi_get_lbolt() < quit_at_ticks) { 79763c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 79773c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock, 79783c34adc5Sramat quit_at_ticks); 79793c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 79803c34adc5Sramat } 79813c34adc5Sramat 79823c34adc5Sramat if ((vhc->vhc_flags & MDI_VHC_EXIT) || 79833c34adc5Sramat !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY)) 79843c34adc5Sramat goto out; 79853c34adc5Sramat } 79863c34adc5Sramat 79873c34adc5Sramat out: 79883c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_THREAD; 79893c34adc5Sramat /* CALLB_CPR_EXIT releases the vhc->vhc_lock */ 79903c34adc5Sramat CALLB_CPR_EXIT(&cprinfo); 79913c34adc5Sramat } 79923c34adc5Sramat 79933c34adc5Sramat /* 79943c34adc5Sramat * Make vhci cache dirty and schedule flushing by vhcache flush thread. 79953c34adc5Sramat */ 79963c34adc5Sramat static void 79973c34adc5Sramat vhcache_dirty(mdi_vhci_config_t *vhc) 79983c34adc5Sramat { 79993c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 80003c34adc5Sramat int create_thread; 80013c34adc5Sramat 80023c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 80033c34adc5Sramat /* do not flush cache until the cache is fully built */ 80043c34adc5Sramat if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) { 80053c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 80063c34adc5Sramat return; 80073c34adc5Sramat } 80083c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 80093c34adc5Sramat 80103c34adc5Sramat mutex_enter(&vhc->vhc_lock); 80113c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_READONLY_FS) { 80123c34adc5Sramat mutex_exit(&vhc->vhc_lock); 80133c34adc5Sramat return; 80143c34adc5Sramat } 80153c34adc5Sramat 80163c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_DIRTY; 80173c34adc5Sramat vhc->vhc_flush_at_ticks = ddi_get_lbolt() + 80183c34adc5Sramat mdi_vhcache_flush_delay * TICKS_PER_SECOND; 80193c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) { 80203c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 80213c34adc5Sramat create_thread = 0; 80223c34adc5Sramat } else { 80233c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_THREAD; 80243c34adc5Sramat create_thread = 1; 80253c34adc5Sramat } 80263c34adc5Sramat mutex_exit(&vhc->vhc_lock); 80273c34adc5Sramat 80283c34adc5Sramat if (create_thread) 80293c34adc5Sramat (void) thread_create(NULL, 0, vhcache_flush_thread, vhc, 80303c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 80313c34adc5Sramat } 80323c34adc5Sramat 80333c34adc5Sramat /* 80343c34adc5Sramat * phci bus config structure - one for for each phci bus config operation that 80353c34adc5Sramat * we initiate on behalf of a vhci. 80363c34adc5Sramat */ 80373c34adc5Sramat typedef struct mdi_phci_bus_config_s { 80383c34adc5Sramat char *phbc_phci_path; 80393c34adc5Sramat struct mdi_vhci_bus_config_s *phbc_vhbusconfig; /* vhci bus config */ 80403c34adc5Sramat struct mdi_phci_bus_config_s *phbc_next; 80413c34adc5Sramat } mdi_phci_bus_config_t; 80423c34adc5Sramat 80433c34adc5Sramat /* vhci bus config structure - one for each vhci bus config operation */ 80443c34adc5Sramat typedef struct mdi_vhci_bus_config_s { 80453c34adc5Sramat ddi_bus_config_op_t vhbc_op; /* bus config op */ 80463c34adc5Sramat major_t vhbc_op_major; /* bus config op major */ 80473c34adc5Sramat uint_t vhbc_op_flags; /* bus config op flags */ 80483c34adc5Sramat kmutex_t vhbc_lock; 80493c34adc5Sramat kcondvar_t vhbc_cv; 80503c34adc5Sramat int vhbc_thr_count; 80513c34adc5Sramat } mdi_vhci_bus_config_t; 80523c34adc5Sramat 80533c34adc5Sramat /* 80543c34adc5Sramat * bus config the specified phci 80553c34adc5Sramat */ 80563c34adc5Sramat static void 80573c34adc5Sramat bus_config_phci(void *arg) 80583c34adc5Sramat { 80593c34adc5Sramat mdi_phci_bus_config_t *phbc = (mdi_phci_bus_config_t *)arg; 80603c34adc5Sramat mdi_vhci_bus_config_t *vhbc = phbc->phbc_vhbusconfig; 80613c34adc5Sramat dev_info_t *ph_dip; 80623c34adc5Sramat 80633c34adc5Sramat /* 80643c34adc5Sramat * first configure all path components upto phci and then configure 80653c34adc5Sramat * the phci children. 80663c34adc5Sramat */ 80673c34adc5Sramat if ((ph_dip = e_ddi_hold_devi_by_path(phbc->phbc_phci_path, 0)) 80683c34adc5Sramat != NULL) { 80693c34adc5Sramat if (vhbc->vhbc_op == BUS_CONFIG_DRIVER || 80703c34adc5Sramat vhbc->vhbc_op == BUS_UNCONFIG_DRIVER) { 80713c34adc5Sramat (void) ndi_devi_config_driver(ph_dip, 80723c34adc5Sramat vhbc->vhbc_op_flags, 80733c34adc5Sramat vhbc->vhbc_op_major); 80743c34adc5Sramat } else 80753c34adc5Sramat (void) ndi_devi_config(ph_dip, 80763c34adc5Sramat vhbc->vhbc_op_flags); 80773c34adc5Sramat 80783c34adc5Sramat /* release the hold that e_ddi_hold_devi_by_path() placed */ 80793c34adc5Sramat ndi_rele_devi(ph_dip); 80803c34adc5Sramat } 80813c34adc5Sramat 80823c34adc5Sramat kmem_free(phbc->phbc_phci_path, strlen(phbc->phbc_phci_path) + 1); 80833c34adc5Sramat kmem_free(phbc, sizeof (*phbc)); 80843c34adc5Sramat 80853c34adc5Sramat mutex_enter(&vhbc->vhbc_lock); 80863c34adc5Sramat vhbc->vhbc_thr_count--; 80873c34adc5Sramat if (vhbc->vhbc_thr_count == 0) 80883c34adc5Sramat cv_broadcast(&vhbc->vhbc_cv); 80893c34adc5Sramat mutex_exit(&vhbc->vhbc_lock); 80903c34adc5Sramat } 80913c34adc5Sramat 80923c34adc5Sramat /* 80933c34adc5Sramat * Bus config all phcis associated with the vhci in parallel. 80943c34adc5Sramat * op must be BUS_CONFIG_DRIVER or BUS_CONFIG_ALL. 80953c34adc5Sramat */ 80963c34adc5Sramat static void 80973c34adc5Sramat bus_config_all_phcis(mdi_vhci_cache_t *vhcache, uint_t flags, 80983c34adc5Sramat ddi_bus_config_op_t op, major_t maj) 80993c34adc5Sramat { 81003c34adc5Sramat mdi_phci_bus_config_t *phbc_head = NULL, *phbc, *phbc_next; 81013c34adc5Sramat mdi_vhci_bus_config_t *vhbc; 81023c34adc5Sramat mdi_vhcache_phci_t *cphci; 81033c34adc5Sramat 81043c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 81053c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) { 81063c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 81073c34adc5Sramat return; 81083c34adc5Sramat } 81093c34adc5Sramat 81103c34adc5Sramat vhbc = kmem_zalloc(sizeof (*vhbc), KM_SLEEP); 81113c34adc5Sramat 81123c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 81133c34adc5Sramat cphci = cphci->cphci_next) { 8114273f4511Sgp87344 /* skip phcis that haven't attached before root is available */ 8115273f4511Sgp87344 if (!modrootloaded && (cphci->cphci_phci == NULL)) 8116273f4511Sgp87344 continue; 81173c34adc5Sramat phbc = kmem_zalloc(sizeof (*phbc), KM_SLEEP); 81183c34adc5Sramat phbc->phbc_phci_path = i_ddi_strdup(cphci->cphci_path, 81193c34adc5Sramat KM_SLEEP); 81203c34adc5Sramat phbc->phbc_vhbusconfig = vhbc; 81213c34adc5Sramat phbc->phbc_next = phbc_head; 81223c34adc5Sramat phbc_head = phbc; 81233c34adc5Sramat vhbc->vhbc_thr_count++; 81243c34adc5Sramat } 81253c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 81263c34adc5Sramat 81273c34adc5Sramat vhbc->vhbc_op = op; 81283c34adc5Sramat vhbc->vhbc_op_major = maj; 81293c34adc5Sramat vhbc->vhbc_op_flags = NDI_NO_EVENT | 81303c34adc5Sramat (flags & (NDI_CONFIG_REPROBE | NDI_DRV_CONF_REPROBE)); 81313c34adc5Sramat mutex_init(&vhbc->vhbc_lock, NULL, MUTEX_DEFAULT, NULL); 81323c34adc5Sramat cv_init(&vhbc->vhbc_cv, NULL, CV_DRIVER, NULL); 81333c34adc5Sramat 81343c34adc5Sramat /* now create threads to initiate bus config on all phcis in parallel */ 81353c34adc5Sramat for (phbc = phbc_head; phbc != NULL; phbc = phbc_next) { 81363c34adc5Sramat phbc_next = phbc->phbc_next; 81373c34adc5Sramat if (mdi_mtc_off) 81383c34adc5Sramat bus_config_phci((void *)phbc); 81393c34adc5Sramat else 81403c34adc5Sramat (void) thread_create(NULL, 0, bus_config_phci, phbc, 81413c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 81423c34adc5Sramat } 81433c34adc5Sramat 81443c34adc5Sramat mutex_enter(&vhbc->vhbc_lock); 81453c34adc5Sramat /* wait until all threads exit */ 81463c34adc5Sramat while (vhbc->vhbc_thr_count > 0) 81473c34adc5Sramat cv_wait(&vhbc->vhbc_cv, &vhbc->vhbc_lock); 81483c34adc5Sramat mutex_exit(&vhbc->vhbc_lock); 81493c34adc5Sramat 81503c34adc5Sramat mutex_destroy(&vhbc->vhbc_lock); 81513c34adc5Sramat cv_destroy(&vhbc->vhbc_cv); 81523c34adc5Sramat kmem_free(vhbc, sizeof (*vhbc)); 81533c34adc5Sramat } 81543c34adc5Sramat 81553c34adc5Sramat /* 815667e56d35Sramat * Single threaded version of bus_config_all_phcis() 815767e56d35Sramat */ 815867e56d35Sramat static void 815967e56d35Sramat st_bus_config_all_phcis(mdi_vhci_config_t *vhc, uint_t flags, 816067e56d35Sramat ddi_bus_config_op_t op, major_t maj) 816167e56d35Sramat { 816267e56d35Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 816367e56d35Sramat 816467e56d35Sramat single_threaded_vhconfig_enter(vhc); 816567e56d35Sramat bus_config_all_phcis(vhcache, flags, op, maj); 816667e56d35Sramat single_threaded_vhconfig_exit(vhc); 816767e56d35Sramat } 816867e56d35Sramat 816967e56d35Sramat /* 81703c34adc5Sramat * Perform BUS_CONFIG_ONE on the specified child of the phci. 81713c34adc5Sramat * The path includes the child component in addition to the phci path. 81723c34adc5Sramat */ 81733c34adc5Sramat static int 81743c34adc5Sramat bus_config_one_phci_child(char *path) 81753c34adc5Sramat { 81763c34adc5Sramat dev_info_t *ph_dip, *child; 81773c34adc5Sramat char *devnm; 81783c34adc5Sramat int rv = MDI_FAILURE; 81793c34adc5Sramat 81803c34adc5Sramat /* extract the child component of the phci */ 81813c34adc5Sramat devnm = strrchr(path, '/'); 81823c34adc5Sramat *devnm++ = '\0'; 81833c34adc5Sramat 81843c34adc5Sramat /* 81853c34adc5Sramat * first configure all path components upto phci and then 81863c34adc5Sramat * configure the phci child. 81873c34adc5Sramat */ 81883c34adc5Sramat if ((ph_dip = e_ddi_hold_devi_by_path(path, 0)) != NULL) { 81893c34adc5Sramat if (ndi_devi_config_one(ph_dip, devnm, &child, NDI_NO_EVENT) == 81903c34adc5Sramat NDI_SUCCESS) { 81913c34adc5Sramat /* 81923c34adc5Sramat * release the hold that ndi_devi_config_one() placed 81933c34adc5Sramat */ 81943c34adc5Sramat ndi_rele_devi(child); 81953c34adc5Sramat rv = MDI_SUCCESS; 81963c34adc5Sramat } 81973c34adc5Sramat 81983c34adc5Sramat /* release the hold that e_ddi_hold_devi_by_path() placed */ 81993c34adc5Sramat ndi_rele_devi(ph_dip); 82003c34adc5Sramat } 82013c34adc5Sramat 82023c34adc5Sramat devnm--; 82033c34adc5Sramat *devnm = '/'; 82043c34adc5Sramat return (rv); 82053c34adc5Sramat } 82063c34adc5Sramat 82073c34adc5Sramat /* 82083c34adc5Sramat * Build a list of phci client paths for the specified vhci client. 82093c34adc5Sramat * The list includes only those phci client paths which aren't configured yet. 82103c34adc5Sramat */ 82113c34adc5Sramat static mdi_phys_path_t * 82123c34adc5Sramat build_phclient_path_list(mdi_vhcache_client_t *cct, char *ct_name) 82133c34adc5Sramat { 82143c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 82153c34adc5Sramat mdi_phys_path_t *pp_head = NULL, *pp_tail = NULL, *pp; 82163c34adc5Sramat int config_path, len; 82173c34adc5Sramat 82183c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 82193c34adc5Sramat /* 82203c34adc5Sramat * include only those paths that aren't configured. 82213c34adc5Sramat */ 82223c34adc5Sramat config_path = 0; 82233c34adc5Sramat if (cpi->cpi_pip == NULL) 82243c34adc5Sramat config_path = 1; 82253c34adc5Sramat else { 82263c34adc5Sramat MDI_PI_LOCK(cpi->cpi_pip); 82273c34adc5Sramat if (MDI_PI_IS_INIT(cpi->cpi_pip)) 82283c34adc5Sramat config_path = 1; 82293c34adc5Sramat MDI_PI_UNLOCK(cpi->cpi_pip); 82303c34adc5Sramat } 82313c34adc5Sramat 82323c34adc5Sramat if (config_path) { 82333c34adc5Sramat pp = kmem_alloc(sizeof (*pp), KM_SLEEP); 82343c34adc5Sramat len = strlen(cpi->cpi_cphci->cphci_path) + 82353c34adc5Sramat strlen(ct_name) + strlen(cpi->cpi_addr) + 3; 82363c34adc5Sramat pp->phys_path = kmem_alloc(len, KM_SLEEP); 82373c34adc5Sramat (void) snprintf(pp->phys_path, len, "%s/%s@%s", 82383c34adc5Sramat cpi->cpi_cphci->cphci_path, ct_name, 82393c34adc5Sramat cpi->cpi_addr); 82403c34adc5Sramat pp->phys_path_next = NULL; 82413c34adc5Sramat 82423c34adc5Sramat if (pp_head == NULL) 82433c34adc5Sramat pp_head = pp; 82443c34adc5Sramat else 82453c34adc5Sramat pp_tail->phys_path_next = pp; 82463c34adc5Sramat pp_tail = pp; 82473c34adc5Sramat } 82483c34adc5Sramat } 82493c34adc5Sramat 82503c34adc5Sramat return (pp_head); 82513c34adc5Sramat } 82523c34adc5Sramat 82533c34adc5Sramat /* 82543c34adc5Sramat * Free the memory allocated for phci client path list. 82553c34adc5Sramat */ 82563c34adc5Sramat static void 82573c34adc5Sramat free_phclient_path_list(mdi_phys_path_t *pp_head) 82583c34adc5Sramat { 82593c34adc5Sramat mdi_phys_path_t *pp, *pp_next; 82603c34adc5Sramat 82613c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp_next) { 82623c34adc5Sramat pp_next = pp->phys_path_next; 82633c34adc5Sramat kmem_free(pp->phys_path, strlen(pp->phys_path) + 1); 82643c34adc5Sramat kmem_free(pp, sizeof (*pp)); 82653c34adc5Sramat } 82663c34adc5Sramat } 82673c34adc5Sramat 82683c34adc5Sramat /* 82693c34adc5Sramat * Allocated async client structure and initialize with the specified values. 82703c34adc5Sramat */ 82713c34adc5Sramat static mdi_async_client_config_t * 82723c34adc5Sramat alloc_async_client_config(char *ct_name, char *ct_addr, 82733c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 82743c34adc5Sramat { 82753c34adc5Sramat mdi_async_client_config_t *acc; 82763c34adc5Sramat 82773c34adc5Sramat acc = kmem_alloc(sizeof (*acc), KM_SLEEP); 82783c34adc5Sramat acc->acc_ct_name = i_ddi_strdup(ct_name, KM_SLEEP); 82793c34adc5Sramat acc->acc_ct_addr = i_ddi_strdup(ct_addr, KM_SLEEP); 82803c34adc5Sramat acc->acc_phclient_path_list_head = pp_head; 82813c34adc5Sramat init_vhcache_lookup_token(&acc->acc_token, tok); 82823c34adc5Sramat acc->acc_next = NULL; 82833c34adc5Sramat return (acc); 82843c34adc5Sramat } 82853c34adc5Sramat 82863c34adc5Sramat /* 82873c34adc5Sramat * Free the memory allocated for the async client structure and their members. 82883c34adc5Sramat */ 82893c34adc5Sramat static void 82903c34adc5Sramat free_async_client_config(mdi_async_client_config_t *acc) 82913c34adc5Sramat { 82923c34adc5Sramat if (acc->acc_phclient_path_list_head) 82933c34adc5Sramat free_phclient_path_list(acc->acc_phclient_path_list_head); 82943c34adc5Sramat kmem_free(acc->acc_ct_name, strlen(acc->acc_ct_name) + 1); 82953c34adc5Sramat kmem_free(acc->acc_ct_addr, strlen(acc->acc_ct_addr) + 1); 82963c34adc5Sramat kmem_free(acc, sizeof (*acc)); 82973c34adc5Sramat } 82983c34adc5Sramat 82993c34adc5Sramat /* 83003c34adc5Sramat * Sort vhcache pathinfos (cpis) of the specified client. 83013c34adc5Sramat * All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST 83023c34adc5Sramat * flag set come at the beginning of the list. All cpis which have this 83033c34adc5Sramat * flag set come at the end of the list. 83043c34adc5Sramat */ 83053c34adc5Sramat static void 83063c34adc5Sramat sort_vhcache_paths(mdi_vhcache_client_t *cct) 83073c34adc5Sramat { 83083c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_next, *cpi_head; 83093c34adc5Sramat 83103c34adc5Sramat cpi_head = cct->cct_cpi_head; 83113c34adc5Sramat cct->cct_cpi_head = cct->cct_cpi_tail = NULL; 83123c34adc5Sramat for (cpi = cpi_head; cpi != NULL; cpi = cpi_next) { 83133c34adc5Sramat cpi_next = cpi->cpi_next; 83143c34adc5Sramat enqueue_vhcache_pathinfo(cct, cpi); 83153c34adc5Sramat } 83163c34adc5Sramat } 83173c34adc5Sramat 83183c34adc5Sramat /* 83193c34adc5Sramat * Verify whether MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag setting is correct for 83203c34adc5Sramat * every vhcache pathinfo of the specified client. If not adjust the flag 83213c34adc5Sramat * setting appropriately. 83223c34adc5Sramat * 83233c34adc5Sramat * Note that MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag is persisted in the 83243c34adc5Sramat * on-disk vhci cache. So every time this flag is updated the cache must be 83253c34adc5Sramat * flushed. 83263c34adc5Sramat */ 83273c34adc5Sramat static void 83283c34adc5Sramat adjust_sort_vhcache_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 83293c34adc5Sramat mdi_vhcache_lookup_token_t *tok) 83303c34adc5Sramat { 83313c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 83323c34adc5Sramat mdi_vhcache_client_t *cct; 83333c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 83343c34adc5Sramat 83353c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 83363c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, tok)) 83373c34adc5Sramat == NULL) { 83383c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 83393c34adc5Sramat return; 83403c34adc5Sramat } 83413c34adc5Sramat 83423c34adc5Sramat /* 83433c34adc5Sramat * to avoid unnecessary on-disk cache updates, first check if an 83443c34adc5Sramat * update is really needed. If no update is needed simply return. 83453c34adc5Sramat */ 83463c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 83473c34adc5Sramat if ((cpi->cpi_pip != NULL && 83483c34adc5Sramat (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST)) || 83493c34adc5Sramat (cpi->cpi_pip == NULL && 83503c34adc5Sramat !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST))) { 83513c34adc5Sramat break; 83523c34adc5Sramat } 83533c34adc5Sramat } 83543c34adc5Sramat if (cpi == NULL) { 83553c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 83563c34adc5Sramat return; 83573c34adc5Sramat } 83583c34adc5Sramat 83593c34adc5Sramat if (rw_tryupgrade(&vhcache->vhcache_lock) == 0) { 83603c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 83613c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 83623c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, 83633c34adc5Sramat tok)) == NULL) { 83643c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 83653c34adc5Sramat return; 83663c34adc5Sramat } 83673c34adc5Sramat } 83683c34adc5Sramat 83693c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 83703c34adc5Sramat if (cpi->cpi_pip != NULL) 83713c34adc5Sramat cpi->cpi_flags &= ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 83723c34adc5Sramat else 83733c34adc5Sramat cpi->cpi_flags |= MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 83743c34adc5Sramat } 83753c34adc5Sramat sort_vhcache_paths(cct); 83763c34adc5Sramat 83773c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 83783c34adc5Sramat vhcache_dirty(vhc); 83793c34adc5Sramat } 83803c34adc5Sramat 83813c34adc5Sramat /* 83823c34adc5Sramat * Configure all specified paths of the client. 83833c34adc5Sramat */ 83843c34adc5Sramat static void 83853c34adc5Sramat config_client_paths_sync(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 83863c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 83873c34adc5Sramat { 83883c34adc5Sramat mdi_phys_path_t *pp; 83893c34adc5Sramat 83903c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp->phys_path_next) 83913c34adc5Sramat (void) bus_config_one_phci_child(pp->phys_path); 83923c34adc5Sramat adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, tok); 83933c34adc5Sramat } 83943c34adc5Sramat 83953c34adc5Sramat /* 83963c34adc5Sramat * Dequeue elements from vhci async client config list and bus configure 83973c34adc5Sramat * their corresponding phci clients. 83983c34adc5Sramat */ 83993c34adc5Sramat static void 84003c34adc5Sramat config_client_paths_thread(void *arg) 84013c34adc5Sramat { 84023c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 84033c34adc5Sramat mdi_async_client_config_t *acc; 84043c34adc5Sramat clock_t quit_at_ticks; 84053c34adc5Sramat clock_t idle_time = mdi_async_config_idle_time * TICKS_PER_SECOND; 84063c34adc5Sramat callb_cpr_t cprinfo; 84073c34adc5Sramat 84083c34adc5Sramat CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr, 84093c34adc5Sramat "mdi_config_client_paths"); 84103c34adc5Sramat 84113c34adc5Sramat for (; ; ) { 84123c34adc5Sramat quit_at_ticks = ddi_get_lbolt() + idle_time; 84133c34adc5Sramat 84143c34adc5Sramat mutex_enter(&vhc->vhc_lock); 84153c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 84163c34adc5Sramat vhc->vhc_acc_list_head == NULL && 84173c34adc5Sramat ddi_get_lbolt() < quit_at_ticks) { 84183c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 84193c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock, 84203c34adc5Sramat quit_at_ticks); 84213c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 84223c34adc5Sramat } 84233c34adc5Sramat 84243c34adc5Sramat if ((vhc->vhc_flags & MDI_VHC_EXIT) || 84253c34adc5Sramat vhc->vhc_acc_list_head == NULL) 84263c34adc5Sramat goto out; 84273c34adc5Sramat 84283c34adc5Sramat acc = vhc->vhc_acc_list_head; 84293c34adc5Sramat vhc->vhc_acc_list_head = acc->acc_next; 84303c34adc5Sramat if (vhc->vhc_acc_list_head == NULL) 84313c34adc5Sramat vhc->vhc_acc_list_tail = NULL; 84323c34adc5Sramat vhc->vhc_acc_count--; 84333c34adc5Sramat mutex_exit(&vhc->vhc_lock); 84343c34adc5Sramat 84353c34adc5Sramat config_client_paths_sync(vhc, acc->acc_ct_name, 84363c34adc5Sramat acc->acc_ct_addr, acc->acc_phclient_path_list_head, 84373c34adc5Sramat &acc->acc_token); 84383c34adc5Sramat 84393c34adc5Sramat free_async_client_config(acc); 84403c34adc5Sramat } 84413c34adc5Sramat 84423c34adc5Sramat out: 84433c34adc5Sramat vhc->vhc_acc_thrcount--; 84443c34adc5Sramat /* CALLB_CPR_EXIT releases the vhc->vhc_lock */ 84453c34adc5Sramat CALLB_CPR_EXIT(&cprinfo); 84463c34adc5Sramat } 84473c34adc5Sramat 84483c34adc5Sramat /* 84493c34adc5Sramat * Arrange for all the phci client paths (pp_head) for the specified client 84503c34adc5Sramat * to be bus configured asynchronously by a thread. 84513c34adc5Sramat */ 84523c34adc5Sramat static void 84533c34adc5Sramat config_client_paths_async(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 84543c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 84553c34adc5Sramat { 84563c34adc5Sramat mdi_async_client_config_t *acc, *newacc; 84573c34adc5Sramat int create_thread; 84583c34adc5Sramat 84593c34adc5Sramat if (pp_head == NULL) 84603c34adc5Sramat return; 84613c34adc5Sramat 84623c34adc5Sramat if (mdi_mtc_off) { 84633c34adc5Sramat config_client_paths_sync(vhc, ct_name, ct_addr, pp_head, tok); 84643c34adc5Sramat free_phclient_path_list(pp_head); 84653c34adc5Sramat return; 84663c34adc5Sramat } 84673c34adc5Sramat 84683c34adc5Sramat newacc = alloc_async_client_config(ct_name, ct_addr, pp_head, tok); 84693c34adc5Sramat ASSERT(newacc); 84703c34adc5Sramat 84713c34adc5Sramat mutex_enter(&vhc->vhc_lock); 84723c34adc5Sramat for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc->acc_next) { 84733c34adc5Sramat if (strcmp(ct_name, acc->acc_ct_name) == 0 && 84743c34adc5Sramat strcmp(ct_addr, acc->acc_ct_addr) == 0) { 84753c34adc5Sramat free_async_client_config(newacc); 84763c34adc5Sramat mutex_exit(&vhc->vhc_lock); 84773c34adc5Sramat return; 84783c34adc5Sramat } 84793c34adc5Sramat } 84803c34adc5Sramat 84813c34adc5Sramat if (vhc->vhc_acc_list_head == NULL) 84823c34adc5Sramat vhc->vhc_acc_list_head = newacc; 84833c34adc5Sramat else 84843c34adc5Sramat vhc->vhc_acc_list_tail->acc_next = newacc; 84853c34adc5Sramat vhc->vhc_acc_list_tail = newacc; 84863c34adc5Sramat vhc->vhc_acc_count++; 84873c34adc5Sramat if (vhc->vhc_acc_count <= vhc->vhc_acc_thrcount) { 84883c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 84893c34adc5Sramat create_thread = 0; 84903c34adc5Sramat } else { 84913c34adc5Sramat vhc->vhc_acc_thrcount++; 84923c34adc5Sramat create_thread = 1; 84933c34adc5Sramat } 84943c34adc5Sramat mutex_exit(&vhc->vhc_lock); 84953c34adc5Sramat 84963c34adc5Sramat if (create_thread) 84973c34adc5Sramat (void) thread_create(NULL, 0, config_client_paths_thread, vhc, 84983c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 84993c34adc5Sramat } 85003c34adc5Sramat 85013c34adc5Sramat /* 85023c34adc5Sramat * Return number of online paths for the specified client. 85033c34adc5Sramat */ 85043c34adc5Sramat static int 85053c34adc5Sramat nonline_paths(mdi_vhcache_client_t *cct) 85063c34adc5Sramat { 85073c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 85083c34adc5Sramat int online_count = 0; 85093c34adc5Sramat 85103c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 85113c34adc5Sramat if (cpi->cpi_pip != NULL) { 85123c34adc5Sramat MDI_PI_LOCK(cpi->cpi_pip); 85133c34adc5Sramat if (cpi->cpi_pip->pi_state == MDI_PATHINFO_STATE_ONLINE) 85143c34adc5Sramat online_count++; 85153c34adc5Sramat MDI_PI_UNLOCK(cpi->cpi_pip); 85163c34adc5Sramat } 85173c34adc5Sramat } 85183c34adc5Sramat 85193c34adc5Sramat return (online_count); 85203c34adc5Sramat } 85213c34adc5Sramat 85223c34adc5Sramat /* 85233c34adc5Sramat * Bus configure all paths for the specified vhci client. 85243c34adc5Sramat * If at least one path for the client is already online, the remaining paths 85253c34adc5Sramat * will be configured asynchronously. Otherwise, it synchronously configures 85263c34adc5Sramat * the paths until at least one path is online and then rest of the paths 85273c34adc5Sramat * will be configured asynchronously. 85283c34adc5Sramat */ 85293c34adc5Sramat static void 85303c34adc5Sramat config_client_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr) 85313c34adc5Sramat { 85323c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 85333c34adc5Sramat mdi_phys_path_t *pp_head, *pp; 85343c34adc5Sramat mdi_vhcache_client_t *cct; 85353c34adc5Sramat mdi_vhcache_lookup_token_t tok; 85363c34adc5Sramat 85373c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 85383c34adc5Sramat 85393c34adc5Sramat init_vhcache_lookup_token(&tok, NULL); 85403c34adc5Sramat 85413c34adc5Sramat if (ct_name == NULL || ct_addr == NULL || 85423c34adc5Sramat (cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, &tok)) 85433c34adc5Sramat == NULL || 85443c34adc5Sramat (pp_head = build_phclient_path_list(cct, ct_name)) == NULL) { 85453c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 85463c34adc5Sramat return; 85473c34adc5Sramat } 85483c34adc5Sramat 85493c34adc5Sramat /* if at least one path is online, configure the rest asynchronously */ 85503c34adc5Sramat if (nonline_paths(cct) > 0) { 85513c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 85523c34adc5Sramat config_client_paths_async(vhc, ct_name, ct_addr, pp_head, &tok); 85533c34adc5Sramat return; 85543c34adc5Sramat } 85553c34adc5Sramat 85563c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 85573c34adc5Sramat 85583c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp->phys_path_next) { 85593c34adc5Sramat if (bus_config_one_phci_child(pp->phys_path) == MDI_SUCCESS) { 85603c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 85613c34adc5Sramat 85623c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, 85633c34adc5Sramat ct_addr, &tok)) == NULL) { 85643c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 85653c34adc5Sramat goto out; 85663c34adc5Sramat } 85673c34adc5Sramat 85683c34adc5Sramat if (nonline_paths(cct) > 0 && 85693c34adc5Sramat pp->phys_path_next != NULL) { 85703c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 85713c34adc5Sramat config_client_paths_async(vhc, ct_name, ct_addr, 85723c34adc5Sramat pp->phys_path_next, &tok); 85733c34adc5Sramat pp->phys_path_next = NULL; 85743c34adc5Sramat goto out; 85753c34adc5Sramat } 85763c34adc5Sramat 85773c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 85783c34adc5Sramat } 85793c34adc5Sramat } 85803c34adc5Sramat 85813c34adc5Sramat adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, &tok); 85823c34adc5Sramat out: 85833c34adc5Sramat free_phclient_path_list(pp_head); 85843c34adc5Sramat } 85853c34adc5Sramat 85863c34adc5Sramat static void 85873c34adc5Sramat single_threaded_vhconfig_enter(mdi_vhci_config_t *vhc) 85883c34adc5Sramat { 85893c34adc5Sramat mutex_enter(&vhc->vhc_lock); 85903c34adc5Sramat while (vhc->vhc_flags & MDI_VHC_SINGLE_THREADED) 85913c34adc5Sramat cv_wait(&vhc->vhc_cv, &vhc->vhc_lock); 85923c34adc5Sramat vhc->vhc_flags |= MDI_VHC_SINGLE_THREADED; 85933c34adc5Sramat mutex_exit(&vhc->vhc_lock); 85943c34adc5Sramat } 85953c34adc5Sramat 85963c34adc5Sramat static void 85973c34adc5Sramat single_threaded_vhconfig_exit(mdi_vhci_config_t *vhc) 85983c34adc5Sramat { 85993c34adc5Sramat mutex_enter(&vhc->vhc_lock); 86003c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_SINGLE_THREADED; 86013c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 86023c34adc5Sramat mutex_exit(&vhc->vhc_lock); 86033c34adc5Sramat } 86043c34adc5Sramat 860552cac543Sramat typedef struct mdi_phci_driver_info { 860652cac543Sramat char *phdriver_name; /* name of the phci driver */ 860752cac543Sramat 860852cac543Sramat /* set to non zero if the phci driver supports root device */ 860952cac543Sramat int phdriver_root_support; 861052cac543Sramat } mdi_phci_driver_info_t; 861152cac543Sramat 86123c34adc5Sramat /* 861352cac543Sramat * vhci class and root support capability of a phci driver can be 861452cac543Sramat * specified using ddi-vhci-class and ddi-no-root-support properties in the 861552cac543Sramat * phci driver.conf file. The built-in tables below contain this information 861652cac543Sramat * for those phci drivers whose driver.conf files don't yet contain this info. 861752cac543Sramat * 861852cac543Sramat * All phci drivers expect iscsi have root device support. 861952cac543Sramat */ 862052cac543Sramat static mdi_phci_driver_info_t scsi_phci_driver_list[] = { 862152cac543Sramat { "fp", 1 }, 862252cac543Sramat { "iscsi", 0 }, 862352cac543Sramat { "ibsrp", 1 } 862452cac543Sramat }; 862552cac543Sramat 862652cac543Sramat static mdi_phci_driver_info_t ib_phci_driver_list[] = { "tavor", 1 }; 862752cac543Sramat 862852cac543Sramat static void * 862952cac543Sramat mdi_realloc(void *old_ptr, size_t old_size, size_t new_size) 863052cac543Sramat { 863152cac543Sramat void *new_ptr; 863252cac543Sramat 863352cac543Sramat new_ptr = kmem_zalloc(new_size, KM_SLEEP); 863452cac543Sramat if (old_ptr) { 8635f7209cf2Spramodbg bcopy(old_ptr, new_ptr, MIN(old_size, new_size)); 863652cac543Sramat kmem_free(old_ptr, old_size); 863752cac543Sramat } 863852cac543Sramat return (new_ptr); 863952cac543Sramat } 864052cac543Sramat 864152cac543Sramat static void 864252cac543Sramat add_to_phci_list(char ***driver_list, int **root_support_list, 864352cac543Sramat int *cur_elements, int *max_elements, char *driver_name, int root_support) 864452cac543Sramat { 864552cac543Sramat ASSERT(*cur_elements <= *max_elements); 864652cac543Sramat if (*cur_elements == *max_elements) { 864752cac543Sramat *max_elements += 10; 864852cac543Sramat *driver_list = mdi_realloc(*driver_list, 864952cac543Sramat sizeof (char *) * (*cur_elements), 865052cac543Sramat sizeof (char *) * (*max_elements)); 865152cac543Sramat *root_support_list = mdi_realloc(*root_support_list, 865252cac543Sramat sizeof (int) * (*cur_elements), 865352cac543Sramat sizeof (int) * (*max_elements)); 865452cac543Sramat } 865552cac543Sramat (*driver_list)[*cur_elements] = i_ddi_strdup(driver_name, KM_SLEEP); 865652cac543Sramat (*root_support_list)[*cur_elements] = root_support; 865752cac543Sramat (*cur_elements)++; 865852cac543Sramat } 865952cac543Sramat 866052cac543Sramat static void 866152cac543Sramat get_phci_driver_list(char *vhci_class, char ***driver_list, 866252cac543Sramat int **root_support_list, int *cur_elements, int *max_elements) 866352cac543Sramat { 866452cac543Sramat mdi_phci_driver_info_t *st_driver_list, *p; 866552cac543Sramat int st_ndrivers, root_support, i, j, driver_conf_count; 866652cac543Sramat major_t m; 866752cac543Sramat struct devnames *dnp; 866852cac543Sramat ddi_prop_t *propp; 866952cac543Sramat 867052cac543Sramat *driver_list = NULL; 867152cac543Sramat *root_support_list = NULL; 867252cac543Sramat *cur_elements = 0; 867352cac543Sramat *max_elements = 0; 867452cac543Sramat 867552cac543Sramat /* add the phci drivers derived from the phci driver.conf files */ 867652cac543Sramat for (m = 0; m < devcnt; m++) { 867752cac543Sramat dnp = &devnamesp[m]; 867852cac543Sramat 867952cac543Sramat if (dnp->dn_flags & DN_PHCI_DRIVER) { 868052cac543Sramat LOCK_DEV_OPS(&dnp->dn_lock); 868152cac543Sramat if (dnp->dn_global_prop_ptr != NULL && 868252cac543Sramat (propp = i_ddi_prop_search(DDI_DEV_T_ANY, 868352cac543Sramat DDI_VHCI_CLASS, DDI_PROP_TYPE_STRING, 868452cac543Sramat &dnp->dn_global_prop_ptr->prop_list)) != NULL && 868552cac543Sramat strcmp(propp->prop_val, vhci_class) == 0) { 868652cac543Sramat 868752cac543Sramat root_support = (i_ddi_prop_search(DDI_DEV_T_ANY, 868852cac543Sramat DDI_NO_ROOT_SUPPORT, DDI_PROP_TYPE_INT, 868952cac543Sramat &dnp->dn_global_prop_ptr->prop_list) 869052cac543Sramat == NULL) ? 1 : 0; 869152cac543Sramat 869252cac543Sramat add_to_phci_list(driver_list, root_support_list, 869352cac543Sramat cur_elements, max_elements, dnp->dn_name, 869452cac543Sramat root_support); 869552cac543Sramat 869652cac543Sramat UNLOCK_DEV_OPS(&dnp->dn_lock); 869752cac543Sramat } else 869852cac543Sramat UNLOCK_DEV_OPS(&dnp->dn_lock); 869952cac543Sramat } 870052cac543Sramat } 870152cac543Sramat 870252cac543Sramat driver_conf_count = *cur_elements; 870352cac543Sramat 870452cac543Sramat /* add the phci drivers specified in the built-in tables */ 870552cac543Sramat if (strcmp(vhci_class, MDI_HCI_CLASS_SCSI) == 0) { 870652cac543Sramat st_driver_list = scsi_phci_driver_list; 870752cac543Sramat st_ndrivers = sizeof (scsi_phci_driver_list) / 870852cac543Sramat sizeof (mdi_phci_driver_info_t); 870952cac543Sramat } else if (strcmp(vhci_class, MDI_HCI_CLASS_IB) == 0) { 871052cac543Sramat st_driver_list = ib_phci_driver_list; 871152cac543Sramat st_ndrivers = sizeof (ib_phci_driver_list) / 871252cac543Sramat sizeof (mdi_phci_driver_info_t); 871352cac543Sramat } else { 871452cac543Sramat st_driver_list = NULL; 871552cac543Sramat st_ndrivers = 0; 871652cac543Sramat } 871752cac543Sramat 871852cac543Sramat for (i = 0, p = st_driver_list; i < st_ndrivers; i++, p++) { 871952cac543Sramat /* add this phci driver if not already added before */ 872052cac543Sramat for (j = 0; j < driver_conf_count; j++) { 872152cac543Sramat if (strcmp((*driver_list)[j], p->phdriver_name) == 0) 872252cac543Sramat break; 872352cac543Sramat } 872452cac543Sramat if (j == driver_conf_count) { 872552cac543Sramat add_to_phci_list(driver_list, root_support_list, 872652cac543Sramat cur_elements, max_elements, p->phdriver_name, 872752cac543Sramat p->phdriver_root_support); 872852cac543Sramat } 872952cac543Sramat } 873052cac543Sramat } 873152cac543Sramat 873252cac543Sramat /* 873352cac543Sramat * Attach the phci driver instances associated with the specified vhci class. 87343c34adc5Sramat * If root is mounted attach all phci driver instances. 87353c34adc5Sramat * If root is not mounted, attach the instances of only those phci 87363c34adc5Sramat * drivers that have the root support. 87373c34adc5Sramat */ 87383c34adc5Sramat static void 873952cac543Sramat attach_phci_drivers(char *vhci_class) 87403c34adc5Sramat { 874152cac543Sramat char **driver_list, **p; 874252cac543Sramat int *root_support_list; 874352cac543Sramat int cur_elements, max_elements, i; 87443c34adc5Sramat major_t m; 87453c34adc5Sramat 874652cac543Sramat get_phci_driver_list(vhci_class, &driver_list, &root_support_list, 874752cac543Sramat &cur_elements, &max_elements); 87483c34adc5Sramat 874952cac543Sramat for (i = 0; i < cur_elements; i++) { 875052cac543Sramat if (modrootloaded || root_support_list[i]) { 875152cac543Sramat m = ddi_name_to_major(driver_list[i]); 8752a204de77Scth if (m != DDI_MAJOR_T_NONE && 8753a204de77Scth ddi_hold_installed_driver(m)) 87543c34adc5Sramat ddi_rele_driver(m); 87553c34adc5Sramat } 87563c34adc5Sramat } 875752cac543Sramat 875852cac543Sramat if (driver_list) { 875952cac543Sramat for (i = 0, p = driver_list; i < cur_elements; i++, p++) 876052cac543Sramat kmem_free(*p, strlen(*p) + 1); 876152cac543Sramat kmem_free(driver_list, sizeof (char *) * max_elements); 876252cac543Sramat kmem_free(root_support_list, sizeof (int) * max_elements); 876352cac543Sramat } 87643c34adc5Sramat } 87653c34adc5Sramat 87663c34adc5Sramat /* 87673c34adc5Sramat * Build vhci cache: 87683c34adc5Sramat * 87693c34adc5Sramat * Attach phci driver instances and then drive BUS_CONFIG_ALL on 87703c34adc5Sramat * the phci driver instances. During this process the cache gets built. 87713c34adc5Sramat * 877267e56d35Sramat * Cache is built fully if the root is mounted. 87733c34adc5Sramat * If the root is not mounted, phci drivers that do not have root support 87743c34adc5Sramat * are not attached. As a result the cache is built partially. The entries 87753c34adc5Sramat * in the cache reflect only those phci drivers that have root support. 87763c34adc5Sramat */ 877767e56d35Sramat static int 877852cac543Sramat build_vhci_cache(mdi_vhci_t *vh) 87793c34adc5Sramat { 878052cac543Sramat mdi_vhci_config_t *vhc = vh->vh_config; 87813c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 87823c34adc5Sramat 878367e56d35Sramat single_threaded_vhconfig_enter(vhc); 878467e56d35Sramat 87853c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 87863c34adc5Sramat if (vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE) { 87873c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 878867e56d35Sramat single_threaded_vhconfig_exit(vhc); 878967e56d35Sramat return (0); 87903c34adc5Sramat } 87913c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 87923c34adc5Sramat 879352cac543Sramat attach_phci_drivers(vh->vh_class); 87943c34adc5Sramat bus_config_all_phcis(vhcache, NDI_DRV_CONF_REPROBE | NDI_NO_EVENT, 8795a204de77Scth BUS_CONFIG_ALL, DDI_MAJOR_T_NONE); 87963c34adc5Sramat 87973c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 87983c34adc5Sramat vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE; 87993c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 880067e56d35Sramat 880167e56d35Sramat single_threaded_vhconfig_exit(vhc); 88023c34adc5Sramat vhcache_dirty(vhc); 880367e56d35Sramat return (1); 88043c34adc5Sramat } 88053c34adc5Sramat 88063c34adc5Sramat /* 880767e56d35Sramat * Determine if discovery of paths is needed. 88083c34adc5Sramat */ 88093c34adc5Sramat static int 881067e56d35Sramat vhcache_do_discovery(mdi_vhci_config_t *vhc) 88113c34adc5Sramat { 881267e56d35Sramat int rv = 1; 881367e56d35Sramat 881467e56d35Sramat mutex_enter(&vhc->vhc_lock); 881567e56d35Sramat if (i_ddi_io_initialized() == 0) { 881667e56d35Sramat if (vhc->vhc_path_discovery_boot > 0) { 881767e56d35Sramat vhc->vhc_path_discovery_boot--; 881867e56d35Sramat goto out; 881967e56d35Sramat } 882067e56d35Sramat } else { 882167e56d35Sramat if (vhc->vhc_path_discovery_postboot > 0) { 882267e56d35Sramat vhc->vhc_path_discovery_postboot--; 882367e56d35Sramat goto out; 882467e56d35Sramat } 882567e56d35Sramat } 882667e56d35Sramat 882767e56d35Sramat /* 882867e56d35Sramat * Do full path discovery at most once per mdi_path_discovery_interval. 882967e56d35Sramat * This is to avoid a series of full path discoveries when opening 883067e56d35Sramat * stale /dev/[r]dsk links. 883167e56d35Sramat */ 883267e56d35Sramat if (mdi_path_discovery_interval != -1 && 883367e56d35Sramat lbolt64 >= vhc->vhc_path_discovery_cutoff_time) 883467e56d35Sramat goto out; 883567e56d35Sramat 883667e56d35Sramat rv = 0; 883767e56d35Sramat out: 883867e56d35Sramat mutex_exit(&vhc->vhc_lock); 883967e56d35Sramat return (rv); 884067e56d35Sramat } 884167e56d35Sramat 884267e56d35Sramat /* 884367e56d35Sramat * Discover all paths: 884467e56d35Sramat * 884567e56d35Sramat * Attach phci driver instances and then drive BUS_CONFIG_ALL on all the phci 884667e56d35Sramat * driver instances. During this process all paths will be discovered. 884767e56d35Sramat */ 884867e56d35Sramat static int 884952cac543Sramat vhcache_discover_paths(mdi_vhci_t *vh) 885067e56d35Sramat { 885152cac543Sramat mdi_vhci_config_t *vhc = vh->vh_config; 885267e56d35Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 885367e56d35Sramat int rv = 0; 88543c34adc5Sramat 88553c34adc5Sramat single_threaded_vhconfig_enter(vhc); 88563c34adc5Sramat 885767e56d35Sramat if (vhcache_do_discovery(vhc)) { 885852cac543Sramat attach_phci_drivers(vh->vh_class); 885967e56d35Sramat bus_config_all_phcis(vhcache, NDI_DRV_CONF_REPROBE | 8860a204de77Scth NDI_NO_EVENT, BUS_CONFIG_ALL, DDI_MAJOR_T_NONE); 886167e56d35Sramat 88623c34adc5Sramat mutex_enter(&vhc->vhc_lock); 886367e56d35Sramat vhc->vhc_path_discovery_cutoff_time = lbolt64 + 886467e56d35Sramat mdi_path_discovery_interval * TICKS_PER_SECOND; 88653c34adc5Sramat mutex_exit(&vhc->vhc_lock); 886667e56d35Sramat rv = 1; 88673c34adc5Sramat } 88683c34adc5Sramat 88693c34adc5Sramat single_threaded_vhconfig_exit(vhc); 88703c34adc5Sramat return (rv); 88713c34adc5Sramat } 88723c34adc5Sramat 88733c34adc5Sramat /* 88743c34adc5Sramat * Generic vhci bus config implementation: 88753c34adc5Sramat * 88763c34adc5Sramat * Parameters 88773c34adc5Sramat * vdip vhci dip 88783c34adc5Sramat * flags bus config flags 88793c34adc5Sramat * op bus config operation 88803c34adc5Sramat * The remaining parameters are bus config operation specific 88813c34adc5Sramat * 88823c34adc5Sramat * for BUS_CONFIG_ONE 88833c34adc5Sramat * arg pointer to name@addr 88843c34adc5Sramat * child upon successful return from this function, *child will be 88853c34adc5Sramat * set to the configured and held devinfo child node of vdip. 88863c34adc5Sramat * ct_addr pointer to client address (i.e. GUID) 88873c34adc5Sramat * 88883c34adc5Sramat * for BUS_CONFIG_DRIVER 88893c34adc5Sramat * arg major number of the driver 88903c34adc5Sramat * child and ct_addr parameters are ignored 88913c34adc5Sramat * 88923c34adc5Sramat * for BUS_CONFIG_ALL 88933c34adc5Sramat * arg, child, and ct_addr parameters are ignored 88943c34adc5Sramat * 88953c34adc5Sramat * Note that for the rest of the bus config operations, this function simply 88963c34adc5Sramat * calls the framework provided default bus config routine. 88973c34adc5Sramat */ 88983c34adc5Sramat int 88993c34adc5Sramat mdi_vhci_bus_config(dev_info_t *vdip, uint_t flags, ddi_bus_config_op_t op, 89003c34adc5Sramat void *arg, dev_info_t **child, char *ct_addr) 89013c34adc5Sramat { 89023c34adc5Sramat mdi_vhci_t *vh = i_devi_get_vhci(vdip); 89033c34adc5Sramat mdi_vhci_config_t *vhc = vh->vh_config; 89043c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 890567e56d35Sramat int rv = 0; 890667e56d35Sramat int params_valid = 0; 89073c34adc5Sramat char *cp; 89083c34adc5Sramat 89093c34adc5Sramat /* 89105e3986cbScth * To bus config vhcis we relay operation, possibly using another 89115e3986cbScth * thread, to phcis. The phci driver then interacts with MDI to cause 89125e3986cbScth * vhci child nodes to be enumerated under the vhci node. Adding a 89135e3986cbScth * vhci child requires an ndi_devi_enter of the vhci. Since another 89145e3986cbScth * thread may be adding the child, to avoid deadlock we can't wait 89155e3986cbScth * for the relayed operations to complete if we have already entered 89165e3986cbScth * the vhci node. 89173c34adc5Sramat */ 89183c34adc5Sramat if (DEVI_BUSY_OWNED(vdip)) { 89195e3986cbScth MDI_DEBUG(2, (CE_NOTE, vdip, "!MDI: vhci bus config: " 89205e3986cbScth "vhci dip is busy owned %p\n", (void *)vdip)); 89213c34adc5Sramat goto default_bus_config; 89223c34adc5Sramat } 89233c34adc5Sramat 89243c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 89253c34adc5Sramat if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) { 89263c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 892752cac543Sramat rv = build_vhci_cache(vh); 89283c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 89293c34adc5Sramat } 89303c34adc5Sramat 89313c34adc5Sramat switch (op) { 89323c34adc5Sramat case BUS_CONFIG_ONE: 893367e56d35Sramat if (arg != NULL && ct_addr != NULL) { 89343c34adc5Sramat /* extract node name */ 89353c34adc5Sramat cp = (char *)arg; 89363c34adc5Sramat while (*cp != '\0' && *cp != '@') 89373c34adc5Sramat cp++; 89383c34adc5Sramat if (*cp == '@') { 893967e56d35Sramat params_valid = 1; 89403c34adc5Sramat *cp = '\0'; 89413c34adc5Sramat config_client_paths(vhc, (char *)arg, ct_addr); 894267e56d35Sramat /* config_client_paths() releases cache_lock */ 89433c34adc5Sramat *cp = '@'; 894467e56d35Sramat break; 894567e56d35Sramat } 894667e56d35Sramat } 894767e56d35Sramat 89483c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 89493c34adc5Sramat break; 89503c34adc5Sramat 89513c34adc5Sramat case BUS_CONFIG_DRIVER: 89523c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 895367e56d35Sramat if (rv == 0) 895467e56d35Sramat st_bus_config_all_phcis(vhc, flags, op, 89553c34adc5Sramat (major_t)(uintptr_t)arg); 89563c34adc5Sramat break; 89573c34adc5Sramat 89583c34adc5Sramat case BUS_CONFIG_ALL: 89593c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 896067e56d35Sramat if (rv == 0) 896167e56d35Sramat st_bus_config_all_phcis(vhc, flags, op, -1); 89623c34adc5Sramat break; 89633c34adc5Sramat 89643c34adc5Sramat default: 89653c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 89663c34adc5Sramat break; 89673c34adc5Sramat } 89683c34adc5Sramat 89693c34adc5Sramat 89703c34adc5Sramat default_bus_config: 89713c34adc5Sramat /* 89723c34adc5Sramat * All requested child nodes are enumerated under the vhci. 89733c34adc5Sramat * Now configure them. 89743c34adc5Sramat */ 89753c34adc5Sramat if (ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 89763c34adc5Sramat NDI_SUCCESS) { 89773c34adc5Sramat return (MDI_SUCCESS); 897867e56d35Sramat } else if (op == BUS_CONFIG_ONE && rv == 0 && params_valid) { 897967e56d35Sramat /* discover all paths and try configuring again */ 898052cac543Sramat if (vhcache_discover_paths(vh) && 898167e56d35Sramat ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 898267e56d35Sramat NDI_SUCCESS) 898367e56d35Sramat return (MDI_SUCCESS); 89843c34adc5Sramat } 89853c34adc5Sramat 89863c34adc5Sramat return (MDI_FAILURE); 89873c34adc5Sramat } 89883c34adc5Sramat 89893c34adc5Sramat /* 89903c34adc5Sramat * Read the on-disk vhci cache into an nvlist for the specified vhci class. 89913c34adc5Sramat */ 89923c34adc5Sramat static nvlist_t * 89933c34adc5Sramat read_on_disk_vhci_cache(char *vhci_class) 89943c34adc5Sramat { 89953c34adc5Sramat nvlist_t *nvl; 89963c34adc5Sramat int err; 89973c34adc5Sramat char *filename; 89983c34adc5Sramat 89993c34adc5Sramat filename = vhclass2vhcache_filename(vhci_class); 90003c34adc5Sramat 90013c34adc5Sramat if ((err = fread_nvlist(filename, &nvl)) == 0) { 90023c34adc5Sramat kmem_free(filename, strlen(filename) + 1); 90033c34adc5Sramat return (nvl); 90043c34adc5Sramat } else if (err == EIO) 90053c34adc5Sramat cmn_err(CE_WARN, "%s: I/O error, will recreate\n", filename); 90063c34adc5Sramat else if (err == EINVAL) 90073c34adc5Sramat cmn_err(CE_WARN, 90083c34adc5Sramat "%s: data file corrupted, will recreate\n", filename); 90093c34adc5Sramat 90103c34adc5Sramat kmem_free(filename, strlen(filename) + 1); 90113c34adc5Sramat return (NULL); 90123c34adc5Sramat } 90133c34adc5Sramat 90143c34adc5Sramat /* 90153c34adc5Sramat * Read on-disk vhci cache into nvlists for all vhci classes. 90163c34adc5Sramat * Called during booting by i_ddi_read_devices_files(). 90173c34adc5Sramat */ 90183c34adc5Sramat void 90193c34adc5Sramat mdi_read_devices_files(void) 90203c34adc5Sramat { 90213c34adc5Sramat int i; 90223c34adc5Sramat 90233c34adc5Sramat for (i = 0; i < N_VHCI_CLASSES; i++) 90243c34adc5Sramat vhcache_nvl[i] = read_on_disk_vhci_cache(vhci_class_list[i]); 90253c34adc5Sramat } 90263c34adc5Sramat 90273c34adc5Sramat /* 90283c34adc5Sramat * Remove all stale entries from vhci cache. 90293c34adc5Sramat */ 90303c34adc5Sramat static void 90313c34adc5Sramat clean_vhcache(mdi_vhci_config_t *vhc) 90323c34adc5Sramat { 90333c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 90343c34adc5Sramat mdi_vhcache_phci_t *cphci, *cphci_head, *cphci_next; 90353c34adc5Sramat mdi_vhcache_client_t *cct, *cct_head, *cct_next; 90363c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_head, *cpi_next; 90373c34adc5Sramat 90383c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 90393c34adc5Sramat 90403c34adc5Sramat cct_head = vhcache->vhcache_client_head; 90413c34adc5Sramat vhcache->vhcache_client_head = vhcache->vhcache_client_tail = NULL; 90423c34adc5Sramat for (cct = cct_head; cct != NULL; cct = cct_next) { 90433c34adc5Sramat cct_next = cct->cct_next; 90443c34adc5Sramat 90453c34adc5Sramat cpi_head = cct->cct_cpi_head; 90463c34adc5Sramat cct->cct_cpi_head = cct->cct_cpi_tail = NULL; 90473c34adc5Sramat for (cpi = cpi_head; cpi != NULL; cpi = cpi_next) { 90483c34adc5Sramat cpi_next = cpi->cpi_next; 90493c34adc5Sramat if (cpi->cpi_pip != NULL) { 90503c34adc5Sramat ASSERT(cpi->cpi_cphci->cphci_phci != NULL); 90513c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, cpi); 90523c34adc5Sramat } else 90533c34adc5Sramat free_vhcache_pathinfo(cpi); 90543c34adc5Sramat } 90553c34adc5Sramat 90563c34adc5Sramat if (cct->cct_cpi_head != NULL) 90573c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 90583c34adc5Sramat else { 90593c34adc5Sramat (void) mod_hash_destroy(vhcache->vhcache_client_hash, 90603c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr); 90613c34adc5Sramat free_vhcache_client(cct); 90623c34adc5Sramat } 90633c34adc5Sramat } 90643c34adc5Sramat 90653c34adc5Sramat cphci_head = vhcache->vhcache_phci_head; 90663c34adc5Sramat vhcache->vhcache_phci_head = vhcache->vhcache_phci_tail = NULL; 90673c34adc5Sramat for (cphci = cphci_head; cphci != NULL; cphci = cphci_next) { 90683c34adc5Sramat cphci_next = cphci->cphci_next; 90693c34adc5Sramat if (cphci->cphci_phci != NULL) 90703c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 90713c34adc5Sramat else 90723c34adc5Sramat free_vhcache_phci(cphci); 90733c34adc5Sramat } 90743c34adc5Sramat 90753c34adc5Sramat vhcache->vhcache_clean_time = lbolt64; 90763c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 90773c34adc5Sramat vhcache_dirty(vhc); 90783c34adc5Sramat } 90793c34adc5Sramat 90803c34adc5Sramat /* 90813c34adc5Sramat * Remove all stale entries from vhci cache. 90823c34adc5Sramat * Called by i_ddi_clean_devices_files() during the execution of devfsadm -C 90833c34adc5Sramat */ 90843c34adc5Sramat void 90853c34adc5Sramat mdi_clean_vhcache(void) 90863c34adc5Sramat { 90873c34adc5Sramat mdi_vhci_t *vh; 90883c34adc5Sramat 90893c34adc5Sramat mutex_enter(&mdi_mutex); 90903c34adc5Sramat for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 90913c34adc5Sramat vh->vh_refcnt++; 90923c34adc5Sramat mutex_exit(&mdi_mutex); 90933c34adc5Sramat clean_vhcache(vh->vh_config); 90943c34adc5Sramat mutex_enter(&mdi_mutex); 90953c34adc5Sramat vh->vh_refcnt--; 90963c34adc5Sramat } 90973c34adc5Sramat mutex_exit(&mdi_mutex); 90983c34adc5Sramat } 90998c4f8890Srs135747 91008c4f8890Srs135747 /* 91018c4f8890Srs135747 * mdi_vhci_walk_clients(): 91028c4f8890Srs135747 * Walker routine to traverse client dev_info nodes 91038c4f8890Srs135747 * ddi_walk_devs(ddi_get_child(vdip), f, arg) returns the entire tree 91048c4f8890Srs135747 * below the client, including nexus devices, which we dont want. 91058c4f8890Srs135747 * So we just traverse the immediate siblings, starting from 1st client. 91068c4f8890Srs135747 */ 91078c4f8890Srs135747 void 91088c4f8890Srs135747 mdi_vhci_walk_clients(dev_info_t *vdip, 91098c4f8890Srs135747 int (*f)(dev_info_t *, void *), void *arg) 91108c4f8890Srs135747 { 91115e3986cbScth mdi_vhci_t *vh = i_devi_get_vhci(vdip); 91128c4f8890Srs135747 dev_info_t *cdip; 91138c4f8890Srs135747 mdi_client_t *ct; 91148c4f8890Srs135747 91155e3986cbScth MDI_VHCI_CLIENT_LOCK(vh); 91168c4f8890Srs135747 cdip = ddi_get_child(vdip); 91178c4f8890Srs135747 while (cdip) { 91188c4f8890Srs135747 ct = i_devi_get_client(cdip); 91198c4f8890Srs135747 MDI_CLIENT_LOCK(ct); 91208c4f8890Srs135747 91215e3986cbScth if (((*f)(cdip, arg)) == DDI_WALK_CONTINUE) 91228c4f8890Srs135747 cdip = ddi_get_next_sibling(cdip); 91235e3986cbScth else 91245e3986cbScth cdip = NULL; 9125c73a93f2Sdm120769 9126c73a93f2Sdm120769 MDI_CLIENT_UNLOCK(ct); 91278c4f8890Srs135747 } 91285e3986cbScth MDI_VHCI_CLIENT_UNLOCK(vh); 91298c4f8890Srs135747 } 91308c4f8890Srs135747 91318c4f8890Srs135747 /* 91328c4f8890Srs135747 * mdi_vhci_walk_phcis(): 91338c4f8890Srs135747 * Walker routine to traverse phci dev_info nodes 91348c4f8890Srs135747 */ 91358c4f8890Srs135747 void 91368c4f8890Srs135747 mdi_vhci_walk_phcis(dev_info_t *vdip, 91378c4f8890Srs135747 int (*f)(dev_info_t *, void *), void *arg) 91388c4f8890Srs135747 { 91395e3986cbScth mdi_vhci_t *vh = i_devi_get_vhci(vdip); 91405e3986cbScth mdi_phci_t *ph, *next; 91418c4f8890Srs135747 91425e3986cbScth MDI_VHCI_PHCI_LOCK(vh); 91438c4f8890Srs135747 ph = vh->vh_phci_head; 91448c4f8890Srs135747 while (ph) { 91458c4f8890Srs135747 MDI_PHCI_LOCK(ph); 91468c4f8890Srs135747 91475e3986cbScth if (((*f)(ph->ph_dip, arg)) == DDI_WALK_CONTINUE) 91485e3986cbScth next = ph->ph_next; 91495e3986cbScth else 91505e3986cbScth next = NULL; 9151c73a93f2Sdm120769 9152c73a93f2Sdm120769 MDI_PHCI_UNLOCK(ph); 91535e3986cbScth ph = next; 91548c4f8890Srs135747 } 91555e3986cbScth MDI_VHCI_PHCI_UNLOCK(vh); 91568c4f8890Srs135747 } 91578c4f8890Srs135747 91588c4f8890Srs135747 91598c4f8890Srs135747 /* 91608c4f8890Srs135747 * mdi_walk_vhcis(): 91618c4f8890Srs135747 * Walker routine to traverse vhci dev_info nodes 91628c4f8890Srs135747 */ 91638c4f8890Srs135747 void 91648c4f8890Srs135747 mdi_walk_vhcis(int (*f)(dev_info_t *, void *), void *arg) 91658c4f8890Srs135747 { 91668c4f8890Srs135747 mdi_vhci_t *vh = NULL; 91678c4f8890Srs135747 91688c4f8890Srs135747 mutex_enter(&mdi_mutex); 91698c4f8890Srs135747 /* 91708c4f8890Srs135747 * Scan for already registered vhci 91718c4f8890Srs135747 */ 91728c4f8890Srs135747 for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 91738c4f8890Srs135747 vh->vh_refcnt++; 91748c4f8890Srs135747 mutex_exit(&mdi_mutex); 91758c4f8890Srs135747 if (((*f)(vh->vh_dip, arg)) != DDI_WALK_CONTINUE) { 91768c4f8890Srs135747 mutex_enter(&mdi_mutex); 91778c4f8890Srs135747 vh->vh_refcnt--; 91788c4f8890Srs135747 break; 91798c4f8890Srs135747 } else { 91808c4f8890Srs135747 mutex_enter(&mdi_mutex); 91818c4f8890Srs135747 vh->vh_refcnt--; 91828c4f8890Srs135747 } 91838c4f8890Srs135747 } 91848c4f8890Srs135747 91858c4f8890Srs135747 mutex_exit(&mdi_mutex); 91868c4f8890Srs135747 } 91878c4f8890Srs135747 91888c4f8890Srs135747 /* 91898c4f8890Srs135747 * i_mdi_log_sysevent(): 91908c4f8890Srs135747 * Logs events for pickup by syseventd 91918c4f8890Srs135747 */ 91928c4f8890Srs135747 static void 91938c4f8890Srs135747 i_mdi_log_sysevent(dev_info_t *dip, char *ph_vh_class, char *subclass) 91948c4f8890Srs135747 { 91958c4f8890Srs135747 char *path_name; 91968c4f8890Srs135747 nvlist_t *attr_list; 91978c4f8890Srs135747 91988c4f8890Srs135747 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 91998c4f8890Srs135747 KM_SLEEP) != DDI_SUCCESS) { 92008c4f8890Srs135747 goto alloc_failed; 92018c4f8890Srs135747 } 92028c4f8890Srs135747 92038c4f8890Srs135747 path_name = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 92048c4f8890Srs135747 (void) ddi_pathname(dip, path_name); 92058c4f8890Srs135747 92068c4f8890Srs135747 if (nvlist_add_string(attr_list, DDI_DRIVER_NAME, 92078c4f8890Srs135747 ddi_driver_name(dip)) != DDI_SUCCESS) { 92088c4f8890Srs135747 goto error; 92098c4f8890Srs135747 } 92108c4f8890Srs135747 92118c4f8890Srs135747 if (nvlist_add_int32(attr_list, DDI_DRIVER_MAJOR, 92128c4f8890Srs135747 (int32_t)ddi_driver_major(dip)) != DDI_SUCCESS) { 92138c4f8890Srs135747 goto error; 92148c4f8890Srs135747 } 92158c4f8890Srs135747 92168c4f8890Srs135747 if (nvlist_add_int32(attr_list, DDI_INSTANCE, 92178c4f8890Srs135747 (int32_t)ddi_get_instance(dip)) != DDI_SUCCESS) { 92188c4f8890Srs135747 goto error; 92198c4f8890Srs135747 } 92208c4f8890Srs135747 92218c4f8890Srs135747 if (nvlist_add_string(attr_list, DDI_PATHNAME, 92228c4f8890Srs135747 path_name) != DDI_SUCCESS) { 92238c4f8890Srs135747 goto error; 92248c4f8890Srs135747 } 92258c4f8890Srs135747 92268c4f8890Srs135747 if (nvlist_add_string(attr_list, DDI_CLASS, 92278c4f8890Srs135747 ph_vh_class) != DDI_SUCCESS) { 92288c4f8890Srs135747 goto error; 92298c4f8890Srs135747 } 92308c4f8890Srs135747 92318c4f8890Srs135747 (void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_DDI, subclass, 92328c4f8890Srs135747 attr_list, NULL, DDI_SLEEP); 92338c4f8890Srs135747 92348c4f8890Srs135747 error: 92358c4f8890Srs135747 kmem_free(path_name, MAXPATHLEN); 92368c4f8890Srs135747 nvlist_free(attr_list); 92378c4f8890Srs135747 return; 92388c4f8890Srs135747 92398c4f8890Srs135747 alloc_failed: 92408c4f8890Srs135747 MDI_DEBUG(1, (CE_WARN, dip, 92418c4f8890Srs135747 "!i_mdi_log_sysevent: Unable to send sysevent")); 92428c4f8890Srs135747 } 9243f7209cf2Spramodbg 9244f7209cf2Spramodbg char ** 9245f7209cf2Spramodbg mdi_get_phci_driver_list(char *vhci_class, int *ndrivers) 9246f7209cf2Spramodbg { 9247f7209cf2Spramodbg char **driver_list, **ret_driver_list = NULL; 9248f7209cf2Spramodbg int *root_support_list; 9249f7209cf2Spramodbg int cur_elements, max_elements; 9250f7209cf2Spramodbg 9251f7209cf2Spramodbg get_phci_driver_list(vhci_class, &driver_list, &root_support_list, 9252f7209cf2Spramodbg &cur_elements, &max_elements); 9253f7209cf2Spramodbg 9254f7209cf2Spramodbg 9255f7209cf2Spramodbg if (driver_list) { 9256f7209cf2Spramodbg kmem_free(root_support_list, sizeof (int) * max_elements); 9257f7209cf2Spramodbg ret_driver_list = mdi_realloc(driver_list, sizeof (char *) 9258f7209cf2Spramodbg * max_elements, sizeof (char *) * cur_elements); 9259f7209cf2Spramodbg } 9260f7209cf2Spramodbg *ndrivers = cur_elements; 9261f7209cf2Spramodbg 9262f7209cf2Spramodbg return (ret_driver_list); 9263f7209cf2Spramodbg 9264f7209cf2Spramodbg } 9265f7209cf2Spramodbg 9266f7209cf2Spramodbg void 9267f7209cf2Spramodbg mdi_free_phci_driver_list(char **driver_list, int ndrivers) 9268f7209cf2Spramodbg { 9269f7209cf2Spramodbg char **p; 9270f7209cf2Spramodbg int i; 9271f7209cf2Spramodbg 9272f7209cf2Spramodbg if (driver_list) { 9273f7209cf2Spramodbg for (i = 0, p = driver_list; i < ndrivers; i++, p++) 9274f7209cf2Spramodbg kmem_free(*p, strlen(*p) + 1); 9275f7209cf2Spramodbg kmem_free(driver_list, sizeof (char *) * ndrivers); 9276f7209cf2Spramodbg } 9277f7209cf2Spramodbg } 9278