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 /* 22737d277aScth * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Multipath driver interface (MDI) implementation; see mdi_impl.h for a more 297c478bd9Sstevel@tonic-gate * detailed discussion of the overall mpxio architecture. 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * Default locking order: 327c478bd9Sstevel@tonic-gate * 33*c73a93f2Sdm120769 * _NOTE(LOCK_ORDER(mdi_mutex, mdi_phci::ph_mutex)) 34*c73a93f2Sdm120769 * _NOTE(LOCK_ORDER(mdi_mutex, mdi_client::ct_mutex)) 357c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 367c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex)) 377c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <sys/note.h> 417c478bd9Sstevel@tonic-gate #include <sys/types.h> 427c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 437c478bd9Sstevel@tonic-gate #include <sys/param.h> 447c478bd9Sstevel@tonic-gate #include <sys/errno.h> 457c478bd9Sstevel@tonic-gate #include <sys/uio.h> 467c478bd9Sstevel@tonic-gate #include <sys/buf.h> 477c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 487c478bd9Sstevel@tonic-gate #include <sys/open.h> 497c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 507c478bd9Sstevel@tonic-gate #include <sys/poll.h> 517c478bd9Sstevel@tonic-gate #include <sys/conf.h> 527c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 537c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 547c478bd9Sstevel@tonic-gate #include <sys/stat.h> 557c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 567c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 577c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h> 587c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 597c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 607c478bd9Sstevel@tonic-gate #include <sys/promif.h> 617c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h> 627c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h> 637c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 647c478bd9Sstevel@tonic-gate #include <sys/epm.h> 657c478bd9Sstevel@tonic-gate #include <sys/sunpm.h> 663c34adc5Sramat #include <sys/modhash.h> 678c4f8890Srs135747 #include <sys/disp.h> 688c4f8890Srs135747 #include <sys/autoconf.h> 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate #ifdef DEBUG 717c478bd9Sstevel@tonic-gate #include <sys/debug.h> 727c478bd9Sstevel@tonic-gate int mdi_debug = 1; 737c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) \ 747c478bd9Sstevel@tonic-gate if (mdi_debug >= (level)) i_mdi_log stmnt 757c478bd9Sstevel@tonic-gate static void i_mdi_log(int, dev_info_t *, const char *fmt, ...); 767c478bd9Sstevel@tonic-gate #else /* !DEBUG */ 777c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) 787c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; 817c478bd9Sstevel@tonic-gate extern int modrootloaded; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * Global mutex: 85*c73a93f2Sdm120769 * Protects vHCI list and structure members, pHCI and Client lists. 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate kmutex_t mdi_mutex; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * Registered vHCI class driver lists 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate int mdi_vhci_count; 937c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_head; 947c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_tail; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * Client Hash Table size 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate static int mdi_client_table_size = CLIENT_HASH_TABLE_SIZE; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * taskq interface definitions 1037c478bd9Sstevel@tonic-gate */ 1047c478bd9Sstevel@tonic-gate #define MDI_TASKQ_N_THREADS 8 1057c478bd9Sstevel@tonic-gate #define MDI_TASKQ_PRI minclsyspri 1067c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MINALLOC (4*mdi_taskq_n_threads) 1077c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MAXALLOC (500*mdi_taskq_n_threads) 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate taskq_t *mdi_taskq; 1107c478bd9Sstevel@tonic-gate static uint_t mdi_taskq_n_threads = MDI_TASKQ_N_THREADS; 1117c478bd9Sstevel@tonic-gate 1123c34adc5Sramat #define TICKS_PER_SECOND (drv_usectohz(1000000)) 1133c34adc5Sramat 1147c478bd9Sstevel@tonic-gate /* 1153c34adc5Sramat * The data should be "quiet" for this interval (in seconds) before the 1163c34adc5Sramat * vhci cached data is flushed to the disk. 1177c478bd9Sstevel@tonic-gate */ 1183c34adc5Sramat static int mdi_vhcache_flush_delay = 10; 1193c34adc5Sramat 1203c34adc5Sramat /* number of seconds the vhcache flush daemon will sleep idle before exiting */ 1213c34adc5Sramat static int mdi_vhcache_flush_daemon_idle_time = 60; 1223c34adc5Sramat 1233c34adc5Sramat /* 12467e56d35Sramat * MDI falls back to discovery of all paths when a bus_config_one fails. 12567e56d35Sramat * The following parameters can be used to tune this operation. 12667e56d35Sramat * 12767e56d35Sramat * mdi_path_discovery_boot 12867e56d35Sramat * Number of times path discovery will be attempted during early boot. 12967e56d35Sramat * Probably there is no reason to ever set this value to greater than one. 13067e56d35Sramat * 13167e56d35Sramat * mdi_path_discovery_postboot 13267e56d35Sramat * Number of times path discovery will be attempted after early boot. 13367e56d35Sramat * Set it to a minimum of two to allow for discovery of iscsi paths which 13467e56d35Sramat * may happen very late during booting. 13567e56d35Sramat * 13667e56d35Sramat * mdi_path_discovery_interval 13767e56d35Sramat * Minimum number of seconds MDI will wait between successive discovery 13867e56d35Sramat * of all paths. Set it to -1 to disable discovery of all paths. 13967e56d35Sramat */ 14067e56d35Sramat static int mdi_path_discovery_boot = 1; 14167e56d35Sramat static int mdi_path_discovery_postboot = 2; 14267e56d35Sramat static int mdi_path_discovery_interval = 10; 14367e56d35Sramat 14467e56d35Sramat /* 1453c34adc5Sramat * number of seconds the asynchronous configuration thread will sleep idle 1463c34adc5Sramat * before exiting. 1473c34adc5Sramat */ 1483c34adc5Sramat static int mdi_async_config_idle_time = 600; 1493c34adc5Sramat 1503c34adc5Sramat static int mdi_bus_config_cache_hash_size = 256; 1513c34adc5Sramat 1523c34adc5Sramat /* turns off multithreaded configuration for certain operations */ 1533c34adc5Sramat static int mdi_mtc_off = 0; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* 1567c478bd9Sstevel@tonic-gate * MDI component property name/value string definitions 1577c478bd9Sstevel@tonic-gate */ 1587c478bd9Sstevel@tonic-gate const char *mdi_component_prop = "mpxio-component"; 1597c478bd9Sstevel@tonic-gate const char *mdi_component_prop_vhci = "vhci"; 1607c478bd9Sstevel@tonic-gate const char *mdi_component_prop_phci = "phci"; 1617c478bd9Sstevel@tonic-gate const char *mdi_component_prop_client = "client"; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate /* 1647c478bd9Sstevel@tonic-gate * MDI client global unique identifier property name 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate const char *mdi_client_guid_prop = "client-guid"; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* 1697c478bd9Sstevel@tonic-gate * MDI client load balancing property name/value string definitions 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate const char *mdi_load_balance = "load-balance"; 1727c478bd9Sstevel@tonic-gate const char *mdi_load_balance_none = "none"; 1737c478bd9Sstevel@tonic-gate const char *mdi_load_balance_rr = "round-robin"; 1747c478bd9Sstevel@tonic-gate const char *mdi_load_balance_lba = "logical-block"; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * Obsolete vHCI class definition; to be removed after Leadville update 1787c478bd9Sstevel@tonic-gate */ 1797c478bd9Sstevel@tonic-gate const char *mdi_vhci_class_scsi = MDI_HCI_CLASS_SCSI; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate static char vhci_greeting[] = 1827c478bd9Sstevel@tonic-gate "\tThere already exists one vHCI driver for class %s\n" 1837c478bd9Sstevel@tonic-gate "\tOnly one vHCI driver for each class is allowed\n"; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* 1867c478bd9Sstevel@tonic-gate * Static function prototypes 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate static int i_mdi_phci_offline(dev_info_t *, uint_t); 1897c478bd9Sstevel@tonic-gate static int i_mdi_client_offline(dev_info_t *, uint_t); 1907c478bd9Sstevel@tonic-gate static int i_mdi_phci_pre_detach(dev_info_t *, ddi_detach_cmd_t); 1917c478bd9Sstevel@tonic-gate static void i_mdi_phci_post_detach(dev_info_t *, 1927c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 1937c478bd9Sstevel@tonic-gate static int i_mdi_client_pre_detach(dev_info_t *, 1947c478bd9Sstevel@tonic-gate ddi_detach_cmd_t); 1957c478bd9Sstevel@tonic-gate static void i_mdi_client_post_detach(dev_info_t *, 1967c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 1977c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_pip(mdi_pathinfo_t *); 1987c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_pip(mdi_pathinfo_t *); 1997c478bd9Sstevel@tonic-gate static int i_mdi_lba_lb(mdi_client_t *ct, 2007c478bd9Sstevel@tonic-gate mdi_pathinfo_t **ret_pip, struct buf *buf); 2017c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_client(mdi_client_t *, int); 2027c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_client(mdi_client_t *, int); 2037c478bd9Sstevel@tonic-gate static void i_mdi_pm_reset_client(mdi_client_t *); 204*c73a93f2Sdm120769 static void i_mdi_pm_hold_all_phci(mdi_client_t *); 2057c478bd9Sstevel@tonic-gate static int i_mdi_power_all_phci(mdi_client_t *); 2068c4f8890Srs135747 static void i_mdi_log_sysevent(dev_info_t *, char *, char *); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate /* 2107c478bd9Sstevel@tonic-gate * Internal mdi_pathinfo node functions 2117c478bd9Sstevel@tonic-gate */ 2127c478bd9Sstevel@tonic-gate static int i_mdi_pi_kstat_create(mdi_pathinfo_t *); 2137c478bd9Sstevel@tonic-gate static void i_mdi_pi_kstat_destroy(mdi_pathinfo_t *); 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_mdi_vhci_class2vhci(char *); 2167c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_devi_get_vhci(dev_info_t *); 2177c478bd9Sstevel@tonic-gate static mdi_phci_t *i_devi_get_phci(dev_info_t *); 2187c478bd9Sstevel@tonic-gate static void i_mdi_phci_lock(mdi_phci_t *, mdi_pathinfo_t *); 219*c73a93f2Sdm120769 static void i_mdi_phci_get_client_lock(mdi_phci_t *, 220*c73a93f2Sdm120769 mdi_client_t *); 2217c478bd9Sstevel@tonic-gate static void i_mdi_phci_unlock(mdi_phci_t *); 2223c34adc5Sramat static mdi_pathinfo_t *i_mdi_pi_alloc(mdi_phci_t *, char *, mdi_client_t *); 2237c478bd9Sstevel@tonic-gate static void i_mdi_phci_add_path(mdi_phci_t *, mdi_pathinfo_t *); 2247c478bd9Sstevel@tonic-gate static void i_mdi_client_add_path(mdi_client_t *, mdi_pathinfo_t *); 2257c478bd9Sstevel@tonic-gate static void i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *, 2267c478bd9Sstevel@tonic-gate mdi_client_t *); 2277c478bd9Sstevel@tonic-gate static void i_mdi_phci_remove_path(mdi_phci_t *, mdi_pathinfo_t *); 2287c478bd9Sstevel@tonic-gate static void i_mdi_client_remove_path(mdi_client_t *, 2297c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate static int i_mdi_pi_state_change(mdi_pathinfo_t *, 2327c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t, int); 2337c478bd9Sstevel@tonic-gate static int i_mdi_pi_offline(mdi_pathinfo_t *, int); 2347c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_create(mdi_vhci_t *, char *, char *, 2353c34adc5Sramat char **, int); 2367c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_find(mdi_vhci_t *, char *, char *); 2377c478bd9Sstevel@tonic-gate static int i_mdi_devinfo_remove(dev_info_t *, dev_info_t *, int); 2387c478bd9Sstevel@tonic-gate static int i_mdi_is_child_present(dev_info_t *, dev_info_t *); 2393c34adc5Sramat static mdi_client_t *i_mdi_client_alloc(mdi_vhci_t *, char *, char *); 2407c478bd9Sstevel@tonic-gate static void i_mdi_client_enlist_table(mdi_vhci_t *, mdi_client_t *); 2417c478bd9Sstevel@tonic-gate static void i_mdi_client_delist_table(mdi_vhci_t *, mdi_client_t *); 2423c34adc5Sramat static mdi_client_t *i_mdi_client_find(mdi_vhci_t *, char *, char *); 2437c478bd9Sstevel@tonic-gate static void i_mdi_client_update_state(mdi_client_t *); 2447c478bd9Sstevel@tonic-gate static int i_mdi_client_compute_state(mdi_client_t *, 2457c478bd9Sstevel@tonic-gate mdi_phci_t *); 2467c478bd9Sstevel@tonic-gate static void i_mdi_client_lock(mdi_client_t *, mdi_pathinfo_t *); 2477c478bd9Sstevel@tonic-gate static void i_mdi_client_unlock(mdi_client_t *); 2487c478bd9Sstevel@tonic-gate static int i_mdi_client_free(mdi_vhci_t *, mdi_client_t *); 2497c478bd9Sstevel@tonic-gate static mdi_client_t *i_devi_get_client(dev_info_t *); 250ee28b439Scm136836 /* 251ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 252ee28b439Scm136836 * mdi_{enable,disable}_path interfaces 253ee28b439Scm136836 */ 254ee28b439Scm136836 static int i_mdi_pi_enable_disable(dev_info_t *, dev_info_t *, 255ee28b439Scm136836 int, int); 256ee28b439Scm136836 static mdi_pathinfo_t *i_mdi_enable_disable_path(mdi_pathinfo_t *pip, 257ee28b439Scm136836 mdi_vhci_t *vh, int flags, int op); 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * Failover related function prototypes 2607c478bd9Sstevel@tonic-gate */ 2617c478bd9Sstevel@tonic-gate static int i_mdi_failover(void *); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* 2647c478bd9Sstevel@tonic-gate * misc internal functions 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate static int i_mdi_get_hash_key(char *); 2677c478bd9Sstevel@tonic-gate static int i_map_nvlist_error_to_mdi(int); 2687c478bd9Sstevel@tonic-gate static void i_mdi_report_path_state(mdi_client_t *, 2697c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 2707c478bd9Sstevel@tonic-gate 2713c34adc5Sramat static void setup_vhci_cache(mdi_vhci_t *); 2723c34adc5Sramat static int destroy_vhci_cache(mdi_vhci_t *); 2733c34adc5Sramat static int stop_vhcache_async_threads(mdi_vhci_config_t *); 2743c34adc5Sramat static boolean_t stop_vhcache_flush_thread(void *, int); 2753c34adc5Sramat static void free_string_array(char **, int); 2763c34adc5Sramat static void free_vhcache_phci(mdi_vhcache_phci_t *); 2773c34adc5Sramat static void free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *); 2783c34adc5Sramat static void free_vhcache_client(mdi_vhcache_client_t *); 2793c34adc5Sramat static int mainnvl_to_vhcache(mdi_vhci_cache_t *, nvlist_t *); 2803c34adc5Sramat static nvlist_t *vhcache_to_mainnvl(mdi_vhci_cache_t *); 2813c34adc5Sramat static void vhcache_phci_add(mdi_vhci_config_t *, mdi_phci_t *); 2823c34adc5Sramat static void vhcache_phci_remove(mdi_vhci_config_t *, mdi_phci_t *); 2833c34adc5Sramat static void vhcache_pi_add(mdi_vhci_config_t *, 2843c34adc5Sramat struct mdi_pathinfo *); 2853c34adc5Sramat static void vhcache_pi_remove(mdi_vhci_config_t *, 2863c34adc5Sramat struct mdi_pathinfo *); 2873c34adc5Sramat static void free_phclient_path_list(mdi_phys_path_t *); 2883c34adc5Sramat static void sort_vhcache_paths(mdi_vhcache_client_t *); 2893c34adc5Sramat static int flush_vhcache(mdi_vhci_config_t *, int); 2903c34adc5Sramat static void vhcache_dirty(mdi_vhci_config_t *); 2913c34adc5Sramat static void free_async_client_config(mdi_async_client_config_t *); 29267e56d35Sramat static void single_threaded_vhconfig_enter(mdi_vhci_config_t *); 29367e56d35Sramat static void single_threaded_vhconfig_exit(mdi_vhci_config_t *); 2943c34adc5Sramat static nvlist_t *read_on_disk_vhci_cache(char *); 2953c34adc5Sramat extern int fread_nvlist(char *, nvlist_t **); 2963c34adc5Sramat extern int fwrite_nvlist(char *, nvlist_t *); 2973c34adc5Sramat 2987c478bd9Sstevel@tonic-gate /* called once when first vhci registers with mdi */ 2997c478bd9Sstevel@tonic-gate static void 3007c478bd9Sstevel@tonic-gate i_mdi_init() 3017c478bd9Sstevel@tonic-gate { 3027c478bd9Sstevel@tonic-gate static int initialized = 0; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if (initialized) 3057c478bd9Sstevel@tonic-gate return; 3067c478bd9Sstevel@tonic-gate initialized = 1; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate mutex_init(&mdi_mutex, NULL, MUTEX_DEFAULT, NULL); 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * Create our taskq resources 3117c478bd9Sstevel@tonic-gate */ 3127c478bd9Sstevel@tonic-gate mdi_taskq = taskq_create("mdi_taskq", mdi_taskq_n_threads, 3137c478bd9Sstevel@tonic-gate MDI_TASKQ_PRI, MDI_TASKQ_MINALLOC, MDI_TASKQ_MAXALLOC, 3147c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE | TASKQ_CPR_SAFE); 3157c478bd9Sstevel@tonic-gate ASSERT(mdi_taskq != NULL); /* taskq_create never fails */ 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * mdi_get_component_type(): 3207c478bd9Sstevel@tonic-gate * Return mpxio component type 3217c478bd9Sstevel@tonic-gate * Return Values: 3227c478bd9Sstevel@tonic-gate * MDI_COMPONENT_NONE 3237c478bd9Sstevel@tonic-gate * MDI_COMPONENT_VHCI 3247c478bd9Sstevel@tonic-gate * MDI_COMPONENT_PHCI 3257c478bd9Sstevel@tonic-gate * MDI_COMPONENT_CLIENT 3267c478bd9Sstevel@tonic-gate * XXX This doesn't work under multi-level MPxIO and should be 327*c73a93f2Sdm120769 * removed when clients migrate mdi_is_*() interfaces. 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate int 3307c478bd9Sstevel@tonic-gate mdi_get_component_type(dev_info_t *dip) 3317c478bd9Sstevel@tonic-gate { 3327c478bd9Sstevel@tonic-gate return (DEVI(dip)->devi_mdi_component); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * mdi_vhci_register(): 3377c478bd9Sstevel@tonic-gate * Register a vHCI module with the mpxio framework 3387c478bd9Sstevel@tonic-gate * mdi_vhci_register() is called by vHCI drivers to register the 3397c478bd9Sstevel@tonic-gate * 'class_driver' vHCI driver and its MDI entrypoints with the 3407c478bd9Sstevel@tonic-gate * mpxio framework. The vHCI driver must call this interface as 3417c478bd9Sstevel@tonic-gate * part of its attach(9e) handler. 3427c478bd9Sstevel@tonic-gate * Competing threads may try to attach mdi_vhci_register() as 3437c478bd9Sstevel@tonic-gate * the vHCI drivers are loaded and attached as a result of pHCI 3447c478bd9Sstevel@tonic-gate * driver instance registration (mdi_phci_register()) with the 3457c478bd9Sstevel@tonic-gate * framework. 3467c478bd9Sstevel@tonic-gate * Return Values: 3477c478bd9Sstevel@tonic-gate * MDI_SUCCESS 3487c478bd9Sstevel@tonic-gate * MDI_FAILURE 3497c478bd9Sstevel@tonic-gate */ 350*c73a93f2Sdm120769 3517c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3527c478bd9Sstevel@tonic-gate int 3537c478bd9Sstevel@tonic-gate mdi_vhci_register(char *class, dev_info_t *vdip, mdi_vhci_ops_t *vops, 3547c478bd9Sstevel@tonic-gate int flags) 3557c478bd9Sstevel@tonic-gate { 3567c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate ASSERT(vops->vo_revision == MDI_VHCI_OPS_REV); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate i_mdi_init(); 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 3637c478bd9Sstevel@tonic-gate /* 3647c478bd9Sstevel@tonic-gate * Scan for already registered vhci 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 3677c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * vHCI has already been created. Check for valid 3707c478bd9Sstevel@tonic-gate * vHCI ops registration. We only support one vHCI 3717c478bd9Sstevel@tonic-gate * module per class 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate if (vh->vh_ops != NULL) { 3747c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 3757c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, vhci_greeting, class); 3767c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate break; 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * if not yet created, create the vHCI component 3847c478bd9Sstevel@tonic-gate */ 3857c478bd9Sstevel@tonic-gate if (vh == NULL) { 3867c478bd9Sstevel@tonic-gate struct client_hash *hash = NULL; 3877c478bd9Sstevel@tonic-gate char *load_balance; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate /* 3907c478bd9Sstevel@tonic-gate * Allocate and initialize the mdi extensions 3917c478bd9Sstevel@tonic-gate */ 3927c478bd9Sstevel@tonic-gate vh = kmem_zalloc(sizeof (mdi_vhci_t), KM_SLEEP); 3937c478bd9Sstevel@tonic-gate hash = kmem_zalloc(mdi_client_table_size * sizeof (*hash), 3947c478bd9Sstevel@tonic-gate KM_SLEEP); 3957c478bd9Sstevel@tonic-gate vh->vh_client_table = hash; 3967c478bd9Sstevel@tonic-gate vh->vh_class = kmem_zalloc(strlen(class) + 1, KM_SLEEP); 3977c478bd9Sstevel@tonic-gate (void) strcpy(vh->vh_class, class); 3987c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_RR; 3997c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vdip, 4007c478bd9Sstevel@tonic-gate 0, LOAD_BALANCE_PROP, &load_balance) == DDI_SUCCESS) { 4017c478bd9Sstevel@tonic-gate if (strcmp(load_balance, LOAD_BALANCE_PROP_NONE) == 0) { 4027c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_NONE; 4037c478bd9Sstevel@tonic-gate } else if (strcmp(load_balance, LOAD_BALANCE_PROP_LBA) 4047c478bd9Sstevel@tonic-gate == 0) { 4057c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_LBA; 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate ddi_prop_free(load_balance); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * Store the vHCI ops vectors 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate vh->vh_dip = vdip; 4147c478bd9Sstevel@tonic-gate vh->vh_ops = vops; 4157c478bd9Sstevel@tonic-gate 4163c34adc5Sramat setup_vhci_cache(vh); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate if (mdi_vhci_head == NULL) { 4197c478bd9Sstevel@tonic-gate mdi_vhci_head = vh; 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate if (mdi_vhci_tail) { 4227c478bd9Sstevel@tonic-gate mdi_vhci_tail->vh_next = vh; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate mdi_vhci_tail = vh; 4257c478bd9Sstevel@tonic-gate mdi_vhci_count++; 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* 4297c478bd9Sstevel@tonic-gate * Claim the devfs node as a vhci component 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component |= MDI_COMPONENT_VHCI; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate /* 4347c478bd9Sstevel@tonic-gate * Initialize our back reference from dev_info node 4357c478bd9Sstevel@tonic-gate */ 4367c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = (caddr_t)vh; 4377c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4387c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* 4427c478bd9Sstevel@tonic-gate * mdi_vhci_unregister(): 4437c478bd9Sstevel@tonic-gate * Unregister a vHCI module from mpxio framework 4447c478bd9Sstevel@tonic-gate * mdi_vhci_unregister() is called from the detach(9E) entrypoint 4457c478bd9Sstevel@tonic-gate * of a vhci to unregister it from the framework. 4467c478bd9Sstevel@tonic-gate * Return Values: 4477c478bd9Sstevel@tonic-gate * MDI_SUCCESS 4487c478bd9Sstevel@tonic-gate * MDI_FAILURE 4497c478bd9Sstevel@tonic-gate */ 450*c73a93f2Sdm120769 4517c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4527c478bd9Sstevel@tonic-gate int 4537c478bd9Sstevel@tonic-gate mdi_vhci_unregister(dev_info_t *vdip, int flags) 4547c478bd9Sstevel@tonic-gate { 4557c478bd9Sstevel@tonic-gate mdi_vhci_t *found, *vh, *prev = NULL; 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* 4587c478bd9Sstevel@tonic-gate * Check for invalid VHCI 4597c478bd9Sstevel@tonic-gate */ 4607c478bd9Sstevel@tonic-gate if ((vh = i_devi_get_vhci(vdip)) == NULL) 4617c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4627c478bd9Sstevel@tonic-gate 463*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 464*c73a93f2Sdm120769 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * Scan the list of registered vHCIs for a match 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate for (found = mdi_vhci_head; found != NULL; found = found->vh_next) { 4697c478bd9Sstevel@tonic-gate if (found == vh) 4707c478bd9Sstevel@tonic-gate break; 4717c478bd9Sstevel@tonic-gate prev = found; 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate if (found == NULL) { 4757c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4767c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate /* 4808c4f8890Srs135747 * Check the vHCI, pHCI and client count. All the pHCIs and clients 4817c478bd9Sstevel@tonic-gate * should have been unregistered, before a vHCI can be 4827c478bd9Sstevel@tonic-gate * unregistered. 4837c478bd9Sstevel@tonic-gate */ 484*c73a93f2Sdm120769 if (vh->vh_phci_count || vh->vh_client_count || vh->vh_refcnt) { 4857c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4867c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate /* 4907c478bd9Sstevel@tonic-gate * Remove the vHCI from the global list 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_head) { 4937c478bd9Sstevel@tonic-gate mdi_vhci_head = vh->vh_next; 4947c478bd9Sstevel@tonic-gate } else { 4957c478bd9Sstevel@tonic-gate prev->vh_next = vh->vh_next; 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_tail) { 4987c478bd9Sstevel@tonic-gate mdi_vhci_tail = prev; 4997c478bd9Sstevel@tonic-gate } 500*c73a93f2Sdm120769 5017c478bd9Sstevel@tonic-gate mdi_vhci_count--; 5027c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5033c34adc5Sramat 504*c73a93f2Sdm120769 if (destroy_vhci_cache(vh) != MDI_SUCCESS) { 505*c73a93f2Sdm120769 /* add vhci to the global list */ 506*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 507*c73a93f2Sdm120769 if (mdi_vhci_head == NULL) 508*c73a93f2Sdm120769 mdi_vhci_head = vh; 509*c73a93f2Sdm120769 else 510*c73a93f2Sdm120769 mdi_vhci_tail->vh_next = vh; 511*c73a93f2Sdm120769 mdi_vhci_tail = vh; 512*c73a93f2Sdm120769 mdi_vhci_count++; 513*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 514*c73a93f2Sdm120769 return (MDI_FAILURE); 515*c73a93f2Sdm120769 } 516*c73a93f2Sdm120769 5173c34adc5Sramat vh->vh_ops = NULL; 5187c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component &= ~MDI_COMPONENT_VHCI; 5197c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = NULL; 5207c478bd9Sstevel@tonic-gate kmem_free(vh->vh_class, strlen(vh->vh_class)+1); 5217c478bd9Sstevel@tonic-gate kmem_free(vh->vh_client_table, 5227c478bd9Sstevel@tonic-gate mdi_client_table_size * sizeof (struct client_hash)); 52378dc6db2Sllai1 5247c478bd9Sstevel@tonic-gate kmem_free(vh, sizeof (mdi_vhci_t)); 5257c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* 5297c478bd9Sstevel@tonic-gate * i_mdi_vhci_class2vhci(): 5307c478bd9Sstevel@tonic-gate * Look for a matching vHCI module given a vHCI class name 5317c478bd9Sstevel@tonic-gate * Return Values: 5327c478bd9Sstevel@tonic-gate * Handle to a vHCI component 5337c478bd9Sstevel@tonic-gate * NULL 5347c478bd9Sstevel@tonic-gate */ 5357c478bd9Sstevel@tonic-gate static mdi_vhci_t * 5367c478bd9Sstevel@tonic-gate i_mdi_vhci_class2vhci(char *class) 5377c478bd9Sstevel@tonic-gate { 5387c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&mdi_mutex)); 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 5437c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 5447c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 5457c478bd9Sstevel@tonic-gate break; 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5497c478bd9Sstevel@tonic-gate return (vh); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate /* 5537c478bd9Sstevel@tonic-gate * i_devi_get_vhci(): 5547c478bd9Sstevel@tonic-gate * Utility function to get the handle to a vHCI component 5557c478bd9Sstevel@tonic-gate * Return Values: 5567c478bd9Sstevel@tonic-gate * Handle to a vHCI component 5577c478bd9Sstevel@tonic-gate * NULL 5587c478bd9Sstevel@tonic-gate */ 5597c478bd9Sstevel@tonic-gate mdi_vhci_t * 5607c478bd9Sstevel@tonic-gate i_devi_get_vhci(dev_info_t *vdip) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 5637c478bd9Sstevel@tonic-gate if (MDI_VHCI(vdip)) { 5647c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci; 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate return (vh); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * mdi_phci_register(): 5717c478bd9Sstevel@tonic-gate * Register a pHCI module with mpxio framework 5727c478bd9Sstevel@tonic-gate * mdi_phci_register() is called by pHCI drivers to register with 5737c478bd9Sstevel@tonic-gate * the mpxio framework and a specific 'class_driver' vHCI. The 5747c478bd9Sstevel@tonic-gate * pHCI driver must call this interface as part of its attach(9e) 5757c478bd9Sstevel@tonic-gate * handler. 5767c478bd9Sstevel@tonic-gate * Return Values: 5777c478bd9Sstevel@tonic-gate * MDI_SUCCESS 5787c478bd9Sstevel@tonic-gate * MDI_FAILURE 5797c478bd9Sstevel@tonic-gate */ 580*c73a93f2Sdm120769 5817c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5827c478bd9Sstevel@tonic-gate int 5837c478bd9Sstevel@tonic-gate mdi_phci_register(char *class, dev_info_t *pdip, int flags) 5847c478bd9Sstevel@tonic-gate { 5857c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 5867c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 5877c478bd9Sstevel@tonic-gate char *data; 5887c478bd9Sstevel@tonic-gate char *pathname; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 5917c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, pathname); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * Check for mpxio-disable property. Enable mpxio if the property is 5957c478bd9Sstevel@tonic-gate * missing or not set to "yes". 5967c478bd9Sstevel@tonic-gate * If the property is set to "yes" then emit a brief message. 5977c478bd9Sstevel@tonic-gate */ 5987c478bd9Sstevel@tonic-gate if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0, "mpxio-disable", 5997c478bd9Sstevel@tonic-gate &data) == DDI_SUCCESS)) { 6007c478bd9Sstevel@tonic-gate if (strcmp(data, "yes") == 0) { 6017c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_CONT, pdip, 6027c478bd9Sstevel@tonic-gate "?%s (%s%d) multipath capabilities " 6037c478bd9Sstevel@tonic-gate "disabled via %s.conf.\n", pathname, 6047c478bd9Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip), 6057c478bd9Sstevel@tonic-gate ddi_driver_name(pdip))); 6067c478bd9Sstevel@tonic-gate ddi_prop_free(data); 6077c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 6087c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate ddi_prop_free(data); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate /* 6167c478bd9Sstevel@tonic-gate * Search for a matching vHCI 6177c478bd9Sstevel@tonic-gate */ 6187c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)i_mdi_vhci_class2vhci(class); 6197c478bd9Sstevel@tonic-gate if (vh == NULL) { 6207c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate ph = kmem_zalloc(sizeof (mdi_phci_t), KM_SLEEP); 6247c478bd9Sstevel@tonic-gate mutex_init(&ph->ph_mutex, NULL, MUTEX_DEFAULT, NULL); 6257c478bd9Sstevel@tonic-gate ph->ph_dip = pdip; 6267c478bd9Sstevel@tonic-gate ph->ph_vhci = vh; 6277c478bd9Sstevel@tonic-gate ph->ph_next = NULL; 6287c478bd9Sstevel@tonic-gate ph->ph_unstable = 0; 6297c478bd9Sstevel@tonic-gate ph->ph_vprivate = 0; 6307c478bd9Sstevel@tonic-gate cv_init(&ph->ph_unstable_cv, NULL, CV_DRIVER, NULL); 631*c73a93f2Sdm120769 cv_init(&ph->ph_powerchange_cv, NULL, CV_DRIVER, NULL); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate MDI_PHCI_SET_POWER_UP(ph); 6347c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component |= MDI_COMPONENT_PHCI; 6357c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = (caddr_t)ph; 6367c478bd9Sstevel@tonic-gate 6373c34adc5Sramat vhcache_phci_add(vh->vh_config, ph); 6383c34adc5Sramat 639*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 6407c478bd9Sstevel@tonic-gate if (vh->vh_phci_head == NULL) { 6417c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph; 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate if (vh->vh_phci_tail) { 6447c478bd9Sstevel@tonic-gate vh->vh_phci_tail->ph_next = ph; 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate vh->vh_phci_tail = ph; 6477c478bd9Sstevel@tonic-gate vh->vh_phci_count++; 648*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 6498c4f8890Srs135747 i_mdi_log_sysevent(pdip, class, ESC_DDI_INITIATOR_REGISTER); 6507c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate /* 6547c478bd9Sstevel@tonic-gate * mdi_phci_unregister(): 6557c478bd9Sstevel@tonic-gate * Unregister a pHCI module from mpxio framework 6567c478bd9Sstevel@tonic-gate * mdi_phci_unregister() is called by the pHCI drivers from their 6577c478bd9Sstevel@tonic-gate * detach(9E) handler to unregister their instances from the 6587c478bd9Sstevel@tonic-gate * framework. 6597c478bd9Sstevel@tonic-gate * Return Values: 6607c478bd9Sstevel@tonic-gate * MDI_SUCCESS 6617c478bd9Sstevel@tonic-gate * MDI_FAILURE 6627c478bd9Sstevel@tonic-gate */ 663*c73a93f2Sdm120769 6647c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6657c478bd9Sstevel@tonic-gate int 6667c478bd9Sstevel@tonic-gate mdi_phci_unregister(dev_info_t *pdip, int flags) 6677c478bd9Sstevel@tonic-gate { 6687c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 6697c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 6707c478bd9Sstevel@tonic-gate mdi_phci_t *tmp; 6717c478bd9Sstevel@tonic-gate mdi_phci_t *prev = NULL; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 6747c478bd9Sstevel@tonic-gate if (ph == NULL) { 6757c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 6767c478bd9Sstevel@tonic-gate "!pHCI unregister: Not a valid pHCI")); 6777c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 6817c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 6827c478bd9Sstevel@tonic-gate if (vh == NULL) { 6837c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 6847c478bd9Sstevel@tonic-gate "!pHCI unregister: Not a valid vHCI")); 6857c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate 688*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 6897c478bd9Sstevel@tonic-gate tmp = vh->vh_phci_head; 6907c478bd9Sstevel@tonic-gate while (tmp) { 6917c478bd9Sstevel@tonic-gate if (tmp == ph) { 6927c478bd9Sstevel@tonic-gate break; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate prev = tmp; 6957c478bd9Sstevel@tonic-gate tmp = tmp->ph_next; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_head) { 6997c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph->ph_next; 7007c478bd9Sstevel@tonic-gate } else { 7017c478bd9Sstevel@tonic-gate prev->ph_next = ph->ph_next; 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_tail) { 7057c478bd9Sstevel@tonic-gate vh->vh_phci_tail = prev; 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate vh->vh_phci_count--; 709*c73a93f2Sdm120769 710*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 7117c478bd9Sstevel@tonic-gate 7128c4f8890Srs135747 i_mdi_log_sysevent(pdip, ph->ph_vhci->vh_class, 7138c4f8890Srs135747 ESC_DDI_INITIATOR_UNREGISTER); 7143c34adc5Sramat vhcache_phci_remove(vh->vh_config, ph); 7157c478bd9Sstevel@tonic-gate cv_destroy(&ph->ph_unstable_cv); 716*c73a93f2Sdm120769 cv_destroy(&ph->ph_powerchange_cv); 7177c478bd9Sstevel@tonic-gate mutex_destroy(&ph->ph_mutex); 7187c478bd9Sstevel@tonic-gate kmem_free(ph, sizeof (mdi_phci_t)); 7197c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component &= ~MDI_COMPONENT_PHCI; 7207c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = NULL; 7217c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate /* 7257c478bd9Sstevel@tonic-gate * i_devi_get_phci(): 7267c478bd9Sstevel@tonic-gate * Utility function to return the phci extensions. 7277c478bd9Sstevel@tonic-gate */ 7287c478bd9Sstevel@tonic-gate static mdi_phci_t * 7297c478bd9Sstevel@tonic-gate i_devi_get_phci(dev_info_t *pdip) 7307c478bd9Sstevel@tonic-gate { 7317c478bd9Sstevel@tonic-gate mdi_phci_t *ph = NULL; 7327c478bd9Sstevel@tonic-gate if (MDI_PHCI(pdip)) { 7337c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(pdip)->devi_mdi_xhci; 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate return (ph); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate /* 7397c478bd9Sstevel@tonic-gate * mdi_phci_path2devinfo(): 7407c478bd9Sstevel@tonic-gate * Utility function to search for a valid phci device given 7417c478bd9Sstevel@tonic-gate * the devfs pathname. 7427c478bd9Sstevel@tonic-gate */ 743*c73a93f2Sdm120769 7447c478bd9Sstevel@tonic-gate dev_info_t * 7457c478bd9Sstevel@tonic-gate mdi_phci_path2devinfo(dev_info_t *vdip, caddr_t pathname) 7467c478bd9Sstevel@tonic-gate { 7477c478bd9Sstevel@tonic-gate char *temp_pathname; 7487c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 7497c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 7507c478bd9Sstevel@tonic-gate dev_info_t *pdip = NULL; 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate vh = i_devi_get_vhci(vdip); 7537c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate if (vh == NULL) { 7567c478bd9Sstevel@tonic-gate /* 7577c478bd9Sstevel@tonic-gate * Invalid vHCI component, return failure 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate return (NULL); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 763*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 7647c478bd9Sstevel@tonic-gate ph = vh->vh_phci_head; 7657c478bd9Sstevel@tonic-gate while (ph != NULL) { 7667c478bd9Sstevel@tonic-gate pdip = ph->ph_dip; 7677c478bd9Sstevel@tonic-gate ASSERT(pdip != NULL); 7687c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 7697c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, temp_pathname); 7707c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 7717c478bd9Sstevel@tonic-gate break; 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate ph = ph->ph_next; 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate if (ph == NULL) { 7767c478bd9Sstevel@tonic-gate pdip = NULL; 7777c478bd9Sstevel@tonic-gate } 778*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 7797c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 7807c478bd9Sstevel@tonic-gate return (pdip); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* 7847c478bd9Sstevel@tonic-gate * mdi_phci_get_path_count(): 7857c478bd9Sstevel@tonic-gate * get number of path information nodes associated with a given 7867c478bd9Sstevel@tonic-gate * pHCI device. 7877c478bd9Sstevel@tonic-gate */ 7887c478bd9Sstevel@tonic-gate int 7897c478bd9Sstevel@tonic-gate mdi_phci_get_path_count(dev_info_t *pdip) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 7927c478bd9Sstevel@tonic-gate int count = 0; 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 7957c478bd9Sstevel@tonic-gate if (ph != NULL) { 7967c478bd9Sstevel@tonic-gate count = ph->ph_path_count; 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate return (count); 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * i_mdi_phci_lock(): 8037c478bd9Sstevel@tonic-gate * Lock a pHCI device 8047c478bd9Sstevel@tonic-gate * Return Values: 8057c478bd9Sstevel@tonic-gate * None 8067c478bd9Sstevel@tonic-gate * Note: 8077c478bd9Sstevel@tonic-gate * The default locking order is: 8087c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 8097c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 8107c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 8117c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 8127c478bd9Sstevel@tonic-gate */ 8137c478bd9Sstevel@tonic-gate static void 8147c478bd9Sstevel@tonic-gate i_mdi_phci_lock(mdi_phci_t *ph, mdi_pathinfo_t *pip) 8157c478bd9Sstevel@tonic-gate { 8167c478bd9Sstevel@tonic-gate if (pip) { 8177c478bd9Sstevel@tonic-gate /* Reverse locking is requested. */ 8187c478bd9Sstevel@tonic-gate while (MDI_PHCI_TRYLOCK(ph) == 0) { 8197c478bd9Sstevel@tonic-gate /* 8207c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 8217c478bd9Sstevel@tonic-gate * after a small delay 8227c478bd9Sstevel@tonic-gate */ 8237c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 8247c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 8257c478bd9Sstevel@tonic-gate delay(1); 8267c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 8277c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate } else { 8307c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate /* 835*c73a93f2Sdm120769 * i_mdi_phci_get_client_lock(): 836*c73a93f2Sdm120769 * Lock a pHCI device 837*c73a93f2Sdm120769 * Return Values: 838*c73a93f2Sdm120769 * None 839*c73a93f2Sdm120769 * Note: 840*c73a93f2Sdm120769 * The default locking order is: 841*c73a93f2Sdm120769 * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex)) 842*c73a93f2Sdm120769 * But there are number of situations where locks need to be 843*c73a93f2Sdm120769 * grabbed in reverse order. This routine implements try and lock 844*c73a93f2Sdm120769 * mechanism depending on the requested parameter option. 845*c73a93f2Sdm120769 */ 846*c73a93f2Sdm120769 static void 847*c73a93f2Sdm120769 i_mdi_phci_get_client_lock(mdi_phci_t *ph, mdi_client_t *ct) 848*c73a93f2Sdm120769 { 849*c73a93f2Sdm120769 if (ct) { 850*c73a93f2Sdm120769 /* Reverse locking is requested. */ 851*c73a93f2Sdm120769 while (MDI_PHCI_TRYLOCK(ph) == 0) { 852*c73a93f2Sdm120769 /* 853*c73a93f2Sdm120769 * tryenter failed. Try to grab again 854*c73a93f2Sdm120769 * after a small delay 855*c73a93f2Sdm120769 */ 856*c73a93f2Sdm120769 MDI_CLIENT_UNLOCK(ct); 857*c73a93f2Sdm120769 delay(1); 858*c73a93f2Sdm120769 MDI_CLIENT_LOCK(ct); 859*c73a93f2Sdm120769 } 860*c73a93f2Sdm120769 } else { 861*c73a93f2Sdm120769 MDI_PHCI_LOCK(ph); 862*c73a93f2Sdm120769 } 863*c73a93f2Sdm120769 } 864*c73a93f2Sdm120769 865*c73a93f2Sdm120769 /* 8667c478bd9Sstevel@tonic-gate * i_mdi_phci_unlock(): 8677c478bd9Sstevel@tonic-gate * Unlock the pHCI component 8687c478bd9Sstevel@tonic-gate */ 8697c478bd9Sstevel@tonic-gate static void 8707c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(mdi_phci_t *ph) 8717c478bd9Sstevel@tonic-gate { 8727c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * i_mdi_devinfo_create(): 8777c478bd9Sstevel@tonic-gate * create client device's devinfo node 8787c478bd9Sstevel@tonic-gate * Return Values: 8797c478bd9Sstevel@tonic-gate * dev_info 8807c478bd9Sstevel@tonic-gate * NULL 8817c478bd9Sstevel@tonic-gate * Notes: 8827c478bd9Sstevel@tonic-gate */ 8837c478bd9Sstevel@tonic-gate static dev_info_t * 8847c478bd9Sstevel@tonic-gate i_mdi_devinfo_create(mdi_vhci_t *vh, char *name, char *guid, 8853c34adc5Sramat char **compatible, int ncompatible) 8867c478bd9Sstevel@tonic-gate { 8877c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 8887c478bd9Sstevel@tonic-gate 889*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&mdi_mutex)); 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate /* Verify for duplicate entry */ 8927c478bd9Sstevel@tonic-gate cdip = i_mdi_devinfo_find(vh, name, guid); 8937c478bd9Sstevel@tonic-gate ASSERT(cdip == NULL); 8947c478bd9Sstevel@tonic-gate if (cdip) { 8957c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8967c478bd9Sstevel@tonic-gate "i_mdi_devinfo_create: client dip %p already exists", 8977c478bd9Sstevel@tonic-gate (void *)cdip); 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate 9003c34adc5Sramat ndi_devi_alloc_sleep(vh->vh_dip, name, DEVI_SID_NODEID, &cdip); 9017c478bd9Sstevel@tonic-gate if (cdip == NULL) 9027c478bd9Sstevel@tonic-gate goto fail; 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * Create component type and Global unique identifier 9067c478bd9Sstevel@tonic-gate * properties 9077c478bd9Sstevel@tonic-gate */ 9087c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, 9097c478bd9Sstevel@tonic-gate MDI_CLIENT_GUID_PROP, guid) != DDI_PROP_SUCCESS) { 9107c478bd9Sstevel@tonic-gate goto fail; 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* Decorate the node with compatible property */ 9147c478bd9Sstevel@tonic-gate if (compatible && 9157c478bd9Sstevel@tonic-gate (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip, 9167c478bd9Sstevel@tonic-gate "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS)) { 9177c478bd9Sstevel@tonic-gate goto fail; 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate return (cdip); 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate fail: 9237c478bd9Sstevel@tonic-gate if (cdip) { 9247c478bd9Sstevel@tonic-gate (void) ndi_prop_remove_all(cdip); 9257c478bd9Sstevel@tonic-gate (void) ndi_devi_free(cdip); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate return (NULL); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate /* 9317c478bd9Sstevel@tonic-gate * i_mdi_devinfo_find(): 9327c478bd9Sstevel@tonic-gate * Find a matching devinfo node for given client node name 9337c478bd9Sstevel@tonic-gate * and its guid. 9347c478bd9Sstevel@tonic-gate * Return Values: 9357c478bd9Sstevel@tonic-gate * Handle to a dev_info node or NULL 9367c478bd9Sstevel@tonic-gate */ 937*c73a93f2Sdm120769 9387c478bd9Sstevel@tonic-gate static dev_info_t * 9397c478bd9Sstevel@tonic-gate i_mdi_devinfo_find(mdi_vhci_t *vh, caddr_t name, char *guid) 9407c478bd9Sstevel@tonic-gate { 9417c478bd9Sstevel@tonic-gate char *data; 9427c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 9437c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 9447c478bd9Sstevel@tonic-gate int circular; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate ndi_devi_enter(vh->vh_dip, &circular); 9477c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vh->vh_dip)->devi_child; 9487c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 9497c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate if (strcmp(DEVI(cdip)->devi_node_name, name)) { 9527c478bd9Sstevel@tonic-gate continue; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip, 9567c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, MDI_CLIENT_GUID_PROP, 9577c478bd9Sstevel@tonic-gate &data) != DDI_PROP_SUCCESS) { 9587c478bd9Sstevel@tonic-gate continue; 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate if (strcmp(data, guid) != 0) { 9627c478bd9Sstevel@tonic-gate ddi_prop_free(data); 9637c478bd9Sstevel@tonic-gate continue; 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate ddi_prop_free(data); 9667c478bd9Sstevel@tonic-gate break; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate ndi_devi_exit(vh->vh_dip, circular); 9697c478bd9Sstevel@tonic-gate return (cdip); 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * i_mdi_devinfo_remove(): 9747c478bd9Sstevel@tonic-gate * Remove a client device node 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate static int 9777c478bd9Sstevel@tonic-gate i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags) 9787c478bd9Sstevel@tonic-gate { 9797c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 9807c478bd9Sstevel@tonic-gate if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS || 9817c478bd9Sstevel@tonic-gate (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) { 9827c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 9837c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 9847c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_devinfo_remove:" 985*c73a93f2Sdm120769 " failed. cdip = %p\n", cdip)); 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate /* 9887c478bd9Sstevel@tonic-gate * Convert to MDI error code 9897c478bd9Sstevel@tonic-gate */ 9907c478bd9Sstevel@tonic-gate switch (rv) { 9917c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 9927c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 9937c478bd9Sstevel@tonic-gate break; 9947c478bd9Sstevel@tonic-gate case NDI_BUSY: 9957c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 9967c478bd9Sstevel@tonic-gate break; 9977c478bd9Sstevel@tonic-gate default: 9987c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 9997c478bd9Sstevel@tonic-gate break; 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate return (rv); 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate /* 10067c478bd9Sstevel@tonic-gate * i_devi_get_client() 10077c478bd9Sstevel@tonic-gate * Utility function to get mpxio component extensions 10087c478bd9Sstevel@tonic-gate */ 10097c478bd9Sstevel@tonic-gate static mdi_client_t * 10107c478bd9Sstevel@tonic-gate i_devi_get_client(dev_info_t *cdip) 10117c478bd9Sstevel@tonic-gate { 10127c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 10137c478bd9Sstevel@tonic-gate if (MDI_CLIENT(cdip)) { 10147c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(cdip)->devi_mdi_client; 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate return (ct); 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* 10207c478bd9Sstevel@tonic-gate * i_mdi_is_child_present(): 10217c478bd9Sstevel@tonic-gate * Search for the presence of client device dev_info node 10227c478bd9Sstevel@tonic-gate */ 1023*c73a93f2Sdm120769 10247c478bd9Sstevel@tonic-gate static int 10257c478bd9Sstevel@tonic-gate i_mdi_is_child_present(dev_info_t *vdip, dev_info_t *cdip) 10267c478bd9Sstevel@tonic-gate { 10277c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 10287c478bd9Sstevel@tonic-gate struct dev_info *dip; 10297c478bd9Sstevel@tonic-gate int circular; 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 10327c478bd9Sstevel@tonic-gate dip = DEVI(vdip)->devi_child; 10337c478bd9Sstevel@tonic-gate while (dip) { 10347c478bd9Sstevel@tonic-gate if (dip == DEVI(cdip)) { 10357c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 10367c478bd9Sstevel@tonic-gate break; 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate dip = dip->devi_sibling; 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 10417c478bd9Sstevel@tonic-gate return (rv); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate /* 10467c478bd9Sstevel@tonic-gate * i_mdi_client_lock(): 10477c478bd9Sstevel@tonic-gate * Grab client component lock 10487c478bd9Sstevel@tonic-gate * Return Values: 10497c478bd9Sstevel@tonic-gate * None 10507c478bd9Sstevel@tonic-gate * Note: 10517c478bd9Sstevel@tonic-gate * The default locking order is: 10527c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 10537c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 10547c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 10557c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 10567c478bd9Sstevel@tonic-gate */ 1057*c73a93f2Sdm120769 10587c478bd9Sstevel@tonic-gate static void 10597c478bd9Sstevel@tonic-gate i_mdi_client_lock(mdi_client_t *ct, mdi_pathinfo_t *pip) 10607c478bd9Sstevel@tonic-gate { 10617c478bd9Sstevel@tonic-gate if (pip) { 10627c478bd9Sstevel@tonic-gate /* 10637c478bd9Sstevel@tonic-gate * Reverse locking is requested. 10647c478bd9Sstevel@tonic-gate */ 10657c478bd9Sstevel@tonic-gate while (MDI_CLIENT_TRYLOCK(ct) == 0) { 10667c478bd9Sstevel@tonic-gate /* 10677c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 10687c478bd9Sstevel@tonic-gate * after a small delay 10697c478bd9Sstevel@tonic-gate */ 10707c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 10717c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 10727c478bd9Sstevel@tonic-gate delay(1); 10737c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 10747c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate } else { 10777c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * i_mdi_client_unlock(): 10837c478bd9Sstevel@tonic-gate * Unlock a client component 10847c478bd9Sstevel@tonic-gate */ 1085*c73a93f2Sdm120769 10867c478bd9Sstevel@tonic-gate static void 10877c478bd9Sstevel@tonic-gate i_mdi_client_unlock(mdi_client_t *ct) 10887c478bd9Sstevel@tonic-gate { 10897c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate /* 10937c478bd9Sstevel@tonic-gate * i_mdi_client_alloc(): 10947c478bd9Sstevel@tonic-gate * Allocate and initialize a client structure. Caller should 1095*c73a93f2Sdm120769 * hold the global mdi_mutex. 10967c478bd9Sstevel@tonic-gate * Return Values: 10977c478bd9Sstevel@tonic-gate * Handle to a client component 10987c478bd9Sstevel@tonic-gate */ 10997c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11007c478bd9Sstevel@tonic-gate static mdi_client_t * 11013c34adc5Sramat i_mdi_client_alloc(mdi_vhci_t *vh, char *name, char *lguid) 11027c478bd9Sstevel@tonic-gate { 11037c478bd9Sstevel@tonic-gate mdi_client_t *ct; 11047c478bd9Sstevel@tonic-gate 1105*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&mdi_mutex)); 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate /* 11087c478bd9Sstevel@tonic-gate * Allocate and initialize a component structure. 11097c478bd9Sstevel@tonic-gate */ 11103c34adc5Sramat ct = kmem_zalloc(sizeof (*ct), KM_SLEEP); 11117c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); 11127c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 11137c478bd9Sstevel@tonic-gate ct->ct_hprev = NULL; 11147c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 11157c478bd9Sstevel@tonic-gate ct->ct_vhci = vh; 11163c34adc5Sramat ct->ct_drvname = kmem_alloc(strlen(name) + 1, KM_SLEEP); 11177c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_drvname, name); 11183c34adc5Sramat ct->ct_guid = kmem_alloc(strlen(lguid) + 1, KM_SLEEP); 11197c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_guid, lguid); 11207c478bd9Sstevel@tonic-gate ct->ct_cprivate = NULL; 11217c478bd9Sstevel@tonic-gate ct->ct_vprivate = NULL; 11227c478bd9Sstevel@tonic-gate ct->ct_flags = 0; 11237c478bd9Sstevel@tonic-gate ct->ct_state = MDI_CLIENT_STATE_FAILED; 11247c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 11257c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 11267c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 11277c478bd9Sstevel@tonic-gate ct->ct_failover_flags = 0; 11287c478bd9Sstevel@tonic-gate ct->ct_failover_status = 0; 11297c478bd9Sstevel@tonic-gate cv_init(&ct->ct_failover_cv, NULL, CV_DRIVER, NULL); 11307c478bd9Sstevel@tonic-gate ct->ct_unstable = 0; 11317c478bd9Sstevel@tonic-gate cv_init(&ct->ct_unstable_cv, NULL, CV_DRIVER, NULL); 11327c478bd9Sstevel@tonic-gate cv_init(&ct->ct_powerchange_cv, NULL, CV_DRIVER, NULL); 11337c478bd9Sstevel@tonic-gate ct->ct_lb = vh->vh_lb; 11343c34adc5Sramat ct->ct_lb_args = kmem_zalloc(sizeof (client_lb_args_t), KM_SLEEP); 11357c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = LOAD_BALANCE_DEFAULT_REGION_SIZE; 11367c478bd9Sstevel@tonic-gate ct->ct_path_count = 0; 11377c478bd9Sstevel@tonic-gate ct->ct_path_head = NULL; 11387c478bd9Sstevel@tonic-gate ct->ct_path_tail = NULL; 11397c478bd9Sstevel@tonic-gate ct->ct_path_last = NULL; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate /* 11427c478bd9Sstevel@tonic-gate * Add this client component to our client hash queue 11437c478bd9Sstevel@tonic-gate */ 11447c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(vh, ct); 11457c478bd9Sstevel@tonic-gate return (ct); 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate /* 11497c478bd9Sstevel@tonic-gate * i_mdi_client_enlist_table(): 11507c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. Caller 1151*c73a93f2Sdm120769 * should hold the mdi_mutex 11527c478bd9Sstevel@tonic-gate */ 1153*c73a93f2Sdm120769 11547c478bd9Sstevel@tonic-gate static void 11557c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(mdi_vhci_t *vh, mdi_client_t *ct) 11567c478bd9Sstevel@tonic-gate { 11577c478bd9Sstevel@tonic-gate int index; 11587c478bd9Sstevel@tonic-gate struct client_hash *head; 11597c478bd9Sstevel@tonic-gate 1160*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&mdi_mutex)); 11617c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(ct->ct_guid); 11627c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 11637c478bd9Sstevel@tonic-gate ct->ct_hnext = (mdi_client_t *)head->ct_hash_head; 11647c478bd9Sstevel@tonic-gate head->ct_hash_head = ct; 11657c478bd9Sstevel@tonic-gate head->ct_hash_count++; 11667c478bd9Sstevel@tonic-gate vh->vh_client_count++; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate /* 11707c478bd9Sstevel@tonic-gate * i_mdi_client_delist_table(): 11717c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. 1172*c73a93f2Sdm120769 * Caller should hold the mdi_mutex 11737c478bd9Sstevel@tonic-gate */ 1174*c73a93f2Sdm120769 11757c478bd9Sstevel@tonic-gate static void 11767c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(mdi_vhci_t *vh, mdi_client_t *ct) 11777c478bd9Sstevel@tonic-gate { 11787c478bd9Sstevel@tonic-gate int index; 11797c478bd9Sstevel@tonic-gate char *guid; 11807c478bd9Sstevel@tonic-gate struct client_hash *head; 11817c478bd9Sstevel@tonic-gate mdi_client_t *next; 11827c478bd9Sstevel@tonic-gate mdi_client_t *last; 11837c478bd9Sstevel@tonic-gate 1184*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&mdi_mutex)); 11857c478bd9Sstevel@tonic-gate guid = ct->ct_guid; 11867c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 11877c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate last = NULL; 11907c478bd9Sstevel@tonic-gate next = (mdi_client_t *)head->ct_hash_head; 11917c478bd9Sstevel@tonic-gate while (next != NULL) { 11927c478bd9Sstevel@tonic-gate if (next == ct) { 11937c478bd9Sstevel@tonic-gate break; 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate last = next; 11967c478bd9Sstevel@tonic-gate next = next->ct_hnext; 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate if (next) { 12007c478bd9Sstevel@tonic-gate head->ct_hash_count--; 12017c478bd9Sstevel@tonic-gate if (last == NULL) { 12027c478bd9Sstevel@tonic-gate head->ct_hash_head = ct->ct_hnext; 12037c478bd9Sstevel@tonic-gate } else { 12047c478bd9Sstevel@tonic-gate last->ct_hnext = ct->ct_hnext; 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 12077c478bd9Sstevel@tonic-gate vh->vh_client_count--; 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate } 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate /* 12137c478bd9Sstevel@tonic-gate * i_mdi_client_free(): 12147c478bd9Sstevel@tonic-gate * Free a client component 12157c478bd9Sstevel@tonic-gate */ 12167c478bd9Sstevel@tonic-gate static int 12177c478bd9Sstevel@tonic-gate i_mdi_client_free(mdi_vhci_t *vh, mdi_client_t *ct) 12187c478bd9Sstevel@tonic-gate { 12197c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 12207c478bd9Sstevel@tonic-gate int flags = ct->ct_flags; 12217c478bd9Sstevel@tonic-gate dev_info_t *cdip; 12227c478bd9Sstevel@tonic-gate dev_info_t *vdip; 12237c478bd9Sstevel@tonic-gate 1224*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&mdi_mutex)); 12257c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 12267c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, MDI_CLIENT_GUID_PROP); 12297c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component &= ~MDI_COMPONENT_CLIENT; 12307c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = NULL; 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate /* 12337c478bd9Sstevel@tonic-gate * Clear out back ref. to dev_info_t node 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate /* 12387c478bd9Sstevel@tonic-gate * Remove this client from our hash queue 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(vh, ct); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate /* 12437c478bd9Sstevel@tonic-gate * Uninitialize and free the component 12447c478bd9Sstevel@tonic-gate */ 12457c478bd9Sstevel@tonic-gate kmem_free(ct->ct_drvname, strlen(ct->ct_drvname) + 1); 12467c478bd9Sstevel@tonic-gate kmem_free(ct->ct_guid, strlen(ct->ct_guid) + 1); 12477c478bd9Sstevel@tonic-gate kmem_free(ct->ct_lb_args, sizeof (client_lb_args_t)); 12487c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_failover_cv); 12497c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_unstable_cv); 12507c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_powerchange_cv); 12517c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_mutex); 12527c478bd9Sstevel@tonic-gate kmem_free(ct, sizeof (*ct)); 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate if (cdip != NULL) { 1255*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 12567c478bd9Sstevel@tonic-gate (void) i_mdi_devinfo_remove(vdip, cdip, flags); 1257*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate return (rv); 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * i_mdi_client_find(): 12647c478bd9Sstevel@tonic-gate * Find the client structure corresponding to a given guid 1265*c73a93f2Sdm120769 * Caller should hold the mdi_mutex 12667c478bd9Sstevel@tonic-gate */ 12677c478bd9Sstevel@tonic-gate static mdi_client_t * 12683c34adc5Sramat i_mdi_client_find(mdi_vhci_t *vh, char *cname, char *guid) 12697c478bd9Sstevel@tonic-gate { 12707c478bd9Sstevel@tonic-gate int index; 12717c478bd9Sstevel@tonic-gate struct client_hash *head; 12727c478bd9Sstevel@tonic-gate mdi_client_t *ct; 12737c478bd9Sstevel@tonic-gate 1274*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&mdi_mutex)); 12757c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 12767c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate ct = head->ct_hash_head; 12797c478bd9Sstevel@tonic-gate while (ct != NULL) { 12803c34adc5Sramat if (strcmp(ct->ct_guid, guid) == 0 && 12813c34adc5Sramat (cname == NULL || strcmp(ct->ct_drvname, cname) == 0)) { 12827c478bd9Sstevel@tonic-gate break; 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate ct = ct->ct_hnext; 12857c478bd9Sstevel@tonic-gate } 12867c478bd9Sstevel@tonic-gate return (ct); 12877c478bd9Sstevel@tonic-gate } 12887c478bd9Sstevel@tonic-gate 1289*c73a93f2Sdm120769 1290*c73a93f2Sdm120769 12917c478bd9Sstevel@tonic-gate /* 12927c478bd9Sstevel@tonic-gate * i_mdi_client_update_state(): 12937c478bd9Sstevel@tonic-gate * Compute and update client device state 12947c478bd9Sstevel@tonic-gate * Notes: 12957c478bd9Sstevel@tonic-gate * A client device can be in any of three possible states: 12967c478bd9Sstevel@tonic-gate * 12977c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_OPTIMAL - Client in optimal state with more 12987c478bd9Sstevel@tonic-gate * one online/standby paths. Can tolerate failures. 12997c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_DEGRADED - Client device in degraded state with 13007c478bd9Sstevel@tonic-gate * no alternate paths available as standby. A failure on the online 13017c478bd9Sstevel@tonic-gate * would result in loss of access to device data. 13027c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_FAILED - Client device in failed state with 13037c478bd9Sstevel@tonic-gate * no paths available to access the device. 13047c478bd9Sstevel@tonic-gate */ 13057c478bd9Sstevel@tonic-gate static void 13067c478bd9Sstevel@tonic-gate i_mdi_client_update_state(mdi_client_t *ct) 13077c478bd9Sstevel@tonic-gate { 13087c478bd9Sstevel@tonic-gate int state; 1309*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&ct->ct_mutex)); 13107c478bd9Sstevel@tonic-gate state = i_mdi_client_compute_state(ct, NULL); 13117c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_STATE(ct, state); 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate /* 13157c478bd9Sstevel@tonic-gate * i_mdi_client_compute_state(): 13167c478bd9Sstevel@tonic-gate * Compute client device state 13177c478bd9Sstevel@tonic-gate * 13187c478bd9Sstevel@tonic-gate * mdi_phci_t * Pointer to pHCI structure which should 13197c478bd9Sstevel@tonic-gate * while computing the new value. Used by 13207c478bd9Sstevel@tonic-gate * i_mdi_phci_offline() to find the new 13217c478bd9Sstevel@tonic-gate * client state after DR of a pHCI. 13227c478bd9Sstevel@tonic-gate */ 13237c478bd9Sstevel@tonic-gate static int 13247c478bd9Sstevel@tonic-gate i_mdi_client_compute_state(mdi_client_t *ct, mdi_phci_t *ph) 13257c478bd9Sstevel@tonic-gate { 13267c478bd9Sstevel@tonic-gate int state; 13277c478bd9Sstevel@tonic-gate int online_count = 0; 13287c478bd9Sstevel@tonic-gate int standby_count = 0; 13297c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 13307c478bd9Sstevel@tonic-gate 1331*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&ct->ct_mutex)); 13327c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 13337c478bd9Sstevel@tonic-gate while (pip != NULL) { 13347c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 13357c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 13367c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 13377c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 13387c478bd9Sstevel@tonic-gate pip = next; 13397c478bd9Sstevel@tonic-gate continue; 13407c478bd9Sstevel@tonic-gate } 13417c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 13427c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_ONLINE) 13437c478bd9Sstevel@tonic-gate online_count++; 13447c478bd9Sstevel@tonic-gate else if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 13457c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_STANDBY) 13467c478bd9Sstevel@tonic-gate standby_count++; 13477c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 13487c478bd9Sstevel@tonic-gate pip = next; 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate if (online_count == 0) { 13527c478bd9Sstevel@tonic-gate if (standby_count == 0) { 13537c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_FAILED; 13547c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!client state: failed" 1355*c73a93f2Sdm120769 " ct = %p\n", ct)); 13567c478bd9Sstevel@tonic-gate } else if (standby_count == 1) { 13577c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 13587c478bd9Sstevel@tonic-gate } else { 13597c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate } else if (online_count == 1) { 13627c478bd9Sstevel@tonic-gate if (standby_count == 0) { 13637c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 13647c478bd9Sstevel@tonic-gate } else { 13657c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate } else { 13687c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate return (state); 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * i_mdi_client2devinfo(): 13757c478bd9Sstevel@tonic-gate * Utility function 13767c478bd9Sstevel@tonic-gate */ 13777c478bd9Sstevel@tonic-gate dev_info_t * 13787c478bd9Sstevel@tonic-gate i_mdi_client2devinfo(mdi_client_t *ct) 13797c478bd9Sstevel@tonic-gate { 13807c478bd9Sstevel@tonic-gate return (ct->ct_dip); 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate /* 13847c478bd9Sstevel@tonic-gate * mdi_client_path2_devinfo(): 13857c478bd9Sstevel@tonic-gate * Given the parent devinfo and child devfs pathname, search for 13867c478bd9Sstevel@tonic-gate * a valid devfs node handle. 13877c478bd9Sstevel@tonic-gate */ 13887c478bd9Sstevel@tonic-gate dev_info_t * 13897c478bd9Sstevel@tonic-gate mdi_client_path2devinfo(dev_info_t *vdip, char *pathname) 13907c478bd9Sstevel@tonic-gate { 13917c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 13927c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 13937c478bd9Sstevel@tonic-gate char *temp_pathname; 13947c478bd9Sstevel@tonic-gate int circular; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* 13977c478bd9Sstevel@tonic-gate * Allocate temp buffer 13987c478bd9Sstevel@tonic-gate */ 13997c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate /* 14027c478bd9Sstevel@tonic-gate * Lock parent against changes 14037c478bd9Sstevel@tonic-gate */ 14047c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 14057c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vdip)->devi_child; 14067c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 14077c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 14107c478bd9Sstevel@tonic-gate (void) ddi_pathname(cdip, temp_pathname); 14117c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 14127c478bd9Sstevel@tonic-gate break; 14137c478bd9Sstevel@tonic-gate } 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate /* 14167c478bd9Sstevel@tonic-gate * Release devinfo lock 14177c478bd9Sstevel@tonic-gate */ 14187c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * Free the temp buffer 14227c478bd9Sstevel@tonic-gate */ 14237c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 14247c478bd9Sstevel@tonic-gate return (cdip); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 1427*c73a93f2Sdm120769 14287c478bd9Sstevel@tonic-gate /* 14297c478bd9Sstevel@tonic-gate * mdi_client_get_path_count(): 14307c478bd9Sstevel@tonic-gate * Utility function to get number of path information nodes 14317c478bd9Sstevel@tonic-gate * associated with a given client device. 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate int 14347c478bd9Sstevel@tonic-gate mdi_client_get_path_count(dev_info_t *cdip) 14357c478bd9Sstevel@tonic-gate { 14367c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14377c478bd9Sstevel@tonic-gate int count = 0; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14407c478bd9Sstevel@tonic-gate if (ct != NULL) { 14417c478bd9Sstevel@tonic-gate count = ct->ct_path_count; 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate return (count); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* 14487c478bd9Sstevel@tonic-gate * i_mdi_get_hash_key(): 14497c478bd9Sstevel@tonic-gate * Create a hash using strings as keys 14507c478bd9Sstevel@tonic-gate * 14517c478bd9Sstevel@tonic-gate */ 14527c478bd9Sstevel@tonic-gate static int 14537c478bd9Sstevel@tonic-gate i_mdi_get_hash_key(char *str) 14547c478bd9Sstevel@tonic-gate { 14557c478bd9Sstevel@tonic-gate uint32_t g, hash = 0; 14567c478bd9Sstevel@tonic-gate char *p; 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate for (p = str; *p != '\0'; p++) { 14597c478bd9Sstevel@tonic-gate g = *p; 14607c478bd9Sstevel@tonic-gate hash += g; 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate return (hash % (CLIENT_HASH_TABLE_SIZE - 1)); 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate /* 14667c478bd9Sstevel@tonic-gate * mdi_get_lb_policy(): 14677c478bd9Sstevel@tonic-gate * Get current load balancing policy for a given client device 14687c478bd9Sstevel@tonic-gate */ 14697c478bd9Sstevel@tonic-gate client_lb_t 14707c478bd9Sstevel@tonic-gate mdi_get_lb_policy(dev_info_t *cdip) 14717c478bd9Sstevel@tonic-gate { 14727c478bd9Sstevel@tonic-gate client_lb_t lb = LOAD_BALANCE_NONE; 14737c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14767c478bd9Sstevel@tonic-gate if (ct != NULL) { 14777c478bd9Sstevel@tonic-gate lb = ct->ct_lb; 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate return (lb); 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate /* 14837c478bd9Sstevel@tonic-gate * mdi_set_lb_region_size(): 14847c478bd9Sstevel@tonic-gate * Set current region size for the load-balance 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate int 14877c478bd9Sstevel@tonic-gate mdi_set_lb_region_size(dev_info_t *cdip, int region_size) 14887c478bd9Sstevel@tonic-gate { 14897c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14907c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14937c478bd9Sstevel@tonic-gate if (ct != NULL && ct->ct_lb_args != NULL) { 14947c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = region_size; 14957c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate return (rv); 14987c478bd9Sstevel@tonic-gate } 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate /* 15017c478bd9Sstevel@tonic-gate * mdi_Set_lb_policy(): 15027c478bd9Sstevel@tonic-gate * Set current load balancing policy for a given client device 15037c478bd9Sstevel@tonic-gate */ 15047c478bd9Sstevel@tonic-gate int 15057c478bd9Sstevel@tonic-gate mdi_set_lb_policy(dev_info_t *cdip, client_lb_t lb) 15067c478bd9Sstevel@tonic-gate { 15077c478bd9Sstevel@tonic-gate mdi_client_t *ct; 15087c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 15117c478bd9Sstevel@tonic-gate if (ct != NULL) { 15127c478bd9Sstevel@tonic-gate ct->ct_lb = lb; 15137c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate return (rv); 15167c478bd9Sstevel@tonic-gate } 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate /* 15197c478bd9Sstevel@tonic-gate * mdi_failover(): 15207c478bd9Sstevel@tonic-gate * failover function called by the vHCI drivers to initiate 15217c478bd9Sstevel@tonic-gate * a failover operation. This is typically due to non-availability 15227c478bd9Sstevel@tonic-gate * of online paths to route I/O requests. Failover can be 15237c478bd9Sstevel@tonic-gate * triggered through user application also. 15247c478bd9Sstevel@tonic-gate * 15257c478bd9Sstevel@tonic-gate * The vHCI driver calls mdi_failover() to initiate a failover 15267c478bd9Sstevel@tonic-gate * operation. mdi_failover() calls back into the vHCI driver's 15277c478bd9Sstevel@tonic-gate * vo_failover() entry point to perform the actual failover 15287c478bd9Sstevel@tonic-gate * operation. The reason for requiring the vHCI driver to 15297c478bd9Sstevel@tonic-gate * initiate failover by calling mdi_failover(), instead of directly 15307c478bd9Sstevel@tonic-gate * executing vo_failover() itself, is to ensure that the mdi 15317c478bd9Sstevel@tonic-gate * framework can keep track of the client state properly. 15327c478bd9Sstevel@tonic-gate * Additionally, mdi_failover() provides as a convenience the 15337c478bd9Sstevel@tonic-gate * option of performing the failover operation synchronously or 15347c478bd9Sstevel@tonic-gate * asynchronously 15357c478bd9Sstevel@tonic-gate * 15367c478bd9Sstevel@tonic-gate * Upon successful completion of the failover operation, the 15377c478bd9Sstevel@tonic-gate * paths that were previously ONLINE will be in the STANDBY state, 15387c478bd9Sstevel@tonic-gate * and the newly activated paths will be in the ONLINE state. 15397c478bd9Sstevel@tonic-gate * 15407c478bd9Sstevel@tonic-gate * The flags modifier determines whether the activation is done 15417c478bd9Sstevel@tonic-gate * synchronously: MDI_FAILOVER_SYNC 15427c478bd9Sstevel@tonic-gate * Return Values: 15437c478bd9Sstevel@tonic-gate * MDI_SUCCESS 15447c478bd9Sstevel@tonic-gate * MDI_FAILURE 15457c478bd9Sstevel@tonic-gate * MDI_BUSY 15467c478bd9Sstevel@tonic-gate */ 15477c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15487c478bd9Sstevel@tonic-gate int 15497c478bd9Sstevel@tonic-gate mdi_failover(dev_info_t *vdip, dev_info_t *cdip, int flags) 15507c478bd9Sstevel@tonic-gate { 15517c478bd9Sstevel@tonic-gate int rv; 15527c478bd9Sstevel@tonic-gate mdi_client_t *ct; 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 15557c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 15567c478bd9Sstevel@tonic-gate if (ct == NULL) { 15577c478bd9Sstevel@tonic-gate /* cdip is not a valid client device. Nothing more to do. */ 15587c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_PATH_FREE_IN_PROGRESS(ct)) { 15647c478bd9Sstevel@tonic-gate /* A path to the client is being freed */ 15657c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15667c478bd9Sstevel@tonic-gate return (MDI_BUSY); 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 15717c478bd9Sstevel@tonic-gate /* 15727c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 15737c478bd9Sstevel@tonic-gate */ 15747c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15757c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 15797c478bd9Sstevel@tonic-gate /* 15807c478bd9Sstevel@tonic-gate * Failover is already in progress; return BUSY 15817c478bd9Sstevel@tonic-gate */ 15827c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15837c478bd9Sstevel@tonic-gate return (MDI_BUSY); 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate * Make sure that mdi_pathinfo node state changes are processed. 15877c478bd9Sstevel@tonic-gate * We do not allow failovers to progress while client path state 15887c478bd9Sstevel@tonic-gate * changes are in progress 15897c478bd9Sstevel@tonic-gate */ 15907c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 15917c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 15927c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15937c478bd9Sstevel@tonic-gate return (MDI_BUSY); 15947c478bd9Sstevel@tonic-gate } else { 15957c478bd9Sstevel@tonic-gate while (ct->ct_unstable) 15967c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_unstable_cv, &ct->ct_mutex); 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate /* 16017c478bd9Sstevel@tonic-gate * Client device is in stable state. Before proceeding, perform sanity 16027c478bd9Sstevel@tonic-gate * checks again. 16037c478bd9Sstevel@tonic-gate */ 16047c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct)) || (MDI_CLIENT_IS_FAILED(ct)) || 1605737d277aScth (!i_ddi_devi_attached(ct->ct_dip))) { 16067c478bd9Sstevel@tonic-gate /* 16077c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 16087c478bd9Sstevel@tonic-gate */ 16097c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 16107c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 16117c478bd9Sstevel@tonic-gate } 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate /* 16147c478bd9Sstevel@tonic-gate * Set the client state as failover in progress. 16157c478bd9Sstevel@tonic-gate */ 16167c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_FAILOVER_IN_PROGRESS(ct); 16177c478bd9Sstevel@tonic-gate ct->ct_failover_flags = flags; 16187c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * Submit the initiate failover request via CPR safe 16237c478bd9Sstevel@tonic-gate * taskq threads. 16247c478bd9Sstevel@tonic-gate */ 16257c478bd9Sstevel@tonic-gate (void) taskq_dispatch(mdi_taskq, (task_func_t *)i_mdi_failover, 16267c478bd9Sstevel@tonic-gate ct, KM_SLEEP); 16277c478bd9Sstevel@tonic-gate return (MDI_ACCEPT); 16287c478bd9Sstevel@tonic-gate } else { 16297c478bd9Sstevel@tonic-gate /* 16307c478bd9Sstevel@tonic-gate * Synchronous failover mode. Typically invoked from the user 16317c478bd9Sstevel@tonic-gate * land. 16327c478bd9Sstevel@tonic-gate */ 16337c478bd9Sstevel@tonic-gate rv = i_mdi_failover(ct); 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate return (rv); 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate /* 16397c478bd9Sstevel@tonic-gate * i_mdi_failover(): 16407c478bd9Sstevel@tonic-gate * internal failover function. Invokes vHCI drivers failover 16417c478bd9Sstevel@tonic-gate * callback function and process the failover status 16427c478bd9Sstevel@tonic-gate * Return Values: 16437c478bd9Sstevel@tonic-gate * None 16447c478bd9Sstevel@tonic-gate * 16457c478bd9Sstevel@tonic-gate * Note: A client device in failover state can not be detached or freed. 16467c478bd9Sstevel@tonic-gate */ 16477c478bd9Sstevel@tonic-gate static int 16487c478bd9Sstevel@tonic-gate i_mdi_failover(void *arg) 16497c478bd9Sstevel@tonic-gate { 16507c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 16517c478bd9Sstevel@tonic-gate mdi_client_t *ct = (mdi_client_t *)arg; 16527c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = ct->ct_vhci; 16537c478bd9Sstevel@tonic-gate 1654*c73a93f2Sdm120769 ASSERT(!MUTEX_HELD(&ct->ct_mutex)); 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate if (vh->vh_ops->vo_failover != NULL) { 16577c478bd9Sstevel@tonic-gate /* 16587c478bd9Sstevel@tonic-gate * Call vHCI drivers callback routine 16597c478bd9Sstevel@tonic-gate */ 16607c478bd9Sstevel@tonic-gate rv = (*vh->vh_ops->vo_failover)(vh->vh_dip, ct->ct_dip, 16617c478bd9Sstevel@tonic-gate ct->ct_failover_flags); 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate 16647c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 16657c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_FAILOVER_IN_PROGRESS(ct); 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate /* 16687c478bd9Sstevel@tonic-gate * Save the failover return status 16697c478bd9Sstevel@tonic-gate */ 16707c478bd9Sstevel@tonic-gate ct->ct_failover_status = rv; 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* 16737c478bd9Sstevel@tonic-gate * As a result of failover, client status would have been changed. 16747c478bd9Sstevel@tonic-gate * Update the client state and wake up anyone waiting on this client 16757c478bd9Sstevel@tonic-gate * device. 16767c478bd9Sstevel@tonic-gate */ 16777c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_failover_cv); 16807c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 16817c478bd9Sstevel@tonic-gate return (rv); 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate /* 16857c478bd9Sstevel@tonic-gate * Load balancing is logical block. 16867c478bd9Sstevel@tonic-gate * IOs within the range described by region_size 16877c478bd9Sstevel@tonic-gate * would go on the same path. This would improve the 16887c478bd9Sstevel@tonic-gate * performance by cache-hit on some of the RAID devices. 16897c478bd9Sstevel@tonic-gate * Search only for online paths(At some point we 16907c478bd9Sstevel@tonic-gate * may want to balance across target ports). 16917c478bd9Sstevel@tonic-gate * If no paths are found then default to round-robin. 16927c478bd9Sstevel@tonic-gate */ 16937c478bd9Sstevel@tonic-gate static int 16947c478bd9Sstevel@tonic-gate i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp) 16957c478bd9Sstevel@tonic-gate { 16967c478bd9Sstevel@tonic-gate int path_index = -1; 16977c478bd9Sstevel@tonic-gate int online_path_count = 0; 16987c478bd9Sstevel@tonic-gate int online_nonpref_path_count = 0; 16997c478bd9Sstevel@tonic-gate int region_size = ct->ct_lb_args->region_size; 17007c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 17017c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 17027c478bd9Sstevel@tonic-gate int preferred, path_cnt; 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 17057c478bd9Sstevel@tonic-gate while (pip) { 17067c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 17077c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_state == 17087c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && MDI_PI(pip)->pi_preferred) { 17097c478bd9Sstevel@tonic-gate online_path_count++; 17107c478bd9Sstevel@tonic-gate } else if (MDI_PI(pip)->pi_state == 17117c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && !MDI_PI(pip)->pi_preferred) { 17127c478bd9Sstevel@tonic-gate online_nonpref_path_count++; 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 17157c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 17167c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 17177c478bd9Sstevel@tonic-gate pip = next; 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate /* if found any online/preferred then use this type */ 17207c478bd9Sstevel@tonic-gate if (online_path_count > 0) { 17217c478bd9Sstevel@tonic-gate path_cnt = online_path_count; 17227c478bd9Sstevel@tonic-gate preferred = 1; 17237c478bd9Sstevel@tonic-gate } else if (online_nonpref_path_count > 0) { 17247c478bd9Sstevel@tonic-gate path_cnt = online_nonpref_path_count; 17257c478bd9Sstevel@tonic-gate preferred = 0; 17267c478bd9Sstevel@tonic-gate } else { 17277c478bd9Sstevel@tonic-gate path_cnt = 0; 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate if (path_cnt) { 17307c478bd9Sstevel@tonic-gate path_index = (bp->b_blkno >> region_size) % path_cnt; 17317c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 17327c478bd9Sstevel@tonic-gate while (pip && path_index != -1) { 17337c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 17347c478bd9Sstevel@tonic-gate if (path_index == 0 && 17357c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 17367c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE) && 17377c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == preferred) { 17387c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 17397c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 17407c478bd9Sstevel@tonic-gate *ret_pip = pip; 17417c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 17427c478bd9Sstevel@tonic-gate } 17437c478bd9Sstevel@tonic-gate path_index --; 17447c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 17457c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 17467c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 17477c478bd9Sstevel@tonic-gate pip = next; 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate if (pip == NULL) { 17507c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 1751*c73a93f2Sdm120769 "!lba %p, no pip !!\n", 1752*c73a93f2Sdm120769 bp->b_blkno)); 17537c478bd9Sstevel@tonic-gate } else { 17547c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 1755*c73a93f2Sdm120769 "!lba %p, no pip for path_index, " 1756*c73a93f2Sdm120769 "pip %p\n", pip)); 17577c478bd9Sstevel@tonic-gate } 17587c478bd9Sstevel@tonic-gate } 17597c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate /* 17637c478bd9Sstevel@tonic-gate * mdi_select_path(): 17647c478bd9Sstevel@tonic-gate * select a path to access a client device. 17657c478bd9Sstevel@tonic-gate * 17667c478bd9Sstevel@tonic-gate * mdi_select_path() function is called by the vHCI drivers to 17677c478bd9Sstevel@tonic-gate * select a path to route the I/O request to. The caller passes 17687c478bd9Sstevel@tonic-gate * the block I/O data transfer structure ("buf") as one of the 17697c478bd9Sstevel@tonic-gate * parameters. The mpxio framework uses the buf structure 17707c478bd9Sstevel@tonic-gate * contents to maintain per path statistics (total I/O size / 17717c478bd9Sstevel@tonic-gate * count pending). If more than one online paths are available to 17727c478bd9Sstevel@tonic-gate * select, the framework automatically selects a suitable path 17737c478bd9Sstevel@tonic-gate * for routing I/O request. If a failover operation is active for 17747c478bd9Sstevel@tonic-gate * this client device the call shall be failed with MDI_BUSY error 17757c478bd9Sstevel@tonic-gate * code. 17767c478bd9Sstevel@tonic-gate * 17777c478bd9Sstevel@tonic-gate * By default this function returns a suitable path in online 17787c478bd9Sstevel@tonic-gate * state based on the current load balancing policy. Currently 17797c478bd9Sstevel@tonic-gate * we support LOAD_BALANCE_NONE (Previously selected online path 17807c478bd9Sstevel@tonic-gate * will continue to be used till the path is usable) and 17817c478bd9Sstevel@tonic-gate * LOAD_BALANCE_RR (Online paths will be selected in a round 17827c478bd9Sstevel@tonic-gate * robin fashion), LOAD_BALANCE_LB(Online paths will be selected 17837c478bd9Sstevel@tonic-gate * based on the logical block). The load balancing 17847c478bd9Sstevel@tonic-gate * through vHCI drivers configuration file (driver.conf). 17857c478bd9Sstevel@tonic-gate * 17867c478bd9Sstevel@tonic-gate * vHCI drivers may override this default behavior by specifying 17877c478bd9Sstevel@tonic-gate * appropriate flags. If start_pip is specified (non NULL) is 17887c478bd9Sstevel@tonic-gate * used as start point to walk and find the next appropriate path. 17897c478bd9Sstevel@tonic-gate * The following values are currently defined: 17907c478bd9Sstevel@tonic-gate * MDI_SELECT_ONLINE_PATH (to select an ONLINE path) and/or 17917c478bd9Sstevel@tonic-gate * MDI_SELECT_STANDBY_PATH (to select an STANDBY path). 17927c478bd9Sstevel@tonic-gate * 17937c478bd9Sstevel@tonic-gate * The non-standard behavior is used by the scsi_vhci driver, 17947c478bd9Sstevel@tonic-gate * whenever it has to use a STANDBY/FAULTED path. Eg. during 17957c478bd9Sstevel@tonic-gate * attach of client devices (to avoid an unnecessary failover 17967c478bd9Sstevel@tonic-gate * when the STANDBY path comes up first), during failover 17977c478bd9Sstevel@tonic-gate * (to activate a STANDBY path as ONLINE). 17987c478bd9Sstevel@tonic-gate * 1799*c73a93f2Sdm120769 * The selected path in returned in a held state (ref_cnt). 1800*c73a93f2Sdm120769 * Caller should release the hold by calling mdi_rele_path(). 18017c478bd9Sstevel@tonic-gate * 18027c478bd9Sstevel@tonic-gate * Return Values: 18037c478bd9Sstevel@tonic-gate * MDI_SUCCESS - Completed successfully 18047c478bd9Sstevel@tonic-gate * MDI_BUSY - Client device is busy failing over 18057c478bd9Sstevel@tonic-gate * MDI_NOPATH - Client device is online, but no valid path are 18067c478bd9Sstevel@tonic-gate * available to access this client device 18077c478bd9Sstevel@tonic-gate * MDI_FAILURE - Invalid client device or state 18087c478bd9Sstevel@tonic-gate * MDI_DEVI_ONLINING 18097c478bd9Sstevel@tonic-gate * - Client device (struct dev_info state) is in 18107c478bd9Sstevel@tonic-gate * onlining state. 18117c478bd9Sstevel@tonic-gate */ 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18147c478bd9Sstevel@tonic-gate int 18157c478bd9Sstevel@tonic-gate mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags, 18167c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start_pip, mdi_pathinfo_t **ret_pip) 18177c478bd9Sstevel@tonic-gate { 18187c478bd9Sstevel@tonic-gate mdi_client_t *ct; 18197c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 18207c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 18217c478bd9Sstevel@tonic-gate mdi_pathinfo_t *head; 18227c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start; 18237c478bd9Sstevel@tonic-gate client_lb_t lbp; /* load balancing policy */ 18247c478bd9Sstevel@tonic-gate int sb = 1; /* standard behavior */ 18257c478bd9Sstevel@tonic-gate int preferred = 1; /* preferred path */ 18267c478bd9Sstevel@tonic-gate int cond, cont = 1; 18277c478bd9Sstevel@tonic-gate int retry = 0; 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate if (flags != 0) { 18307c478bd9Sstevel@tonic-gate /* 18317c478bd9Sstevel@tonic-gate * disable default behavior 18327c478bd9Sstevel@tonic-gate */ 18337c478bd9Sstevel@tonic-gate sb = 0; 18347c478bd9Sstevel@tonic-gate } 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate *ret_pip = NULL; 18377c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 18387c478bd9Sstevel@tonic-gate if (ct == NULL) { 18397c478bd9Sstevel@tonic-gate /* mdi extensions are NULL, Nothing more to do */ 18407c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 18417c478bd9Sstevel@tonic-gate } 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate if (sb) { 18467c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 18477c478bd9Sstevel@tonic-gate /* 18487c478bd9Sstevel@tonic-gate * Client is not ready to accept any I/O requests. 18497c478bd9Sstevel@tonic-gate * Fail this request. 18507c478bd9Sstevel@tonic-gate */ 18517c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 1852*c73a93f2Sdm120769 "client state offline ct = %p\n", ct)); 18537c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18547c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 18587c478bd9Sstevel@tonic-gate /* 18597c478bd9Sstevel@tonic-gate * Check for Failover is in progress. If so tell the 18607c478bd9Sstevel@tonic-gate * caller that this device is busy. 18617c478bd9Sstevel@tonic-gate */ 18627c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 1863*c73a93f2Sdm120769 "client failover in progress ct = %p\n", ct)); 18647c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18657c478bd9Sstevel@tonic-gate return (MDI_BUSY); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate /* 18697c478bd9Sstevel@tonic-gate * Check to see whether the client device is attached. 18707c478bd9Sstevel@tonic-gate * If not so, let the vHCI driver manually select a path 18717c478bd9Sstevel@tonic-gate * (standby) and let the probe/attach process to continue. 18727c478bd9Sstevel@tonic-gate */ 1873737d277aScth if (MDI_CLIENT_IS_DETACHED(ct) || !i_ddi_devi_attached(cdip)) { 1874*c73a93f2Sdm120769 MDI_DEBUG(4, (CE_NOTE, cdip, "!Devi is onlining\n")); 18757c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18767c478bd9Sstevel@tonic-gate return (MDI_DEVI_ONLINING); 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate /* 18817c478bd9Sstevel@tonic-gate * Cache in the client list head. If head of the list is NULL 18827c478bd9Sstevel@tonic-gate * return MDI_NOPATH 18837c478bd9Sstevel@tonic-gate */ 18847c478bd9Sstevel@tonic-gate head = ct->ct_path_head; 18857c478bd9Sstevel@tonic-gate if (head == NULL) { 18867c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18877c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 18887c478bd9Sstevel@tonic-gate } 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate /* 18917c478bd9Sstevel@tonic-gate * for non default behavior, bypass current 18927c478bd9Sstevel@tonic-gate * load balancing policy and always use LOAD_BALANCE_RR 18937c478bd9Sstevel@tonic-gate * except that the start point will be adjusted based 18947c478bd9Sstevel@tonic-gate * on the provided start_pip 18957c478bd9Sstevel@tonic-gate */ 18967c478bd9Sstevel@tonic-gate lbp = sb ? ct->ct_lb : LOAD_BALANCE_RR; 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate switch (lbp) { 18997c478bd9Sstevel@tonic-gate case LOAD_BALANCE_NONE: 19007c478bd9Sstevel@tonic-gate /* 19017c478bd9Sstevel@tonic-gate * Load balancing is None or Alternate path mode 19027c478bd9Sstevel@tonic-gate * Start looking for a online mdi_pathinfo node starting from 19037c478bd9Sstevel@tonic-gate * last known selected path 19047c478bd9Sstevel@tonic-gate */ 19057c478bd9Sstevel@tonic-gate preferred = 1; 19067c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_last; 19077c478bd9Sstevel@tonic-gate if (pip == NULL) { 19087c478bd9Sstevel@tonic-gate pip = head; 19097c478bd9Sstevel@tonic-gate } 19107c478bd9Sstevel@tonic-gate start = pip; 19117c478bd9Sstevel@tonic-gate do { 19127c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 19137c478bd9Sstevel@tonic-gate /* 19147c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 19157c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 19167c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 19177c478bd9Sstevel@tonic-gate */ 1918ee28b439Scm136836 if ((MDI_PI(pip)->pi_state == 1919ee28b439Scm136836 MDI_PATHINFO_STATE_ONLINE) && 19207c478bd9Sstevel@tonic-gate preferred == MDI_PI(pip)->pi_preferred) { 19217c478bd9Sstevel@tonic-gate /* 19227c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 19237c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 19247c478bd9Sstevel@tonic-gate */ 19257c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 19267c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19277c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 19287c478bd9Sstevel@tonic-gate *ret_pip = pip; 19297c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 19307c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 19317c478bd9Sstevel@tonic-gate } 19327c478bd9Sstevel@tonic-gate 19337c478bd9Sstevel@tonic-gate /* 19347c478bd9Sstevel@tonic-gate * Path is busy. 19357c478bd9Sstevel@tonic-gate */ 19367c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 19377c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 19387c478bd9Sstevel@tonic-gate retry = 1; 19397c478bd9Sstevel@tonic-gate /* 19407c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 19417c478bd9Sstevel@tonic-gate */ 19427c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 19437c478bd9Sstevel@tonic-gate if (next == NULL) { 19447c478bd9Sstevel@tonic-gate next = head; 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19477c478bd9Sstevel@tonic-gate pip = next; 19487c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 19497c478bd9Sstevel@tonic-gate preferred = 0; 19507c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 19517c478bd9Sstevel@tonic-gate cont = 0; 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate } while (cont); 19547c478bd9Sstevel@tonic-gate break; 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate case LOAD_BALANCE_LBA: 19577c478bd9Sstevel@tonic-gate /* 19587c478bd9Sstevel@tonic-gate * Make sure we are looking 19597c478bd9Sstevel@tonic-gate * for an online path. Otherwise, if it is for a STANDBY 19607c478bd9Sstevel@tonic-gate * path request, it will go through and fetch an ONLINE 19617c478bd9Sstevel@tonic-gate * path which is not desirable. 19627c478bd9Sstevel@tonic-gate */ 19637c478bd9Sstevel@tonic-gate if ((ct->ct_lb_args != NULL) && 19647c478bd9Sstevel@tonic-gate (ct->ct_lb_args->region_size) && bp && 19657c478bd9Sstevel@tonic-gate (sb || (flags == MDI_SELECT_ONLINE_PATH))) { 19667c478bd9Sstevel@tonic-gate if (i_mdi_lba_lb(ct, ret_pip, bp) 19677c478bd9Sstevel@tonic-gate == MDI_SUCCESS) { 19687c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 19697c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 19707c478bd9Sstevel@tonic-gate } 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 19737c478bd9Sstevel@tonic-gate case LOAD_BALANCE_RR: 19747c478bd9Sstevel@tonic-gate /* 19757c478bd9Sstevel@tonic-gate * Load balancing is Round Robin. Start looking for a online 19767c478bd9Sstevel@tonic-gate * mdi_pathinfo node starting from last known selected path 19777c478bd9Sstevel@tonic-gate * as the start point. If override flags are specified, 19787c478bd9Sstevel@tonic-gate * process accordingly. 19797c478bd9Sstevel@tonic-gate * If the search is already in effect(start_pip not null), 19807c478bd9Sstevel@tonic-gate * then lets just use the same path preference to continue the 19817c478bd9Sstevel@tonic-gate * traversal. 19827c478bd9Sstevel@tonic-gate */ 19837c478bd9Sstevel@tonic-gate 19847c478bd9Sstevel@tonic-gate if (start_pip != NULL) { 19857c478bd9Sstevel@tonic-gate preferred = MDI_PI(start_pip)->pi_preferred; 19867c478bd9Sstevel@tonic-gate } else { 19877c478bd9Sstevel@tonic-gate preferred = 1; 19887c478bd9Sstevel@tonic-gate } 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate start = sb ? (mdi_pathinfo_t *)ct->ct_path_last : start_pip; 19917c478bd9Sstevel@tonic-gate if (start == NULL) { 19927c478bd9Sstevel@tonic-gate pip = head; 19937c478bd9Sstevel@tonic-gate } else { 19947c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(start)->pi_client_link; 19957c478bd9Sstevel@tonic-gate if (pip == NULL) { 19967c478bd9Sstevel@tonic-gate if (!sb) { 19977c478bd9Sstevel@tonic-gate if (preferred == 0) { 19987c478bd9Sstevel@tonic-gate /* 19997c478bd9Sstevel@tonic-gate * Looks like we have completed 20007c478bd9Sstevel@tonic-gate * the traversal as preferred 20017c478bd9Sstevel@tonic-gate * value is 0. Time to bail out. 20027c478bd9Sstevel@tonic-gate */ 20037c478bd9Sstevel@tonic-gate *ret_pip = NULL; 20047c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 20057c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 20067c478bd9Sstevel@tonic-gate } else { 20077c478bd9Sstevel@tonic-gate /* 20087c478bd9Sstevel@tonic-gate * Looks like we reached the 20097c478bd9Sstevel@tonic-gate * end of the list. Lets enable 20107c478bd9Sstevel@tonic-gate * traversal of non preferred 20117c478bd9Sstevel@tonic-gate * paths. 20127c478bd9Sstevel@tonic-gate */ 20137c478bd9Sstevel@tonic-gate preferred = 0; 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate } 20167c478bd9Sstevel@tonic-gate pip = head; 20177c478bd9Sstevel@tonic-gate } 20187c478bd9Sstevel@tonic-gate } 20197c478bd9Sstevel@tonic-gate start = pip; 20207c478bd9Sstevel@tonic-gate do { 20217c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 20227c478bd9Sstevel@tonic-gate if (sb) { 20237c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 20247c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 20257c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20267c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20277c478bd9Sstevel@tonic-gate } else { 20287c478bd9Sstevel@tonic-gate if (flags == MDI_SELECT_ONLINE_PATH) { 20297c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 20307c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 20317c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20327c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20337c478bd9Sstevel@tonic-gate } else if (flags == MDI_SELECT_STANDBY_PATH) { 20347c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 20357c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY && 20367c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20377c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20387c478bd9Sstevel@tonic-gate } else if (flags == (MDI_SELECT_ONLINE_PATH | 20397c478bd9Sstevel@tonic-gate MDI_SELECT_STANDBY_PATH)) { 20407c478bd9Sstevel@tonic-gate cond = (((MDI_PI(pip)->pi_state == 20417c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE || 20427c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 20437c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY)) && 20447c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20457c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 2046ee28b439Scm136836 } else if (flags == 2047ee28b439Scm136836 (MDI_SELECT_STANDBY_PATH | 2048ee28b439Scm136836 MDI_SELECT_ONLINE_PATH | 2049ee28b439Scm136836 MDI_SELECT_USER_DISABLE_PATH)) { 2050ee28b439Scm136836 cond = (((MDI_PI(pip)->pi_state == 2051ee28b439Scm136836 MDI_PATHINFO_STATE_ONLINE || 2052ee28b439Scm136836 (MDI_PI(pip)->pi_state == 2053ee28b439Scm136836 MDI_PATHINFO_STATE_STANDBY) || 2054ee28b439Scm136836 (MDI_PI(pip)->pi_state == 2055ee28b439Scm136836 (MDI_PATHINFO_STATE_ONLINE| 2056ee28b439Scm136836 MDI_PATHINFO_STATE_USER_DISABLE)) || 2057ee28b439Scm136836 (MDI_PI(pip)->pi_state == 2058ee28b439Scm136836 (MDI_PATHINFO_STATE_STANDBY | 2059ee28b439Scm136836 MDI_PATHINFO_STATE_USER_DISABLE)))&& 2060ee28b439Scm136836 MDI_PI(pip)->pi_preferred == 2061ee28b439Scm136836 preferred) ? 1 : 0); 20627c478bd9Sstevel@tonic-gate } else { 20637c478bd9Sstevel@tonic-gate cond = 0; 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate /* 20677c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 20687c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 20697c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 20707c478bd9Sstevel@tonic-gate */ 20717c478bd9Sstevel@tonic-gate if (cond) { 20727c478bd9Sstevel@tonic-gate /* 20737c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 20747c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 20757c478bd9Sstevel@tonic-gate */ 20767c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 20777c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 20787c478bd9Sstevel@tonic-gate if (sb) 20797c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 20807c478bd9Sstevel@tonic-gate *ret_pip = pip; 20817c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 20827c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 20837c478bd9Sstevel@tonic-gate } 20847c478bd9Sstevel@tonic-gate /* 20857c478bd9Sstevel@tonic-gate * Path is busy. 20867c478bd9Sstevel@tonic-gate */ 20877c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 20887c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 20897c478bd9Sstevel@tonic-gate retry = 1; 20907c478bd9Sstevel@tonic-gate 20917c478bd9Sstevel@tonic-gate /* 20927c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 20937c478bd9Sstevel@tonic-gate */ 20947c478bd9Sstevel@tonic-gate do_again: 20957c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 20967c478bd9Sstevel@tonic-gate if (next == NULL) { 20977c478bd9Sstevel@tonic-gate if (!sb) { 20987c478bd9Sstevel@tonic-gate if (preferred == 1) { 20997c478bd9Sstevel@tonic-gate /* 21007c478bd9Sstevel@tonic-gate * Looks like we reached the 21017c478bd9Sstevel@tonic-gate * end of the list. Lets enable 21027c478bd9Sstevel@tonic-gate * traversal of non preferred 21037c478bd9Sstevel@tonic-gate * paths. 21047c478bd9Sstevel@tonic-gate */ 21057c478bd9Sstevel@tonic-gate preferred = 0; 21067c478bd9Sstevel@tonic-gate next = head; 21077c478bd9Sstevel@tonic-gate } else { 21087c478bd9Sstevel@tonic-gate /* 21097c478bd9Sstevel@tonic-gate * We have done both the passes 21107c478bd9Sstevel@tonic-gate * Preferred as well as for 21117c478bd9Sstevel@tonic-gate * Non-preferred. Bail out now. 21127c478bd9Sstevel@tonic-gate */ 21137c478bd9Sstevel@tonic-gate cont = 0; 21147c478bd9Sstevel@tonic-gate } 21157c478bd9Sstevel@tonic-gate } else { 21167c478bd9Sstevel@tonic-gate /* 21177c478bd9Sstevel@tonic-gate * Standard behavior case. 21187c478bd9Sstevel@tonic-gate */ 21197c478bd9Sstevel@tonic-gate next = head; 21207c478bd9Sstevel@tonic-gate } 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 21237c478bd9Sstevel@tonic-gate if (cont == 0) { 21247c478bd9Sstevel@tonic-gate break; 21257c478bd9Sstevel@tonic-gate } 21267c478bd9Sstevel@tonic-gate pip = next; 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate if (!sb) { 21297c478bd9Sstevel@tonic-gate /* 21307c478bd9Sstevel@tonic-gate * We need to handle the selection of 21317c478bd9Sstevel@tonic-gate * non-preferred path in the following 21327c478bd9Sstevel@tonic-gate * case: 21337c478bd9Sstevel@tonic-gate * 21347c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 21357c478bd9Sstevel@tonic-gate * | A : 1| - | B : 1| - | C : 0| - |NULL | 21367c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 21377c478bd9Sstevel@tonic-gate * 21387c478bd9Sstevel@tonic-gate * If we start the search with B, we need to 21397c478bd9Sstevel@tonic-gate * skip beyond B to pick C which is non - 21407c478bd9Sstevel@tonic-gate * preferred in the second pass. The following 21417c478bd9Sstevel@tonic-gate * test, if true, will allow us to skip over 21427c478bd9Sstevel@tonic-gate * the 'start'(B in the example) to select 21437c478bd9Sstevel@tonic-gate * other non preferred elements. 21447c478bd9Sstevel@tonic-gate */ 21457c478bd9Sstevel@tonic-gate if ((start_pip != NULL) && (start_pip == pip) && 21467c478bd9Sstevel@tonic-gate (MDI_PI(start_pip)->pi_preferred 21477c478bd9Sstevel@tonic-gate != preferred)) { 21487c478bd9Sstevel@tonic-gate /* 21497c478bd9Sstevel@tonic-gate * try again after going past the start 21507c478bd9Sstevel@tonic-gate * pip 21517c478bd9Sstevel@tonic-gate */ 21527c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 21537c478bd9Sstevel@tonic-gate goto do_again; 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate } else { 21567c478bd9Sstevel@tonic-gate /* 21577c478bd9Sstevel@tonic-gate * Standard behavior case 21587c478bd9Sstevel@tonic-gate */ 21597c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 21607c478bd9Sstevel@tonic-gate /* look for nonpreferred paths */ 21617c478bd9Sstevel@tonic-gate preferred = 0; 21627c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 21637c478bd9Sstevel@tonic-gate /* 21647c478bd9Sstevel@tonic-gate * Exit condition 21657c478bd9Sstevel@tonic-gate */ 21667c478bd9Sstevel@tonic-gate cont = 0; 21677c478bd9Sstevel@tonic-gate } 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate } while (cont); 21707c478bd9Sstevel@tonic-gate break; 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 21747c478bd9Sstevel@tonic-gate if (retry == 1) { 21757c478bd9Sstevel@tonic-gate return (MDI_BUSY); 21767c478bd9Sstevel@tonic-gate } else { 21777c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 21787c478bd9Sstevel@tonic-gate } 21797c478bd9Sstevel@tonic-gate } 21807c478bd9Sstevel@tonic-gate 21817c478bd9Sstevel@tonic-gate /* 21827c478bd9Sstevel@tonic-gate * For a client, return the next available path to any phci 21837c478bd9Sstevel@tonic-gate * 21847c478bd9Sstevel@tonic-gate * Note: 21857c478bd9Sstevel@tonic-gate * Caller should hold the branch's devinfo node to get a consistent 21867c478bd9Sstevel@tonic-gate * snap shot of the mdi_pathinfo nodes. 21877c478bd9Sstevel@tonic-gate * 21887c478bd9Sstevel@tonic-gate * Please note that even the list is stable the mdi_pathinfo 21897c478bd9Sstevel@tonic-gate * node state and properties are volatile. The caller should lock 21907c478bd9Sstevel@tonic-gate * and unlock the nodes by calling mdi_pi_lock() and 21917c478bd9Sstevel@tonic-gate * mdi_pi_unlock() functions to get a stable properties. 21927c478bd9Sstevel@tonic-gate * 21937c478bd9Sstevel@tonic-gate * If there is a need to use the nodes beyond the hold of the 21947c478bd9Sstevel@tonic-gate * devinfo node period (For ex. I/O), then mdi_pathinfo node 21957c478bd9Sstevel@tonic-gate * need to be held against unexpected removal by calling 21967c478bd9Sstevel@tonic-gate * mdi_hold_path() and should be released by calling 21977c478bd9Sstevel@tonic-gate * mdi_rele_path() on completion. 21987c478bd9Sstevel@tonic-gate */ 21997c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 22007c478bd9Sstevel@tonic-gate mdi_get_next_phci_path(dev_info_t *ct_dip, mdi_pathinfo_t *pip) 22017c478bd9Sstevel@tonic-gate { 22027c478bd9Sstevel@tonic-gate mdi_client_t *ct; 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(ct_dip)) 22057c478bd9Sstevel@tonic-gate return (NULL); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate /* 22087c478bd9Sstevel@tonic-gate * Walk through client link 22097c478bd9Sstevel@tonic-gate */ 22107c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(ct_dip)->devi_mdi_client; 22117c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate if (pip == NULL) 22147c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ct->ct_path_head); 22157c478bd9Sstevel@tonic-gate 22167c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link); 22177c478bd9Sstevel@tonic-gate } 22187c478bd9Sstevel@tonic-gate 22197c478bd9Sstevel@tonic-gate /* 22207c478bd9Sstevel@tonic-gate * For a phci, return the next available path to any client 22217c478bd9Sstevel@tonic-gate * Note: ditto mdi_get_next_phci_path() 22227c478bd9Sstevel@tonic-gate */ 22237c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 22247c478bd9Sstevel@tonic-gate mdi_get_next_client_path(dev_info_t *ph_dip, mdi_pathinfo_t *pip) 22257c478bd9Sstevel@tonic-gate { 22267c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 22277c478bd9Sstevel@tonic-gate 22287c478bd9Sstevel@tonic-gate if (!MDI_PHCI(ph_dip)) 22297c478bd9Sstevel@tonic-gate return (NULL); 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate /* 22327c478bd9Sstevel@tonic-gate * Walk through pHCI link 22337c478bd9Sstevel@tonic-gate */ 22347c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(ph_dip)->devi_mdi_xhci; 22357c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate if (pip == NULL) 22387c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ph->ph_path_head); 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link); 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate /* 2244*c73a93f2Sdm120769 * mdi_get_nextpath(): 2245*c73a93f2Sdm120769 * mdi_pathinfo node walker function. Get the next node from the 2246*c73a93f2Sdm120769 * client or pHCI device list. 2247*c73a93f2Sdm120769 * 2248*c73a93f2Sdm120769 * XXX This is wrapper function for compatibility purposes only. 2249*c73a93f2Sdm120769 * 2250*c73a93f2Sdm120769 * It doesn't work under Multi-level MPxIO, where a dip 2251*c73a93f2Sdm120769 * is both client and phci (which link should next_path follow?). 2252*c73a93f2Sdm120769 * Once Leadville is modified to call mdi_get_next_phci/client_path, 2253*c73a93f2Sdm120769 * this interface should be removed. 2254*c73a93f2Sdm120769 */ 2255*c73a93f2Sdm120769 void 2256*c73a93f2Sdm120769 mdi_get_next_path(dev_info_t *dip, mdi_pathinfo_t *pip, 2257*c73a93f2Sdm120769 mdi_pathinfo_t **ret_pip) 2258*c73a93f2Sdm120769 { 2259*c73a93f2Sdm120769 if (MDI_CLIENT(dip)) { 2260*c73a93f2Sdm120769 *ret_pip = mdi_get_next_phci_path(dip, pip); 2261*c73a93f2Sdm120769 } else if (MDI_PHCI(dip)) { 2262*c73a93f2Sdm120769 *ret_pip = mdi_get_next_client_path(dip, pip); 2263*c73a93f2Sdm120769 } else { 2264*c73a93f2Sdm120769 *ret_pip = NULL; 2265*c73a93f2Sdm120769 } 2266*c73a93f2Sdm120769 } 2267*c73a93f2Sdm120769 2268*c73a93f2Sdm120769 /* 22697c478bd9Sstevel@tonic-gate * mdi_hold_path(): 22707c478bd9Sstevel@tonic-gate * Hold the mdi_pathinfo node against unwanted unexpected free. 22717c478bd9Sstevel@tonic-gate * Return Values: 22727c478bd9Sstevel@tonic-gate * None 22737c478bd9Sstevel@tonic-gate */ 22747c478bd9Sstevel@tonic-gate void 22757c478bd9Sstevel@tonic-gate mdi_hold_path(mdi_pathinfo_t *pip) 22767c478bd9Sstevel@tonic-gate { 22777c478bd9Sstevel@tonic-gate if (pip) { 22787c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22797c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 22807c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 22817c478bd9Sstevel@tonic-gate } 22827c478bd9Sstevel@tonic-gate } 22837c478bd9Sstevel@tonic-gate 22847c478bd9Sstevel@tonic-gate 22857c478bd9Sstevel@tonic-gate /* 22867c478bd9Sstevel@tonic-gate * mdi_rele_path(): 22877c478bd9Sstevel@tonic-gate * Release the mdi_pathinfo node which was selected 22887c478bd9Sstevel@tonic-gate * through mdi_select_path() mechanism or manually held by 22897c478bd9Sstevel@tonic-gate * calling mdi_hold_path(). 22907c478bd9Sstevel@tonic-gate * Return Values: 22917c478bd9Sstevel@tonic-gate * None 22927c478bd9Sstevel@tonic-gate */ 22937c478bd9Sstevel@tonic-gate void 22947c478bd9Sstevel@tonic-gate mdi_rele_path(mdi_pathinfo_t *pip) 22957c478bd9Sstevel@tonic-gate { 22967c478bd9Sstevel@tonic-gate if (pip) { 22977c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22987c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 22997c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_ref_cnt == 0) { 23007c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_ref_cv); 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate } 23057c478bd9Sstevel@tonic-gate 2306*c73a93f2Sdm120769 23077c478bd9Sstevel@tonic-gate /* 23087c478bd9Sstevel@tonic-gate * mdi_pi_lock(): 23097c478bd9Sstevel@tonic-gate * Lock the mdi_pathinfo node. 23107c478bd9Sstevel@tonic-gate * Note: 23117c478bd9Sstevel@tonic-gate * The caller should release the lock by calling mdi_pi_unlock() 23127c478bd9Sstevel@tonic-gate */ 23137c478bd9Sstevel@tonic-gate void 23147c478bd9Sstevel@tonic-gate mdi_pi_lock(mdi_pathinfo_t *pip) 23157c478bd9Sstevel@tonic-gate { 23167c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 23177c478bd9Sstevel@tonic-gate if (pip) { 23187c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 23197c478bd9Sstevel@tonic-gate } 23207c478bd9Sstevel@tonic-gate } 23217c478bd9Sstevel@tonic-gate 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate /* 23247c478bd9Sstevel@tonic-gate * mdi_pi_unlock(): 23257c478bd9Sstevel@tonic-gate * Unlock the mdi_pathinfo node. 23267c478bd9Sstevel@tonic-gate * Note: 23277c478bd9Sstevel@tonic-gate * The mdi_pathinfo node should have been locked with mdi_pi_lock() 23287c478bd9Sstevel@tonic-gate */ 23297c478bd9Sstevel@tonic-gate void 23307c478bd9Sstevel@tonic-gate mdi_pi_unlock(mdi_pathinfo_t *pip) 23317c478bd9Sstevel@tonic-gate { 23327c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 23337c478bd9Sstevel@tonic-gate if (pip) { 23347c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 23357c478bd9Sstevel@tonic-gate } 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate /* 23397c478bd9Sstevel@tonic-gate * mdi_pi_find(): 23407c478bd9Sstevel@tonic-gate * Search the list of mdi_pathinfo nodes attached to the 23417c478bd9Sstevel@tonic-gate * pHCI/Client device node whose path address matches "paddr". 23427c478bd9Sstevel@tonic-gate * Returns a pointer to the mdi_pathinfo node if a matching node is 23437c478bd9Sstevel@tonic-gate * found. 23447c478bd9Sstevel@tonic-gate * Return Values: 23457c478bd9Sstevel@tonic-gate * mdi_pathinfo node handle 23467c478bd9Sstevel@tonic-gate * NULL 23477c478bd9Sstevel@tonic-gate * Notes: 23487c478bd9Sstevel@tonic-gate * Caller need not hold any locks to call this function. 23497c478bd9Sstevel@tonic-gate */ 23507c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 23517c478bd9Sstevel@tonic-gate mdi_pi_find(dev_info_t *pdip, char *caddr, char *paddr) 23527c478bd9Sstevel@tonic-gate { 23537c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 23547c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 23557c478bd9Sstevel@tonic-gate mdi_client_t *ct; 23567c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 23577c478bd9Sstevel@tonic-gate 23587c478bd9Sstevel@tonic-gate if ((pdip == NULL) || (paddr == NULL)) { 23597c478bd9Sstevel@tonic-gate return (NULL); 23607c478bd9Sstevel@tonic-gate } 23617c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 23627c478bd9Sstevel@tonic-gate if (ph == NULL) { 23637c478bd9Sstevel@tonic-gate /* 23647c478bd9Sstevel@tonic-gate * Invalid pHCI device, Nothing more to do. 23657c478bd9Sstevel@tonic-gate */ 2366*c73a93f2Sdm120769 MDI_DEBUG(2, (CE_WARN, NULL, 23677c478bd9Sstevel@tonic-gate "!mdi_pi_find: invalid phci")); 23687c478bd9Sstevel@tonic-gate return (NULL); 23697c478bd9Sstevel@tonic-gate } 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 23727c478bd9Sstevel@tonic-gate if (vh == NULL) { 23737c478bd9Sstevel@tonic-gate /* 23747c478bd9Sstevel@tonic-gate * Invalid vHCI device, Nothing more to do. 23757c478bd9Sstevel@tonic-gate */ 2376*c73a93f2Sdm120769 MDI_DEBUG(2, (CE_WARN, NULL, 2377*c73a93f2Sdm120769 "!mdi_pi_find: invalid phci")); 23787c478bd9Sstevel@tonic-gate return (NULL); 23797c478bd9Sstevel@tonic-gate } 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate /* 2382*c73a93f2Sdm120769 * Look for client device identified by caddr (guid) 23837c478bd9Sstevel@tonic-gate */ 23847c478bd9Sstevel@tonic-gate if (caddr == NULL) { 23857c478bd9Sstevel@tonic-gate /* 23867c478bd9Sstevel@tonic-gate * Find a mdi_pathinfo node under pHCI list for a matching 23877c478bd9Sstevel@tonic-gate * unit address. 23887c478bd9Sstevel@tonic-gate */ 2389*c73a93f2Sdm120769 mutex_enter(&ph->ph_mutex); 23907c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ph->ph_path_head; 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate while (pip != NULL) { 23937c478bd9Sstevel@tonic-gate if (strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 23947c478bd9Sstevel@tonic-gate break; 23957c478bd9Sstevel@tonic-gate } 23967c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 23977c478bd9Sstevel@tonic-gate } 2398*c73a93f2Sdm120769 mutex_exit(&ph->ph_mutex); 23997c478bd9Sstevel@tonic-gate return (pip); 24007c478bd9Sstevel@tonic-gate } 24017c478bd9Sstevel@tonic-gate 24027c478bd9Sstevel@tonic-gate /* 24033c34adc5Sramat * XXX - Is the rest of the code in this function really necessary? 24043c34adc5Sramat * The consumers of mdi_pi_find() can search for the desired pathinfo 24053c34adc5Sramat * node by calling mdi_pi_find(pdip, NULL, paddr). Irrespective of 24063c34adc5Sramat * whether the search is based on the pathinfo nodes attached to 24073c34adc5Sramat * the pHCI or the client node, the result will be the same. 24083c34adc5Sramat */ 24093c34adc5Sramat 24103c34adc5Sramat /* 24117c478bd9Sstevel@tonic-gate * Find the client device corresponding to 'caddr' 24127c478bd9Sstevel@tonic-gate */ 2413*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 24143c34adc5Sramat 24153c34adc5Sramat /* 24163c34adc5Sramat * XXX - Passing NULL to the following function works as long as the 24173c34adc5Sramat * the client addresses (caddr) are unique per vhci basis. 24183c34adc5Sramat */ 24193c34adc5Sramat ct = i_mdi_client_find(vh, NULL, caddr); 24207c478bd9Sstevel@tonic-gate if (ct == NULL) { 24217c478bd9Sstevel@tonic-gate /* 24227c478bd9Sstevel@tonic-gate * Client not found, Obviously mdi_pathinfo node has not been 24237c478bd9Sstevel@tonic-gate * created yet. 24247c478bd9Sstevel@tonic-gate */ 2425*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 2426*c73a93f2Sdm120769 return (pip); 24277c478bd9Sstevel@tonic-gate } 24287c478bd9Sstevel@tonic-gate 24297c478bd9Sstevel@tonic-gate /* 24307c478bd9Sstevel@tonic-gate * Hold the client lock and look for a mdi_pathinfo node with matching 24317c478bd9Sstevel@tonic-gate * pHCI and paddr 24327c478bd9Sstevel@tonic-gate */ 24337c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate /* 24367c478bd9Sstevel@tonic-gate * Release the global mutex as it is no more needed. Note: We always 24377c478bd9Sstevel@tonic-gate * respect the locking order while acquiring. 24387c478bd9Sstevel@tonic-gate */ 2439*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 24427c478bd9Sstevel@tonic-gate while (pip != NULL) { 24437c478bd9Sstevel@tonic-gate /* 24447c478bd9Sstevel@tonic-gate * Compare the unit address 24457c478bd9Sstevel@tonic-gate */ 24467c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 24477c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 24487c478bd9Sstevel@tonic-gate break; 24497c478bd9Sstevel@tonic-gate } 24507c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 24517c478bd9Sstevel@tonic-gate } 24527c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 24537c478bd9Sstevel@tonic-gate return (pip); 24547c478bd9Sstevel@tonic-gate } 24557c478bd9Sstevel@tonic-gate 24567c478bd9Sstevel@tonic-gate /* 24577c478bd9Sstevel@tonic-gate * mdi_pi_alloc(): 24587c478bd9Sstevel@tonic-gate * Allocate and initialize a new instance of a mdi_pathinfo node. 24597c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function identifies a 24607c478bd9Sstevel@tonic-gate * unique device path is capable of having properties attached 24617c478bd9Sstevel@tonic-gate * and passed to mdi_pi_online() to fully attach and online the 24627c478bd9Sstevel@tonic-gate * path and client device node. 24637c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function must be 24647c478bd9Sstevel@tonic-gate * destroyed using mdi_pi_free() if the path is no longer 24657c478bd9Sstevel@tonic-gate * operational or if the caller fails to attach a client device 24667c478bd9Sstevel@tonic-gate * node when calling mdi_pi_online(). The framework will not free 24677c478bd9Sstevel@tonic-gate * the resources allocated. 24687c478bd9Sstevel@tonic-gate * This function can be called from both interrupt and kernel 24697c478bd9Sstevel@tonic-gate * contexts. DDI_NOSLEEP flag should be used while calling 24707c478bd9Sstevel@tonic-gate * from interrupt contexts. 24717c478bd9Sstevel@tonic-gate * Return Values: 24727c478bd9Sstevel@tonic-gate * MDI_SUCCESS 24737c478bd9Sstevel@tonic-gate * MDI_FAILURE 24747c478bd9Sstevel@tonic-gate * MDI_NOMEM 24757c478bd9Sstevel@tonic-gate */ 24767c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 24777c478bd9Sstevel@tonic-gate int 24787c478bd9Sstevel@tonic-gate mdi_pi_alloc_compatible(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 24797c478bd9Sstevel@tonic-gate char **compatible, int ncompatible, int flags, mdi_pathinfo_t **ret_pip) 24807c478bd9Sstevel@tonic-gate { 24817c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 24827c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 24837c478bd9Sstevel@tonic-gate mdi_client_t *ct; 24847c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 24857c478bd9Sstevel@tonic-gate dev_info_t *cdip; 24867c478bd9Sstevel@tonic-gate int rv = MDI_NOMEM; 24873c34adc5Sramat int path_allocated = 0; 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate if (pdip == NULL || cname == NULL || caddr == NULL || paddr == NULL || 24907c478bd9Sstevel@tonic-gate ret_pip == NULL) { 24917c478bd9Sstevel@tonic-gate /* Nothing more to do */ 24927c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 24937c478bd9Sstevel@tonic-gate } 24947c478bd9Sstevel@tonic-gate 24957c478bd9Sstevel@tonic-gate *ret_pip = NULL; 24967c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 24977c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 24987c478bd9Sstevel@tonic-gate if (ph == NULL) { 24997c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 2500*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_WARN, NULL, 2501*c73a93f2Sdm120769 "!mdi_pi_alloc: invalid pHCI=%p", pdip)); 25027c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 25037c478bd9Sstevel@tonic-gate } 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 25067c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 25077c478bd9Sstevel@tonic-gate if (vh == NULL) { 25087c478bd9Sstevel@tonic-gate /* Invalid vHCI device, return failure */ 2509*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_WARN, NULL, 2510*c73a93f2Sdm120769 "!mdi_pi_alloc: invalid pHCI=%p", pdip)); 25117c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 25127c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 25137c478bd9Sstevel@tonic-gate } 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 25167c478bd9Sstevel@tonic-gate /* 25177c478bd9Sstevel@tonic-gate * Do not allow new node creation when pHCI is in 25187c478bd9Sstevel@tonic-gate * offline/suspended states 25197c478bd9Sstevel@tonic-gate */ 2520*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_WARN, NULL, 2521*c73a93f2Sdm120769 "mdi_pi_alloc: pHCI=%p is not ready", ph)); 25227c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 25237c478bd9Sstevel@tonic-gate return (MDI_BUSY); 25247c478bd9Sstevel@tonic-gate } 25257c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 25267c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 25277c478bd9Sstevel@tonic-gate 25283c34adc5Sramat /* look for a matching client, create one if not found */ 2529*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 25303c34adc5Sramat ct = i_mdi_client_find(vh, cname, caddr); 25317c478bd9Sstevel@tonic-gate if (ct == NULL) { 25323c34adc5Sramat ct = i_mdi_client_alloc(vh, cname, caddr); 25333c34adc5Sramat ASSERT(ct != NULL); 25347c478bd9Sstevel@tonic-gate } 25357c478bd9Sstevel@tonic-gate 25367c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 25377c478bd9Sstevel@tonic-gate /* 25387c478bd9Sstevel@tonic-gate * Allocate a devinfo node 25397c478bd9Sstevel@tonic-gate */ 25407c478bd9Sstevel@tonic-gate ct->ct_dip = i_mdi_devinfo_create(vh, cname, caddr, 25413c34adc5Sramat compatible, ncompatible); 25427c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 25437c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(vh, ct); 25447c478bd9Sstevel@tonic-gate goto fail; 25457c478bd9Sstevel@tonic-gate } 25467c478bd9Sstevel@tonic-gate } 25477c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 25487c478bd9Sstevel@tonic-gate 25497c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component |= MDI_COMPONENT_CLIENT; 25507c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = (caddr_t)ct; 25517c478bd9Sstevel@tonic-gate 25527c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 25537c478bd9Sstevel@tonic-gate while (pip != NULL) { 25547c478bd9Sstevel@tonic-gate /* 25557c478bd9Sstevel@tonic-gate * Compare the unit address 25567c478bd9Sstevel@tonic-gate */ 25577c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 25587c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 25597c478bd9Sstevel@tonic-gate break; 25607c478bd9Sstevel@tonic-gate } 25617c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 25627c478bd9Sstevel@tonic-gate } 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate if (pip == NULL) { 25657c478bd9Sstevel@tonic-gate /* 25667c478bd9Sstevel@tonic-gate * This is a new path for this client device. Allocate and 25677c478bd9Sstevel@tonic-gate * initialize a new pathinfo node 25687c478bd9Sstevel@tonic-gate */ 25693c34adc5Sramat pip = i_mdi_pi_alloc(ph, paddr, ct); 25703c34adc5Sramat ASSERT(pip != NULL); 25713c34adc5Sramat path_allocated = 1; 25727c478bd9Sstevel@tonic-gate } 25737c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 25747c478bd9Sstevel@tonic-gate 25757c478bd9Sstevel@tonic-gate fail: 25767c478bd9Sstevel@tonic-gate /* 25777c478bd9Sstevel@tonic-gate * Release the global mutex. 25787c478bd9Sstevel@tonic-gate */ 2579*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 25807c478bd9Sstevel@tonic-gate 25817c478bd9Sstevel@tonic-gate /* 25827c478bd9Sstevel@tonic-gate * Mark the pHCI as stable 25837c478bd9Sstevel@tonic-gate */ 25847c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 25857c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 25867c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 25877c478bd9Sstevel@tonic-gate *ret_pip = pip; 25883c34adc5Sramat 25893c34adc5Sramat if (path_allocated) 25903c34adc5Sramat vhcache_pi_add(vh->vh_config, MDI_PI(pip)); 25913c34adc5Sramat 25927c478bd9Sstevel@tonic-gate return (rv); 25937c478bd9Sstevel@tonic-gate } 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 25967c478bd9Sstevel@tonic-gate int 25977c478bd9Sstevel@tonic-gate mdi_pi_alloc(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 25987c478bd9Sstevel@tonic-gate int flags, mdi_pathinfo_t **ret_pip) 25997c478bd9Sstevel@tonic-gate { 26007c478bd9Sstevel@tonic-gate return (mdi_pi_alloc_compatible(pdip, cname, caddr, paddr, NULL, 0, 26017c478bd9Sstevel@tonic-gate flags, ret_pip)); 26027c478bd9Sstevel@tonic-gate } 26037c478bd9Sstevel@tonic-gate 26047c478bd9Sstevel@tonic-gate /* 26057c478bd9Sstevel@tonic-gate * i_mdi_pi_alloc(): 26067c478bd9Sstevel@tonic-gate * Allocate a mdi_pathinfo node and add to the pHCI path list 26077c478bd9Sstevel@tonic-gate * Return Values: 26087c478bd9Sstevel@tonic-gate * mdi_pathinfo 26097c478bd9Sstevel@tonic-gate */ 2610*c73a93f2Sdm120769 26117c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 26127c478bd9Sstevel@tonic-gate static mdi_pathinfo_t * 26133c34adc5Sramat i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct) 26147c478bd9Sstevel@tonic-gate { 26153c34adc5Sramat mdi_pathinfo_t *pip; 26167c478bd9Sstevel@tonic-gate int ct_circular; 26177c478bd9Sstevel@tonic-gate int ph_circular; 26188c4f8890Srs135747 int se_flag; 26198c4f8890Srs135747 int kmem_flag; 26207c478bd9Sstevel@tonic-gate 26213c34adc5Sramat pip = kmem_zalloc(sizeof (struct mdi_pathinfo), KM_SLEEP); 26227c478bd9Sstevel@tonic-gate mutex_init(&MDI_PI(pip)->pi_mutex, NULL, MUTEX_DEFAULT, NULL); 26237c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PATHINFO_STATE_INIT | 26247c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_TRANSIENT; 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_USER_DISABLED(ph)) 26277c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED_TRANSIENT(ph)) 26307c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED(ph)) 26337c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_old_state = MDI_PATHINFO_STATE_INIT; 26367c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_state_cv, NULL, CV_DEFAULT, NULL); 26377c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = ct; 26387c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = ph; 26393c34adc5Sramat MDI_PI(pip)->pi_addr = kmem_alloc(strlen(paddr) + 1, KM_SLEEP); 26407c478bd9Sstevel@tonic-gate (void) strcpy(MDI_PI(pip)->pi_addr, paddr); 26413c34adc5Sramat (void) nvlist_alloc(&MDI_PI(pip)->pi_prop, NV_UNIQUE_NAME, KM_SLEEP); 26423c34adc5Sramat ASSERT(MDI_PI(pip)->pi_prop != NULL); 26437c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = NULL; 26447c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = NULL; 26457c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = NULL; 26467c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 26477c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 26487c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt = 0; 26497c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 26507c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = 1; 26517c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_ref_cv, NULL, CV_DEFAULT, NULL); 26527c478bd9Sstevel@tonic-gate 26537c478bd9Sstevel@tonic-gate /* 26547c478bd9Sstevel@tonic-gate * Lock both dev_info nodes against changes in parallel. 26557c478bd9Sstevel@tonic-gate */ 26567c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 26577c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 26587c478bd9Sstevel@tonic-gate 26597c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(ph, pip); 26607c478bd9Sstevel@tonic-gate i_mdi_client_add_path(ct, pip); 26617c478bd9Sstevel@tonic-gate 26627c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 26637c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 26647c478bd9Sstevel@tonic-gate 26658c4f8890Srs135747 /* determine interrupt context */ 26668c4f8890Srs135747 se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP; 26678c4f8890Srs135747 kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 26688c4f8890Srs135747 26698c4f8890Srs135747 i_ddi_di_cache_invalidate(kmem_flag); 26708c4f8890Srs135747 26717c478bd9Sstevel@tonic-gate return (pip); 26727c478bd9Sstevel@tonic-gate } 26737c478bd9Sstevel@tonic-gate 26747c478bd9Sstevel@tonic-gate /* 26757c478bd9Sstevel@tonic-gate * i_mdi_phci_add_path(): 26767c478bd9Sstevel@tonic-gate * Add a mdi_pathinfo node to pHCI list. 26777c478bd9Sstevel@tonic-gate * Notes: 26787c478bd9Sstevel@tonic-gate * Caller should per-pHCI mutex 26797c478bd9Sstevel@tonic-gate */ 2680*c73a93f2Sdm120769 26817c478bd9Sstevel@tonic-gate static void 26827c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 26837c478bd9Sstevel@tonic-gate { 26847c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 26857c478bd9Sstevel@tonic-gate 26867c478bd9Sstevel@tonic-gate if (ph->ph_path_head == NULL) { 26877c478bd9Sstevel@tonic-gate ph->ph_path_head = pip; 26887c478bd9Sstevel@tonic-gate } else { 26897c478bd9Sstevel@tonic-gate MDI_PI(ph->ph_path_tail)->pi_phci_link = MDI_PI(pip); 26907c478bd9Sstevel@tonic-gate } 26917c478bd9Sstevel@tonic-gate ph->ph_path_tail = pip; 26927c478bd9Sstevel@tonic-gate ph->ph_path_count++; 26937c478bd9Sstevel@tonic-gate } 26947c478bd9Sstevel@tonic-gate 26957c478bd9Sstevel@tonic-gate /* 26967c478bd9Sstevel@tonic-gate * i_mdi_client_add_path(): 26977c478bd9Sstevel@tonic-gate * Add mdi_pathinfo node to client list 26987c478bd9Sstevel@tonic-gate */ 2699*c73a93f2Sdm120769 27007c478bd9Sstevel@tonic-gate static void 27017c478bd9Sstevel@tonic-gate i_mdi_client_add_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 27027c478bd9Sstevel@tonic-gate { 27037c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 27047c478bd9Sstevel@tonic-gate 27057c478bd9Sstevel@tonic-gate if (ct->ct_path_head == NULL) { 27067c478bd9Sstevel@tonic-gate ct->ct_path_head = pip; 27077c478bd9Sstevel@tonic-gate } else { 27087c478bd9Sstevel@tonic-gate MDI_PI(ct->ct_path_tail)->pi_client_link = MDI_PI(pip); 27097c478bd9Sstevel@tonic-gate } 27107c478bd9Sstevel@tonic-gate ct->ct_path_tail = pip; 27117c478bd9Sstevel@tonic-gate ct->ct_path_count++; 27127c478bd9Sstevel@tonic-gate } 27137c478bd9Sstevel@tonic-gate 27147c478bd9Sstevel@tonic-gate /* 27157c478bd9Sstevel@tonic-gate * mdi_pi_free(): 27167c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node and also client device node if this 27177c478bd9Sstevel@tonic-gate * is the last path to the device 27187c478bd9Sstevel@tonic-gate * Return Values: 27197c478bd9Sstevel@tonic-gate * MDI_SUCCESS 27207c478bd9Sstevel@tonic-gate * MDI_FAILURE 27217c478bd9Sstevel@tonic-gate * MDI_BUSY 27227c478bd9Sstevel@tonic-gate */ 2723*c73a93f2Sdm120769 27247c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 27257c478bd9Sstevel@tonic-gate int 27267c478bd9Sstevel@tonic-gate mdi_pi_free(mdi_pathinfo_t *pip, int flags) 27277c478bd9Sstevel@tonic-gate { 27287c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 27297c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 27307c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 27317c478bd9Sstevel@tonic-gate mdi_client_t *ct; 27327c478bd9Sstevel@tonic-gate int (*f)(); 27337c478bd9Sstevel@tonic-gate int client_held = 0; 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 27367c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 27377c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 27387c478bd9Sstevel@tonic-gate if (ph == NULL) { 27397c478bd9Sstevel@tonic-gate /* 27407c478bd9Sstevel@tonic-gate * Invalid pHCI device, return failure 27417c478bd9Sstevel@tonic-gate */ 27427c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2743*c73a93f2Sdm120769 "!mdi_pi_free: invalid pHCI")); 27447c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27457c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27467c478bd9Sstevel@tonic-gate } 27477c478bd9Sstevel@tonic-gate 27487c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 27497c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 27507c478bd9Sstevel@tonic-gate if (vh == NULL) { 27517c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 27527c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2753*c73a93f2Sdm120769 "!mdi_pi_free: invalid vHCI")); 27547c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27557c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27567c478bd9Sstevel@tonic-gate } 27577c478bd9Sstevel@tonic-gate 27587c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 27597c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 27607c478bd9Sstevel@tonic-gate if (ct == NULL) { 27617c478bd9Sstevel@tonic-gate /* 27627c478bd9Sstevel@tonic-gate * Invalid Client device, return failure 27637c478bd9Sstevel@tonic-gate */ 27647c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2765*c73a93f2Sdm120769 "!mdi_pi_free: invalid client")); 27667c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27677c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27687c478bd9Sstevel@tonic-gate } 27697c478bd9Sstevel@tonic-gate 27707c478bd9Sstevel@tonic-gate /* 27717c478bd9Sstevel@tonic-gate * Check to see for busy condition. A mdi_pathinfo can only be freed 27727c478bd9Sstevel@tonic-gate * if the node state is either offline or init and the reference count 27737c478bd9Sstevel@tonic-gate * is zero. 27747c478bd9Sstevel@tonic-gate */ 27757c478bd9Sstevel@tonic-gate if (!(MDI_PI_IS_OFFLINE(pip) || MDI_PI_IS_INIT(pip) || 27767c478bd9Sstevel@tonic-gate MDI_PI_IS_INITING(pip))) { 27777c478bd9Sstevel@tonic-gate /* 27787c478bd9Sstevel@tonic-gate * Node is busy 27797c478bd9Sstevel@tonic-gate */ 2780*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_WARN, NULL, 2781*c73a93f2Sdm120769 "!mdi_pi_free: pathinfo node is busy pip=%p", pip)); 27827c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27837c478bd9Sstevel@tonic-gate return (MDI_BUSY); 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate 27867c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 27877c478bd9Sstevel@tonic-gate /* 27887c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 27897c478bd9Sstevel@tonic-gate */ 2790*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, "!mdi_pi_free: " 27917c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 2792*c73a93f2Sdm120769 MDI_PI(pip)->pi_ref_cnt, pip)); 27937c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 27947c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 27957c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 27967c478bd9Sstevel@tonic-gate /* 27977c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 27987c478bd9Sstevel@tonic-gate * being signaled. 27997c478bd9Sstevel@tonic-gate */ 2800*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, 28018c4f8890Srs135747 "!mdi_pi_free: " 28027c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 2803*c73a93f2Sdm120769 pip)); 2804*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, 28058c4f8890Srs135747 "!mdi_pi_free: " 28067c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 2807*c73a93f2Sdm120769 MDI_PI(pip)->pi_ref_cnt, pip)); 28087c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 28097c478bd9Sstevel@tonic-gate return (MDI_BUSY); 28107c478bd9Sstevel@tonic-gate } 28117c478bd9Sstevel@tonic-gate } 28127c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 28137c478bd9Sstevel@tonic-gate client_held = 1; 28147c478bd9Sstevel@tonic-gate } 28157c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 28167c478bd9Sstevel@tonic-gate 28173c34adc5Sramat vhcache_pi_remove(vh->vh_config, MDI_PI(pip)); 28183c34adc5Sramat 28197c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 28207c478bd9Sstevel@tonic-gate 2821*c73a93f2Sdm120769 /* Prevent further failovers till mdi_mutex is held */ 28227c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_PATH_FREE_IN_PROGRESS(ct); 28237c478bd9Sstevel@tonic-gate 28247c478bd9Sstevel@tonic-gate /* 28257c478bd9Sstevel@tonic-gate * Wait till failover is complete before removing this node. 28267c478bd9Sstevel@tonic-gate */ 28277c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 28287c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 2831*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 28327c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 28337c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_PATH_FREE_IN_PROGRESS(ct); 28347c478bd9Sstevel@tonic-gate 28357c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_INITING(pip)) { 28367c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_uninit; 28377c478bd9Sstevel@tonic-gate if (f != NULL) { 28387c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 28397c478bd9Sstevel@tonic-gate } 28407c478bd9Sstevel@tonic-gate } 28417c478bd9Sstevel@tonic-gate /* 28427c478bd9Sstevel@tonic-gate * If vo_pi_uninit() completed successfully. 28437c478bd9Sstevel@tonic-gate */ 28447c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 28457c478bd9Sstevel@tonic-gate if (client_held) { 28467c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_free " 28477c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 28487c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 28497c478bd9Sstevel@tonic-gate } 28507c478bd9Sstevel@tonic-gate i_mdi_pi_free(ph, pip, ct); 28517c478bd9Sstevel@tonic-gate if (ct->ct_path_count == 0) { 28527c478bd9Sstevel@tonic-gate /* 28537c478bd9Sstevel@tonic-gate * Client lost its last path. 28547c478bd9Sstevel@tonic-gate * Clean up the client device 28557c478bd9Sstevel@tonic-gate */ 28567c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 28577c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(ct->ct_vhci, ct); 2858*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 28597c478bd9Sstevel@tonic-gate return (rv); 28607c478bd9Sstevel@tonic-gate } 28617c478bd9Sstevel@tonic-gate } 28627c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 2863*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 28643c34adc5Sramat 28653c34adc5Sramat if (rv == MDI_FAILURE) 28663c34adc5Sramat vhcache_pi_add(vh->vh_config, MDI_PI(pip)); 28673c34adc5Sramat 28687c478bd9Sstevel@tonic-gate return (rv); 28697c478bd9Sstevel@tonic-gate } 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate /* 28727c478bd9Sstevel@tonic-gate * i_mdi_pi_free(): 28737c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node 28747c478bd9Sstevel@tonic-gate */ 28757c478bd9Sstevel@tonic-gate static void 28767c478bd9Sstevel@tonic-gate i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct) 28777c478bd9Sstevel@tonic-gate { 28787c478bd9Sstevel@tonic-gate int ct_circular; 28797c478bd9Sstevel@tonic-gate int ph_circular; 28808c4f8890Srs135747 int se_flag; 28818c4f8890Srs135747 int kmem_flag; 28827c478bd9Sstevel@tonic-gate 28837c478bd9Sstevel@tonic-gate /* 28847c478bd9Sstevel@tonic-gate * remove any per-path kstats 28857c478bd9Sstevel@tonic-gate */ 28867c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(pip); 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 28897c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 28907c478bd9Sstevel@tonic-gate 28917c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(ct, pip); 28927c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(ph, pip); 28937c478bd9Sstevel@tonic-gate 28947c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 28957c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 28967c478bd9Sstevel@tonic-gate 28978c4f8890Srs135747 /* determine interrupt context */ 28988c4f8890Srs135747 se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP; 28998c4f8890Srs135747 kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 29008c4f8890Srs135747 29018c4f8890Srs135747 i_ddi_di_cache_invalidate(kmem_flag); 29028c4f8890Srs135747 29037c478bd9Sstevel@tonic-gate mutex_destroy(&MDI_PI(pip)->pi_mutex); 29047c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_state_cv); 29057c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_ref_cv); 29067c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_addr) { 29077c478bd9Sstevel@tonic-gate kmem_free(MDI_PI(pip)->pi_addr, 29087c478bd9Sstevel@tonic-gate strlen(MDI_PI(pip)->pi_addr) + 1); 29097c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr = NULL; 29107c478bd9Sstevel@tonic-gate } 29117c478bd9Sstevel@tonic-gate 29127c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop) { 29137c478bd9Sstevel@tonic-gate (void) nvlist_free(MDI_PI(pip)->pi_prop); 29147c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_prop = NULL; 29157c478bd9Sstevel@tonic-gate } 29167c478bd9Sstevel@tonic-gate kmem_free(pip, sizeof (struct mdi_pathinfo)); 29177c478bd9Sstevel@tonic-gate } 29187c478bd9Sstevel@tonic-gate 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate /* 29217c478bd9Sstevel@tonic-gate * i_mdi_phci_remove_path(): 29227c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from pHCI list. 29237c478bd9Sstevel@tonic-gate * Notes: 29247c478bd9Sstevel@tonic-gate * Caller should hold per-pHCI mutex 29257c478bd9Sstevel@tonic-gate */ 2926*c73a93f2Sdm120769 29277c478bd9Sstevel@tonic-gate static void 29287c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 29297c478bd9Sstevel@tonic-gate { 29307c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 29317c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path = NULL; 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 29347c478bd9Sstevel@tonic-gate 29357c478bd9Sstevel@tonic-gate path = ph->ph_path_head; 29367c478bd9Sstevel@tonic-gate while (path != NULL) { 29377c478bd9Sstevel@tonic-gate if (path == pip) { 29387c478bd9Sstevel@tonic-gate break; 29397c478bd9Sstevel@tonic-gate } 29407c478bd9Sstevel@tonic-gate prev = path; 29417c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 29427c478bd9Sstevel@tonic-gate } 29437c478bd9Sstevel@tonic-gate 29447c478bd9Sstevel@tonic-gate if (path) { 29457c478bd9Sstevel@tonic-gate ph->ph_path_count--; 29467c478bd9Sstevel@tonic-gate if (prev) { 29477c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_phci_link = MDI_PI(path)->pi_phci_link; 29487c478bd9Sstevel@tonic-gate } else { 29497c478bd9Sstevel@tonic-gate ph->ph_path_head = 29507c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 29517c478bd9Sstevel@tonic-gate } 29527c478bd9Sstevel@tonic-gate if (ph->ph_path_tail == path) { 29537c478bd9Sstevel@tonic-gate ph->ph_path_tail = prev; 29547c478bd9Sstevel@tonic-gate } 29557c478bd9Sstevel@tonic-gate } 29567c478bd9Sstevel@tonic-gate 29577c478bd9Sstevel@tonic-gate /* 29587c478bd9Sstevel@tonic-gate * Clear the pHCI link 29597c478bd9Sstevel@tonic-gate */ 29607c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 29617c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = NULL; 29627c478bd9Sstevel@tonic-gate } 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate /* 29657c478bd9Sstevel@tonic-gate * i_mdi_client_remove_path(): 29667c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from client path list. 29677c478bd9Sstevel@tonic-gate */ 2968*c73a93f2Sdm120769 29697c478bd9Sstevel@tonic-gate static void 29707c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 29717c478bd9Sstevel@tonic-gate { 29727c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 29737c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path; 29747c478bd9Sstevel@tonic-gate 29757c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 29767c478bd9Sstevel@tonic-gate 29777c478bd9Sstevel@tonic-gate path = ct->ct_path_head; 29787c478bd9Sstevel@tonic-gate while (path != NULL) { 29797c478bd9Sstevel@tonic-gate if (path == pip) { 29807c478bd9Sstevel@tonic-gate break; 29817c478bd9Sstevel@tonic-gate } 29827c478bd9Sstevel@tonic-gate prev = path; 29837c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 29847c478bd9Sstevel@tonic-gate } 29857c478bd9Sstevel@tonic-gate 29867c478bd9Sstevel@tonic-gate if (path) { 29877c478bd9Sstevel@tonic-gate ct->ct_path_count--; 29887c478bd9Sstevel@tonic-gate if (prev) { 29897c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_client_link = 29907c478bd9Sstevel@tonic-gate MDI_PI(path)->pi_client_link; 29917c478bd9Sstevel@tonic-gate } else { 29927c478bd9Sstevel@tonic-gate ct->ct_path_head = 29937c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 29947c478bd9Sstevel@tonic-gate } 29957c478bd9Sstevel@tonic-gate if (ct->ct_path_tail == path) { 29967c478bd9Sstevel@tonic-gate ct->ct_path_tail = prev; 29977c478bd9Sstevel@tonic-gate } 29987c478bd9Sstevel@tonic-gate if (ct->ct_path_last == path) { 29997c478bd9Sstevel@tonic-gate ct->ct_path_last = ct->ct_path_head; 30007c478bd9Sstevel@tonic-gate } 30017c478bd9Sstevel@tonic-gate } 30027c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 30037c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = NULL; 30047c478bd9Sstevel@tonic-gate } 30057c478bd9Sstevel@tonic-gate 30067c478bd9Sstevel@tonic-gate /* 30077c478bd9Sstevel@tonic-gate * i_mdi_pi_state_change(): 30087c478bd9Sstevel@tonic-gate * online a mdi_pathinfo node 30097c478bd9Sstevel@tonic-gate * 30107c478bd9Sstevel@tonic-gate * Return Values: 30117c478bd9Sstevel@tonic-gate * MDI_SUCCESS 30127c478bd9Sstevel@tonic-gate * MDI_FAILURE 30137c478bd9Sstevel@tonic-gate */ 30147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 30157c478bd9Sstevel@tonic-gate static int 30167c478bd9Sstevel@tonic-gate i_mdi_pi_state_change(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state, int flag) 30177c478bd9Sstevel@tonic-gate { 30187c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 30197c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 30207c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 30217c478bd9Sstevel@tonic-gate mdi_client_t *ct; 30227c478bd9Sstevel@tonic-gate int (*f)(); 30237c478bd9Sstevel@tonic-gate dev_info_t *cdip; 30247c478bd9Sstevel@tonic-gate 30257c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 30267c478bd9Sstevel@tonic-gate 30277c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 30287c478bd9Sstevel@tonic-gate ASSERT(ph); 30297c478bd9Sstevel@tonic-gate if (ph == NULL) { 30307c478bd9Sstevel@tonic-gate /* 30317c478bd9Sstevel@tonic-gate * Invalid pHCI device, fail the request 30327c478bd9Sstevel@tonic-gate */ 30337c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30347c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 3035*c73a93f2Sdm120769 "!mdi_pi_state_change: invalid phci")); 30367c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30377c478bd9Sstevel@tonic-gate } 30387c478bd9Sstevel@tonic-gate 30397c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 30407c478bd9Sstevel@tonic-gate ASSERT(vh); 30417c478bd9Sstevel@tonic-gate if (vh == NULL) { 30427c478bd9Sstevel@tonic-gate /* 30437c478bd9Sstevel@tonic-gate * Invalid vHCI device, fail the request 30447c478bd9Sstevel@tonic-gate */ 30457c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30467c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 3047*c73a93f2Sdm120769 "!mdi_pi_state_change: invalid vhci")); 30487c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30497c478bd9Sstevel@tonic-gate } 30507c478bd9Sstevel@tonic-gate 30517c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 30527c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 30537c478bd9Sstevel@tonic-gate if (ct == NULL) { 30547c478bd9Sstevel@tonic-gate /* 30557c478bd9Sstevel@tonic-gate * Invalid client device, fail the request 30567c478bd9Sstevel@tonic-gate */ 30577c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30587c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 3059*c73a93f2Sdm120769 "!mdi_pi_state_change: invalid client")); 30607c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30617c478bd9Sstevel@tonic-gate } 30627c478bd9Sstevel@tonic-gate 30637c478bd9Sstevel@tonic-gate /* 30647c478bd9Sstevel@tonic-gate * If this path has not been initialized yet, Callback vHCI driver's 30657c478bd9Sstevel@tonic-gate * pathinfo node initialize entry point 30667c478bd9Sstevel@tonic-gate */ 30677c478bd9Sstevel@tonic-gate 30687c478bd9Sstevel@tonic-gate if (MDI_PI_IS_INITING(pip)) { 30697c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30707c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_init; 30717c478bd9Sstevel@tonic-gate if (f != NULL) { 30727c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 30737c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 3074*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_WARN, vh->vh_dip, 30757c478bd9Sstevel@tonic-gate "!vo_pi_init: failed vHCI=0x%p, pip=0x%p", 3076*c73a93f2Sdm120769 vh, pip)); 30777c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30787c478bd9Sstevel@tonic-gate } 30797c478bd9Sstevel@tonic-gate } 30807c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 30817c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 30827c478bd9Sstevel@tonic-gate } 30837c478bd9Sstevel@tonic-gate 30847c478bd9Sstevel@tonic-gate /* 30857c478bd9Sstevel@tonic-gate * Do not allow state transition when pHCI is in offline/suspended 30867c478bd9Sstevel@tonic-gate * states 30877c478bd9Sstevel@tonic-gate */ 30887c478bd9Sstevel@tonic-gate i_mdi_phci_lock(ph, pip); 30897c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 3090*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_WARN, NULL, 3091*c73a93f2Sdm120769 "!mdi_pi_state_change: pHCI not ready, pHCI=%p", ph)); 30927c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30937c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 30947c478bd9Sstevel@tonic-gate return (MDI_BUSY); 30957c478bd9Sstevel@tonic-gate } 30967c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 30977c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 30987c478bd9Sstevel@tonic-gate 30997c478bd9Sstevel@tonic-gate /* 31007c478bd9Sstevel@tonic-gate * Check if mdi_pathinfo state is in transient state. 31017c478bd9Sstevel@tonic-gate * If yes, offlining is in progress and wait till transient state is 31027c478bd9Sstevel@tonic-gate * cleared. 31037c478bd9Sstevel@tonic-gate */ 31047c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 31057c478bd9Sstevel@tonic-gate while (MDI_PI_IS_TRANSIENT(pip)) { 31067c478bd9Sstevel@tonic-gate cv_wait(&MDI_PI(pip)->pi_state_cv, 31077c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex); 31087c478bd9Sstevel@tonic-gate } 31097c478bd9Sstevel@tonic-gate } 31107c478bd9Sstevel@tonic-gate 31117c478bd9Sstevel@tonic-gate /* 31127c478bd9Sstevel@tonic-gate * Grab the client lock in reverse order sequence and release the 31137c478bd9Sstevel@tonic-gate * mdi_pathinfo mutex. 31147c478bd9Sstevel@tonic-gate */ 31157c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 31167c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31177c478bd9Sstevel@tonic-gate 31187c478bd9Sstevel@tonic-gate /* 31197c478bd9Sstevel@tonic-gate * Wait till failover state is cleared 31207c478bd9Sstevel@tonic-gate */ 31217c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 31227c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 31237c478bd9Sstevel@tonic-gate 31247c478bd9Sstevel@tonic-gate /* 31257c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 31267c478bd9Sstevel@tonic-gate */ 31277c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 31287c478bd9Sstevel@tonic-gate switch (state) { 31297c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_ONLINE: 31307c478bd9Sstevel@tonic-gate MDI_PI_SET_ONLINING(pip); 31317c478bd9Sstevel@tonic-gate break; 31327c478bd9Sstevel@tonic-gate 31337c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_STANDBY: 31347c478bd9Sstevel@tonic-gate MDI_PI_SET_STANDBYING(pip); 31357c478bd9Sstevel@tonic-gate break; 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_FAULT: 31387c478bd9Sstevel@tonic-gate /* 31397c478bd9Sstevel@tonic-gate * Mark the pathinfo state as FAULTED 31407c478bd9Sstevel@tonic-gate */ 31417c478bd9Sstevel@tonic-gate MDI_PI_SET_FAULTING(pip); 31427c478bd9Sstevel@tonic-gate MDI_PI_ERRSTAT(pip, MDI_PI_HARDERR); 31437c478bd9Sstevel@tonic-gate break; 31447c478bd9Sstevel@tonic-gate 31457c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_OFFLINE: 31467c478bd9Sstevel@tonic-gate /* 31477c478bd9Sstevel@tonic-gate * ndi_devi_offline() cannot hold pip or ct locks. 31487c478bd9Sstevel@tonic-gate */ 31497c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31507c478bd9Sstevel@tonic-gate /* 31517c478bd9Sstevel@tonic-gate * Do not offline if path will become last path and path 31527c478bd9Sstevel@tonic-gate * is busy for user initiated events. 31537c478bd9Sstevel@tonic-gate */ 31547c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 31557c478bd9Sstevel@tonic-gate if ((flag & NDI_DEVI_REMOVE) && 31567c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED)) { 31577c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 31587c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 31597c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 31607c478bd9Sstevel@tonic-gate /* 31617c478bd9Sstevel@tonic-gate * Convert to MDI error code 31627c478bd9Sstevel@tonic-gate */ 31637c478bd9Sstevel@tonic-gate switch (rv) { 31647c478bd9Sstevel@tonic-gate case NDI_BUSY: 31657c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 31667c478bd9Sstevel@tonic-gate break; 31677c478bd9Sstevel@tonic-gate default: 31687c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 31697c478bd9Sstevel@tonic-gate break; 31707c478bd9Sstevel@tonic-gate } 31717c478bd9Sstevel@tonic-gate goto state_change_exit; 31727c478bd9Sstevel@tonic-gate } else { 31737c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 31747c478bd9Sstevel@tonic-gate } 31757c478bd9Sstevel@tonic-gate } 31767c478bd9Sstevel@tonic-gate /* 31777c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 31787c478bd9Sstevel@tonic-gate */ 31797c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 31807c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 31817c478bd9Sstevel@tonic-gate break; 31827c478bd9Sstevel@tonic-gate } 31837c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31847c478bd9Sstevel@tonic-gate MDI_CLIENT_UNSTABLE(ct); 31857c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 31867c478bd9Sstevel@tonic-gate 31877c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 3188*c73a93f2Sdm120769 if (f != NULL) { 31897c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, state, 0, flag); 31907c478bd9Sstevel@tonic-gate if (rv == MDI_NOT_SUPPORTED) { 31917c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DEV_NOT_SUPPORTED(ct); 31927c478bd9Sstevel@tonic-gate } 31937c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 3194*c73a93f2Sdm120769 MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 31957c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 31967c478bd9Sstevel@tonic-gate } 3197*c73a93f2Sdm120769 } 3198*c73a93f2Sdm120769 MDI_CLIENT_LOCK(ct); 3199*c73a93f2Sdm120769 MDI_PI_LOCK(pip); 32007c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 32017c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 32027c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 32037c478bd9Sstevel@tonic-gate } else { 32047c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip); 32057c478bd9Sstevel@tonic-gate } 32067c478bd9Sstevel@tonic-gate } 32077c478bd9Sstevel@tonic-gate 32087c478bd9Sstevel@tonic-gate /* 32097c478bd9Sstevel@tonic-gate * Wake anyone waiting for this mdi_pathinfo node 32107c478bd9Sstevel@tonic-gate */ 32117c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 32127c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 32137c478bd9Sstevel@tonic-gate 32147c478bd9Sstevel@tonic-gate /* 32157c478bd9Sstevel@tonic-gate * Mark the client device as stable 32167c478bd9Sstevel@tonic-gate */ 32177c478bd9Sstevel@tonic-gate MDI_CLIENT_STABLE(ct); 32187c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 32197c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 32207c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 32217c478bd9Sstevel@tonic-gate 32227c478bd9Sstevel@tonic-gate /* 32237c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 32247c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 32257c478bd9Sstevel@tonic-gate * state accordingly 32267c478bd9Sstevel@tonic-gate */ 32277c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 32287c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 32297c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 32307c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 32317c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 3232737d277aScth if (cdip && !i_ddi_devi_attached(cdip) && 32337c478bd9Sstevel@tonic-gate ((state == MDI_PATHINFO_STATE_ONLINE) || 32347c478bd9Sstevel@tonic-gate (state == MDI_PATHINFO_STATE_STANDBY))) { 32357c478bd9Sstevel@tonic-gate 3236*c73a93f2Sdm120769 i_mdi_client_unlock(ct); 32377c478bd9Sstevel@tonic-gate /* 32387c478bd9Sstevel@tonic-gate * Must do ndi_devi_online() through 32397c478bd9Sstevel@tonic-gate * hotplug thread for deferred 32407c478bd9Sstevel@tonic-gate * attach mechanism to work 32417c478bd9Sstevel@tonic-gate */ 32427c478bd9Sstevel@tonic-gate rv = ndi_devi_online(cdip, 0); 3243*c73a93f2Sdm120769 i_mdi_client_lock(ct, NULL); 32447c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && 32457c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == 32467c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_DEGRADED)) { 32477c478bd9Sstevel@tonic-gate /* 32487c478bd9Sstevel@tonic-gate * ndi_devi_online failed. 32497c478bd9Sstevel@tonic-gate * Reset client flags to 32507c478bd9Sstevel@tonic-gate * offline. 32517c478bd9Sstevel@tonic-gate */ 32527c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 32537c478bd9Sstevel@tonic-gate "!ndi_devi_online: failed " 32547c478bd9Sstevel@tonic-gate " Error: %x", rv)); 32557c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 32567c478bd9Sstevel@tonic-gate } 32577c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 32587c478bd9Sstevel@tonic-gate /* Reset the path state */ 32597c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 32607c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = 32617c478bd9Sstevel@tonic-gate MDI_PI_OLD_STATE(pip); 32627c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 32637c478bd9Sstevel@tonic-gate } 32647c478bd9Sstevel@tonic-gate } 32657c478bd9Sstevel@tonic-gate break; 32667c478bd9Sstevel@tonic-gate 32677c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 32687c478bd9Sstevel@tonic-gate /* 32697c478bd9Sstevel@tonic-gate * This is the last path case for 32707c478bd9Sstevel@tonic-gate * non-user initiated events. 32717c478bd9Sstevel@tonic-gate */ 32727c478bd9Sstevel@tonic-gate if (((flag & NDI_DEVI_REMOVE) == 0) && 32737c478bd9Sstevel@tonic-gate cdip && (i_ddi_node_state(cdip) >= 32747c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 3275*c73a93f2Sdm120769 i_mdi_client_unlock(ct); 32767c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 3277*c73a93f2Sdm120769 i_mdi_client_lock(ct, NULL); 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 32807c478bd9Sstevel@tonic-gate /* 32817c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 32827c478bd9Sstevel@tonic-gate * Reset client flags to 32837c478bd9Sstevel@tonic-gate * online as the path could not 32847c478bd9Sstevel@tonic-gate * be offlined. 32857c478bd9Sstevel@tonic-gate */ 32867c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 32877c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 32887c478bd9Sstevel@tonic-gate " Error: %x", rv)); 32897c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 32907c478bd9Sstevel@tonic-gate } 32917c478bd9Sstevel@tonic-gate } 32927c478bd9Sstevel@tonic-gate break; 32937c478bd9Sstevel@tonic-gate } 32947c478bd9Sstevel@tonic-gate /* 32957c478bd9Sstevel@tonic-gate * Convert to MDI error code 32967c478bd9Sstevel@tonic-gate */ 32977c478bd9Sstevel@tonic-gate switch (rv) { 32987c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 32997c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 33007c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 33017c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 33027c478bd9Sstevel@tonic-gate break; 33037c478bd9Sstevel@tonic-gate case NDI_BUSY: 33047c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 33057c478bd9Sstevel@tonic-gate break; 33067c478bd9Sstevel@tonic-gate default: 33077c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 33087c478bd9Sstevel@tonic-gate break; 33097c478bd9Sstevel@tonic-gate } 33107c478bd9Sstevel@tonic-gate } 33117c478bd9Sstevel@tonic-gate } 33127c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 33137c478bd9Sstevel@tonic-gate 33147c478bd9Sstevel@tonic-gate state_change_exit: 33157c478bd9Sstevel@tonic-gate /* 33167c478bd9Sstevel@tonic-gate * Mark the pHCI as stable again. 33177c478bd9Sstevel@tonic-gate */ 33187c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 33197c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 33207c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 33217c478bd9Sstevel@tonic-gate return (rv); 33227c478bd9Sstevel@tonic-gate } 33237c478bd9Sstevel@tonic-gate 33247c478bd9Sstevel@tonic-gate /* 33257c478bd9Sstevel@tonic-gate * mdi_pi_online(): 33267c478bd9Sstevel@tonic-gate * Place the path_info node in the online state. The path is 33277c478bd9Sstevel@tonic-gate * now available to be selected by mdi_select_path() for 33287c478bd9Sstevel@tonic-gate * transporting I/O requests to client devices. 33297c478bd9Sstevel@tonic-gate * Return Values: 33307c478bd9Sstevel@tonic-gate * MDI_SUCCESS 33317c478bd9Sstevel@tonic-gate * MDI_FAILURE 33327c478bd9Sstevel@tonic-gate */ 33337c478bd9Sstevel@tonic-gate int 33347c478bd9Sstevel@tonic-gate mdi_pi_online(mdi_pathinfo_t *pip, int flags) 33357c478bd9Sstevel@tonic-gate { 33367c478bd9Sstevel@tonic-gate mdi_client_t *ct = MDI_PI(pip)->pi_client; 33377c478bd9Sstevel@tonic-gate dev_info_t *cdip; 33387c478bd9Sstevel@tonic-gate int client_held = 0; 33397c478bd9Sstevel@tonic-gate int rv; 33407c478bd9Sstevel@tonic-gate 33417c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 33427c478bd9Sstevel@tonic-gate rv = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_ONLINE, flags); 33437c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) 33447c478bd9Sstevel@tonic-gate return (rv); 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 33477c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 33487c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 3349*c73a93f2Sdm120769 "i_mdi_pm_hold_pip\n")); 33507c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 33517c478bd9Sstevel@tonic-gate client_held = 1; 33527c478bd9Sstevel@tonic-gate } 33537c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 33547c478bd9Sstevel@tonic-gate 33557c478bd9Sstevel@tonic-gate if (client_held) { 33567c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 33577c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 33587c478bd9Sstevel@tonic-gate rv = i_mdi_power_all_phci(ct); 33597c478bd9Sstevel@tonic-gate } 33607c478bd9Sstevel@tonic-gate 33617c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 3362*c73a93f2Sdm120769 "i_mdi_pm_hold_client\n")); 33637c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 33647c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 33657c478bd9Sstevel@tonic-gate } 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate /* 33687c478bd9Sstevel@tonic-gate * Create the per-path (pathinfo) IO and error kstats which 33697c478bd9Sstevel@tonic-gate * are reported via iostat(1m). 33707c478bd9Sstevel@tonic-gate * 33717c478bd9Sstevel@tonic-gate * Defer creating the per-path kstats if device is not yet 33727c478bd9Sstevel@tonic-gate * attached; the names of the kstats are constructed in part 33737c478bd9Sstevel@tonic-gate * using the devices instance number which is assigned during 33747c478bd9Sstevel@tonic-gate * process of attaching the client device. 33757c478bd9Sstevel@tonic-gate * 33767c478bd9Sstevel@tonic-gate * The framework post_attach handler, mdi_post_attach(), is 33777c478bd9Sstevel@tonic-gate * is responsible for initializing the client's pathinfo list 33787c478bd9Sstevel@tonic-gate * once successfully attached. 33797c478bd9Sstevel@tonic-gate */ 33807c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 33817c478bd9Sstevel@tonic-gate ASSERT(cdip); 3382737d277aScth if (cdip == NULL || !i_ddi_devi_attached(cdip)) 33837c478bd9Sstevel@tonic-gate return (rv); 33847c478bd9Sstevel@tonic-gate 33857c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 33867c478bd9Sstevel@tonic-gate rv = i_mdi_pi_kstat_create(pip); 33877c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 33887c478bd9Sstevel@tonic-gate return (rv); 33897c478bd9Sstevel@tonic-gate } 33907c478bd9Sstevel@tonic-gate 33917c478bd9Sstevel@tonic-gate /* 33927c478bd9Sstevel@tonic-gate * mdi_pi_standby(): 33937c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in standby state 33947c478bd9Sstevel@tonic-gate * 33957c478bd9Sstevel@tonic-gate * Return Values: 33967c478bd9Sstevel@tonic-gate * MDI_SUCCESS 33977c478bd9Sstevel@tonic-gate * MDI_FAILURE 33987c478bd9Sstevel@tonic-gate */ 33997c478bd9Sstevel@tonic-gate int 34007c478bd9Sstevel@tonic-gate mdi_pi_standby(mdi_pathinfo_t *pip, int flags) 34017c478bd9Sstevel@tonic-gate { 34027c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_STANDBY, flags)); 34037c478bd9Sstevel@tonic-gate } 34047c478bd9Sstevel@tonic-gate 34057c478bd9Sstevel@tonic-gate /* 34067c478bd9Sstevel@tonic-gate * mdi_pi_fault(): 34077c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in fault'ed state 34087c478bd9Sstevel@tonic-gate * Return Values: 34097c478bd9Sstevel@tonic-gate * MDI_SUCCESS 34107c478bd9Sstevel@tonic-gate * MDI_FAILURE 34117c478bd9Sstevel@tonic-gate */ 34127c478bd9Sstevel@tonic-gate int 34137c478bd9Sstevel@tonic-gate mdi_pi_fault(mdi_pathinfo_t *pip, int flags) 34147c478bd9Sstevel@tonic-gate { 34157c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_FAULT, flags)); 34167c478bd9Sstevel@tonic-gate } 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate /* 34197c478bd9Sstevel@tonic-gate * mdi_pi_offline(): 34207c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node. 34217c478bd9Sstevel@tonic-gate * Return Values: 34227c478bd9Sstevel@tonic-gate * MDI_SUCCESS 34237c478bd9Sstevel@tonic-gate * MDI_FAILURE 34247c478bd9Sstevel@tonic-gate */ 34257c478bd9Sstevel@tonic-gate int 34267c478bd9Sstevel@tonic-gate mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 34277c478bd9Sstevel@tonic-gate { 34287c478bd9Sstevel@tonic-gate int ret, client_held = 0; 34297c478bd9Sstevel@tonic-gate mdi_client_t *ct; 34307c478bd9Sstevel@tonic-gate 34317c478bd9Sstevel@tonic-gate ret = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_OFFLINE, flags); 34327c478bd9Sstevel@tonic-gate 34337c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) { 34347c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34357c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 34367c478bd9Sstevel@tonic-gate client_held = 1; 34377c478bd9Sstevel@tonic-gate } 34387c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34397c478bd9Sstevel@tonic-gate 34407c478bd9Sstevel@tonic-gate if (client_held) { 34417c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 34427c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 34437c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, 34447c478bd9Sstevel@tonic-gate "mdi_pi_offline i_mdi_pm_rele_client\n")); 34457c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 34467c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 34477c478bd9Sstevel@tonic-gate } 34487c478bd9Sstevel@tonic-gate } 34497c478bd9Sstevel@tonic-gate 34507c478bd9Sstevel@tonic-gate return (ret); 34517c478bd9Sstevel@tonic-gate } 34527c478bd9Sstevel@tonic-gate 34537c478bd9Sstevel@tonic-gate /* 34547c478bd9Sstevel@tonic-gate * i_mdi_pi_offline(): 34557c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node and call the vHCI driver's callback 34567c478bd9Sstevel@tonic-gate */ 34577c478bd9Sstevel@tonic-gate static int 34587c478bd9Sstevel@tonic-gate i_mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 34597c478bd9Sstevel@tonic-gate { 34607c478bd9Sstevel@tonic-gate dev_info_t *vdip = NULL; 34617c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 34627c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 34637c478bd9Sstevel@tonic-gate int (*f)(); 34647c478bd9Sstevel@tonic-gate int rv; 34657c478bd9Sstevel@tonic-gate 34667c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34677c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 34687c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 34697c478bd9Sstevel@tonic-gate 34707c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 34717c478bd9Sstevel@tonic-gate /* 34727c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 34737c478bd9Sstevel@tonic-gate */ 3474*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 34757c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 3476*c73a93f2Sdm120769 MDI_PI(pip)->pi_ref_cnt, pip)); 34777c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 34787c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 34797c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 34807c478bd9Sstevel@tonic-gate /* 34817c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 34827c478bd9Sstevel@tonic-gate * being signaled. 34837c478bd9Sstevel@tonic-gate */ 3484*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 34857c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 3486*c73a93f2Sdm120769 pip)); 3487*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 34887c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 3489*c73a93f2Sdm120769 MDI_PI(pip)->pi_ref_cnt, pip)); 34907c478bd9Sstevel@tonic-gate } 34917c478bd9Sstevel@tonic-gate } 34927c478bd9Sstevel@tonic-gate vh = ct->ct_vhci; 34937c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 34947c478bd9Sstevel@tonic-gate 34957c478bd9Sstevel@tonic-gate /* 34967c478bd9Sstevel@tonic-gate * Notify vHCI that has registered this event 34977c478bd9Sstevel@tonic-gate */ 34987c478bd9Sstevel@tonic-gate ASSERT(vh->vh_ops); 34997c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 35007c478bd9Sstevel@tonic-gate 35017c478bd9Sstevel@tonic-gate if (f != NULL) { 35027c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 35037c478bd9Sstevel@tonic-gate if ((rv = (*f)(vdip, pip, MDI_PATHINFO_STATE_OFFLINE, 0, 35047c478bd9Sstevel@tonic-gate flags)) != MDI_SUCCESS) { 3505*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_WARN, vdip, "!vo_path_offline failed " 3506*c73a93f2Sdm120769 "vdip 0x%x, pip 0x%x", vdip, pip)); 35077c478bd9Sstevel@tonic-gate } 35087c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 35097c478bd9Sstevel@tonic-gate } 35107c478bd9Sstevel@tonic-gate 35117c478bd9Sstevel@tonic-gate /* 35127c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state and clear the transient condition 35137c478bd9Sstevel@tonic-gate */ 35147c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINE(pip); 35157c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 35167c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 35177c478bd9Sstevel@tonic-gate 35187c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 35197c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 35207c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 35217c478bd9Sstevel@tonic-gate dev_info_t *cdip = ct->ct_dip; 35227c478bd9Sstevel@tonic-gate 35237c478bd9Sstevel@tonic-gate /* 35247c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 35257c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 35267c478bd9Sstevel@tonic-gate * state accordingly 35277c478bd9Sstevel@tonic-gate */ 35287c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 35297c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 35307c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 35317c478bd9Sstevel@tonic-gate if (cdip && 35327c478bd9Sstevel@tonic-gate (i_ddi_node_state(cdip) >= 35337c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 35347c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 35357c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 35367c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 35377c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 35387c478bd9Sstevel@tonic-gate /* 35397c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 35407c478bd9Sstevel@tonic-gate * Reset client flags to 35417c478bd9Sstevel@tonic-gate * online. 35427c478bd9Sstevel@tonic-gate */ 35437c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, cdip, 35447c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 35457c478bd9Sstevel@tonic-gate " Error: %x", rv)); 35467c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 35477c478bd9Sstevel@tonic-gate } 35487c478bd9Sstevel@tonic-gate } 35497c478bd9Sstevel@tonic-gate } 35507c478bd9Sstevel@tonic-gate /* 35517c478bd9Sstevel@tonic-gate * Convert to MDI error code 35527c478bd9Sstevel@tonic-gate */ 35537c478bd9Sstevel@tonic-gate switch (rv) { 35547c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 35557c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 35567c478bd9Sstevel@tonic-gate break; 35577c478bd9Sstevel@tonic-gate case NDI_BUSY: 35587c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 35597c478bd9Sstevel@tonic-gate break; 35607c478bd9Sstevel@tonic-gate default: 35617c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 35627c478bd9Sstevel@tonic-gate break; 35637c478bd9Sstevel@tonic-gate } 35647c478bd9Sstevel@tonic-gate } 35657c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 35667c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 35677c478bd9Sstevel@tonic-gate } 35687c478bd9Sstevel@tonic-gate 35697c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 35707c478bd9Sstevel@tonic-gate 35717c478bd9Sstevel@tonic-gate /* 35727c478bd9Sstevel@tonic-gate * Change in the mdi_pathinfo node state will impact the client state 35737c478bd9Sstevel@tonic-gate */ 35747c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!i_mdi_pi_offline ct = %p pip = %p", 3575*c73a93f2Sdm120769 ct, pip)); 35767c478bd9Sstevel@tonic-gate return (rv); 35777c478bd9Sstevel@tonic-gate } 35787c478bd9Sstevel@tonic-gate 35797c478bd9Sstevel@tonic-gate 35807c478bd9Sstevel@tonic-gate /* 35817c478bd9Sstevel@tonic-gate * mdi_pi_get_addr(): 35827c478bd9Sstevel@tonic-gate * Get the unit address associated with a mdi_pathinfo node 35837c478bd9Sstevel@tonic-gate * 35847c478bd9Sstevel@tonic-gate * Return Values: 35857c478bd9Sstevel@tonic-gate * char * 35867c478bd9Sstevel@tonic-gate */ 35877c478bd9Sstevel@tonic-gate char * 35887c478bd9Sstevel@tonic-gate mdi_pi_get_addr(mdi_pathinfo_t *pip) 35897c478bd9Sstevel@tonic-gate { 35907c478bd9Sstevel@tonic-gate if (pip == NULL) 35917c478bd9Sstevel@tonic-gate return (NULL); 35927c478bd9Sstevel@tonic-gate 359372a50065Scth return (MDI_PI(pip)->pi_addr); 35947c478bd9Sstevel@tonic-gate } 35957c478bd9Sstevel@tonic-gate 35967c478bd9Sstevel@tonic-gate /* 35977c478bd9Sstevel@tonic-gate * mdi_pi_get_client(): 35987c478bd9Sstevel@tonic-gate * Get the client devinfo associated with a mdi_pathinfo node 35997c478bd9Sstevel@tonic-gate * 36007c478bd9Sstevel@tonic-gate * Return Values: 36017c478bd9Sstevel@tonic-gate * Handle to client device dev_info node 36027c478bd9Sstevel@tonic-gate */ 36037c478bd9Sstevel@tonic-gate dev_info_t * 36047c478bd9Sstevel@tonic-gate mdi_pi_get_client(mdi_pathinfo_t *pip) 36057c478bd9Sstevel@tonic-gate { 36067c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 36077c478bd9Sstevel@tonic-gate if (pip) { 36087c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_client->ct_dip; 36097c478bd9Sstevel@tonic-gate } 36107c478bd9Sstevel@tonic-gate return (dip); 36117c478bd9Sstevel@tonic-gate } 36127c478bd9Sstevel@tonic-gate 36137c478bd9Sstevel@tonic-gate /* 36147c478bd9Sstevel@tonic-gate * mdi_pi_get_phci(): 36157c478bd9Sstevel@tonic-gate * Get the pHCI devinfo associated with the mdi_pathinfo node 36167c478bd9Sstevel@tonic-gate * Return Values: 36177c478bd9Sstevel@tonic-gate * Handle to dev_info node 36187c478bd9Sstevel@tonic-gate */ 36197c478bd9Sstevel@tonic-gate dev_info_t * 36207c478bd9Sstevel@tonic-gate mdi_pi_get_phci(mdi_pathinfo_t *pip) 36217c478bd9Sstevel@tonic-gate { 36227c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 36237c478bd9Sstevel@tonic-gate if (pip) { 36247c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_phci->ph_dip; 36257c478bd9Sstevel@tonic-gate } 36267c478bd9Sstevel@tonic-gate return (dip); 36277c478bd9Sstevel@tonic-gate } 36287c478bd9Sstevel@tonic-gate 36297c478bd9Sstevel@tonic-gate /* 36307c478bd9Sstevel@tonic-gate * mdi_pi_get_client_private(): 36317c478bd9Sstevel@tonic-gate * Get the client private information associated with the 36327c478bd9Sstevel@tonic-gate * mdi_pathinfo node 36337c478bd9Sstevel@tonic-gate */ 36347c478bd9Sstevel@tonic-gate void * 36357c478bd9Sstevel@tonic-gate mdi_pi_get_client_private(mdi_pathinfo_t *pip) 36367c478bd9Sstevel@tonic-gate { 36377c478bd9Sstevel@tonic-gate void *cprivate = NULL; 36387c478bd9Sstevel@tonic-gate if (pip) { 36397c478bd9Sstevel@tonic-gate cprivate = MDI_PI(pip)->pi_cprivate; 36407c478bd9Sstevel@tonic-gate } 36417c478bd9Sstevel@tonic-gate return (cprivate); 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate /* 36457c478bd9Sstevel@tonic-gate * mdi_pi_set_client_private(): 36467c478bd9Sstevel@tonic-gate * Set the client private information in the mdi_pathinfo node 36477c478bd9Sstevel@tonic-gate */ 36487c478bd9Sstevel@tonic-gate void 36497c478bd9Sstevel@tonic-gate mdi_pi_set_client_private(mdi_pathinfo_t *pip, void *priv) 36507c478bd9Sstevel@tonic-gate { 36517c478bd9Sstevel@tonic-gate if (pip) { 36527c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = priv; 36537c478bd9Sstevel@tonic-gate } 36547c478bd9Sstevel@tonic-gate } 36557c478bd9Sstevel@tonic-gate 36567c478bd9Sstevel@tonic-gate /* 36577c478bd9Sstevel@tonic-gate * mdi_pi_get_phci_private(): 36587c478bd9Sstevel@tonic-gate * Get the pHCI private information associated with the 36597c478bd9Sstevel@tonic-gate * mdi_pathinfo node 36607c478bd9Sstevel@tonic-gate */ 36617c478bd9Sstevel@tonic-gate caddr_t 36627c478bd9Sstevel@tonic-gate mdi_pi_get_phci_private(mdi_pathinfo_t *pip) 36637c478bd9Sstevel@tonic-gate { 36647c478bd9Sstevel@tonic-gate caddr_t pprivate = NULL; 36657c478bd9Sstevel@tonic-gate if (pip) { 36667c478bd9Sstevel@tonic-gate pprivate = MDI_PI(pip)->pi_pprivate; 36677c478bd9Sstevel@tonic-gate } 36687c478bd9Sstevel@tonic-gate return (pprivate); 36697c478bd9Sstevel@tonic-gate } 36707c478bd9Sstevel@tonic-gate 36717c478bd9Sstevel@tonic-gate /* 36727c478bd9Sstevel@tonic-gate * mdi_pi_set_phci_private(): 36737c478bd9Sstevel@tonic-gate * Set the pHCI private information in the mdi_pathinfo node 36747c478bd9Sstevel@tonic-gate */ 36757c478bd9Sstevel@tonic-gate void 36767c478bd9Sstevel@tonic-gate mdi_pi_set_phci_private(mdi_pathinfo_t *pip, caddr_t priv) 36777c478bd9Sstevel@tonic-gate { 36787c478bd9Sstevel@tonic-gate if (pip) { 36797c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = priv; 36807c478bd9Sstevel@tonic-gate } 36817c478bd9Sstevel@tonic-gate } 36827c478bd9Sstevel@tonic-gate 36837c478bd9Sstevel@tonic-gate /* 36847c478bd9Sstevel@tonic-gate * mdi_pi_get_state(): 36857c478bd9Sstevel@tonic-gate * Get the mdi_pathinfo node state. Transient states are internal 36867c478bd9Sstevel@tonic-gate * and not provided to the users 36877c478bd9Sstevel@tonic-gate */ 36887c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t 36897c478bd9Sstevel@tonic-gate mdi_pi_get_state(mdi_pathinfo_t *pip) 36907c478bd9Sstevel@tonic-gate { 36917c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t state = MDI_PATHINFO_STATE_INIT; 36927c478bd9Sstevel@tonic-gate 36937c478bd9Sstevel@tonic-gate if (pip) { 36947c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 36957c478bd9Sstevel@tonic-gate /* 36967c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 36977c478bd9Sstevel@tonic-gate * last good state. 36987c478bd9Sstevel@tonic-gate */ 36997c478bd9Sstevel@tonic-gate state = MDI_PI_OLD_STATE(pip); 37007c478bd9Sstevel@tonic-gate } else { 37017c478bd9Sstevel@tonic-gate state = MDI_PI_STATE(pip); 37027c478bd9Sstevel@tonic-gate } 37037c478bd9Sstevel@tonic-gate } 37047c478bd9Sstevel@tonic-gate return (state); 37057c478bd9Sstevel@tonic-gate } 37067c478bd9Sstevel@tonic-gate 37077c478bd9Sstevel@tonic-gate /* 37087c478bd9Sstevel@tonic-gate * Note that the following function needs to be the new interface for 37097c478bd9Sstevel@tonic-gate * mdi_pi_get_state when mpxio gets integrated to ON. 37107c478bd9Sstevel@tonic-gate */ 37117c478bd9Sstevel@tonic-gate int 37127c478bd9Sstevel@tonic-gate mdi_pi_get_state2(mdi_pathinfo_t *pip, mdi_pathinfo_state_t *state, 37137c478bd9Sstevel@tonic-gate uint32_t *ext_state) 37147c478bd9Sstevel@tonic-gate { 37157c478bd9Sstevel@tonic-gate *state = MDI_PATHINFO_STATE_INIT; 37167c478bd9Sstevel@tonic-gate 37177c478bd9Sstevel@tonic-gate if (pip) { 37187c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 37197c478bd9Sstevel@tonic-gate /* 37207c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 37217c478bd9Sstevel@tonic-gate * last good state. 37227c478bd9Sstevel@tonic-gate */ 37237c478bd9Sstevel@tonic-gate *state = MDI_PI_OLD_STATE(pip); 37247c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_OLD_EXT_STATE(pip); 37257c478bd9Sstevel@tonic-gate } else { 37267c478bd9Sstevel@tonic-gate *state = MDI_PI_STATE(pip); 37277c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_EXT_STATE(pip); 37287c478bd9Sstevel@tonic-gate } 37297c478bd9Sstevel@tonic-gate } 37307c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 37317c478bd9Sstevel@tonic-gate } 37327c478bd9Sstevel@tonic-gate 37337c478bd9Sstevel@tonic-gate /* 37347c478bd9Sstevel@tonic-gate * mdi_pi_get_preferred: 37357c478bd9Sstevel@tonic-gate * Get the preferred path flag 37367c478bd9Sstevel@tonic-gate */ 37377c478bd9Sstevel@tonic-gate int 37387c478bd9Sstevel@tonic-gate mdi_pi_get_preferred(mdi_pathinfo_t *pip) 37397c478bd9Sstevel@tonic-gate { 37407c478bd9Sstevel@tonic-gate if (pip) { 37417c478bd9Sstevel@tonic-gate return (MDI_PI(pip)->pi_preferred); 37427c478bd9Sstevel@tonic-gate } 37437c478bd9Sstevel@tonic-gate return (0); 37447c478bd9Sstevel@tonic-gate } 37457c478bd9Sstevel@tonic-gate 37467c478bd9Sstevel@tonic-gate /* 37477c478bd9Sstevel@tonic-gate * mdi_pi_set_preferred: 37487c478bd9Sstevel@tonic-gate * Set the preferred path flag 37497c478bd9Sstevel@tonic-gate */ 37507c478bd9Sstevel@tonic-gate void 37517c478bd9Sstevel@tonic-gate mdi_pi_set_preferred(mdi_pathinfo_t *pip, int preferred) 37527c478bd9Sstevel@tonic-gate { 37537c478bd9Sstevel@tonic-gate if (pip) { 37547c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = preferred; 37557c478bd9Sstevel@tonic-gate } 37567c478bd9Sstevel@tonic-gate } 37577c478bd9Sstevel@tonic-gate 3758*c73a93f2Sdm120769 37597c478bd9Sstevel@tonic-gate /* 37607c478bd9Sstevel@tonic-gate * mdi_pi_set_state(): 37617c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state 37627c478bd9Sstevel@tonic-gate */ 37637c478bd9Sstevel@tonic-gate void 37647c478bd9Sstevel@tonic-gate mdi_pi_set_state(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state) 37657c478bd9Sstevel@tonic-gate { 37667c478bd9Sstevel@tonic-gate uint32_t ext_state; 37677c478bd9Sstevel@tonic-gate 37687c478bd9Sstevel@tonic-gate if (pip) { 37697c478bd9Sstevel@tonic-gate ext_state = MDI_PI(pip)->pi_state & MDI_PATHINFO_EXT_STATE_MASK; 37707c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = state; 37717c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state |= ext_state; 37727c478bd9Sstevel@tonic-gate } 37737c478bd9Sstevel@tonic-gate } 37747c478bd9Sstevel@tonic-gate 37757c478bd9Sstevel@tonic-gate /* 37767c478bd9Sstevel@tonic-gate * Property functions: 37777c478bd9Sstevel@tonic-gate */ 3778*c73a93f2Sdm120769 37797c478bd9Sstevel@tonic-gate int 37807c478bd9Sstevel@tonic-gate i_map_nvlist_error_to_mdi(int val) 37817c478bd9Sstevel@tonic-gate { 37827c478bd9Sstevel@tonic-gate int rv; 37837c478bd9Sstevel@tonic-gate 37847c478bd9Sstevel@tonic-gate switch (val) { 37857c478bd9Sstevel@tonic-gate case 0: 37867c478bd9Sstevel@tonic-gate rv = DDI_PROP_SUCCESS; 37877c478bd9Sstevel@tonic-gate break; 37887c478bd9Sstevel@tonic-gate case EINVAL: 37897c478bd9Sstevel@tonic-gate case ENOTSUP: 37907c478bd9Sstevel@tonic-gate rv = DDI_PROP_INVAL_ARG; 37917c478bd9Sstevel@tonic-gate break; 37927c478bd9Sstevel@tonic-gate case ENOMEM: 37937c478bd9Sstevel@tonic-gate rv = DDI_PROP_NO_MEMORY; 37947c478bd9Sstevel@tonic-gate break; 37957c478bd9Sstevel@tonic-gate default: 37967c478bd9Sstevel@tonic-gate rv = DDI_PROP_NOT_FOUND; 37977c478bd9Sstevel@tonic-gate break; 37987c478bd9Sstevel@tonic-gate } 37997c478bd9Sstevel@tonic-gate return (rv); 38007c478bd9Sstevel@tonic-gate } 38017c478bd9Sstevel@tonic-gate 38027c478bd9Sstevel@tonic-gate /* 38037c478bd9Sstevel@tonic-gate * mdi_pi_get_next_prop(): 38047c478bd9Sstevel@tonic-gate * Property walk function. The caller should hold mdi_pi_lock() 38057c478bd9Sstevel@tonic-gate * and release by calling mdi_pi_unlock() at the end of walk to 38067c478bd9Sstevel@tonic-gate * get a consistent value. 38077c478bd9Sstevel@tonic-gate */ 3808*c73a93f2Sdm120769 38097c478bd9Sstevel@tonic-gate nvpair_t * 38107c478bd9Sstevel@tonic-gate mdi_pi_get_next_prop(mdi_pathinfo_t *pip, nvpair_t *prev) 38117c478bd9Sstevel@tonic-gate { 38127c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 38137c478bd9Sstevel@tonic-gate return (NULL); 38147c478bd9Sstevel@tonic-gate } 3815*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38167c478bd9Sstevel@tonic-gate return (nvlist_next_nvpair(MDI_PI(pip)->pi_prop, prev)); 38177c478bd9Sstevel@tonic-gate } 38187c478bd9Sstevel@tonic-gate 38197c478bd9Sstevel@tonic-gate /* 38207c478bd9Sstevel@tonic-gate * mdi_prop_remove(): 38217c478bd9Sstevel@tonic-gate * Remove the named property from the named list. 38227c478bd9Sstevel@tonic-gate */ 3823*c73a93f2Sdm120769 38247c478bd9Sstevel@tonic-gate int 38257c478bd9Sstevel@tonic-gate mdi_prop_remove(mdi_pathinfo_t *pip, char *name) 38267c478bd9Sstevel@tonic-gate { 38277c478bd9Sstevel@tonic-gate if (pip == NULL) { 38287c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38297c478bd9Sstevel@tonic-gate } 3830*c73a93f2Sdm120769 ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38317c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 38327c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 38337c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38347c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38357c478bd9Sstevel@tonic-gate } 38367c478bd9Sstevel@tonic-gate if (name) { 38377c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, name); 38387c478bd9Sstevel@tonic-gate } else { 38397c478bd9Sstevel@tonic-gate char nvp_name[MAXNAMELEN]; 38407c478bd9Sstevel@tonic-gate nvpair_t *nvp; 38417c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, NULL); 38427c478bd9Sstevel@tonic-gate while (nvp) { 38437c478bd9Sstevel@tonic-gate nvpair_t *next; 38447c478bd9Sstevel@tonic-gate next = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, nvp); 38457c478bd9Sstevel@tonic-gate (void) snprintf(nvp_name, MAXNAMELEN, "%s", 38467c478bd9Sstevel@tonic-gate nvpair_name(nvp)); 38477c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, 38487c478bd9Sstevel@tonic-gate nvp_name); 38497c478bd9Sstevel@tonic-gate nvp = next; 38507c478bd9Sstevel@tonic-gate } 38517c478bd9Sstevel@tonic-gate } 38527c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38537c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 38547c478bd9Sstevel@tonic-gate } 38557c478bd9Sstevel@tonic-gate 38567c478bd9Sstevel@tonic-gate /* 38577c478bd9Sstevel@tonic-gate * mdi_prop_size(): 38587c478bd9Sstevel@tonic-gate * Get buffer size needed to pack the property data. 38597c478bd9Sstevel@tonic-gate * Caller should hold the mdi_pathinfo_t lock to get a consistent 38607c478bd9Sstevel@tonic-gate * buffer size. 38617c478bd9Sstevel@tonic-gate */ 3862*c73a93f2Sdm120769 38637c478bd9Sstevel@tonic-gate int 38647c478bd9Sstevel@tonic-gate mdi_prop_size(mdi_pathinfo_t *pip, size_t *buflenp) 38657c478bd9Sstevel@tonic-gate { 38667c478bd9Sstevel@tonic-gate int rv; 38677c478bd9Sstevel@tonic-gate size_t bufsize; 38687c478bd9Sstevel@tonic-gate 38697c478bd9Sstevel@tonic-gate *buflenp = 0; 38707c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 38717c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38727c478bd9Sstevel@tonic-gate } 3873*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38747c478bd9Sstevel@tonic-gate rv = nvlist_size(MDI_PI(pip)->pi_prop, 38757c478bd9Sstevel@tonic-gate &bufsize, NV_ENCODE_NATIVE); 38767c478bd9Sstevel@tonic-gate *buflenp = bufsize; 38777c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 38787c478bd9Sstevel@tonic-gate } 38797c478bd9Sstevel@tonic-gate 38807c478bd9Sstevel@tonic-gate /* 38817c478bd9Sstevel@tonic-gate * mdi_prop_pack(): 38827c478bd9Sstevel@tonic-gate * pack the property list. The caller should hold the 38837c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node to get a consistent data 38847c478bd9Sstevel@tonic-gate */ 3885*c73a93f2Sdm120769 38867c478bd9Sstevel@tonic-gate int 38877c478bd9Sstevel@tonic-gate mdi_prop_pack(mdi_pathinfo_t *pip, char **bufp, uint_t buflen) 38887c478bd9Sstevel@tonic-gate { 38897c478bd9Sstevel@tonic-gate int rv; 38907c478bd9Sstevel@tonic-gate size_t bufsize; 38917c478bd9Sstevel@tonic-gate 38927c478bd9Sstevel@tonic-gate if ((pip == NULL) || MDI_PI(pip)->pi_prop == NULL) { 38937c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38947c478bd9Sstevel@tonic-gate } 38957c478bd9Sstevel@tonic-gate 3896*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38977c478bd9Sstevel@tonic-gate 38987c478bd9Sstevel@tonic-gate bufsize = buflen; 38997c478bd9Sstevel@tonic-gate rv = nvlist_pack(MDI_PI(pip)->pi_prop, bufp, (size_t *)&bufsize, 39007c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE, KM_SLEEP); 39017c478bd9Sstevel@tonic-gate 39027c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39037c478bd9Sstevel@tonic-gate } 39047c478bd9Sstevel@tonic-gate 39057c478bd9Sstevel@tonic-gate /* 39067c478bd9Sstevel@tonic-gate * mdi_prop_update_byte(): 39077c478bd9Sstevel@tonic-gate * Create/Update a byte property 39087c478bd9Sstevel@tonic-gate */ 39097c478bd9Sstevel@tonic-gate int 39107c478bd9Sstevel@tonic-gate mdi_prop_update_byte(mdi_pathinfo_t *pip, char *name, uchar_t data) 39117c478bd9Sstevel@tonic-gate { 39127c478bd9Sstevel@tonic-gate int rv; 39137c478bd9Sstevel@tonic-gate 39147c478bd9Sstevel@tonic-gate if (pip == NULL) { 39157c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39167c478bd9Sstevel@tonic-gate } 3917*c73a93f2Sdm120769 ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39187c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39197c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39207c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39217c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39227c478bd9Sstevel@tonic-gate } 39237c478bd9Sstevel@tonic-gate rv = nvlist_add_byte(MDI_PI(pip)->pi_prop, name, data); 39247c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39257c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39267c478bd9Sstevel@tonic-gate } 39277c478bd9Sstevel@tonic-gate 39287c478bd9Sstevel@tonic-gate /* 39297c478bd9Sstevel@tonic-gate * mdi_prop_update_byte_array(): 39307c478bd9Sstevel@tonic-gate * Create/Update a byte array property 39317c478bd9Sstevel@tonic-gate */ 39327c478bd9Sstevel@tonic-gate int 39337c478bd9Sstevel@tonic-gate mdi_prop_update_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t *data, 39347c478bd9Sstevel@tonic-gate uint_t nelements) 39357c478bd9Sstevel@tonic-gate { 39367c478bd9Sstevel@tonic-gate int rv; 39377c478bd9Sstevel@tonic-gate 39387c478bd9Sstevel@tonic-gate if (pip == NULL) { 39397c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39407c478bd9Sstevel@tonic-gate } 3941*c73a93f2Sdm120769 ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39427c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39437c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39447c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39457c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39467c478bd9Sstevel@tonic-gate } 39477c478bd9Sstevel@tonic-gate rv = nvlist_add_byte_array(MDI_PI(pip)->pi_prop, name, data, nelements); 39487c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39497c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39507c478bd9Sstevel@tonic-gate } 39517c478bd9Sstevel@tonic-gate 39527c478bd9Sstevel@tonic-gate /* 39537c478bd9Sstevel@tonic-gate * mdi_prop_update_int(): 39547c478bd9Sstevel@tonic-gate * Create/Update a 32 bit integer property 39557c478bd9Sstevel@tonic-gate */ 39567c478bd9Sstevel@tonic-gate int 39577c478bd9Sstevel@tonic-gate mdi_prop_update_int(mdi_pathinfo_t *pip, char *name, int data) 39587c478bd9Sstevel@tonic-gate { 39597c478bd9Sstevel@tonic-gate int rv; 39607c478bd9Sstevel@tonic-gate 39617c478bd9Sstevel@tonic-gate if (pip == NULL) { 39627c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39637c478bd9Sstevel@tonic-gate } 3964*c73a93f2Sdm120769 ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39657c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39667c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39677c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39687c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39697c478bd9Sstevel@tonic-gate } 39707c478bd9Sstevel@tonic-gate rv = nvlist_add_int32(MDI_PI(pip)->pi_prop, name, (int32_t)data); 39717c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39727c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39737c478bd9Sstevel@tonic-gate } 39747c478bd9Sstevel@tonic-gate 39757c478bd9Sstevel@tonic-gate /* 39767c478bd9Sstevel@tonic-gate * mdi_prop_update_int64(): 39777c478bd9Sstevel@tonic-gate * Create/Update a 64 bit integer property 39787c478bd9Sstevel@tonic-gate */ 39797c478bd9Sstevel@tonic-gate int 39807c478bd9Sstevel@tonic-gate mdi_prop_update_int64(mdi_pathinfo_t *pip, char *name, int64_t data) 39817c478bd9Sstevel@tonic-gate { 39827c478bd9Sstevel@tonic-gate int rv; 39837c478bd9Sstevel@tonic-gate 39847c478bd9Sstevel@tonic-gate if (pip == NULL) { 39857c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39867c478bd9Sstevel@tonic-gate } 3987*c73a93f2Sdm120769 ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39887c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39897c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39907c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39917c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39927c478bd9Sstevel@tonic-gate } 39937c478bd9Sstevel@tonic-gate rv = nvlist_add_int64(MDI_PI(pip)->pi_prop, name, data); 39947c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39957c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39967c478bd9Sstevel@tonic-gate } 39977c478bd9Sstevel@tonic-gate 39987c478bd9Sstevel@tonic-gate /* 39997c478bd9Sstevel@tonic-gate * mdi_prop_update_int_array(): 40007c478bd9Sstevel@tonic-gate * Create/Update a int array property 40017c478bd9Sstevel@tonic-gate */ 40027c478bd9Sstevel@tonic-gate int 40037c478bd9Sstevel@tonic-gate mdi_prop_update_int_array(mdi_pathinfo_t *pip, char *name, int *data, 40047c478bd9Sstevel@tonic-gate uint_t nelements) 40057c478bd9Sstevel@tonic-gate { 40067c478bd9Sstevel@tonic-gate int rv; 40077c478bd9Sstevel@tonic-gate 40087c478bd9Sstevel@tonic-gate if (pip == NULL) { 40097c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 40107c478bd9Sstevel@tonic-gate } 4011*c73a93f2Sdm120769 ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 40127c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 40137c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 40147c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40157c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40167c478bd9Sstevel@tonic-gate } 40177c478bd9Sstevel@tonic-gate rv = nvlist_add_int32_array(MDI_PI(pip)->pi_prop, name, (int32_t *)data, 40187c478bd9Sstevel@tonic-gate nelements); 40197c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40207c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40217c478bd9Sstevel@tonic-gate } 40227c478bd9Sstevel@tonic-gate 40237c478bd9Sstevel@tonic-gate /* 40247c478bd9Sstevel@tonic-gate * mdi_prop_update_string(): 40257c478bd9Sstevel@tonic-gate * Create/Update a string property 40267c478bd9Sstevel@tonic-gate */ 40277c478bd9Sstevel@tonic-gate int 40287c478bd9Sstevel@tonic-gate mdi_prop_update_string(mdi_pathinfo_t *pip, char *name, char *data) 40297c478bd9Sstevel@tonic-gate { 40307c478bd9Sstevel@tonic-gate int rv; 40317c478bd9Sstevel@tonic-gate 40327c478bd9Sstevel@tonic-gate if (pip == NULL) { 40337c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 40347c478bd9Sstevel@tonic-gate } 4035*c73a93f2Sdm120769 ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 40367c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 40377c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 40387c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40397c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40407c478bd9Sstevel@tonic-gate } 40417c478bd9Sstevel@tonic-gate rv = nvlist_add_string(MDI_PI(pip)->pi_prop, name, data); 40427c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40437c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40447c478bd9Sstevel@tonic-gate } 40457c478bd9Sstevel@tonic-gate 40467c478bd9Sstevel@tonic-gate /* 40477c478bd9Sstevel@tonic-gate * mdi_prop_update_string_array(): 40487c478bd9Sstevel@tonic-gate * Create/Update a string array property 40497c478bd9Sstevel@tonic-gate */ 40507c478bd9Sstevel@tonic-gate int 40517c478bd9Sstevel@tonic-gate mdi_prop_update_string_array(mdi_pathinfo_t *pip, char *name, char **data, 40527c478bd9Sstevel@tonic-gate uint_t nelements) 40537c478bd9Sstevel@tonic-gate { 40547c478bd9Sstevel@tonic-gate int rv; 40557c478bd9Sstevel@tonic-gate 40567c478bd9Sstevel@tonic-gate if (pip == NULL) { 40577c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 40587c478bd9Sstevel@tonic-gate } 4059*c73a93f2Sdm120769 ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 40607c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 40617c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 40627c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40637c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40647c478bd9Sstevel@tonic-gate } 40657c478bd9Sstevel@tonic-gate rv = nvlist_add_string_array(MDI_PI(pip)->pi_prop, name, data, 40667c478bd9Sstevel@tonic-gate nelements); 40677c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40687c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40697c478bd9Sstevel@tonic-gate } 40707c478bd9Sstevel@tonic-gate 40717c478bd9Sstevel@tonic-gate /* 40727c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte(): 40737c478bd9Sstevel@tonic-gate * Look for byte property identified by name. The data returned 40747c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 40757c478bd9Sstevel@tonic-gate * is alive. 40767c478bd9Sstevel@tonic-gate */ 40777c478bd9Sstevel@tonic-gate int 40787c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte(mdi_pathinfo_t *pip, char *name, uchar_t *data) 40797c478bd9Sstevel@tonic-gate { 40807c478bd9Sstevel@tonic-gate int rv; 40817c478bd9Sstevel@tonic-gate 40827c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 40837c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40847c478bd9Sstevel@tonic-gate } 40857c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte(MDI_PI(pip)->pi_prop, name, data); 40867c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40877c478bd9Sstevel@tonic-gate } 40887c478bd9Sstevel@tonic-gate 40897c478bd9Sstevel@tonic-gate 40907c478bd9Sstevel@tonic-gate /* 40917c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte_array(): 40927c478bd9Sstevel@tonic-gate * Look for byte array property identified by name. The data 40937c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 40947c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 40957c478bd9Sstevel@tonic-gate */ 40967c478bd9Sstevel@tonic-gate int 40977c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t **data, 40987c478bd9Sstevel@tonic-gate uint_t *nelements) 40997c478bd9Sstevel@tonic-gate { 41007c478bd9Sstevel@tonic-gate int rv; 41017c478bd9Sstevel@tonic-gate 41027c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41037c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41047c478bd9Sstevel@tonic-gate } 41057c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte_array(MDI_PI(pip)->pi_prop, name, data, 41067c478bd9Sstevel@tonic-gate nelements); 41077c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41087c478bd9Sstevel@tonic-gate } 41097c478bd9Sstevel@tonic-gate 41107c478bd9Sstevel@tonic-gate /* 41117c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int(): 41127c478bd9Sstevel@tonic-gate * Look for int property identified by name. The data returned 41137c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t 41147c478bd9Sstevel@tonic-gate * node is alive. 41157c478bd9Sstevel@tonic-gate */ 41167c478bd9Sstevel@tonic-gate int 41177c478bd9Sstevel@tonic-gate mdi_prop_lookup_int(mdi_pathinfo_t *pip, char *name, int *data) 41187c478bd9Sstevel@tonic-gate { 41197c478bd9Sstevel@tonic-gate int rv; 41207c478bd9Sstevel@tonic-gate 41217c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41227c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41237c478bd9Sstevel@tonic-gate } 41247c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32(MDI_PI(pip)->pi_prop, name, (int32_t *)data); 41257c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41267c478bd9Sstevel@tonic-gate } 41277c478bd9Sstevel@tonic-gate 41287c478bd9Sstevel@tonic-gate /* 41297c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int64(): 41307c478bd9Sstevel@tonic-gate * Look for int64 property identified by name. The data returned 41317c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 41327c478bd9Sstevel@tonic-gate * is alive. 41337c478bd9Sstevel@tonic-gate */ 41347c478bd9Sstevel@tonic-gate int 41357c478bd9Sstevel@tonic-gate mdi_prop_lookup_int64(mdi_pathinfo_t *pip, char *name, int64_t *data) 41367c478bd9Sstevel@tonic-gate { 41377c478bd9Sstevel@tonic-gate int rv; 41387c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41397c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41407c478bd9Sstevel@tonic-gate } 41417c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int64(MDI_PI(pip)->pi_prop, name, data); 41427c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41437c478bd9Sstevel@tonic-gate } 41447c478bd9Sstevel@tonic-gate 41457c478bd9Sstevel@tonic-gate /* 41467c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int_array(): 41477c478bd9Sstevel@tonic-gate * Look for int array property identified by name. The data 41487c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 41497c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 41507c478bd9Sstevel@tonic-gate */ 41517c478bd9Sstevel@tonic-gate int 41527c478bd9Sstevel@tonic-gate mdi_prop_lookup_int_array(mdi_pathinfo_t *pip, char *name, int **data, 41537c478bd9Sstevel@tonic-gate uint_t *nelements) 41547c478bd9Sstevel@tonic-gate { 41557c478bd9Sstevel@tonic-gate int rv; 41567c478bd9Sstevel@tonic-gate 41577c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41587c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41597c478bd9Sstevel@tonic-gate } 41607c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32_array(MDI_PI(pip)->pi_prop, name, 41617c478bd9Sstevel@tonic-gate (int32_t **)data, nelements); 41627c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41637c478bd9Sstevel@tonic-gate } 41647c478bd9Sstevel@tonic-gate 41657c478bd9Sstevel@tonic-gate /* 41667c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string(): 41677c478bd9Sstevel@tonic-gate * Look for string property identified by name. The data 41687c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 41697c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 41707c478bd9Sstevel@tonic-gate */ 41717c478bd9Sstevel@tonic-gate int 41727c478bd9Sstevel@tonic-gate mdi_prop_lookup_string(mdi_pathinfo_t *pip, char *name, char **data) 41737c478bd9Sstevel@tonic-gate { 41747c478bd9Sstevel@tonic-gate int rv; 41757c478bd9Sstevel@tonic-gate 41767c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41777c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41787c478bd9Sstevel@tonic-gate } 41797c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string(MDI_PI(pip)->pi_prop, name, data); 41807c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41817c478bd9Sstevel@tonic-gate } 41827c478bd9Sstevel@tonic-gate 41837c478bd9Sstevel@tonic-gate /* 41847c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string_array(): 41857c478bd9Sstevel@tonic-gate * Look for string array property identified by name. The data 41867c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 41877c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 41887c478bd9Sstevel@tonic-gate */ 4189*c73a93f2Sdm120769 41907c478bd9Sstevel@tonic-gate int 41917c478bd9Sstevel@tonic-gate mdi_prop_lookup_string_array(mdi_pathinfo_t *pip, char *name, char ***data, 41927c478bd9Sstevel@tonic-gate uint_t *nelements) 41937c478bd9Sstevel@tonic-gate { 41947c478bd9Sstevel@tonic-gate int rv; 41957c478bd9Sstevel@tonic-gate 41967c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41977c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41987c478bd9Sstevel@tonic-gate } 41997c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string_array(MDI_PI(pip)->pi_prop, name, data, 42007c478bd9Sstevel@tonic-gate nelements); 42017c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 42027c478bd9Sstevel@tonic-gate } 42037c478bd9Sstevel@tonic-gate 42047c478bd9Sstevel@tonic-gate /* 42057c478bd9Sstevel@tonic-gate * mdi_prop_free(): 42067c478bd9Sstevel@tonic-gate * Symmetrical function to ddi_prop_free(). nvlist_lookup_xx() 42077c478bd9Sstevel@tonic-gate * functions return the pointer to actual property data and not a 42087c478bd9Sstevel@tonic-gate * copy of it. So the data returned is valid as long as 42097c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is valid. 42107c478bd9Sstevel@tonic-gate */ 4211*c73a93f2Sdm120769 42127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 42137c478bd9Sstevel@tonic-gate int 42147c478bd9Sstevel@tonic-gate mdi_prop_free(void *data) 42157c478bd9Sstevel@tonic-gate { 42167c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 42177c478bd9Sstevel@tonic-gate } 42187c478bd9Sstevel@tonic-gate 42197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 42207c478bd9Sstevel@tonic-gate static void 42217c478bd9Sstevel@tonic-gate i_mdi_report_path_state(mdi_client_t *ct, mdi_pathinfo_t *pip) 42227c478bd9Sstevel@tonic-gate { 42237c478bd9Sstevel@tonic-gate char *phci_path, *ct_path; 42247c478bd9Sstevel@tonic-gate char *ct_status; 42257c478bd9Sstevel@tonic-gate char *status; 42267c478bd9Sstevel@tonic-gate dev_info_t *dip = ct->ct_dip; 42277c478bd9Sstevel@tonic-gate char lb_buf[64]; 42287c478bd9Sstevel@tonic-gate 4229*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&ct->ct_mutex)); 42307c478bd9Sstevel@tonic-gate if ((dip == NULL) || (ddi_get_instance(dip) == -1) || 42317c478bd9Sstevel@tonic-gate (MDI_CLIENT_IS_REPORT_DEV_NEEDED(ct) == 0)) { 42327c478bd9Sstevel@tonic-gate return; 42337c478bd9Sstevel@tonic-gate } 42347c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL) { 42357c478bd9Sstevel@tonic-gate ct_status = "optimal"; 42367c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) { 42377c478bd9Sstevel@tonic-gate ct_status = "degraded"; 42387c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 42397c478bd9Sstevel@tonic-gate ct_status = "failed"; 42407c478bd9Sstevel@tonic-gate } else { 42417c478bd9Sstevel@tonic-gate ct_status = "unknown"; 42427c478bd9Sstevel@tonic-gate } 42437c478bd9Sstevel@tonic-gate 42447c478bd9Sstevel@tonic-gate if (MDI_PI_IS_OFFLINE(pip)) { 42457c478bd9Sstevel@tonic-gate status = "offline"; 42467c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_ONLINE(pip)) { 42477c478bd9Sstevel@tonic-gate status = "online"; 42487c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_STANDBY(pip)) { 42497c478bd9Sstevel@tonic-gate status = "standby"; 42507c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_FAULT(pip)) { 42517c478bd9Sstevel@tonic-gate status = "faulted"; 42527c478bd9Sstevel@tonic-gate } else { 42537c478bd9Sstevel@tonic-gate status = "unknown"; 42547c478bd9Sstevel@tonic-gate } 42557c478bd9Sstevel@tonic-gate 42567c478bd9Sstevel@tonic-gate if (ct->ct_lb == LOAD_BALANCE_LBA) { 42577c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 42587c478bd9Sstevel@tonic-gate "%s, region-size: %d", mdi_load_balance_lba, 42597c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size); 42607c478bd9Sstevel@tonic-gate } else if (ct->ct_lb == LOAD_BALANCE_NONE) { 42617c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 42627c478bd9Sstevel@tonic-gate "%s", mdi_load_balance_none); 42637c478bd9Sstevel@tonic-gate } else { 42647c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), "%s", 42657c478bd9Sstevel@tonic-gate mdi_load_balance_rr); 42667c478bd9Sstevel@tonic-gate } 42677c478bd9Sstevel@tonic-gate 42687c478bd9Sstevel@tonic-gate if (dip) { 42697c478bd9Sstevel@tonic-gate ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 42707c478bd9Sstevel@tonic-gate phci_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 42717c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s (%s%d) multipath status: %s, " 42727c478bd9Sstevel@tonic-gate "path %s (%s%d) to target address: %s is %s" 42737c478bd9Sstevel@tonic-gate " Load balancing: %s\n", 42747c478bd9Sstevel@tonic-gate ddi_pathname(dip, ct_path), ddi_driver_name(dip), 42757c478bd9Sstevel@tonic-gate ddi_get_instance(dip), ct_status, 42767c478bd9Sstevel@tonic-gate ddi_pathname(MDI_PI(pip)->pi_phci->ph_dip, phci_path), 42777c478bd9Sstevel@tonic-gate ddi_driver_name(MDI_PI(pip)->pi_phci->ph_dip), 42787c478bd9Sstevel@tonic-gate ddi_get_instance(MDI_PI(pip)->pi_phci->ph_dip), 42797c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr, status, lb_buf); 42807c478bd9Sstevel@tonic-gate kmem_free(phci_path, MAXPATHLEN); 42817c478bd9Sstevel@tonic-gate kmem_free(ct_path, MAXPATHLEN); 42827c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct); 42837c478bd9Sstevel@tonic-gate } 42847c478bd9Sstevel@tonic-gate } 42857c478bd9Sstevel@tonic-gate 42867c478bd9Sstevel@tonic-gate #ifdef DEBUG 42877c478bd9Sstevel@tonic-gate /* 42887c478bd9Sstevel@tonic-gate * i_mdi_log(): 42897c478bd9Sstevel@tonic-gate * Utility function for error message management 42907c478bd9Sstevel@tonic-gate * 42917c478bd9Sstevel@tonic-gate */ 4292*c73a93f2Sdm120769 4293*c73a93f2Sdm120769 /*VARARGS3*/ 42947c478bd9Sstevel@tonic-gate static void 42957c478bd9Sstevel@tonic-gate i_mdi_log(int level, dev_info_t *dip, const char *fmt, ...) 42967c478bd9Sstevel@tonic-gate { 4297144dfaa9Scth char buf[MAXNAMELEN]; 4298*c73a93f2Sdm120769 char name[MAXNAMELEN]; 42997c478bd9Sstevel@tonic-gate va_list ap; 43007c478bd9Sstevel@tonic-gate int log_only = 0; 43017c478bd9Sstevel@tonic-gate int boot_only = 0; 43027c478bd9Sstevel@tonic-gate int console_only = 0; 43037c478bd9Sstevel@tonic-gate 43047c478bd9Sstevel@tonic-gate if (dip) { 4305*c73a93f2Sdm120769 if (level == CE_PANIC || level == CE_WARN || level == CE_NOTE) { 4306*c73a93f2Sdm120769 (void) snprintf(name, MAXNAMELEN, "%s%d:\n", 43077c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip)); 43087c478bd9Sstevel@tonic-gate } else { 4309*c73a93f2Sdm120769 (void) snprintf(name, MAXNAMELEN, "%s%d:", 4310*c73a93f2Sdm120769 ddi_node_name(dip), ddi_get_instance(dip)); 4311*c73a93f2Sdm120769 } 4312*c73a93f2Sdm120769 } else { 4313*c73a93f2Sdm120769 name[0] = '\0'; 43147c478bd9Sstevel@tonic-gate } 43157c478bd9Sstevel@tonic-gate 43167c478bd9Sstevel@tonic-gate va_start(ap, fmt); 43177c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, MAXNAMELEN, fmt, ap); 43187c478bd9Sstevel@tonic-gate va_end(ap); 43197c478bd9Sstevel@tonic-gate 43207c478bd9Sstevel@tonic-gate switch (buf[0]) { 43217c478bd9Sstevel@tonic-gate case '!': 43227c478bd9Sstevel@tonic-gate log_only = 1; 43237c478bd9Sstevel@tonic-gate break; 43247c478bd9Sstevel@tonic-gate case '?': 43257c478bd9Sstevel@tonic-gate boot_only = 1; 43267c478bd9Sstevel@tonic-gate break; 43277c478bd9Sstevel@tonic-gate case '^': 43287c478bd9Sstevel@tonic-gate console_only = 1; 43297c478bd9Sstevel@tonic-gate break; 43307c478bd9Sstevel@tonic-gate } 43317c478bd9Sstevel@tonic-gate 43327c478bd9Sstevel@tonic-gate switch (level) { 43337c478bd9Sstevel@tonic-gate case CE_NOTE: 43347c478bd9Sstevel@tonic-gate level = CE_CONT; 43357c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 43367c478bd9Sstevel@tonic-gate case CE_CONT: 43377c478bd9Sstevel@tonic-gate case CE_WARN: 43387c478bd9Sstevel@tonic-gate case CE_PANIC: 43397c478bd9Sstevel@tonic-gate if (boot_only) { 4340*c73a93f2Sdm120769 cmn_err(level, "?%s\t%s", name, &buf[1]); 43417c478bd9Sstevel@tonic-gate } else if (console_only) { 4342*c73a93f2Sdm120769 cmn_err(level, "^%s\t%s", name, &buf[1]); 43437c478bd9Sstevel@tonic-gate } else if (log_only) { 4344*c73a93f2Sdm120769 cmn_err(level, "!%s\t%s", name, &buf[1]); 43457c478bd9Sstevel@tonic-gate } else { 4346*c73a93f2Sdm120769 cmn_err(level, "%s\t%s", name, buf); 43477c478bd9Sstevel@tonic-gate } 43487c478bd9Sstevel@tonic-gate break; 43497c478bd9Sstevel@tonic-gate default: 4350*c73a93f2Sdm120769 cmn_err(level, "%s\t%s", name, buf); 43517c478bd9Sstevel@tonic-gate break; 43527c478bd9Sstevel@tonic-gate } 43537c478bd9Sstevel@tonic-gate } 43547c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 43557c478bd9Sstevel@tonic-gate 43567c478bd9Sstevel@tonic-gate void 43577c478bd9Sstevel@tonic-gate i_mdi_client_online(dev_info_t *ct_dip) 43587c478bd9Sstevel@tonic-gate { 43597c478bd9Sstevel@tonic-gate mdi_client_t *ct; 43607c478bd9Sstevel@tonic-gate 43617c478bd9Sstevel@tonic-gate /* 43627c478bd9Sstevel@tonic-gate * Client online notification. Mark client state as online 43637c478bd9Sstevel@tonic-gate * restore our binding with dev_info node 43647c478bd9Sstevel@tonic-gate */ 43657c478bd9Sstevel@tonic-gate ct = i_devi_get_client(ct_dip); 43667c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 43677c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 43687c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 43697c478bd9Sstevel@tonic-gate /* catch for any memory leaks */ 43707c478bd9Sstevel@tonic-gate ASSERT((ct->ct_dip == NULL) || (ct->ct_dip == ct_dip)); 43717c478bd9Sstevel@tonic-gate ct->ct_dip = ct_dip; 43727c478bd9Sstevel@tonic-gate 43737c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) 43747c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 43757c478bd9Sstevel@tonic-gate 43767c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct_dip, "i_mdi_client_online " 4377*c73a93f2Sdm120769 "i_mdi_pm_hold_client\n")); 43787c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 43797c478bd9Sstevel@tonic-gate 43807c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 43817c478bd9Sstevel@tonic-gate } 43827c478bd9Sstevel@tonic-gate 43837c478bd9Sstevel@tonic-gate void 43847c478bd9Sstevel@tonic-gate i_mdi_phci_online(dev_info_t *ph_dip) 43857c478bd9Sstevel@tonic-gate { 43867c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 43877c478bd9Sstevel@tonic-gate 43887c478bd9Sstevel@tonic-gate /* pHCI online notification. Mark state accordingly */ 43897c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(ph_dip); 43907c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 43917c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 43927c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 43937c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 43947c478bd9Sstevel@tonic-gate } 43957c478bd9Sstevel@tonic-gate 43967c478bd9Sstevel@tonic-gate /* 43977c478bd9Sstevel@tonic-gate * mdi_devi_online(): 43987c478bd9Sstevel@tonic-gate * Online notification from NDI framework on pHCI/client 43997c478bd9Sstevel@tonic-gate * device online. 44007c478bd9Sstevel@tonic-gate * Return Values: 44017c478bd9Sstevel@tonic-gate * NDI_SUCCESS 44027c478bd9Sstevel@tonic-gate * MDI_FAILURE 44037c478bd9Sstevel@tonic-gate */ 4404*c73a93f2Sdm120769 44057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 44067c478bd9Sstevel@tonic-gate int 44077c478bd9Sstevel@tonic-gate mdi_devi_online(dev_info_t *dip, uint_t flags) 44087c478bd9Sstevel@tonic-gate { 44097c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 44107c478bd9Sstevel@tonic-gate i_mdi_phci_online(dip); 44117c478bd9Sstevel@tonic-gate } 44127c478bd9Sstevel@tonic-gate 44137c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 44147c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 44157c478bd9Sstevel@tonic-gate } 44167c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 44177c478bd9Sstevel@tonic-gate } 44187c478bd9Sstevel@tonic-gate 44197c478bd9Sstevel@tonic-gate /* 44207c478bd9Sstevel@tonic-gate * mdi_devi_offline(): 44217c478bd9Sstevel@tonic-gate * Offline notification from NDI framework on pHCI/Client device 44227c478bd9Sstevel@tonic-gate * offline. 44237c478bd9Sstevel@tonic-gate * 44247c478bd9Sstevel@tonic-gate * Return Values: 44257c478bd9Sstevel@tonic-gate * NDI_SUCCESS 44267c478bd9Sstevel@tonic-gate * NDI_FAILURE 44277c478bd9Sstevel@tonic-gate */ 4428*c73a93f2Sdm120769 44297c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 44307c478bd9Sstevel@tonic-gate int 44317c478bd9Sstevel@tonic-gate mdi_devi_offline(dev_info_t *dip, uint_t flags) 44327c478bd9Sstevel@tonic-gate { 44337c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 44347c478bd9Sstevel@tonic-gate 44357c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 44367c478bd9Sstevel@tonic-gate rv = i_mdi_client_offline(dip, flags); 44377c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) 44387c478bd9Sstevel@tonic-gate return (rv); 44397c478bd9Sstevel@tonic-gate } 44407c478bd9Sstevel@tonic-gate 44417c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 44427c478bd9Sstevel@tonic-gate rv = i_mdi_phci_offline(dip, flags); 44437c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && MDI_CLIENT(dip)) { 44447c478bd9Sstevel@tonic-gate /* set client back online */ 44457c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 44467c478bd9Sstevel@tonic-gate } 44477c478bd9Sstevel@tonic-gate } 44487c478bd9Sstevel@tonic-gate 44497c478bd9Sstevel@tonic-gate return (rv); 44507c478bd9Sstevel@tonic-gate } 44517c478bd9Sstevel@tonic-gate 44527c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 44537c478bd9Sstevel@tonic-gate static int 44547c478bd9Sstevel@tonic-gate i_mdi_phci_offline(dev_info_t *dip, uint_t flags) 44557c478bd9Sstevel@tonic-gate { 44567c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 44577c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 44587c478bd9Sstevel@tonic-gate mdi_client_t *ct; 44597c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 44607c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 44617c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 44627c478bd9Sstevel@tonic-gate dev_info_t *cdip; 44637c478bd9Sstevel@tonic-gate 44647c478bd9Sstevel@tonic-gate /* 44657c478bd9Sstevel@tonic-gate * pHCI component offline notification 44667c478bd9Sstevel@tonic-gate * Make sure that this pHCI instance is free to be offlined. 44677c478bd9Sstevel@tonic-gate * If it is OK to proceed, Offline and remove all the child 44687c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes. This process automatically offlines 44697c478bd9Sstevel@tonic-gate * corresponding client devices, for which this pHCI provides 44707c478bd9Sstevel@tonic-gate * critical services. 44717c478bd9Sstevel@tonic-gate */ 4472*c73a93f2Sdm120769 MDI_DEBUG(2, (CE_NOTE, dip, "!mdi_phci_offline called %p\n", 4473*c73a93f2Sdm120769 dip)); 4474*c73a93f2Sdm120769 44757c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 44767c478bd9Sstevel@tonic-gate if (ph == NULL) { 44777c478bd9Sstevel@tonic-gate return (rv); 44787c478bd9Sstevel@tonic-gate } 44797c478bd9Sstevel@tonic-gate 44807c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 44817c478bd9Sstevel@tonic-gate 44827c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_OFFLINE(ph)) { 4483*c73a93f2Sdm120769 MDI_DEBUG(1, (CE_WARN, dip, "!pHCI %p already offlined", ph)); 44847c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44857c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 44867c478bd9Sstevel@tonic-gate } 44877c478bd9Sstevel@tonic-gate 44887c478bd9Sstevel@tonic-gate /* 44897c478bd9Sstevel@tonic-gate * Check to see if the pHCI can be offlined 44907c478bd9Sstevel@tonic-gate */ 44917c478bd9Sstevel@tonic-gate if (ph->ph_unstable) { 44927c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 44937c478bd9Sstevel@tonic-gate "!One or more target devices are in transient " 44947c478bd9Sstevel@tonic-gate "state. This device can not be removed at " 44957c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 44967c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44977c478bd9Sstevel@tonic-gate return (NDI_BUSY); 44987c478bd9Sstevel@tonic-gate } 44997c478bd9Sstevel@tonic-gate 45007c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 45017c478bd9Sstevel@tonic-gate while (pip != NULL) { 45027c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45037c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 45047c478bd9Sstevel@tonic-gate /* 45057c478bd9Sstevel@tonic-gate * The mdi_pathinfo state is OK. Check the client state. 45067c478bd9Sstevel@tonic-gate * If failover in progress fail the pHCI from offlining 45077c478bd9Sstevel@tonic-gate */ 45087c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 45097c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 45107c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 45117c478bd9Sstevel@tonic-gate (ct->ct_unstable)) { 45127c478bd9Sstevel@tonic-gate /* 45137c478bd9Sstevel@tonic-gate * Failover is in progress, Fail the DR 45147c478bd9Sstevel@tonic-gate */ 45157c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 45167c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 45177c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 45187c478bd9Sstevel@tonic-gate "This device can not be removed at " 45197c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 45207c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4521*c73a93f2Sdm120769 MDI_CLIENT_UNLOCK(ct); 45227c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45237c478bd9Sstevel@tonic-gate return (NDI_BUSY); 45247c478bd9Sstevel@tonic-gate } 45257c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45267c478bd9Sstevel@tonic-gate 45277c478bd9Sstevel@tonic-gate /* 45287c478bd9Sstevel@tonic-gate * Check to see of we are removing the last path of this 45297c478bd9Sstevel@tonic-gate * client device... 45307c478bd9Sstevel@tonic-gate */ 45317c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 45327c478bd9Sstevel@tonic-gate if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 45337c478bd9Sstevel@tonic-gate (i_mdi_client_compute_state(ct, ph) == 45347c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_FAILED)) { 45357c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45367c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45377c478bd9Sstevel@tonic-gate if (ndi_devi_offline(cdip, 0) != NDI_SUCCESS) { 45387c478bd9Sstevel@tonic-gate /* 45397c478bd9Sstevel@tonic-gate * ndi_devi_offline() failed. 45407c478bd9Sstevel@tonic-gate * This pHCI provides the critical path 45417c478bd9Sstevel@tonic-gate * to one or more client devices. 45427c478bd9Sstevel@tonic-gate * Return busy. 45437c478bd9Sstevel@tonic-gate */ 45447c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45457c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 45467c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 45477c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 45487c478bd9Sstevel@tonic-gate "This device can not be removed at " 45497c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 45507c478bd9Sstevel@tonic-gate failed_pip = pip; 45517c478bd9Sstevel@tonic-gate break; 45527c478bd9Sstevel@tonic-gate } else { 45537c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45547c478bd9Sstevel@tonic-gate pip = next; 45557c478bd9Sstevel@tonic-gate } 45567c478bd9Sstevel@tonic-gate } else { 45577c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45587c478bd9Sstevel@tonic-gate pip = next; 45597c478bd9Sstevel@tonic-gate } 45607c478bd9Sstevel@tonic-gate } 45617c478bd9Sstevel@tonic-gate 45627c478bd9Sstevel@tonic-gate if (failed_pip) { 45637c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 45647c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 45657c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45667c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 45677c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 45687c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 45697c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 45707c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 45717c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 45727c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 45737c478bd9Sstevel@tonic-gate if (cdip) { 45747c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45757c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45767c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45777c478bd9Sstevel@tonic-gate (void) ndi_devi_online(cdip, 0); 45787c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45797c478bd9Sstevel@tonic-gate pip = next; 45807c478bd9Sstevel@tonic-gate continue; 45817c478bd9Sstevel@tonic-gate } 45827c478bd9Sstevel@tonic-gate break; 45837c478bd9Sstevel@tonic-gate 45847c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 45857c478bd9Sstevel@tonic-gate if (cdip) { 45867c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45877c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45887c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45897c478bd9Sstevel@tonic-gate (void) ndi_devi_offline(cdip, 0); 45907c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45917c478bd9Sstevel@tonic-gate pip = next; 45927c478bd9Sstevel@tonic-gate continue; 45937c478bd9Sstevel@tonic-gate } 45947c478bd9Sstevel@tonic-gate break; 45957c478bd9Sstevel@tonic-gate } 45967c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45977c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45987c478bd9Sstevel@tonic-gate pip = next; 45997c478bd9Sstevel@tonic-gate } 46007c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 46017c478bd9Sstevel@tonic-gate return (NDI_BUSY); 46027c478bd9Sstevel@tonic-gate } 46037c478bd9Sstevel@tonic-gate 46047c478bd9Sstevel@tonic-gate /* 46057c478bd9Sstevel@tonic-gate * Mark the pHCI as offline 46067c478bd9Sstevel@tonic-gate */ 46077c478bd9Sstevel@tonic-gate MDI_PHCI_SET_OFFLINE(ph); 46087c478bd9Sstevel@tonic-gate 46097c478bd9Sstevel@tonic-gate /* 46107c478bd9Sstevel@tonic-gate * Mark the child mdi_pathinfo nodes as transient 46117c478bd9Sstevel@tonic-gate */ 46127c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 46137c478bd9Sstevel@tonic-gate while (pip != NULL) { 46147c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 46157c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 46167c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 46177c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46187c478bd9Sstevel@tonic-gate pip = next; 46197c478bd9Sstevel@tonic-gate } 46207c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 46217c478bd9Sstevel@tonic-gate /* 46227c478bd9Sstevel@tonic-gate * Give a chance for any pending commands to execute 46237c478bd9Sstevel@tonic-gate */ 46247c478bd9Sstevel@tonic-gate delay(1); 46257c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 46267c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 46277c478bd9Sstevel@tonic-gate while (pip != NULL) { 46287c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 46297c478bd9Sstevel@tonic-gate (void) i_mdi_pi_offline(pip, flags); 46307c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 46317c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 46327c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_OFFLINE(pip)) { 46337c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 46347c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 46357c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 46367c478bd9Sstevel@tonic-gate "This device can not be removed at " 46377c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 46387c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46397c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 46407c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 46417c478bd9Sstevel@tonic-gate return (NDI_BUSY); 46427c478bd9Sstevel@tonic-gate } 46437c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 46447c478bd9Sstevel@tonic-gate pip = next; 46457c478bd9Sstevel@tonic-gate } 46467c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 46477c478bd9Sstevel@tonic-gate 46487c478bd9Sstevel@tonic-gate return (rv); 46497c478bd9Sstevel@tonic-gate } 46507c478bd9Sstevel@tonic-gate 46517c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 46527c478bd9Sstevel@tonic-gate static int 46537c478bd9Sstevel@tonic-gate i_mdi_client_offline(dev_info_t *dip, uint_t flags) 46547c478bd9Sstevel@tonic-gate { 46557c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 46567c478bd9Sstevel@tonic-gate mdi_client_t *ct; 46577c478bd9Sstevel@tonic-gate 46587c478bd9Sstevel@tonic-gate /* 46597c478bd9Sstevel@tonic-gate * Client component to go offline. Make sure that we are 46607c478bd9Sstevel@tonic-gate * not in failing over state and update client state 46617c478bd9Sstevel@tonic-gate * accordingly 46627c478bd9Sstevel@tonic-gate */ 4663*c73a93f2Sdm120769 MDI_DEBUG(2, (CE_NOTE, dip, "!i_mdi_client_offline called %p\n", 4664*c73a93f2Sdm120769 dip)); 46657c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 46667c478bd9Sstevel@tonic-gate if (ct != NULL) { 46677c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 46687c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 46697c478bd9Sstevel@tonic-gate /* 46707c478bd9Sstevel@tonic-gate * One or more paths are in transient state, 46717c478bd9Sstevel@tonic-gate * Dont allow offline of a client device 46727c478bd9Sstevel@tonic-gate */ 46737c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 46747c478bd9Sstevel@tonic-gate "!One or more paths to this device is " 46757c478bd9Sstevel@tonic-gate "in transient state. This device can not " 46767c478bd9Sstevel@tonic-gate "be removed at this moment. " 46777c478bd9Sstevel@tonic-gate "Please try again later.")); 46787c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 46797c478bd9Sstevel@tonic-gate return (NDI_BUSY); 46807c478bd9Sstevel@tonic-gate } 46817c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 46827c478bd9Sstevel@tonic-gate /* 46837c478bd9Sstevel@tonic-gate * Failover is in progress, Dont allow DR of 46847c478bd9Sstevel@tonic-gate * a client device 46857c478bd9Sstevel@tonic-gate */ 46867c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 46877c478bd9Sstevel@tonic-gate "!Client device (%s%d) is Busy. %s", 46887c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 46897c478bd9Sstevel@tonic-gate "This device can not be removed at " 46907c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 46917c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 46927c478bd9Sstevel@tonic-gate return (NDI_BUSY); 46937c478bd9Sstevel@tonic-gate } 46947c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 46957c478bd9Sstevel@tonic-gate 46967c478bd9Sstevel@tonic-gate /* 46977c478bd9Sstevel@tonic-gate * Unbind our relationship with the dev_info node 46987c478bd9Sstevel@tonic-gate */ 46997c478bd9Sstevel@tonic-gate if (flags & NDI_DEVI_REMOVE) { 47007c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 47017c478bd9Sstevel@tonic-gate } 47027c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 47037c478bd9Sstevel@tonic-gate } 47047c478bd9Sstevel@tonic-gate return (rv); 47057c478bd9Sstevel@tonic-gate } 47067c478bd9Sstevel@tonic-gate 47077c478bd9Sstevel@tonic-gate /* 47087c478bd9Sstevel@tonic-gate * mdi_pre_attach(): 47097c478bd9Sstevel@tonic-gate * Pre attach() notification handler 47107c478bd9Sstevel@tonic-gate */ 4711*c73a93f2Sdm120769 47127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47137c478bd9Sstevel@tonic-gate int 47147c478bd9Sstevel@tonic-gate mdi_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 47157c478bd9Sstevel@tonic-gate { 47167c478bd9Sstevel@tonic-gate /* don't support old DDI_PM_RESUME */ 47177c478bd9Sstevel@tonic-gate if ((DEVI(dip)->devi_mdi_component != MDI_COMPONENT_NONE) && 47187c478bd9Sstevel@tonic-gate (cmd == DDI_PM_RESUME)) 47197c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 47207c478bd9Sstevel@tonic-gate 47217c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 47227c478bd9Sstevel@tonic-gate } 47237c478bd9Sstevel@tonic-gate 47247c478bd9Sstevel@tonic-gate /* 47257c478bd9Sstevel@tonic-gate * mdi_post_attach(): 47267c478bd9Sstevel@tonic-gate * Post attach() notification handler 47277c478bd9Sstevel@tonic-gate */ 4728*c73a93f2Sdm120769 47297c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47307c478bd9Sstevel@tonic-gate void 47317c478bd9Sstevel@tonic-gate mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error) 47327c478bd9Sstevel@tonic-gate { 47337c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 47347c478bd9Sstevel@tonic-gate mdi_client_t *ct; 47357c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 47367c478bd9Sstevel@tonic-gate 47377c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 47387c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 47397c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 47407c478bd9Sstevel@tonic-gate 47417c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 47427c478bd9Sstevel@tonic-gate switch (cmd) { 47437c478bd9Sstevel@tonic-gate case DDI_ATTACH: 47447c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4745*c73a93f2Sdm120769 "!pHCI post_attach: called %p\n", ph)); 47467c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 47477c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 47487c478bd9Sstevel@tonic-gate } else { 47497c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47507c478bd9Sstevel@tonic-gate "!pHCI post_attach: failed error=%d\n", 47517c478bd9Sstevel@tonic-gate error)); 47527c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 47537c478bd9Sstevel@tonic-gate } 47547c478bd9Sstevel@tonic-gate break; 47557c478bd9Sstevel@tonic-gate 47567c478bd9Sstevel@tonic-gate case DDI_RESUME: 47577c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4758*c73a93f2Sdm120769 "!pHCI post_resume: called %p\n", ph)); 47597c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 47607c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 47617c478bd9Sstevel@tonic-gate } else { 47627c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47637c478bd9Sstevel@tonic-gate "!pHCI post_resume: failed error=%d\n", 47647c478bd9Sstevel@tonic-gate error)); 47657c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 47667c478bd9Sstevel@tonic-gate } 47677c478bd9Sstevel@tonic-gate break; 47687c478bd9Sstevel@tonic-gate } 47697c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 47707c478bd9Sstevel@tonic-gate } 47717c478bd9Sstevel@tonic-gate 47727c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 47737c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 47747c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 47757c478bd9Sstevel@tonic-gate 47767c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 47777c478bd9Sstevel@tonic-gate switch (cmd) { 47787c478bd9Sstevel@tonic-gate case DDI_ATTACH: 47797c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4780*c73a93f2Sdm120769 "!Client post_attach: called %p\n", ct)); 47817c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) { 47827c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47837c478bd9Sstevel@tonic-gate "!Client post_attach: failed error=%d\n", 47847c478bd9Sstevel@tonic-gate error)); 47857c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 47867c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, dip, 47877c478bd9Sstevel@tonic-gate "mdi_post_attach i_mdi_pm_reset_client\n")); 47887c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 47897c478bd9Sstevel@tonic-gate break; 47907c478bd9Sstevel@tonic-gate } 47917c478bd9Sstevel@tonic-gate 47927c478bd9Sstevel@tonic-gate /* 47937c478bd9Sstevel@tonic-gate * Client device has successfully attached. 47947c478bd9Sstevel@tonic-gate * Create kstats for any pathinfo structures 47957c478bd9Sstevel@tonic-gate * initially associated with this client. 47967c478bd9Sstevel@tonic-gate */ 47977c478bd9Sstevel@tonic-gate for (pip = ct->ct_path_head; pip != NULL; 47987c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *) 47997c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link) { 48007c478bd9Sstevel@tonic-gate (void) i_mdi_pi_kstat_create(pip); 48017c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 48027c478bd9Sstevel@tonic-gate } 48037c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 48047c478bd9Sstevel@tonic-gate break; 48057c478bd9Sstevel@tonic-gate 48067c478bd9Sstevel@tonic-gate case DDI_RESUME: 48077c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4808*c73a93f2Sdm120769 "!Client post_attach: called %p\n", ct)); 48097c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 48107c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 48117c478bd9Sstevel@tonic-gate } else { 48127c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 48137c478bd9Sstevel@tonic-gate "!Client post_resume: failed error=%d\n", 48147c478bd9Sstevel@tonic-gate error)); 48157c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 48167c478bd9Sstevel@tonic-gate } 48177c478bd9Sstevel@tonic-gate break; 48187c478bd9Sstevel@tonic-gate } 48197c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 48207c478bd9Sstevel@tonic-gate } 48217c478bd9Sstevel@tonic-gate } 48227c478bd9Sstevel@tonic-gate 48237c478bd9Sstevel@tonic-gate /* 48247c478bd9Sstevel@tonic-gate * mdi_pre_detach(): 48257c478bd9Sstevel@tonic-gate * Pre detach notification handler 48267c478bd9Sstevel@tonic-gate */ 4827*c73a93f2Sdm120769 48287c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 48297c478bd9Sstevel@tonic-gate int 48307c478bd9Sstevel@tonic-gate mdi_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 48317c478bd9Sstevel@tonic-gate { 48327c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 48337c478bd9Sstevel@tonic-gate 48347c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 48357c478bd9Sstevel@tonic-gate (void) i_mdi_client_pre_detach(dip, cmd); 48367c478bd9Sstevel@tonic-gate } 48377c478bd9Sstevel@tonic-gate 48387c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 48397c478bd9Sstevel@tonic-gate rv = i_mdi_phci_pre_detach(dip, cmd); 48407c478bd9Sstevel@tonic-gate } 48417c478bd9Sstevel@tonic-gate 48427c478bd9Sstevel@tonic-gate return (rv); 48437c478bd9Sstevel@tonic-gate } 48447c478bd9Sstevel@tonic-gate 48457c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 48467c478bd9Sstevel@tonic-gate static int 48477c478bd9Sstevel@tonic-gate i_mdi_phci_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 48487c478bd9Sstevel@tonic-gate { 48497c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 48507c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 48517c478bd9Sstevel@tonic-gate mdi_client_t *ct; 48527c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 48537c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 48547c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 48557c478bd9Sstevel@tonic-gate 48567c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 48577c478bd9Sstevel@tonic-gate if (ph == NULL) { 48587c478bd9Sstevel@tonic-gate return (rv); 48597c478bd9Sstevel@tonic-gate } 48607c478bd9Sstevel@tonic-gate 48617c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 48627c478bd9Sstevel@tonic-gate switch (cmd) { 48637c478bd9Sstevel@tonic-gate case DDI_DETACH: 48647c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4865*c73a93f2Sdm120769 "!pHCI pre_detach: called %p\n", ph)); 48667c478bd9Sstevel@tonic-gate if (!MDI_PHCI_IS_OFFLINE(ph)) { 48677c478bd9Sstevel@tonic-gate /* 48687c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes are still attached to 48697c478bd9Sstevel@tonic-gate * this pHCI. Fail the detach for this pHCI. 48707c478bd9Sstevel@tonic-gate */ 48717c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, dip, 48727c478bd9Sstevel@tonic-gate "!pHCI pre_detach: " 48737c478bd9Sstevel@tonic-gate "mdi_pathinfo nodes are still attached " 4874*c73a93f2Sdm120769 "%p\n", ph)); 48757c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 48767c478bd9Sstevel@tonic-gate break; 48777c478bd9Sstevel@tonic-gate } 48787c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 48797c478bd9Sstevel@tonic-gate break; 48807c478bd9Sstevel@tonic-gate 48817c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 48827c478bd9Sstevel@tonic-gate /* 48837c478bd9Sstevel@tonic-gate * pHCI is getting suspended. Since mpxio client 48847c478bd9Sstevel@tonic-gate * devices may not be suspended at this point, to avoid 48857c478bd9Sstevel@tonic-gate * a potential stack overflow, it is important to suspend 48867c478bd9Sstevel@tonic-gate * client devices before pHCI can be suspended. 48877c478bd9Sstevel@tonic-gate */ 48887c478bd9Sstevel@tonic-gate 48897c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4890*c73a93f2Sdm120769 "!pHCI pre_suspend: called %p\n", ph)); 48917c478bd9Sstevel@tonic-gate /* 48927c478bd9Sstevel@tonic-gate * Suspend all the client devices accessible through this pHCI 48937c478bd9Sstevel@tonic-gate */ 48947c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 48957c478bd9Sstevel@tonic-gate while (pip != NULL && rv == DDI_SUCCESS) { 48967c478bd9Sstevel@tonic-gate dev_info_t *cdip; 48977c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 48987c478bd9Sstevel@tonic-gate next = 48997c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 49007c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 49017c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 49027c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 49037c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 49047c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct) == 0) && 49057c478bd9Sstevel@tonic-gate MDI_CLIENT_IS_SUSPENDED(ct) == 0) { 49067c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49077c478bd9Sstevel@tonic-gate if ((rv = devi_detach(cdip, DDI_SUSPEND)) != 49087c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 49097c478bd9Sstevel@tonic-gate /* 49107c478bd9Sstevel@tonic-gate * Suspend of one of the client 49117c478bd9Sstevel@tonic-gate * device has failed. 49127c478bd9Sstevel@tonic-gate */ 49137c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 49147c478bd9Sstevel@tonic-gate "!Suspend of device (%s%d) failed.", 49157c478bd9Sstevel@tonic-gate ddi_driver_name(cdip), 49167c478bd9Sstevel@tonic-gate ddi_get_instance(cdip))); 49177c478bd9Sstevel@tonic-gate failed_pip = pip; 49187c478bd9Sstevel@tonic-gate break; 49197c478bd9Sstevel@tonic-gate } 49207c478bd9Sstevel@tonic-gate } else { 49217c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49227c478bd9Sstevel@tonic-gate } 49237c478bd9Sstevel@tonic-gate pip = next; 49247c478bd9Sstevel@tonic-gate } 49257c478bd9Sstevel@tonic-gate 49267c478bd9Sstevel@tonic-gate if (rv == DDI_SUCCESS) { 49277c478bd9Sstevel@tonic-gate /* 49287c478bd9Sstevel@tonic-gate * Suspend of client devices is complete. Proceed 49297c478bd9Sstevel@tonic-gate * with pHCI suspend. 49307c478bd9Sstevel@tonic-gate */ 49317c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 49327c478bd9Sstevel@tonic-gate } else { 49337c478bd9Sstevel@tonic-gate /* 49347c478bd9Sstevel@tonic-gate * Revert back all the suspended client device states 49357c478bd9Sstevel@tonic-gate * to converse. 49367c478bd9Sstevel@tonic-gate */ 49377c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 49387c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 49397c478bd9Sstevel@tonic-gate dev_info_t *cdip; 49407c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 49417c478bd9Sstevel@tonic-gate next = 49427c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 49437c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 49447c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 49457c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 49467c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 49477c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_SUSPENDED(ct)) { 49487c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49497c478bd9Sstevel@tonic-gate (void) devi_attach(cdip, DDI_RESUME); 49507c478bd9Sstevel@tonic-gate } else { 49517c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 49527c478bd9Sstevel@tonic-gate } 49537c478bd9Sstevel@tonic-gate pip = next; 49547c478bd9Sstevel@tonic-gate } 49557c478bd9Sstevel@tonic-gate } 49567c478bd9Sstevel@tonic-gate break; 49577c478bd9Sstevel@tonic-gate 49587c478bd9Sstevel@tonic-gate default: 49597c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 49607c478bd9Sstevel@tonic-gate break; 49617c478bd9Sstevel@tonic-gate } 49627c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 49637c478bd9Sstevel@tonic-gate return (rv); 49647c478bd9Sstevel@tonic-gate } 49657c478bd9Sstevel@tonic-gate 49667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49677c478bd9Sstevel@tonic-gate static int 49687c478bd9Sstevel@tonic-gate i_mdi_client_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 49697c478bd9Sstevel@tonic-gate { 49707c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 49717c478bd9Sstevel@tonic-gate mdi_client_t *ct; 49727c478bd9Sstevel@tonic-gate 49737c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 49747c478bd9Sstevel@tonic-gate if (ct == NULL) { 49757c478bd9Sstevel@tonic-gate return (rv); 49767c478bd9Sstevel@tonic-gate } 49777c478bd9Sstevel@tonic-gate 49787c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 49797c478bd9Sstevel@tonic-gate switch (cmd) { 49807c478bd9Sstevel@tonic-gate case DDI_DETACH: 49817c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4982*c73a93f2Sdm120769 "!Client pre_detach: called %p\n", ct)); 49837c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 49847c478bd9Sstevel@tonic-gate break; 49857c478bd9Sstevel@tonic-gate 49867c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 49877c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4988*c73a93f2Sdm120769 "!Client pre_suspend: called %p\n", ct)); 49897c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 49907c478bd9Sstevel@tonic-gate break; 49917c478bd9Sstevel@tonic-gate 49927c478bd9Sstevel@tonic-gate default: 49937c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 49947c478bd9Sstevel@tonic-gate break; 49957c478bd9Sstevel@tonic-gate } 49967c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 49977c478bd9Sstevel@tonic-gate return (rv); 49987c478bd9Sstevel@tonic-gate } 49997c478bd9Sstevel@tonic-gate 50007c478bd9Sstevel@tonic-gate /* 50017c478bd9Sstevel@tonic-gate * mdi_post_detach(): 50027c478bd9Sstevel@tonic-gate * Post detach notification handler 50037c478bd9Sstevel@tonic-gate */ 5004*c73a93f2Sdm120769 50057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 50067c478bd9Sstevel@tonic-gate void 50077c478bd9Sstevel@tonic-gate mdi_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 50087c478bd9Sstevel@tonic-gate { 50097c478bd9Sstevel@tonic-gate /* 50107c478bd9Sstevel@tonic-gate * Detach/Suspend of mpxio component failed. Update our state 50117c478bd9Sstevel@tonic-gate * too 50127c478bd9Sstevel@tonic-gate */ 50137c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) 50147c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dip, cmd, error); 50157c478bd9Sstevel@tonic-gate 50167c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) 50177c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dip, cmd, error); 50187c478bd9Sstevel@tonic-gate } 50197c478bd9Sstevel@tonic-gate 50207c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 50217c478bd9Sstevel@tonic-gate static void 50227c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 50237c478bd9Sstevel@tonic-gate { 50247c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 50257c478bd9Sstevel@tonic-gate 50267c478bd9Sstevel@tonic-gate /* 50277c478bd9Sstevel@tonic-gate * Detach/Suspend of phci component failed. Update our state 50287c478bd9Sstevel@tonic-gate * too 50297c478bd9Sstevel@tonic-gate */ 50307c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 50317c478bd9Sstevel@tonic-gate if (ph == NULL) { 50327c478bd9Sstevel@tonic-gate return; 50337c478bd9Sstevel@tonic-gate } 50347c478bd9Sstevel@tonic-gate 50357c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 50367c478bd9Sstevel@tonic-gate /* 50377c478bd9Sstevel@tonic-gate * Detach of pHCI failed. Restore back converse 50387c478bd9Sstevel@tonic-gate * state 50397c478bd9Sstevel@tonic-gate */ 50407c478bd9Sstevel@tonic-gate switch (cmd) { 50417c478bd9Sstevel@tonic-gate case DDI_DETACH: 50427c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 5043*c73a93f2Sdm120769 "!pHCI post_detach: called %p\n", ph)); 50447c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50457c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 50467c478bd9Sstevel@tonic-gate break; 50477c478bd9Sstevel@tonic-gate 50487c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 50497c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 5050*c73a93f2Sdm120769 "!pHCI post_suspend: called %p\n", ph)); 50517c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50527c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 50537c478bd9Sstevel@tonic-gate break; 50547c478bd9Sstevel@tonic-gate } 50557c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 50567c478bd9Sstevel@tonic-gate } 50577c478bd9Sstevel@tonic-gate 50587c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 50597c478bd9Sstevel@tonic-gate static void 50607c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 50617c478bd9Sstevel@tonic-gate { 50627c478bd9Sstevel@tonic-gate mdi_client_t *ct; 50637c478bd9Sstevel@tonic-gate 50647c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 50657c478bd9Sstevel@tonic-gate if (ct == NULL) { 50667c478bd9Sstevel@tonic-gate return; 50677c478bd9Sstevel@tonic-gate } 50687c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 50697c478bd9Sstevel@tonic-gate /* 50707c478bd9Sstevel@tonic-gate * Detach of Client failed. Restore back converse 50717c478bd9Sstevel@tonic-gate * state 50727c478bd9Sstevel@tonic-gate */ 50737c478bd9Sstevel@tonic-gate switch (cmd) { 50747c478bd9Sstevel@tonic-gate case DDI_DETACH: 50757c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 5076*c73a93f2Sdm120769 "!Client post_detach: called %p\n", ct)); 50777c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 50787c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 50797c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 50807c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 50817c478bd9Sstevel@tonic-gate } else { 50827c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 50837c478bd9Sstevel@tonic-gate "i_mdi_pm_reset_client\n")); 50847c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 50857c478bd9Sstevel@tonic-gate } 50867c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50877c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 50887c478bd9Sstevel@tonic-gate break; 50897c478bd9Sstevel@tonic-gate 50907c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 50917c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 5092*c73a93f2Sdm120769 "!Client post_suspend: called %p\n", ct)); 50937c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50947c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 50957c478bd9Sstevel@tonic-gate break; 50967c478bd9Sstevel@tonic-gate } 50977c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 50987c478bd9Sstevel@tonic-gate } 50997c478bd9Sstevel@tonic-gate 51007c478bd9Sstevel@tonic-gate /* 51017c478bd9Sstevel@tonic-gate * create and install per-path (client - pHCI) statistics 51027c478bd9Sstevel@tonic-gate * I/O stats supported: nread, nwritten, reads, and writes 51037c478bd9Sstevel@tonic-gate * Error stats - hard errors, soft errors, & transport errors 51047c478bd9Sstevel@tonic-gate */ 51057c478bd9Sstevel@tonic-gate static int 51067c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_create(mdi_pathinfo_t *pip) 51077c478bd9Sstevel@tonic-gate { 51087c478bd9Sstevel@tonic-gate 51097c478bd9Sstevel@tonic-gate dev_info_t *client = MDI_PI(pip)->pi_client->ct_dip; 51107c478bd9Sstevel@tonic-gate dev_info_t *ppath = MDI_PI(pip)->pi_phci->ph_dip; 51117c478bd9Sstevel@tonic-gate char ksname[KSTAT_STRLEN]; 51127c478bd9Sstevel@tonic-gate mdi_pathinfo_t *cpip; 51137c478bd9Sstevel@tonic-gate const char *err_postfix = ",err"; 51147c478bd9Sstevel@tonic-gate kstat_t *kiosp, *kerrsp; 51157c478bd9Sstevel@tonic-gate struct pi_errs *nsp; 51167c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 51177c478bd9Sstevel@tonic-gate 51187c478bd9Sstevel@tonic-gate ASSERT(client != NULL && ppath != NULL); 51197c478bd9Sstevel@tonic-gate 5120*c73a93f2Sdm120769 ASSERT(mutex_owned(&(MDI_PI(pip)->pi_client->ct_mutex))); 51217c478bd9Sstevel@tonic-gate 51227c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_kstats != NULL) 51237c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 51247c478bd9Sstevel@tonic-gate 51257c478bd9Sstevel@tonic-gate for (cpip = MDI_PI(pip)->pi_client->ct_path_head; cpip != NULL; 51267c478bd9Sstevel@tonic-gate cpip = (mdi_pathinfo_t *)(MDI_PI(cpip)->pi_client_link)) { 5127*c73a93f2Sdm120769 if (cpip == pip) 51287c478bd9Sstevel@tonic-gate continue; 51297c478bd9Sstevel@tonic-gate /* 51307c478bd9Sstevel@tonic-gate * We have found a different path with same parent 51317c478bd9Sstevel@tonic-gate * kstats for a given client-pHCI are common 51327c478bd9Sstevel@tonic-gate */ 51337c478bd9Sstevel@tonic-gate if ((MDI_PI(cpip)->pi_phci->ph_dip == ppath) && 51347c478bd9Sstevel@tonic-gate (MDI_PI(cpip)->pi_kstats != NULL)) { 51357c478bd9Sstevel@tonic-gate MDI_PI(cpip)->pi_kstats->pi_kstat_ref++; 51367c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = MDI_PI(cpip)->pi_kstats; 51377c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 51387c478bd9Sstevel@tonic-gate } 51397c478bd9Sstevel@tonic-gate } 51407c478bd9Sstevel@tonic-gate 51417c478bd9Sstevel@tonic-gate /* 51427c478bd9Sstevel@tonic-gate * stats are named as follows: TGTx.HBAy, e.g. "ssd0.fp0" 51437c478bd9Sstevel@tonic-gate * clamp length of name against max length of error kstat name 51447c478bd9Sstevel@tonic-gate */ 51457c478bd9Sstevel@tonic-gate if (snprintf(ksname, KSTAT_STRLEN, "%s%d.%s%d", 51467c478bd9Sstevel@tonic-gate ddi_driver_name(client), ddi_get_instance(client), 51477c478bd9Sstevel@tonic-gate ddi_driver_name(ppath), ddi_get_instance(ppath)) > 51487c478bd9Sstevel@tonic-gate (KSTAT_STRLEN - strlen(err_postfix))) { 51497c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 51507c478bd9Sstevel@tonic-gate } 51517c478bd9Sstevel@tonic-gate if ((kiosp = kstat_create("mdi", 0, ksname, "iopath", 51527c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, 0)) == NULL) { 51537c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 51547c478bd9Sstevel@tonic-gate } 51557c478bd9Sstevel@tonic-gate 51567c478bd9Sstevel@tonic-gate (void) strcat(ksname, err_postfix); 51577c478bd9Sstevel@tonic-gate kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors", 51587c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, 51597c478bd9Sstevel@tonic-gate sizeof (struct pi_errs) / sizeof (kstat_named_t), 0); 51607c478bd9Sstevel@tonic-gate 51617c478bd9Sstevel@tonic-gate if (kerrsp == NULL) { 51627c478bd9Sstevel@tonic-gate kstat_delete(kiosp); 51637c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 51647c478bd9Sstevel@tonic-gate } 51657c478bd9Sstevel@tonic-gate 51667c478bd9Sstevel@tonic-gate nsp = (struct pi_errs *)kerrsp->ks_data; 51677c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32); 51687c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32); 51697c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_transerrs, "Transport Errors", 51707c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51717c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy", 51727c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51737c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors", 51747c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51757c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources", 51767c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51777c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors", 51787c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51797c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State", 51807c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51817c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedfrom, "Failed From", 51827c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51837c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32); 51847c478bd9Sstevel@tonic-gate 51857c478bd9Sstevel@tonic-gate mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP); 51867c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_ref = 1; 51877c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_iostats = kiosp; 51887c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_errstats = kerrsp; 51897c478bd9Sstevel@tonic-gate kstat_install(kiosp); 51907c478bd9Sstevel@tonic-gate kstat_install(kerrsp); 51917c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = mdi_statp; 51927c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 51937c478bd9Sstevel@tonic-gate } 51947c478bd9Sstevel@tonic-gate 51957c478bd9Sstevel@tonic-gate /* 51967c478bd9Sstevel@tonic-gate * destroy per-path properties 51977c478bd9Sstevel@tonic-gate */ 51987c478bd9Sstevel@tonic-gate static void 51997c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip) 52007c478bd9Sstevel@tonic-gate { 52017c478bd9Sstevel@tonic-gate 52027c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 52037c478bd9Sstevel@tonic-gate 52047c478bd9Sstevel@tonic-gate if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL) 52057c478bd9Sstevel@tonic-gate return; 52067c478bd9Sstevel@tonic-gate 52077c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 52087c478bd9Sstevel@tonic-gate 52097c478bd9Sstevel@tonic-gate /* 52107c478bd9Sstevel@tonic-gate * the kstat may be shared between multiple pathinfo nodes 52117c478bd9Sstevel@tonic-gate * decrement this pathinfo's usage, removing the kstats 52127c478bd9Sstevel@tonic-gate * themselves when the last pathinfo reference is removed. 52137c478bd9Sstevel@tonic-gate */ 52147c478bd9Sstevel@tonic-gate ASSERT(mdi_statp->pi_kstat_ref > 0); 52157c478bd9Sstevel@tonic-gate if (--mdi_statp->pi_kstat_ref != 0) 52167c478bd9Sstevel@tonic-gate return; 52177c478bd9Sstevel@tonic-gate 52187c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_iostats); 52197c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_errstats); 52207c478bd9Sstevel@tonic-gate kmem_free(mdi_statp, sizeof (*mdi_statp)); 52217c478bd9Sstevel@tonic-gate } 52227c478bd9Sstevel@tonic-gate 52237c478bd9Sstevel@tonic-gate /* 52247c478bd9Sstevel@tonic-gate * update I/O paths KSTATS 52257c478bd9Sstevel@tonic-gate */ 52267c478bd9Sstevel@tonic-gate void 52277c478bd9Sstevel@tonic-gate mdi_pi_kstat_iosupdate(mdi_pathinfo_t *pip, struct buf *bp) 52287c478bd9Sstevel@tonic-gate { 52297c478bd9Sstevel@tonic-gate kstat_t *iostatp; 52307c478bd9Sstevel@tonic-gate size_t xfer_cnt; 52317c478bd9Sstevel@tonic-gate 52327c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 52337c478bd9Sstevel@tonic-gate 52347c478bd9Sstevel@tonic-gate /* 52357c478bd9Sstevel@tonic-gate * I/O can be driven across a path prior to having path 52367c478bd9Sstevel@tonic-gate * statistics available, i.e. probe(9e). 52377c478bd9Sstevel@tonic-gate */ 52387c478bd9Sstevel@tonic-gate if (bp != NULL && MDI_PI(pip)->pi_kstats != NULL) { 52397c478bd9Sstevel@tonic-gate iostatp = MDI_PI(pip)->pi_kstats->pi_kstat_iostats; 52407c478bd9Sstevel@tonic-gate xfer_cnt = bp->b_bcount - bp->b_resid; 52417c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 52427c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->reads++; 52437c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nread += xfer_cnt; 52447c478bd9Sstevel@tonic-gate } else { 52457c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->writes++; 52467c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nwritten += xfer_cnt; 52477c478bd9Sstevel@tonic-gate } 52487c478bd9Sstevel@tonic-gate } 52497c478bd9Sstevel@tonic-gate } 52507c478bd9Sstevel@tonic-gate 52517c478bd9Sstevel@tonic-gate /* 5252ee28b439Scm136836 * Enable the path(specific client/target/initiator) 5253ee28b439Scm136836 * Enabling a path means that MPxIO may select the enabled path for routing 5254ee28b439Scm136836 * future I/O requests, subject to other path state constraints. 5255ee28b439Scm136836 */ 5256ee28b439Scm136836 int 5257ee28b439Scm136836 mdi_pi_enable_path(mdi_pathinfo_t *pip, int flags) 5258ee28b439Scm136836 { 5259ee28b439Scm136836 mdi_phci_t *ph; 5260ee28b439Scm136836 5261ee28b439Scm136836 ph = i_devi_get_phci(mdi_pi_get_phci(pip)); 5262ee28b439Scm136836 if (ph == NULL) { 5263ee28b439Scm136836 MDI_DEBUG(1, (CE_NOTE, NULL, "!mdi_pi_enable_path:" 5264*c73a93f2Sdm120769 " failed. pip: %p ph = NULL\n", pip)); 5265ee28b439Scm136836 return (MDI_FAILURE); 5266ee28b439Scm136836 } 5267ee28b439Scm136836 5268ee28b439Scm136836 (void) i_mdi_enable_disable_path(pip, ph->ph_vhci, flags, 5269ee28b439Scm136836 MDI_ENABLE_OP); 5270ee28b439Scm136836 MDI_DEBUG(5, (CE_NOTE, NULL, "!mdi_pi_enable_path:" 5271*c73a93f2Sdm120769 " Returning success pip = %p. ph = %p\n", pip, ph)); 5272ee28b439Scm136836 return (MDI_SUCCESS); 5273ee28b439Scm136836 5274ee28b439Scm136836 } 5275ee28b439Scm136836 5276ee28b439Scm136836 /* 5277ee28b439Scm136836 * Disable the path (specific client/target/initiator) 5278ee28b439Scm136836 * Disabling a path means that MPxIO will not select the disabled path for 5279ee28b439Scm136836 * routing any new I/O requests. 5280ee28b439Scm136836 */ 5281ee28b439Scm136836 int 5282ee28b439Scm136836 mdi_pi_disable_path(mdi_pathinfo_t *pip, int flags) 5283ee28b439Scm136836 { 5284ee28b439Scm136836 mdi_phci_t *ph; 5285ee28b439Scm136836 5286ee28b439Scm136836 ph = i_devi_get_phci(mdi_pi_get_phci(pip)); 5287ee28b439Scm136836 if (ph == NULL) { 5288ee28b439Scm136836 MDI_DEBUG(1, (CE_NOTE, NULL, "!mdi_pi_disable_path:" 5289*c73a93f2Sdm120769 " failed. pip: %p ph = NULL\n", pip)); 5290ee28b439Scm136836 return (MDI_FAILURE); 5291ee28b439Scm136836 } 5292ee28b439Scm136836 5293ee28b439Scm136836 (void) i_mdi_enable_disable_path(pip, 5294ee28b439Scm136836 ph->ph_vhci, flags, MDI_DISABLE_OP); 5295ee28b439Scm136836 MDI_DEBUG(5, (CE_NOTE, NULL, "!mdi_pi_disable_path:" 5296*c73a93f2Sdm120769 "Returning success pip = %p. ph = %p", pip, ph)); 5297ee28b439Scm136836 return (MDI_SUCCESS); 5298ee28b439Scm136836 } 5299ee28b439Scm136836 5300ee28b439Scm136836 /* 53017c478bd9Sstevel@tonic-gate * disable the path to a particular pHCI (pHCI specified in the phci_path 53027c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 53037c478bd9Sstevel@tonic-gate * Disabling a path means that MPxIO will not select the disabled path for 53047c478bd9Sstevel@tonic-gate * routing any new I/O requests. 5305ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 5306ee28b439Scm136836 * mdi_{enable,disable}_path interfaces 53077c478bd9Sstevel@tonic-gate */ 53087c478bd9Sstevel@tonic-gate int 53097c478bd9Sstevel@tonic-gate mdi_pi_disable(dev_info_t *cdip, dev_info_t *pdip, int flags) 53107c478bd9Sstevel@tonic-gate { 53117c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_DISABLE_OP)); 53127c478bd9Sstevel@tonic-gate } 53137c478bd9Sstevel@tonic-gate 53147c478bd9Sstevel@tonic-gate /* 53157c478bd9Sstevel@tonic-gate * Enable the path to a particular pHCI (pHCI specified in the phci_path 53167c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 53177c478bd9Sstevel@tonic-gate * Enabling a path means that MPxIO may select the enabled path for routing 53187c478bd9Sstevel@tonic-gate * future I/O requests, subject to other path state constraints. 5319ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 5320ee28b439Scm136836 * mdi_{enable,disable}_path interfaces 53217c478bd9Sstevel@tonic-gate */ 53227c478bd9Sstevel@tonic-gate 53237c478bd9Sstevel@tonic-gate int 53247c478bd9Sstevel@tonic-gate mdi_pi_enable(dev_info_t *cdip, dev_info_t *pdip, int flags) 53257c478bd9Sstevel@tonic-gate { 53267c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_ENABLE_OP)); 53277c478bd9Sstevel@tonic-gate } 53287c478bd9Sstevel@tonic-gate 5329ee28b439Scm136836 /* 5330ee28b439Scm136836 * Common routine for doing enable/disable. 5331ee28b439Scm136836 */ 5332ee28b439Scm136836 static mdi_pathinfo_t * 5333ee28b439Scm136836 i_mdi_enable_disable_path(mdi_pathinfo_t *pip, mdi_vhci_t *vh, int flags, 5334ee28b439Scm136836 int op) 5335ee28b439Scm136836 { 5336ee28b439Scm136836 int sync_flag = 0; 5337ee28b439Scm136836 int rv; 5338ee28b439Scm136836 mdi_pathinfo_t *next; 5339ee28b439Scm136836 int (*f)() = NULL; 5340ee28b439Scm136836 5341ee28b439Scm136836 f = vh->vh_ops->vo_pi_state_change; 5342ee28b439Scm136836 5343ee28b439Scm136836 sync_flag = (flags << 8) & 0xf00; 5344ee28b439Scm136836 5345ee28b439Scm136836 /* 5346ee28b439Scm136836 * Do a callback into the mdi consumer to let it 5347ee28b439Scm136836 * know that path is about to get enabled/disabled. 5348ee28b439Scm136836 */ 5349ee28b439Scm136836 if (f != NULL) { 5350ee28b439Scm136836 rv = (*f)(vh->vh_dip, pip, 0, 5351ee28b439Scm136836 MDI_PI_EXT_STATE(pip), 5352ee28b439Scm136836 MDI_EXT_STATE_CHANGE | sync_flag | 5353ee28b439Scm136836 op | MDI_BEFORE_STATE_CHANGE); 5354ee28b439Scm136836 if (rv != MDI_SUCCESS) { 5355ee28b439Scm136836 MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 5356ee28b439Scm136836 "!vo_pi_state_change: failed rv = %x", rv)); 5357ee28b439Scm136836 } 5358ee28b439Scm136836 } 5359ee28b439Scm136836 MDI_PI_LOCK(pip); 5360ee28b439Scm136836 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 5361ee28b439Scm136836 5362ee28b439Scm136836 switch (flags) { 5363ee28b439Scm136836 case USER_DISABLE: 5364*c73a93f2Sdm120769 if (op == MDI_DISABLE_OP) 5365ee28b439Scm136836 MDI_PI_SET_USER_DISABLE(pip); 5366*c73a93f2Sdm120769 else 5367ee28b439Scm136836 MDI_PI_SET_USER_ENABLE(pip); 5368ee28b439Scm136836 break; 5369ee28b439Scm136836 case DRIVER_DISABLE: 5370*c73a93f2Sdm120769 if (op == MDI_DISABLE_OP) 5371ee28b439Scm136836 MDI_PI_SET_DRV_DISABLE(pip); 5372*c73a93f2Sdm120769 else 5373ee28b439Scm136836 MDI_PI_SET_DRV_ENABLE(pip); 5374ee28b439Scm136836 break; 5375ee28b439Scm136836 case DRIVER_DISABLE_TRANSIENT: 5376*c73a93f2Sdm120769 if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) 5377ee28b439Scm136836 MDI_PI_SET_DRV_DISABLE_TRANS(pip); 5378*c73a93f2Sdm120769 else 5379ee28b439Scm136836 MDI_PI_SET_DRV_ENABLE_TRANS(pip); 5380ee28b439Scm136836 break; 5381ee28b439Scm136836 } 5382ee28b439Scm136836 MDI_PI_UNLOCK(pip); 5383ee28b439Scm136836 /* 5384ee28b439Scm136836 * Do a callback into the mdi consumer to let it 5385ee28b439Scm136836 * know that path is now enabled/disabled. 5386ee28b439Scm136836 */ 5387ee28b439Scm136836 if (f != NULL) { 5388ee28b439Scm136836 rv = (*f)(vh->vh_dip, pip, 0, 5389ee28b439Scm136836 MDI_PI_EXT_STATE(pip), 5390ee28b439Scm136836 MDI_EXT_STATE_CHANGE | sync_flag | 5391ee28b439Scm136836 op | MDI_AFTER_STATE_CHANGE); 5392ee28b439Scm136836 if (rv != MDI_SUCCESS) { 5393ee28b439Scm136836 MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 5394ee28b439Scm136836 "!vo_pi_state_change: failed rv = %x", rv)); 5395ee28b439Scm136836 } 5396ee28b439Scm136836 } 5397ee28b439Scm136836 return (next); 5398ee28b439Scm136836 } 53997c478bd9Sstevel@tonic-gate 54007c478bd9Sstevel@tonic-gate /* 54017c478bd9Sstevel@tonic-gate * Common routine for doing enable/disable. 5402ee28b439Scm136836 * NOTE: this will be removed once the NWS files are changed to use the new 5403ee28b439Scm136836 * mdi_{enable,disable}_path has been putback 54047c478bd9Sstevel@tonic-gate */ 54057c478bd9Sstevel@tonic-gate int 54067c478bd9Sstevel@tonic-gate i_mdi_pi_enable_disable(dev_info_t *cdip, dev_info_t *pdip, int flags, int op) 54077c478bd9Sstevel@tonic-gate { 54087c478bd9Sstevel@tonic-gate 54097c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 54107c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 54117c478bd9Sstevel@tonic-gate mdi_client_t *ct; 54127c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next, *pip; 54137c478bd9Sstevel@tonic-gate int found_it; 54147c478bd9Sstevel@tonic-gate 54157c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 54167c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5417*c73a93f2Sdm120769 " Operation = %d pdip = %p cdip = %p\n", op, pdip, cdip)); 54187c478bd9Sstevel@tonic-gate if (ph == NULL) { 54197c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5420*c73a93f2Sdm120769 " failed. ph = NULL operation = %d\n", op)); 54217c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54227c478bd9Sstevel@tonic-gate } 54237c478bd9Sstevel@tonic-gate 54247c478bd9Sstevel@tonic-gate if ((op != MDI_ENABLE_OP) && (op != MDI_DISABLE_OP)) { 54257c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5426*c73a93f2Sdm120769 " Invalid operation = %d\n", op)); 54277c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54287c478bd9Sstevel@tonic-gate } 54297c478bd9Sstevel@tonic-gate 54307c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 54317c478bd9Sstevel@tonic-gate 54327c478bd9Sstevel@tonic-gate if (cdip == NULL) { 54337c478bd9Sstevel@tonic-gate /* 54347c478bd9Sstevel@tonic-gate * Need to mark the Phci as enabled/disabled. 54357c478bd9Sstevel@tonic-gate */ 54367c478bd9Sstevel@tonic-gate MDI_DEBUG(3, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5437*c73a93f2Sdm120769 "Operation %d for the phci\n", op)); 54387c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 54397c478bd9Sstevel@tonic-gate switch (flags) { 54407c478bd9Sstevel@tonic-gate case USER_DISABLE: 5441*c73a93f2Sdm120769 if (op == MDI_DISABLE_OP) 54427c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_DISABLE(ph); 5443*c73a93f2Sdm120769 else 54447c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_ENABLE(ph); 54457c478bd9Sstevel@tonic-gate break; 54467c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 5447*c73a93f2Sdm120769 if (op == MDI_DISABLE_OP) 54487c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE(ph); 5449*c73a93f2Sdm120769 else 54507c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE(ph); 54517c478bd9Sstevel@tonic-gate break; 54527c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 5453*c73a93f2Sdm120769 if (op == MDI_DISABLE_OP) 54547c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE_TRANSIENT(ph); 5455*c73a93f2Sdm120769 else 54567c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE_TRANSIENT(ph); 54577c478bd9Sstevel@tonic-gate break; 54587c478bd9Sstevel@tonic-gate default: 54597c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 54607c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 54617c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 54627c478bd9Sstevel@tonic-gate " Invalid flag argument= %d\n", flags)); 54637c478bd9Sstevel@tonic-gate } 54647c478bd9Sstevel@tonic-gate 54657c478bd9Sstevel@tonic-gate /* 54667c478bd9Sstevel@tonic-gate * Phci has been disabled. Now try to enable/disable 54677c478bd9Sstevel@tonic-gate * path info's to each client. 54687c478bd9Sstevel@tonic-gate */ 54697c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 54707c478bd9Sstevel@tonic-gate while (pip != NULL) { 5471ee28b439Scm136836 pip = i_mdi_enable_disable_path(pip, vh, flags, op); 54727c478bd9Sstevel@tonic-gate } 54737c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 54747c478bd9Sstevel@tonic-gate } else { 54757c478bd9Sstevel@tonic-gate 54767c478bd9Sstevel@tonic-gate /* 54777c478bd9Sstevel@tonic-gate * Disable a specific client. 54787c478bd9Sstevel@tonic-gate */ 54797c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 54807c478bd9Sstevel@tonic-gate if (ct == NULL) { 54817c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 54827c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 54837c478bd9Sstevel@tonic-gate " failed. ct = NULL operation = %d\n", op)); 54847c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54857c478bd9Sstevel@tonic-gate } 54867c478bd9Sstevel@tonic-gate 54877c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 54887c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 54897c478bd9Sstevel@tonic-gate found_it = 0; 54907c478bd9Sstevel@tonic-gate while (pip != NULL) { 54917c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 54927c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 54937c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 54947c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 54957c478bd9Sstevel@tonic-gate found_it = 1; 54967c478bd9Sstevel@tonic-gate break; 54977c478bd9Sstevel@tonic-gate } 54987c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 54997c478bd9Sstevel@tonic-gate pip = next; 55007c478bd9Sstevel@tonic-gate } 55017c478bd9Sstevel@tonic-gate 5502ee28b439Scm136836 55037c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 55047c478bd9Sstevel@tonic-gate if (found_it == 0) { 55057c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 55067c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 55077c478bd9Sstevel@tonic-gate " failed. Could not find corresponding pip\n")); 55087c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 55097c478bd9Sstevel@tonic-gate } 5510ee28b439Scm136836 5511ee28b439Scm136836 (void) i_mdi_enable_disable_path(pip, vh, flags, op); 55127c478bd9Sstevel@tonic-gate } 55137c478bd9Sstevel@tonic-gate 55147c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5515*c73a93f2Sdm120769 " Returning success op: %x pdip = %p cdip = %p\n", op, 5516*c73a93f2Sdm120769 pdip, cdip)); 5517*c73a93f2Sdm120769 return (MDI_SUCCESS); 5518*c73a93f2Sdm120769 } 5519*c73a93f2Sdm120769 5520*c73a93f2Sdm120769 /*ARGSUSED3*/ 5521*c73a93f2Sdm120769 int 5522*c73a93f2Sdm120769 mdi_devi_config_one(dev_info_t *pdip, char *devnm, dev_info_t **cdipp, 5523*c73a93f2Sdm120769 int flags, clock_t timeout) 5524*c73a93f2Sdm120769 { 5525*c73a93f2Sdm120769 mdi_pathinfo_t *pip; 5526*c73a93f2Sdm120769 dev_info_t *dip; 5527*c73a93f2Sdm120769 clock_t interval = drv_usectohz(100000); /* 0.1 sec */ 5528*c73a93f2Sdm120769 char *paddr; 5529*c73a93f2Sdm120769 5530*c73a93f2Sdm120769 MDI_DEBUG(2, (CE_NOTE, NULL, "configure device %s", devnm)); 5531*c73a93f2Sdm120769 5532*c73a93f2Sdm120769 if (!MDI_PHCI(pdip)) 5533*c73a93f2Sdm120769 return (MDI_FAILURE); 5534*c73a93f2Sdm120769 5535*c73a93f2Sdm120769 paddr = strchr(devnm, '@'); 5536*c73a93f2Sdm120769 if (paddr == NULL) 5537*c73a93f2Sdm120769 return (MDI_FAILURE); 5538*c73a93f2Sdm120769 5539*c73a93f2Sdm120769 paddr++; /* skip '@' */ 5540*c73a93f2Sdm120769 pip = mdi_pi_find(pdip, NULL, paddr); 5541*c73a93f2Sdm120769 while (pip == NULL && timeout > 0) { 5542*c73a93f2Sdm120769 if (interval > timeout) 5543*c73a93f2Sdm120769 interval = timeout; 5544*c73a93f2Sdm120769 if (flags & NDI_DEVI_DEBUG) { 5545*c73a93f2Sdm120769 cmn_err(CE_CONT, "%s%d: %s timeout %ld %ld\n", 5546*c73a93f2Sdm120769 ddi_driver_name(pdip), ddi_get_instance(pdip), 5547*c73a93f2Sdm120769 paddr, interval, timeout); 5548*c73a93f2Sdm120769 } 5549*c73a93f2Sdm120769 delay(interval); 5550*c73a93f2Sdm120769 timeout -= interval; 5551*c73a93f2Sdm120769 interval += interval; 5552*c73a93f2Sdm120769 pip = mdi_pi_find(pdip, NULL, paddr); 5553*c73a93f2Sdm120769 } 5554*c73a93f2Sdm120769 5555*c73a93f2Sdm120769 if (pip == NULL) 5556*c73a93f2Sdm120769 return (MDI_FAILURE); 5557*c73a93f2Sdm120769 dip = mdi_pi_get_client(pip); 5558*c73a93f2Sdm120769 if (ndi_devi_online(dip, flags) != NDI_SUCCESS) 5559*c73a93f2Sdm120769 return (MDI_FAILURE); 5560*c73a93f2Sdm120769 *cdipp = dip; 5561*c73a93f2Sdm120769 5562*c73a93f2Sdm120769 /* TODO: holding should happen inside search functions */ 5563*c73a93f2Sdm120769 ndi_hold_devi(dip); 55647c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 55657c478bd9Sstevel@tonic-gate } 55667c478bd9Sstevel@tonic-gate 55677c478bd9Sstevel@tonic-gate /* 55687c478bd9Sstevel@tonic-gate * Ensure phci powered up 55697c478bd9Sstevel@tonic-gate */ 55707c478bd9Sstevel@tonic-gate static void 55717c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(mdi_pathinfo_t *pip) 55727c478bd9Sstevel@tonic-gate { 55737c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 55747c478bd9Sstevel@tonic-gate 55757c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 5576*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 55777c478bd9Sstevel@tonic-gate 55787c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 55797c478bd9Sstevel@tonic-gate return; 55807c478bd9Sstevel@tonic-gate } 55817c478bd9Sstevel@tonic-gate 55827c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 5583*c73a93f2Sdm120769 MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_hold_pip for %s%d\n", 5584*c73a93f2Sdm120769 ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 55857c478bd9Sstevel@tonic-gate if (ph_dip == NULL) { 55867c478bd9Sstevel@tonic-gate return; 55877c478bd9Sstevel@tonic-gate } 55887c478bd9Sstevel@tonic-gate 55897c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 55907c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 55917c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55927c478bd9Sstevel@tonic-gate pm_hold_power(ph_dip); 55937c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 55947c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55957c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 55967c478bd9Sstevel@tonic-gate 55977c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 1; 55987c478bd9Sstevel@tonic-gate } 55997c478bd9Sstevel@tonic-gate 56007c478bd9Sstevel@tonic-gate /* 56017c478bd9Sstevel@tonic-gate * Allow phci powered down 56027c478bd9Sstevel@tonic-gate */ 56037c478bd9Sstevel@tonic-gate static void 56047c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(mdi_pathinfo_t *pip) 56057c478bd9Sstevel@tonic-gate { 56067c478bd9Sstevel@tonic-gate dev_info_t *ph_dip = NULL; 56077c478bd9Sstevel@tonic-gate 56087c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 5609*c73a93f2Sdm120769 ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 56107c478bd9Sstevel@tonic-gate 56117c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 56127c478bd9Sstevel@tonic-gate return; 56137c478bd9Sstevel@tonic-gate } 56147c478bd9Sstevel@tonic-gate 56157c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 56167c478bd9Sstevel@tonic-gate ASSERT(ph_dip != NULL); 56177c478bd9Sstevel@tonic-gate 56187c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5619*c73a93f2Sdm120769 MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_rele_pip for %s%d\n", 5620*c73a93f2Sdm120769 ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 56217c478bd9Sstevel@tonic-gate 56227c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 56237c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 56247c478bd9Sstevel@tonic-gate pm_rele_power(ph_dip); 56257c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 56267c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 56277c478bd9Sstevel@tonic-gate 56287c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 56297c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 0; 56307c478bd9Sstevel@tonic-gate } 56317c478bd9Sstevel@tonic-gate 56327c478bd9Sstevel@tonic-gate static void 56337c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(mdi_client_t *ct, int incr) 56347c478bd9Sstevel@tonic-gate { 5635*c73a93f2Sdm120769 ASSERT(ct); 56367c478bd9Sstevel@tonic-gate 56377c478bd9Sstevel@tonic-gate ct->ct_power_cnt += incr; 5638*c73a93f2Sdm120769 MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_hold_client " 5639*c73a93f2Sdm120769 "ct_power_cnt = %d incr = %d\n", ct->ct_power_cnt, incr)); 56407c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 56417c478bd9Sstevel@tonic-gate } 56427c478bd9Sstevel@tonic-gate 56437c478bd9Sstevel@tonic-gate static void 56447c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(mdi_client_t *ct) 56457c478bd9Sstevel@tonic-gate { 56467c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 56477c478bd9Sstevel@tonic-gate 5648*c73a93f2Sdm120769 ASSERT(mutex_owned(&ct->ct_mutex)); 56497c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 56507c478bd9Sstevel@tonic-gate while (pip != NULL) { 56517c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 56527c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 56537c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 56547c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 56557c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 56567c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 56577c478bd9Sstevel@tonic-gate } 56587c478bd9Sstevel@tonic-gate } 56597c478bd9Sstevel@tonic-gate 56607c478bd9Sstevel@tonic-gate static void 56617c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(mdi_client_t *ct, int decr) 56627c478bd9Sstevel@tonic-gate { 5663*c73a93f2Sdm120769 ASSERT(ct); 56647c478bd9Sstevel@tonic-gate 5665737d277aScth if (i_ddi_devi_attached(ct->ct_dip)) { 56667c478bd9Sstevel@tonic-gate ct->ct_power_cnt -= decr; 5667*c73a93f2Sdm120769 MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_rele_client " 5668*c73a93f2Sdm120769 "ct_power_cnt = %d decr = %d\n", ct->ct_power_cnt, decr)); 56697c478bd9Sstevel@tonic-gate } 56707c478bd9Sstevel@tonic-gate 56717c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 56727c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 56737c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 56747c478bd9Sstevel@tonic-gate return; 56757c478bd9Sstevel@tonic-gate } 56767c478bd9Sstevel@tonic-gate } 56777c478bd9Sstevel@tonic-gate 56787c478bd9Sstevel@tonic-gate static void 56797c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(mdi_client_t *ct) 56807c478bd9Sstevel@tonic-gate { 5681*c73a93f2Sdm120769 MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_reset_client " 5682*c73a93f2Sdm120769 "ct_power_cnt = %d\n", ct->ct_power_cnt)); 56837c478bd9Sstevel@tonic-gate ct->ct_power_cnt = 0; 56847c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 568578dc6db2Sllai1 ct->ct_powercnt_config = 0; 568678dc6db2Sllai1 ct->ct_powercnt_unconfig = 0; 56877c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 1; 56887c478bd9Sstevel@tonic-gate } 56897c478bd9Sstevel@tonic-gate 5690*c73a93f2Sdm120769 static void 5691*c73a93f2Sdm120769 i_mdi_pm_hold_all_phci(mdi_client_t *ct) 5692*c73a93f2Sdm120769 { 5693*c73a93f2Sdm120769 mdi_pathinfo_t *pip; 5694*c73a93f2Sdm120769 ASSERT(mutex_owned(&ct->ct_mutex)); 5695*c73a93f2Sdm120769 5696*c73a93f2Sdm120769 pip = (mdi_pathinfo_t *)ct->ct_path_head; 5697*c73a93f2Sdm120769 while (pip != NULL) { 5698*c73a93f2Sdm120769 mdi_hold_path(pip); 5699*c73a93f2Sdm120769 MDI_PI_LOCK(pip); 5700*c73a93f2Sdm120769 i_mdi_pm_hold_pip(pip); 5701*c73a93f2Sdm120769 MDI_PI_UNLOCK(pip); 5702*c73a93f2Sdm120769 mdi_rele_path(pip); 5703*c73a93f2Sdm120769 pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 5704*c73a93f2Sdm120769 } 5705*c73a93f2Sdm120769 } 5706*c73a93f2Sdm120769 57077c478bd9Sstevel@tonic-gate static int 57087c478bd9Sstevel@tonic-gate i_mdi_power_one_phci(mdi_pathinfo_t *pip) 57097c478bd9Sstevel@tonic-gate { 57107c478bd9Sstevel@tonic-gate int ret; 57117c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 57127c478bd9Sstevel@tonic-gate 57137c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 57147c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 57157c478bd9Sstevel@tonic-gate 57167c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 57177c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 57187c478bd9Sstevel@tonic-gate 57197c478bd9Sstevel@tonic-gate /* bring all components of phci to full power */ 57207c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 5721*c73a93f2Sdm120769 "pm_powerup for %s%d\n", ddi_get_name(ph_dip), 5722*c73a93f2Sdm120769 ddi_get_instance(ph_dip))); 57237c478bd9Sstevel@tonic-gate 57247c478bd9Sstevel@tonic-gate ret = pm_powerup(ph_dip); 57257c478bd9Sstevel@tonic-gate 57267c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 57277c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 5728*c73a93f2Sdm120769 "pm_powerup FAILED for %s%d\n", 5729*c73a93f2Sdm120769 ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 57307c478bd9Sstevel@tonic-gate 57317c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 57327c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 57337c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 57347c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 57357c478bd9Sstevel@tonic-gate } 57367c478bd9Sstevel@tonic-gate 57377c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 57387c478bd9Sstevel@tonic-gate } 57397c478bd9Sstevel@tonic-gate 57407c478bd9Sstevel@tonic-gate static int 57417c478bd9Sstevel@tonic-gate i_mdi_power_all_phci(mdi_client_t *ct) 57427c478bd9Sstevel@tonic-gate { 57437c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 57447c478bd9Sstevel@tonic-gate int succeeded = 0; 57457c478bd9Sstevel@tonic-gate 57467c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 57477c478bd9Sstevel@tonic-gate while (pip != NULL) { 57487c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 57497c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 57507c478bd9Sstevel@tonic-gate if (i_mdi_power_one_phci(pip) == MDI_SUCCESS) 57517c478bd9Sstevel@tonic-gate succeeded = 1; 57527c478bd9Sstevel@tonic-gate 57537c478bd9Sstevel@tonic-gate ASSERT(ct == MDI_PI(pip)->pi_client); 57547c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 57557c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 57567c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 57577c478bd9Sstevel@tonic-gate } 57587c478bd9Sstevel@tonic-gate 57597c478bd9Sstevel@tonic-gate return (succeeded ? MDI_SUCCESS : MDI_FAILURE); 57607c478bd9Sstevel@tonic-gate } 57617c478bd9Sstevel@tonic-gate 57627c478bd9Sstevel@tonic-gate /* 57637c478bd9Sstevel@tonic-gate * mdi_bus_power(): 57647c478bd9Sstevel@tonic-gate * 1. Place the phci(s) into powered up state so that 57657c478bd9Sstevel@tonic-gate * client can do power management 57667c478bd9Sstevel@tonic-gate * 2. Ensure phci powered up as client power managing 57677c478bd9Sstevel@tonic-gate * Return Values: 57687c478bd9Sstevel@tonic-gate * MDI_SUCCESS 57697c478bd9Sstevel@tonic-gate * MDI_FAILURE 57707c478bd9Sstevel@tonic-gate */ 57717c478bd9Sstevel@tonic-gate int 57727c478bd9Sstevel@tonic-gate mdi_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op, 57737c478bd9Sstevel@tonic-gate void *arg, void *result) 57747c478bd9Sstevel@tonic-gate { 57757c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 57767c478bd9Sstevel@tonic-gate pm_bp_child_pwrchg_t *bpc; 57777c478bd9Sstevel@tonic-gate mdi_client_t *ct; 57787c478bd9Sstevel@tonic-gate dev_info_t *cdip; 57797c478bd9Sstevel@tonic-gate pm_bp_has_changed_t *bphc; 57807c478bd9Sstevel@tonic-gate 57817c478bd9Sstevel@tonic-gate /* 57827c478bd9Sstevel@tonic-gate * BUS_POWER_NOINVOL not supported 57837c478bd9Sstevel@tonic-gate */ 57847c478bd9Sstevel@tonic-gate if (op == BUS_POWER_NOINVOL) 57857c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 57867c478bd9Sstevel@tonic-gate 57877c478bd9Sstevel@tonic-gate /* 57887c478bd9Sstevel@tonic-gate * ignore other OPs. 57897c478bd9Sstevel@tonic-gate * return quickly to save cou cycles on the ct processing 57907c478bd9Sstevel@tonic-gate */ 57917c478bd9Sstevel@tonic-gate switch (op) { 57927c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 57937c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 57947c478bd9Sstevel@tonic-gate bpc = (pm_bp_child_pwrchg_t *)arg; 57957c478bd9Sstevel@tonic-gate cdip = bpc->bpc_dip; 57967c478bd9Sstevel@tonic-gate break; 57977c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 57987c478bd9Sstevel@tonic-gate bphc = (pm_bp_has_changed_t *)arg; 57997c478bd9Sstevel@tonic-gate cdip = bphc->bphc_dip; 58007c478bd9Sstevel@tonic-gate break; 58017c478bd9Sstevel@tonic-gate default: 58027c478bd9Sstevel@tonic-gate return (pm_busop_bus_power(parent, impl_arg, op, arg, result)); 58037c478bd9Sstevel@tonic-gate } 58047c478bd9Sstevel@tonic-gate 58057c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(cdip)); 58067c478bd9Sstevel@tonic-gate 58077c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 58087c478bd9Sstevel@tonic-gate if (ct == NULL) 58097c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 58107c478bd9Sstevel@tonic-gate 58117c478bd9Sstevel@tonic-gate /* 58127c478bd9Sstevel@tonic-gate * wait till the mdi_pathinfo node state change are processed 58137c478bd9Sstevel@tonic-gate */ 58147c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 58157c478bd9Sstevel@tonic-gate switch (op) { 58167c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 58177c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 58187c478bd9Sstevel@tonic-gate "BUS_POWER_PRE_NOTIFICATION:" 58197c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 58207c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 58217c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp)); 58227c478bd9Sstevel@tonic-gate 58237c478bd9Sstevel@tonic-gate /* serialize power level change per client */ 58247c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 58257c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 58267c478bd9Sstevel@tonic-gate 58277c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_TRANSITION(ct); 58287c478bd9Sstevel@tonic-gate 58297c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 58307c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 58317c478bd9Sstevel@tonic-gate } 58327c478bd9Sstevel@tonic-gate 58337c478bd9Sstevel@tonic-gate /* 58347c478bd9Sstevel@tonic-gate * if new_level > 0: 58357c478bd9Sstevel@tonic-gate * - hold phci(s) 58367c478bd9Sstevel@tonic-gate * - power up phci(s) if not already 58377c478bd9Sstevel@tonic-gate * ignore power down 58387c478bd9Sstevel@tonic-gate */ 58397c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 58407c478bd9Sstevel@tonic-gate if (!DEVI_IS_ATTACHING(ct->ct_dip)) { 58417c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 58427c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 58437c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 58447c478bd9Sstevel@tonic-gate } 58457c478bd9Sstevel@tonic-gate } 58467c478bd9Sstevel@tonic-gate break; 58477c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 58487c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 58497c478bd9Sstevel@tonic-gate "BUS_POWER_POST_NOTIFICATION:" 58507c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d result=%d\n", 58517c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 58527c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp, 58537c478bd9Sstevel@tonic-gate *(int *)result)); 58547c478bd9Sstevel@tonic-gate 58557c478bd9Sstevel@tonic-gate if (*(int *)result == DDI_SUCCESS) { 58567c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 58577c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 58587c478bd9Sstevel@tonic-gate } else { 58597c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_DOWN(ct); 58607c478bd9Sstevel@tonic-gate } 58617c478bd9Sstevel@tonic-gate } 58627c478bd9Sstevel@tonic-gate 58637c478bd9Sstevel@tonic-gate /* release the hold we did in pre-notification */ 58647c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0 && (*(int *)result != DDI_SUCCESS) && 58657c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) { 58667c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 58677c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 58687c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 58697c478bd9Sstevel@tonic-gate } 58707c478bd9Sstevel@tonic-gate 58717c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel == 0 && (*(int *)result == DDI_SUCCESS)) { 58727c478bd9Sstevel@tonic-gate /* another thread might started attaching */ 58737c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 58747c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 58757c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 58767c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 58777c478bd9Sstevel@tonic-gate /* detaching has been taken care in pm_post_unconfig */ 58787c478bd9Sstevel@tonic-gate } else if (!DEVI_IS_DETACHING(ct->ct_dip)) { 58797c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 58807c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_reset_client\n")); 58817c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 58827c478bd9Sstevel@tonic-gate } 58837c478bd9Sstevel@tonic-gate } 58847c478bd9Sstevel@tonic-gate 58857c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_POWER_TRANSITION(ct); 58867c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_powerchange_cv); 58877c478bd9Sstevel@tonic-gate 58887c478bd9Sstevel@tonic-gate break; 58897c478bd9Sstevel@tonic-gate 58907c478bd9Sstevel@tonic-gate /* need to do more */ 58917c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 58927c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, "mdi_bus_power " 58937c478bd9Sstevel@tonic-gate "BUS_POWER_HAS_CHANGED:" 58947c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 58957c478bd9Sstevel@tonic-gate PM_NAME(bphc->bphc_dip), PM_ADDR(bphc->bphc_dip), 58967c478bd9Sstevel@tonic-gate bphc->bphc_olevel, bphc->bphc_nlevel, bphc->bphc_comp)); 58977c478bd9Sstevel@tonic-gate 58987c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel > 0 && 58997c478bd9Sstevel@tonic-gate bphc->bphc_nlevel > bphc->bphc_olevel) { 59007c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 59017c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 59027c478bd9Sstevel@tonic-gate } 59037c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 59047c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 59057c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 59067c478bd9Sstevel@tonic-gate } 59077c478bd9Sstevel@tonic-gate 59087c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel == 0 && bphc->bphc_olevel != -1) { 59097c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 59107c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 59117c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 59127c478bd9Sstevel@tonic-gate } 59137c478bd9Sstevel@tonic-gate break; 59147c478bd9Sstevel@tonic-gate } 59157c478bd9Sstevel@tonic-gate 59167c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59177c478bd9Sstevel@tonic-gate return (ret); 59187c478bd9Sstevel@tonic-gate } 59197c478bd9Sstevel@tonic-gate 59207c478bd9Sstevel@tonic-gate static int 59217c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config_one(dev_info_t *child) 59227c478bd9Sstevel@tonic-gate { 59237c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 59247c478bd9Sstevel@tonic-gate mdi_client_t *ct; 59257c478bd9Sstevel@tonic-gate 59267c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 59277c478bd9Sstevel@tonic-gate if (ct == NULL) 59287c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 59297c478bd9Sstevel@tonic-gate 59307c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 59317c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 59327c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 59337c478bd9Sstevel@tonic-gate 59347c478bd9Sstevel@tonic-gate if (!MDI_CLIENT_IS_FAILED(ct)) { 59357c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59367c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59377c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one already configured\n")); 59387c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 59397c478bd9Sstevel@tonic-gate } 59407c478bd9Sstevel@tonic-gate 594178dc6db2Sllai1 if (ct->ct_powercnt_config) { 59427c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59437c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59447c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one ALREADY held\n")); 59457c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 59467c478bd9Sstevel@tonic-gate } 59477c478bd9Sstevel@tonic-gate 59487c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 59497c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 59507c478bd9Sstevel@tonic-gate } 59517c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59527c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one i_mdi_pm_hold_client\n")); 59537c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 595478dc6db2Sllai1 ct->ct_powercnt_config = 1; 59557c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 59567c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59577c478bd9Sstevel@tonic-gate return (ret); 59587c478bd9Sstevel@tonic-gate } 59597c478bd9Sstevel@tonic-gate 59607c478bd9Sstevel@tonic-gate static int 5961*c73a93f2Sdm120769 i_mdi_pm_pre_config(dev_info_t *parent, dev_info_t *child) 59627c478bd9Sstevel@tonic-gate { 59637c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 59647c478bd9Sstevel@tonic-gate dev_info_t *cdip; 59657c478bd9Sstevel@tonic-gate int circ; 59667c478bd9Sstevel@tonic-gate 5967*c73a93f2Sdm120769 ASSERT(MDI_VHCI(parent)); 59687c478bd9Sstevel@tonic-gate 59697c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 59707c478bd9Sstevel@tonic-gate if (child) { 59717c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_config_one(child)); 59727c478bd9Sstevel@tonic-gate } 59737c478bd9Sstevel@tonic-gate 59747c478bd9Sstevel@tonic-gate /* devi_config_common */ 5975*c73a93f2Sdm120769 ndi_devi_enter(parent, &circ); 5976*c73a93f2Sdm120769 cdip = ddi_get_child(parent); 59777c478bd9Sstevel@tonic-gate while (cdip) { 59787c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 59797c478bd9Sstevel@tonic-gate 59807c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config_one(cdip); 59817c478bd9Sstevel@tonic-gate if (ret != MDI_SUCCESS) 59827c478bd9Sstevel@tonic-gate break; 59837c478bd9Sstevel@tonic-gate cdip = next; 59847c478bd9Sstevel@tonic-gate } 5985*c73a93f2Sdm120769 ndi_devi_exit(parent, circ); 59867c478bd9Sstevel@tonic-gate return (ret); 59877c478bd9Sstevel@tonic-gate } 59887c478bd9Sstevel@tonic-gate 59897c478bd9Sstevel@tonic-gate static int 59907c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig_one(dev_info_t *child, int *held, int flags) 59917c478bd9Sstevel@tonic-gate { 59927c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 59937c478bd9Sstevel@tonic-gate mdi_client_t *ct; 59947c478bd9Sstevel@tonic-gate 59957c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 59967c478bd9Sstevel@tonic-gate if (ct == NULL) 59977c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 59987c478bd9Sstevel@tonic-gate 59997c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 60007c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 60017c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 60027c478bd9Sstevel@tonic-gate 6003737d277aScth if (!i_ddi_devi_attached(ct->ct_dip)) { 60047c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60057c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig node detached already\n")); 60067c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60077c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 60087c478bd9Sstevel@tonic-gate } 60097c478bd9Sstevel@tonic-gate 60107c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_POWERED_DOWN(ct) && 60117c478bd9Sstevel@tonic-gate (flags & NDI_AUTODETACH)) { 60127c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60137c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig auto-modunload\n")); 60147c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60157c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 60167c478bd9Sstevel@tonic-gate } 60177c478bd9Sstevel@tonic-gate 601878dc6db2Sllai1 if (ct->ct_powercnt_unconfig) { 60197c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60207c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig ct_powercnt_held\n")); 60217c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60227c478bd9Sstevel@tonic-gate *held = 1; 60237c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 60247c478bd9Sstevel@tonic-gate } 60257c478bd9Sstevel@tonic-gate 60267c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 60277c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 60287c478bd9Sstevel@tonic-gate } 60297c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60307c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig i_mdi_pm_hold_client\n")); 60317c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 603278dc6db2Sllai1 ct->ct_powercnt_unconfig = 1; 60337c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 60347c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60357c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) 60367c478bd9Sstevel@tonic-gate *held = 1; 60377c478bd9Sstevel@tonic-gate return (ret); 60387c478bd9Sstevel@tonic-gate } 60397c478bd9Sstevel@tonic-gate 60407c478bd9Sstevel@tonic-gate static int 6041*c73a93f2Sdm120769 i_mdi_pm_pre_unconfig(dev_info_t *parent, dev_info_t *child, int *held, 60427c478bd9Sstevel@tonic-gate int flags) 60437c478bd9Sstevel@tonic-gate { 60447c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 60457c478bd9Sstevel@tonic-gate dev_info_t *cdip; 60467c478bd9Sstevel@tonic-gate int circ; 60477c478bd9Sstevel@tonic-gate 6048*c73a93f2Sdm120769 ASSERT(MDI_VHCI(parent)); 60497c478bd9Sstevel@tonic-gate *held = 0; 60507c478bd9Sstevel@tonic-gate 60517c478bd9Sstevel@tonic-gate /* ndi_devi_unconfig_one */ 60527c478bd9Sstevel@tonic-gate if (child) { 60537c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_unconfig_one(child, held, flags)); 60547c478bd9Sstevel@tonic-gate } 60557c478bd9Sstevel@tonic-gate 60567c478bd9Sstevel@tonic-gate /* devi_unconfig_common */ 6057*c73a93f2Sdm120769 ndi_devi_enter(parent, &circ); 6058*c73a93f2Sdm120769 cdip = ddi_get_child(parent); 60597c478bd9Sstevel@tonic-gate while (cdip) { 60607c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 60617c478bd9Sstevel@tonic-gate 60627c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig_one(cdip, held, flags); 60637c478bd9Sstevel@tonic-gate cdip = next; 60647c478bd9Sstevel@tonic-gate } 6065*c73a93f2Sdm120769 ndi_devi_exit(parent, circ); 60667c478bd9Sstevel@tonic-gate 60677c478bd9Sstevel@tonic-gate if (*held) 60687c478bd9Sstevel@tonic-gate ret = MDI_SUCCESS; 60697c478bd9Sstevel@tonic-gate 60707c478bd9Sstevel@tonic-gate return (ret); 60717c478bd9Sstevel@tonic-gate } 60727c478bd9Sstevel@tonic-gate 60737c478bd9Sstevel@tonic-gate static void 60747c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(dev_info_t *child) 60757c478bd9Sstevel@tonic-gate { 60767c478bd9Sstevel@tonic-gate mdi_client_t *ct; 60777c478bd9Sstevel@tonic-gate 60787c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 60797c478bd9Sstevel@tonic-gate if (ct == NULL) 60807c478bd9Sstevel@tonic-gate return; 60817c478bd9Sstevel@tonic-gate 60827c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 60837c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 60847c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 60857c478bd9Sstevel@tonic-gate 608678dc6db2Sllai1 if (ct->ct_powercnt_reset || !ct->ct_powercnt_config) { 60877c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 608878dc6db2Sllai1 "i_mdi_pm_post_config_one NOT configured\n")); 60897c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60907c478bd9Sstevel@tonic-gate return; 60917c478bd9Sstevel@tonic-gate } 60927c478bd9Sstevel@tonic-gate 60937c478bd9Sstevel@tonic-gate /* client has not been updated */ 60947c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 60957c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60967c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config_one NOT configured\n")); 60977c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60987c478bd9Sstevel@tonic-gate return; 60997c478bd9Sstevel@tonic-gate } 61007c478bd9Sstevel@tonic-gate 61017c478bd9Sstevel@tonic-gate /* another thread might have powered it down or detached it */ 61027c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 61037c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) || 6104737d277aScth (!i_ddi_devi_attached(ct->ct_dip) && 61057c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 61067c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 61077c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_reset_client\n")); 61087c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 61097c478bd9Sstevel@tonic-gate } else { 61107c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 61117c478bd9Sstevel@tonic-gate int valid_path_count = 0; 61127c478bd9Sstevel@tonic-gate 61137c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 61147c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_rele_client\n")); 61157c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 61167c478bd9Sstevel@tonic-gate while (pip != NULL) { 61177c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 61187c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 611978dc6db2Sllai1 if (MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip)) 61207c478bd9Sstevel@tonic-gate valid_path_count ++; 61217c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 61227c478bd9Sstevel@tonic-gate pip = next; 61237c478bd9Sstevel@tonic-gate } 61247c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, valid_path_count); 61257c478bd9Sstevel@tonic-gate } 612678dc6db2Sllai1 ct->ct_powercnt_config = 0; 61277c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 61287c478bd9Sstevel@tonic-gate } 61297c478bd9Sstevel@tonic-gate 61307c478bd9Sstevel@tonic-gate static void 6131*c73a93f2Sdm120769 i_mdi_pm_post_config(dev_info_t *parent, dev_info_t *child) 61327c478bd9Sstevel@tonic-gate { 61337c478bd9Sstevel@tonic-gate int circ; 61347c478bd9Sstevel@tonic-gate dev_info_t *cdip; 6135*c73a93f2Sdm120769 ASSERT(MDI_VHCI(parent)); 61367c478bd9Sstevel@tonic-gate 61377c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 61387c478bd9Sstevel@tonic-gate if (child) { 61397c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(child); 61407c478bd9Sstevel@tonic-gate return; 61417c478bd9Sstevel@tonic-gate } 61427c478bd9Sstevel@tonic-gate 61437c478bd9Sstevel@tonic-gate /* devi_config_common */ 6144*c73a93f2Sdm120769 ndi_devi_enter(parent, &circ); 6145*c73a93f2Sdm120769 cdip = ddi_get_child(parent); 61467c478bd9Sstevel@tonic-gate while (cdip) { 61477c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 61487c478bd9Sstevel@tonic-gate 61497c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(cdip); 61507c478bd9Sstevel@tonic-gate cdip = next; 61517c478bd9Sstevel@tonic-gate } 6152*c73a93f2Sdm120769 ndi_devi_exit(parent, circ); 61537c478bd9Sstevel@tonic-gate } 61547c478bd9Sstevel@tonic-gate 61557c478bd9Sstevel@tonic-gate static void 61567c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(dev_info_t *child) 61577c478bd9Sstevel@tonic-gate { 61587c478bd9Sstevel@tonic-gate mdi_client_t *ct; 61597c478bd9Sstevel@tonic-gate 61607c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 61617c478bd9Sstevel@tonic-gate if (ct == NULL) 61627c478bd9Sstevel@tonic-gate return; 61637c478bd9Sstevel@tonic-gate 61647c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 61657c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 61667c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 61677c478bd9Sstevel@tonic-gate 616878dc6db2Sllai1 if (!ct->ct_powercnt_unconfig || ct->ct_powercnt_reset) { 61697c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 61707c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig NOT held\n")); 61717c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 61727c478bd9Sstevel@tonic-gate return; 61737c478bd9Sstevel@tonic-gate } 61747c478bd9Sstevel@tonic-gate 61757c478bd9Sstevel@tonic-gate /* failure detaching or another thread just attached it */ 61767c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 6177737d277aScth i_ddi_devi_attached(ct->ct_dip)) || 6178737d277aScth (!i_ddi_devi_attached(ct->ct_dip) && 61797c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 61807c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 61817c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig i_mdi_pm_reset_client\n")); 61827c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 618378dc6db2Sllai1 } else { 618478dc6db2Sllai1 mdi_pathinfo_t *pip, *next; 618578dc6db2Sllai1 int valid_path_count = 0; 61867c478bd9Sstevel@tonic-gate 61877c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 618878dc6db2Sllai1 "i_mdi_pm_post_unconfig i_mdi_pm_rele_client\n")); 618978dc6db2Sllai1 pip = ct->ct_path_head; 619078dc6db2Sllai1 while (pip != NULL) { 619178dc6db2Sllai1 MDI_PI_LOCK(pip); 619278dc6db2Sllai1 next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 619378dc6db2Sllai1 if (MDI_PI_IS_ONLINE(pip) || MDI_PI_IS_STANDBY(pip)) 619478dc6db2Sllai1 valid_path_count ++; 619578dc6db2Sllai1 MDI_PI_UNLOCK(pip); 619678dc6db2Sllai1 pip = next; 619778dc6db2Sllai1 } 619878dc6db2Sllai1 i_mdi_pm_rele_client(ct, valid_path_count); 619978dc6db2Sllai1 ct->ct_powercnt_unconfig = 0; 620078dc6db2Sllai1 } 620178dc6db2Sllai1 62027c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 62037c478bd9Sstevel@tonic-gate } 62047c478bd9Sstevel@tonic-gate 62057c478bd9Sstevel@tonic-gate static void 6206*c73a93f2Sdm120769 i_mdi_pm_post_unconfig(dev_info_t *parent, dev_info_t *child, int held) 62077c478bd9Sstevel@tonic-gate { 62087c478bd9Sstevel@tonic-gate int circ; 62097c478bd9Sstevel@tonic-gate dev_info_t *cdip; 62107c478bd9Sstevel@tonic-gate 6211*c73a93f2Sdm120769 ASSERT(MDI_VHCI(parent)); 62127c478bd9Sstevel@tonic-gate 62137c478bd9Sstevel@tonic-gate if (!held) { 6214*c73a93f2Sdm120769 MDI_DEBUG(4, (CE_NOTE, parent, 62157c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig held = %d\n", held)); 62167c478bd9Sstevel@tonic-gate return; 62177c478bd9Sstevel@tonic-gate } 62187c478bd9Sstevel@tonic-gate 62197c478bd9Sstevel@tonic-gate if (child) { 62207c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(child); 62217c478bd9Sstevel@tonic-gate return; 62227c478bd9Sstevel@tonic-gate } 62237c478bd9Sstevel@tonic-gate 6224*c73a93f2Sdm120769 ndi_devi_enter(parent, &circ); 6225*c73a93f2Sdm120769 cdip = ddi_get_child(parent); 62267c478bd9Sstevel@tonic-gate while (cdip) { 62277c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 62287c478bd9Sstevel@tonic-gate 62297c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(cdip); 62307c478bd9Sstevel@tonic-gate cdip = next; 62317c478bd9Sstevel@tonic-gate } 6232*c73a93f2Sdm120769 ndi_devi_exit(parent, circ); 62337c478bd9Sstevel@tonic-gate } 62347c478bd9Sstevel@tonic-gate 62357c478bd9Sstevel@tonic-gate int 62367c478bd9Sstevel@tonic-gate mdi_power(dev_info_t *vdip, mdi_pm_op_t op, void *args, char *devnm, int flags) 62377c478bd9Sstevel@tonic-gate { 62387c478bd9Sstevel@tonic-gate int circ, ret = MDI_SUCCESS; 62397c478bd9Sstevel@tonic-gate dev_info_t *client_dip = NULL; 62407c478bd9Sstevel@tonic-gate mdi_client_t *ct; 62417c478bd9Sstevel@tonic-gate 62427c478bd9Sstevel@tonic-gate /* 62437c478bd9Sstevel@tonic-gate * Handling ndi_devi_config_one and ndi_devi_unconfig_one. 62447c478bd9Sstevel@tonic-gate * Power up pHCI for the named client device. 62457c478bd9Sstevel@tonic-gate * Note: Before the client is enumerated under vhci by phci, 62467c478bd9Sstevel@tonic-gate * client_dip can be NULL. Then proceed to power up all the 62477c478bd9Sstevel@tonic-gate * pHCIs. 62487c478bd9Sstevel@tonic-gate */ 62497c478bd9Sstevel@tonic-gate if (devnm != NULL) { 62507c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circ); 62517c478bd9Sstevel@tonic-gate client_dip = ndi_devi_findchild(vdip, devnm); 6252*c73a93f2Sdm120769 ndi_devi_exit(vdip, circ); 62537c478bd9Sstevel@tonic-gate } 62547c478bd9Sstevel@tonic-gate 6255*c73a93f2Sdm120769 MDI_DEBUG(4, (CE_NOTE, vdip, "mdi_power op = %d\n", op)); 62567c478bd9Sstevel@tonic-gate 62577c478bd9Sstevel@tonic-gate switch (op) { 62587c478bd9Sstevel@tonic-gate case MDI_PM_PRE_CONFIG: 62597c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config(vdip, client_dip); 6260144dfaa9Scth 6261*c73a93f2Sdm120769 break; 62627c478bd9Sstevel@tonic-gate case MDI_PM_PRE_UNCONFIG: 62637c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig(vdip, client_dip, (int *)args, 62647c478bd9Sstevel@tonic-gate flags); 6265144dfaa9Scth 6266*c73a93f2Sdm120769 break; 62677c478bd9Sstevel@tonic-gate case MDI_PM_POST_CONFIG: 62687c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(vdip, client_dip); 6269144dfaa9Scth 6270*c73a93f2Sdm120769 break; 62717c478bd9Sstevel@tonic-gate case MDI_PM_POST_UNCONFIG: 62727c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(vdip, client_dip, *(int *)args); 6273144dfaa9Scth 6274*c73a93f2Sdm120769 break; 62757c478bd9Sstevel@tonic-gate case MDI_PM_HOLD_POWER: 62767c478bd9Sstevel@tonic-gate case MDI_PM_RELE_POWER: 62777c478bd9Sstevel@tonic-gate ASSERT(args); 62787c478bd9Sstevel@tonic-gate 62797c478bd9Sstevel@tonic-gate client_dip = (dev_info_t *)args; 62807c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(client_dip)); 62817c478bd9Sstevel@tonic-gate 62827c478bd9Sstevel@tonic-gate ct = i_devi_get_client(client_dip); 62837c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 62847c478bd9Sstevel@tonic-gate 62857c478bd9Sstevel@tonic-gate if (op == MDI_PM_HOLD_POWER) { 62867c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 62877c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 62887c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 62897c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_hold_client\n")); 62907c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 62917c478bd9Sstevel@tonic-gate } 62927c478bd9Sstevel@tonic-gate } else { 62937c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 62947c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 62957c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_rele_client\n")); 62967c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 62977c478bd9Sstevel@tonic-gate } else { 62987c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 62997c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_reset_client\n")); 63007c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 63017c478bd9Sstevel@tonic-gate } 63027c478bd9Sstevel@tonic-gate } 63037c478bd9Sstevel@tonic-gate 63047c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 63057c478bd9Sstevel@tonic-gate break; 63067c478bd9Sstevel@tonic-gate default: 63077c478bd9Sstevel@tonic-gate break; 63087c478bd9Sstevel@tonic-gate } 63097c478bd9Sstevel@tonic-gate 63107c478bd9Sstevel@tonic-gate return (ret); 63117c478bd9Sstevel@tonic-gate } 63127c478bd9Sstevel@tonic-gate 63137c478bd9Sstevel@tonic-gate int 63147c478bd9Sstevel@tonic-gate mdi_component_is_vhci(dev_info_t *dip, const char **mdi_class) 63157c478bd9Sstevel@tonic-gate { 63167c478bd9Sstevel@tonic-gate mdi_vhci_t *vhci; 63177c478bd9Sstevel@tonic-gate 63187c478bd9Sstevel@tonic-gate if (!MDI_VHCI(dip)) 63197c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 63207c478bd9Sstevel@tonic-gate 63217c478bd9Sstevel@tonic-gate if (mdi_class) { 63227c478bd9Sstevel@tonic-gate vhci = DEVI(dip)->devi_mdi_xhci; 63237c478bd9Sstevel@tonic-gate ASSERT(vhci); 63247c478bd9Sstevel@tonic-gate *mdi_class = vhci->vh_class; 63257c478bd9Sstevel@tonic-gate } 63267c478bd9Sstevel@tonic-gate 63277c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 63287c478bd9Sstevel@tonic-gate } 63297c478bd9Sstevel@tonic-gate 63307c478bd9Sstevel@tonic-gate int 63317c478bd9Sstevel@tonic-gate mdi_component_is_phci(dev_info_t *dip, const char **mdi_class) 63327c478bd9Sstevel@tonic-gate { 63337c478bd9Sstevel@tonic-gate mdi_phci_t *phci; 63347c478bd9Sstevel@tonic-gate 63357c478bd9Sstevel@tonic-gate if (!MDI_PHCI(dip)) 63367c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 63377c478bd9Sstevel@tonic-gate 63387c478bd9Sstevel@tonic-gate if (mdi_class) { 63397c478bd9Sstevel@tonic-gate phci = DEVI(dip)->devi_mdi_xhci; 63407c478bd9Sstevel@tonic-gate ASSERT(phci); 63417c478bd9Sstevel@tonic-gate *mdi_class = phci->ph_vhci->vh_class; 63427c478bd9Sstevel@tonic-gate } 63437c478bd9Sstevel@tonic-gate 63447c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 63457c478bd9Sstevel@tonic-gate } 63467c478bd9Sstevel@tonic-gate 63477c478bd9Sstevel@tonic-gate int 63487c478bd9Sstevel@tonic-gate mdi_component_is_client(dev_info_t *dip, const char **mdi_class) 63497c478bd9Sstevel@tonic-gate { 63507c478bd9Sstevel@tonic-gate mdi_client_t *client; 63517c478bd9Sstevel@tonic-gate 63527c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(dip)) 63537c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 63547c478bd9Sstevel@tonic-gate 63557c478bd9Sstevel@tonic-gate if (mdi_class) { 63567c478bd9Sstevel@tonic-gate client = DEVI(dip)->devi_mdi_client; 63577c478bd9Sstevel@tonic-gate ASSERT(client); 63587c478bd9Sstevel@tonic-gate *mdi_class = client->ct_vhci->vh_class; 63597c478bd9Sstevel@tonic-gate } 63607c478bd9Sstevel@tonic-gate 63617c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 63627c478bd9Sstevel@tonic-gate } 63637c478bd9Sstevel@tonic-gate 63647c478bd9Sstevel@tonic-gate void * 63657c478bd9Sstevel@tonic-gate mdi_client_get_vhci_private(dev_info_t *dip) 63667c478bd9Sstevel@tonic-gate { 63677c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 63687c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 63697c478bd9Sstevel@tonic-gate mdi_client_t *ct; 63707c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 63717c478bd9Sstevel@tonic-gate return (ct->ct_vprivate); 63727c478bd9Sstevel@tonic-gate } 63737c478bd9Sstevel@tonic-gate return (NULL); 63747c478bd9Sstevel@tonic-gate } 63757c478bd9Sstevel@tonic-gate 63767c478bd9Sstevel@tonic-gate void 63777c478bd9Sstevel@tonic-gate mdi_client_set_vhci_private(dev_info_t *dip, void *data) 63787c478bd9Sstevel@tonic-gate { 63797c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 63807c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 63817c478bd9Sstevel@tonic-gate mdi_client_t *ct; 63827c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 63837c478bd9Sstevel@tonic-gate ct->ct_vprivate = data; 63847c478bd9Sstevel@tonic-gate } 63857c478bd9Sstevel@tonic-gate } 63867c478bd9Sstevel@tonic-gate /* 63877c478bd9Sstevel@tonic-gate * mdi_pi_get_vhci_private(): 63887c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 63897c478bd9Sstevel@tonic-gate * mdi_pathinfo node 63907c478bd9Sstevel@tonic-gate */ 63917c478bd9Sstevel@tonic-gate void * 63927c478bd9Sstevel@tonic-gate mdi_pi_get_vhci_private(mdi_pathinfo_t *pip) 63937c478bd9Sstevel@tonic-gate { 63947c478bd9Sstevel@tonic-gate caddr_t vprivate = NULL; 63957c478bd9Sstevel@tonic-gate if (pip) { 63967c478bd9Sstevel@tonic-gate vprivate = MDI_PI(pip)->pi_vprivate; 63977c478bd9Sstevel@tonic-gate } 63987c478bd9Sstevel@tonic-gate return (vprivate); 63997c478bd9Sstevel@tonic-gate } 64007c478bd9Sstevel@tonic-gate 64017c478bd9Sstevel@tonic-gate /* 64027c478bd9Sstevel@tonic-gate * mdi_pi_set_vhci_private(): 64037c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_pathinfo node 64047c478bd9Sstevel@tonic-gate */ 64057c478bd9Sstevel@tonic-gate void 64067c478bd9Sstevel@tonic-gate mdi_pi_set_vhci_private(mdi_pathinfo_t *pip, void *priv) 64077c478bd9Sstevel@tonic-gate { 64087c478bd9Sstevel@tonic-gate if (pip) { 64097c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = priv; 64107c478bd9Sstevel@tonic-gate } 64117c478bd9Sstevel@tonic-gate } 64127c478bd9Sstevel@tonic-gate 64137c478bd9Sstevel@tonic-gate /* 64147c478bd9Sstevel@tonic-gate * mdi_phci_get_vhci_private(): 64157c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 64167c478bd9Sstevel@tonic-gate * mdi_phci node 64177c478bd9Sstevel@tonic-gate */ 64187c478bd9Sstevel@tonic-gate void * 64197c478bd9Sstevel@tonic-gate mdi_phci_get_vhci_private(dev_info_t *dip) 64207c478bd9Sstevel@tonic-gate { 64217c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 64227c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 64237c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 64247c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 64257c478bd9Sstevel@tonic-gate return (ph->ph_vprivate); 64267c478bd9Sstevel@tonic-gate } 64277c478bd9Sstevel@tonic-gate return (NULL); 64287c478bd9Sstevel@tonic-gate } 64297c478bd9Sstevel@tonic-gate 64307c478bd9Sstevel@tonic-gate /* 64317c478bd9Sstevel@tonic-gate * mdi_phci_set_vhci_private(): 64327c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_phci node 64337c478bd9Sstevel@tonic-gate */ 64347c478bd9Sstevel@tonic-gate void 64357c478bd9Sstevel@tonic-gate mdi_phci_set_vhci_private(dev_info_t *dip, void *priv) 64367c478bd9Sstevel@tonic-gate { 64377c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 64387c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 64397c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 64407c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 64417c478bd9Sstevel@tonic-gate ph->ph_vprivate = priv; 64427c478bd9Sstevel@tonic-gate } 64437c478bd9Sstevel@tonic-gate } 64443c34adc5Sramat 64453c34adc5Sramat /* 64463c34adc5Sramat * List of vhci class names: 64473c34adc5Sramat * A vhci class name must be in this list only if the corresponding vhci 64483c34adc5Sramat * driver intends to use the mdi provided bus config implementation 64493c34adc5Sramat * (i.e., mdi_vhci_bus_config()). 64503c34adc5Sramat */ 64513c34adc5Sramat static char *vhci_class_list[] = { MDI_HCI_CLASS_SCSI, MDI_HCI_CLASS_IB }; 64523c34adc5Sramat #define N_VHCI_CLASSES (sizeof (vhci_class_list) / sizeof (char *)) 64533c34adc5Sramat 64543c34adc5Sramat /* 64553c34adc5Sramat * During boot time, the on-disk vhci cache for every vhci class is read 64563c34adc5Sramat * in the form of an nvlist and stored here. 64573c34adc5Sramat */ 64583c34adc5Sramat static nvlist_t *vhcache_nvl[N_VHCI_CLASSES]; 64593c34adc5Sramat 64603c34adc5Sramat /* nvpair names in vhci cache nvlist */ 64613c34adc5Sramat #define MDI_VHCI_CACHE_VERSION 1 64623c34adc5Sramat #define MDI_NVPNAME_VERSION "version" 64633c34adc5Sramat #define MDI_NVPNAME_PHCIS "phcis" 64643c34adc5Sramat #define MDI_NVPNAME_CTADDRMAP "clientaddrmap" 64653c34adc5Sramat 64663c34adc5Sramat /* 64673c34adc5Sramat * Given vhci class name, return its on-disk vhci cache filename. 64683c34adc5Sramat * Memory for the returned filename which includes the full path is allocated 64693c34adc5Sramat * by this function. 64703c34adc5Sramat */ 64713c34adc5Sramat static char * 64723c34adc5Sramat vhclass2vhcache_filename(char *vhclass) 64733c34adc5Sramat { 64743c34adc5Sramat char *filename; 64753c34adc5Sramat int len; 64763c34adc5Sramat static char *fmt = "/etc/devices/mdi_%s_cache"; 64773c34adc5Sramat 64783c34adc5Sramat /* 64793c34adc5Sramat * fmt contains the on-disk vhci cache file name format; 64803c34adc5Sramat * for scsi_vhci the filename is "/etc/devices/mdi_scsi_vhci_cache". 64813c34adc5Sramat */ 64823c34adc5Sramat 64833c34adc5Sramat /* the -1 below is to account for "%s" in the format string */ 64843c34adc5Sramat len = strlen(fmt) + strlen(vhclass) - 1; 64853c34adc5Sramat filename = kmem_alloc(len, KM_SLEEP); 64863c34adc5Sramat (void) snprintf(filename, len, fmt, vhclass); 64873c34adc5Sramat ASSERT(len == (strlen(filename) + 1)); 64883c34adc5Sramat return (filename); 64893c34adc5Sramat } 64903c34adc5Sramat 64913c34adc5Sramat /* 64923c34adc5Sramat * initialize the vhci cache related data structures and read the on-disk 64933c34adc5Sramat * vhci cached data into memory. 64943c34adc5Sramat */ 64953c34adc5Sramat static void 64963c34adc5Sramat setup_vhci_cache(mdi_vhci_t *vh) 64973c34adc5Sramat { 64983c34adc5Sramat mdi_vhci_config_t *vhc; 64993c34adc5Sramat mdi_vhci_cache_t *vhcache; 65003c34adc5Sramat int i; 65013c34adc5Sramat nvlist_t *nvl = NULL; 65023c34adc5Sramat 65033c34adc5Sramat vhc = kmem_zalloc(sizeof (mdi_vhci_config_t), KM_SLEEP); 65043c34adc5Sramat vh->vh_config = vhc; 65053c34adc5Sramat vhcache = &vhc->vhc_vhcache; 65063c34adc5Sramat 65073c34adc5Sramat vhc->vhc_vhcache_filename = vhclass2vhcache_filename(vh->vh_class); 65083c34adc5Sramat 65093c34adc5Sramat mutex_init(&vhc->vhc_lock, NULL, MUTEX_DEFAULT, NULL); 65103c34adc5Sramat cv_init(&vhc->vhc_cv, NULL, CV_DRIVER, NULL); 65113c34adc5Sramat 65123c34adc5Sramat rw_init(&vhcache->vhcache_lock, NULL, RW_DRIVER, NULL); 65133c34adc5Sramat 65143c34adc5Sramat /* 65153c34adc5Sramat * Create string hash; same as mod_hash_create_strhash() except that 65163c34adc5Sramat * we use NULL key destructor. 65173c34adc5Sramat */ 65183c34adc5Sramat vhcache->vhcache_client_hash = mod_hash_create_extended(vh->vh_class, 65193c34adc5Sramat mdi_bus_config_cache_hash_size, 65203c34adc5Sramat mod_hash_null_keydtor, mod_hash_null_valdtor, 65213c34adc5Sramat mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 65223c34adc5Sramat 65233c34adc5Sramat /* 65243c34adc5Sramat * The on-disk vhci cache is read during booting prior to the 65253c34adc5Sramat * lights-out period by mdi_read_devices_files(). 65263c34adc5Sramat */ 65273c34adc5Sramat for (i = 0; i < N_VHCI_CLASSES; i++) { 65283c34adc5Sramat if (strcmp(vhci_class_list[i], vh->vh_class) == 0) { 65293c34adc5Sramat nvl = vhcache_nvl[i]; 65303c34adc5Sramat vhcache_nvl[i] = NULL; 65313c34adc5Sramat break; 65323c34adc5Sramat } 65333c34adc5Sramat } 65343c34adc5Sramat 65353c34adc5Sramat /* 65363c34adc5Sramat * this is to cover the case of some one manually causing unloading 65373c34adc5Sramat * (or detaching) and reloading (or attaching) of a vhci driver. 65383c34adc5Sramat */ 65393c34adc5Sramat if (nvl == NULL && modrootloaded) 65403c34adc5Sramat nvl = read_on_disk_vhci_cache(vh->vh_class); 65413c34adc5Sramat 65423c34adc5Sramat if (nvl != NULL) { 65433c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 65443c34adc5Sramat if (mainnvl_to_vhcache(vhcache, nvl) == MDI_SUCCESS) 65453c34adc5Sramat vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE; 65463c34adc5Sramat else { 65473c34adc5Sramat cmn_err(CE_WARN, 65483c34adc5Sramat "%s: data file corrupted, will recreate\n", 65493c34adc5Sramat vhc->vhc_vhcache_filename); 65503c34adc5Sramat } 65513c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 65523c34adc5Sramat nvlist_free(nvl); 65533c34adc5Sramat } 65543c34adc5Sramat 65553c34adc5Sramat vhc->vhc_cbid = callb_add(stop_vhcache_flush_thread, vhc, 65563c34adc5Sramat CB_CL_UADMIN_PRE_VFS, "mdi_vhcache_flush"); 655767e56d35Sramat 655867e56d35Sramat vhc->vhc_path_discovery_boot = mdi_path_discovery_boot; 655967e56d35Sramat vhc->vhc_path_discovery_postboot = mdi_path_discovery_postboot; 65603c34adc5Sramat } 65613c34adc5Sramat 65623c34adc5Sramat /* 65633c34adc5Sramat * free all vhci cache related resources 65643c34adc5Sramat */ 65653c34adc5Sramat static int 65663c34adc5Sramat destroy_vhci_cache(mdi_vhci_t *vh) 65673c34adc5Sramat { 65683c34adc5Sramat mdi_vhci_config_t *vhc = vh->vh_config; 65693c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 65703c34adc5Sramat mdi_vhcache_phci_t *cphci, *cphci_next; 65713c34adc5Sramat mdi_vhcache_client_t *cct, *cct_next; 65723c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_next; 65733c34adc5Sramat 65743c34adc5Sramat if (stop_vhcache_async_threads(vhc) != MDI_SUCCESS) 65753c34adc5Sramat return (MDI_FAILURE); 65763c34adc5Sramat 65773c34adc5Sramat kmem_free(vhc->vhc_vhcache_filename, 65783c34adc5Sramat strlen(vhc->vhc_vhcache_filename) + 1); 65793c34adc5Sramat 65803c34adc5Sramat mod_hash_destroy_strhash(vhcache->vhcache_client_hash); 65813c34adc5Sramat 65823c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 65833c34adc5Sramat cphci = cphci_next) { 65843c34adc5Sramat cphci_next = cphci->cphci_next; 65853c34adc5Sramat free_vhcache_phci(cphci); 65863c34adc5Sramat } 65873c34adc5Sramat 65883c34adc5Sramat for (cct = vhcache->vhcache_client_head; cct != NULL; cct = cct_next) { 65893c34adc5Sramat cct_next = cct->cct_next; 65903c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi_next) { 65913c34adc5Sramat cpi_next = cpi->cpi_next; 65923c34adc5Sramat free_vhcache_pathinfo(cpi); 65933c34adc5Sramat } 65943c34adc5Sramat free_vhcache_client(cct); 65953c34adc5Sramat } 65963c34adc5Sramat 65973c34adc5Sramat rw_destroy(&vhcache->vhcache_lock); 65983c34adc5Sramat 65993c34adc5Sramat mutex_destroy(&vhc->vhc_lock); 66003c34adc5Sramat cv_destroy(&vhc->vhc_cv); 66013c34adc5Sramat kmem_free(vhc, sizeof (mdi_vhci_config_t)); 66023c34adc5Sramat return (MDI_SUCCESS); 66033c34adc5Sramat } 66043c34adc5Sramat 66053c34adc5Sramat /* 66063c34adc5Sramat * Stop all vhci cache related async threads and free their resources. 66073c34adc5Sramat */ 66083c34adc5Sramat static int 66093c34adc5Sramat stop_vhcache_async_threads(mdi_vhci_config_t *vhc) 66103c34adc5Sramat { 66113c34adc5Sramat mdi_async_client_config_t *acc, *acc_next; 66123c34adc5Sramat 66133c34adc5Sramat mutex_enter(&vhc->vhc_lock); 66143c34adc5Sramat vhc->vhc_flags |= MDI_VHC_EXIT; 66153c34adc5Sramat ASSERT(vhc->vhc_acc_thrcount >= 0); 66163c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 66173c34adc5Sramat 66183c34adc5Sramat while ((vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) || 66193c34adc5Sramat vhc->vhc_acc_thrcount != 0) { 66203c34adc5Sramat mutex_exit(&vhc->vhc_lock); 66213c34adc5Sramat delay(1); 66223c34adc5Sramat mutex_enter(&vhc->vhc_lock); 66233c34adc5Sramat } 66243c34adc5Sramat 66253c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_EXIT; 66263c34adc5Sramat 66273c34adc5Sramat for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc_next) { 66283c34adc5Sramat acc_next = acc->acc_next; 66293c34adc5Sramat free_async_client_config(acc); 66303c34adc5Sramat } 66313c34adc5Sramat vhc->vhc_acc_list_head = NULL; 66323c34adc5Sramat vhc->vhc_acc_list_tail = NULL; 66333c34adc5Sramat vhc->vhc_acc_count = 0; 66343c34adc5Sramat 66353c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) { 66363c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 66373c34adc5Sramat mutex_exit(&vhc->vhc_lock); 66383c34adc5Sramat if (flush_vhcache(vhc, 0) != MDI_SUCCESS) { 66393c34adc5Sramat vhcache_dirty(vhc); 66403c34adc5Sramat return (MDI_FAILURE); 66413c34adc5Sramat } 66423c34adc5Sramat } else 66433c34adc5Sramat mutex_exit(&vhc->vhc_lock); 66443c34adc5Sramat 66453c34adc5Sramat if (callb_delete(vhc->vhc_cbid) != 0) 66463c34adc5Sramat return (MDI_FAILURE); 66473c34adc5Sramat 66483c34adc5Sramat return (MDI_SUCCESS); 66493c34adc5Sramat } 66503c34adc5Sramat 66513c34adc5Sramat /* 66523c34adc5Sramat * Stop vhci cache flush thread 66533c34adc5Sramat */ 66543c34adc5Sramat /* ARGSUSED */ 66553c34adc5Sramat static boolean_t 66563c34adc5Sramat stop_vhcache_flush_thread(void *arg, int code) 66573c34adc5Sramat { 66583c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 66593c34adc5Sramat 66603c34adc5Sramat mutex_enter(&vhc->vhc_lock); 66613c34adc5Sramat vhc->vhc_flags |= MDI_VHC_EXIT; 66623c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 66633c34adc5Sramat 66643c34adc5Sramat while (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) { 66653c34adc5Sramat mutex_exit(&vhc->vhc_lock); 66663c34adc5Sramat delay(1); 66673c34adc5Sramat mutex_enter(&vhc->vhc_lock); 66683c34adc5Sramat } 66693c34adc5Sramat 66703c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) { 66713c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 66723c34adc5Sramat mutex_exit(&vhc->vhc_lock); 66733c34adc5Sramat (void) flush_vhcache(vhc, 1); 66743c34adc5Sramat } else 66753c34adc5Sramat mutex_exit(&vhc->vhc_lock); 66763c34adc5Sramat 66773c34adc5Sramat return (B_TRUE); 66783c34adc5Sramat } 66793c34adc5Sramat 66803c34adc5Sramat /* 66813c34adc5Sramat * Enqueue the vhcache phci (cphci) at the tail of the list 66823c34adc5Sramat */ 66833c34adc5Sramat static void 66843c34adc5Sramat enqueue_vhcache_phci(mdi_vhci_cache_t *vhcache, mdi_vhcache_phci_t *cphci) 66853c34adc5Sramat { 66863c34adc5Sramat cphci->cphci_next = NULL; 66873c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) 66883c34adc5Sramat vhcache->vhcache_phci_head = cphci; 66893c34adc5Sramat else 66903c34adc5Sramat vhcache->vhcache_phci_tail->cphci_next = cphci; 66913c34adc5Sramat vhcache->vhcache_phci_tail = cphci; 66923c34adc5Sramat } 66933c34adc5Sramat 66943c34adc5Sramat /* 66953c34adc5Sramat * Enqueue the vhcache pathinfo (cpi) at the tail of the list 66963c34adc5Sramat */ 66973c34adc5Sramat static void 66983c34adc5Sramat enqueue_tail_vhcache_pathinfo(mdi_vhcache_client_t *cct, 66993c34adc5Sramat mdi_vhcache_pathinfo_t *cpi) 67003c34adc5Sramat { 67013c34adc5Sramat cpi->cpi_next = NULL; 67023c34adc5Sramat if (cct->cct_cpi_head == NULL) 67033c34adc5Sramat cct->cct_cpi_head = cpi; 67043c34adc5Sramat else 67053c34adc5Sramat cct->cct_cpi_tail->cpi_next = cpi; 67063c34adc5Sramat cct->cct_cpi_tail = cpi; 67073c34adc5Sramat } 67083c34adc5Sramat 67093c34adc5Sramat /* 67103c34adc5Sramat * Enqueue the vhcache pathinfo (cpi) at the correct location in the 67113c34adc5Sramat * ordered list. All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST 67123c34adc5Sramat * flag set come at the beginning of the list. All cpis which have this 67133c34adc5Sramat * flag set come at the end of the list. 67143c34adc5Sramat */ 67153c34adc5Sramat static void 67163c34adc5Sramat enqueue_vhcache_pathinfo(mdi_vhcache_client_t *cct, 67173c34adc5Sramat mdi_vhcache_pathinfo_t *newcpi) 67183c34adc5Sramat { 67193c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *prev_cpi; 67203c34adc5Sramat 67213c34adc5Sramat if (cct->cct_cpi_head == NULL || 67223c34adc5Sramat (newcpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST)) 67233c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, newcpi); 67243c34adc5Sramat else { 67253c34adc5Sramat for (cpi = cct->cct_cpi_head, prev_cpi = NULL; cpi != NULL && 67263c34adc5Sramat !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST); 67273c34adc5Sramat prev_cpi = cpi, cpi = cpi->cpi_next) 67283c34adc5Sramat ; 67293c34adc5Sramat 67303c34adc5Sramat if (prev_cpi == NULL) 67313c34adc5Sramat cct->cct_cpi_head = newcpi; 67323c34adc5Sramat else 67333c34adc5Sramat prev_cpi->cpi_next = newcpi; 67343c34adc5Sramat 67353c34adc5Sramat newcpi->cpi_next = cpi; 67363c34adc5Sramat 67373c34adc5Sramat if (cpi == NULL) 67383c34adc5Sramat cct->cct_cpi_tail = newcpi; 67393c34adc5Sramat } 67403c34adc5Sramat } 67413c34adc5Sramat 67423c34adc5Sramat /* 67433c34adc5Sramat * Enqueue the vhcache client (cct) at the tail of the list 67443c34adc5Sramat */ 67453c34adc5Sramat static void 67463c34adc5Sramat enqueue_vhcache_client(mdi_vhci_cache_t *vhcache, 67473c34adc5Sramat mdi_vhcache_client_t *cct) 67483c34adc5Sramat { 67493c34adc5Sramat cct->cct_next = NULL; 67503c34adc5Sramat if (vhcache->vhcache_client_head == NULL) 67513c34adc5Sramat vhcache->vhcache_client_head = cct; 67523c34adc5Sramat else 67533c34adc5Sramat vhcache->vhcache_client_tail->cct_next = cct; 67543c34adc5Sramat vhcache->vhcache_client_tail = cct; 67553c34adc5Sramat } 67563c34adc5Sramat 67573c34adc5Sramat static void 67583c34adc5Sramat free_string_array(char **str, int nelem) 67593c34adc5Sramat { 67603c34adc5Sramat int i; 67613c34adc5Sramat 67623c34adc5Sramat if (str) { 67633c34adc5Sramat for (i = 0; i < nelem; i++) { 67643c34adc5Sramat if (str[i]) 67653c34adc5Sramat kmem_free(str[i], strlen(str[i]) + 1); 67663c34adc5Sramat } 67673c34adc5Sramat kmem_free(str, sizeof (char *) * nelem); 67683c34adc5Sramat } 67693c34adc5Sramat } 67703c34adc5Sramat 67713c34adc5Sramat static void 67723c34adc5Sramat free_vhcache_phci(mdi_vhcache_phci_t *cphci) 67733c34adc5Sramat { 67743c34adc5Sramat kmem_free(cphci->cphci_path, strlen(cphci->cphci_path) + 1); 67753c34adc5Sramat kmem_free(cphci, sizeof (*cphci)); 67763c34adc5Sramat } 67773c34adc5Sramat 67783c34adc5Sramat static void 67793c34adc5Sramat free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *cpi) 67803c34adc5Sramat { 67813c34adc5Sramat kmem_free(cpi->cpi_addr, strlen(cpi->cpi_addr) + 1); 67823c34adc5Sramat kmem_free(cpi, sizeof (*cpi)); 67833c34adc5Sramat } 67843c34adc5Sramat 67853c34adc5Sramat static void 67863c34adc5Sramat free_vhcache_client(mdi_vhcache_client_t *cct) 67873c34adc5Sramat { 67883c34adc5Sramat kmem_free(cct->cct_name_addr, strlen(cct->cct_name_addr) + 1); 67893c34adc5Sramat kmem_free(cct, sizeof (*cct)); 67903c34adc5Sramat } 67913c34adc5Sramat 67923c34adc5Sramat static char * 67933c34adc5Sramat vhcache_mknameaddr(char *ct_name, char *ct_addr, int *ret_len) 67943c34adc5Sramat { 67953c34adc5Sramat char *name_addr; 67963c34adc5Sramat int len; 67973c34adc5Sramat 67983c34adc5Sramat len = strlen(ct_name) + strlen(ct_addr) + 2; 67993c34adc5Sramat name_addr = kmem_alloc(len, KM_SLEEP); 68003c34adc5Sramat (void) snprintf(name_addr, len, "%s@%s", ct_name, ct_addr); 68013c34adc5Sramat 68023c34adc5Sramat if (ret_len) 68033c34adc5Sramat *ret_len = len; 68043c34adc5Sramat return (name_addr); 68053c34adc5Sramat } 68063c34adc5Sramat 68073c34adc5Sramat /* 68083c34adc5Sramat * Copy the contents of paddrnvl to vhci cache. 68093c34adc5Sramat * paddrnvl nvlist contains path information for a vhci client. 68103c34adc5Sramat * See the comment in mainnvl_to_vhcache() for the format of this nvlist. 68113c34adc5Sramat */ 68123c34adc5Sramat static void 68133c34adc5Sramat paddrnvl_to_vhcache(nvlist_t *nvl, mdi_vhcache_phci_t *cphci_list[], 68143c34adc5Sramat mdi_vhcache_client_t *cct) 68153c34adc5Sramat { 68163c34adc5Sramat nvpair_t *nvp = NULL; 68173c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 68183c34adc5Sramat uint_t nelem; 68193c34adc5Sramat uint32_t *val; 68203c34adc5Sramat 68213c34adc5Sramat while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 68223c34adc5Sramat ASSERT(nvpair_type(nvp) == DATA_TYPE_UINT32_ARRAY); 68233c34adc5Sramat cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP); 68243c34adc5Sramat cpi->cpi_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP); 68253c34adc5Sramat (void) nvpair_value_uint32_array(nvp, &val, &nelem); 68263c34adc5Sramat ASSERT(nelem == 2); 68273c34adc5Sramat cpi->cpi_cphci = cphci_list[val[0]]; 68283c34adc5Sramat cpi->cpi_flags = val[1]; 68293c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, cpi); 68303c34adc5Sramat } 68313c34adc5Sramat } 68323c34adc5Sramat 68333c34adc5Sramat /* 68343c34adc5Sramat * Copy the contents of caddrmapnvl to vhci cache. 68353c34adc5Sramat * caddrmapnvl nvlist contains vhci client address to phci client address 68363c34adc5Sramat * mappings. See the comment in mainnvl_to_vhcache() for the format of 68373c34adc5Sramat * this nvlist. 68383c34adc5Sramat */ 68393c34adc5Sramat static void 68403c34adc5Sramat caddrmapnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl, 68413c34adc5Sramat mdi_vhcache_phci_t *cphci_list[]) 68423c34adc5Sramat { 68433c34adc5Sramat nvpair_t *nvp = NULL; 68443c34adc5Sramat nvlist_t *paddrnvl; 68453c34adc5Sramat mdi_vhcache_client_t *cct; 68463c34adc5Sramat 68473c34adc5Sramat while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 68483c34adc5Sramat ASSERT(nvpair_type(nvp) == DATA_TYPE_NVLIST); 68493c34adc5Sramat cct = kmem_zalloc(sizeof (*cct), KM_SLEEP); 68503c34adc5Sramat cct->cct_name_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP); 68513c34adc5Sramat (void) nvpair_value_nvlist(nvp, &paddrnvl); 68523c34adc5Sramat paddrnvl_to_vhcache(paddrnvl, cphci_list, cct); 68533c34adc5Sramat /* the client must contain at least one path */ 68543c34adc5Sramat ASSERT(cct->cct_cpi_head != NULL); 68553c34adc5Sramat 68563c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 68573c34adc5Sramat (void) mod_hash_insert(vhcache->vhcache_client_hash, 68583c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct); 68593c34adc5Sramat } 68603c34adc5Sramat } 68613c34adc5Sramat 68623c34adc5Sramat /* 68633c34adc5Sramat * Copy the contents of the main nvlist to vhci cache. 68643c34adc5Sramat * 68653c34adc5Sramat * VHCI busconfig cached data is stored in the form of a nvlist on the disk. 68663c34adc5Sramat * The nvlist contains the mappings between the vhci client addresses and 68673c34adc5Sramat * their corresponding phci client addresses. 68683c34adc5Sramat * 68693c34adc5Sramat * The structure of the nvlist is as follows: 68703c34adc5Sramat * 68713c34adc5Sramat * Main nvlist: 68723c34adc5Sramat * NAME TYPE DATA 68733c34adc5Sramat * version int32 version number 68743c34adc5Sramat * phcis string array array of phci paths 68753c34adc5Sramat * clientaddrmap nvlist_t c2paddrs_nvl (see below) 68763c34adc5Sramat * 68773c34adc5Sramat * structure of c2paddrs_nvl: 68783c34adc5Sramat * NAME TYPE DATA 68793c34adc5Sramat * caddr1 nvlist_t paddrs_nvl1 68803c34adc5Sramat * caddr2 nvlist_t paddrs_nvl2 68813c34adc5Sramat * ... 68823c34adc5Sramat * where caddr1, caddr2, ... are vhci client name and addresses in the 68833c34adc5Sramat * form of "<clientname>@<clientaddress>". 68843c34adc5Sramat * (for example: "ssd@2000002037cd9f72"); 68853c34adc5Sramat * paddrs_nvl1, paddrs_nvl2, .. are nvlists that contain path information. 68863c34adc5Sramat * 68873c34adc5Sramat * structure of paddrs_nvl: 68883c34adc5Sramat * NAME TYPE DATA 68893c34adc5Sramat * pi_addr1 uint32_array (phci-id, cpi_flags) 68903c34adc5Sramat * pi_addr2 uint32_array (phci-id, cpi_flags) 68913c34adc5Sramat * ... 68923c34adc5Sramat * where pi_addr1, pi_addr2, ... are bus specific addresses of pathinfo nodes 68933c34adc5Sramat * (so called pi_addrs, for example: "w2100002037cd9f72,0"); 68943c34adc5Sramat * phci-ids are integers that identify PHCIs to which the 68953c34adc5Sramat * the bus specific address belongs to. These integers are used as an index 68963c34adc5Sramat * into to the phcis string array in the main nvlist to get the PHCI path. 68973c34adc5Sramat */ 68983c34adc5Sramat static int 68993c34adc5Sramat mainnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl) 69003c34adc5Sramat { 69013c34adc5Sramat char **phcis, **phci_namep; 69023c34adc5Sramat uint_t nphcis; 69033c34adc5Sramat mdi_vhcache_phci_t *cphci, **cphci_list; 69043c34adc5Sramat nvlist_t *caddrmapnvl; 69053c34adc5Sramat int32_t ver; 69063c34adc5Sramat int i; 69073c34adc5Sramat size_t cphci_list_size; 69083c34adc5Sramat 69093c34adc5Sramat ASSERT(RW_WRITE_HELD(&vhcache->vhcache_lock)); 69103c34adc5Sramat 69113c34adc5Sramat if (nvlist_lookup_int32(nvl, MDI_NVPNAME_VERSION, &ver) != 0 || 69123c34adc5Sramat ver != MDI_VHCI_CACHE_VERSION) 69133c34adc5Sramat return (MDI_FAILURE); 69143c34adc5Sramat 69153c34adc5Sramat if (nvlist_lookup_string_array(nvl, MDI_NVPNAME_PHCIS, &phcis, 69163c34adc5Sramat &nphcis) != 0) 69173c34adc5Sramat return (MDI_SUCCESS); 69183c34adc5Sramat 69193c34adc5Sramat ASSERT(nphcis > 0); 69203c34adc5Sramat 69213c34adc5Sramat cphci_list_size = sizeof (mdi_vhcache_phci_t *) * nphcis; 69223c34adc5Sramat cphci_list = kmem_alloc(cphci_list_size, KM_SLEEP); 69233c34adc5Sramat for (i = 0, phci_namep = phcis; i < nphcis; i++, phci_namep++) { 69243c34adc5Sramat cphci = kmem_zalloc(sizeof (mdi_vhcache_phci_t), KM_SLEEP); 69253c34adc5Sramat cphci->cphci_path = i_ddi_strdup(*phci_namep, KM_SLEEP); 69263c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 69273c34adc5Sramat cphci_list[i] = cphci; 69283c34adc5Sramat } 69293c34adc5Sramat 69303c34adc5Sramat ASSERT(vhcache->vhcache_phci_head != NULL); 69313c34adc5Sramat 69323c34adc5Sramat if (nvlist_lookup_nvlist(nvl, MDI_NVPNAME_CTADDRMAP, &caddrmapnvl) == 0) 69333c34adc5Sramat caddrmapnvl_to_vhcache(vhcache, caddrmapnvl, cphci_list); 69343c34adc5Sramat 69353c34adc5Sramat kmem_free(cphci_list, cphci_list_size); 69363c34adc5Sramat return (MDI_SUCCESS); 69373c34adc5Sramat } 69383c34adc5Sramat 69393c34adc5Sramat /* 69403c34adc5Sramat * Build paddrnvl for the specified client using the information in the 69413c34adc5Sramat * vhci cache and add it to the caddrmapnnvl. 69423c34adc5Sramat * Returns 0 on success, errno on failure. 69433c34adc5Sramat */ 69443c34adc5Sramat static int 69453c34adc5Sramat vhcache_to_paddrnvl(mdi_vhci_cache_t *vhcache, mdi_vhcache_client_t *cct, 69463c34adc5Sramat nvlist_t *caddrmapnvl) 69473c34adc5Sramat { 69483c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 69493c34adc5Sramat nvlist_t *nvl; 69503c34adc5Sramat int err; 69513c34adc5Sramat uint32_t val[2]; 69523c34adc5Sramat 69533c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 69543c34adc5Sramat 69553c34adc5Sramat if ((err = nvlist_alloc(&nvl, 0, KM_SLEEP)) != 0) 69563c34adc5Sramat return (err); 69573c34adc5Sramat 69583c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 69593c34adc5Sramat val[0] = cpi->cpi_cphci->cphci_id; 69603c34adc5Sramat val[1] = cpi->cpi_flags; 69613c34adc5Sramat if ((err = nvlist_add_uint32_array(nvl, cpi->cpi_addr, val, 2)) 69623c34adc5Sramat != 0) 69633c34adc5Sramat goto out; 69643c34adc5Sramat } 69653c34adc5Sramat 69663c34adc5Sramat err = nvlist_add_nvlist(caddrmapnvl, cct->cct_name_addr, nvl); 69673c34adc5Sramat out: 69683c34adc5Sramat nvlist_free(nvl); 69693c34adc5Sramat return (err); 69703c34adc5Sramat } 69713c34adc5Sramat 69723c34adc5Sramat /* 69733c34adc5Sramat * Build caddrmapnvl using the information in the vhci cache 69743c34adc5Sramat * and add it to the mainnvl. 69753c34adc5Sramat * Returns 0 on success, errno on failure. 69763c34adc5Sramat */ 69773c34adc5Sramat static int 69783c34adc5Sramat vhcache_to_caddrmapnvl(mdi_vhci_cache_t *vhcache, nvlist_t *mainnvl) 69793c34adc5Sramat { 69803c34adc5Sramat mdi_vhcache_client_t *cct; 69813c34adc5Sramat nvlist_t *nvl; 69823c34adc5Sramat int err; 69833c34adc5Sramat 69843c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 69853c34adc5Sramat 69863c34adc5Sramat if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0) 69873c34adc5Sramat return (err); 69883c34adc5Sramat 69893c34adc5Sramat for (cct = vhcache->vhcache_client_head; cct != NULL; 69903c34adc5Sramat cct = cct->cct_next) { 69913c34adc5Sramat if ((err = vhcache_to_paddrnvl(vhcache, cct, nvl)) != 0) 69923c34adc5Sramat goto out; 69933c34adc5Sramat } 69943c34adc5Sramat 69953c34adc5Sramat err = nvlist_add_nvlist(mainnvl, MDI_NVPNAME_CTADDRMAP, nvl); 69963c34adc5Sramat out: 69973c34adc5Sramat nvlist_free(nvl); 69983c34adc5Sramat return (err); 69993c34adc5Sramat } 70003c34adc5Sramat 70013c34adc5Sramat /* 70023c34adc5Sramat * Build nvlist using the information in the vhci cache. 70033c34adc5Sramat * See the comment in mainnvl_to_vhcache() for the format of the nvlist. 70043c34adc5Sramat * Returns nvl on success, NULL on failure. 70053c34adc5Sramat */ 70063c34adc5Sramat static nvlist_t * 70073c34adc5Sramat vhcache_to_mainnvl(mdi_vhci_cache_t *vhcache) 70083c34adc5Sramat { 70093c34adc5Sramat mdi_vhcache_phci_t *cphci; 70103c34adc5Sramat uint_t phci_count; 70113c34adc5Sramat char **phcis; 70123c34adc5Sramat nvlist_t *nvl; 70133c34adc5Sramat int err, i; 70143c34adc5Sramat 70153c34adc5Sramat if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0) { 70163c34adc5Sramat nvl = NULL; 70173c34adc5Sramat goto out; 70183c34adc5Sramat } 70193c34adc5Sramat 70203c34adc5Sramat if ((err = nvlist_add_int32(nvl, MDI_NVPNAME_VERSION, 70213c34adc5Sramat MDI_VHCI_CACHE_VERSION)) != 0) 70223c34adc5Sramat goto out; 70233c34adc5Sramat 70243c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 70253c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) { 70263c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 70273c34adc5Sramat return (nvl); 70283c34adc5Sramat } 70293c34adc5Sramat 70303c34adc5Sramat phci_count = 0; 70313c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 70323c34adc5Sramat cphci = cphci->cphci_next) 70333c34adc5Sramat cphci->cphci_id = phci_count++; 70343c34adc5Sramat 70353c34adc5Sramat /* build phci pathname list */ 70363c34adc5Sramat phcis = kmem_alloc(sizeof (char *) * phci_count, KM_SLEEP); 70373c34adc5Sramat for (cphci = vhcache->vhcache_phci_head, i = 0; cphci != NULL; 70383c34adc5Sramat cphci = cphci->cphci_next, i++) 70393c34adc5Sramat phcis[i] = i_ddi_strdup(cphci->cphci_path, KM_SLEEP); 70403c34adc5Sramat 70413c34adc5Sramat err = nvlist_add_string_array(nvl, MDI_NVPNAME_PHCIS, phcis, 70423c34adc5Sramat phci_count); 70433c34adc5Sramat free_string_array(phcis, phci_count); 70443c34adc5Sramat 70453c34adc5Sramat if (err == 0 && 70463c34adc5Sramat (err = vhcache_to_caddrmapnvl(vhcache, nvl)) == 0) { 70473c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 70483c34adc5Sramat return (nvl); 70493c34adc5Sramat } 70503c34adc5Sramat 70513c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 70523c34adc5Sramat out: 70533c34adc5Sramat if (nvl) 70543c34adc5Sramat nvlist_free(nvl); 70553c34adc5Sramat return (NULL); 70563c34adc5Sramat } 70573c34adc5Sramat 70583c34adc5Sramat /* 70593c34adc5Sramat * Lookup vhcache phci structure for the specified phci path. 70603c34adc5Sramat */ 70613c34adc5Sramat static mdi_vhcache_phci_t * 70623c34adc5Sramat lookup_vhcache_phci_by_name(mdi_vhci_cache_t *vhcache, char *phci_path) 70633c34adc5Sramat { 70643c34adc5Sramat mdi_vhcache_phci_t *cphci; 70653c34adc5Sramat 70663c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 70673c34adc5Sramat 70683c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 70693c34adc5Sramat cphci = cphci->cphci_next) { 70703c34adc5Sramat if (strcmp(cphci->cphci_path, phci_path) == 0) 70713c34adc5Sramat return (cphci); 70723c34adc5Sramat } 70733c34adc5Sramat 70743c34adc5Sramat return (NULL); 70753c34adc5Sramat } 70763c34adc5Sramat 70773c34adc5Sramat /* 70783c34adc5Sramat * Lookup vhcache phci structure for the specified phci. 70793c34adc5Sramat */ 70803c34adc5Sramat static mdi_vhcache_phci_t * 70813c34adc5Sramat lookup_vhcache_phci_by_addr(mdi_vhci_cache_t *vhcache, mdi_phci_t *ph) 70823c34adc5Sramat { 70833c34adc5Sramat mdi_vhcache_phci_t *cphci; 70843c34adc5Sramat 70853c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 70863c34adc5Sramat 70873c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 70883c34adc5Sramat cphci = cphci->cphci_next) { 70893c34adc5Sramat if (cphci->cphci_phci == ph) 70903c34adc5Sramat return (cphci); 70913c34adc5Sramat } 70923c34adc5Sramat 70933c34adc5Sramat return (NULL); 70943c34adc5Sramat } 70953c34adc5Sramat 70963c34adc5Sramat /* 70973c34adc5Sramat * Add the specified phci to the vhci cache if not already present. 70983c34adc5Sramat */ 70993c34adc5Sramat static void 71003c34adc5Sramat vhcache_phci_add(mdi_vhci_config_t *vhc, mdi_phci_t *ph) 71013c34adc5Sramat { 71023c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 71033c34adc5Sramat mdi_vhcache_phci_t *cphci; 71043c34adc5Sramat char *pathname; 71053c34adc5Sramat int cache_updated; 71063c34adc5Sramat 71073c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 71083c34adc5Sramat 71093c34adc5Sramat pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 71103c34adc5Sramat (void) ddi_pathname(ph->ph_dip, pathname); 71113c34adc5Sramat if ((cphci = lookup_vhcache_phci_by_name(vhcache, pathname)) 71123c34adc5Sramat != NULL) { 71133c34adc5Sramat cphci->cphci_phci = ph; 71143c34adc5Sramat cache_updated = 0; 71153c34adc5Sramat } else { 71163c34adc5Sramat cphci = kmem_zalloc(sizeof (*cphci), KM_SLEEP); 71173c34adc5Sramat cphci->cphci_path = i_ddi_strdup(pathname, KM_SLEEP); 71183c34adc5Sramat cphci->cphci_phci = ph; 71193c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 71203c34adc5Sramat cache_updated = 1; 71213c34adc5Sramat } 712267e56d35Sramat 71233c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 71243c34adc5Sramat 712567e56d35Sramat /* 712667e56d35Sramat * Since a new phci has been added, reset 712767e56d35Sramat * vhc_path_discovery_cutoff_time to allow for discovery of paths 712867e56d35Sramat * during next vhcache_discover_paths(). 712967e56d35Sramat */ 713067e56d35Sramat mutex_enter(&vhc->vhc_lock); 713167e56d35Sramat vhc->vhc_path_discovery_cutoff_time = 0; 713267e56d35Sramat mutex_exit(&vhc->vhc_lock); 713367e56d35Sramat 71343c34adc5Sramat kmem_free(pathname, MAXPATHLEN); 71353c34adc5Sramat if (cache_updated) 71363c34adc5Sramat vhcache_dirty(vhc); 71373c34adc5Sramat } 71383c34adc5Sramat 71393c34adc5Sramat /* 71403c34adc5Sramat * Remove the reference to the specified phci from the vhci cache. 71413c34adc5Sramat */ 71423c34adc5Sramat static void 71433c34adc5Sramat vhcache_phci_remove(mdi_vhci_config_t *vhc, mdi_phci_t *ph) 71443c34adc5Sramat { 71453c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 71463c34adc5Sramat mdi_vhcache_phci_t *cphci; 71473c34adc5Sramat 71483c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 71493c34adc5Sramat if ((cphci = lookup_vhcache_phci_by_addr(vhcache, ph)) != NULL) { 71503c34adc5Sramat /* do not remove the actual mdi_vhcache_phci structure */ 71513c34adc5Sramat cphci->cphci_phci = NULL; 71523c34adc5Sramat } 71533c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 71543c34adc5Sramat } 71553c34adc5Sramat 71563c34adc5Sramat static void 71573c34adc5Sramat init_vhcache_lookup_token(mdi_vhcache_lookup_token_t *dst, 71583c34adc5Sramat mdi_vhcache_lookup_token_t *src) 71593c34adc5Sramat { 71603c34adc5Sramat if (src == NULL) { 71613c34adc5Sramat dst->lt_cct = NULL; 71623c34adc5Sramat dst->lt_cct_lookup_time = 0; 71633c34adc5Sramat } else { 71643c34adc5Sramat dst->lt_cct = src->lt_cct; 71653c34adc5Sramat dst->lt_cct_lookup_time = src->lt_cct_lookup_time; 71663c34adc5Sramat } 71673c34adc5Sramat } 71683c34adc5Sramat 71693c34adc5Sramat /* 71703c34adc5Sramat * Look up vhcache client for the specified client. 71713c34adc5Sramat */ 71723c34adc5Sramat static mdi_vhcache_client_t * 71733c34adc5Sramat lookup_vhcache_client(mdi_vhci_cache_t *vhcache, char *ct_name, char *ct_addr, 71743c34adc5Sramat mdi_vhcache_lookup_token_t *token) 71753c34adc5Sramat { 71763c34adc5Sramat mod_hash_val_t hv; 71773c34adc5Sramat char *name_addr; 71783c34adc5Sramat int len; 71793c34adc5Sramat 71803c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 71813c34adc5Sramat 71823c34adc5Sramat /* 71833c34adc5Sramat * If no vhcache clean occurred since the last lookup, we can 71843c34adc5Sramat * simply return the cct from the last lookup operation. 71853c34adc5Sramat * It works because ccts are never freed except during the vhcache 71863c34adc5Sramat * cleanup operation. 71873c34adc5Sramat */ 71883c34adc5Sramat if (token != NULL && 71893c34adc5Sramat vhcache->vhcache_clean_time < token->lt_cct_lookup_time) 71903c34adc5Sramat return (token->lt_cct); 71913c34adc5Sramat 71923c34adc5Sramat name_addr = vhcache_mknameaddr(ct_name, ct_addr, &len); 71933c34adc5Sramat if (mod_hash_find(vhcache->vhcache_client_hash, 71943c34adc5Sramat (mod_hash_key_t)name_addr, &hv) == 0) { 71953c34adc5Sramat if (token) { 71963c34adc5Sramat token->lt_cct = (mdi_vhcache_client_t *)hv; 71973c34adc5Sramat token->lt_cct_lookup_time = lbolt64; 71983c34adc5Sramat } 71993c34adc5Sramat } else { 72003c34adc5Sramat if (token) { 72013c34adc5Sramat token->lt_cct = NULL; 72023c34adc5Sramat token->lt_cct_lookup_time = 0; 72033c34adc5Sramat } 72043c34adc5Sramat hv = NULL; 72053c34adc5Sramat } 72063c34adc5Sramat kmem_free(name_addr, len); 72073c34adc5Sramat return ((mdi_vhcache_client_t *)hv); 72083c34adc5Sramat } 72093c34adc5Sramat 72103c34adc5Sramat /* 72113c34adc5Sramat * Add the specified path to the vhci cache if not already present. 72123c34adc5Sramat * Also add the vhcache client for the client corresponding to this path 72133c34adc5Sramat * if it doesn't already exist. 72143c34adc5Sramat */ 72153c34adc5Sramat static void 72163c34adc5Sramat vhcache_pi_add(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip) 72173c34adc5Sramat { 72183c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 72193c34adc5Sramat mdi_vhcache_client_t *cct; 72203c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 72213c34adc5Sramat mdi_phci_t *ph = pip->pi_phci; 72223c34adc5Sramat mdi_client_t *ct = pip->pi_client; 72233c34adc5Sramat int cache_updated = 0; 72243c34adc5Sramat 72253c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 72263c34adc5Sramat 72273c34adc5Sramat /* if vhcache client for this pip doesn't already exist, add it */ 72283c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid, 72293c34adc5Sramat NULL)) == NULL) { 72303c34adc5Sramat cct = kmem_zalloc(sizeof (*cct), KM_SLEEP); 72313c34adc5Sramat cct->cct_name_addr = vhcache_mknameaddr(ct->ct_drvname, 72323c34adc5Sramat ct->ct_guid, NULL); 72333c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 72343c34adc5Sramat (void) mod_hash_insert(vhcache->vhcache_client_hash, 72353c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct); 72363c34adc5Sramat cache_updated = 1; 72373c34adc5Sramat } 72383c34adc5Sramat 72393c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 72403c34adc5Sramat if (cpi->cpi_cphci->cphci_phci == ph && 72413c34adc5Sramat strcmp(cpi->cpi_addr, pip->pi_addr) == 0) { 72423c34adc5Sramat cpi->cpi_pip = pip; 72433c34adc5Sramat if (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST) { 72443c34adc5Sramat cpi->cpi_flags &= 72453c34adc5Sramat ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 72463c34adc5Sramat sort_vhcache_paths(cct); 72473c34adc5Sramat cache_updated = 1; 72483c34adc5Sramat } 72493c34adc5Sramat break; 72503c34adc5Sramat } 72513c34adc5Sramat } 72523c34adc5Sramat 72533c34adc5Sramat if (cpi == NULL) { 72543c34adc5Sramat cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP); 72553c34adc5Sramat cpi->cpi_addr = i_ddi_strdup(pip->pi_addr, KM_SLEEP); 72563c34adc5Sramat cpi->cpi_cphci = lookup_vhcache_phci_by_addr(vhcache, ph); 72573c34adc5Sramat ASSERT(cpi->cpi_cphci != NULL); 72583c34adc5Sramat cpi->cpi_pip = pip; 72593c34adc5Sramat enqueue_vhcache_pathinfo(cct, cpi); 72603c34adc5Sramat cache_updated = 1; 72613c34adc5Sramat } 72623c34adc5Sramat 72633c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 72643c34adc5Sramat 72653c34adc5Sramat if (cache_updated) 72663c34adc5Sramat vhcache_dirty(vhc); 72673c34adc5Sramat } 72683c34adc5Sramat 72693c34adc5Sramat /* 72703c34adc5Sramat * Remove the reference to the specified path from the vhci cache. 72713c34adc5Sramat */ 72723c34adc5Sramat static void 72733c34adc5Sramat vhcache_pi_remove(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip) 72743c34adc5Sramat { 72753c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 72763c34adc5Sramat mdi_client_t *ct = pip->pi_client; 72773c34adc5Sramat mdi_vhcache_client_t *cct; 72783c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 72793c34adc5Sramat 72803c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 72813c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid, 72823c34adc5Sramat NULL)) != NULL) { 72833c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; 72843c34adc5Sramat cpi = cpi->cpi_next) { 72853c34adc5Sramat if (cpi->cpi_pip == pip) { 72863c34adc5Sramat cpi->cpi_pip = NULL; 72873c34adc5Sramat break; 72883c34adc5Sramat } 72893c34adc5Sramat } 72903c34adc5Sramat } 72913c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 72923c34adc5Sramat } 72933c34adc5Sramat 72943c34adc5Sramat /* 72953c34adc5Sramat * Flush the vhci cache to disk. 72963c34adc5Sramat * Returns MDI_SUCCESS on success, MDI_FAILURE on failure. 72973c34adc5Sramat */ 72983c34adc5Sramat static int 72993c34adc5Sramat flush_vhcache(mdi_vhci_config_t *vhc, int force_flag) 73003c34adc5Sramat { 73013c34adc5Sramat nvlist_t *nvl; 73023c34adc5Sramat int err; 73033c34adc5Sramat int rv; 73043c34adc5Sramat 73053c34adc5Sramat /* 73063c34adc5Sramat * It is possible that the system may shutdown before 73073c34adc5Sramat * i_ddi_io_initialized (during stmsboot for example). To allow for 73083c34adc5Sramat * flushing the cache in this case do not check for 73093c34adc5Sramat * i_ddi_io_initialized when force flag is set. 73103c34adc5Sramat */ 73113c34adc5Sramat if (force_flag == 0 && !i_ddi_io_initialized()) 73123c34adc5Sramat return (MDI_FAILURE); 73133c34adc5Sramat 73143c34adc5Sramat if ((nvl = vhcache_to_mainnvl(&vhc->vhc_vhcache)) != NULL) { 73153c34adc5Sramat err = fwrite_nvlist(vhc->vhc_vhcache_filename, nvl); 73163c34adc5Sramat nvlist_free(nvl); 73173c34adc5Sramat } else 73183c34adc5Sramat err = EFAULT; 73193c34adc5Sramat 73203c34adc5Sramat rv = MDI_SUCCESS; 73213c34adc5Sramat mutex_enter(&vhc->vhc_lock); 73223c34adc5Sramat if (err != 0) { 73233c34adc5Sramat if (err == EROFS) { 73243c34adc5Sramat vhc->vhc_flags |= MDI_VHC_READONLY_FS; 73253c34adc5Sramat vhc->vhc_flags &= ~(MDI_VHC_VHCACHE_FLUSH_ERROR | 73263c34adc5Sramat MDI_VHC_VHCACHE_DIRTY); 73273c34adc5Sramat } else { 73283c34adc5Sramat if (!(vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR)) { 73293c34adc5Sramat cmn_err(CE_CONT, "%s: update failed\n", 73303c34adc5Sramat vhc->vhc_vhcache_filename); 73313c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_ERROR; 73323c34adc5Sramat } 73333c34adc5Sramat rv = MDI_FAILURE; 73343c34adc5Sramat } 73353c34adc5Sramat } else if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR) { 73363c34adc5Sramat cmn_err(CE_CONT, 73373c34adc5Sramat "%s: update now ok\n", vhc->vhc_vhcache_filename); 73383c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_ERROR; 73393c34adc5Sramat } 73403c34adc5Sramat mutex_exit(&vhc->vhc_lock); 73413c34adc5Sramat 73423c34adc5Sramat return (rv); 73433c34adc5Sramat } 73443c34adc5Sramat 73453c34adc5Sramat /* 73463c34adc5Sramat * Call flush_vhcache() to flush the vhci cache at the scheduled time. 73473c34adc5Sramat * Exits itself if left idle for the idle timeout period. 73483c34adc5Sramat */ 73493c34adc5Sramat static void 73503c34adc5Sramat vhcache_flush_thread(void *arg) 73513c34adc5Sramat { 73523c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 73533c34adc5Sramat clock_t idle_time, quit_at_ticks; 73543c34adc5Sramat callb_cpr_t cprinfo; 73553c34adc5Sramat 73563c34adc5Sramat /* number of seconds to sleep idle before exiting */ 73573c34adc5Sramat idle_time = mdi_vhcache_flush_daemon_idle_time * TICKS_PER_SECOND; 73583c34adc5Sramat 73593c34adc5Sramat CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr, 73603c34adc5Sramat "mdi_vhcache_flush"); 73613c34adc5Sramat mutex_enter(&vhc->vhc_lock); 73623c34adc5Sramat for (; ; ) { 73633c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 73643c34adc5Sramat (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY)) { 73653c34adc5Sramat if (ddi_get_lbolt() < vhc->vhc_flush_at_ticks) { 73663c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 73673c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, 73683c34adc5Sramat &vhc->vhc_lock, vhc->vhc_flush_at_ticks); 73693c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 73703c34adc5Sramat } else { 73713c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 73723c34adc5Sramat mutex_exit(&vhc->vhc_lock); 73733c34adc5Sramat 73743c34adc5Sramat if (flush_vhcache(vhc, 0) != MDI_SUCCESS) 73753c34adc5Sramat vhcache_dirty(vhc); 73763c34adc5Sramat 73773c34adc5Sramat mutex_enter(&vhc->vhc_lock); 73783c34adc5Sramat } 73793c34adc5Sramat } 73803c34adc5Sramat 73813c34adc5Sramat quit_at_ticks = ddi_get_lbolt() + idle_time; 73823c34adc5Sramat 73833c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 73843c34adc5Sramat !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) && 73853c34adc5Sramat ddi_get_lbolt() < quit_at_ticks) { 73863c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 73873c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock, 73883c34adc5Sramat quit_at_ticks); 73893c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 73903c34adc5Sramat } 73913c34adc5Sramat 73923c34adc5Sramat if ((vhc->vhc_flags & MDI_VHC_EXIT) || 73933c34adc5Sramat !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY)) 73943c34adc5Sramat goto out; 73953c34adc5Sramat } 73963c34adc5Sramat 73973c34adc5Sramat out: 73983c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_THREAD; 73993c34adc5Sramat /* CALLB_CPR_EXIT releases the vhc->vhc_lock */ 74003c34adc5Sramat CALLB_CPR_EXIT(&cprinfo); 74013c34adc5Sramat } 74023c34adc5Sramat 74033c34adc5Sramat /* 74043c34adc5Sramat * Make vhci cache dirty and schedule flushing by vhcache flush thread. 74053c34adc5Sramat */ 74063c34adc5Sramat static void 74073c34adc5Sramat vhcache_dirty(mdi_vhci_config_t *vhc) 74083c34adc5Sramat { 74093c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 74103c34adc5Sramat int create_thread; 74113c34adc5Sramat 74123c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 74133c34adc5Sramat /* do not flush cache until the cache is fully built */ 74143c34adc5Sramat if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) { 74153c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 74163c34adc5Sramat return; 74173c34adc5Sramat } 74183c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 74193c34adc5Sramat 74203c34adc5Sramat mutex_enter(&vhc->vhc_lock); 74213c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_READONLY_FS) { 74223c34adc5Sramat mutex_exit(&vhc->vhc_lock); 74233c34adc5Sramat return; 74243c34adc5Sramat } 74253c34adc5Sramat 74263c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_DIRTY; 74273c34adc5Sramat vhc->vhc_flush_at_ticks = ddi_get_lbolt() + 74283c34adc5Sramat mdi_vhcache_flush_delay * TICKS_PER_SECOND; 74293c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) { 74303c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 74313c34adc5Sramat create_thread = 0; 74323c34adc5Sramat } else { 74333c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_THREAD; 74343c34adc5Sramat create_thread = 1; 74353c34adc5Sramat } 74363c34adc5Sramat mutex_exit(&vhc->vhc_lock); 74373c34adc5Sramat 74383c34adc5Sramat if (create_thread) 74393c34adc5Sramat (void) thread_create(NULL, 0, vhcache_flush_thread, vhc, 74403c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 74413c34adc5Sramat } 74423c34adc5Sramat 74433c34adc5Sramat /* 74443c34adc5Sramat * phci bus config structure - one for for each phci bus config operation that 74453c34adc5Sramat * we initiate on behalf of a vhci. 74463c34adc5Sramat */ 74473c34adc5Sramat typedef struct mdi_phci_bus_config_s { 74483c34adc5Sramat char *phbc_phci_path; 74493c34adc5Sramat struct mdi_vhci_bus_config_s *phbc_vhbusconfig; /* vhci bus config */ 74503c34adc5Sramat struct mdi_phci_bus_config_s *phbc_next; 74513c34adc5Sramat } mdi_phci_bus_config_t; 74523c34adc5Sramat 74533c34adc5Sramat /* vhci bus config structure - one for each vhci bus config operation */ 74543c34adc5Sramat typedef struct mdi_vhci_bus_config_s { 74553c34adc5Sramat ddi_bus_config_op_t vhbc_op; /* bus config op */ 74563c34adc5Sramat major_t vhbc_op_major; /* bus config op major */ 74573c34adc5Sramat uint_t vhbc_op_flags; /* bus config op flags */ 74583c34adc5Sramat kmutex_t vhbc_lock; 74593c34adc5Sramat kcondvar_t vhbc_cv; 74603c34adc5Sramat int vhbc_thr_count; 74613c34adc5Sramat } mdi_vhci_bus_config_t; 74623c34adc5Sramat 74633c34adc5Sramat /* 74643c34adc5Sramat * bus config the specified phci 74653c34adc5Sramat */ 74663c34adc5Sramat static void 74673c34adc5Sramat bus_config_phci(void *arg) 74683c34adc5Sramat { 74693c34adc5Sramat mdi_phci_bus_config_t *phbc = (mdi_phci_bus_config_t *)arg; 74703c34adc5Sramat mdi_vhci_bus_config_t *vhbc = phbc->phbc_vhbusconfig; 74713c34adc5Sramat dev_info_t *ph_dip; 74723c34adc5Sramat 74733c34adc5Sramat /* 74743c34adc5Sramat * first configure all path components upto phci and then configure 74753c34adc5Sramat * the phci children. 74763c34adc5Sramat */ 74773c34adc5Sramat if ((ph_dip = e_ddi_hold_devi_by_path(phbc->phbc_phci_path, 0)) 74783c34adc5Sramat != NULL) { 74793c34adc5Sramat if (vhbc->vhbc_op == BUS_CONFIG_DRIVER || 74803c34adc5Sramat vhbc->vhbc_op == BUS_UNCONFIG_DRIVER) { 74813c34adc5Sramat (void) ndi_devi_config_driver(ph_dip, 74823c34adc5Sramat vhbc->vhbc_op_flags, 74833c34adc5Sramat vhbc->vhbc_op_major); 74843c34adc5Sramat } else 74853c34adc5Sramat (void) ndi_devi_config(ph_dip, 74863c34adc5Sramat vhbc->vhbc_op_flags); 74873c34adc5Sramat 74883c34adc5Sramat /* release the hold that e_ddi_hold_devi_by_path() placed */ 74893c34adc5Sramat ndi_rele_devi(ph_dip); 74903c34adc5Sramat } 74913c34adc5Sramat 74923c34adc5Sramat kmem_free(phbc->phbc_phci_path, strlen(phbc->phbc_phci_path) + 1); 74933c34adc5Sramat kmem_free(phbc, sizeof (*phbc)); 74943c34adc5Sramat 74953c34adc5Sramat mutex_enter(&vhbc->vhbc_lock); 74963c34adc5Sramat vhbc->vhbc_thr_count--; 74973c34adc5Sramat if (vhbc->vhbc_thr_count == 0) 74983c34adc5Sramat cv_broadcast(&vhbc->vhbc_cv); 74993c34adc5Sramat mutex_exit(&vhbc->vhbc_lock); 75003c34adc5Sramat } 75013c34adc5Sramat 75023c34adc5Sramat /* 75033c34adc5Sramat * Bus config all phcis associated with the vhci in parallel. 75043c34adc5Sramat * op must be BUS_CONFIG_DRIVER or BUS_CONFIG_ALL. 75053c34adc5Sramat */ 75063c34adc5Sramat static void 75073c34adc5Sramat bus_config_all_phcis(mdi_vhci_cache_t *vhcache, uint_t flags, 75083c34adc5Sramat ddi_bus_config_op_t op, major_t maj) 75093c34adc5Sramat { 75103c34adc5Sramat mdi_phci_bus_config_t *phbc_head = NULL, *phbc, *phbc_next; 75113c34adc5Sramat mdi_vhci_bus_config_t *vhbc; 75123c34adc5Sramat mdi_vhcache_phci_t *cphci; 75133c34adc5Sramat 75143c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 75153c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) { 75163c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 75173c34adc5Sramat return; 75183c34adc5Sramat } 75193c34adc5Sramat 75203c34adc5Sramat vhbc = kmem_zalloc(sizeof (*vhbc), KM_SLEEP); 75213c34adc5Sramat 75223c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 75233c34adc5Sramat cphci = cphci->cphci_next) { 75243c34adc5Sramat phbc = kmem_zalloc(sizeof (*phbc), KM_SLEEP); 75253c34adc5Sramat phbc->phbc_phci_path = i_ddi_strdup(cphci->cphci_path, 75263c34adc5Sramat KM_SLEEP); 75273c34adc5Sramat phbc->phbc_vhbusconfig = vhbc; 75283c34adc5Sramat phbc->phbc_next = phbc_head; 75293c34adc5Sramat phbc_head = phbc; 75303c34adc5Sramat vhbc->vhbc_thr_count++; 75313c34adc5Sramat } 75323c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 75333c34adc5Sramat 75343c34adc5Sramat vhbc->vhbc_op = op; 75353c34adc5Sramat vhbc->vhbc_op_major = maj; 75363c34adc5Sramat vhbc->vhbc_op_flags = NDI_NO_EVENT | 75373c34adc5Sramat (flags & (NDI_CONFIG_REPROBE | NDI_DRV_CONF_REPROBE)); 75383c34adc5Sramat mutex_init(&vhbc->vhbc_lock, NULL, MUTEX_DEFAULT, NULL); 75393c34adc5Sramat cv_init(&vhbc->vhbc_cv, NULL, CV_DRIVER, NULL); 75403c34adc5Sramat 75413c34adc5Sramat /* now create threads to initiate bus config on all phcis in parallel */ 75423c34adc5Sramat for (phbc = phbc_head; phbc != NULL; phbc = phbc_next) { 75433c34adc5Sramat phbc_next = phbc->phbc_next; 75443c34adc5Sramat if (mdi_mtc_off) 75453c34adc5Sramat bus_config_phci((void *)phbc); 75463c34adc5Sramat else 75473c34adc5Sramat (void) thread_create(NULL, 0, bus_config_phci, phbc, 75483c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 75493c34adc5Sramat } 75503c34adc5Sramat 75513c34adc5Sramat mutex_enter(&vhbc->vhbc_lock); 75523c34adc5Sramat /* wait until all threads exit */ 75533c34adc5Sramat while (vhbc->vhbc_thr_count > 0) 75543c34adc5Sramat cv_wait(&vhbc->vhbc_cv, &vhbc->vhbc_lock); 75553c34adc5Sramat mutex_exit(&vhbc->vhbc_lock); 75563c34adc5Sramat 75573c34adc5Sramat mutex_destroy(&vhbc->vhbc_lock); 75583c34adc5Sramat cv_destroy(&vhbc->vhbc_cv); 75593c34adc5Sramat kmem_free(vhbc, sizeof (*vhbc)); 75603c34adc5Sramat } 75613c34adc5Sramat 75623c34adc5Sramat /* 756367e56d35Sramat * Single threaded version of bus_config_all_phcis() 756467e56d35Sramat */ 756567e56d35Sramat static void 756667e56d35Sramat st_bus_config_all_phcis(mdi_vhci_config_t *vhc, uint_t flags, 756767e56d35Sramat ddi_bus_config_op_t op, major_t maj) 756867e56d35Sramat { 756967e56d35Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 757067e56d35Sramat 757167e56d35Sramat single_threaded_vhconfig_enter(vhc); 757267e56d35Sramat bus_config_all_phcis(vhcache, flags, op, maj); 757367e56d35Sramat single_threaded_vhconfig_exit(vhc); 757467e56d35Sramat } 757567e56d35Sramat 757667e56d35Sramat /* 75773c34adc5Sramat * Perform BUS_CONFIG_ONE on the specified child of the phci. 75783c34adc5Sramat * The path includes the child component in addition to the phci path. 75793c34adc5Sramat */ 75803c34adc5Sramat static int 75813c34adc5Sramat bus_config_one_phci_child(char *path) 75823c34adc5Sramat { 75833c34adc5Sramat dev_info_t *ph_dip, *child; 75843c34adc5Sramat char *devnm; 75853c34adc5Sramat int rv = MDI_FAILURE; 75863c34adc5Sramat 75873c34adc5Sramat /* extract the child component of the phci */ 75883c34adc5Sramat devnm = strrchr(path, '/'); 75893c34adc5Sramat *devnm++ = '\0'; 75903c34adc5Sramat 75913c34adc5Sramat /* 75923c34adc5Sramat * first configure all path components upto phci and then 75933c34adc5Sramat * configure the phci child. 75943c34adc5Sramat */ 75953c34adc5Sramat if ((ph_dip = e_ddi_hold_devi_by_path(path, 0)) != NULL) { 75963c34adc5Sramat if (ndi_devi_config_one(ph_dip, devnm, &child, NDI_NO_EVENT) == 75973c34adc5Sramat NDI_SUCCESS) { 75983c34adc5Sramat /* 75993c34adc5Sramat * release the hold that ndi_devi_config_one() placed 76003c34adc5Sramat */ 76013c34adc5Sramat ndi_rele_devi(child); 76023c34adc5Sramat rv = MDI_SUCCESS; 76033c34adc5Sramat } 76043c34adc5Sramat 76053c34adc5Sramat /* release the hold that e_ddi_hold_devi_by_path() placed */ 76063c34adc5Sramat ndi_rele_devi(ph_dip); 76073c34adc5Sramat } 76083c34adc5Sramat 76093c34adc5Sramat devnm--; 76103c34adc5Sramat *devnm = '/'; 76113c34adc5Sramat return (rv); 76123c34adc5Sramat } 76133c34adc5Sramat 76143c34adc5Sramat /* 76153c34adc5Sramat * Build a list of phci client paths for the specified vhci client. 76163c34adc5Sramat * The list includes only those phci client paths which aren't configured yet. 76173c34adc5Sramat */ 76183c34adc5Sramat static mdi_phys_path_t * 76193c34adc5Sramat build_phclient_path_list(mdi_vhcache_client_t *cct, char *ct_name) 76203c34adc5Sramat { 76213c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 76223c34adc5Sramat mdi_phys_path_t *pp_head = NULL, *pp_tail = NULL, *pp; 76233c34adc5Sramat int config_path, len; 76243c34adc5Sramat 76253c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 76263c34adc5Sramat /* 76273c34adc5Sramat * include only those paths that aren't configured. 76283c34adc5Sramat */ 76293c34adc5Sramat config_path = 0; 76303c34adc5Sramat if (cpi->cpi_pip == NULL) 76313c34adc5Sramat config_path = 1; 76323c34adc5Sramat else { 76333c34adc5Sramat MDI_PI_LOCK(cpi->cpi_pip); 76343c34adc5Sramat if (MDI_PI_IS_INIT(cpi->cpi_pip)) 76353c34adc5Sramat config_path = 1; 76363c34adc5Sramat MDI_PI_UNLOCK(cpi->cpi_pip); 76373c34adc5Sramat } 76383c34adc5Sramat 76393c34adc5Sramat if (config_path) { 76403c34adc5Sramat pp = kmem_alloc(sizeof (*pp), KM_SLEEP); 76413c34adc5Sramat len = strlen(cpi->cpi_cphci->cphci_path) + 76423c34adc5Sramat strlen(ct_name) + strlen(cpi->cpi_addr) + 3; 76433c34adc5Sramat pp->phys_path = kmem_alloc(len, KM_SLEEP); 76443c34adc5Sramat (void) snprintf(pp->phys_path, len, "%s/%s@%s", 76453c34adc5Sramat cpi->cpi_cphci->cphci_path, ct_name, 76463c34adc5Sramat cpi->cpi_addr); 76473c34adc5Sramat pp->phys_path_next = NULL; 76483c34adc5Sramat 76493c34adc5Sramat if (pp_head == NULL) 76503c34adc5Sramat pp_head = pp; 76513c34adc5Sramat else 76523c34adc5Sramat pp_tail->phys_path_next = pp; 76533c34adc5Sramat pp_tail = pp; 76543c34adc5Sramat } 76553c34adc5Sramat } 76563c34adc5Sramat 76573c34adc5Sramat return (pp_head); 76583c34adc5Sramat } 76593c34adc5Sramat 76603c34adc5Sramat /* 76613c34adc5Sramat * Free the memory allocated for phci client path list. 76623c34adc5Sramat */ 76633c34adc5Sramat static void 76643c34adc5Sramat free_phclient_path_list(mdi_phys_path_t *pp_head) 76653c34adc5Sramat { 76663c34adc5Sramat mdi_phys_path_t *pp, *pp_next; 76673c34adc5Sramat 76683c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp_next) { 76693c34adc5Sramat pp_next = pp->phys_path_next; 76703c34adc5Sramat kmem_free(pp->phys_path, strlen(pp->phys_path) + 1); 76713c34adc5Sramat kmem_free(pp, sizeof (*pp)); 76723c34adc5Sramat } 76733c34adc5Sramat } 76743c34adc5Sramat 76753c34adc5Sramat /* 76763c34adc5Sramat * Allocated async client structure and initialize with the specified values. 76773c34adc5Sramat */ 76783c34adc5Sramat static mdi_async_client_config_t * 76793c34adc5Sramat alloc_async_client_config(char *ct_name, char *ct_addr, 76803c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 76813c34adc5Sramat { 76823c34adc5Sramat mdi_async_client_config_t *acc; 76833c34adc5Sramat 76843c34adc5Sramat acc = kmem_alloc(sizeof (*acc), KM_SLEEP); 76853c34adc5Sramat acc->acc_ct_name = i_ddi_strdup(ct_name, KM_SLEEP); 76863c34adc5Sramat acc->acc_ct_addr = i_ddi_strdup(ct_addr, KM_SLEEP); 76873c34adc5Sramat acc->acc_phclient_path_list_head = pp_head; 76883c34adc5Sramat init_vhcache_lookup_token(&acc->acc_token, tok); 76893c34adc5Sramat acc->acc_next = NULL; 76903c34adc5Sramat return (acc); 76913c34adc5Sramat } 76923c34adc5Sramat 76933c34adc5Sramat /* 76943c34adc5Sramat * Free the memory allocated for the async client structure and their members. 76953c34adc5Sramat */ 76963c34adc5Sramat static void 76973c34adc5Sramat free_async_client_config(mdi_async_client_config_t *acc) 76983c34adc5Sramat { 76993c34adc5Sramat if (acc->acc_phclient_path_list_head) 77003c34adc5Sramat free_phclient_path_list(acc->acc_phclient_path_list_head); 77013c34adc5Sramat kmem_free(acc->acc_ct_name, strlen(acc->acc_ct_name) + 1); 77023c34adc5Sramat kmem_free(acc->acc_ct_addr, strlen(acc->acc_ct_addr) + 1); 77033c34adc5Sramat kmem_free(acc, sizeof (*acc)); 77043c34adc5Sramat } 77053c34adc5Sramat 77063c34adc5Sramat /* 77073c34adc5Sramat * Sort vhcache pathinfos (cpis) of the specified client. 77083c34adc5Sramat * All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST 77093c34adc5Sramat * flag set come at the beginning of the list. All cpis which have this 77103c34adc5Sramat * flag set come at the end of the list. 77113c34adc5Sramat */ 77123c34adc5Sramat static void 77133c34adc5Sramat sort_vhcache_paths(mdi_vhcache_client_t *cct) 77143c34adc5Sramat { 77153c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_next, *cpi_head; 77163c34adc5Sramat 77173c34adc5Sramat cpi_head = cct->cct_cpi_head; 77183c34adc5Sramat cct->cct_cpi_head = cct->cct_cpi_tail = NULL; 77193c34adc5Sramat for (cpi = cpi_head; cpi != NULL; cpi = cpi_next) { 77203c34adc5Sramat cpi_next = cpi->cpi_next; 77213c34adc5Sramat enqueue_vhcache_pathinfo(cct, cpi); 77223c34adc5Sramat } 77233c34adc5Sramat } 77243c34adc5Sramat 77253c34adc5Sramat /* 77263c34adc5Sramat * Verify whether MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag setting is correct for 77273c34adc5Sramat * every vhcache pathinfo of the specified client. If not adjust the flag 77283c34adc5Sramat * setting appropriately. 77293c34adc5Sramat * 77303c34adc5Sramat * Note that MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag is persisted in the 77313c34adc5Sramat * on-disk vhci cache. So every time this flag is updated the cache must be 77323c34adc5Sramat * flushed. 77333c34adc5Sramat */ 77343c34adc5Sramat static void 77353c34adc5Sramat adjust_sort_vhcache_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 77363c34adc5Sramat mdi_vhcache_lookup_token_t *tok) 77373c34adc5Sramat { 77383c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 77393c34adc5Sramat mdi_vhcache_client_t *cct; 77403c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 77413c34adc5Sramat 77423c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 77433c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, tok)) 77443c34adc5Sramat == NULL) { 77453c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 77463c34adc5Sramat return; 77473c34adc5Sramat } 77483c34adc5Sramat 77493c34adc5Sramat /* 77503c34adc5Sramat * to avoid unnecessary on-disk cache updates, first check if an 77513c34adc5Sramat * update is really needed. If no update is needed simply return. 77523c34adc5Sramat */ 77533c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 77543c34adc5Sramat if ((cpi->cpi_pip != NULL && 77553c34adc5Sramat (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST)) || 77563c34adc5Sramat (cpi->cpi_pip == NULL && 77573c34adc5Sramat !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST))) { 77583c34adc5Sramat break; 77593c34adc5Sramat } 77603c34adc5Sramat } 77613c34adc5Sramat if (cpi == NULL) { 77623c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 77633c34adc5Sramat return; 77643c34adc5Sramat } 77653c34adc5Sramat 77663c34adc5Sramat if (rw_tryupgrade(&vhcache->vhcache_lock) == 0) { 77673c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 77683c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 77693c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, 77703c34adc5Sramat tok)) == NULL) { 77713c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 77723c34adc5Sramat return; 77733c34adc5Sramat } 77743c34adc5Sramat } 77753c34adc5Sramat 77763c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 77773c34adc5Sramat if (cpi->cpi_pip != NULL) 77783c34adc5Sramat cpi->cpi_flags &= ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 77793c34adc5Sramat else 77803c34adc5Sramat cpi->cpi_flags |= MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 77813c34adc5Sramat } 77823c34adc5Sramat sort_vhcache_paths(cct); 77833c34adc5Sramat 77843c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 77853c34adc5Sramat vhcache_dirty(vhc); 77863c34adc5Sramat } 77873c34adc5Sramat 77883c34adc5Sramat /* 77893c34adc5Sramat * Configure all specified paths of the client. 77903c34adc5Sramat */ 77913c34adc5Sramat static void 77923c34adc5Sramat config_client_paths_sync(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 77933c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 77943c34adc5Sramat { 77953c34adc5Sramat mdi_phys_path_t *pp; 77963c34adc5Sramat 77973c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp->phys_path_next) 77983c34adc5Sramat (void) bus_config_one_phci_child(pp->phys_path); 77993c34adc5Sramat adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, tok); 78003c34adc5Sramat } 78013c34adc5Sramat 78023c34adc5Sramat /* 78033c34adc5Sramat * Dequeue elements from vhci async client config list and bus configure 78043c34adc5Sramat * their corresponding phci clients. 78053c34adc5Sramat */ 78063c34adc5Sramat static void 78073c34adc5Sramat config_client_paths_thread(void *arg) 78083c34adc5Sramat { 78093c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 78103c34adc5Sramat mdi_async_client_config_t *acc; 78113c34adc5Sramat clock_t quit_at_ticks; 78123c34adc5Sramat clock_t idle_time = mdi_async_config_idle_time * TICKS_PER_SECOND; 78133c34adc5Sramat callb_cpr_t cprinfo; 78143c34adc5Sramat 78153c34adc5Sramat CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr, 78163c34adc5Sramat "mdi_config_client_paths"); 78173c34adc5Sramat 78183c34adc5Sramat for (; ; ) { 78193c34adc5Sramat quit_at_ticks = ddi_get_lbolt() + idle_time; 78203c34adc5Sramat 78213c34adc5Sramat mutex_enter(&vhc->vhc_lock); 78223c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 78233c34adc5Sramat vhc->vhc_acc_list_head == NULL && 78243c34adc5Sramat ddi_get_lbolt() < quit_at_ticks) { 78253c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 78263c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock, 78273c34adc5Sramat quit_at_ticks); 78283c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 78293c34adc5Sramat } 78303c34adc5Sramat 78313c34adc5Sramat if ((vhc->vhc_flags & MDI_VHC_EXIT) || 78323c34adc5Sramat vhc->vhc_acc_list_head == NULL) 78333c34adc5Sramat goto out; 78343c34adc5Sramat 78353c34adc5Sramat acc = vhc->vhc_acc_list_head; 78363c34adc5Sramat vhc->vhc_acc_list_head = acc->acc_next; 78373c34adc5Sramat if (vhc->vhc_acc_list_head == NULL) 78383c34adc5Sramat vhc->vhc_acc_list_tail = NULL; 78393c34adc5Sramat vhc->vhc_acc_count--; 78403c34adc5Sramat mutex_exit(&vhc->vhc_lock); 78413c34adc5Sramat 78423c34adc5Sramat config_client_paths_sync(vhc, acc->acc_ct_name, 78433c34adc5Sramat acc->acc_ct_addr, acc->acc_phclient_path_list_head, 78443c34adc5Sramat &acc->acc_token); 78453c34adc5Sramat 78463c34adc5Sramat free_async_client_config(acc); 78473c34adc5Sramat } 78483c34adc5Sramat 78493c34adc5Sramat out: 78503c34adc5Sramat vhc->vhc_acc_thrcount--; 78513c34adc5Sramat /* CALLB_CPR_EXIT releases the vhc->vhc_lock */ 78523c34adc5Sramat CALLB_CPR_EXIT(&cprinfo); 78533c34adc5Sramat } 78543c34adc5Sramat 78553c34adc5Sramat /* 78563c34adc5Sramat * Arrange for all the phci client paths (pp_head) for the specified client 78573c34adc5Sramat * to be bus configured asynchronously by a thread. 78583c34adc5Sramat */ 78593c34adc5Sramat static void 78603c34adc5Sramat config_client_paths_async(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 78613c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 78623c34adc5Sramat { 78633c34adc5Sramat mdi_async_client_config_t *acc, *newacc; 78643c34adc5Sramat int create_thread; 78653c34adc5Sramat 78663c34adc5Sramat if (pp_head == NULL) 78673c34adc5Sramat return; 78683c34adc5Sramat 78693c34adc5Sramat if (mdi_mtc_off) { 78703c34adc5Sramat config_client_paths_sync(vhc, ct_name, ct_addr, pp_head, tok); 78713c34adc5Sramat free_phclient_path_list(pp_head); 78723c34adc5Sramat return; 78733c34adc5Sramat } 78743c34adc5Sramat 78753c34adc5Sramat newacc = alloc_async_client_config(ct_name, ct_addr, pp_head, tok); 78763c34adc5Sramat ASSERT(newacc); 78773c34adc5Sramat 78783c34adc5Sramat mutex_enter(&vhc->vhc_lock); 78793c34adc5Sramat for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc->acc_next) { 78803c34adc5Sramat if (strcmp(ct_name, acc->acc_ct_name) == 0 && 78813c34adc5Sramat strcmp(ct_addr, acc->acc_ct_addr) == 0) { 78823c34adc5Sramat free_async_client_config(newacc); 78833c34adc5Sramat mutex_exit(&vhc->vhc_lock); 78843c34adc5Sramat return; 78853c34adc5Sramat } 78863c34adc5Sramat } 78873c34adc5Sramat 78883c34adc5Sramat if (vhc->vhc_acc_list_head == NULL) 78893c34adc5Sramat vhc->vhc_acc_list_head = newacc; 78903c34adc5Sramat else 78913c34adc5Sramat vhc->vhc_acc_list_tail->acc_next = newacc; 78923c34adc5Sramat vhc->vhc_acc_list_tail = newacc; 78933c34adc5Sramat vhc->vhc_acc_count++; 78943c34adc5Sramat if (vhc->vhc_acc_count <= vhc->vhc_acc_thrcount) { 78953c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 78963c34adc5Sramat create_thread = 0; 78973c34adc5Sramat } else { 78983c34adc5Sramat vhc->vhc_acc_thrcount++; 78993c34adc5Sramat create_thread = 1; 79003c34adc5Sramat } 79013c34adc5Sramat mutex_exit(&vhc->vhc_lock); 79023c34adc5Sramat 79033c34adc5Sramat if (create_thread) 79043c34adc5Sramat (void) thread_create(NULL, 0, config_client_paths_thread, vhc, 79053c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 79063c34adc5Sramat } 79073c34adc5Sramat 79083c34adc5Sramat /* 79093c34adc5Sramat * Return number of online paths for the specified client. 79103c34adc5Sramat */ 79113c34adc5Sramat static int 79123c34adc5Sramat nonline_paths(mdi_vhcache_client_t *cct) 79133c34adc5Sramat { 79143c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 79153c34adc5Sramat int online_count = 0; 79163c34adc5Sramat 79173c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 79183c34adc5Sramat if (cpi->cpi_pip != NULL) { 79193c34adc5Sramat MDI_PI_LOCK(cpi->cpi_pip); 79203c34adc5Sramat if (cpi->cpi_pip->pi_state == MDI_PATHINFO_STATE_ONLINE) 79213c34adc5Sramat online_count++; 79223c34adc5Sramat MDI_PI_UNLOCK(cpi->cpi_pip); 79233c34adc5Sramat } 79243c34adc5Sramat } 79253c34adc5Sramat 79263c34adc5Sramat return (online_count); 79273c34adc5Sramat } 79283c34adc5Sramat 79293c34adc5Sramat /* 79303c34adc5Sramat * Bus configure all paths for the specified vhci client. 79313c34adc5Sramat * If at least one path for the client is already online, the remaining paths 79323c34adc5Sramat * will be configured asynchronously. Otherwise, it synchronously configures 79333c34adc5Sramat * the paths until at least one path is online and then rest of the paths 79343c34adc5Sramat * will be configured asynchronously. 79353c34adc5Sramat */ 79363c34adc5Sramat static void 79373c34adc5Sramat config_client_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr) 79383c34adc5Sramat { 79393c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 79403c34adc5Sramat mdi_phys_path_t *pp_head, *pp; 79413c34adc5Sramat mdi_vhcache_client_t *cct; 79423c34adc5Sramat mdi_vhcache_lookup_token_t tok; 79433c34adc5Sramat 79443c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 79453c34adc5Sramat 79463c34adc5Sramat init_vhcache_lookup_token(&tok, NULL); 79473c34adc5Sramat 79483c34adc5Sramat if (ct_name == NULL || ct_addr == NULL || 79493c34adc5Sramat (cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, &tok)) 79503c34adc5Sramat == NULL || 79513c34adc5Sramat (pp_head = build_phclient_path_list(cct, ct_name)) == NULL) { 79523c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 79533c34adc5Sramat return; 79543c34adc5Sramat } 79553c34adc5Sramat 79563c34adc5Sramat /* if at least one path is online, configure the rest asynchronously */ 79573c34adc5Sramat if (nonline_paths(cct) > 0) { 79583c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 79593c34adc5Sramat config_client_paths_async(vhc, ct_name, ct_addr, pp_head, &tok); 79603c34adc5Sramat return; 79613c34adc5Sramat } 79623c34adc5Sramat 79633c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 79643c34adc5Sramat 79653c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp->phys_path_next) { 79663c34adc5Sramat if (bus_config_one_phci_child(pp->phys_path) == MDI_SUCCESS) { 79673c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 79683c34adc5Sramat 79693c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, 79703c34adc5Sramat ct_addr, &tok)) == NULL) { 79713c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 79723c34adc5Sramat goto out; 79733c34adc5Sramat } 79743c34adc5Sramat 79753c34adc5Sramat if (nonline_paths(cct) > 0 && 79763c34adc5Sramat pp->phys_path_next != NULL) { 79773c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 79783c34adc5Sramat config_client_paths_async(vhc, ct_name, ct_addr, 79793c34adc5Sramat pp->phys_path_next, &tok); 79803c34adc5Sramat pp->phys_path_next = NULL; 79813c34adc5Sramat goto out; 79823c34adc5Sramat } 79833c34adc5Sramat 79843c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 79853c34adc5Sramat } 79863c34adc5Sramat } 79873c34adc5Sramat 79883c34adc5Sramat adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, &tok); 79893c34adc5Sramat out: 79903c34adc5Sramat free_phclient_path_list(pp_head); 79913c34adc5Sramat } 79923c34adc5Sramat 79933c34adc5Sramat static void 79943c34adc5Sramat single_threaded_vhconfig_enter(mdi_vhci_config_t *vhc) 79953c34adc5Sramat { 79963c34adc5Sramat mutex_enter(&vhc->vhc_lock); 79973c34adc5Sramat while (vhc->vhc_flags & MDI_VHC_SINGLE_THREADED) 79983c34adc5Sramat cv_wait(&vhc->vhc_cv, &vhc->vhc_lock); 79993c34adc5Sramat vhc->vhc_flags |= MDI_VHC_SINGLE_THREADED; 80003c34adc5Sramat mutex_exit(&vhc->vhc_lock); 80013c34adc5Sramat } 80023c34adc5Sramat 80033c34adc5Sramat static void 80043c34adc5Sramat single_threaded_vhconfig_exit(mdi_vhci_config_t *vhc) 80053c34adc5Sramat { 80063c34adc5Sramat mutex_enter(&vhc->vhc_lock); 80073c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_SINGLE_THREADED; 80083c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 80093c34adc5Sramat mutex_exit(&vhc->vhc_lock); 80103c34adc5Sramat } 80113c34adc5Sramat 801252cac543Sramat typedef struct mdi_phci_driver_info { 801352cac543Sramat char *phdriver_name; /* name of the phci driver */ 801452cac543Sramat 801552cac543Sramat /* set to non zero if the phci driver supports root device */ 801652cac543Sramat int phdriver_root_support; 801752cac543Sramat } mdi_phci_driver_info_t; 801852cac543Sramat 80193c34adc5Sramat /* 802052cac543Sramat * vhci class and root support capability of a phci driver can be 802152cac543Sramat * specified using ddi-vhci-class and ddi-no-root-support properties in the 802252cac543Sramat * phci driver.conf file. The built-in tables below contain this information 802352cac543Sramat * for those phci drivers whose driver.conf files don't yet contain this info. 802452cac543Sramat * 802552cac543Sramat * All phci drivers expect iscsi have root device support. 802652cac543Sramat */ 802752cac543Sramat static mdi_phci_driver_info_t scsi_phci_driver_list[] = { 802852cac543Sramat { "fp", 1 }, 802952cac543Sramat { "iscsi", 0 }, 803052cac543Sramat { "ibsrp", 1 } 803152cac543Sramat }; 803252cac543Sramat 803352cac543Sramat static mdi_phci_driver_info_t ib_phci_driver_list[] = { "tavor", 1 }; 803452cac543Sramat 803552cac543Sramat static void * 803652cac543Sramat mdi_realloc(void *old_ptr, size_t old_size, size_t new_size) 803752cac543Sramat { 803852cac543Sramat void *new_ptr; 803952cac543Sramat 804052cac543Sramat new_ptr = kmem_zalloc(new_size, KM_SLEEP); 804152cac543Sramat if (old_ptr) { 804252cac543Sramat bcopy(old_ptr, new_ptr, old_size); 804352cac543Sramat kmem_free(old_ptr, old_size); 804452cac543Sramat } 804552cac543Sramat return (new_ptr); 804652cac543Sramat } 804752cac543Sramat 804852cac543Sramat static void 804952cac543Sramat add_to_phci_list(char ***driver_list, int **root_support_list, 805052cac543Sramat int *cur_elements, int *max_elements, char *driver_name, int root_support) 805152cac543Sramat { 805252cac543Sramat ASSERT(*cur_elements <= *max_elements); 805352cac543Sramat if (*cur_elements == *max_elements) { 805452cac543Sramat *max_elements += 10; 805552cac543Sramat *driver_list = mdi_realloc(*driver_list, 805652cac543Sramat sizeof (char *) * (*cur_elements), 805752cac543Sramat sizeof (char *) * (*max_elements)); 805852cac543Sramat *root_support_list = mdi_realloc(*root_support_list, 805952cac543Sramat sizeof (int) * (*cur_elements), 806052cac543Sramat sizeof (int) * (*max_elements)); 806152cac543Sramat } 806252cac543Sramat (*driver_list)[*cur_elements] = i_ddi_strdup(driver_name, KM_SLEEP); 806352cac543Sramat (*root_support_list)[*cur_elements] = root_support; 806452cac543Sramat (*cur_elements)++; 806552cac543Sramat } 806652cac543Sramat 806752cac543Sramat static void 806852cac543Sramat get_phci_driver_list(char *vhci_class, char ***driver_list, 806952cac543Sramat int **root_support_list, int *cur_elements, int *max_elements) 807052cac543Sramat { 807152cac543Sramat mdi_phci_driver_info_t *st_driver_list, *p; 807252cac543Sramat int st_ndrivers, root_support, i, j, driver_conf_count; 807352cac543Sramat major_t m; 807452cac543Sramat struct devnames *dnp; 807552cac543Sramat ddi_prop_t *propp; 807652cac543Sramat 807752cac543Sramat *driver_list = NULL; 807852cac543Sramat *root_support_list = NULL; 807952cac543Sramat *cur_elements = 0; 808052cac543Sramat *max_elements = 0; 808152cac543Sramat 808252cac543Sramat /* add the phci drivers derived from the phci driver.conf files */ 808352cac543Sramat for (m = 0; m < devcnt; m++) { 808452cac543Sramat dnp = &devnamesp[m]; 808552cac543Sramat 808652cac543Sramat if (dnp->dn_flags & DN_PHCI_DRIVER) { 808752cac543Sramat LOCK_DEV_OPS(&dnp->dn_lock); 808852cac543Sramat if (dnp->dn_global_prop_ptr != NULL && 808952cac543Sramat (propp = i_ddi_prop_search(DDI_DEV_T_ANY, 809052cac543Sramat DDI_VHCI_CLASS, DDI_PROP_TYPE_STRING, 809152cac543Sramat &dnp->dn_global_prop_ptr->prop_list)) != NULL && 809252cac543Sramat strcmp(propp->prop_val, vhci_class) == 0) { 809352cac543Sramat 809452cac543Sramat root_support = (i_ddi_prop_search(DDI_DEV_T_ANY, 809552cac543Sramat DDI_NO_ROOT_SUPPORT, DDI_PROP_TYPE_INT, 809652cac543Sramat &dnp->dn_global_prop_ptr->prop_list) 809752cac543Sramat == NULL) ? 1 : 0; 809852cac543Sramat 809952cac543Sramat add_to_phci_list(driver_list, root_support_list, 810052cac543Sramat cur_elements, max_elements, dnp->dn_name, 810152cac543Sramat root_support); 810252cac543Sramat 810352cac543Sramat UNLOCK_DEV_OPS(&dnp->dn_lock); 810452cac543Sramat } else 810552cac543Sramat UNLOCK_DEV_OPS(&dnp->dn_lock); 810652cac543Sramat } 810752cac543Sramat } 810852cac543Sramat 810952cac543Sramat driver_conf_count = *cur_elements; 811052cac543Sramat 811152cac543Sramat /* add the phci drivers specified in the built-in tables */ 811252cac543Sramat if (strcmp(vhci_class, MDI_HCI_CLASS_SCSI) == 0) { 811352cac543Sramat st_driver_list = scsi_phci_driver_list; 811452cac543Sramat st_ndrivers = sizeof (scsi_phci_driver_list) / 811552cac543Sramat sizeof (mdi_phci_driver_info_t); 811652cac543Sramat } else if (strcmp(vhci_class, MDI_HCI_CLASS_IB) == 0) { 811752cac543Sramat st_driver_list = ib_phci_driver_list; 811852cac543Sramat st_ndrivers = sizeof (ib_phci_driver_list) / 811952cac543Sramat sizeof (mdi_phci_driver_info_t); 812052cac543Sramat } else { 812152cac543Sramat st_driver_list = NULL; 812252cac543Sramat st_ndrivers = 0; 812352cac543Sramat } 812452cac543Sramat 812552cac543Sramat for (i = 0, p = st_driver_list; i < st_ndrivers; i++, p++) { 812652cac543Sramat /* add this phci driver if not already added before */ 812752cac543Sramat for (j = 0; j < driver_conf_count; j++) { 812852cac543Sramat if (strcmp((*driver_list)[j], p->phdriver_name) == 0) 812952cac543Sramat break; 813052cac543Sramat } 813152cac543Sramat if (j == driver_conf_count) { 813252cac543Sramat add_to_phci_list(driver_list, root_support_list, 813352cac543Sramat cur_elements, max_elements, p->phdriver_name, 813452cac543Sramat p->phdriver_root_support); 813552cac543Sramat } 813652cac543Sramat } 813752cac543Sramat } 813852cac543Sramat 813952cac543Sramat /* 814052cac543Sramat * Attach the phci driver instances associated with the specified vhci class. 81413c34adc5Sramat * If root is mounted attach all phci driver instances. 81423c34adc5Sramat * If root is not mounted, attach the instances of only those phci 81433c34adc5Sramat * drivers that have the root support. 81443c34adc5Sramat */ 81453c34adc5Sramat static void 814652cac543Sramat attach_phci_drivers(char *vhci_class) 81473c34adc5Sramat { 814852cac543Sramat char **driver_list, **p; 814952cac543Sramat int *root_support_list; 815052cac543Sramat int cur_elements, max_elements, i; 81513c34adc5Sramat major_t m; 81523c34adc5Sramat 815352cac543Sramat get_phci_driver_list(vhci_class, &driver_list, &root_support_list, 815452cac543Sramat &cur_elements, &max_elements); 81553c34adc5Sramat 815652cac543Sramat for (i = 0; i < cur_elements; i++) { 815752cac543Sramat if (modrootloaded || root_support_list[i]) { 815852cac543Sramat m = ddi_name_to_major(driver_list[i]); 815952cac543Sramat if (m != (major_t)-1 && ddi_hold_installed_driver(m)) 81603c34adc5Sramat ddi_rele_driver(m); 81613c34adc5Sramat } 81623c34adc5Sramat } 816352cac543Sramat 816452cac543Sramat if (driver_list) { 816552cac543Sramat for (i = 0, p = driver_list; i < cur_elements; i++, p++) 816652cac543Sramat kmem_free(*p, strlen(*p) + 1); 816752cac543Sramat kmem_free(driver_list, sizeof (char *) * max_elements); 816852cac543Sramat kmem_free(root_support_list, sizeof (int) * max_elements); 816952cac543Sramat } 81703c34adc5Sramat } 81713c34adc5Sramat 81723c34adc5Sramat /* 81733c34adc5Sramat * Build vhci cache: 81743c34adc5Sramat * 81753c34adc5Sramat * Attach phci driver instances and then drive BUS_CONFIG_ALL on 81763c34adc5Sramat * the phci driver instances. During this process the cache gets built. 81773c34adc5Sramat * 817867e56d35Sramat * Cache is built fully if the root is mounted. 81793c34adc5Sramat * If the root is not mounted, phci drivers that do not have root support 81803c34adc5Sramat * are not attached. As a result the cache is built partially. The entries 81813c34adc5Sramat * in the cache reflect only those phci drivers that have root support. 81823c34adc5Sramat */ 818367e56d35Sramat static int 818452cac543Sramat build_vhci_cache(mdi_vhci_t *vh) 81853c34adc5Sramat { 818652cac543Sramat mdi_vhci_config_t *vhc = vh->vh_config; 81873c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 81883c34adc5Sramat 818967e56d35Sramat single_threaded_vhconfig_enter(vhc); 819067e56d35Sramat 81913c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 81923c34adc5Sramat if (vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE) { 81933c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 819467e56d35Sramat single_threaded_vhconfig_exit(vhc); 819567e56d35Sramat return (0); 81963c34adc5Sramat } 81973c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 81983c34adc5Sramat 819952cac543Sramat attach_phci_drivers(vh->vh_class); 82003c34adc5Sramat bus_config_all_phcis(vhcache, NDI_DRV_CONF_REPROBE | NDI_NO_EVENT, 82013c34adc5Sramat BUS_CONFIG_ALL, (major_t)-1); 82023c34adc5Sramat 82033c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 82043c34adc5Sramat vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE; 82053c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 820667e56d35Sramat 820767e56d35Sramat single_threaded_vhconfig_exit(vhc); 82083c34adc5Sramat vhcache_dirty(vhc); 820967e56d35Sramat return (1); 82103c34adc5Sramat } 82113c34adc5Sramat 82123c34adc5Sramat /* 821367e56d35Sramat * Determine if discovery of paths is needed. 82143c34adc5Sramat */ 82153c34adc5Sramat static int 821667e56d35Sramat vhcache_do_discovery(mdi_vhci_config_t *vhc) 82173c34adc5Sramat { 821867e56d35Sramat int rv = 1; 821967e56d35Sramat 822067e56d35Sramat mutex_enter(&vhc->vhc_lock); 822167e56d35Sramat if (i_ddi_io_initialized() == 0) { 822267e56d35Sramat if (vhc->vhc_path_discovery_boot > 0) { 822367e56d35Sramat vhc->vhc_path_discovery_boot--; 822467e56d35Sramat goto out; 822567e56d35Sramat } 822667e56d35Sramat } else { 822767e56d35Sramat if (vhc->vhc_path_discovery_postboot > 0) { 822867e56d35Sramat vhc->vhc_path_discovery_postboot--; 822967e56d35Sramat goto out; 823067e56d35Sramat } 823167e56d35Sramat } 823267e56d35Sramat 823367e56d35Sramat /* 823467e56d35Sramat * Do full path discovery at most once per mdi_path_discovery_interval. 823567e56d35Sramat * This is to avoid a series of full path discoveries when opening 823667e56d35Sramat * stale /dev/[r]dsk links. 823767e56d35Sramat */ 823867e56d35Sramat if (mdi_path_discovery_interval != -1 && 823967e56d35Sramat lbolt64 >= vhc->vhc_path_discovery_cutoff_time) 824067e56d35Sramat goto out; 824167e56d35Sramat 824267e56d35Sramat rv = 0; 824367e56d35Sramat out: 824467e56d35Sramat mutex_exit(&vhc->vhc_lock); 824567e56d35Sramat return (rv); 824667e56d35Sramat } 824767e56d35Sramat 824867e56d35Sramat /* 824967e56d35Sramat * Discover all paths: 825067e56d35Sramat * 825167e56d35Sramat * Attach phci driver instances and then drive BUS_CONFIG_ALL on all the phci 825267e56d35Sramat * driver instances. During this process all paths will be discovered. 825367e56d35Sramat */ 825467e56d35Sramat static int 825552cac543Sramat vhcache_discover_paths(mdi_vhci_t *vh) 825667e56d35Sramat { 825752cac543Sramat mdi_vhci_config_t *vhc = vh->vh_config; 825867e56d35Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 825967e56d35Sramat int rv = 0; 82603c34adc5Sramat 82613c34adc5Sramat single_threaded_vhconfig_enter(vhc); 82623c34adc5Sramat 826367e56d35Sramat if (vhcache_do_discovery(vhc)) { 826452cac543Sramat attach_phci_drivers(vh->vh_class); 826567e56d35Sramat bus_config_all_phcis(vhcache, NDI_DRV_CONF_REPROBE | 826667e56d35Sramat NDI_NO_EVENT, BUS_CONFIG_ALL, (major_t)-1); 826767e56d35Sramat 82683c34adc5Sramat mutex_enter(&vhc->vhc_lock); 826967e56d35Sramat vhc->vhc_path_discovery_cutoff_time = lbolt64 + 827067e56d35Sramat mdi_path_discovery_interval * TICKS_PER_SECOND; 82713c34adc5Sramat mutex_exit(&vhc->vhc_lock); 827267e56d35Sramat rv = 1; 82733c34adc5Sramat } 82743c34adc5Sramat 82753c34adc5Sramat single_threaded_vhconfig_exit(vhc); 82763c34adc5Sramat return (rv); 82773c34adc5Sramat } 82783c34adc5Sramat 82793c34adc5Sramat /* 82803c34adc5Sramat * Generic vhci bus config implementation: 82813c34adc5Sramat * 82823c34adc5Sramat * Parameters 82833c34adc5Sramat * vdip vhci dip 82843c34adc5Sramat * flags bus config flags 82853c34adc5Sramat * op bus config operation 82863c34adc5Sramat * The remaining parameters are bus config operation specific 82873c34adc5Sramat * 82883c34adc5Sramat * for BUS_CONFIG_ONE 82893c34adc5Sramat * arg pointer to name@addr 82903c34adc5Sramat * child upon successful return from this function, *child will be 82913c34adc5Sramat * set to the configured and held devinfo child node of vdip. 82923c34adc5Sramat * ct_addr pointer to client address (i.e. GUID) 82933c34adc5Sramat * 82943c34adc5Sramat * for BUS_CONFIG_DRIVER 82953c34adc5Sramat * arg major number of the driver 82963c34adc5Sramat * child and ct_addr parameters are ignored 82973c34adc5Sramat * 82983c34adc5Sramat * for BUS_CONFIG_ALL 82993c34adc5Sramat * arg, child, and ct_addr parameters are ignored 83003c34adc5Sramat * 83013c34adc5Sramat * Note that for the rest of the bus config operations, this function simply 83023c34adc5Sramat * calls the framework provided default bus config routine. 83033c34adc5Sramat */ 83043c34adc5Sramat int 83053c34adc5Sramat mdi_vhci_bus_config(dev_info_t *vdip, uint_t flags, ddi_bus_config_op_t op, 83063c34adc5Sramat void *arg, dev_info_t **child, char *ct_addr) 83073c34adc5Sramat { 83083c34adc5Sramat mdi_vhci_t *vh = i_devi_get_vhci(vdip); 83093c34adc5Sramat mdi_vhci_config_t *vhc = vh->vh_config; 83103c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 831167e56d35Sramat int rv = 0; 831267e56d35Sramat int params_valid = 0; 83133c34adc5Sramat char *cp; 83143c34adc5Sramat 83153c34adc5Sramat /* 8316*c73a93f2Sdm120769 * While bus configuring phcis, the phci driver interactions with MDI 8317*c73a93f2Sdm120769 * cause child nodes to be enumerated under the vhci node for which 8318*c73a93f2Sdm120769 * they need to ndi_devi_enter the vhci node. 8319*c73a93f2Sdm120769 * 8320*c73a93f2Sdm120769 * Unfortunately, to avoid the deadlock, we ourself can not wait for 8321*c73a93f2Sdm120769 * for the bus config operations on phcis to finish while holding the 8322*c73a93f2Sdm120769 * ndi_devi_enter lock. To avoid this deadlock, skip bus configs on 8323*c73a93f2Sdm120769 * phcis and call the default framework provided bus config function 8324*c73a93f2Sdm120769 * if we are called with ndi_devi_enter lock held. 83253c34adc5Sramat */ 83263c34adc5Sramat if (DEVI_BUSY_OWNED(vdip)) { 8327*c73a93f2Sdm120769 MDI_DEBUG(2, (CE_NOTE, vdip, 8328*c73a93f2Sdm120769 "!MDI: vhci bus config: vhci dip is busy owned\n")); 83293c34adc5Sramat goto default_bus_config; 83303c34adc5Sramat } 83313c34adc5Sramat 83323c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 83333c34adc5Sramat if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) { 83343c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 833552cac543Sramat rv = build_vhci_cache(vh); 83363c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 83373c34adc5Sramat } 83383c34adc5Sramat 83393c34adc5Sramat switch (op) { 83403c34adc5Sramat case BUS_CONFIG_ONE: 834167e56d35Sramat if (arg != NULL && ct_addr != NULL) { 83423c34adc5Sramat /* extract node name */ 83433c34adc5Sramat cp = (char *)arg; 83443c34adc5Sramat while (*cp != '\0' && *cp != '@') 83453c34adc5Sramat cp++; 83463c34adc5Sramat if (*cp == '@') { 834767e56d35Sramat params_valid = 1; 83483c34adc5Sramat *cp = '\0'; 83493c34adc5Sramat config_client_paths(vhc, (char *)arg, ct_addr); 835067e56d35Sramat /* config_client_paths() releases cache_lock */ 83513c34adc5Sramat *cp = '@'; 835267e56d35Sramat break; 835367e56d35Sramat } 835467e56d35Sramat } 835567e56d35Sramat 83563c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 83573c34adc5Sramat break; 83583c34adc5Sramat 83593c34adc5Sramat case BUS_CONFIG_DRIVER: 83603c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 836167e56d35Sramat if (rv == 0) 836267e56d35Sramat st_bus_config_all_phcis(vhc, flags, op, 83633c34adc5Sramat (major_t)(uintptr_t)arg); 83643c34adc5Sramat break; 83653c34adc5Sramat 83663c34adc5Sramat case BUS_CONFIG_ALL: 83673c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 836867e56d35Sramat if (rv == 0) 836967e56d35Sramat st_bus_config_all_phcis(vhc, flags, op, -1); 83703c34adc5Sramat break; 83713c34adc5Sramat 83723c34adc5Sramat default: 83733c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 83743c34adc5Sramat break; 83753c34adc5Sramat } 83763c34adc5Sramat 83773c34adc5Sramat 83783c34adc5Sramat default_bus_config: 83793c34adc5Sramat /* 83803c34adc5Sramat * All requested child nodes are enumerated under the vhci. 83813c34adc5Sramat * Now configure them. 83823c34adc5Sramat */ 83833c34adc5Sramat if (ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 83843c34adc5Sramat NDI_SUCCESS) { 83853c34adc5Sramat return (MDI_SUCCESS); 838667e56d35Sramat } else if (op == BUS_CONFIG_ONE && rv == 0 && params_valid) { 838767e56d35Sramat /* discover all paths and try configuring again */ 838852cac543Sramat if (vhcache_discover_paths(vh) && 838967e56d35Sramat ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 839067e56d35Sramat NDI_SUCCESS) 839167e56d35Sramat return (MDI_SUCCESS); 83923c34adc5Sramat } 83933c34adc5Sramat 83943c34adc5Sramat return (MDI_FAILURE); 83953c34adc5Sramat } 83963c34adc5Sramat 83973c34adc5Sramat /* 83983c34adc5Sramat * Read the on-disk vhci cache into an nvlist for the specified vhci class. 83993c34adc5Sramat */ 84003c34adc5Sramat static nvlist_t * 84013c34adc5Sramat read_on_disk_vhci_cache(char *vhci_class) 84023c34adc5Sramat { 84033c34adc5Sramat nvlist_t *nvl; 84043c34adc5Sramat int err; 84053c34adc5Sramat char *filename; 84063c34adc5Sramat 84073c34adc5Sramat filename = vhclass2vhcache_filename(vhci_class); 84083c34adc5Sramat 84093c34adc5Sramat if ((err = fread_nvlist(filename, &nvl)) == 0) { 84103c34adc5Sramat kmem_free(filename, strlen(filename) + 1); 84113c34adc5Sramat return (nvl); 84123c34adc5Sramat } else if (err == EIO) 84133c34adc5Sramat cmn_err(CE_WARN, "%s: I/O error, will recreate\n", filename); 84143c34adc5Sramat else if (err == EINVAL) 84153c34adc5Sramat cmn_err(CE_WARN, 84163c34adc5Sramat "%s: data file corrupted, will recreate\n", filename); 84173c34adc5Sramat 84183c34adc5Sramat kmem_free(filename, strlen(filename) + 1); 84193c34adc5Sramat return (NULL); 84203c34adc5Sramat } 84213c34adc5Sramat 84223c34adc5Sramat /* 84233c34adc5Sramat * Read on-disk vhci cache into nvlists for all vhci classes. 84243c34adc5Sramat * Called during booting by i_ddi_read_devices_files(). 84253c34adc5Sramat */ 84263c34adc5Sramat void 84273c34adc5Sramat mdi_read_devices_files(void) 84283c34adc5Sramat { 84293c34adc5Sramat int i; 84303c34adc5Sramat 84313c34adc5Sramat for (i = 0; i < N_VHCI_CLASSES; i++) 84323c34adc5Sramat vhcache_nvl[i] = read_on_disk_vhci_cache(vhci_class_list[i]); 84333c34adc5Sramat } 84343c34adc5Sramat 84353c34adc5Sramat /* 84363c34adc5Sramat * Remove all stale entries from vhci cache. 84373c34adc5Sramat */ 84383c34adc5Sramat static void 84393c34adc5Sramat clean_vhcache(mdi_vhci_config_t *vhc) 84403c34adc5Sramat { 84413c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 84423c34adc5Sramat mdi_vhcache_phci_t *cphci, *cphci_head, *cphci_next; 84433c34adc5Sramat mdi_vhcache_client_t *cct, *cct_head, *cct_next; 84443c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_head, *cpi_next; 84453c34adc5Sramat 84463c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 84473c34adc5Sramat 84483c34adc5Sramat cct_head = vhcache->vhcache_client_head; 84493c34adc5Sramat vhcache->vhcache_client_head = vhcache->vhcache_client_tail = NULL; 84503c34adc5Sramat for (cct = cct_head; cct != NULL; cct = cct_next) { 84513c34adc5Sramat cct_next = cct->cct_next; 84523c34adc5Sramat 84533c34adc5Sramat cpi_head = cct->cct_cpi_head; 84543c34adc5Sramat cct->cct_cpi_head = cct->cct_cpi_tail = NULL; 84553c34adc5Sramat for (cpi = cpi_head; cpi != NULL; cpi = cpi_next) { 84563c34adc5Sramat cpi_next = cpi->cpi_next; 84573c34adc5Sramat if (cpi->cpi_pip != NULL) { 84583c34adc5Sramat ASSERT(cpi->cpi_cphci->cphci_phci != NULL); 84593c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, cpi); 84603c34adc5Sramat } else 84613c34adc5Sramat free_vhcache_pathinfo(cpi); 84623c34adc5Sramat } 84633c34adc5Sramat 84643c34adc5Sramat if (cct->cct_cpi_head != NULL) 84653c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 84663c34adc5Sramat else { 84673c34adc5Sramat (void) mod_hash_destroy(vhcache->vhcache_client_hash, 84683c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr); 84693c34adc5Sramat free_vhcache_client(cct); 84703c34adc5Sramat } 84713c34adc5Sramat } 84723c34adc5Sramat 84733c34adc5Sramat cphci_head = vhcache->vhcache_phci_head; 84743c34adc5Sramat vhcache->vhcache_phci_head = vhcache->vhcache_phci_tail = NULL; 84753c34adc5Sramat for (cphci = cphci_head; cphci != NULL; cphci = cphci_next) { 84763c34adc5Sramat cphci_next = cphci->cphci_next; 84773c34adc5Sramat if (cphci->cphci_phci != NULL) 84783c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 84793c34adc5Sramat else 84803c34adc5Sramat free_vhcache_phci(cphci); 84813c34adc5Sramat } 84823c34adc5Sramat 84833c34adc5Sramat vhcache->vhcache_clean_time = lbolt64; 84843c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 84853c34adc5Sramat vhcache_dirty(vhc); 84863c34adc5Sramat } 84873c34adc5Sramat 84883c34adc5Sramat /* 84893c34adc5Sramat * Remove all stale entries from vhci cache. 84903c34adc5Sramat * Called by i_ddi_clean_devices_files() during the execution of devfsadm -C 84913c34adc5Sramat */ 84923c34adc5Sramat void 84933c34adc5Sramat mdi_clean_vhcache(void) 84943c34adc5Sramat { 84953c34adc5Sramat mdi_vhci_t *vh; 84963c34adc5Sramat 84973c34adc5Sramat mutex_enter(&mdi_mutex); 84983c34adc5Sramat for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 84993c34adc5Sramat vh->vh_refcnt++; 85003c34adc5Sramat mutex_exit(&mdi_mutex); 85013c34adc5Sramat clean_vhcache(vh->vh_config); 85023c34adc5Sramat mutex_enter(&mdi_mutex); 85033c34adc5Sramat vh->vh_refcnt--; 85043c34adc5Sramat } 85053c34adc5Sramat mutex_exit(&mdi_mutex); 85063c34adc5Sramat } 85078c4f8890Srs135747 85088c4f8890Srs135747 /* 85098c4f8890Srs135747 * mdi_vhci_walk_clients(): 85108c4f8890Srs135747 * Walker routine to traverse client dev_info nodes 85118c4f8890Srs135747 * ddi_walk_devs(ddi_get_child(vdip), f, arg) returns the entire tree 85128c4f8890Srs135747 * below the client, including nexus devices, which we dont want. 85138c4f8890Srs135747 * So we just traverse the immediate siblings, starting from 1st client. 85148c4f8890Srs135747 */ 85158c4f8890Srs135747 void 85168c4f8890Srs135747 mdi_vhci_walk_clients(dev_info_t *vdip, 85178c4f8890Srs135747 int (*f)(dev_info_t *, void *), void *arg) 85188c4f8890Srs135747 { 85198c4f8890Srs135747 dev_info_t *cdip; 85208c4f8890Srs135747 mdi_client_t *ct; 85218c4f8890Srs135747 8522*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 8523*c73a93f2Sdm120769 85248c4f8890Srs135747 cdip = ddi_get_child(vdip); 8525*c73a93f2Sdm120769 85268c4f8890Srs135747 while (cdip) { 85278c4f8890Srs135747 ct = i_devi_get_client(cdip); 85288c4f8890Srs135747 MDI_CLIENT_LOCK(ct); 85298c4f8890Srs135747 8530*c73a93f2Sdm120769 switch ((*f)(cdip, arg)) { 8531*c73a93f2Sdm120769 case DDI_WALK_CONTINUE: 85328c4f8890Srs135747 cdip = ddi_get_next_sibling(cdip); 85338c4f8890Srs135747 MDI_CLIENT_UNLOCK(ct); 8534*c73a93f2Sdm120769 break; 8535*c73a93f2Sdm120769 8536*c73a93f2Sdm120769 default: 8537*c73a93f2Sdm120769 MDI_CLIENT_UNLOCK(ct); 8538*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 8539*c73a93f2Sdm120769 return; 85408c4f8890Srs135747 } 8541*c73a93f2Sdm120769 } 8542*c73a93f2Sdm120769 8543*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 85448c4f8890Srs135747 } 85458c4f8890Srs135747 85468c4f8890Srs135747 /* 85478c4f8890Srs135747 * mdi_vhci_walk_phcis(): 85488c4f8890Srs135747 * Walker routine to traverse phci dev_info nodes 85498c4f8890Srs135747 */ 85508c4f8890Srs135747 void 85518c4f8890Srs135747 mdi_vhci_walk_phcis(dev_info_t *vdip, 85528c4f8890Srs135747 int (*f)(dev_info_t *, void *), void *arg) 85538c4f8890Srs135747 { 8554*c73a93f2Sdm120769 mdi_vhci_t *vh = NULL; 8555*c73a93f2Sdm120769 mdi_phci_t *ph = NULL; 85568c4f8890Srs135747 8557*c73a93f2Sdm120769 mutex_enter(&mdi_mutex); 8558*c73a93f2Sdm120769 8559*c73a93f2Sdm120769 vh = i_devi_get_vhci(vdip); 85608c4f8890Srs135747 ph = vh->vh_phci_head; 8561*c73a93f2Sdm120769 85628c4f8890Srs135747 while (ph) { 85638c4f8890Srs135747 MDI_PHCI_LOCK(ph); 85648c4f8890Srs135747 8565*c73a93f2Sdm120769 switch ((*f)(ph->ph_dip, arg)) { 8566*c73a93f2Sdm120769 case DDI_WALK_CONTINUE: 85678c4f8890Srs135747 MDI_PHCI_UNLOCK(ph); 8568*c73a93f2Sdm120769 ph = ph->ph_next; 8569*c73a93f2Sdm120769 break; 8570*c73a93f2Sdm120769 8571*c73a93f2Sdm120769 default: 8572*c73a93f2Sdm120769 MDI_PHCI_UNLOCK(ph); 8573*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 8574*c73a93f2Sdm120769 return; 85758c4f8890Srs135747 } 8576*c73a93f2Sdm120769 } 8577*c73a93f2Sdm120769 8578*c73a93f2Sdm120769 mutex_exit(&mdi_mutex); 85798c4f8890Srs135747 } 85808c4f8890Srs135747 85818c4f8890Srs135747 85828c4f8890Srs135747 /* 85838c4f8890Srs135747 * mdi_walk_vhcis(): 85848c4f8890Srs135747 * Walker routine to traverse vhci dev_info nodes 85858c4f8890Srs135747 */ 85868c4f8890Srs135747 void 85878c4f8890Srs135747 mdi_walk_vhcis(int (*f)(dev_info_t *, void *), void *arg) 85888c4f8890Srs135747 { 85898c4f8890Srs135747 mdi_vhci_t *vh = NULL; 85908c4f8890Srs135747 85918c4f8890Srs135747 mutex_enter(&mdi_mutex); 85928c4f8890Srs135747 /* 85938c4f8890Srs135747 * Scan for already registered vhci 85948c4f8890Srs135747 */ 85958c4f8890Srs135747 for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 85968c4f8890Srs135747 vh->vh_refcnt++; 85978c4f8890Srs135747 mutex_exit(&mdi_mutex); 85988c4f8890Srs135747 if (((*f)(vh->vh_dip, arg)) != DDI_WALK_CONTINUE) { 85998c4f8890Srs135747 mutex_enter(&mdi_mutex); 86008c4f8890Srs135747 vh->vh_refcnt--; 86018c4f8890Srs135747 break; 86028c4f8890Srs135747 } else { 86038c4f8890Srs135747 mutex_enter(&mdi_mutex); 86048c4f8890Srs135747 vh->vh_refcnt--; 86058c4f8890Srs135747 } 86068c4f8890Srs135747 } 86078c4f8890Srs135747 86088c4f8890Srs135747 mutex_exit(&mdi_mutex); 86098c4f8890Srs135747 } 86108c4f8890Srs135747 86118c4f8890Srs135747 /* 86128c4f8890Srs135747 * i_mdi_log_sysevent(): 86138c4f8890Srs135747 * Logs events for pickup by syseventd 86148c4f8890Srs135747 */ 86158c4f8890Srs135747 static void 86168c4f8890Srs135747 i_mdi_log_sysevent(dev_info_t *dip, char *ph_vh_class, char *subclass) 86178c4f8890Srs135747 { 86188c4f8890Srs135747 char *path_name; 86198c4f8890Srs135747 nvlist_t *attr_list; 86208c4f8890Srs135747 86218c4f8890Srs135747 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 86228c4f8890Srs135747 KM_SLEEP) != DDI_SUCCESS) { 86238c4f8890Srs135747 goto alloc_failed; 86248c4f8890Srs135747 } 86258c4f8890Srs135747 86268c4f8890Srs135747 path_name = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 86278c4f8890Srs135747 (void) ddi_pathname(dip, path_name); 86288c4f8890Srs135747 86298c4f8890Srs135747 if (nvlist_add_string(attr_list, DDI_DRIVER_NAME, 86308c4f8890Srs135747 ddi_driver_name(dip)) != DDI_SUCCESS) { 86318c4f8890Srs135747 goto error; 86328c4f8890Srs135747 } 86338c4f8890Srs135747 86348c4f8890Srs135747 if (nvlist_add_int32(attr_list, DDI_DRIVER_MAJOR, 86358c4f8890Srs135747 (int32_t)ddi_driver_major(dip)) != DDI_SUCCESS) { 86368c4f8890Srs135747 goto error; 86378c4f8890Srs135747 } 86388c4f8890Srs135747 86398c4f8890Srs135747 if (nvlist_add_int32(attr_list, DDI_INSTANCE, 86408c4f8890Srs135747 (int32_t)ddi_get_instance(dip)) != DDI_SUCCESS) { 86418c4f8890Srs135747 goto error; 86428c4f8890Srs135747 } 86438c4f8890Srs135747 86448c4f8890Srs135747 if (nvlist_add_string(attr_list, DDI_PATHNAME, 86458c4f8890Srs135747 path_name) != DDI_SUCCESS) { 86468c4f8890Srs135747 goto error; 86478c4f8890Srs135747 } 86488c4f8890Srs135747 86498c4f8890Srs135747 if (nvlist_add_string(attr_list, DDI_CLASS, 86508c4f8890Srs135747 ph_vh_class) != DDI_SUCCESS) { 86518c4f8890Srs135747 goto error; 86528c4f8890Srs135747 } 86538c4f8890Srs135747 86548c4f8890Srs135747 (void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_DDI, subclass, 86558c4f8890Srs135747 attr_list, NULL, DDI_SLEEP); 86568c4f8890Srs135747 86578c4f8890Srs135747 error: 86588c4f8890Srs135747 kmem_free(path_name, MAXPATHLEN); 86598c4f8890Srs135747 nvlist_free(attr_list); 86608c4f8890Srs135747 return; 86618c4f8890Srs135747 86628c4f8890Srs135747 alloc_failed: 86638c4f8890Srs135747 MDI_DEBUG(1, (CE_WARN, dip, 86648c4f8890Srs135747 "!i_mdi_log_sysevent: Unable to send sysevent")); 86658c4f8890Srs135747 } 8666