17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Multipath driver interface (MDI) implementation; see mdi_impl.h for a more 307c478bd9Sstevel@tonic-gate * detailed discussion of the overall mpxio architecture. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * Default locking order: 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_mutex, mdi_phci::ph_mutex)) 357c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_mutex, mdi_client::ct_mutex)) 367c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 377c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex)) 387c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <sys/note.h> 427c478bd9Sstevel@tonic-gate #include <sys/types.h> 437c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 447c478bd9Sstevel@tonic-gate #include <sys/param.h> 457c478bd9Sstevel@tonic-gate #include <sys/errno.h> 467c478bd9Sstevel@tonic-gate #include <sys/uio.h> 477c478bd9Sstevel@tonic-gate #include <sys/buf.h> 487c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 497c478bd9Sstevel@tonic-gate #include <sys/open.h> 507c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 517c478bd9Sstevel@tonic-gate #include <sys/poll.h> 527c478bd9Sstevel@tonic-gate #include <sys/conf.h> 537c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 557c478bd9Sstevel@tonic-gate #include <sys/stat.h> 567c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 577c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 587c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h> 597c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 607c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 617c478bd9Sstevel@tonic-gate #include <sys/promif.h> 627c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h> 637c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h> 647c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 657c478bd9Sstevel@tonic-gate #include <sys/epm.h> 667c478bd9Sstevel@tonic-gate #include <sys/sunpm.h> 67*3c34adc5Sramat #include <sys/modhash.h> 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #ifdef DEBUG 707c478bd9Sstevel@tonic-gate #include <sys/debug.h> 717c478bd9Sstevel@tonic-gate int mdi_debug = 1; 727c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) \ 737c478bd9Sstevel@tonic-gate if (mdi_debug >= (level)) i_mdi_log stmnt 747c478bd9Sstevel@tonic-gate static void i_mdi_log(int, dev_info_t *, const char *fmt, ...); 757c478bd9Sstevel@tonic-gate #else /* !DEBUG */ 767c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) 777c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; 807c478bd9Sstevel@tonic-gate extern int modrootloaded; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * Global mutex: 847c478bd9Sstevel@tonic-gate * Protects vHCI list and structure members, pHCI and Client lists. 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate kmutex_t mdi_mutex; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * Registered vHCI class driver lists 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate int mdi_vhci_count; 927c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_head; 937c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_tail; 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * Client Hash Table size 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate static int mdi_client_table_size = CLIENT_HASH_TABLE_SIZE; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * taskq interface definitions 1027c478bd9Sstevel@tonic-gate */ 1037c478bd9Sstevel@tonic-gate #define MDI_TASKQ_N_THREADS 8 1047c478bd9Sstevel@tonic-gate #define MDI_TASKQ_PRI minclsyspri 1057c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MINALLOC (4*mdi_taskq_n_threads) 1067c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MAXALLOC (500*mdi_taskq_n_threads) 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate taskq_t *mdi_taskq; 1097c478bd9Sstevel@tonic-gate static uint_t mdi_taskq_n_threads = MDI_TASKQ_N_THREADS; 1107c478bd9Sstevel@tonic-gate 111*3c34adc5Sramat #define TICKS_PER_SECOND (drv_usectohz(1000000)) 112*3c34adc5Sramat 1137c478bd9Sstevel@tonic-gate /* 114*3c34adc5Sramat * The data should be "quiet" for this interval (in seconds) before the 115*3c34adc5Sramat * vhci cached data is flushed to the disk. 1167c478bd9Sstevel@tonic-gate */ 117*3c34adc5Sramat static int mdi_vhcache_flush_delay = 10; 118*3c34adc5Sramat 119*3c34adc5Sramat /* number of seconds the vhcache flush daemon will sleep idle before exiting */ 120*3c34adc5Sramat static int mdi_vhcache_flush_daemon_idle_time = 60; 121*3c34adc5Sramat 122*3c34adc5Sramat /* 123*3c34adc5Sramat * number of seconds the asynchronous configuration thread will sleep idle 124*3c34adc5Sramat * before exiting. 125*3c34adc5Sramat */ 126*3c34adc5Sramat static int mdi_async_config_idle_time = 600; 127*3c34adc5Sramat 128*3c34adc5Sramat static int mdi_bus_config_cache_hash_size = 256; 129*3c34adc5Sramat 130*3c34adc5Sramat /* turns off multithreaded configuration for certain operations */ 131*3c34adc5Sramat static int mdi_mtc_off = 0; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * MDI component property name/value string definitions 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate const char *mdi_component_prop = "mpxio-component"; 1377c478bd9Sstevel@tonic-gate const char *mdi_component_prop_vhci = "vhci"; 1387c478bd9Sstevel@tonic-gate const char *mdi_component_prop_phci = "phci"; 1397c478bd9Sstevel@tonic-gate const char *mdi_component_prop_client = "client"; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /* 1427c478bd9Sstevel@tonic-gate * MDI client global unique identifier property name 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate const char *mdi_client_guid_prop = "client-guid"; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * MDI client load balancing property name/value string definitions 1487c478bd9Sstevel@tonic-gate */ 1497c478bd9Sstevel@tonic-gate const char *mdi_load_balance = "load-balance"; 1507c478bd9Sstevel@tonic-gate const char *mdi_load_balance_none = "none"; 1517c478bd9Sstevel@tonic-gate const char *mdi_load_balance_rr = "round-robin"; 1527c478bd9Sstevel@tonic-gate const char *mdi_load_balance_lba = "logical-block"; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * Obsolete vHCI class definition; to be removed after Leadville update 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate const char *mdi_vhci_class_scsi = MDI_HCI_CLASS_SCSI; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate static char vhci_greeting[] = 1607c478bd9Sstevel@tonic-gate "\tThere already exists one vHCI driver for class %s\n" 1617c478bd9Sstevel@tonic-gate "\tOnly one vHCI driver for each class is allowed\n"; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate /* 1647c478bd9Sstevel@tonic-gate * Static function prototypes 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate static int i_mdi_phci_offline(dev_info_t *, uint_t); 1677c478bd9Sstevel@tonic-gate static int i_mdi_client_offline(dev_info_t *, uint_t); 1687c478bd9Sstevel@tonic-gate static int i_mdi_phci_pre_detach(dev_info_t *, ddi_detach_cmd_t); 1697c478bd9Sstevel@tonic-gate static void i_mdi_phci_post_detach(dev_info_t *, 1707c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 1717c478bd9Sstevel@tonic-gate static int i_mdi_client_pre_detach(dev_info_t *, 1727c478bd9Sstevel@tonic-gate ddi_detach_cmd_t); 1737c478bd9Sstevel@tonic-gate static void i_mdi_client_post_detach(dev_info_t *, 1747c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 1757c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_pip(mdi_pathinfo_t *); 1767c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_pip(mdi_pathinfo_t *); 1777c478bd9Sstevel@tonic-gate static int i_mdi_lba_lb(mdi_client_t *ct, 1787c478bd9Sstevel@tonic-gate mdi_pathinfo_t **ret_pip, struct buf *buf); 1797c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_client(mdi_client_t *, int); 1807c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_client(mdi_client_t *, int); 1817c478bd9Sstevel@tonic-gate static void i_mdi_pm_reset_client(mdi_client_t *); 1827c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_all_phci(mdi_client_t *); 1837c478bd9Sstevel@tonic-gate static int i_mdi_power_all_phci(mdi_client_t *); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * Internal mdi_pathinfo node functions 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate static int i_mdi_pi_kstat_create(mdi_pathinfo_t *); 1907c478bd9Sstevel@tonic-gate static void i_mdi_pi_kstat_destroy(mdi_pathinfo_t *); 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_mdi_vhci_class2vhci(char *); 1937c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_devi_get_vhci(dev_info_t *); 1947c478bd9Sstevel@tonic-gate static mdi_phci_t *i_devi_get_phci(dev_info_t *); 1957c478bd9Sstevel@tonic-gate static void i_mdi_phci_lock(mdi_phci_t *, mdi_pathinfo_t *); 1967c478bd9Sstevel@tonic-gate static void i_mdi_phci_get_client_lock(mdi_phci_t *, 1977c478bd9Sstevel@tonic-gate mdi_client_t *); 1987c478bd9Sstevel@tonic-gate static void i_mdi_phci_unlock(mdi_phci_t *); 199*3c34adc5Sramat static mdi_pathinfo_t *i_mdi_pi_alloc(mdi_phci_t *, char *, mdi_client_t *); 2007c478bd9Sstevel@tonic-gate static void i_mdi_phci_add_path(mdi_phci_t *, mdi_pathinfo_t *); 2017c478bd9Sstevel@tonic-gate static void i_mdi_client_add_path(mdi_client_t *, mdi_pathinfo_t *); 2027c478bd9Sstevel@tonic-gate static void i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *, 2037c478bd9Sstevel@tonic-gate mdi_client_t *); 2047c478bd9Sstevel@tonic-gate static void i_mdi_phci_remove_path(mdi_phci_t *, mdi_pathinfo_t *); 2057c478bd9Sstevel@tonic-gate static void i_mdi_client_remove_path(mdi_client_t *, 2067c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate static int i_mdi_pi_state_change(mdi_pathinfo_t *, 2097c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t, int); 2107c478bd9Sstevel@tonic-gate static int i_mdi_pi_offline(mdi_pathinfo_t *, int); 2117c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_create(mdi_vhci_t *, char *, char *, 212*3c34adc5Sramat char **, int); 2137c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_find(mdi_vhci_t *, char *, char *); 2147c478bd9Sstevel@tonic-gate static int i_mdi_devinfo_remove(dev_info_t *, dev_info_t *, int); 2157c478bd9Sstevel@tonic-gate static int i_mdi_is_child_present(dev_info_t *, dev_info_t *); 216*3c34adc5Sramat static mdi_client_t *i_mdi_client_alloc(mdi_vhci_t *, char *, char *); 2177c478bd9Sstevel@tonic-gate static void i_mdi_client_enlist_table(mdi_vhci_t *, mdi_client_t *); 2187c478bd9Sstevel@tonic-gate static void i_mdi_client_delist_table(mdi_vhci_t *, mdi_client_t *); 219*3c34adc5Sramat static mdi_client_t *i_mdi_client_find(mdi_vhci_t *, char *, char *); 2207c478bd9Sstevel@tonic-gate static void i_mdi_client_update_state(mdi_client_t *); 2217c478bd9Sstevel@tonic-gate static int i_mdi_client_compute_state(mdi_client_t *, 2227c478bd9Sstevel@tonic-gate mdi_phci_t *); 2237c478bd9Sstevel@tonic-gate static void i_mdi_client_lock(mdi_client_t *, mdi_pathinfo_t *); 2247c478bd9Sstevel@tonic-gate static void i_mdi_client_unlock(mdi_client_t *); 2257c478bd9Sstevel@tonic-gate static int i_mdi_client_free(mdi_vhci_t *, mdi_client_t *); 2267c478bd9Sstevel@tonic-gate static mdi_client_t *i_devi_get_client(dev_info_t *); 2277c478bd9Sstevel@tonic-gate static int i_mdi_pi_enable_disable(dev_info_t *, dev_info_t *, int, 2287c478bd9Sstevel@tonic-gate int); 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * Failover related function prototypes 2317c478bd9Sstevel@tonic-gate */ 2327c478bd9Sstevel@tonic-gate static int i_mdi_failover(void *); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* 2357c478bd9Sstevel@tonic-gate * misc internal functions 2367c478bd9Sstevel@tonic-gate */ 2377c478bd9Sstevel@tonic-gate static int i_mdi_get_hash_key(char *); 2387c478bd9Sstevel@tonic-gate static int i_map_nvlist_error_to_mdi(int); 2397c478bd9Sstevel@tonic-gate static void i_mdi_report_path_state(mdi_client_t *, 2407c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 2417c478bd9Sstevel@tonic-gate 242*3c34adc5Sramat static void setup_vhci_cache(mdi_vhci_t *); 243*3c34adc5Sramat static int destroy_vhci_cache(mdi_vhci_t *); 244*3c34adc5Sramat static void setup_phci_driver_list(mdi_vhci_t *); 245*3c34adc5Sramat static void free_phci_driver_list(mdi_vhci_config_t *); 246*3c34adc5Sramat static int stop_vhcache_async_threads(mdi_vhci_config_t *); 247*3c34adc5Sramat static boolean_t stop_vhcache_flush_thread(void *, int); 248*3c34adc5Sramat static void free_string_array(char **, int); 249*3c34adc5Sramat static void free_vhcache_phci(mdi_vhcache_phci_t *); 250*3c34adc5Sramat static void free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *); 251*3c34adc5Sramat static void free_vhcache_client(mdi_vhcache_client_t *); 252*3c34adc5Sramat static int mainnvl_to_vhcache(mdi_vhci_cache_t *, nvlist_t *); 253*3c34adc5Sramat static nvlist_t *vhcache_to_mainnvl(mdi_vhci_cache_t *); 254*3c34adc5Sramat static void vhcache_phci_add(mdi_vhci_config_t *, mdi_phci_t *); 255*3c34adc5Sramat static void vhcache_phci_remove(mdi_vhci_config_t *, mdi_phci_t *); 256*3c34adc5Sramat static void vhcache_pi_add(mdi_vhci_config_t *, 257*3c34adc5Sramat struct mdi_pathinfo *); 258*3c34adc5Sramat static void vhcache_pi_remove(mdi_vhci_config_t *, 259*3c34adc5Sramat struct mdi_pathinfo *); 260*3c34adc5Sramat static void free_phclient_path_list(mdi_phys_path_t *); 261*3c34adc5Sramat static void sort_vhcache_paths(mdi_vhcache_client_t *); 262*3c34adc5Sramat static int flush_vhcache(mdi_vhci_config_t *, int); 263*3c34adc5Sramat static void vhcache_dirty(mdi_vhci_config_t *); 264*3c34adc5Sramat static void free_async_client_config(mdi_async_client_config_t *); 265*3c34adc5Sramat static nvlist_t *read_on_disk_vhci_cache(char *); 266*3c34adc5Sramat extern int fread_nvlist(char *, nvlist_t **); 267*3c34adc5Sramat extern int fwrite_nvlist(char *, nvlist_t *); 268*3c34adc5Sramat 2697c478bd9Sstevel@tonic-gate /* called once when first vhci registers with mdi */ 2707c478bd9Sstevel@tonic-gate static void 2717c478bd9Sstevel@tonic-gate i_mdi_init() 2727c478bd9Sstevel@tonic-gate { 2737c478bd9Sstevel@tonic-gate static int initialized = 0; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate if (initialized) 2767c478bd9Sstevel@tonic-gate return; 2777c478bd9Sstevel@tonic-gate initialized = 1; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate mutex_init(&mdi_mutex, NULL, MUTEX_DEFAULT, NULL); 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * Create our taskq resources 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate mdi_taskq = taskq_create("mdi_taskq", mdi_taskq_n_threads, 2847c478bd9Sstevel@tonic-gate MDI_TASKQ_PRI, MDI_TASKQ_MINALLOC, MDI_TASKQ_MAXALLOC, 2857c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE | TASKQ_CPR_SAFE); 2867c478bd9Sstevel@tonic-gate ASSERT(mdi_taskq != NULL); /* taskq_create never fails */ 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate /* 2907c478bd9Sstevel@tonic-gate * mdi_get_component_type(): 2917c478bd9Sstevel@tonic-gate * Return mpxio component type 2927c478bd9Sstevel@tonic-gate * Return Values: 2937c478bd9Sstevel@tonic-gate * MDI_COMPONENT_NONE 2947c478bd9Sstevel@tonic-gate * MDI_COMPONENT_VHCI 2957c478bd9Sstevel@tonic-gate * MDI_COMPONENT_PHCI 2967c478bd9Sstevel@tonic-gate * MDI_COMPONENT_CLIENT 2977c478bd9Sstevel@tonic-gate * XXX This doesn't work under multi-level MPxIO and should be 2987c478bd9Sstevel@tonic-gate * removed when clients migrate mdi_is_*() interfaces. 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate int 3017c478bd9Sstevel@tonic-gate mdi_get_component_type(dev_info_t *dip) 3027c478bd9Sstevel@tonic-gate { 3037c478bd9Sstevel@tonic-gate return (DEVI(dip)->devi_mdi_component); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * mdi_vhci_register(): 3087c478bd9Sstevel@tonic-gate * Register a vHCI module with the mpxio framework 3097c478bd9Sstevel@tonic-gate * mdi_vhci_register() is called by vHCI drivers to register the 3107c478bd9Sstevel@tonic-gate * 'class_driver' vHCI driver and its MDI entrypoints with the 3117c478bd9Sstevel@tonic-gate * mpxio framework. The vHCI driver must call this interface as 3127c478bd9Sstevel@tonic-gate * part of its attach(9e) handler. 3137c478bd9Sstevel@tonic-gate * Competing threads may try to attach mdi_vhci_register() as 3147c478bd9Sstevel@tonic-gate * the vHCI drivers are loaded and attached as a result of pHCI 3157c478bd9Sstevel@tonic-gate * driver instance registration (mdi_phci_register()) with the 3167c478bd9Sstevel@tonic-gate * framework. 3177c478bd9Sstevel@tonic-gate * Return Values: 3187c478bd9Sstevel@tonic-gate * MDI_SUCCESS 3197c478bd9Sstevel@tonic-gate * MDI_FAILURE 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3237c478bd9Sstevel@tonic-gate int 3247c478bd9Sstevel@tonic-gate mdi_vhci_register(char *class, dev_info_t *vdip, mdi_vhci_ops_t *vops, 3257c478bd9Sstevel@tonic-gate int flags) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate ASSERT(vops->vo_revision == MDI_VHCI_OPS_REV); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate i_mdi_init(); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * Scan for already registered vhci 3367c478bd9Sstevel@tonic-gate */ 3377c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 3387c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * vHCI has already been created. Check for valid 3417c478bd9Sstevel@tonic-gate * vHCI ops registration. We only support one vHCI 3427c478bd9Sstevel@tonic-gate * module per class 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate if (vh->vh_ops != NULL) { 3457c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 3467c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, vhci_greeting, class); 3477c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate break; 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * if not yet created, create the vHCI component 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate if (vh == NULL) { 3577c478bd9Sstevel@tonic-gate struct client_hash *hash = NULL; 3587c478bd9Sstevel@tonic-gate char *load_balance; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * Allocate and initialize the mdi extensions 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate vh = kmem_zalloc(sizeof (mdi_vhci_t), KM_SLEEP); 3647c478bd9Sstevel@tonic-gate hash = kmem_zalloc(mdi_client_table_size * sizeof (*hash), 3657c478bd9Sstevel@tonic-gate KM_SLEEP); 3667c478bd9Sstevel@tonic-gate vh->vh_client_table = hash; 3677c478bd9Sstevel@tonic-gate vh->vh_class = kmem_zalloc(strlen(class) + 1, KM_SLEEP); 3687c478bd9Sstevel@tonic-gate (void) strcpy(vh->vh_class, class); 3697c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_RR; 3707c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vdip, 3717c478bd9Sstevel@tonic-gate 0, LOAD_BALANCE_PROP, &load_balance) == DDI_SUCCESS) { 3727c478bd9Sstevel@tonic-gate if (strcmp(load_balance, LOAD_BALANCE_PROP_NONE) == 0) { 3737c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_NONE; 3747c478bd9Sstevel@tonic-gate } else if (strcmp(load_balance, LOAD_BALANCE_PROP_LBA) 3757c478bd9Sstevel@tonic-gate == 0) { 3767c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_LBA; 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate ddi_prop_free(load_balance); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * Store the vHCI ops vectors 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate vh->vh_dip = vdip; 3857c478bd9Sstevel@tonic-gate vh->vh_ops = vops; 3867c478bd9Sstevel@tonic-gate 387*3c34adc5Sramat setup_vhci_cache(vh); 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate if (mdi_vhci_head == NULL) { 3907c478bd9Sstevel@tonic-gate mdi_vhci_head = vh; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate if (mdi_vhci_tail) { 3937c478bd9Sstevel@tonic-gate mdi_vhci_tail->vh_next = vh; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate mdi_vhci_tail = vh; 3967c478bd9Sstevel@tonic-gate mdi_vhci_count++; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* 4007c478bd9Sstevel@tonic-gate * Claim the devfs node as a vhci component 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component |= MDI_COMPONENT_VHCI; 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* 4057c478bd9Sstevel@tonic-gate * Initialize our back reference from dev_info node 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = (caddr_t)vh; 4087c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4097c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * mdi_vhci_unregister(): 4147c478bd9Sstevel@tonic-gate * Unregister a vHCI module from mpxio framework 4157c478bd9Sstevel@tonic-gate * mdi_vhci_unregister() is called from the detach(9E) entrypoint 4167c478bd9Sstevel@tonic-gate * of a vhci to unregister it from the framework. 4177c478bd9Sstevel@tonic-gate * Return Values: 4187c478bd9Sstevel@tonic-gate * MDI_SUCCESS 4197c478bd9Sstevel@tonic-gate * MDI_FAILURE 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4237c478bd9Sstevel@tonic-gate int 4247c478bd9Sstevel@tonic-gate mdi_vhci_unregister(dev_info_t *vdip, int flags) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate mdi_vhci_t *found, *vh, *prev = NULL; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* 4297c478bd9Sstevel@tonic-gate * Check for invalid VHCI 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate if ((vh = i_devi_get_vhci(vdip)) == NULL) 4327c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * Scan the list of registered vHCIs for a match 4387c478bd9Sstevel@tonic-gate */ 4397c478bd9Sstevel@tonic-gate for (found = mdi_vhci_head; found != NULL; found = found->vh_next) { 4407c478bd9Sstevel@tonic-gate if (found == vh) 4417c478bd9Sstevel@tonic-gate break; 4427c478bd9Sstevel@tonic-gate prev = found; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate if (found == NULL) { 4467c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4477c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * Check the pHCI and client count. All the pHCIs and clients 4527c478bd9Sstevel@tonic-gate * should have been unregistered, before a vHCI can be 4537c478bd9Sstevel@tonic-gate * unregistered. 4547c478bd9Sstevel@tonic-gate */ 455*3c34adc5Sramat if (vh->vh_phci_count || vh->vh_client_count || vh->vh_refcnt) { 4567c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 4577c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * Remove the vHCI from the global list 4627c478bd9Sstevel@tonic-gate */ 4637c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_head) { 4647c478bd9Sstevel@tonic-gate mdi_vhci_head = vh->vh_next; 4657c478bd9Sstevel@tonic-gate } else { 4667c478bd9Sstevel@tonic-gate prev->vh_next = vh->vh_next; 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_tail) { 4697c478bd9Sstevel@tonic-gate mdi_vhci_tail = prev; 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate mdi_vhci_count--; 4737c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 474*3c34adc5Sramat 475*3c34adc5Sramat if (destroy_vhci_cache(vh) != MDI_SUCCESS) { 476*3c34adc5Sramat /* add vhci to the global list */ 477*3c34adc5Sramat mutex_enter(&mdi_mutex); 478*3c34adc5Sramat if (mdi_vhci_head == NULL) 479*3c34adc5Sramat mdi_vhci_head = vh; 480*3c34adc5Sramat else 481*3c34adc5Sramat mdi_vhci_tail->vh_next = vh; 482*3c34adc5Sramat mdi_vhci_tail = vh; 483*3c34adc5Sramat mdi_vhci_count++; 484*3c34adc5Sramat mutex_exit(&mdi_mutex); 485*3c34adc5Sramat return (MDI_FAILURE); 486*3c34adc5Sramat } 487*3c34adc5Sramat 488*3c34adc5Sramat vh->vh_ops = NULL; 4897c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component &= ~MDI_COMPONENT_VHCI; 4907c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = NULL; 4917c478bd9Sstevel@tonic-gate kmem_free(vh->vh_class, strlen(vh->vh_class)+1); 4927c478bd9Sstevel@tonic-gate kmem_free(vh->vh_client_table, 4937c478bd9Sstevel@tonic-gate mdi_client_table_size * sizeof (struct client_hash)); 4947c478bd9Sstevel@tonic-gate kmem_free(vh, sizeof (mdi_vhci_t)); 4957c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate /* 4997c478bd9Sstevel@tonic-gate * i_mdi_vhci_class2vhci(): 5007c478bd9Sstevel@tonic-gate * Look for a matching vHCI module given a vHCI class name 5017c478bd9Sstevel@tonic-gate * Return Values: 5027c478bd9Sstevel@tonic-gate * Handle to a vHCI component 5037c478bd9Sstevel@tonic-gate * NULL 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate static mdi_vhci_t * 5067c478bd9Sstevel@tonic-gate i_mdi_vhci_class2vhci(char *class) 5077c478bd9Sstevel@tonic-gate { 5087c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&mdi_mutex)); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 5137c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 5147c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 5157c478bd9Sstevel@tonic-gate break; 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 5197c478bd9Sstevel@tonic-gate return (vh); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate /* 5237c478bd9Sstevel@tonic-gate * i_devi_get_vhci(): 5247c478bd9Sstevel@tonic-gate * Utility function to get the handle to a vHCI component 5257c478bd9Sstevel@tonic-gate * Return Values: 5267c478bd9Sstevel@tonic-gate * Handle to a vHCI component 5277c478bd9Sstevel@tonic-gate * NULL 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate mdi_vhci_t * 5307c478bd9Sstevel@tonic-gate i_devi_get_vhci(dev_info_t *vdip) 5317c478bd9Sstevel@tonic-gate { 5327c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 5337c478bd9Sstevel@tonic-gate if (MDI_VHCI(vdip)) { 5347c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci; 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate return (vh); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * mdi_phci_register(): 5417c478bd9Sstevel@tonic-gate * Register a pHCI module with mpxio framework 5427c478bd9Sstevel@tonic-gate * mdi_phci_register() is called by pHCI drivers to register with 5437c478bd9Sstevel@tonic-gate * the mpxio framework and a specific 'class_driver' vHCI. The 5447c478bd9Sstevel@tonic-gate * pHCI driver must call this interface as part of its attach(9e) 5457c478bd9Sstevel@tonic-gate * handler. 5467c478bd9Sstevel@tonic-gate * Return Values: 5477c478bd9Sstevel@tonic-gate * MDI_SUCCESS 5487c478bd9Sstevel@tonic-gate * MDI_FAILURE 5497c478bd9Sstevel@tonic-gate */ 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5527c478bd9Sstevel@tonic-gate int 5537c478bd9Sstevel@tonic-gate mdi_phci_register(char *class, dev_info_t *pdip, int flags) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 5567c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 5577c478bd9Sstevel@tonic-gate char *data; 5587c478bd9Sstevel@tonic-gate char *pathname; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 5617c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, pathname); 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate /* 5647c478bd9Sstevel@tonic-gate * Check for mpxio-disable property. Enable mpxio if the property is 5657c478bd9Sstevel@tonic-gate * missing or not set to "yes". 5667c478bd9Sstevel@tonic-gate * If the property is set to "yes" then emit a brief message. 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0, "mpxio-disable", 5697c478bd9Sstevel@tonic-gate &data) == DDI_SUCCESS)) { 5707c478bd9Sstevel@tonic-gate if (strcmp(data, "yes") == 0) { 5717c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_CONT, pdip, 5727c478bd9Sstevel@tonic-gate "?%s (%s%d) multipath capabilities " 5737c478bd9Sstevel@tonic-gate "disabled via %s.conf.\n", pathname, 5747c478bd9Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip), 5757c478bd9Sstevel@tonic-gate ddi_driver_name(pdip))); 5767c478bd9Sstevel@tonic-gate ddi_prop_free(data); 5777c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 5787c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate ddi_prop_free(data); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate * Search for a matching vHCI 5877c478bd9Sstevel@tonic-gate */ 5887c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)i_mdi_vhci_class2vhci(class); 5897c478bd9Sstevel@tonic-gate if (vh == NULL) { 5907c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate ph = kmem_zalloc(sizeof (mdi_phci_t), KM_SLEEP); 5947c478bd9Sstevel@tonic-gate mutex_init(&ph->ph_mutex, NULL, MUTEX_DEFAULT, NULL); 5957c478bd9Sstevel@tonic-gate ph->ph_dip = pdip; 5967c478bd9Sstevel@tonic-gate ph->ph_vhci = vh; 5977c478bd9Sstevel@tonic-gate ph->ph_next = NULL; 5987c478bd9Sstevel@tonic-gate ph->ph_unstable = 0; 5997c478bd9Sstevel@tonic-gate ph->ph_vprivate = 0; 6007c478bd9Sstevel@tonic-gate cv_init(&ph->ph_unstable_cv, NULL, CV_DRIVER, NULL); 6017c478bd9Sstevel@tonic-gate cv_init(&ph->ph_powerchange_cv, NULL, CV_DRIVER, NULL); 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate MDI_PHCI_SET_POWER_UP(ph); 6047c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component |= MDI_COMPONENT_PHCI; 6057c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = (caddr_t)ph; 6067c478bd9Sstevel@tonic-gate 607*3c34adc5Sramat vhcache_phci_add(vh->vh_config, ph); 608*3c34adc5Sramat 6097c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 6107c478bd9Sstevel@tonic-gate if (vh->vh_phci_head == NULL) { 6117c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate if (vh->vh_phci_tail) { 6147c478bd9Sstevel@tonic-gate vh->vh_phci_tail->ph_next = ph; 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate vh->vh_phci_tail = ph; 6177c478bd9Sstevel@tonic-gate vh->vh_phci_count++; 6187c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6197c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate /* 6237c478bd9Sstevel@tonic-gate * mdi_phci_unregister(): 6247c478bd9Sstevel@tonic-gate * Unregister a pHCI module from mpxio framework 6257c478bd9Sstevel@tonic-gate * mdi_phci_unregister() is called by the pHCI drivers from their 6267c478bd9Sstevel@tonic-gate * detach(9E) handler to unregister their instances from the 6277c478bd9Sstevel@tonic-gate * framework. 6287c478bd9Sstevel@tonic-gate * Return Values: 6297c478bd9Sstevel@tonic-gate * MDI_SUCCESS 6307c478bd9Sstevel@tonic-gate * MDI_FAILURE 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6347c478bd9Sstevel@tonic-gate int 6357c478bd9Sstevel@tonic-gate mdi_phci_unregister(dev_info_t *pdip, int flags) 6367c478bd9Sstevel@tonic-gate { 6377c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 6387c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 6397c478bd9Sstevel@tonic-gate mdi_phci_t *tmp; 6407c478bd9Sstevel@tonic-gate mdi_phci_t *prev = NULL; 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 6437c478bd9Sstevel@tonic-gate if (ph == NULL) { 6447c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 6457c478bd9Sstevel@tonic-gate "!pHCI unregister: Not a valid pHCI")); 6467c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 6507c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 6517c478bd9Sstevel@tonic-gate if (vh == NULL) { 6527c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 6537c478bd9Sstevel@tonic-gate "!pHCI unregister: Not a valid vHCI")); 6547c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 6587c478bd9Sstevel@tonic-gate tmp = vh->vh_phci_head; 6597c478bd9Sstevel@tonic-gate while (tmp) { 6607c478bd9Sstevel@tonic-gate if (tmp == ph) { 6617c478bd9Sstevel@tonic-gate break; 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate prev = tmp; 6647c478bd9Sstevel@tonic-gate tmp = tmp->ph_next; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_head) { 6687c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph->ph_next; 6697c478bd9Sstevel@tonic-gate } else { 6707c478bd9Sstevel@tonic-gate prev->ph_next = ph->ph_next; 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_tail) { 6747c478bd9Sstevel@tonic-gate vh->vh_phci_tail = prev; 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate vh->vh_phci_count--; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6807c478bd9Sstevel@tonic-gate 681*3c34adc5Sramat vhcache_phci_remove(vh->vh_config, ph); 6827c478bd9Sstevel@tonic-gate cv_destroy(&ph->ph_unstable_cv); 6837c478bd9Sstevel@tonic-gate cv_destroy(&ph->ph_powerchange_cv); 6847c478bd9Sstevel@tonic-gate mutex_destroy(&ph->ph_mutex); 6857c478bd9Sstevel@tonic-gate kmem_free(ph, sizeof (mdi_phci_t)); 6867c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component &= ~MDI_COMPONENT_PHCI; 6877c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = NULL; 6887c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * i_devi_get_phci(): 6937c478bd9Sstevel@tonic-gate * Utility function to return the phci extensions. 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate static mdi_phci_t * 6967c478bd9Sstevel@tonic-gate i_devi_get_phci(dev_info_t *pdip) 6977c478bd9Sstevel@tonic-gate { 6987c478bd9Sstevel@tonic-gate mdi_phci_t *ph = NULL; 6997c478bd9Sstevel@tonic-gate if (MDI_PHCI(pdip)) { 7007c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(pdip)->devi_mdi_xhci; 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate return (ph); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* 7067c478bd9Sstevel@tonic-gate * mdi_phci_path2devinfo(): 7077c478bd9Sstevel@tonic-gate * Utility function to search for a valid phci device given 7087c478bd9Sstevel@tonic-gate * the devfs pathname. 7097c478bd9Sstevel@tonic-gate */ 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate dev_info_t * 7127c478bd9Sstevel@tonic-gate mdi_phci_path2devinfo(dev_info_t *vdip, caddr_t pathname) 7137c478bd9Sstevel@tonic-gate { 7147c478bd9Sstevel@tonic-gate char *temp_pathname; 7157c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 7167c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 7177c478bd9Sstevel@tonic-gate dev_info_t *pdip = NULL; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate vh = i_devi_get_vhci(vdip); 7207c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate if (vh == NULL) { 7237c478bd9Sstevel@tonic-gate /* 7247c478bd9Sstevel@tonic-gate * Invalid vHCI component, return failure 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate return (NULL); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7307c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 7317c478bd9Sstevel@tonic-gate ph = vh->vh_phci_head; 7327c478bd9Sstevel@tonic-gate while (ph != NULL) { 7337c478bd9Sstevel@tonic-gate pdip = ph->ph_dip; 7347c478bd9Sstevel@tonic-gate ASSERT(pdip != NULL); 7357c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 7367c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, temp_pathname); 7377c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 7387c478bd9Sstevel@tonic-gate break; 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate ph = ph->ph_next; 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate if (ph == NULL) { 7437c478bd9Sstevel@tonic-gate pdip = NULL; 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 7467c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 7477c478bd9Sstevel@tonic-gate return (pdip); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * mdi_phci_get_path_count(): 7527c478bd9Sstevel@tonic-gate * get number of path information nodes associated with a given 7537c478bd9Sstevel@tonic-gate * pHCI device. 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate int 7567c478bd9Sstevel@tonic-gate mdi_phci_get_path_count(dev_info_t *pdip) 7577c478bd9Sstevel@tonic-gate { 7587c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 7597c478bd9Sstevel@tonic-gate int count = 0; 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 7627c478bd9Sstevel@tonic-gate if (ph != NULL) { 7637c478bd9Sstevel@tonic-gate count = ph->ph_path_count; 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate return (count); 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate /* 7697c478bd9Sstevel@tonic-gate * i_mdi_phci_lock(): 7707c478bd9Sstevel@tonic-gate * Lock a pHCI device 7717c478bd9Sstevel@tonic-gate * Return Values: 7727c478bd9Sstevel@tonic-gate * None 7737c478bd9Sstevel@tonic-gate * Note: 7747c478bd9Sstevel@tonic-gate * The default locking order is: 7757c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 7767c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 7777c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 7787c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 7797c478bd9Sstevel@tonic-gate */ 7807c478bd9Sstevel@tonic-gate static void 7817c478bd9Sstevel@tonic-gate i_mdi_phci_lock(mdi_phci_t *ph, mdi_pathinfo_t *pip) 7827c478bd9Sstevel@tonic-gate { 7837c478bd9Sstevel@tonic-gate if (pip) { 7847c478bd9Sstevel@tonic-gate /* Reverse locking is requested. */ 7857c478bd9Sstevel@tonic-gate while (MDI_PHCI_TRYLOCK(ph) == 0) { 7867c478bd9Sstevel@tonic-gate /* 7877c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 7887c478bd9Sstevel@tonic-gate * after a small delay 7897c478bd9Sstevel@tonic-gate */ 7907c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 7917c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 7927c478bd9Sstevel@tonic-gate delay(1); 7937c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 7947c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate } else { 7977c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * i_mdi_phci_get_client_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_client::ct_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_get_client_lock(mdi_phci_t *ph, mdi_client_t *ct) 8157c478bd9Sstevel@tonic-gate { 8167c478bd9Sstevel@tonic-gate if (ct) { 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_CLIENT_UNLOCK(ct); 8247c478bd9Sstevel@tonic-gate delay(1); 8257c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate } else { 8287c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* 8337c478bd9Sstevel@tonic-gate * i_mdi_phci_unlock(): 8347c478bd9Sstevel@tonic-gate * Unlock the pHCI component 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate static void 8377c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(mdi_phci_t *ph) 8387c478bd9Sstevel@tonic-gate { 8397c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate /* 8437c478bd9Sstevel@tonic-gate * i_mdi_devinfo_create(): 8447c478bd9Sstevel@tonic-gate * create client device's devinfo node 8457c478bd9Sstevel@tonic-gate * Return Values: 8467c478bd9Sstevel@tonic-gate * dev_info 8477c478bd9Sstevel@tonic-gate * NULL 8487c478bd9Sstevel@tonic-gate * Notes: 8497c478bd9Sstevel@tonic-gate */ 8507c478bd9Sstevel@tonic-gate static dev_info_t * 8517c478bd9Sstevel@tonic-gate i_mdi_devinfo_create(mdi_vhci_t *vh, char *name, char *guid, 852*3c34adc5Sramat char **compatible, int ncompatible) 8537c478bd9Sstevel@tonic-gate { 8547c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate /* Verify for duplicate entry */ 8597c478bd9Sstevel@tonic-gate cdip = i_mdi_devinfo_find(vh, name, guid); 8607c478bd9Sstevel@tonic-gate ASSERT(cdip == NULL); 8617c478bd9Sstevel@tonic-gate if (cdip) { 8627c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8637c478bd9Sstevel@tonic-gate "i_mdi_devinfo_create: client dip %p already exists", 8647c478bd9Sstevel@tonic-gate (void *)cdip); 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 867*3c34adc5Sramat ndi_devi_alloc_sleep(vh->vh_dip, name, DEVI_SID_NODEID, &cdip); 8687c478bd9Sstevel@tonic-gate if (cdip == NULL) 8697c478bd9Sstevel@tonic-gate goto fail; 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate /* 8727c478bd9Sstevel@tonic-gate * Create component type and Global unique identifier 8737c478bd9Sstevel@tonic-gate * properties 8747c478bd9Sstevel@tonic-gate */ 8757c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, 8767c478bd9Sstevel@tonic-gate MDI_CLIENT_GUID_PROP, guid) != DDI_PROP_SUCCESS) { 8777c478bd9Sstevel@tonic-gate goto fail; 8787c478bd9Sstevel@tonic-gate } 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate /* Decorate the node with compatible property */ 8817c478bd9Sstevel@tonic-gate if (compatible && 8827c478bd9Sstevel@tonic-gate (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip, 8837c478bd9Sstevel@tonic-gate "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS)) { 8847c478bd9Sstevel@tonic-gate goto fail; 8857c478bd9Sstevel@tonic-gate } 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate return (cdip); 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate fail: 8907c478bd9Sstevel@tonic-gate if (cdip) { 8917c478bd9Sstevel@tonic-gate (void) ndi_prop_remove_all(cdip); 8927c478bd9Sstevel@tonic-gate (void) ndi_devi_free(cdip); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate return (NULL); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * i_mdi_devinfo_find(): 8997c478bd9Sstevel@tonic-gate * Find a matching devinfo node for given client node name 9007c478bd9Sstevel@tonic-gate * and its guid. 9017c478bd9Sstevel@tonic-gate * Return Values: 9027c478bd9Sstevel@tonic-gate * Handle to a dev_info node or NULL 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate static dev_info_t * 9067c478bd9Sstevel@tonic-gate i_mdi_devinfo_find(mdi_vhci_t *vh, caddr_t name, char *guid) 9077c478bd9Sstevel@tonic-gate { 9087c478bd9Sstevel@tonic-gate char *data; 9097c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 9107c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 9117c478bd9Sstevel@tonic-gate int circular; 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate ndi_devi_enter(vh->vh_dip, &circular); 9147c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vh->vh_dip)->devi_child; 9157c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 9167c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate if (strcmp(DEVI(cdip)->devi_node_name, name)) { 9197c478bd9Sstevel@tonic-gate continue; 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip, 9237c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, MDI_CLIENT_GUID_PROP, 9247c478bd9Sstevel@tonic-gate &data) != DDI_PROP_SUCCESS) { 9257c478bd9Sstevel@tonic-gate continue; 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate if (strcmp(data, guid) != 0) { 9297c478bd9Sstevel@tonic-gate ddi_prop_free(data); 9307c478bd9Sstevel@tonic-gate continue; 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate ddi_prop_free(data); 9337c478bd9Sstevel@tonic-gate break; 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate ndi_devi_exit(vh->vh_dip, circular); 9367c478bd9Sstevel@tonic-gate return (cdip); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate /* 9407c478bd9Sstevel@tonic-gate * i_mdi_devinfo_remove(): 9417c478bd9Sstevel@tonic-gate * Remove a client device node 9427c478bd9Sstevel@tonic-gate */ 9437c478bd9Sstevel@tonic-gate static int 9447c478bd9Sstevel@tonic-gate i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags) 9457c478bd9Sstevel@tonic-gate { 9467c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 9477c478bd9Sstevel@tonic-gate if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS || 9487c478bd9Sstevel@tonic-gate (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) { 9497c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 9507c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 9517c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_devinfo_remove:" 9527c478bd9Sstevel@tonic-gate " failed. cdip = %p\n", cdip)); 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * Convert to MDI error code 9567c478bd9Sstevel@tonic-gate */ 9577c478bd9Sstevel@tonic-gate switch (rv) { 9587c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 9597c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 9607c478bd9Sstevel@tonic-gate break; 9617c478bd9Sstevel@tonic-gate case NDI_BUSY: 9627c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 9637c478bd9Sstevel@tonic-gate break; 9647c478bd9Sstevel@tonic-gate default: 9657c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 9667c478bd9Sstevel@tonic-gate break; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate return (rv); 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * i_devi_get_client() 9747c478bd9Sstevel@tonic-gate * Utility function to get mpxio component extensions 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate static mdi_client_t * 9777c478bd9Sstevel@tonic-gate i_devi_get_client(dev_info_t *cdip) 9787c478bd9Sstevel@tonic-gate { 9797c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 9807c478bd9Sstevel@tonic-gate if (MDI_CLIENT(cdip)) { 9817c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(cdip)->devi_mdi_client; 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate return (ct); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate /* 9877c478bd9Sstevel@tonic-gate * i_mdi_is_child_present(): 9887c478bd9Sstevel@tonic-gate * Search for the presence of client device dev_info node 9897c478bd9Sstevel@tonic-gate */ 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate static int 9927c478bd9Sstevel@tonic-gate i_mdi_is_child_present(dev_info_t *vdip, dev_info_t *cdip) 9937c478bd9Sstevel@tonic-gate { 9947c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 9957c478bd9Sstevel@tonic-gate struct dev_info *dip; 9967c478bd9Sstevel@tonic-gate int circular; 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 9997c478bd9Sstevel@tonic-gate dip = DEVI(vdip)->devi_child; 10007c478bd9Sstevel@tonic-gate while (dip) { 10017c478bd9Sstevel@tonic-gate if (dip == DEVI(cdip)) { 10027c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 10037c478bd9Sstevel@tonic-gate break; 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate dip = dip->devi_sibling; 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 10087c478bd9Sstevel@tonic-gate return (rv); 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate /* 10137c478bd9Sstevel@tonic-gate * i_mdi_client_lock(): 10147c478bd9Sstevel@tonic-gate * Grab client component lock 10157c478bd9Sstevel@tonic-gate * Return Values: 10167c478bd9Sstevel@tonic-gate * None 10177c478bd9Sstevel@tonic-gate * Note: 10187c478bd9Sstevel@tonic-gate * The default locking order is: 10197c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 10207c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 10217c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 10227c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 10237c478bd9Sstevel@tonic-gate */ 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate static void 10267c478bd9Sstevel@tonic-gate i_mdi_client_lock(mdi_client_t *ct, mdi_pathinfo_t *pip) 10277c478bd9Sstevel@tonic-gate { 10287c478bd9Sstevel@tonic-gate if (pip) { 10297c478bd9Sstevel@tonic-gate /* 10307c478bd9Sstevel@tonic-gate * Reverse locking is requested. 10317c478bd9Sstevel@tonic-gate */ 10327c478bd9Sstevel@tonic-gate while (MDI_CLIENT_TRYLOCK(ct) == 0) { 10337c478bd9Sstevel@tonic-gate /* 10347c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 10357c478bd9Sstevel@tonic-gate * after a small delay 10367c478bd9Sstevel@tonic-gate */ 10377c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 10387c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 10397c478bd9Sstevel@tonic-gate delay(1); 10407c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 10417c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate } else { 10447c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate /* 10497c478bd9Sstevel@tonic-gate * i_mdi_client_unlock(): 10507c478bd9Sstevel@tonic-gate * Unlock a client component 10517c478bd9Sstevel@tonic-gate */ 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate static void 10547c478bd9Sstevel@tonic-gate i_mdi_client_unlock(mdi_client_t *ct) 10557c478bd9Sstevel@tonic-gate { 10567c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate /* 10607c478bd9Sstevel@tonic-gate * i_mdi_client_alloc(): 10617c478bd9Sstevel@tonic-gate * Allocate and initialize a client structure. Caller should 10627c478bd9Sstevel@tonic-gate * hold the global mdi_mutex. 10637c478bd9Sstevel@tonic-gate * Return Values: 10647c478bd9Sstevel@tonic-gate * Handle to a client component 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10677c478bd9Sstevel@tonic-gate static mdi_client_t * 1068*3c34adc5Sramat i_mdi_client_alloc(mdi_vhci_t *vh, char *name, char *lguid) 10697c478bd9Sstevel@tonic-gate { 10707c478bd9Sstevel@tonic-gate mdi_client_t *ct; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate /* 10757c478bd9Sstevel@tonic-gate * Allocate and initialize a component structure. 10767c478bd9Sstevel@tonic-gate */ 1077*3c34adc5Sramat ct = kmem_zalloc(sizeof (*ct), KM_SLEEP); 10787c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); 10797c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 10807c478bd9Sstevel@tonic-gate ct->ct_hprev = NULL; 10817c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 10827c478bd9Sstevel@tonic-gate ct->ct_vhci = vh; 1083*3c34adc5Sramat ct->ct_drvname = kmem_alloc(strlen(name) + 1, KM_SLEEP); 10847c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_drvname, name); 1085*3c34adc5Sramat ct->ct_guid = kmem_alloc(strlen(lguid) + 1, KM_SLEEP); 10867c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_guid, lguid); 10877c478bd9Sstevel@tonic-gate ct->ct_cprivate = NULL; 10887c478bd9Sstevel@tonic-gate ct->ct_vprivate = NULL; 10897c478bd9Sstevel@tonic-gate ct->ct_flags = 0; 10907c478bd9Sstevel@tonic-gate ct->ct_state = MDI_CLIENT_STATE_FAILED; 10917c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 10927c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 10937c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 10947c478bd9Sstevel@tonic-gate ct->ct_failover_flags = 0; 10957c478bd9Sstevel@tonic-gate ct->ct_failover_status = 0; 10967c478bd9Sstevel@tonic-gate cv_init(&ct->ct_failover_cv, NULL, CV_DRIVER, NULL); 10977c478bd9Sstevel@tonic-gate ct->ct_unstable = 0; 10987c478bd9Sstevel@tonic-gate cv_init(&ct->ct_unstable_cv, NULL, CV_DRIVER, NULL); 10997c478bd9Sstevel@tonic-gate cv_init(&ct->ct_powerchange_cv, NULL, CV_DRIVER, NULL); 11007c478bd9Sstevel@tonic-gate ct->ct_lb = vh->vh_lb; 1101*3c34adc5Sramat ct->ct_lb_args = kmem_zalloc(sizeof (client_lb_args_t), KM_SLEEP); 11027c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = LOAD_BALANCE_DEFAULT_REGION_SIZE; 11037c478bd9Sstevel@tonic-gate ct->ct_path_count = 0; 11047c478bd9Sstevel@tonic-gate ct->ct_path_head = NULL; 11057c478bd9Sstevel@tonic-gate ct->ct_path_tail = NULL; 11067c478bd9Sstevel@tonic-gate ct->ct_path_last = NULL; 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate /* 11097c478bd9Sstevel@tonic-gate * Add this client component to our client hash queue 11107c478bd9Sstevel@tonic-gate */ 11117c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(vh, ct); 11127c478bd9Sstevel@tonic-gate return (ct); 11137c478bd9Sstevel@tonic-gate } 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate /* 11167c478bd9Sstevel@tonic-gate * i_mdi_client_enlist_table(): 11177c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. Caller 11187c478bd9Sstevel@tonic-gate * should hold the mdi_mutex 11197c478bd9Sstevel@tonic-gate */ 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate static void 11227c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(mdi_vhci_t *vh, mdi_client_t *ct) 11237c478bd9Sstevel@tonic-gate { 11247c478bd9Sstevel@tonic-gate int index; 11257c478bd9Sstevel@tonic-gate struct client_hash *head; 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 11287c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(ct->ct_guid); 11297c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 11307c478bd9Sstevel@tonic-gate ct->ct_hnext = (mdi_client_t *)head->ct_hash_head; 11317c478bd9Sstevel@tonic-gate head->ct_hash_head = ct; 11327c478bd9Sstevel@tonic-gate head->ct_hash_count++; 11337c478bd9Sstevel@tonic-gate vh->vh_client_count++; 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * i_mdi_client_delist_table(): 11387c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. 11397c478bd9Sstevel@tonic-gate * Caller should hold the mdi_mutex 11407c478bd9Sstevel@tonic-gate */ 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate static void 11437c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(mdi_vhci_t *vh, mdi_client_t *ct) 11447c478bd9Sstevel@tonic-gate { 11457c478bd9Sstevel@tonic-gate int index; 11467c478bd9Sstevel@tonic-gate char *guid; 11477c478bd9Sstevel@tonic-gate struct client_hash *head; 11487c478bd9Sstevel@tonic-gate mdi_client_t *next; 11497c478bd9Sstevel@tonic-gate mdi_client_t *last; 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 11527c478bd9Sstevel@tonic-gate guid = ct->ct_guid; 11537c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 11547c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate last = NULL; 11577c478bd9Sstevel@tonic-gate next = (mdi_client_t *)head->ct_hash_head; 11587c478bd9Sstevel@tonic-gate while (next != NULL) { 11597c478bd9Sstevel@tonic-gate if (next == ct) { 11607c478bd9Sstevel@tonic-gate break; 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate last = next; 11637c478bd9Sstevel@tonic-gate next = next->ct_hnext; 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate if (next) { 11677c478bd9Sstevel@tonic-gate head->ct_hash_count--; 11687c478bd9Sstevel@tonic-gate if (last == NULL) { 11697c478bd9Sstevel@tonic-gate head->ct_hash_head = ct->ct_hnext; 11707c478bd9Sstevel@tonic-gate } else { 11717c478bd9Sstevel@tonic-gate last->ct_hnext = ct->ct_hnext; 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 11747c478bd9Sstevel@tonic-gate vh->vh_client_count--; 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate /* 11807c478bd9Sstevel@tonic-gate * i_mdi_client_free(): 11817c478bd9Sstevel@tonic-gate * Free a client component 11827c478bd9Sstevel@tonic-gate */ 11837c478bd9Sstevel@tonic-gate static int 11847c478bd9Sstevel@tonic-gate i_mdi_client_free(mdi_vhci_t *vh, mdi_client_t *ct) 11857c478bd9Sstevel@tonic-gate { 11867c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 11877c478bd9Sstevel@tonic-gate int flags = ct->ct_flags; 11887c478bd9Sstevel@tonic-gate dev_info_t *cdip; 11897c478bd9Sstevel@tonic-gate dev_info_t *vdip; 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 11927c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 11937c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, MDI_CLIENT_GUID_PROP); 11967c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component &= ~MDI_COMPONENT_CLIENT; 11977c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = NULL; 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * Clear out back ref. to dev_info_t node 12017c478bd9Sstevel@tonic-gate */ 12027c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate /* 12057c478bd9Sstevel@tonic-gate * Remove this client from our hash queue 12067c478bd9Sstevel@tonic-gate */ 12077c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(vh, ct); 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate /* 12107c478bd9Sstevel@tonic-gate * Uninitialize and free the component 12117c478bd9Sstevel@tonic-gate */ 12127c478bd9Sstevel@tonic-gate kmem_free(ct->ct_drvname, strlen(ct->ct_drvname) + 1); 12137c478bd9Sstevel@tonic-gate kmem_free(ct->ct_guid, strlen(ct->ct_guid) + 1); 12147c478bd9Sstevel@tonic-gate kmem_free(ct->ct_lb_args, sizeof (client_lb_args_t)); 12157c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_failover_cv); 12167c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_unstable_cv); 12177c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_powerchange_cv); 12187c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_mutex); 12197c478bd9Sstevel@tonic-gate kmem_free(ct, sizeof (*ct)); 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate if (cdip != NULL) { 12227c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 12237c478bd9Sstevel@tonic-gate (void) i_mdi_devinfo_remove(vdip, cdip, flags); 12247c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate return (rv); 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate /* 12307c478bd9Sstevel@tonic-gate * i_mdi_client_find(): 12317c478bd9Sstevel@tonic-gate * Find the client structure corresponding to a given guid 12327c478bd9Sstevel@tonic-gate * Caller should hold the mdi_mutex 12337c478bd9Sstevel@tonic-gate */ 12347c478bd9Sstevel@tonic-gate static mdi_client_t * 1235*3c34adc5Sramat i_mdi_client_find(mdi_vhci_t *vh, char *cname, char *guid) 12367c478bd9Sstevel@tonic-gate { 12377c478bd9Sstevel@tonic-gate int index; 12387c478bd9Sstevel@tonic-gate struct client_hash *head; 12397c478bd9Sstevel@tonic-gate mdi_client_t *ct; 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 12427c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 12437c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate ct = head->ct_hash_head; 12467c478bd9Sstevel@tonic-gate while (ct != NULL) { 1247*3c34adc5Sramat if (strcmp(ct->ct_guid, guid) == 0 && 1248*3c34adc5Sramat (cname == NULL || strcmp(ct->ct_drvname, cname) == 0)) { 12497c478bd9Sstevel@tonic-gate break; 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate ct = ct->ct_hnext; 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate return (ct); 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate /* 12597c478bd9Sstevel@tonic-gate * i_mdi_client_update_state(): 12607c478bd9Sstevel@tonic-gate * Compute and update client device state 12617c478bd9Sstevel@tonic-gate * Notes: 12627c478bd9Sstevel@tonic-gate * A client device can be in any of three possible states: 12637c478bd9Sstevel@tonic-gate * 12647c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_OPTIMAL - Client in optimal state with more 12657c478bd9Sstevel@tonic-gate * one online/standby paths. Can tolerate failures. 12667c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_DEGRADED - Client device in degraded state with 12677c478bd9Sstevel@tonic-gate * no alternate paths available as standby. A failure on the online 12687c478bd9Sstevel@tonic-gate * would result in loss of access to device data. 12697c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_FAILED - Client device in failed state with 12707c478bd9Sstevel@tonic-gate * no paths available to access the device. 12717c478bd9Sstevel@tonic-gate */ 12727c478bd9Sstevel@tonic-gate static void 12737c478bd9Sstevel@tonic-gate i_mdi_client_update_state(mdi_client_t *ct) 12747c478bd9Sstevel@tonic-gate { 12757c478bd9Sstevel@tonic-gate int state; 12767c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_mutex)); 12777c478bd9Sstevel@tonic-gate state = i_mdi_client_compute_state(ct, NULL); 12787c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_STATE(ct, state); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate /* 12827c478bd9Sstevel@tonic-gate * i_mdi_client_compute_state(): 12837c478bd9Sstevel@tonic-gate * Compute client device state 12847c478bd9Sstevel@tonic-gate * 12857c478bd9Sstevel@tonic-gate * mdi_phci_t * Pointer to pHCI structure which should 12867c478bd9Sstevel@tonic-gate * while computing the new value. Used by 12877c478bd9Sstevel@tonic-gate * i_mdi_phci_offline() to find the new 12887c478bd9Sstevel@tonic-gate * client state after DR of a pHCI. 12897c478bd9Sstevel@tonic-gate */ 12907c478bd9Sstevel@tonic-gate static int 12917c478bd9Sstevel@tonic-gate i_mdi_client_compute_state(mdi_client_t *ct, mdi_phci_t *ph) 12927c478bd9Sstevel@tonic-gate { 12937c478bd9Sstevel@tonic-gate int state; 12947c478bd9Sstevel@tonic-gate int online_count = 0; 12957c478bd9Sstevel@tonic-gate int standby_count = 0; 12967c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_mutex)); 12997c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 13007c478bd9Sstevel@tonic-gate while (pip != NULL) { 13017c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 13027c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 13037c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 13047c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 13057c478bd9Sstevel@tonic-gate pip = next; 13067c478bd9Sstevel@tonic-gate continue; 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 13097c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_ONLINE) 13107c478bd9Sstevel@tonic-gate online_count++; 13117c478bd9Sstevel@tonic-gate else if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 13127c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_STANDBY) 13137c478bd9Sstevel@tonic-gate standby_count++; 13147c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 13157c478bd9Sstevel@tonic-gate pip = next; 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate if (online_count == 0) { 13197c478bd9Sstevel@tonic-gate if (standby_count == 0) { 13207c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_FAILED; 13217c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!client state: failed" 13227c478bd9Sstevel@tonic-gate " ct = %p\n", ct)); 13237c478bd9Sstevel@tonic-gate } else if (standby_count == 1) { 13247c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 13257c478bd9Sstevel@tonic-gate } else { 13267c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate } else if (online_count == 1) { 13297c478bd9Sstevel@tonic-gate if (standby_count == 0) { 13307c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 13317c478bd9Sstevel@tonic-gate } else { 13327c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate } else { 13357c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 13367c478bd9Sstevel@tonic-gate } 13377c478bd9Sstevel@tonic-gate return (state); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate /* 13417c478bd9Sstevel@tonic-gate * i_mdi_client2devinfo(): 13427c478bd9Sstevel@tonic-gate * Utility function 13437c478bd9Sstevel@tonic-gate */ 13447c478bd9Sstevel@tonic-gate dev_info_t * 13457c478bd9Sstevel@tonic-gate i_mdi_client2devinfo(mdi_client_t *ct) 13467c478bd9Sstevel@tonic-gate { 13477c478bd9Sstevel@tonic-gate return (ct->ct_dip); 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate /* 13517c478bd9Sstevel@tonic-gate * mdi_client_path2_devinfo(): 13527c478bd9Sstevel@tonic-gate * Given the parent devinfo and child devfs pathname, search for 13537c478bd9Sstevel@tonic-gate * a valid devfs node handle. 13547c478bd9Sstevel@tonic-gate */ 13557c478bd9Sstevel@tonic-gate dev_info_t * 13567c478bd9Sstevel@tonic-gate mdi_client_path2devinfo(dev_info_t *vdip, char *pathname) 13577c478bd9Sstevel@tonic-gate { 13587c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 13597c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 13607c478bd9Sstevel@tonic-gate char *temp_pathname; 13617c478bd9Sstevel@tonic-gate int circular; 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate /* 13647c478bd9Sstevel@tonic-gate * Allocate temp buffer 13657c478bd9Sstevel@tonic-gate */ 13667c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate /* 13697c478bd9Sstevel@tonic-gate * Lock parent against changes 13707c478bd9Sstevel@tonic-gate */ 13717c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 13727c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vdip)->devi_child; 13737c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 13747c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 13777c478bd9Sstevel@tonic-gate (void) ddi_pathname(cdip, temp_pathname); 13787c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 13797c478bd9Sstevel@tonic-gate break; 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate /* 13837c478bd9Sstevel@tonic-gate * Release devinfo lock 13847c478bd9Sstevel@tonic-gate */ 13857c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate /* 13887c478bd9Sstevel@tonic-gate * Free the temp buffer 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 13917c478bd9Sstevel@tonic-gate return (cdip); 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate /* 13967c478bd9Sstevel@tonic-gate * mdi_client_get_path_count(): 13977c478bd9Sstevel@tonic-gate * Utility function to get number of path information nodes 13987c478bd9Sstevel@tonic-gate * associated with a given client device. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate int 14017c478bd9Sstevel@tonic-gate mdi_client_get_path_count(dev_info_t *cdip) 14027c478bd9Sstevel@tonic-gate { 14037c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14047c478bd9Sstevel@tonic-gate int count = 0; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14077c478bd9Sstevel@tonic-gate if (ct != NULL) { 14087c478bd9Sstevel@tonic-gate count = ct->ct_path_count; 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate return (count); 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * i_mdi_get_hash_key(): 14167c478bd9Sstevel@tonic-gate * Create a hash using strings as keys 14177c478bd9Sstevel@tonic-gate * 14187c478bd9Sstevel@tonic-gate */ 14197c478bd9Sstevel@tonic-gate static int 14207c478bd9Sstevel@tonic-gate i_mdi_get_hash_key(char *str) 14217c478bd9Sstevel@tonic-gate { 14227c478bd9Sstevel@tonic-gate uint32_t g, hash = 0; 14237c478bd9Sstevel@tonic-gate char *p; 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate for (p = str; *p != '\0'; p++) { 14267c478bd9Sstevel@tonic-gate g = *p; 14277c478bd9Sstevel@tonic-gate hash += g; 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate return (hash % (CLIENT_HASH_TABLE_SIZE - 1)); 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate /* 14337c478bd9Sstevel@tonic-gate * mdi_get_lb_policy(): 14347c478bd9Sstevel@tonic-gate * Get current load balancing policy for a given client device 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate client_lb_t 14377c478bd9Sstevel@tonic-gate mdi_get_lb_policy(dev_info_t *cdip) 14387c478bd9Sstevel@tonic-gate { 14397c478bd9Sstevel@tonic-gate client_lb_t lb = LOAD_BALANCE_NONE; 14407c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14437c478bd9Sstevel@tonic-gate if (ct != NULL) { 14447c478bd9Sstevel@tonic-gate lb = ct->ct_lb; 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate return (lb); 14477c478bd9Sstevel@tonic-gate } 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate /* 14507c478bd9Sstevel@tonic-gate * mdi_set_lb_region_size(): 14517c478bd9Sstevel@tonic-gate * Set current region size for the load-balance 14527c478bd9Sstevel@tonic-gate */ 14537c478bd9Sstevel@tonic-gate int 14547c478bd9Sstevel@tonic-gate mdi_set_lb_region_size(dev_info_t *cdip, int region_size) 14557c478bd9Sstevel@tonic-gate { 14567c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14577c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14607c478bd9Sstevel@tonic-gate if (ct != NULL && ct->ct_lb_args != NULL) { 14617c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = region_size; 14627c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate return (rv); 14657c478bd9Sstevel@tonic-gate } 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate /* 14687c478bd9Sstevel@tonic-gate * mdi_Set_lb_policy(): 14697c478bd9Sstevel@tonic-gate * Set current load balancing policy for a given client device 14707c478bd9Sstevel@tonic-gate */ 14717c478bd9Sstevel@tonic-gate int 14727c478bd9Sstevel@tonic-gate mdi_set_lb_policy(dev_info_t *cdip, client_lb_t lb) 14737c478bd9Sstevel@tonic-gate { 14747c478bd9Sstevel@tonic-gate mdi_client_t *ct; 14757c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 14787c478bd9Sstevel@tonic-gate if (ct != NULL) { 14797c478bd9Sstevel@tonic-gate ct->ct_lb = lb; 14807c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 14817c478bd9Sstevel@tonic-gate } 14827c478bd9Sstevel@tonic-gate return (rv); 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate /* 14867c478bd9Sstevel@tonic-gate * mdi_failover(): 14877c478bd9Sstevel@tonic-gate * failover function called by the vHCI drivers to initiate 14887c478bd9Sstevel@tonic-gate * a failover operation. This is typically due to non-availability 14897c478bd9Sstevel@tonic-gate * of online paths to route I/O requests. Failover can be 14907c478bd9Sstevel@tonic-gate * triggered through user application also. 14917c478bd9Sstevel@tonic-gate * 14927c478bd9Sstevel@tonic-gate * The vHCI driver calls mdi_failover() to initiate a failover 14937c478bd9Sstevel@tonic-gate * operation. mdi_failover() calls back into the vHCI driver's 14947c478bd9Sstevel@tonic-gate * vo_failover() entry point to perform the actual failover 14957c478bd9Sstevel@tonic-gate * operation. The reason for requiring the vHCI driver to 14967c478bd9Sstevel@tonic-gate * initiate failover by calling mdi_failover(), instead of directly 14977c478bd9Sstevel@tonic-gate * executing vo_failover() itself, is to ensure that the mdi 14987c478bd9Sstevel@tonic-gate * framework can keep track of the client state properly. 14997c478bd9Sstevel@tonic-gate * Additionally, mdi_failover() provides as a convenience the 15007c478bd9Sstevel@tonic-gate * option of performing the failover operation synchronously or 15017c478bd9Sstevel@tonic-gate * asynchronously 15027c478bd9Sstevel@tonic-gate * 15037c478bd9Sstevel@tonic-gate * Upon successful completion of the failover operation, the 15047c478bd9Sstevel@tonic-gate * paths that were previously ONLINE will be in the STANDBY state, 15057c478bd9Sstevel@tonic-gate * and the newly activated paths will be in the ONLINE state. 15067c478bd9Sstevel@tonic-gate * 15077c478bd9Sstevel@tonic-gate * The flags modifier determines whether the activation is done 15087c478bd9Sstevel@tonic-gate * synchronously: MDI_FAILOVER_SYNC 15097c478bd9Sstevel@tonic-gate * Return Values: 15107c478bd9Sstevel@tonic-gate * MDI_SUCCESS 15117c478bd9Sstevel@tonic-gate * MDI_FAILURE 15127c478bd9Sstevel@tonic-gate * MDI_BUSY 15137c478bd9Sstevel@tonic-gate */ 15147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15157c478bd9Sstevel@tonic-gate int 15167c478bd9Sstevel@tonic-gate mdi_failover(dev_info_t *vdip, dev_info_t *cdip, int flags) 15177c478bd9Sstevel@tonic-gate { 15187c478bd9Sstevel@tonic-gate int rv; 15197c478bd9Sstevel@tonic-gate mdi_client_t *ct; 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 15227c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 15237c478bd9Sstevel@tonic-gate if (ct == NULL) { 15247c478bd9Sstevel@tonic-gate /* cdip is not a valid client device. Nothing more to do. */ 15257c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 15267c478bd9Sstevel@tonic-gate } 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_PATH_FREE_IN_PROGRESS(ct)) { 15317c478bd9Sstevel@tonic-gate /* A path to the client is being freed */ 15327c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15337c478bd9Sstevel@tonic-gate return (MDI_BUSY); 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 15387c478bd9Sstevel@tonic-gate /* 15397c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 15407c478bd9Sstevel@tonic-gate */ 15417c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15427c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 15437c478bd9Sstevel@tonic-gate } 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 15467c478bd9Sstevel@tonic-gate /* 15477c478bd9Sstevel@tonic-gate * Failover is already in progress; return BUSY 15487c478bd9Sstevel@tonic-gate */ 15497c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15507c478bd9Sstevel@tonic-gate return (MDI_BUSY); 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate /* 15537c478bd9Sstevel@tonic-gate * Make sure that mdi_pathinfo node state changes are processed. 15547c478bd9Sstevel@tonic-gate * We do not allow failovers to progress while client path state 15557c478bd9Sstevel@tonic-gate * changes are in progress 15567c478bd9Sstevel@tonic-gate */ 15577c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 15587c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 15597c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15607c478bd9Sstevel@tonic-gate return (MDI_BUSY); 15617c478bd9Sstevel@tonic-gate } else { 15627c478bd9Sstevel@tonic-gate while (ct->ct_unstable) 15637c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_unstable_cv, &ct->ct_mutex); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate /* 15687c478bd9Sstevel@tonic-gate * Client device is in stable state. Before proceeding, perform sanity 15697c478bd9Sstevel@tonic-gate * checks again. 15707c478bd9Sstevel@tonic-gate */ 15717c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct)) || (MDI_CLIENT_IS_FAILED(ct)) || 15727c478bd9Sstevel@tonic-gate (i_ddi_node_state(ct->ct_dip) < DS_READY)) { 15737c478bd9Sstevel@tonic-gate /* 15747c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 15757c478bd9Sstevel@tonic-gate */ 15767c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15777c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * Set the client state as failover in progress. 15827c478bd9Sstevel@tonic-gate */ 15837c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_FAILOVER_IN_PROGRESS(ct); 15847c478bd9Sstevel@tonic-gate ct->ct_failover_flags = flags; 15857c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 15887c478bd9Sstevel@tonic-gate /* 15897c478bd9Sstevel@tonic-gate * Submit the initiate failover request via CPR safe 15907c478bd9Sstevel@tonic-gate * taskq threads. 15917c478bd9Sstevel@tonic-gate */ 15927c478bd9Sstevel@tonic-gate (void) taskq_dispatch(mdi_taskq, (task_func_t *)i_mdi_failover, 15937c478bd9Sstevel@tonic-gate ct, KM_SLEEP); 15947c478bd9Sstevel@tonic-gate return (MDI_ACCEPT); 15957c478bd9Sstevel@tonic-gate } else { 15967c478bd9Sstevel@tonic-gate /* 15977c478bd9Sstevel@tonic-gate * Synchronous failover mode. Typically invoked from the user 15987c478bd9Sstevel@tonic-gate * land. 15997c478bd9Sstevel@tonic-gate */ 16007c478bd9Sstevel@tonic-gate rv = i_mdi_failover(ct); 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate return (rv); 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate /* 16067c478bd9Sstevel@tonic-gate * i_mdi_failover(): 16077c478bd9Sstevel@tonic-gate * internal failover function. Invokes vHCI drivers failover 16087c478bd9Sstevel@tonic-gate * callback function and process the failover status 16097c478bd9Sstevel@tonic-gate * Return Values: 16107c478bd9Sstevel@tonic-gate * None 16117c478bd9Sstevel@tonic-gate * 16127c478bd9Sstevel@tonic-gate * Note: A client device in failover state can not be detached or freed. 16137c478bd9Sstevel@tonic-gate */ 16147c478bd9Sstevel@tonic-gate static int 16157c478bd9Sstevel@tonic-gate i_mdi_failover(void *arg) 16167c478bd9Sstevel@tonic-gate { 16177c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 16187c478bd9Sstevel@tonic-gate mdi_client_t *ct = (mdi_client_t *)arg; 16197c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = ct->ct_vhci; 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&ct->ct_mutex)); 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate if (vh->vh_ops->vo_failover != NULL) { 16247c478bd9Sstevel@tonic-gate /* 16257c478bd9Sstevel@tonic-gate * Call vHCI drivers callback routine 16267c478bd9Sstevel@tonic-gate */ 16277c478bd9Sstevel@tonic-gate rv = (*vh->vh_ops->vo_failover)(vh->vh_dip, ct->ct_dip, 16287c478bd9Sstevel@tonic-gate ct->ct_failover_flags); 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 16327c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_FAILOVER_IN_PROGRESS(ct); 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate /* 16357c478bd9Sstevel@tonic-gate * Save the failover return status 16367c478bd9Sstevel@tonic-gate */ 16377c478bd9Sstevel@tonic-gate ct->ct_failover_status = rv; 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate /* 16407c478bd9Sstevel@tonic-gate * As a result of failover, client status would have been changed. 16417c478bd9Sstevel@tonic-gate * Update the client state and wake up anyone waiting on this client 16427c478bd9Sstevel@tonic-gate * device. 16437c478bd9Sstevel@tonic-gate */ 16447c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_failover_cv); 16477c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 16487c478bd9Sstevel@tonic-gate return (rv); 16497c478bd9Sstevel@tonic-gate } 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate /* 16527c478bd9Sstevel@tonic-gate * Load balancing is logical block. 16537c478bd9Sstevel@tonic-gate * IOs within the range described by region_size 16547c478bd9Sstevel@tonic-gate * would go on the same path. This would improve the 16557c478bd9Sstevel@tonic-gate * performance by cache-hit on some of the RAID devices. 16567c478bd9Sstevel@tonic-gate * Search only for online paths(At some point we 16577c478bd9Sstevel@tonic-gate * may want to balance across target ports). 16587c478bd9Sstevel@tonic-gate * If no paths are found then default to round-robin. 16597c478bd9Sstevel@tonic-gate */ 16607c478bd9Sstevel@tonic-gate static int 16617c478bd9Sstevel@tonic-gate i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp) 16627c478bd9Sstevel@tonic-gate { 16637c478bd9Sstevel@tonic-gate int path_index = -1; 16647c478bd9Sstevel@tonic-gate int online_path_count = 0; 16657c478bd9Sstevel@tonic-gate int online_nonpref_path_count = 0; 16667c478bd9Sstevel@tonic-gate int region_size = ct->ct_lb_args->region_size; 16677c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 16687c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 16697c478bd9Sstevel@tonic-gate int preferred, path_cnt; 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 16727c478bd9Sstevel@tonic-gate while (pip) { 16737c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 16747c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_state == 16757c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && MDI_PI(pip)->pi_preferred) { 16767c478bd9Sstevel@tonic-gate online_path_count++; 16777c478bd9Sstevel@tonic-gate } else if (MDI_PI(pip)->pi_state == 16787c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && !MDI_PI(pip)->pi_preferred) { 16797c478bd9Sstevel@tonic-gate online_nonpref_path_count++; 16807c478bd9Sstevel@tonic-gate } 16817c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 16827c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 16837c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 16847c478bd9Sstevel@tonic-gate pip = next; 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate /* if found any online/preferred then use this type */ 16877c478bd9Sstevel@tonic-gate if (online_path_count > 0) { 16887c478bd9Sstevel@tonic-gate path_cnt = online_path_count; 16897c478bd9Sstevel@tonic-gate preferred = 1; 16907c478bd9Sstevel@tonic-gate } else if (online_nonpref_path_count > 0) { 16917c478bd9Sstevel@tonic-gate path_cnt = online_nonpref_path_count; 16927c478bd9Sstevel@tonic-gate preferred = 0; 16937c478bd9Sstevel@tonic-gate } else { 16947c478bd9Sstevel@tonic-gate path_cnt = 0; 16957c478bd9Sstevel@tonic-gate } 16967c478bd9Sstevel@tonic-gate if (path_cnt) { 16977c478bd9Sstevel@tonic-gate path_index = (bp->b_blkno >> region_size) % path_cnt; 16987c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 16997c478bd9Sstevel@tonic-gate while (pip && path_index != -1) { 17007c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 17017c478bd9Sstevel@tonic-gate if (path_index == 0 && 17027c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 17037c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE) && 17047c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == preferred) { 17057c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 17067c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 17077c478bd9Sstevel@tonic-gate *ret_pip = pip; 17087c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate path_index --; 17117c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 17127c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 17137c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 17147c478bd9Sstevel@tonic-gate pip = next; 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate if (pip == NULL) { 17177c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 17187c478bd9Sstevel@tonic-gate "!lba %p, no pip !!\n", 17197c478bd9Sstevel@tonic-gate bp->b_blkno)); 17207c478bd9Sstevel@tonic-gate } else { 17217c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 17227c478bd9Sstevel@tonic-gate "!lba %p, no pip for path_index, " 17237c478bd9Sstevel@tonic-gate "pip %p\n", pip)); 17247c478bd9Sstevel@tonic-gate } 17257c478bd9Sstevel@tonic-gate } 17267c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate /* 17307c478bd9Sstevel@tonic-gate * mdi_select_path(): 17317c478bd9Sstevel@tonic-gate * select a path to access a client device. 17327c478bd9Sstevel@tonic-gate * 17337c478bd9Sstevel@tonic-gate * mdi_select_path() function is called by the vHCI drivers to 17347c478bd9Sstevel@tonic-gate * select a path to route the I/O request to. The caller passes 17357c478bd9Sstevel@tonic-gate * the block I/O data transfer structure ("buf") as one of the 17367c478bd9Sstevel@tonic-gate * parameters. The mpxio framework uses the buf structure 17377c478bd9Sstevel@tonic-gate * contents to maintain per path statistics (total I/O size / 17387c478bd9Sstevel@tonic-gate * count pending). If more than one online paths are available to 17397c478bd9Sstevel@tonic-gate * select, the framework automatically selects a suitable path 17407c478bd9Sstevel@tonic-gate * for routing I/O request. If a failover operation is active for 17417c478bd9Sstevel@tonic-gate * this client device the call shall be failed with MDI_BUSY error 17427c478bd9Sstevel@tonic-gate * code. 17437c478bd9Sstevel@tonic-gate * 17447c478bd9Sstevel@tonic-gate * By default this function returns a suitable path in online 17457c478bd9Sstevel@tonic-gate * state based on the current load balancing policy. Currently 17467c478bd9Sstevel@tonic-gate * we support LOAD_BALANCE_NONE (Previously selected online path 17477c478bd9Sstevel@tonic-gate * will continue to be used till the path is usable) and 17487c478bd9Sstevel@tonic-gate * LOAD_BALANCE_RR (Online paths will be selected in a round 17497c478bd9Sstevel@tonic-gate * robin fashion), LOAD_BALANCE_LB(Online paths will be selected 17507c478bd9Sstevel@tonic-gate * based on the logical block). The load balancing 17517c478bd9Sstevel@tonic-gate * through vHCI drivers configuration file (driver.conf). 17527c478bd9Sstevel@tonic-gate * 17537c478bd9Sstevel@tonic-gate * vHCI drivers may override this default behavior by specifying 17547c478bd9Sstevel@tonic-gate * appropriate flags. If start_pip is specified (non NULL) is 17557c478bd9Sstevel@tonic-gate * used as start point to walk and find the next appropriate path. 17567c478bd9Sstevel@tonic-gate * The following values are currently defined: 17577c478bd9Sstevel@tonic-gate * MDI_SELECT_ONLINE_PATH (to select an ONLINE path) and/or 17587c478bd9Sstevel@tonic-gate * MDI_SELECT_STANDBY_PATH (to select an STANDBY path). 17597c478bd9Sstevel@tonic-gate * 17607c478bd9Sstevel@tonic-gate * The non-standard behavior is used by the scsi_vhci driver, 17617c478bd9Sstevel@tonic-gate * whenever it has to use a STANDBY/FAULTED path. Eg. during 17627c478bd9Sstevel@tonic-gate * attach of client devices (to avoid an unnecessary failover 17637c478bd9Sstevel@tonic-gate * when the STANDBY path comes up first), during failover 17647c478bd9Sstevel@tonic-gate * (to activate a STANDBY path as ONLINE). 17657c478bd9Sstevel@tonic-gate * 17667c478bd9Sstevel@tonic-gate * The selected path in returned in a held state (ref_cnt). 17677c478bd9Sstevel@tonic-gate * Caller should release the hold by calling mdi_rele_path(). 17687c478bd9Sstevel@tonic-gate * 17697c478bd9Sstevel@tonic-gate * Return Values: 17707c478bd9Sstevel@tonic-gate * MDI_SUCCESS - Completed successfully 17717c478bd9Sstevel@tonic-gate * MDI_BUSY - Client device is busy failing over 17727c478bd9Sstevel@tonic-gate * MDI_NOPATH - Client device is online, but no valid path are 17737c478bd9Sstevel@tonic-gate * available to access this client device 17747c478bd9Sstevel@tonic-gate * MDI_FAILURE - Invalid client device or state 17757c478bd9Sstevel@tonic-gate * MDI_DEVI_ONLINING 17767c478bd9Sstevel@tonic-gate * - Client device (struct dev_info state) is in 17777c478bd9Sstevel@tonic-gate * onlining state. 17787c478bd9Sstevel@tonic-gate */ 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17817c478bd9Sstevel@tonic-gate int 17827c478bd9Sstevel@tonic-gate mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags, 17837c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start_pip, mdi_pathinfo_t **ret_pip) 17847c478bd9Sstevel@tonic-gate { 17857c478bd9Sstevel@tonic-gate mdi_client_t *ct; 17867c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 17877c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 17887c478bd9Sstevel@tonic-gate mdi_pathinfo_t *head; 17897c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start; 17907c478bd9Sstevel@tonic-gate client_lb_t lbp; /* load balancing policy */ 17917c478bd9Sstevel@tonic-gate int sb = 1; /* standard behavior */ 17927c478bd9Sstevel@tonic-gate int preferred = 1; /* preferred path */ 17937c478bd9Sstevel@tonic-gate int cond, cont = 1; 17947c478bd9Sstevel@tonic-gate int retry = 0; 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate if (flags != 0) { 17977c478bd9Sstevel@tonic-gate /* 17987c478bd9Sstevel@tonic-gate * disable default behavior 17997c478bd9Sstevel@tonic-gate */ 18007c478bd9Sstevel@tonic-gate sb = 0; 18017c478bd9Sstevel@tonic-gate } 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate *ret_pip = NULL; 18047c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 18057c478bd9Sstevel@tonic-gate if (ct == NULL) { 18067c478bd9Sstevel@tonic-gate /* mdi extensions are NULL, Nothing more to do */ 18077c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate if (sb) { 18137c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 18147c478bd9Sstevel@tonic-gate /* 18157c478bd9Sstevel@tonic-gate * Client is not ready to accept any I/O requests. 18167c478bd9Sstevel@tonic-gate * Fail this request. 18177c478bd9Sstevel@tonic-gate */ 18187c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 18197c478bd9Sstevel@tonic-gate "client state offline ct = %p\n", ct)); 18207c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18217c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 18257c478bd9Sstevel@tonic-gate /* 18267c478bd9Sstevel@tonic-gate * Check for Failover is in progress. If so tell the 18277c478bd9Sstevel@tonic-gate * caller that this device is busy. 18287c478bd9Sstevel@tonic-gate */ 18297c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 18307c478bd9Sstevel@tonic-gate "client failover in progress ct = %p\n", ct)); 18317c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18327c478bd9Sstevel@tonic-gate return (MDI_BUSY); 18337c478bd9Sstevel@tonic-gate } 18347c478bd9Sstevel@tonic-gate 18357c478bd9Sstevel@tonic-gate /* 18367c478bd9Sstevel@tonic-gate * Check to see whether the client device is attached. 18377c478bd9Sstevel@tonic-gate * If not so, let the vHCI driver manually select a path 18387c478bd9Sstevel@tonic-gate * (standby) and let the probe/attach process to continue. 18397c478bd9Sstevel@tonic-gate */ 18407c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct)) || 18417c478bd9Sstevel@tonic-gate i_ddi_node_state(cdip) < DS_READY) { 18427c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, cdip, "!Devi is onlining\n")); 18437c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18447c478bd9Sstevel@tonic-gate return (MDI_DEVI_ONLINING); 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate /* 18497c478bd9Sstevel@tonic-gate * Cache in the client list head. If head of the list is NULL 18507c478bd9Sstevel@tonic-gate * return MDI_NOPATH 18517c478bd9Sstevel@tonic-gate */ 18527c478bd9Sstevel@tonic-gate head = ct->ct_path_head; 18537c478bd9Sstevel@tonic-gate if (head == NULL) { 18547c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18557c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate /* 18597c478bd9Sstevel@tonic-gate * for non default behavior, bypass current 18607c478bd9Sstevel@tonic-gate * load balancing policy and always use LOAD_BALANCE_RR 18617c478bd9Sstevel@tonic-gate * except that the start point will be adjusted based 18627c478bd9Sstevel@tonic-gate * on the provided start_pip 18637c478bd9Sstevel@tonic-gate */ 18647c478bd9Sstevel@tonic-gate lbp = sb ? ct->ct_lb : LOAD_BALANCE_RR; 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate switch (lbp) { 18677c478bd9Sstevel@tonic-gate case LOAD_BALANCE_NONE: 18687c478bd9Sstevel@tonic-gate /* 18697c478bd9Sstevel@tonic-gate * Load balancing is None or Alternate path mode 18707c478bd9Sstevel@tonic-gate * Start looking for a online mdi_pathinfo node starting from 18717c478bd9Sstevel@tonic-gate * last known selected path 18727c478bd9Sstevel@tonic-gate */ 18737c478bd9Sstevel@tonic-gate preferred = 1; 18747c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_last; 18757c478bd9Sstevel@tonic-gate if (pip == NULL) { 18767c478bd9Sstevel@tonic-gate pip = head; 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate start = pip; 18797c478bd9Sstevel@tonic-gate do { 18807c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 18817c478bd9Sstevel@tonic-gate /* 18827c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 18837c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 18847c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 18857c478bd9Sstevel@tonic-gate */ 18867c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_state == 18877c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 18887c478bd9Sstevel@tonic-gate preferred == MDI_PI(pip)->pi_preferred) { 18897c478bd9Sstevel@tonic-gate /* 18907c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 18917c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 18927c478bd9Sstevel@tonic-gate */ 18937c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 18947c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 18957c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 18967c478bd9Sstevel@tonic-gate *ret_pip = pip; 18977c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 18987c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate /* 19027c478bd9Sstevel@tonic-gate * Path is busy. 19037c478bd9Sstevel@tonic-gate */ 19047c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 19057c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 19067c478bd9Sstevel@tonic-gate retry = 1; 19077c478bd9Sstevel@tonic-gate /* 19087c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 19097c478bd9Sstevel@tonic-gate */ 19107c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 19117c478bd9Sstevel@tonic-gate if (next == NULL) { 19127c478bd9Sstevel@tonic-gate next = head; 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 19157c478bd9Sstevel@tonic-gate pip = next; 19167c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 19177c478bd9Sstevel@tonic-gate preferred = 0; 19187c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 19197c478bd9Sstevel@tonic-gate cont = 0; 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate } while (cont); 19227c478bd9Sstevel@tonic-gate break; 19237c478bd9Sstevel@tonic-gate 19247c478bd9Sstevel@tonic-gate case LOAD_BALANCE_LBA: 19257c478bd9Sstevel@tonic-gate /* 19267c478bd9Sstevel@tonic-gate * Make sure we are looking 19277c478bd9Sstevel@tonic-gate * for an online path. Otherwise, if it is for a STANDBY 19287c478bd9Sstevel@tonic-gate * path request, it will go through and fetch an ONLINE 19297c478bd9Sstevel@tonic-gate * path which is not desirable. 19307c478bd9Sstevel@tonic-gate */ 19317c478bd9Sstevel@tonic-gate if ((ct->ct_lb_args != NULL) && 19327c478bd9Sstevel@tonic-gate (ct->ct_lb_args->region_size) && bp && 19337c478bd9Sstevel@tonic-gate (sb || (flags == MDI_SELECT_ONLINE_PATH))) { 19347c478bd9Sstevel@tonic-gate if (i_mdi_lba_lb(ct, ret_pip, bp) 19357c478bd9Sstevel@tonic-gate == MDI_SUCCESS) { 19367c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 19377c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 19387c478bd9Sstevel@tonic-gate } 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 19417c478bd9Sstevel@tonic-gate case LOAD_BALANCE_RR: 19427c478bd9Sstevel@tonic-gate /* 19437c478bd9Sstevel@tonic-gate * Load balancing is Round Robin. Start looking for a online 19447c478bd9Sstevel@tonic-gate * mdi_pathinfo node starting from last known selected path 19457c478bd9Sstevel@tonic-gate * as the start point. If override flags are specified, 19467c478bd9Sstevel@tonic-gate * process accordingly. 19477c478bd9Sstevel@tonic-gate * If the search is already in effect(start_pip not null), 19487c478bd9Sstevel@tonic-gate * then lets just use the same path preference to continue the 19497c478bd9Sstevel@tonic-gate * traversal. 19507c478bd9Sstevel@tonic-gate */ 19517c478bd9Sstevel@tonic-gate 19527c478bd9Sstevel@tonic-gate if (start_pip != NULL) { 19537c478bd9Sstevel@tonic-gate preferred = MDI_PI(start_pip)->pi_preferred; 19547c478bd9Sstevel@tonic-gate } else { 19557c478bd9Sstevel@tonic-gate preferred = 1; 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate start = sb ? (mdi_pathinfo_t *)ct->ct_path_last : start_pip; 19597c478bd9Sstevel@tonic-gate if (start == NULL) { 19607c478bd9Sstevel@tonic-gate pip = head; 19617c478bd9Sstevel@tonic-gate } else { 19627c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(start)->pi_client_link; 19637c478bd9Sstevel@tonic-gate if (pip == NULL) { 19647c478bd9Sstevel@tonic-gate if (!sb) { 19657c478bd9Sstevel@tonic-gate if (preferred == 0) { 19667c478bd9Sstevel@tonic-gate /* 19677c478bd9Sstevel@tonic-gate * Looks like we have completed 19687c478bd9Sstevel@tonic-gate * the traversal as preferred 19697c478bd9Sstevel@tonic-gate * value is 0. Time to bail out. 19707c478bd9Sstevel@tonic-gate */ 19717c478bd9Sstevel@tonic-gate *ret_pip = NULL; 19727c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 19737c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 19747c478bd9Sstevel@tonic-gate } else { 19757c478bd9Sstevel@tonic-gate /* 19767c478bd9Sstevel@tonic-gate * Looks like we reached the 19777c478bd9Sstevel@tonic-gate * end of the list. Lets enable 19787c478bd9Sstevel@tonic-gate * traversal of non preferred 19797c478bd9Sstevel@tonic-gate * paths. 19807c478bd9Sstevel@tonic-gate */ 19817c478bd9Sstevel@tonic-gate preferred = 0; 19827c478bd9Sstevel@tonic-gate } 19837c478bd9Sstevel@tonic-gate } 19847c478bd9Sstevel@tonic-gate pip = head; 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate start = pip; 19887c478bd9Sstevel@tonic-gate do { 19897c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 19907c478bd9Sstevel@tonic-gate if (sb) { 19917c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 19927c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 19937c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 19947c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 19957c478bd9Sstevel@tonic-gate } else { 19967c478bd9Sstevel@tonic-gate if (flags == MDI_SELECT_ONLINE_PATH) { 19977c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 19987c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 19997c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20007c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20017c478bd9Sstevel@tonic-gate } else if (flags == MDI_SELECT_STANDBY_PATH) { 20027c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 20037c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY && 20047c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20057c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20067c478bd9Sstevel@tonic-gate } else if (flags == (MDI_SELECT_ONLINE_PATH | 20077c478bd9Sstevel@tonic-gate MDI_SELECT_STANDBY_PATH)) { 20087c478bd9Sstevel@tonic-gate cond = (((MDI_PI(pip)->pi_state == 20097c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE || 20107c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 20117c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY)) && 20127c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 20137c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 20147c478bd9Sstevel@tonic-gate } else { 20157c478bd9Sstevel@tonic-gate cond = 0; 20167c478bd9Sstevel@tonic-gate } 20177c478bd9Sstevel@tonic-gate } 20187c478bd9Sstevel@tonic-gate /* 20197c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 20207c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 20217c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 20227c478bd9Sstevel@tonic-gate */ 20237c478bd9Sstevel@tonic-gate if (cond) { 20247c478bd9Sstevel@tonic-gate /* 20257c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 20267c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 20277c478bd9Sstevel@tonic-gate */ 20287c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 20297c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 20307c478bd9Sstevel@tonic-gate if (sb) 20317c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 20327c478bd9Sstevel@tonic-gate *ret_pip = pip; 20337c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 20347c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 20357c478bd9Sstevel@tonic-gate } 20367c478bd9Sstevel@tonic-gate /* 20377c478bd9Sstevel@tonic-gate * Path is busy. 20387c478bd9Sstevel@tonic-gate */ 20397c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 20407c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 20417c478bd9Sstevel@tonic-gate retry = 1; 20427c478bd9Sstevel@tonic-gate 20437c478bd9Sstevel@tonic-gate /* 20447c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 20457c478bd9Sstevel@tonic-gate */ 20467c478bd9Sstevel@tonic-gate do_again: 20477c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 20487c478bd9Sstevel@tonic-gate if (next == NULL) { 20497c478bd9Sstevel@tonic-gate if (!sb) { 20507c478bd9Sstevel@tonic-gate if (preferred == 1) { 20517c478bd9Sstevel@tonic-gate /* 20527c478bd9Sstevel@tonic-gate * Looks like we reached the 20537c478bd9Sstevel@tonic-gate * end of the list. Lets enable 20547c478bd9Sstevel@tonic-gate * traversal of non preferred 20557c478bd9Sstevel@tonic-gate * paths. 20567c478bd9Sstevel@tonic-gate */ 20577c478bd9Sstevel@tonic-gate preferred = 0; 20587c478bd9Sstevel@tonic-gate next = head; 20597c478bd9Sstevel@tonic-gate } else { 20607c478bd9Sstevel@tonic-gate /* 20617c478bd9Sstevel@tonic-gate * We have done both the passes 20627c478bd9Sstevel@tonic-gate * Preferred as well as for 20637c478bd9Sstevel@tonic-gate * Non-preferred. Bail out now. 20647c478bd9Sstevel@tonic-gate */ 20657c478bd9Sstevel@tonic-gate cont = 0; 20667c478bd9Sstevel@tonic-gate } 20677c478bd9Sstevel@tonic-gate } else { 20687c478bd9Sstevel@tonic-gate /* 20697c478bd9Sstevel@tonic-gate * Standard behavior case. 20707c478bd9Sstevel@tonic-gate */ 20717c478bd9Sstevel@tonic-gate next = head; 20727c478bd9Sstevel@tonic-gate } 20737c478bd9Sstevel@tonic-gate } 20747c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 20757c478bd9Sstevel@tonic-gate if (cont == 0) { 20767c478bd9Sstevel@tonic-gate break; 20777c478bd9Sstevel@tonic-gate } 20787c478bd9Sstevel@tonic-gate pip = next; 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate if (!sb) { 20817c478bd9Sstevel@tonic-gate /* 20827c478bd9Sstevel@tonic-gate * We need to handle the selection of 20837c478bd9Sstevel@tonic-gate * non-preferred path in the following 20847c478bd9Sstevel@tonic-gate * case: 20857c478bd9Sstevel@tonic-gate * 20867c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 20877c478bd9Sstevel@tonic-gate * | A : 1| - | B : 1| - | C : 0| - |NULL | 20887c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 20897c478bd9Sstevel@tonic-gate * 20907c478bd9Sstevel@tonic-gate * If we start the search with B, we need to 20917c478bd9Sstevel@tonic-gate * skip beyond B to pick C which is non - 20927c478bd9Sstevel@tonic-gate * preferred in the second pass. The following 20937c478bd9Sstevel@tonic-gate * test, if true, will allow us to skip over 20947c478bd9Sstevel@tonic-gate * the 'start'(B in the example) to select 20957c478bd9Sstevel@tonic-gate * other non preferred elements. 20967c478bd9Sstevel@tonic-gate */ 20977c478bd9Sstevel@tonic-gate if ((start_pip != NULL) && (start_pip == pip) && 20987c478bd9Sstevel@tonic-gate (MDI_PI(start_pip)->pi_preferred 20997c478bd9Sstevel@tonic-gate != preferred)) { 21007c478bd9Sstevel@tonic-gate /* 21017c478bd9Sstevel@tonic-gate * try again after going past the start 21027c478bd9Sstevel@tonic-gate * pip 21037c478bd9Sstevel@tonic-gate */ 21047c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 21057c478bd9Sstevel@tonic-gate goto do_again; 21067c478bd9Sstevel@tonic-gate } 21077c478bd9Sstevel@tonic-gate } else { 21087c478bd9Sstevel@tonic-gate /* 21097c478bd9Sstevel@tonic-gate * Standard behavior case 21107c478bd9Sstevel@tonic-gate */ 21117c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 21127c478bd9Sstevel@tonic-gate /* look for nonpreferred paths */ 21137c478bd9Sstevel@tonic-gate preferred = 0; 21147c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 21157c478bd9Sstevel@tonic-gate /* 21167c478bd9Sstevel@tonic-gate * Exit condition 21177c478bd9Sstevel@tonic-gate */ 21187c478bd9Sstevel@tonic-gate cont = 0; 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate } 21217c478bd9Sstevel@tonic-gate } while (cont); 21227c478bd9Sstevel@tonic-gate break; 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 21267c478bd9Sstevel@tonic-gate if (retry == 1) { 21277c478bd9Sstevel@tonic-gate return (MDI_BUSY); 21287c478bd9Sstevel@tonic-gate } else { 21297c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 21307c478bd9Sstevel@tonic-gate } 21317c478bd9Sstevel@tonic-gate } 21327c478bd9Sstevel@tonic-gate 21337c478bd9Sstevel@tonic-gate /* 21347c478bd9Sstevel@tonic-gate * For a client, return the next available path to any phci 21357c478bd9Sstevel@tonic-gate * 21367c478bd9Sstevel@tonic-gate * Note: 21377c478bd9Sstevel@tonic-gate * Caller should hold the branch's devinfo node to get a consistent 21387c478bd9Sstevel@tonic-gate * snap shot of the mdi_pathinfo nodes. 21397c478bd9Sstevel@tonic-gate * 21407c478bd9Sstevel@tonic-gate * Please note that even the list is stable the mdi_pathinfo 21417c478bd9Sstevel@tonic-gate * node state and properties are volatile. The caller should lock 21427c478bd9Sstevel@tonic-gate * and unlock the nodes by calling mdi_pi_lock() and 21437c478bd9Sstevel@tonic-gate * mdi_pi_unlock() functions to get a stable properties. 21447c478bd9Sstevel@tonic-gate * 21457c478bd9Sstevel@tonic-gate * If there is a need to use the nodes beyond the hold of the 21467c478bd9Sstevel@tonic-gate * devinfo node period (For ex. I/O), then mdi_pathinfo node 21477c478bd9Sstevel@tonic-gate * need to be held against unexpected removal by calling 21487c478bd9Sstevel@tonic-gate * mdi_hold_path() and should be released by calling 21497c478bd9Sstevel@tonic-gate * mdi_rele_path() on completion. 21507c478bd9Sstevel@tonic-gate */ 21517c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 21527c478bd9Sstevel@tonic-gate mdi_get_next_phci_path(dev_info_t *ct_dip, mdi_pathinfo_t *pip) 21537c478bd9Sstevel@tonic-gate { 21547c478bd9Sstevel@tonic-gate mdi_client_t *ct; 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(ct_dip)) 21577c478bd9Sstevel@tonic-gate return (NULL); 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate /* 21607c478bd9Sstevel@tonic-gate * Walk through client link 21617c478bd9Sstevel@tonic-gate */ 21627c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(ct_dip)->devi_mdi_client; 21637c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 21647c478bd9Sstevel@tonic-gate 21657c478bd9Sstevel@tonic-gate if (pip == NULL) 21667c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ct->ct_path_head); 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link); 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate /* 21727c478bd9Sstevel@tonic-gate * For a phci, return the next available path to any client 21737c478bd9Sstevel@tonic-gate * Note: ditto mdi_get_next_phci_path() 21747c478bd9Sstevel@tonic-gate */ 21757c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 21767c478bd9Sstevel@tonic-gate mdi_get_next_client_path(dev_info_t *ph_dip, mdi_pathinfo_t *pip) 21777c478bd9Sstevel@tonic-gate { 21787c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate if (!MDI_PHCI(ph_dip)) 21817c478bd9Sstevel@tonic-gate return (NULL); 21827c478bd9Sstevel@tonic-gate 21837c478bd9Sstevel@tonic-gate /* 21847c478bd9Sstevel@tonic-gate * Walk through pHCI link 21857c478bd9Sstevel@tonic-gate */ 21867c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(ph_dip)->devi_mdi_xhci; 21877c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate if (pip == NULL) 21907c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ph->ph_path_head); 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link); 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate /* 21967c478bd9Sstevel@tonic-gate * mdi_get_nextpath(): 21977c478bd9Sstevel@tonic-gate * mdi_pathinfo node walker function. Get the next node from the 21987c478bd9Sstevel@tonic-gate * client or pHCI device list. 21997c478bd9Sstevel@tonic-gate * 22007c478bd9Sstevel@tonic-gate * XXX This is wrapper function for compatibility purposes only. 22017c478bd9Sstevel@tonic-gate * 22027c478bd9Sstevel@tonic-gate * It doesn't work under Multi-level MPxIO, where a dip 22037c478bd9Sstevel@tonic-gate * is both client and phci (which link should next_path follow?). 22047c478bd9Sstevel@tonic-gate * Once Leadville is modified to call mdi_get_next_phci/client_path, 22057c478bd9Sstevel@tonic-gate * this interface should be removed. 22067c478bd9Sstevel@tonic-gate */ 22077c478bd9Sstevel@tonic-gate void 22087c478bd9Sstevel@tonic-gate mdi_get_next_path(dev_info_t *dip, mdi_pathinfo_t *pip, 22097c478bd9Sstevel@tonic-gate mdi_pathinfo_t **ret_pip) 22107c478bd9Sstevel@tonic-gate { 22117c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 22127c478bd9Sstevel@tonic-gate *ret_pip = mdi_get_next_phci_path(dip, pip); 22137c478bd9Sstevel@tonic-gate } else if (MDI_PHCI(dip)) { 22147c478bd9Sstevel@tonic-gate *ret_pip = mdi_get_next_client_path(dip, pip); 22157c478bd9Sstevel@tonic-gate } else { 22167c478bd9Sstevel@tonic-gate *ret_pip = NULL; 22177c478bd9Sstevel@tonic-gate } 22187c478bd9Sstevel@tonic-gate } 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate /* 22217c478bd9Sstevel@tonic-gate * mdi_hold_path(): 22227c478bd9Sstevel@tonic-gate * Hold the mdi_pathinfo node against unwanted unexpected free. 22237c478bd9Sstevel@tonic-gate * Return Values: 22247c478bd9Sstevel@tonic-gate * None 22257c478bd9Sstevel@tonic-gate */ 22267c478bd9Sstevel@tonic-gate void 22277c478bd9Sstevel@tonic-gate mdi_hold_path(mdi_pathinfo_t *pip) 22287c478bd9Sstevel@tonic-gate { 22297c478bd9Sstevel@tonic-gate if (pip) { 22307c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22317c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 22327c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 22337c478bd9Sstevel@tonic-gate } 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate /* 22387c478bd9Sstevel@tonic-gate * mdi_rele_path(): 22397c478bd9Sstevel@tonic-gate * Release the mdi_pathinfo node which was selected 22407c478bd9Sstevel@tonic-gate * through mdi_select_path() mechanism or manually held by 22417c478bd9Sstevel@tonic-gate * calling mdi_hold_path(). 22427c478bd9Sstevel@tonic-gate * Return Values: 22437c478bd9Sstevel@tonic-gate * None 22447c478bd9Sstevel@tonic-gate */ 22457c478bd9Sstevel@tonic-gate void 22467c478bd9Sstevel@tonic-gate mdi_rele_path(mdi_pathinfo_t *pip) 22477c478bd9Sstevel@tonic-gate { 22487c478bd9Sstevel@tonic-gate if (pip) { 22497c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22507c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 22517c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_ref_cnt == 0) { 22527c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_ref_cv); 22537c478bd9Sstevel@tonic-gate } 22547c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate } 22577c478bd9Sstevel@tonic-gate 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate /* 22607c478bd9Sstevel@tonic-gate * mdi_pi_lock(): 22617c478bd9Sstevel@tonic-gate * Lock the mdi_pathinfo node. 22627c478bd9Sstevel@tonic-gate * Note: 22637c478bd9Sstevel@tonic-gate * The caller should release the lock by calling mdi_pi_unlock() 22647c478bd9Sstevel@tonic-gate */ 22657c478bd9Sstevel@tonic-gate void 22667c478bd9Sstevel@tonic-gate mdi_pi_lock(mdi_pathinfo_t *pip) 22677c478bd9Sstevel@tonic-gate { 22687c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 22697c478bd9Sstevel@tonic-gate if (pip) { 22707c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 22717c478bd9Sstevel@tonic-gate } 22727c478bd9Sstevel@tonic-gate } 22737c478bd9Sstevel@tonic-gate 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate /* 22767c478bd9Sstevel@tonic-gate * mdi_pi_unlock(): 22777c478bd9Sstevel@tonic-gate * Unlock the mdi_pathinfo node. 22787c478bd9Sstevel@tonic-gate * Note: 22797c478bd9Sstevel@tonic-gate * The mdi_pathinfo node should have been locked with mdi_pi_lock() 22807c478bd9Sstevel@tonic-gate */ 22817c478bd9Sstevel@tonic-gate void 22827c478bd9Sstevel@tonic-gate mdi_pi_unlock(mdi_pathinfo_t *pip) 22837c478bd9Sstevel@tonic-gate { 22847c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 22857c478bd9Sstevel@tonic-gate if (pip) { 22867c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 22877c478bd9Sstevel@tonic-gate } 22887c478bd9Sstevel@tonic-gate } 22897c478bd9Sstevel@tonic-gate 22907c478bd9Sstevel@tonic-gate /* 22917c478bd9Sstevel@tonic-gate * mdi_pi_find(): 22927c478bd9Sstevel@tonic-gate * Search the list of mdi_pathinfo nodes attached to the 22937c478bd9Sstevel@tonic-gate * pHCI/Client device node whose path address matches "paddr". 22947c478bd9Sstevel@tonic-gate * Returns a pointer to the mdi_pathinfo node if a matching node is 22957c478bd9Sstevel@tonic-gate * found. 22967c478bd9Sstevel@tonic-gate * Return Values: 22977c478bd9Sstevel@tonic-gate * mdi_pathinfo node handle 22987c478bd9Sstevel@tonic-gate * NULL 22997c478bd9Sstevel@tonic-gate * Notes: 23007c478bd9Sstevel@tonic-gate * Caller need not hold any locks to call this function. 23017c478bd9Sstevel@tonic-gate */ 23027c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 23037c478bd9Sstevel@tonic-gate mdi_pi_find(dev_info_t *pdip, char *caddr, char *paddr) 23047c478bd9Sstevel@tonic-gate { 23057c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 23067c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 23077c478bd9Sstevel@tonic-gate mdi_client_t *ct; 23087c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 23097c478bd9Sstevel@tonic-gate 23107c478bd9Sstevel@tonic-gate if ((pdip == NULL) || (paddr == NULL)) { 23117c478bd9Sstevel@tonic-gate return (NULL); 23127c478bd9Sstevel@tonic-gate } 23137c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 23147c478bd9Sstevel@tonic-gate if (ph == NULL) { 23157c478bd9Sstevel@tonic-gate /* 23167c478bd9Sstevel@tonic-gate * Invalid pHCI device, Nothing more to do. 23177c478bd9Sstevel@tonic-gate */ 23187c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, NULL, 23197c478bd9Sstevel@tonic-gate "!mdi_pi_find: invalid phci")); 23207c478bd9Sstevel@tonic-gate return (NULL); 23217c478bd9Sstevel@tonic-gate } 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 23247c478bd9Sstevel@tonic-gate if (vh == NULL) { 23257c478bd9Sstevel@tonic-gate /* 23267c478bd9Sstevel@tonic-gate * Invalid vHCI device, Nothing more to do. 23277c478bd9Sstevel@tonic-gate */ 23287c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, NULL, 23297c478bd9Sstevel@tonic-gate "!mdi_pi_find: invalid phci")); 23307c478bd9Sstevel@tonic-gate return (NULL); 23317c478bd9Sstevel@tonic-gate } 23327c478bd9Sstevel@tonic-gate 23337c478bd9Sstevel@tonic-gate /* 23347c478bd9Sstevel@tonic-gate * Look for client device identified by caddr (guid) 23357c478bd9Sstevel@tonic-gate */ 23367c478bd9Sstevel@tonic-gate if (caddr == NULL) { 23377c478bd9Sstevel@tonic-gate /* 23387c478bd9Sstevel@tonic-gate * Find a mdi_pathinfo node under pHCI list for a matching 23397c478bd9Sstevel@tonic-gate * unit address. 23407c478bd9Sstevel@tonic-gate */ 23417c478bd9Sstevel@tonic-gate mutex_enter(&ph->ph_mutex); 23427c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ph->ph_path_head; 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate while (pip != NULL) { 23457c478bd9Sstevel@tonic-gate if (strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 23467c478bd9Sstevel@tonic-gate break; 23477c478bd9Sstevel@tonic-gate } 23487c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 23497c478bd9Sstevel@tonic-gate } 23507c478bd9Sstevel@tonic-gate mutex_exit(&ph->ph_mutex); 23517c478bd9Sstevel@tonic-gate return (pip); 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate /* 2355*3c34adc5Sramat * XXX - Is the rest of the code in this function really necessary? 2356*3c34adc5Sramat * The consumers of mdi_pi_find() can search for the desired pathinfo 2357*3c34adc5Sramat * node by calling mdi_pi_find(pdip, NULL, paddr). Irrespective of 2358*3c34adc5Sramat * whether the search is based on the pathinfo nodes attached to 2359*3c34adc5Sramat * the pHCI or the client node, the result will be the same. 2360*3c34adc5Sramat */ 2361*3c34adc5Sramat 2362*3c34adc5Sramat /* 23637c478bd9Sstevel@tonic-gate * Find the client device corresponding to 'caddr' 23647c478bd9Sstevel@tonic-gate */ 23657c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 2366*3c34adc5Sramat 2367*3c34adc5Sramat /* 2368*3c34adc5Sramat * XXX - Passing NULL to the following function works as long as the 2369*3c34adc5Sramat * the client addresses (caddr) are unique per vhci basis. 2370*3c34adc5Sramat */ 2371*3c34adc5Sramat ct = i_mdi_client_find(vh, NULL, caddr); 23727c478bd9Sstevel@tonic-gate if (ct == NULL) { 23737c478bd9Sstevel@tonic-gate /* 23747c478bd9Sstevel@tonic-gate * Client not found, Obviously mdi_pathinfo node has not been 23757c478bd9Sstevel@tonic-gate * created yet. 23767c478bd9Sstevel@tonic-gate */ 23777c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 23787c478bd9Sstevel@tonic-gate return (pip); 23797c478bd9Sstevel@tonic-gate } 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate /* 23827c478bd9Sstevel@tonic-gate * Hold the client lock and look for a mdi_pathinfo node with matching 23837c478bd9Sstevel@tonic-gate * pHCI and paddr 23847c478bd9Sstevel@tonic-gate */ 23857c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate /* 23887c478bd9Sstevel@tonic-gate * Release the global mutex as it is no more needed. Note: We always 23897c478bd9Sstevel@tonic-gate * respect the locking order while acquiring. 23907c478bd9Sstevel@tonic-gate */ 23917c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 23927c478bd9Sstevel@tonic-gate 23937c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 23947c478bd9Sstevel@tonic-gate while (pip != NULL) { 23957c478bd9Sstevel@tonic-gate /* 23967c478bd9Sstevel@tonic-gate * Compare the unit address 23977c478bd9Sstevel@tonic-gate */ 23987c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 23997c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 24007c478bd9Sstevel@tonic-gate break; 24017c478bd9Sstevel@tonic-gate } 24027c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 24037c478bd9Sstevel@tonic-gate } 24047c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 24057c478bd9Sstevel@tonic-gate return (pip); 24067c478bd9Sstevel@tonic-gate } 24077c478bd9Sstevel@tonic-gate 24087c478bd9Sstevel@tonic-gate /* 24097c478bd9Sstevel@tonic-gate * mdi_pi_alloc(): 24107c478bd9Sstevel@tonic-gate * Allocate and initialize a new instance of a mdi_pathinfo node. 24117c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function identifies a 24127c478bd9Sstevel@tonic-gate * unique device path is capable of having properties attached 24137c478bd9Sstevel@tonic-gate * and passed to mdi_pi_online() to fully attach and online the 24147c478bd9Sstevel@tonic-gate * path and client device node. 24157c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function must be 24167c478bd9Sstevel@tonic-gate * destroyed using mdi_pi_free() if the path is no longer 24177c478bd9Sstevel@tonic-gate * operational or if the caller fails to attach a client device 24187c478bd9Sstevel@tonic-gate * node when calling mdi_pi_online(). The framework will not free 24197c478bd9Sstevel@tonic-gate * the resources allocated. 24207c478bd9Sstevel@tonic-gate * This function can be called from both interrupt and kernel 24217c478bd9Sstevel@tonic-gate * contexts. DDI_NOSLEEP flag should be used while calling 24227c478bd9Sstevel@tonic-gate * from interrupt contexts. 24237c478bd9Sstevel@tonic-gate * Return Values: 24247c478bd9Sstevel@tonic-gate * MDI_SUCCESS 24257c478bd9Sstevel@tonic-gate * MDI_FAILURE 24267c478bd9Sstevel@tonic-gate * MDI_NOMEM 24277c478bd9Sstevel@tonic-gate */ 24287c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 24297c478bd9Sstevel@tonic-gate int 24307c478bd9Sstevel@tonic-gate mdi_pi_alloc_compatible(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 24317c478bd9Sstevel@tonic-gate char **compatible, int ncompatible, int flags, mdi_pathinfo_t **ret_pip) 24327c478bd9Sstevel@tonic-gate { 24337c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 24347c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 24357c478bd9Sstevel@tonic-gate mdi_client_t *ct; 24367c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 24377c478bd9Sstevel@tonic-gate dev_info_t *cdip; 24387c478bd9Sstevel@tonic-gate int rv = MDI_NOMEM; 2439*3c34adc5Sramat int path_allocated = 0; 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate if (pdip == NULL || cname == NULL || caddr == NULL || paddr == NULL || 24427c478bd9Sstevel@tonic-gate ret_pip == NULL) { 24437c478bd9Sstevel@tonic-gate /* Nothing more to do */ 24447c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 24457c478bd9Sstevel@tonic-gate } 24467c478bd9Sstevel@tonic-gate 24477c478bd9Sstevel@tonic-gate *ret_pip = NULL; 24487c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 24497c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 24507c478bd9Sstevel@tonic-gate if (ph == NULL) { 24517c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 24527c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 24537c478bd9Sstevel@tonic-gate "!mdi_pi_alloc: invalid pHCI=%p", pdip)); 24547c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 24557c478bd9Sstevel@tonic-gate } 24567c478bd9Sstevel@tonic-gate 24577c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 24587c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 24597c478bd9Sstevel@tonic-gate if (vh == NULL) { 24607c478bd9Sstevel@tonic-gate /* Invalid vHCI device, return failure */ 24617c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 24627c478bd9Sstevel@tonic-gate "!mdi_pi_alloc: invalid pHCI=%p", pdip)); 24637c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 24647c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 24657c478bd9Sstevel@tonic-gate } 24667c478bd9Sstevel@tonic-gate 24677c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 24687c478bd9Sstevel@tonic-gate /* 24697c478bd9Sstevel@tonic-gate * Do not allow new node creation when pHCI is in 24707c478bd9Sstevel@tonic-gate * offline/suspended states 24717c478bd9Sstevel@tonic-gate */ 24727c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 24737c478bd9Sstevel@tonic-gate "mdi_pi_alloc: pHCI=%p is not ready", ph)); 24747c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 24757c478bd9Sstevel@tonic-gate return (MDI_BUSY); 24767c478bd9Sstevel@tonic-gate } 24777c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 24787c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 24797c478bd9Sstevel@tonic-gate 2480*3c34adc5Sramat /* look for a matching client, create one if not found */ 24817c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 2482*3c34adc5Sramat ct = i_mdi_client_find(vh, cname, caddr); 24837c478bd9Sstevel@tonic-gate if (ct == NULL) { 2484*3c34adc5Sramat ct = i_mdi_client_alloc(vh, cname, caddr); 2485*3c34adc5Sramat ASSERT(ct != NULL); 24867c478bd9Sstevel@tonic-gate } 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 24897c478bd9Sstevel@tonic-gate /* 24907c478bd9Sstevel@tonic-gate * Allocate a devinfo node 24917c478bd9Sstevel@tonic-gate */ 24927c478bd9Sstevel@tonic-gate ct->ct_dip = i_mdi_devinfo_create(vh, cname, caddr, 2493*3c34adc5Sramat compatible, ncompatible); 24947c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 24957c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(vh, ct); 24967c478bd9Sstevel@tonic-gate goto fail; 24977c478bd9Sstevel@tonic-gate } 24987c478bd9Sstevel@tonic-gate } 24997c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component |= MDI_COMPONENT_CLIENT; 25027c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = (caddr_t)ct; 25037c478bd9Sstevel@tonic-gate 25047c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 25057c478bd9Sstevel@tonic-gate while (pip != NULL) { 25067c478bd9Sstevel@tonic-gate /* 25077c478bd9Sstevel@tonic-gate * Compare the unit address 25087c478bd9Sstevel@tonic-gate */ 25097c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 25107c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 25117c478bd9Sstevel@tonic-gate break; 25127c478bd9Sstevel@tonic-gate } 25137c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 25147c478bd9Sstevel@tonic-gate } 25157c478bd9Sstevel@tonic-gate 25167c478bd9Sstevel@tonic-gate if (pip == NULL) { 25177c478bd9Sstevel@tonic-gate /* 25187c478bd9Sstevel@tonic-gate * This is a new path for this client device. Allocate and 25197c478bd9Sstevel@tonic-gate * initialize a new pathinfo node 25207c478bd9Sstevel@tonic-gate */ 2521*3c34adc5Sramat pip = i_mdi_pi_alloc(ph, paddr, ct); 2522*3c34adc5Sramat ASSERT(pip != NULL); 2523*3c34adc5Sramat path_allocated = 1; 25247c478bd9Sstevel@tonic-gate } 25257c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate fail: 25287c478bd9Sstevel@tonic-gate /* 25297c478bd9Sstevel@tonic-gate * Release the global mutex. 25307c478bd9Sstevel@tonic-gate */ 25317c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate /* 25347c478bd9Sstevel@tonic-gate * Mark the pHCI as stable 25357c478bd9Sstevel@tonic-gate */ 25367c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 25377c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 25387c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 25397c478bd9Sstevel@tonic-gate *ret_pip = pip; 2540*3c34adc5Sramat 2541*3c34adc5Sramat if (path_allocated) 2542*3c34adc5Sramat vhcache_pi_add(vh->vh_config, MDI_PI(pip)); 2543*3c34adc5Sramat 25447c478bd9Sstevel@tonic-gate return (rv); 25457c478bd9Sstevel@tonic-gate } 25467c478bd9Sstevel@tonic-gate 25477c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 25487c478bd9Sstevel@tonic-gate int 25497c478bd9Sstevel@tonic-gate mdi_pi_alloc(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 25507c478bd9Sstevel@tonic-gate int flags, mdi_pathinfo_t **ret_pip) 25517c478bd9Sstevel@tonic-gate { 25527c478bd9Sstevel@tonic-gate return (mdi_pi_alloc_compatible(pdip, cname, caddr, paddr, NULL, 0, 25537c478bd9Sstevel@tonic-gate flags, ret_pip)); 25547c478bd9Sstevel@tonic-gate } 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate /* 25577c478bd9Sstevel@tonic-gate * i_mdi_pi_alloc(): 25587c478bd9Sstevel@tonic-gate * Allocate a mdi_pathinfo node and add to the pHCI path list 25597c478bd9Sstevel@tonic-gate * Return Values: 25607c478bd9Sstevel@tonic-gate * mdi_pathinfo 25617c478bd9Sstevel@tonic-gate */ 25627c478bd9Sstevel@tonic-gate 25637c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 25647c478bd9Sstevel@tonic-gate static mdi_pathinfo_t * 2565*3c34adc5Sramat i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct) 25667c478bd9Sstevel@tonic-gate { 2567*3c34adc5Sramat mdi_pathinfo_t *pip; 25687c478bd9Sstevel@tonic-gate int ct_circular; 25697c478bd9Sstevel@tonic-gate int ph_circular; 25707c478bd9Sstevel@tonic-gate 2571*3c34adc5Sramat pip = kmem_zalloc(sizeof (struct mdi_pathinfo), KM_SLEEP); 25727c478bd9Sstevel@tonic-gate mutex_init(&MDI_PI(pip)->pi_mutex, NULL, MUTEX_DEFAULT, NULL); 25737c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PATHINFO_STATE_INIT | 25747c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_TRANSIENT; 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_USER_DISABLED(ph)) 25777c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 25787c478bd9Sstevel@tonic-gate 25797c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED_TRANSIENT(ph)) 25807c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED(ph)) 25837c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 25847c478bd9Sstevel@tonic-gate 25857c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_old_state = MDI_PATHINFO_STATE_INIT; 25867c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_state_cv, NULL, CV_DEFAULT, NULL); 25877c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = ct; 25887c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = ph; 2589*3c34adc5Sramat MDI_PI(pip)->pi_addr = kmem_alloc(strlen(paddr) + 1, KM_SLEEP); 25907c478bd9Sstevel@tonic-gate (void) strcpy(MDI_PI(pip)->pi_addr, paddr); 2591*3c34adc5Sramat (void) nvlist_alloc(&MDI_PI(pip)->pi_prop, NV_UNIQUE_NAME, KM_SLEEP); 2592*3c34adc5Sramat ASSERT(MDI_PI(pip)->pi_prop != NULL); 25937c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = NULL; 25947c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = NULL; 25957c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = NULL; 25967c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 25977c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 25987c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt = 0; 25997c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 26007c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = 1; 26017c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_ref_cv, NULL, CV_DEFAULT, NULL); 26027c478bd9Sstevel@tonic-gate 26037c478bd9Sstevel@tonic-gate /* 26047c478bd9Sstevel@tonic-gate * Lock both dev_info nodes against changes in parallel. 26057c478bd9Sstevel@tonic-gate */ 26067c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 26077c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(ph, pip); 26107c478bd9Sstevel@tonic-gate i_mdi_client_add_path(ct, pip); 26117c478bd9Sstevel@tonic-gate 26127c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 26137c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate return (pip); 26167c478bd9Sstevel@tonic-gate } 26177c478bd9Sstevel@tonic-gate 26187c478bd9Sstevel@tonic-gate /* 26197c478bd9Sstevel@tonic-gate * i_mdi_phci_add_path(): 26207c478bd9Sstevel@tonic-gate * Add a mdi_pathinfo node to pHCI list. 26217c478bd9Sstevel@tonic-gate * Notes: 26227c478bd9Sstevel@tonic-gate * Caller should per-pHCI mutex 26237c478bd9Sstevel@tonic-gate */ 26247c478bd9Sstevel@tonic-gate 26257c478bd9Sstevel@tonic-gate static void 26267c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 26277c478bd9Sstevel@tonic-gate { 26287c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 26297c478bd9Sstevel@tonic-gate 26307c478bd9Sstevel@tonic-gate if (ph->ph_path_head == NULL) { 26317c478bd9Sstevel@tonic-gate ph->ph_path_head = pip; 26327c478bd9Sstevel@tonic-gate } else { 26337c478bd9Sstevel@tonic-gate MDI_PI(ph->ph_path_tail)->pi_phci_link = MDI_PI(pip); 26347c478bd9Sstevel@tonic-gate } 26357c478bd9Sstevel@tonic-gate ph->ph_path_tail = pip; 26367c478bd9Sstevel@tonic-gate ph->ph_path_count++; 26377c478bd9Sstevel@tonic-gate } 26387c478bd9Sstevel@tonic-gate 26397c478bd9Sstevel@tonic-gate /* 26407c478bd9Sstevel@tonic-gate * i_mdi_client_add_path(): 26417c478bd9Sstevel@tonic-gate * Add mdi_pathinfo node to client list 26427c478bd9Sstevel@tonic-gate */ 26437c478bd9Sstevel@tonic-gate 26447c478bd9Sstevel@tonic-gate static void 26457c478bd9Sstevel@tonic-gate i_mdi_client_add_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 26467c478bd9Sstevel@tonic-gate { 26477c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate if (ct->ct_path_head == NULL) { 26507c478bd9Sstevel@tonic-gate ct->ct_path_head = pip; 26517c478bd9Sstevel@tonic-gate } else { 26527c478bd9Sstevel@tonic-gate MDI_PI(ct->ct_path_tail)->pi_client_link = MDI_PI(pip); 26537c478bd9Sstevel@tonic-gate } 26547c478bd9Sstevel@tonic-gate ct->ct_path_tail = pip; 26557c478bd9Sstevel@tonic-gate ct->ct_path_count++; 26567c478bd9Sstevel@tonic-gate } 26577c478bd9Sstevel@tonic-gate 26587c478bd9Sstevel@tonic-gate /* 26597c478bd9Sstevel@tonic-gate * mdi_pi_free(): 26607c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node and also client device node if this 26617c478bd9Sstevel@tonic-gate * is the last path to the device 26627c478bd9Sstevel@tonic-gate * Return Values: 26637c478bd9Sstevel@tonic-gate * MDI_SUCCESS 26647c478bd9Sstevel@tonic-gate * MDI_FAILURE 26657c478bd9Sstevel@tonic-gate * MDI_BUSY 26667c478bd9Sstevel@tonic-gate */ 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 26697c478bd9Sstevel@tonic-gate int 26707c478bd9Sstevel@tonic-gate mdi_pi_free(mdi_pathinfo_t *pip, int flags) 26717c478bd9Sstevel@tonic-gate { 26727c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 26737c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 26747c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 26757c478bd9Sstevel@tonic-gate mdi_client_t *ct; 26767c478bd9Sstevel@tonic-gate int (*f)(); 26777c478bd9Sstevel@tonic-gate int client_held = 0; 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 26807c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 26817c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 26827c478bd9Sstevel@tonic-gate if (ph == NULL) { 26837c478bd9Sstevel@tonic-gate /* 26847c478bd9Sstevel@tonic-gate * Invalid pHCI device, return failure 26857c478bd9Sstevel@tonic-gate */ 26867c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 26877c478bd9Sstevel@tonic-gate "!mdi_pi_free: invalid pHCI")); 26887c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 26897c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 26907c478bd9Sstevel@tonic-gate } 26917c478bd9Sstevel@tonic-gate 26927c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 26937c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 26947c478bd9Sstevel@tonic-gate if (vh == NULL) { 26957c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 26967c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 26977c478bd9Sstevel@tonic-gate "!mdi_pi_free: invalid vHCI")); 26987c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 26997c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27007c478bd9Sstevel@tonic-gate } 27017c478bd9Sstevel@tonic-gate 27027c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 27037c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 27047c478bd9Sstevel@tonic-gate if (ct == NULL) { 27057c478bd9Sstevel@tonic-gate /* 27067c478bd9Sstevel@tonic-gate * Invalid Client device, return failure 27077c478bd9Sstevel@tonic-gate */ 27087c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 27097c478bd9Sstevel@tonic-gate "!mdi_pi_free: invalid client")); 27107c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27117c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 27127c478bd9Sstevel@tonic-gate } 27137c478bd9Sstevel@tonic-gate 27147c478bd9Sstevel@tonic-gate /* 27157c478bd9Sstevel@tonic-gate * Check to see for busy condition. A mdi_pathinfo can only be freed 27167c478bd9Sstevel@tonic-gate * if the node state is either offline or init and the reference count 27177c478bd9Sstevel@tonic-gate * is zero. 27187c478bd9Sstevel@tonic-gate */ 27197c478bd9Sstevel@tonic-gate if (!(MDI_PI_IS_OFFLINE(pip) || MDI_PI_IS_INIT(pip) || 27207c478bd9Sstevel@tonic-gate MDI_PI_IS_INITING(pip))) { 27217c478bd9Sstevel@tonic-gate /* 27227c478bd9Sstevel@tonic-gate * Node is busy 27237c478bd9Sstevel@tonic-gate */ 27247c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 27257c478bd9Sstevel@tonic-gate "!mdi_pi_free: pathinfo node is busy pip=%p", pip)); 27267c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27277c478bd9Sstevel@tonic-gate return (MDI_BUSY); 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 27317c478bd9Sstevel@tonic-gate /* 27327c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 27337c478bd9Sstevel@tonic-gate */ 27347c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, "!i_mdi_pi_free: " 27357c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 27367c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 27377c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 27387c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 27397c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 27407c478bd9Sstevel@tonic-gate /* 27417c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 27427c478bd9Sstevel@tonic-gate * being signaled. 27437c478bd9Sstevel@tonic-gate */ 27447c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, 27457c478bd9Sstevel@tonic-gate "!i_mdi_pi_free: " 27467c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 27477c478bd9Sstevel@tonic-gate pip)); 27487c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, 27497c478bd9Sstevel@tonic-gate "!i_mdi_pi_free: " 27507c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 27517c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 27527c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27537c478bd9Sstevel@tonic-gate return (MDI_BUSY); 27547c478bd9Sstevel@tonic-gate } 27557c478bd9Sstevel@tonic-gate } 27567c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 27577c478bd9Sstevel@tonic-gate client_held = 1; 27587c478bd9Sstevel@tonic-gate } 27597c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 27607c478bd9Sstevel@tonic-gate 2761*3c34adc5Sramat vhcache_pi_remove(vh->vh_config, MDI_PI(pip)); 2762*3c34adc5Sramat 27637c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 27647c478bd9Sstevel@tonic-gate 27657c478bd9Sstevel@tonic-gate /* Prevent further failovers till mdi_mutex is held */ 27667c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_PATH_FREE_IN_PROGRESS(ct); 27677c478bd9Sstevel@tonic-gate 27687c478bd9Sstevel@tonic-gate /* 27697c478bd9Sstevel@tonic-gate * Wait till failover is complete before removing this node. 27707c478bd9Sstevel@tonic-gate */ 27717c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 27727c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 27737c478bd9Sstevel@tonic-gate 27747c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 27757c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 27767c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 27777c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_PATH_FREE_IN_PROGRESS(ct); 27787c478bd9Sstevel@tonic-gate 27797c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_INITING(pip)) { 27807c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_uninit; 27817c478bd9Sstevel@tonic-gate if (f != NULL) { 27827c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 27837c478bd9Sstevel@tonic-gate } 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate /* 27867c478bd9Sstevel@tonic-gate * If vo_pi_uninit() completed successfully. 27877c478bd9Sstevel@tonic-gate */ 27887c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 27897c478bd9Sstevel@tonic-gate if (client_held) { 27907c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_free " 27917c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 27927c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 27937c478bd9Sstevel@tonic-gate } 27947c478bd9Sstevel@tonic-gate i_mdi_pi_free(ph, pip, ct); 27957c478bd9Sstevel@tonic-gate if (ct->ct_path_count == 0) { 27967c478bd9Sstevel@tonic-gate /* 27977c478bd9Sstevel@tonic-gate * Client lost its last path. 27987c478bd9Sstevel@tonic-gate * Clean up the client device 27997c478bd9Sstevel@tonic-gate */ 28007c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 28017c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(ct->ct_vhci, ct); 28027c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 28037c478bd9Sstevel@tonic-gate return (rv); 28047c478bd9Sstevel@tonic-gate } 28057c478bd9Sstevel@tonic-gate } 28067c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 28077c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 2808*3c34adc5Sramat 2809*3c34adc5Sramat if (rv == MDI_FAILURE) 2810*3c34adc5Sramat vhcache_pi_add(vh->vh_config, MDI_PI(pip)); 2811*3c34adc5Sramat 28127c478bd9Sstevel@tonic-gate return (rv); 28137c478bd9Sstevel@tonic-gate } 28147c478bd9Sstevel@tonic-gate 28157c478bd9Sstevel@tonic-gate /* 28167c478bd9Sstevel@tonic-gate * i_mdi_pi_free(): 28177c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node 28187c478bd9Sstevel@tonic-gate */ 28197c478bd9Sstevel@tonic-gate static void 28207c478bd9Sstevel@tonic-gate i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct) 28217c478bd9Sstevel@tonic-gate { 28227c478bd9Sstevel@tonic-gate int ct_circular; 28237c478bd9Sstevel@tonic-gate int ph_circular; 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate /* 28267c478bd9Sstevel@tonic-gate * remove any per-path kstats 28277c478bd9Sstevel@tonic-gate */ 28287c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(pip); 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 28317c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(ct, pip); 28347c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(ph, pip); 28357c478bd9Sstevel@tonic-gate 28367c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 28377c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 28387c478bd9Sstevel@tonic-gate 28397c478bd9Sstevel@tonic-gate mutex_destroy(&MDI_PI(pip)->pi_mutex); 28407c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_state_cv); 28417c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_ref_cv); 28427c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_addr) { 28437c478bd9Sstevel@tonic-gate kmem_free(MDI_PI(pip)->pi_addr, 28447c478bd9Sstevel@tonic-gate strlen(MDI_PI(pip)->pi_addr) + 1); 28457c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr = NULL; 28467c478bd9Sstevel@tonic-gate } 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop) { 28497c478bd9Sstevel@tonic-gate (void) nvlist_free(MDI_PI(pip)->pi_prop); 28507c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_prop = NULL; 28517c478bd9Sstevel@tonic-gate } 28527c478bd9Sstevel@tonic-gate kmem_free(pip, sizeof (struct mdi_pathinfo)); 28537c478bd9Sstevel@tonic-gate } 28547c478bd9Sstevel@tonic-gate 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate /* 28577c478bd9Sstevel@tonic-gate * i_mdi_phci_remove_path(): 28587c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from pHCI list. 28597c478bd9Sstevel@tonic-gate * Notes: 28607c478bd9Sstevel@tonic-gate * Caller should hold per-pHCI mutex 28617c478bd9Sstevel@tonic-gate */ 28627c478bd9Sstevel@tonic-gate 28637c478bd9Sstevel@tonic-gate static void 28647c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 28657c478bd9Sstevel@tonic-gate { 28667c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 28677c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path = NULL; 28687c478bd9Sstevel@tonic-gate 28697c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate path = ph->ph_path_head; 28727c478bd9Sstevel@tonic-gate while (path != NULL) { 28737c478bd9Sstevel@tonic-gate if (path == pip) { 28747c478bd9Sstevel@tonic-gate break; 28757c478bd9Sstevel@tonic-gate } 28767c478bd9Sstevel@tonic-gate prev = path; 28777c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 28787c478bd9Sstevel@tonic-gate } 28797c478bd9Sstevel@tonic-gate 28807c478bd9Sstevel@tonic-gate if (path) { 28817c478bd9Sstevel@tonic-gate ph->ph_path_count--; 28827c478bd9Sstevel@tonic-gate if (prev) { 28837c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_phci_link = MDI_PI(path)->pi_phci_link; 28847c478bd9Sstevel@tonic-gate } else { 28857c478bd9Sstevel@tonic-gate ph->ph_path_head = 28867c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 28877c478bd9Sstevel@tonic-gate } 28887c478bd9Sstevel@tonic-gate if (ph->ph_path_tail == path) { 28897c478bd9Sstevel@tonic-gate ph->ph_path_tail = prev; 28907c478bd9Sstevel@tonic-gate } 28917c478bd9Sstevel@tonic-gate } 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate /* 28947c478bd9Sstevel@tonic-gate * Clear the pHCI link 28957c478bd9Sstevel@tonic-gate */ 28967c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 28977c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = NULL; 28987c478bd9Sstevel@tonic-gate } 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate /* 29017c478bd9Sstevel@tonic-gate * i_mdi_client_remove_path(): 29027c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from client path list. 29037c478bd9Sstevel@tonic-gate */ 29047c478bd9Sstevel@tonic-gate 29057c478bd9Sstevel@tonic-gate static void 29067c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 29077c478bd9Sstevel@tonic-gate { 29087c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 29097c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path; 29107c478bd9Sstevel@tonic-gate 29117c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 29127c478bd9Sstevel@tonic-gate 29137c478bd9Sstevel@tonic-gate path = ct->ct_path_head; 29147c478bd9Sstevel@tonic-gate while (path != NULL) { 29157c478bd9Sstevel@tonic-gate if (path == pip) { 29167c478bd9Sstevel@tonic-gate break; 29177c478bd9Sstevel@tonic-gate } 29187c478bd9Sstevel@tonic-gate prev = path; 29197c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 29207c478bd9Sstevel@tonic-gate } 29217c478bd9Sstevel@tonic-gate 29227c478bd9Sstevel@tonic-gate if (path) { 29237c478bd9Sstevel@tonic-gate ct->ct_path_count--; 29247c478bd9Sstevel@tonic-gate if (prev) { 29257c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_client_link = 29267c478bd9Sstevel@tonic-gate MDI_PI(path)->pi_client_link; 29277c478bd9Sstevel@tonic-gate } else { 29287c478bd9Sstevel@tonic-gate ct->ct_path_head = 29297c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 29307c478bd9Sstevel@tonic-gate } 29317c478bd9Sstevel@tonic-gate if (ct->ct_path_tail == path) { 29327c478bd9Sstevel@tonic-gate ct->ct_path_tail = prev; 29337c478bd9Sstevel@tonic-gate } 29347c478bd9Sstevel@tonic-gate if (ct->ct_path_last == path) { 29357c478bd9Sstevel@tonic-gate ct->ct_path_last = ct->ct_path_head; 29367c478bd9Sstevel@tonic-gate } 29377c478bd9Sstevel@tonic-gate } 29387c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 29397c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = NULL; 29407c478bd9Sstevel@tonic-gate } 29417c478bd9Sstevel@tonic-gate 29427c478bd9Sstevel@tonic-gate /* 29437c478bd9Sstevel@tonic-gate * i_mdi_pi_state_change(): 29447c478bd9Sstevel@tonic-gate * online a mdi_pathinfo node 29457c478bd9Sstevel@tonic-gate * 29467c478bd9Sstevel@tonic-gate * Return Values: 29477c478bd9Sstevel@tonic-gate * MDI_SUCCESS 29487c478bd9Sstevel@tonic-gate * MDI_FAILURE 29497c478bd9Sstevel@tonic-gate */ 29507c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 29517c478bd9Sstevel@tonic-gate static int 29527c478bd9Sstevel@tonic-gate i_mdi_pi_state_change(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state, int flag) 29537c478bd9Sstevel@tonic-gate { 29547c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 29557c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 29567c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 29577c478bd9Sstevel@tonic-gate mdi_client_t *ct; 29587c478bd9Sstevel@tonic-gate int (*f)(); 29597c478bd9Sstevel@tonic-gate dev_info_t *cdip; 29607c478bd9Sstevel@tonic-gate 29617c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 29627c478bd9Sstevel@tonic-gate 29637c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 29647c478bd9Sstevel@tonic-gate ASSERT(ph); 29657c478bd9Sstevel@tonic-gate if (ph == NULL) { 29667c478bd9Sstevel@tonic-gate /* 29677c478bd9Sstevel@tonic-gate * Invalid pHCI device, fail the request 29687c478bd9Sstevel@tonic-gate */ 29697c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 29707c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 29717c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: invalid phci")); 29727c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 29737c478bd9Sstevel@tonic-gate } 29747c478bd9Sstevel@tonic-gate 29757c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 29767c478bd9Sstevel@tonic-gate ASSERT(vh); 29777c478bd9Sstevel@tonic-gate if (vh == NULL) { 29787c478bd9Sstevel@tonic-gate /* 29797c478bd9Sstevel@tonic-gate * Invalid vHCI device, fail the request 29807c478bd9Sstevel@tonic-gate */ 29817c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 29827c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 29837c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: invalid vhci")); 29847c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 29857c478bd9Sstevel@tonic-gate } 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 29887c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 29897c478bd9Sstevel@tonic-gate if (ct == NULL) { 29907c478bd9Sstevel@tonic-gate /* 29917c478bd9Sstevel@tonic-gate * Invalid client device, fail the request 29927c478bd9Sstevel@tonic-gate */ 29937c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 29947c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 29957c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: invalid client")); 29967c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 29977c478bd9Sstevel@tonic-gate } 29987c478bd9Sstevel@tonic-gate 29997c478bd9Sstevel@tonic-gate /* 30007c478bd9Sstevel@tonic-gate * If this path has not been initialized yet, Callback vHCI driver's 30017c478bd9Sstevel@tonic-gate * pathinfo node initialize entry point 30027c478bd9Sstevel@tonic-gate */ 30037c478bd9Sstevel@tonic-gate 30047c478bd9Sstevel@tonic-gate if (MDI_PI_IS_INITING(pip)) { 30057c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30067c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_init; 30077c478bd9Sstevel@tonic-gate if (f != NULL) { 30087c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 30097c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 30107c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, vh->vh_dip, 30117c478bd9Sstevel@tonic-gate "!vo_pi_init: failed vHCI=0x%p, pip=0x%p", 30127c478bd9Sstevel@tonic-gate vh, pip)); 30137c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 30147c478bd9Sstevel@tonic-gate } 30157c478bd9Sstevel@tonic-gate } 30167c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 30177c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 30187c478bd9Sstevel@tonic-gate } 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate /* 30217c478bd9Sstevel@tonic-gate * Do not allow state transition when pHCI is in offline/suspended 30227c478bd9Sstevel@tonic-gate * states 30237c478bd9Sstevel@tonic-gate */ 30247c478bd9Sstevel@tonic-gate i_mdi_phci_lock(ph, pip); 30257c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 30267c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 30277c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: pHCI not ready, pHCI=%p", ph)); 30287c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30297c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 30307c478bd9Sstevel@tonic-gate return (MDI_BUSY); 30317c478bd9Sstevel@tonic-gate } 30327c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 30337c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 30347c478bd9Sstevel@tonic-gate 30357c478bd9Sstevel@tonic-gate /* 30367c478bd9Sstevel@tonic-gate * Check if mdi_pathinfo state is in transient state. 30377c478bd9Sstevel@tonic-gate * If yes, offlining is in progress and wait till transient state is 30387c478bd9Sstevel@tonic-gate * cleared. 30397c478bd9Sstevel@tonic-gate */ 30407c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 30417c478bd9Sstevel@tonic-gate while (MDI_PI_IS_TRANSIENT(pip)) { 30427c478bd9Sstevel@tonic-gate cv_wait(&MDI_PI(pip)->pi_state_cv, 30437c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex); 30447c478bd9Sstevel@tonic-gate } 30457c478bd9Sstevel@tonic-gate } 30467c478bd9Sstevel@tonic-gate 30477c478bd9Sstevel@tonic-gate /* 30487c478bd9Sstevel@tonic-gate * Grab the client lock in reverse order sequence and release the 30497c478bd9Sstevel@tonic-gate * mdi_pathinfo mutex. 30507c478bd9Sstevel@tonic-gate */ 30517c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 30527c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30537c478bd9Sstevel@tonic-gate 30547c478bd9Sstevel@tonic-gate /* 30557c478bd9Sstevel@tonic-gate * Wait till failover state is cleared 30567c478bd9Sstevel@tonic-gate */ 30577c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 30587c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate /* 30617c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 30627c478bd9Sstevel@tonic-gate */ 30637c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 30647c478bd9Sstevel@tonic-gate switch (state) { 30657c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_ONLINE: 30667c478bd9Sstevel@tonic-gate MDI_PI_SET_ONLINING(pip); 30677c478bd9Sstevel@tonic-gate break; 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_STANDBY: 30707c478bd9Sstevel@tonic-gate MDI_PI_SET_STANDBYING(pip); 30717c478bd9Sstevel@tonic-gate break; 30727c478bd9Sstevel@tonic-gate 30737c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_FAULT: 30747c478bd9Sstevel@tonic-gate /* 30757c478bd9Sstevel@tonic-gate * Mark the pathinfo state as FAULTED 30767c478bd9Sstevel@tonic-gate */ 30777c478bd9Sstevel@tonic-gate MDI_PI_SET_FAULTING(pip); 30787c478bd9Sstevel@tonic-gate MDI_PI_ERRSTAT(pip, MDI_PI_HARDERR); 30797c478bd9Sstevel@tonic-gate break; 30807c478bd9Sstevel@tonic-gate 30817c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_OFFLINE: 30827c478bd9Sstevel@tonic-gate /* 30837c478bd9Sstevel@tonic-gate * ndi_devi_offline() cannot hold pip or ct locks. 30847c478bd9Sstevel@tonic-gate */ 30857c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 30867c478bd9Sstevel@tonic-gate /* 30877c478bd9Sstevel@tonic-gate * Do not offline if path will become last path and path 30887c478bd9Sstevel@tonic-gate * is busy for user initiated events. 30897c478bd9Sstevel@tonic-gate */ 30907c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 30917c478bd9Sstevel@tonic-gate if ((flag & NDI_DEVI_REMOVE) && 30927c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED)) { 30937c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 30947c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 30957c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 30967c478bd9Sstevel@tonic-gate /* 30977c478bd9Sstevel@tonic-gate * Convert to MDI error code 30987c478bd9Sstevel@tonic-gate */ 30997c478bd9Sstevel@tonic-gate switch (rv) { 31007c478bd9Sstevel@tonic-gate case NDI_BUSY: 31017c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 31027c478bd9Sstevel@tonic-gate break; 31037c478bd9Sstevel@tonic-gate default: 31047c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 31057c478bd9Sstevel@tonic-gate break; 31067c478bd9Sstevel@tonic-gate } 31077c478bd9Sstevel@tonic-gate goto state_change_exit; 31087c478bd9Sstevel@tonic-gate } else { 31097c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 31107c478bd9Sstevel@tonic-gate } 31117c478bd9Sstevel@tonic-gate } 31127c478bd9Sstevel@tonic-gate /* 31137c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 31147c478bd9Sstevel@tonic-gate */ 31157c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 31167c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 31177c478bd9Sstevel@tonic-gate break; 31187c478bd9Sstevel@tonic-gate } 31197c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31207c478bd9Sstevel@tonic-gate MDI_CLIENT_UNSTABLE(ct); 31217c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 31227c478bd9Sstevel@tonic-gate 31237c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 31247c478bd9Sstevel@tonic-gate if (f != NULL) { 31257c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, state, 0, flag); 31267c478bd9Sstevel@tonic-gate if (rv == MDI_NOT_SUPPORTED) { 31277c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DEV_NOT_SUPPORTED(ct); 31287c478bd9Sstevel@tonic-gate } 31297c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 31307c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 31317c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 31327c478bd9Sstevel@tonic-gate } 31337c478bd9Sstevel@tonic-gate } 31347c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 31357c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 31367c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 31377c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 31387c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 31397c478bd9Sstevel@tonic-gate } else { 31407c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip); 31417c478bd9Sstevel@tonic-gate } 31427c478bd9Sstevel@tonic-gate } 31437c478bd9Sstevel@tonic-gate 31447c478bd9Sstevel@tonic-gate /* 31457c478bd9Sstevel@tonic-gate * Wake anyone waiting for this mdi_pathinfo node 31467c478bd9Sstevel@tonic-gate */ 31477c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 31487c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 31497c478bd9Sstevel@tonic-gate 31507c478bd9Sstevel@tonic-gate /* 31517c478bd9Sstevel@tonic-gate * Mark the client device as stable 31527c478bd9Sstevel@tonic-gate */ 31537c478bd9Sstevel@tonic-gate MDI_CLIENT_STABLE(ct); 31547c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 31557c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 31567c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 31577c478bd9Sstevel@tonic-gate 31587c478bd9Sstevel@tonic-gate /* 31597c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 31607c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 31617c478bd9Sstevel@tonic-gate * state accordingly 31627c478bd9Sstevel@tonic-gate */ 31637c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 31647c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 31657c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 31667c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 31677c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 31687c478bd9Sstevel@tonic-gate if (cdip && 31697c478bd9Sstevel@tonic-gate (i_ddi_node_state(cdip) < DS_READY) && 31707c478bd9Sstevel@tonic-gate ((state == MDI_PATHINFO_STATE_ONLINE) || 31717c478bd9Sstevel@tonic-gate (state == MDI_PATHINFO_STATE_STANDBY))) { 31727c478bd9Sstevel@tonic-gate 31737c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 31747c478bd9Sstevel@tonic-gate /* 31757c478bd9Sstevel@tonic-gate * Must do ndi_devi_online() through 31767c478bd9Sstevel@tonic-gate * hotplug thread for deferred 31777c478bd9Sstevel@tonic-gate * attach mechanism to work 31787c478bd9Sstevel@tonic-gate */ 31797c478bd9Sstevel@tonic-gate rv = ndi_devi_online(cdip, 0); 31807c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 31817c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && 31827c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == 31837c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_DEGRADED)) { 31847c478bd9Sstevel@tonic-gate /* 31857c478bd9Sstevel@tonic-gate * ndi_devi_online failed. 31867c478bd9Sstevel@tonic-gate * Reset client flags to 31877c478bd9Sstevel@tonic-gate * offline. 31887c478bd9Sstevel@tonic-gate */ 31897c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 31907c478bd9Sstevel@tonic-gate "!ndi_devi_online: failed " 31917c478bd9Sstevel@tonic-gate " Error: %x", rv)); 31927c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 31937c478bd9Sstevel@tonic-gate } 31947c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 31957c478bd9Sstevel@tonic-gate /* Reset the path state */ 31967c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 31977c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = 31987c478bd9Sstevel@tonic-gate MDI_PI_OLD_STATE(pip); 31997c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 32007c478bd9Sstevel@tonic-gate } 32017c478bd9Sstevel@tonic-gate } 32027c478bd9Sstevel@tonic-gate break; 32037c478bd9Sstevel@tonic-gate 32047c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 32057c478bd9Sstevel@tonic-gate /* 32067c478bd9Sstevel@tonic-gate * This is the last path case for 32077c478bd9Sstevel@tonic-gate * non-user initiated events. 32087c478bd9Sstevel@tonic-gate */ 32097c478bd9Sstevel@tonic-gate if (((flag & NDI_DEVI_REMOVE) == 0) && 32107c478bd9Sstevel@tonic-gate cdip && (i_ddi_node_state(cdip) >= 32117c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 32127c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 32137c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 32147c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 32157c478bd9Sstevel@tonic-gate 32167c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 32177c478bd9Sstevel@tonic-gate /* 32187c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 32197c478bd9Sstevel@tonic-gate * Reset client flags to 32207c478bd9Sstevel@tonic-gate * online as the path could not 32217c478bd9Sstevel@tonic-gate * be offlined. 32227c478bd9Sstevel@tonic-gate */ 32237c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 32247c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 32257c478bd9Sstevel@tonic-gate " Error: %x", rv)); 32267c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 32277c478bd9Sstevel@tonic-gate } 32287c478bd9Sstevel@tonic-gate } 32297c478bd9Sstevel@tonic-gate break; 32307c478bd9Sstevel@tonic-gate } 32317c478bd9Sstevel@tonic-gate /* 32327c478bd9Sstevel@tonic-gate * Convert to MDI error code 32337c478bd9Sstevel@tonic-gate */ 32347c478bd9Sstevel@tonic-gate switch (rv) { 32357c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 32367c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 32377c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 32387c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 32397c478bd9Sstevel@tonic-gate break; 32407c478bd9Sstevel@tonic-gate case NDI_BUSY: 32417c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 32427c478bd9Sstevel@tonic-gate break; 32437c478bd9Sstevel@tonic-gate default: 32447c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 32457c478bd9Sstevel@tonic-gate break; 32467c478bd9Sstevel@tonic-gate } 32477c478bd9Sstevel@tonic-gate } 32487c478bd9Sstevel@tonic-gate } 32497c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 32507c478bd9Sstevel@tonic-gate 32517c478bd9Sstevel@tonic-gate state_change_exit: 32527c478bd9Sstevel@tonic-gate /* 32537c478bd9Sstevel@tonic-gate * Mark the pHCI as stable again. 32547c478bd9Sstevel@tonic-gate */ 32557c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 32567c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 32577c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 32587c478bd9Sstevel@tonic-gate return (rv); 32597c478bd9Sstevel@tonic-gate } 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate /* 32627c478bd9Sstevel@tonic-gate * mdi_pi_online(): 32637c478bd9Sstevel@tonic-gate * Place the path_info node in the online state. The path is 32647c478bd9Sstevel@tonic-gate * now available to be selected by mdi_select_path() for 32657c478bd9Sstevel@tonic-gate * transporting I/O requests to client devices. 32667c478bd9Sstevel@tonic-gate * Return Values: 32677c478bd9Sstevel@tonic-gate * MDI_SUCCESS 32687c478bd9Sstevel@tonic-gate * MDI_FAILURE 32697c478bd9Sstevel@tonic-gate */ 32707c478bd9Sstevel@tonic-gate int 32717c478bd9Sstevel@tonic-gate mdi_pi_online(mdi_pathinfo_t *pip, int flags) 32727c478bd9Sstevel@tonic-gate { 32737c478bd9Sstevel@tonic-gate mdi_client_t *ct = MDI_PI(pip)->pi_client; 32747c478bd9Sstevel@tonic-gate dev_info_t *cdip; 32757c478bd9Sstevel@tonic-gate int client_held = 0; 32767c478bd9Sstevel@tonic-gate int rv; 32777c478bd9Sstevel@tonic-gate 32787c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 32797c478bd9Sstevel@tonic-gate rv = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_ONLINE, flags); 32807c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) 32817c478bd9Sstevel@tonic-gate return (rv); 32827c478bd9Sstevel@tonic-gate 32837c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 32847c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 32857c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 32867c478bd9Sstevel@tonic-gate "i_mdi_pm_hold_pip\n")); 32877c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 32887c478bd9Sstevel@tonic-gate client_held = 1; 32897c478bd9Sstevel@tonic-gate } 32907c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 32917c478bd9Sstevel@tonic-gate 32927c478bd9Sstevel@tonic-gate if (client_held) { 32937c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 32947c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 32957c478bd9Sstevel@tonic-gate rv = i_mdi_power_all_phci(ct); 32967c478bd9Sstevel@tonic-gate } 32977c478bd9Sstevel@tonic-gate 32987c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 32997c478bd9Sstevel@tonic-gate "i_mdi_pm_hold_client\n")); 33007c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 33017c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 33027c478bd9Sstevel@tonic-gate } 33037c478bd9Sstevel@tonic-gate 33047c478bd9Sstevel@tonic-gate /* 33057c478bd9Sstevel@tonic-gate * Create the per-path (pathinfo) IO and error kstats which 33067c478bd9Sstevel@tonic-gate * are reported via iostat(1m). 33077c478bd9Sstevel@tonic-gate * 33087c478bd9Sstevel@tonic-gate * Defer creating the per-path kstats if device is not yet 33097c478bd9Sstevel@tonic-gate * attached; the names of the kstats are constructed in part 33107c478bd9Sstevel@tonic-gate * using the devices instance number which is assigned during 33117c478bd9Sstevel@tonic-gate * process of attaching the client device. 33127c478bd9Sstevel@tonic-gate * 33137c478bd9Sstevel@tonic-gate * The framework post_attach handler, mdi_post_attach(), is 33147c478bd9Sstevel@tonic-gate * is responsible for initializing the client's pathinfo list 33157c478bd9Sstevel@tonic-gate * once successfully attached. 33167c478bd9Sstevel@tonic-gate */ 33177c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 33187c478bd9Sstevel@tonic-gate ASSERT(cdip); 33197c478bd9Sstevel@tonic-gate if (cdip == NULL || (i_ddi_node_state(cdip) < DS_ATTACHED)) 33207c478bd9Sstevel@tonic-gate return (rv); 33217c478bd9Sstevel@tonic-gate 33227c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 33237c478bd9Sstevel@tonic-gate rv = i_mdi_pi_kstat_create(pip); 33247c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 33257c478bd9Sstevel@tonic-gate return (rv); 33267c478bd9Sstevel@tonic-gate } 33277c478bd9Sstevel@tonic-gate 33287c478bd9Sstevel@tonic-gate /* 33297c478bd9Sstevel@tonic-gate * mdi_pi_standby(): 33307c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in standby state 33317c478bd9Sstevel@tonic-gate * 33327c478bd9Sstevel@tonic-gate * Return Values: 33337c478bd9Sstevel@tonic-gate * MDI_SUCCESS 33347c478bd9Sstevel@tonic-gate * MDI_FAILURE 33357c478bd9Sstevel@tonic-gate */ 33367c478bd9Sstevel@tonic-gate int 33377c478bd9Sstevel@tonic-gate mdi_pi_standby(mdi_pathinfo_t *pip, int flags) 33387c478bd9Sstevel@tonic-gate { 33397c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_STANDBY, flags)); 33407c478bd9Sstevel@tonic-gate } 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate /* 33437c478bd9Sstevel@tonic-gate * mdi_pi_fault(): 33447c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in fault'ed state 33457c478bd9Sstevel@tonic-gate * Return Values: 33467c478bd9Sstevel@tonic-gate * MDI_SUCCESS 33477c478bd9Sstevel@tonic-gate * MDI_FAILURE 33487c478bd9Sstevel@tonic-gate */ 33497c478bd9Sstevel@tonic-gate int 33507c478bd9Sstevel@tonic-gate mdi_pi_fault(mdi_pathinfo_t *pip, int flags) 33517c478bd9Sstevel@tonic-gate { 33527c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_FAULT, flags)); 33537c478bd9Sstevel@tonic-gate } 33547c478bd9Sstevel@tonic-gate 33557c478bd9Sstevel@tonic-gate /* 33567c478bd9Sstevel@tonic-gate * mdi_pi_offline(): 33577c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node. 33587c478bd9Sstevel@tonic-gate * Return Values: 33597c478bd9Sstevel@tonic-gate * MDI_SUCCESS 33607c478bd9Sstevel@tonic-gate * MDI_FAILURE 33617c478bd9Sstevel@tonic-gate */ 33627c478bd9Sstevel@tonic-gate int 33637c478bd9Sstevel@tonic-gate mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 33647c478bd9Sstevel@tonic-gate { 33657c478bd9Sstevel@tonic-gate int ret, client_held = 0; 33667c478bd9Sstevel@tonic-gate mdi_client_t *ct; 33677c478bd9Sstevel@tonic-gate 33687c478bd9Sstevel@tonic-gate ret = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_OFFLINE, flags); 33697c478bd9Sstevel@tonic-gate 33707c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) { 33717c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 33727c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 33737c478bd9Sstevel@tonic-gate client_held = 1; 33747c478bd9Sstevel@tonic-gate } 33757c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 33767c478bd9Sstevel@tonic-gate 33777c478bd9Sstevel@tonic-gate if (client_held) { 33787c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 33797c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 33807c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, 33817c478bd9Sstevel@tonic-gate "mdi_pi_offline i_mdi_pm_rele_client\n")); 33827c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 33837c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 33847c478bd9Sstevel@tonic-gate } 33857c478bd9Sstevel@tonic-gate } 33867c478bd9Sstevel@tonic-gate 33877c478bd9Sstevel@tonic-gate return (ret); 33887c478bd9Sstevel@tonic-gate } 33897c478bd9Sstevel@tonic-gate 33907c478bd9Sstevel@tonic-gate /* 33917c478bd9Sstevel@tonic-gate * i_mdi_pi_offline(): 33927c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node and call the vHCI driver's callback 33937c478bd9Sstevel@tonic-gate */ 33947c478bd9Sstevel@tonic-gate static int 33957c478bd9Sstevel@tonic-gate i_mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 33967c478bd9Sstevel@tonic-gate { 33977c478bd9Sstevel@tonic-gate dev_info_t *vdip = NULL; 33987c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 33997c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 34007c478bd9Sstevel@tonic-gate int (*f)(); 34017c478bd9Sstevel@tonic-gate int rv; 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34047c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 34057c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 34067c478bd9Sstevel@tonic-gate 34077c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 34087c478bd9Sstevel@tonic-gate /* 34097c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 34107c478bd9Sstevel@tonic-gate */ 34117c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 34127c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 34137c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 34147c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 34157c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 34167c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 34177c478bd9Sstevel@tonic-gate /* 34187c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 34197c478bd9Sstevel@tonic-gate * being signaled. 34207c478bd9Sstevel@tonic-gate */ 34217c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 34227c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 34237c478bd9Sstevel@tonic-gate pip)); 34247c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 34257c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 34267c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 34277c478bd9Sstevel@tonic-gate } 34287c478bd9Sstevel@tonic-gate } 34297c478bd9Sstevel@tonic-gate vh = ct->ct_vhci; 34307c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 34317c478bd9Sstevel@tonic-gate 34327c478bd9Sstevel@tonic-gate /* 34337c478bd9Sstevel@tonic-gate * Notify vHCI that has registered this event 34347c478bd9Sstevel@tonic-gate */ 34357c478bd9Sstevel@tonic-gate ASSERT(vh->vh_ops); 34367c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate if (f != NULL) { 34397c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34407c478bd9Sstevel@tonic-gate if ((rv = (*f)(vdip, pip, MDI_PATHINFO_STATE_OFFLINE, 0, 34417c478bd9Sstevel@tonic-gate flags)) != MDI_SUCCESS) { 34427c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, vdip, "!vo_path_offline failed " 34437c478bd9Sstevel@tonic-gate "vdip 0x%x, pip 0x%x", vdip, pip)); 34447c478bd9Sstevel@tonic-gate } 34457c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 34467c478bd9Sstevel@tonic-gate } 34477c478bd9Sstevel@tonic-gate 34487c478bd9Sstevel@tonic-gate /* 34497c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state and clear the transient condition 34507c478bd9Sstevel@tonic-gate */ 34517c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINE(pip); 34527c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 34537c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 34547c478bd9Sstevel@tonic-gate 34557c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 34567c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 34577c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 34587c478bd9Sstevel@tonic-gate dev_info_t *cdip = ct->ct_dip; 34597c478bd9Sstevel@tonic-gate 34607c478bd9Sstevel@tonic-gate /* 34617c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 34627c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 34637c478bd9Sstevel@tonic-gate * state accordingly 34647c478bd9Sstevel@tonic-gate */ 34657c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 34667c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 34677c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 34687c478bd9Sstevel@tonic-gate if (cdip && 34697c478bd9Sstevel@tonic-gate (i_ddi_node_state(cdip) >= 34707c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 34717c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 34727c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 34737c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 34747c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 34757c478bd9Sstevel@tonic-gate /* 34767c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 34777c478bd9Sstevel@tonic-gate * Reset client flags to 34787c478bd9Sstevel@tonic-gate * online. 34797c478bd9Sstevel@tonic-gate */ 34807c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, cdip, 34817c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 34827c478bd9Sstevel@tonic-gate " Error: %x", rv)); 34837c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 34847c478bd9Sstevel@tonic-gate } 34857c478bd9Sstevel@tonic-gate } 34867c478bd9Sstevel@tonic-gate } 34877c478bd9Sstevel@tonic-gate /* 34887c478bd9Sstevel@tonic-gate * Convert to MDI error code 34897c478bd9Sstevel@tonic-gate */ 34907c478bd9Sstevel@tonic-gate switch (rv) { 34917c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 34927c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 34937c478bd9Sstevel@tonic-gate break; 34947c478bd9Sstevel@tonic-gate case NDI_BUSY: 34957c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 34967c478bd9Sstevel@tonic-gate break; 34977c478bd9Sstevel@tonic-gate default: 34987c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 34997c478bd9Sstevel@tonic-gate break; 35007c478bd9Sstevel@tonic-gate } 35017c478bd9Sstevel@tonic-gate } 35027c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 35037c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 35047c478bd9Sstevel@tonic-gate } 35057c478bd9Sstevel@tonic-gate 35067c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 35077c478bd9Sstevel@tonic-gate 35087c478bd9Sstevel@tonic-gate /* 35097c478bd9Sstevel@tonic-gate * Change in the mdi_pathinfo node state will impact the client state 35107c478bd9Sstevel@tonic-gate */ 35117c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!i_mdi_pi_offline ct = %p pip = %p", 35127c478bd9Sstevel@tonic-gate ct, pip)); 35137c478bd9Sstevel@tonic-gate return (rv); 35147c478bd9Sstevel@tonic-gate } 35157c478bd9Sstevel@tonic-gate 35167c478bd9Sstevel@tonic-gate 35177c478bd9Sstevel@tonic-gate /* 35187c478bd9Sstevel@tonic-gate * mdi_pi_get_addr(): 35197c478bd9Sstevel@tonic-gate * Get the unit address associated with a mdi_pathinfo node 35207c478bd9Sstevel@tonic-gate * 35217c478bd9Sstevel@tonic-gate * Return Values: 35227c478bd9Sstevel@tonic-gate * char * 35237c478bd9Sstevel@tonic-gate */ 35247c478bd9Sstevel@tonic-gate char * 35257c478bd9Sstevel@tonic-gate mdi_pi_get_addr(mdi_pathinfo_t *pip) 35267c478bd9Sstevel@tonic-gate { 35277c478bd9Sstevel@tonic-gate if (pip == NULL) 35287c478bd9Sstevel@tonic-gate return (NULL); 35297c478bd9Sstevel@tonic-gate 353072a50065Scth return (MDI_PI(pip)->pi_addr); 35317c478bd9Sstevel@tonic-gate } 35327c478bd9Sstevel@tonic-gate 35337c478bd9Sstevel@tonic-gate /* 35347c478bd9Sstevel@tonic-gate * mdi_pi_get_client(): 35357c478bd9Sstevel@tonic-gate * Get the client devinfo associated with a mdi_pathinfo node 35367c478bd9Sstevel@tonic-gate * 35377c478bd9Sstevel@tonic-gate * Return Values: 35387c478bd9Sstevel@tonic-gate * Handle to client device dev_info node 35397c478bd9Sstevel@tonic-gate */ 35407c478bd9Sstevel@tonic-gate dev_info_t * 35417c478bd9Sstevel@tonic-gate mdi_pi_get_client(mdi_pathinfo_t *pip) 35427c478bd9Sstevel@tonic-gate { 35437c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 35447c478bd9Sstevel@tonic-gate if (pip) { 35457c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_client->ct_dip; 35467c478bd9Sstevel@tonic-gate } 35477c478bd9Sstevel@tonic-gate return (dip); 35487c478bd9Sstevel@tonic-gate } 35497c478bd9Sstevel@tonic-gate 35507c478bd9Sstevel@tonic-gate /* 35517c478bd9Sstevel@tonic-gate * mdi_pi_get_phci(): 35527c478bd9Sstevel@tonic-gate * Get the pHCI devinfo associated with the mdi_pathinfo node 35537c478bd9Sstevel@tonic-gate * Return Values: 35547c478bd9Sstevel@tonic-gate * Handle to dev_info node 35557c478bd9Sstevel@tonic-gate */ 35567c478bd9Sstevel@tonic-gate dev_info_t * 35577c478bd9Sstevel@tonic-gate mdi_pi_get_phci(mdi_pathinfo_t *pip) 35587c478bd9Sstevel@tonic-gate { 35597c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 35607c478bd9Sstevel@tonic-gate if (pip) { 35617c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_phci->ph_dip; 35627c478bd9Sstevel@tonic-gate } 35637c478bd9Sstevel@tonic-gate return (dip); 35647c478bd9Sstevel@tonic-gate } 35657c478bd9Sstevel@tonic-gate 35667c478bd9Sstevel@tonic-gate /* 35677c478bd9Sstevel@tonic-gate * mdi_pi_get_client_private(): 35687c478bd9Sstevel@tonic-gate * Get the client private information associated with the 35697c478bd9Sstevel@tonic-gate * mdi_pathinfo node 35707c478bd9Sstevel@tonic-gate */ 35717c478bd9Sstevel@tonic-gate void * 35727c478bd9Sstevel@tonic-gate mdi_pi_get_client_private(mdi_pathinfo_t *pip) 35737c478bd9Sstevel@tonic-gate { 35747c478bd9Sstevel@tonic-gate void *cprivate = NULL; 35757c478bd9Sstevel@tonic-gate if (pip) { 35767c478bd9Sstevel@tonic-gate cprivate = MDI_PI(pip)->pi_cprivate; 35777c478bd9Sstevel@tonic-gate } 35787c478bd9Sstevel@tonic-gate return (cprivate); 35797c478bd9Sstevel@tonic-gate } 35807c478bd9Sstevel@tonic-gate 35817c478bd9Sstevel@tonic-gate /* 35827c478bd9Sstevel@tonic-gate * mdi_pi_set_client_private(): 35837c478bd9Sstevel@tonic-gate * Set the client private information in the mdi_pathinfo node 35847c478bd9Sstevel@tonic-gate */ 35857c478bd9Sstevel@tonic-gate void 35867c478bd9Sstevel@tonic-gate mdi_pi_set_client_private(mdi_pathinfo_t *pip, void *priv) 35877c478bd9Sstevel@tonic-gate { 35887c478bd9Sstevel@tonic-gate if (pip) { 35897c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = priv; 35907c478bd9Sstevel@tonic-gate } 35917c478bd9Sstevel@tonic-gate } 35927c478bd9Sstevel@tonic-gate 35937c478bd9Sstevel@tonic-gate /* 35947c478bd9Sstevel@tonic-gate * mdi_pi_get_phci_private(): 35957c478bd9Sstevel@tonic-gate * Get the pHCI private information associated with the 35967c478bd9Sstevel@tonic-gate * mdi_pathinfo node 35977c478bd9Sstevel@tonic-gate */ 35987c478bd9Sstevel@tonic-gate caddr_t 35997c478bd9Sstevel@tonic-gate mdi_pi_get_phci_private(mdi_pathinfo_t *pip) 36007c478bd9Sstevel@tonic-gate { 36017c478bd9Sstevel@tonic-gate caddr_t pprivate = NULL; 36027c478bd9Sstevel@tonic-gate if (pip) { 36037c478bd9Sstevel@tonic-gate pprivate = MDI_PI(pip)->pi_pprivate; 36047c478bd9Sstevel@tonic-gate } 36057c478bd9Sstevel@tonic-gate return (pprivate); 36067c478bd9Sstevel@tonic-gate } 36077c478bd9Sstevel@tonic-gate 36087c478bd9Sstevel@tonic-gate /* 36097c478bd9Sstevel@tonic-gate * mdi_pi_set_phci_private(): 36107c478bd9Sstevel@tonic-gate * Set the pHCI private information in the mdi_pathinfo node 36117c478bd9Sstevel@tonic-gate */ 36127c478bd9Sstevel@tonic-gate void 36137c478bd9Sstevel@tonic-gate mdi_pi_set_phci_private(mdi_pathinfo_t *pip, caddr_t priv) 36147c478bd9Sstevel@tonic-gate { 36157c478bd9Sstevel@tonic-gate if (pip) { 36167c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = priv; 36177c478bd9Sstevel@tonic-gate } 36187c478bd9Sstevel@tonic-gate } 36197c478bd9Sstevel@tonic-gate 36207c478bd9Sstevel@tonic-gate /* 36217c478bd9Sstevel@tonic-gate * mdi_pi_get_state(): 36227c478bd9Sstevel@tonic-gate * Get the mdi_pathinfo node state. Transient states are internal 36237c478bd9Sstevel@tonic-gate * and not provided to the users 36247c478bd9Sstevel@tonic-gate */ 36257c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t 36267c478bd9Sstevel@tonic-gate mdi_pi_get_state(mdi_pathinfo_t *pip) 36277c478bd9Sstevel@tonic-gate { 36287c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t state = MDI_PATHINFO_STATE_INIT; 36297c478bd9Sstevel@tonic-gate 36307c478bd9Sstevel@tonic-gate if (pip) { 36317c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 36327c478bd9Sstevel@tonic-gate /* 36337c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 36347c478bd9Sstevel@tonic-gate * last good state. 36357c478bd9Sstevel@tonic-gate */ 36367c478bd9Sstevel@tonic-gate state = MDI_PI_OLD_STATE(pip); 36377c478bd9Sstevel@tonic-gate } else { 36387c478bd9Sstevel@tonic-gate state = MDI_PI_STATE(pip); 36397c478bd9Sstevel@tonic-gate } 36407c478bd9Sstevel@tonic-gate } 36417c478bd9Sstevel@tonic-gate return (state); 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate /* 36457c478bd9Sstevel@tonic-gate * Note that the following function needs to be the new interface for 36467c478bd9Sstevel@tonic-gate * mdi_pi_get_state when mpxio gets integrated to ON. 36477c478bd9Sstevel@tonic-gate */ 36487c478bd9Sstevel@tonic-gate int 36497c478bd9Sstevel@tonic-gate mdi_pi_get_state2(mdi_pathinfo_t *pip, mdi_pathinfo_state_t *state, 36507c478bd9Sstevel@tonic-gate uint32_t *ext_state) 36517c478bd9Sstevel@tonic-gate { 36527c478bd9Sstevel@tonic-gate *state = MDI_PATHINFO_STATE_INIT; 36537c478bd9Sstevel@tonic-gate 36547c478bd9Sstevel@tonic-gate if (pip) { 36557c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 36567c478bd9Sstevel@tonic-gate /* 36577c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 36587c478bd9Sstevel@tonic-gate * last good state. 36597c478bd9Sstevel@tonic-gate */ 36607c478bd9Sstevel@tonic-gate *state = MDI_PI_OLD_STATE(pip); 36617c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_OLD_EXT_STATE(pip); 36627c478bd9Sstevel@tonic-gate } else { 36637c478bd9Sstevel@tonic-gate *state = MDI_PI_STATE(pip); 36647c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_EXT_STATE(pip); 36657c478bd9Sstevel@tonic-gate } 36667c478bd9Sstevel@tonic-gate } 36677c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 36687c478bd9Sstevel@tonic-gate } 36697c478bd9Sstevel@tonic-gate 36707c478bd9Sstevel@tonic-gate /* 36717c478bd9Sstevel@tonic-gate * mdi_pi_get_preferred: 36727c478bd9Sstevel@tonic-gate * Get the preferred path flag 36737c478bd9Sstevel@tonic-gate */ 36747c478bd9Sstevel@tonic-gate int 36757c478bd9Sstevel@tonic-gate mdi_pi_get_preferred(mdi_pathinfo_t *pip) 36767c478bd9Sstevel@tonic-gate { 36777c478bd9Sstevel@tonic-gate if (pip) { 36787c478bd9Sstevel@tonic-gate return (MDI_PI(pip)->pi_preferred); 36797c478bd9Sstevel@tonic-gate } 36807c478bd9Sstevel@tonic-gate return (0); 36817c478bd9Sstevel@tonic-gate } 36827c478bd9Sstevel@tonic-gate 36837c478bd9Sstevel@tonic-gate /* 36847c478bd9Sstevel@tonic-gate * mdi_pi_set_preferred: 36857c478bd9Sstevel@tonic-gate * Set the preferred path flag 36867c478bd9Sstevel@tonic-gate */ 36877c478bd9Sstevel@tonic-gate void 36887c478bd9Sstevel@tonic-gate mdi_pi_set_preferred(mdi_pathinfo_t *pip, int preferred) 36897c478bd9Sstevel@tonic-gate { 36907c478bd9Sstevel@tonic-gate if (pip) { 36917c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = preferred; 36927c478bd9Sstevel@tonic-gate } 36937c478bd9Sstevel@tonic-gate } 36947c478bd9Sstevel@tonic-gate 36957c478bd9Sstevel@tonic-gate 36967c478bd9Sstevel@tonic-gate /* 36977c478bd9Sstevel@tonic-gate * mdi_pi_set_state(): 36987c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state 36997c478bd9Sstevel@tonic-gate */ 37007c478bd9Sstevel@tonic-gate void 37017c478bd9Sstevel@tonic-gate mdi_pi_set_state(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state) 37027c478bd9Sstevel@tonic-gate { 37037c478bd9Sstevel@tonic-gate uint32_t ext_state; 37047c478bd9Sstevel@tonic-gate 37057c478bd9Sstevel@tonic-gate if (pip) { 37067c478bd9Sstevel@tonic-gate ext_state = MDI_PI(pip)->pi_state & MDI_PATHINFO_EXT_STATE_MASK; 37077c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = state; 37087c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state |= ext_state; 37097c478bd9Sstevel@tonic-gate } 37107c478bd9Sstevel@tonic-gate } 37117c478bd9Sstevel@tonic-gate 37127c478bd9Sstevel@tonic-gate /* 37137c478bd9Sstevel@tonic-gate * Property functions: 37147c478bd9Sstevel@tonic-gate */ 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate int 37177c478bd9Sstevel@tonic-gate i_map_nvlist_error_to_mdi(int val) 37187c478bd9Sstevel@tonic-gate { 37197c478bd9Sstevel@tonic-gate int rv; 37207c478bd9Sstevel@tonic-gate 37217c478bd9Sstevel@tonic-gate switch (val) { 37227c478bd9Sstevel@tonic-gate case 0: 37237c478bd9Sstevel@tonic-gate rv = DDI_PROP_SUCCESS; 37247c478bd9Sstevel@tonic-gate break; 37257c478bd9Sstevel@tonic-gate case EINVAL: 37267c478bd9Sstevel@tonic-gate case ENOTSUP: 37277c478bd9Sstevel@tonic-gate rv = DDI_PROP_INVAL_ARG; 37287c478bd9Sstevel@tonic-gate break; 37297c478bd9Sstevel@tonic-gate case ENOMEM: 37307c478bd9Sstevel@tonic-gate rv = DDI_PROP_NO_MEMORY; 37317c478bd9Sstevel@tonic-gate break; 37327c478bd9Sstevel@tonic-gate default: 37337c478bd9Sstevel@tonic-gate rv = DDI_PROP_NOT_FOUND; 37347c478bd9Sstevel@tonic-gate break; 37357c478bd9Sstevel@tonic-gate } 37367c478bd9Sstevel@tonic-gate return (rv); 37377c478bd9Sstevel@tonic-gate } 37387c478bd9Sstevel@tonic-gate 37397c478bd9Sstevel@tonic-gate /* 37407c478bd9Sstevel@tonic-gate * mdi_pi_get_next_prop(): 37417c478bd9Sstevel@tonic-gate * Property walk function. The caller should hold mdi_pi_lock() 37427c478bd9Sstevel@tonic-gate * and release by calling mdi_pi_unlock() at the end of walk to 37437c478bd9Sstevel@tonic-gate * get a consistent value. 37447c478bd9Sstevel@tonic-gate */ 37457c478bd9Sstevel@tonic-gate 37467c478bd9Sstevel@tonic-gate nvpair_t * 37477c478bd9Sstevel@tonic-gate mdi_pi_get_next_prop(mdi_pathinfo_t *pip, nvpair_t *prev) 37487c478bd9Sstevel@tonic-gate { 37497c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 37507c478bd9Sstevel@tonic-gate return (NULL); 37517c478bd9Sstevel@tonic-gate } 37527c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 37537c478bd9Sstevel@tonic-gate return (nvlist_next_nvpair(MDI_PI(pip)->pi_prop, prev)); 37547c478bd9Sstevel@tonic-gate } 37557c478bd9Sstevel@tonic-gate 37567c478bd9Sstevel@tonic-gate /* 37577c478bd9Sstevel@tonic-gate * mdi_prop_remove(): 37587c478bd9Sstevel@tonic-gate * Remove the named property from the named list. 37597c478bd9Sstevel@tonic-gate */ 37607c478bd9Sstevel@tonic-gate 37617c478bd9Sstevel@tonic-gate int 37627c478bd9Sstevel@tonic-gate mdi_prop_remove(mdi_pathinfo_t *pip, char *name) 37637c478bd9Sstevel@tonic-gate { 37647c478bd9Sstevel@tonic-gate if (pip == NULL) { 37657c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 37667c478bd9Sstevel@tonic-gate } 37677c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 37687c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 37697c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 37707c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 37717c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 37727c478bd9Sstevel@tonic-gate } 37737c478bd9Sstevel@tonic-gate if (name) { 37747c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, name); 37757c478bd9Sstevel@tonic-gate } else { 37767c478bd9Sstevel@tonic-gate char nvp_name[MAXNAMELEN]; 37777c478bd9Sstevel@tonic-gate nvpair_t *nvp; 37787c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, NULL); 37797c478bd9Sstevel@tonic-gate while (nvp) { 37807c478bd9Sstevel@tonic-gate nvpair_t *next; 37817c478bd9Sstevel@tonic-gate next = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, nvp); 37827c478bd9Sstevel@tonic-gate (void) snprintf(nvp_name, MAXNAMELEN, "%s", 37837c478bd9Sstevel@tonic-gate nvpair_name(nvp)); 37847c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, 37857c478bd9Sstevel@tonic-gate nvp_name); 37867c478bd9Sstevel@tonic-gate nvp = next; 37877c478bd9Sstevel@tonic-gate } 37887c478bd9Sstevel@tonic-gate } 37897c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 37907c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 37917c478bd9Sstevel@tonic-gate } 37927c478bd9Sstevel@tonic-gate 37937c478bd9Sstevel@tonic-gate /* 37947c478bd9Sstevel@tonic-gate * mdi_prop_size(): 37957c478bd9Sstevel@tonic-gate * Get buffer size needed to pack the property data. 37967c478bd9Sstevel@tonic-gate * Caller should hold the mdi_pathinfo_t lock to get a consistent 37977c478bd9Sstevel@tonic-gate * buffer size. 37987c478bd9Sstevel@tonic-gate */ 37997c478bd9Sstevel@tonic-gate 38007c478bd9Sstevel@tonic-gate int 38017c478bd9Sstevel@tonic-gate mdi_prop_size(mdi_pathinfo_t *pip, size_t *buflenp) 38027c478bd9Sstevel@tonic-gate { 38037c478bd9Sstevel@tonic-gate int rv; 38047c478bd9Sstevel@tonic-gate size_t bufsize; 38057c478bd9Sstevel@tonic-gate 38067c478bd9Sstevel@tonic-gate *buflenp = 0; 38077c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 38087c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38097c478bd9Sstevel@tonic-gate } 38107c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38117c478bd9Sstevel@tonic-gate rv = nvlist_size(MDI_PI(pip)->pi_prop, 38127c478bd9Sstevel@tonic-gate &bufsize, NV_ENCODE_NATIVE); 38137c478bd9Sstevel@tonic-gate *buflenp = bufsize; 38147c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 38157c478bd9Sstevel@tonic-gate } 38167c478bd9Sstevel@tonic-gate 38177c478bd9Sstevel@tonic-gate /* 38187c478bd9Sstevel@tonic-gate * mdi_prop_pack(): 38197c478bd9Sstevel@tonic-gate * pack the property list. The caller should hold the 38207c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node to get a consistent data 38217c478bd9Sstevel@tonic-gate */ 38227c478bd9Sstevel@tonic-gate 38237c478bd9Sstevel@tonic-gate int 38247c478bd9Sstevel@tonic-gate mdi_prop_pack(mdi_pathinfo_t *pip, char **bufp, uint_t buflen) 38257c478bd9Sstevel@tonic-gate { 38267c478bd9Sstevel@tonic-gate int rv; 38277c478bd9Sstevel@tonic-gate size_t bufsize; 38287c478bd9Sstevel@tonic-gate 38297c478bd9Sstevel@tonic-gate if ((pip == NULL) || MDI_PI(pip)->pi_prop == NULL) { 38307c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38317c478bd9Sstevel@tonic-gate } 38327c478bd9Sstevel@tonic-gate 38337c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38347c478bd9Sstevel@tonic-gate 38357c478bd9Sstevel@tonic-gate bufsize = buflen; 38367c478bd9Sstevel@tonic-gate rv = nvlist_pack(MDI_PI(pip)->pi_prop, bufp, (size_t *)&bufsize, 38377c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE, KM_SLEEP); 38387c478bd9Sstevel@tonic-gate 38397c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 38407c478bd9Sstevel@tonic-gate } 38417c478bd9Sstevel@tonic-gate 38427c478bd9Sstevel@tonic-gate /* 38437c478bd9Sstevel@tonic-gate * mdi_prop_update_byte(): 38447c478bd9Sstevel@tonic-gate * Create/Update a byte property 38457c478bd9Sstevel@tonic-gate */ 38467c478bd9Sstevel@tonic-gate int 38477c478bd9Sstevel@tonic-gate mdi_prop_update_byte(mdi_pathinfo_t *pip, char *name, uchar_t data) 38487c478bd9Sstevel@tonic-gate { 38497c478bd9Sstevel@tonic-gate int rv; 38507c478bd9Sstevel@tonic-gate 38517c478bd9Sstevel@tonic-gate if (pip == NULL) { 38527c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 38537c478bd9Sstevel@tonic-gate } 38547c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38557c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 38567c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 38577c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38587c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38597c478bd9Sstevel@tonic-gate } 38607c478bd9Sstevel@tonic-gate rv = nvlist_add_byte(MDI_PI(pip)->pi_prop, name, data); 38617c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38627c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 38637c478bd9Sstevel@tonic-gate } 38647c478bd9Sstevel@tonic-gate 38657c478bd9Sstevel@tonic-gate /* 38667c478bd9Sstevel@tonic-gate * mdi_prop_update_byte_array(): 38677c478bd9Sstevel@tonic-gate * Create/Update a byte array property 38687c478bd9Sstevel@tonic-gate */ 38697c478bd9Sstevel@tonic-gate int 38707c478bd9Sstevel@tonic-gate mdi_prop_update_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t *data, 38717c478bd9Sstevel@tonic-gate uint_t nelements) 38727c478bd9Sstevel@tonic-gate { 38737c478bd9Sstevel@tonic-gate int rv; 38747c478bd9Sstevel@tonic-gate 38757c478bd9Sstevel@tonic-gate if (pip == NULL) { 38767c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 38777c478bd9Sstevel@tonic-gate } 38787c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 38797c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 38807c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 38817c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38827c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 38837c478bd9Sstevel@tonic-gate } 38847c478bd9Sstevel@tonic-gate rv = nvlist_add_byte_array(MDI_PI(pip)->pi_prop, name, data, nelements); 38857c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 38867c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 38877c478bd9Sstevel@tonic-gate } 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate /* 38907c478bd9Sstevel@tonic-gate * mdi_prop_update_int(): 38917c478bd9Sstevel@tonic-gate * Create/Update a 32 bit integer property 38927c478bd9Sstevel@tonic-gate */ 38937c478bd9Sstevel@tonic-gate int 38947c478bd9Sstevel@tonic-gate mdi_prop_update_int(mdi_pathinfo_t *pip, char *name, int data) 38957c478bd9Sstevel@tonic-gate { 38967c478bd9Sstevel@tonic-gate int rv; 38977c478bd9Sstevel@tonic-gate 38987c478bd9Sstevel@tonic-gate if (pip == NULL) { 38997c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39007c478bd9Sstevel@tonic-gate } 39017c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39027c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39037c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39047c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39057c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39067c478bd9Sstevel@tonic-gate } 39077c478bd9Sstevel@tonic-gate rv = nvlist_add_int32(MDI_PI(pip)->pi_prop, name, (int32_t)data); 39087c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39097c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39107c478bd9Sstevel@tonic-gate } 39117c478bd9Sstevel@tonic-gate 39127c478bd9Sstevel@tonic-gate /* 39137c478bd9Sstevel@tonic-gate * mdi_prop_update_int64(): 39147c478bd9Sstevel@tonic-gate * Create/Update a 64 bit integer property 39157c478bd9Sstevel@tonic-gate */ 39167c478bd9Sstevel@tonic-gate int 39177c478bd9Sstevel@tonic-gate mdi_prop_update_int64(mdi_pathinfo_t *pip, char *name, int64_t data) 39187c478bd9Sstevel@tonic-gate { 39197c478bd9Sstevel@tonic-gate int rv; 39207c478bd9Sstevel@tonic-gate 39217c478bd9Sstevel@tonic-gate if (pip == NULL) { 39227c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39237c478bd9Sstevel@tonic-gate } 39247c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39257c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39267c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39277c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39287c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39297c478bd9Sstevel@tonic-gate } 39307c478bd9Sstevel@tonic-gate rv = nvlist_add_int64(MDI_PI(pip)->pi_prop, name, data); 39317c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39327c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39337c478bd9Sstevel@tonic-gate } 39347c478bd9Sstevel@tonic-gate 39357c478bd9Sstevel@tonic-gate /* 39367c478bd9Sstevel@tonic-gate * mdi_prop_update_int_array(): 39377c478bd9Sstevel@tonic-gate * Create/Update a int array property 39387c478bd9Sstevel@tonic-gate */ 39397c478bd9Sstevel@tonic-gate int 39407c478bd9Sstevel@tonic-gate mdi_prop_update_int_array(mdi_pathinfo_t *pip, char *name, int *data, 39417c478bd9Sstevel@tonic-gate uint_t nelements) 39427c478bd9Sstevel@tonic-gate { 39437c478bd9Sstevel@tonic-gate int rv; 39447c478bd9Sstevel@tonic-gate 39457c478bd9Sstevel@tonic-gate if (pip == NULL) { 39467c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39477c478bd9Sstevel@tonic-gate } 39487c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39497c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39507c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39517c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39527c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39537c478bd9Sstevel@tonic-gate } 39547c478bd9Sstevel@tonic-gate rv = nvlist_add_int32_array(MDI_PI(pip)->pi_prop, name, (int32_t *)data, 39557c478bd9Sstevel@tonic-gate nelements); 39567c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39577c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39587c478bd9Sstevel@tonic-gate } 39597c478bd9Sstevel@tonic-gate 39607c478bd9Sstevel@tonic-gate /* 39617c478bd9Sstevel@tonic-gate * mdi_prop_update_string(): 39627c478bd9Sstevel@tonic-gate * Create/Update a string property 39637c478bd9Sstevel@tonic-gate */ 39647c478bd9Sstevel@tonic-gate int 39657c478bd9Sstevel@tonic-gate mdi_prop_update_string(mdi_pathinfo_t *pip, char *name, char *data) 39667c478bd9Sstevel@tonic-gate { 39677c478bd9Sstevel@tonic-gate int rv; 39687c478bd9Sstevel@tonic-gate 39697c478bd9Sstevel@tonic-gate if (pip == NULL) { 39707c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39717c478bd9Sstevel@tonic-gate } 39727c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39737c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39747c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39757c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39767c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 39777c478bd9Sstevel@tonic-gate } 39787c478bd9Sstevel@tonic-gate rv = nvlist_add_string(MDI_PI(pip)->pi_prop, name, data); 39797c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 39807c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 39817c478bd9Sstevel@tonic-gate } 39827c478bd9Sstevel@tonic-gate 39837c478bd9Sstevel@tonic-gate /* 39847c478bd9Sstevel@tonic-gate * mdi_prop_update_string_array(): 39857c478bd9Sstevel@tonic-gate * Create/Update a string array property 39867c478bd9Sstevel@tonic-gate */ 39877c478bd9Sstevel@tonic-gate int 39887c478bd9Sstevel@tonic-gate mdi_prop_update_string_array(mdi_pathinfo_t *pip, char *name, char **data, 39897c478bd9Sstevel@tonic-gate uint_t nelements) 39907c478bd9Sstevel@tonic-gate { 39917c478bd9Sstevel@tonic-gate int rv; 39927c478bd9Sstevel@tonic-gate 39937c478bd9Sstevel@tonic-gate if (pip == NULL) { 39947c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 39957c478bd9Sstevel@tonic-gate } 39967c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 39977c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 39987c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 39997c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40007c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40017c478bd9Sstevel@tonic-gate } 40027c478bd9Sstevel@tonic-gate rv = nvlist_add_string_array(MDI_PI(pip)->pi_prop, name, data, 40037c478bd9Sstevel@tonic-gate nelements); 40047c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 40057c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40067c478bd9Sstevel@tonic-gate } 40077c478bd9Sstevel@tonic-gate 40087c478bd9Sstevel@tonic-gate /* 40097c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte(): 40107c478bd9Sstevel@tonic-gate * Look for byte property identified by name. The data returned 40117c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 40127c478bd9Sstevel@tonic-gate * is alive. 40137c478bd9Sstevel@tonic-gate */ 40147c478bd9Sstevel@tonic-gate int 40157c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte(mdi_pathinfo_t *pip, char *name, uchar_t *data) 40167c478bd9Sstevel@tonic-gate { 40177c478bd9Sstevel@tonic-gate int rv; 40187c478bd9Sstevel@tonic-gate 40197c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 40207c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40217c478bd9Sstevel@tonic-gate } 40227c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte(MDI_PI(pip)->pi_prop, name, data); 40237c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40247c478bd9Sstevel@tonic-gate } 40257c478bd9Sstevel@tonic-gate 40267c478bd9Sstevel@tonic-gate 40277c478bd9Sstevel@tonic-gate /* 40287c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte_array(): 40297c478bd9Sstevel@tonic-gate * Look for byte array property identified by name. The data 40307c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 40317c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 40327c478bd9Sstevel@tonic-gate */ 40337c478bd9Sstevel@tonic-gate int 40347c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t **data, 40357c478bd9Sstevel@tonic-gate uint_t *nelements) 40367c478bd9Sstevel@tonic-gate { 40377c478bd9Sstevel@tonic-gate int rv; 40387c478bd9Sstevel@tonic-gate 40397c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 40407c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40417c478bd9Sstevel@tonic-gate } 40427c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte_array(MDI_PI(pip)->pi_prop, name, data, 40437c478bd9Sstevel@tonic-gate nelements); 40447c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40457c478bd9Sstevel@tonic-gate } 40467c478bd9Sstevel@tonic-gate 40477c478bd9Sstevel@tonic-gate /* 40487c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int(): 40497c478bd9Sstevel@tonic-gate * Look for int property identified by name. The data returned 40507c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t 40517c478bd9Sstevel@tonic-gate * node is alive. 40527c478bd9Sstevel@tonic-gate */ 40537c478bd9Sstevel@tonic-gate int 40547c478bd9Sstevel@tonic-gate mdi_prop_lookup_int(mdi_pathinfo_t *pip, char *name, int *data) 40557c478bd9Sstevel@tonic-gate { 40567c478bd9Sstevel@tonic-gate int rv; 40577c478bd9Sstevel@tonic-gate 40587c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 40597c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40607c478bd9Sstevel@tonic-gate } 40617c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32(MDI_PI(pip)->pi_prop, name, (int32_t *)data); 40627c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40637c478bd9Sstevel@tonic-gate } 40647c478bd9Sstevel@tonic-gate 40657c478bd9Sstevel@tonic-gate /* 40667c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int64(): 40677c478bd9Sstevel@tonic-gate * Look for int64 property identified by name. The data returned 40687c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 40697c478bd9Sstevel@tonic-gate * is alive. 40707c478bd9Sstevel@tonic-gate */ 40717c478bd9Sstevel@tonic-gate int 40727c478bd9Sstevel@tonic-gate mdi_prop_lookup_int64(mdi_pathinfo_t *pip, char *name, int64_t *data) 40737c478bd9Sstevel@tonic-gate { 40747c478bd9Sstevel@tonic-gate int rv; 40757c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 40767c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40777c478bd9Sstevel@tonic-gate } 40787c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int64(MDI_PI(pip)->pi_prop, name, data); 40797c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 40807c478bd9Sstevel@tonic-gate } 40817c478bd9Sstevel@tonic-gate 40827c478bd9Sstevel@tonic-gate /* 40837c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int_array(): 40847c478bd9Sstevel@tonic-gate * Look for int array property identified by name. The data 40857c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 40867c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 40877c478bd9Sstevel@tonic-gate */ 40887c478bd9Sstevel@tonic-gate int 40897c478bd9Sstevel@tonic-gate mdi_prop_lookup_int_array(mdi_pathinfo_t *pip, char *name, int **data, 40907c478bd9Sstevel@tonic-gate uint_t *nelements) 40917c478bd9Sstevel@tonic-gate { 40927c478bd9Sstevel@tonic-gate int rv; 40937c478bd9Sstevel@tonic-gate 40947c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 40957c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 40967c478bd9Sstevel@tonic-gate } 40977c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32_array(MDI_PI(pip)->pi_prop, name, 40987c478bd9Sstevel@tonic-gate (int32_t **)data, nelements); 40997c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41007c478bd9Sstevel@tonic-gate } 41017c478bd9Sstevel@tonic-gate 41027c478bd9Sstevel@tonic-gate /* 41037c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string(): 41047c478bd9Sstevel@tonic-gate * Look for string property identified by name. The data 41057c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 41067c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 41077c478bd9Sstevel@tonic-gate */ 41087c478bd9Sstevel@tonic-gate int 41097c478bd9Sstevel@tonic-gate mdi_prop_lookup_string(mdi_pathinfo_t *pip, char *name, char **data) 41107c478bd9Sstevel@tonic-gate { 41117c478bd9Sstevel@tonic-gate int rv; 41127c478bd9Sstevel@tonic-gate 41137c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41147c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41157c478bd9Sstevel@tonic-gate } 41167c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string(MDI_PI(pip)->pi_prop, name, data); 41177c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41187c478bd9Sstevel@tonic-gate } 41197c478bd9Sstevel@tonic-gate 41207c478bd9Sstevel@tonic-gate /* 41217c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string_array(): 41227c478bd9Sstevel@tonic-gate * Look for string array property identified by name. The data 41237c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 41247c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 41257c478bd9Sstevel@tonic-gate */ 41267c478bd9Sstevel@tonic-gate 41277c478bd9Sstevel@tonic-gate int 41287c478bd9Sstevel@tonic-gate mdi_prop_lookup_string_array(mdi_pathinfo_t *pip, char *name, char ***data, 41297c478bd9Sstevel@tonic-gate uint_t *nelements) 41307c478bd9Sstevel@tonic-gate { 41317c478bd9Sstevel@tonic-gate int rv; 41327c478bd9Sstevel@tonic-gate 41337c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 41347c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 41357c478bd9Sstevel@tonic-gate } 41367c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string_array(MDI_PI(pip)->pi_prop, name, data, 41377c478bd9Sstevel@tonic-gate nelements); 41387c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 41397c478bd9Sstevel@tonic-gate } 41407c478bd9Sstevel@tonic-gate 41417c478bd9Sstevel@tonic-gate /* 41427c478bd9Sstevel@tonic-gate * mdi_prop_free(): 41437c478bd9Sstevel@tonic-gate * Symmetrical function to ddi_prop_free(). nvlist_lookup_xx() 41447c478bd9Sstevel@tonic-gate * functions return the pointer to actual property data and not a 41457c478bd9Sstevel@tonic-gate * copy of it. So the data returned is valid as long as 41467c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is valid. 41477c478bd9Sstevel@tonic-gate */ 41487c478bd9Sstevel@tonic-gate 41497c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41507c478bd9Sstevel@tonic-gate int 41517c478bd9Sstevel@tonic-gate mdi_prop_free(void *data) 41527c478bd9Sstevel@tonic-gate { 41537c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 41547c478bd9Sstevel@tonic-gate } 41557c478bd9Sstevel@tonic-gate 41567c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41577c478bd9Sstevel@tonic-gate static void 41587c478bd9Sstevel@tonic-gate i_mdi_report_path_state(mdi_client_t *ct, mdi_pathinfo_t *pip) 41597c478bd9Sstevel@tonic-gate { 41607c478bd9Sstevel@tonic-gate char *phci_path, *ct_path; 41617c478bd9Sstevel@tonic-gate char *ct_status; 41627c478bd9Sstevel@tonic-gate char *status; 41637c478bd9Sstevel@tonic-gate dev_info_t *dip = ct->ct_dip; 41647c478bd9Sstevel@tonic-gate char lb_buf[64]; 41657c478bd9Sstevel@tonic-gate 41667c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_mutex)); 41677c478bd9Sstevel@tonic-gate if ((dip == NULL) || (ddi_get_instance(dip) == -1) || 41687c478bd9Sstevel@tonic-gate (MDI_CLIENT_IS_REPORT_DEV_NEEDED(ct) == 0)) { 41697c478bd9Sstevel@tonic-gate return; 41707c478bd9Sstevel@tonic-gate } 41717c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL) { 41727c478bd9Sstevel@tonic-gate ct_status = "optimal"; 41737c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) { 41747c478bd9Sstevel@tonic-gate ct_status = "degraded"; 41757c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 41767c478bd9Sstevel@tonic-gate ct_status = "failed"; 41777c478bd9Sstevel@tonic-gate } else { 41787c478bd9Sstevel@tonic-gate ct_status = "unknown"; 41797c478bd9Sstevel@tonic-gate } 41807c478bd9Sstevel@tonic-gate 41817c478bd9Sstevel@tonic-gate if (MDI_PI_IS_OFFLINE(pip)) { 41827c478bd9Sstevel@tonic-gate status = "offline"; 41837c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_ONLINE(pip)) { 41847c478bd9Sstevel@tonic-gate status = "online"; 41857c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_STANDBY(pip)) { 41867c478bd9Sstevel@tonic-gate status = "standby"; 41877c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_FAULT(pip)) { 41887c478bd9Sstevel@tonic-gate status = "faulted"; 41897c478bd9Sstevel@tonic-gate } else { 41907c478bd9Sstevel@tonic-gate status = "unknown"; 41917c478bd9Sstevel@tonic-gate } 41927c478bd9Sstevel@tonic-gate 41937c478bd9Sstevel@tonic-gate if (ct->ct_lb == LOAD_BALANCE_LBA) { 41947c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 41957c478bd9Sstevel@tonic-gate "%s, region-size: %d", mdi_load_balance_lba, 41967c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size); 41977c478bd9Sstevel@tonic-gate } else if (ct->ct_lb == LOAD_BALANCE_NONE) { 41987c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 41997c478bd9Sstevel@tonic-gate "%s", mdi_load_balance_none); 42007c478bd9Sstevel@tonic-gate } else { 42017c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), "%s", 42027c478bd9Sstevel@tonic-gate mdi_load_balance_rr); 42037c478bd9Sstevel@tonic-gate } 42047c478bd9Sstevel@tonic-gate 42057c478bd9Sstevel@tonic-gate if (dip) { 42067c478bd9Sstevel@tonic-gate ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 42077c478bd9Sstevel@tonic-gate phci_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 42087c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s (%s%d) multipath status: %s, " 42097c478bd9Sstevel@tonic-gate "path %s (%s%d) to target address: %s is %s" 42107c478bd9Sstevel@tonic-gate " Load balancing: %s\n", 42117c478bd9Sstevel@tonic-gate ddi_pathname(dip, ct_path), ddi_driver_name(dip), 42127c478bd9Sstevel@tonic-gate ddi_get_instance(dip), ct_status, 42137c478bd9Sstevel@tonic-gate ddi_pathname(MDI_PI(pip)->pi_phci->ph_dip, phci_path), 42147c478bd9Sstevel@tonic-gate ddi_driver_name(MDI_PI(pip)->pi_phci->ph_dip), 42157c478bd9Sstevel@tonic-gate ddi_get_instance(MDI_PI(pip)->pi_phci->ph_dip), 42167c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr, status, lb_buf); 42177c478bd9Sstevel@tonic-gate kmem_free(phci_path, MAXPATHLEN); 42187c478bd9Sstevel@tonic-gate kmem_free(ct_path, MAXPATHLEN); 42197c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct); 42207c478bd9Sstevel@tonic-gate } 42217c478bd9Sstevel@tonic-gate } 42227c478bd9Sstevel@tonic-gate 42237c478bd9Sstevel@tonic-gate #ifdef DEBUG 42247c478bd9Sstevel@tonic-gate /* 42257c478bd9Sstevel@tonic-gate * i_mdi_log(): 42267c478bd9Sstevel@tonic-gate * Utility function for error message management 42277c478bd9Sstevel@tonic-gate * 42287c478bd9Sstevel@tonic-gate */ 42297c478bd9Sstevel@tonic-gate 42307c478bd9Sstevel@tonic-gate /*VARARGS3*/ 42317c478bd9Sstevel@tonic-gate static void 42327c478bd9Sstevel@tonic-gate i_mdi_log(int level, dev_info_t *dip, const char *fmt, ...) 42337c478bd9Sstevel@tonic-gate { 42347c478bd9Sstevel@tonic-gate char buf[MAXNAMELEN]; 42357c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 42367c478bd9Sstevel@tonic-gate va_list ap; 42377c478bd9Sstevel@tonic-gate int log_only = 0; 42387c478bd9Sstevel@tonic-gate int boot_only = 0; 42397c478bd9Sstevel@tonic-gate int console_only = 0; 42407c478bd9Sstevel@tonic-gate 42417c478bd9Sstevel@tonic-gate if (dip) { 42427c478bd9Sstevel@tonic-gate if (level == CE_PANIC || level == CE_WARN || level == CE_NOTE) { 42437c478bd9Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "%s%d:\n", 42447c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip)); 42457c478bd9Sstevel@tonic-gate } else { 42467c478bd9Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "%s%d:", 42477c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip)); 42487c478bd9Sstevel@tonic-gate } 42497c478bd9Sstevel@tonic-gate } else { 42507c478bd9Sstevel@tonic-gate name[0] = '\0'; 42517c478bd9Sstevel@tonic-gate } 42527c478bd9Sstevel@tonic-gate 42537c478bd9Sstevel@tonic-gate va_start(ap, fmt); 42547c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, MAXNAMELEN, fmt, ap); 42557c478bd9Sstevel@tonic-gate va_end(ap); 42567c478bd9Sstevel@tonic-gate 42577c478bd9Sstevel@tonic-gate switch (buf[0]) { 42587c478bd9Sstevel@tonic-gate case '!': 42597c478bd9Sstevel@tonic-gate log_only = 1; 42607c478bd9Sstevel@tonic-gate break; 42617c478bd9Sstevel@tonic-gate case '?': 42627c478bd9Sstevel@tonic-gate boot_only = 1; 42637c478bd9Sstevel@tonic-gate break; 42647c478bd9Sstevel@tonic-gate case '^': 42657c478bd9Sstevel@tonic-gate console_only = 1; 42667c478bd9Sstevel@tonic-gate break; 42677c478bd9Sstevel@tonic-gate } 42687c478bd9Sstevel@tonic-gate 42697c478bd9Sstevel@tonic-gate switch (level) { 42707c478bd9Sstevel@tonic-gate case CE_NOTE: 42717c478bd9Sstevel@tonic-gate level = CE_CONT; 42727c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 42737c478bd9Sstevel@tonic-gate case CE_CONT: 42747c478bd9Sstevel@tonic-gate case CE_WARN: 42757c478bd9Sstevel@tonic-gate case CE_PANIC: 42767c478bd9Sstevel@tonic-gate if (boot_only) { 42777c478bd9Sstevel@tonic-gate cmn_err(level, "?%s\t%s", name, &buf[1]); 42787c478bd9Sstevel@tonic-gate } else if (console_only) { 42797c478bd9Sstevel@tonic-gate cmn_err(level, "^%s\t%s", name, &buf[1]); 42807c478bd9Sstevel@tonic-gate } else if (log_only) { 42817c478bd9Sstevel@tonic-gate cmn_err(level, "!%s\t%s", name, &buf[1]); 42827c478bd9Sstevel@tonic-gate } else { 42837c478bd9Sstevel@tonic-gate cmn_err(level, "%s\t%s", name, buf); 42847c478bd9Sstevel@tonic-gate } 42857c478bd9Sstevel@tonic-gate break; 42867c478bd9Sstevel@tonic-gate default: 42877c478bd9Sstevel@tonic-gate cmn_err(level, "%s\t%s", name, buf); 42887c478bd9Sstevel@tonic-gate break; 42897c478bd9Sstevel@tonic-gate } 42907c478bd9Sstevel@tonic-gate } 42917c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 42927c478bd9Sstevel@tonic-gate 42937c478bd9Sstevel@tonic-gate void 42947c478bd9Sstevel@tonic-gate i_mdi_client_online(dev_info_t *ct_dip) 42957c478bd9Sstevel@tonic-gate { 42967c478bd9Sstevel@tonic-gate mdi_client_t *ct; 42977c478bd9Sstevel@tonic-gate 42987c478bd9Sstevel@tonic-gate /* 42997c478bd9Sstevel@tonic-gate * Client online notification. Mark client state as online 43007c478bd9Sstevel@tonic-gate * restore our binding with dev_info node 43017c478bd9Sstevel@tonic-gate */ 43027c478bd9Sstevel@tonic-gate ct = i_devi_get_client(ct_dip); 43037c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 43047c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 43057c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 43067c478bd9Sstevel@tonic-gate /* catch for any memory leaks */ 43077c478bd9Sstevel@tonic-gate ASSERT((ct->ct_dip == NULL) || (ct->ct_dip == ct_dip)); 43087c478bd9Sstevel@tonic-gate ct->ct_dip = ct_dip; 43097c478bd9Sstevel@tonic-gate 43107c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) 43117c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 43127c478bd9Sstevel@tonic-gate 43137c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct_dip, "i_mdi_client_online " 43147c478bd9Sstevel@tonic-gate "i_mdi_pm_hold_client\n")); 43157c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 43167c478bd9Sstevel@tonic-gate 43177c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 43187c478bd9Sstevel@tonic-gate } 43197c478bd9Sstevel@tonic-gate 43207c478bd9Sstevel@tonic-gate void 43217c478bd9Sstevel@tonic-gate i_mdi_phci_online(dev_info_t *ph_dip) 43227c478bd9Sstevel@tonic-gate { 43237c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 43247c478bd9Sstevel@tonic-gate 43257c478bd9Sstevel@tonic-gate /* pHCI online notification. Mark state accordingly */ 43267c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(ph_dip); 43277c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 43287c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 43297c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 43307c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 43317c478bd9Sstevel@tonic-gate } 43327c478bd9Sstevel@tonic-gate 43337c478bd9Sstevel@tonic-gate /* 43347c478bd9Sstevel@tonic-gate * mdi_devi_online(): 43357c478bd9Sstevel@tonic-gate * Online notification from NDI framework on pHCI/client 43367c478bd9Sstevel@tonic-gate * device online. 43377c478bd9Sstevel@tonic-gate * Return Values: 43387c478bd9Sstevel@tonic-gate * NDI_SUCCESS 43397c478bd9Sstevel@tonic-gate * MDI_FAILURE 43407c478bd9Sstevel@tonic-gate */ 43417c478bd9Sstevel@tonic-gate 43427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 43437c478bd9Sstevel@tonic-gate int 43447c478bd9Sstevel@tonic-gate mdi_devi_online(dev_info_t *dip, uint_t flags) 43457c478bd9Sstevel@tonic-gate { 43467c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 43477c478bd9Sstevel@tonic-gate i_mdi_phci_online(dip); 43487c478bd9Sstevel@tonic-gate } 43497c478bd9Sstevel@tonic-gate 43507c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 43517c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 43527c478bd9Sstevel@tonic-gate } 43537c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 43547c478bd9Sstevel@tonic-gate } 43557c478bd9Sstevel@tonic-gate 43567c478bd9Sstevel@tonic-gate /* 43577c478bd9Sstevel@tonic-gate * mdi_devi_offline(): 43587c478bd9Sstevel@tonic-gate * Offline notification from NDI framework on pHCI/Client device 43597c478bd9Sstevel@tonic-gate * offline. 43607c478bd9Sstevel@tonic-gate * 43617c478bd9Sstevel@tonic-gate * Return Values: 43627c478bd9Sstevel@tonic-gate * NDI_SUCCESS 43637c478bd9Sstevel@tonic-gate * NDI_FAILURE 43647c478bd9Sstevel@tonic-gate */ 43657c478bd9Sstevel@tonic-gate 43667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 43677c478bd9Sstevel@tonic-gate int 43687c478bd9Sstevel@tonic-gate mdi_devi_offline(dev_info_t *dip, uint_t flags) 43697c478bd9Sstevel@tonic-gate { 43707c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 43717c478bd9Sstevel@tonic-gate 43727c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 43737c478bd9Sstevel@tonic-gate rv = i_mdi_client_offline(dip, flags); 43747c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) 43757c478bd9Sstevel@tonic-gate return (rv); 43767c478bd9Sstevel@tonic-gate } 43777c478bd9Sstevel@tonic-gate 43787c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 43797c478bd9Sstevel@tonic-gate rv = i_mdi_phci_offline(dip, flags); 43807c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && MDI_CLIENT(dip)) { 43817c478bd9Sstevel@tonic-gate /* set client back online */ 43827c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 43837c478bd9Sstevel@tonic-gate } 43847c478bd9Sstevel@tonic-gate } 43857c478bd9Sstevel@tonic-gate 43867c478bd9Sstevel@tonic-gate return (rv); 43877c478bd9Sstevel@tonic-gate } 43887c478bd9Sstevel@tonic-gate 43897c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 43907c478bd9Sstevel@tonic-gate static int 43917c478bd9Sstevel@tonic-gate i_mdi_phci_offline(dev_info_t *dip, uint_t flags) 43927c478bd9Sstevel@tonic-gate { 43937c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 43947c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 43957c478bd9Sstevel@tonic-gate mdi_client_t *ct; 43967c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 43977c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 43987c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 43997c478bd9Sstevel@tonic-gate dev_info_t *cdip; 44007c478bd9Sstevel@tonic-gate 44017c478bd9Sstevel@tonic-gate /* 44027c478bd9Sstevel@tonic-gate * pHCI component offline notification 44037c478bd9Sstevel@tonic-gate * Make sure that this pHCI instance is free to be offlined. 44047c478bd9Sstevel@tonic-gate * If it is OK to proceed, Offline and remove all the child 44057c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes. This process automatically offlines 44067c478bd9Sstevel@tonic-gate * corresponding client devices, for which this pHCI provides 44077c478bd9Sstevel@tonic-gate * critical services. 44087c478bd9Sstevel@tonic-gate */ 44097c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, "!mdi_phci_offline called %p\n", 44107c478bd9Sstevel@tonic-gate dip)); 44117c478bd9Sstevel@tonic-gate 44127c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 44137c478bd9Sstevel@tonic-gate if (ph == NULL) { 44147c478bd9Sstevel@tonic-gate return (rv); 44157c478bd9Sstevel@tonic-gate } 44167c478bd9Sstevel@tonic-gate 44177c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 44187c478bd9Sstevel@tonic-gate 44197c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_OFFLINE(ph)) { 44207c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, "!pHCI %p already offlined", ph)); 44217c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44227c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 44237c478bd9Sstevel@tonic-gate } 44247c478bd9Sstevel@tonic-gate 44257c478bd9Sstevel@tonic-gate /* 44267c478bd9Sstevel@tonic-gate * Check to see if the pHCI can be offlined 44277c478bd9Sstevel@tonic-gate */ 44287c478bd9Sstevel@tonic-gate if (ph->ph_unstable) { 44297c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 44307c478bd9Sstevel@tonic-gate "!One or more target devices are in transient " 44317c478bd9Sstevel@tonic-gate "state. This device can not be removed at " 44327c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 44337c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44347c478bd9Sstevel@tonic-gate return (NDI_BUSY); 44357c478bd9Sstevel@tonic-gate } 44367c478bd9Sstevel@tonic-gate 44377c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 44387c478bd9Sstevel@tonic-gate while (pip != NULL) { 44397c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 44407c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 44417c478bd9Sstevel@tonic-gate /* 44427c478bd9Sstevel@tonic-gate * The mdi_pathinfo state is OK. Check the client state. 44437c478bd9Sstevel@tonic-gate * If failover in progress fail the pHCI from offlining 44447c478bd9Sstevel@tonic-gate */ 44457c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 44467c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 44477c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 44487c478bd9Sstevel@tonic-gate (ct->ct_unstable)) { 44497c478bd9Sstevel@tonic-gate /* 44507c478bd9Sstevel@tonic-gate * Failover is in progress, Fail the DR 44517c478bd9Sstevel@tonic-gate */ 44527c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 44537c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 44547c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 44557c478bd9Sstevel@tonic-gate "This device can not be removed at " 44567c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 44577c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44587c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 44597c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44607c478bd9Sstevel@tonic-gate return (NDI_BUSY); 44617c478bd9Sstevel@tonic-gate } 44627c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 44637c478bd9Sstevel@tonic-gate 44647c478bd9Sstevel@tonic-gate /* 44657c478bd9Sstevel@tonic-gate * Check to see of we are removing the last path of this 44667c478bd9Sstevel@tonic-gate * client device... 44677c478bd9Sstevel@tonic-gate */ 44687c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 44697c478bd9Sstevel@tonic-gate if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 44707c478bd9Sstevel@tonic-gate (i_mdi_client_compute_state(ct, ph) == 44717c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_FAILED)) { 44727c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 44737c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 44747c478bd9Sstevel@tonic-gate if (ndi_devi_offline(cdip, 0) != NDI_SUCCESS) { 44757c478bd9Sstevel@tonic-gate /* 44767c478bd9Sstevel@tonic-gate * ndi_devi_offline() failed. 44777c478bd9Sstevel@tonic-gate * This pHCI provides the critical path 44787c478bd9Sstevel@tonic-gate * to one or more client devices. 44797c478bd9Sstevel@tonic-gate * Return busy. 44807c478bd9Sstevel@tonic-gate */ 44817c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 44827c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 44837c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 44847c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 44857c478bd9Sstevel@tonic-gate "This device can not be removed at " 44867c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 44877c478bd9Sstevel@tonic-gate failed_pip = pip; 44887c478bd9Sstevel@tonic-gate break; 44897c478bd9Sstevel@tonic-gate } else { 44907c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 44917c478bd9Sstevel@tonic-gate pip = next; 44927c478bd9Sstevel@tonic-gate } 44937c478bd9Sstevel@tonic-gate } else { 44947c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 44957c478bd9Sstevel@tonic-gate pip = next; 44967c478bd9Sstevel@tonic-gate } 44977c478bd9Sstevel@tonic-gate } 44987c478bd9Sstevel@tonic-gate 44997c478bd9Sstevel@tonic-gate if (failed_pip) { 45007c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 45017c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 45027c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45037c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 45047c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 45057c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 45067c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 45077c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 45087c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 45097c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 45107c478bd9Sstevel@tonic-gate if (cdip) { 45117c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45127c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45137c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45147c478bd9Sstevel@tonic-gate (void) ndi_devi_online(cdip, 0); 45157c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45167c478bd9Sstevel@tonic-gate pip = next; 45177c478bd9Sstevel@tonic-gate continue; 45187c478bd9Sstevel@tonic-gate } 45197c478bd9Sstevel@tonic-gate break; 45207c478bd9Sstevel@tonic-gate 45217c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 45227c478bd9Sstevel@tonic-gate if (cdip) { 45237c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45247c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45257c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45267c478bd9Sstevel@tonic-gate (void) ndi_devi_offline(cdip, 0); 45277c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45287c478bd9Sstevel@tonic-gate pip = next; 45297c478bd9Sstevel@tonic-gate continue; 45307c478bd9Sstevel@tonic-gate } 45317c478bd9Sstevel@tonic-gate break; 45327c478bd9Sstevel@tonic-gate } 45337c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45347c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 45357c478bd9Sstevel@tonic-gate pip = next; 45367c478bd9Sstevel@tonic-gate } 45377c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45387c478bd9Sstevel@tonic-gate return (NDI_BUSY); 45397c478bd9Sstevel@tonic-gate } 45407c478bd9Sstevel@tonic-gate 45417c478bd9Sstevel@tonic-gate /* 45427c478bd9Sstevel@tonic-gate * Mark the pHCI as offline 45437c478bd9Sstevel@tonic-gate */ 45447c478bd9Sstevel@tonic-gate MDI_PHCI_SET_OFFLINE(ph); 45457c478bd9Sstevel@tonic-gate 45467c478bd9Sstevel@tonic-gate /* 45477c478bd9Sstevel@tonic-gate * Mark the child mdi_pathinfo nodes as transient 45487c478bd9Sstevel@tonic-gate */ 45497c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 45507c478bd9Sstevel@tonic-gate while (pip != NULL) { 45517c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45527c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 45537c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 45547c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45557c478bd9Sstevel@tonic-gate pip = next; 45567c478bd9Sstevel@tonic-gate } 45577c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45587c478bd9Sstevel@tonic-gate /* 45597c478bd9Sstevel@tonic-gate * Give a chance for any pending commands to execute 45607c478bd9Sstevel@tonic-gate */ 45617c478bd9Sstevel@tonic-gate delay(1); 45627c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 45637c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 45647c478bd9Sstevel@tonic-gate while (pip != NULL) { 45657c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 45667c478bd9Sstevel@tonic-gate (void) i_mdi_pi_offline(pip, flags); 45677c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 45687c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 45697c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_OFFLINE(pip)) { 45707c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 45717c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 45727c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 45737c478bd9Sstevel@tonic-gate "This device can not be removed at " 45747c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 45757c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45767c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 45777c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45787c478bd9Sstevel@tonic-gate return (NDI_BUSY); 45797c478bd9Sstevel@tonic-gate } 45807c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 45817c478bd9Sstevel@tonic-gate pip = next; 45827c478bd9Sstevel@tonic-gate } 45837c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 45847c478bd9Sstevel@tonic-gate 45857c478bd9Sstevel@tonic-gate return (rv); 45867c478bd9Sstevel@tonic-gate } 45877c478bd9Sstevel@tonic-gate 45887c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 45897c478bd9Sstevel@tonic-gate static int 45907c478bd9Sstevel@tonic-gate i_mdi_client_offline(dev_info_t *dip, uint_t flags) 45917c478bd9Sstevel@tonic-gate { 45927c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 45937c478bd9Sstevel@tonic-gate mdi_client_t *ct; 45947c478bd9Sstevel@tonic-gate 45957c478bd9Sstevel@tonic-gate /* 45967c478bd9Sstevel@tonic-gate * Client component to go offline. Make sure that we are 45977c478bd9Sstevel@tonic-gate * not in failing over state and update client state 45987c478bd9Sstevel@tonic-gate * accordingly 45997c478bd9Sstevel@tonic-gate */ 46007c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, "!i_mdi_client_offline called %p\n", 46017c478bd9Sstevel@tonic-gate dip)); 46027c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 46037c478bd9Sstevel@tonic-gate if (ct != NULL) { 46047c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 46057c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 46067c478bd9Sstevel@tonic-gate /* 46077c478bd9Sstevel@tonic-gate * One or more paths are in transient state, 46087c478bd9Sstevel@tonic-gate * Dont allow offline of a client device 46097c478bd9Sstevel@tonic-gate */ 46107c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 46117c478bd9Sstevel@tonic-gate "!One or more paths to this device is " 46127c478bd9Sstevel@tonic-gate "in transient state. This device can not " 46137c478bd9Sstevel@tonic-gate "be removed at this moment. " 46147c478bd9Sstevel@tonic-gate "Please try again later.")); 46157c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 46167c478bd9Sstevel@tonic-gate return (NDI_BUSY); 46177c478bd9Sstevel@tonic-gate } 46187c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 46197c478bd9Sstevel@tonic-gate /* 46207c478bd9Sstevel@tonic-gate * Failover is in progress, Dont allow DR of 46217c478bd9Sstevel@tonic-gate * a client device 46227c478bd9Sstevel@tonic-gate */ 46237c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 46247c478bd9Sstevel@tonic-gate "!Client device (%s%d) is Busy. %s", 46257c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 46267c478bd9Sstevel@tonic-gate "This device can not be removed at " 46277c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 46287c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 46297c478bd9Sstevel@tonic-gate return (NDI_BUSY); 46307c478bd9Sstevel@tonic-gate } 46317c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 46327c478bd9Sstevel@tonic-gate 46337c478bd9Sstevel@tonic-gate /* 46347c478bd9Sstevel@tonic-gate * Unbind our relationship with the dev_info node 46357c478bd9Sstevel@tonic-gate */ 46367c478bd9Sstevel@tonic-gate if (flags & NDI_DEVI_REMOVE) { 46377c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 46387c478bd9Sstevel@tonic-gate } 46397c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 46407c478bd9Sstevel@tonic-gate } 46417c478bd9Sstevel@tonic-gate return (rv); 46427c478bd9Sstevel@tonic-gate } 46437c478bd9Sstevel@tonic-gate 46447c478bd9Sstevel@tonic-gate /* 46457c478bd9Sstevel@tonic-gate * mdi_pre_attach(): 46467c478bd9Sstevel@tonic-gate * Pre attach() notification handler 46477c478bd9Sstevel@tonic-gate */ 46487c478bd9Sstevel@tonic-gate 46497c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 46507c478bd9Sstevel@tonic-gate int 46517c478bd9Sstevel@tonic-gate mdi_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 46527c478bd9Sstevel@tonic-gate { 46537c478bd9Sstevel@tonic-gate /* don't support old DDI_PM_RESUME */ 46547c478bd9Sstevel@tonic-gate if ((DEVI(dip)->devi_mdi_component != MDI_COMPONENT_NONE) && 46557c478bd9Sstevel@tonic-gate (cmd == DDI_PM_RESUME)) 46567c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 46577c478bd9Sstevel@tonic-gate 46587c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 46597c478bd9Sstevel@tonic-gate } 46607c478bd9Sstevel@tonic-gate 46617c478bd9Sstevel@tonic-gate /* 46627c478bd9Sstevel@tonic-gate * mdi_post_attach(): 46637c478bd9Sstevel@tonic-gate * Post attach() notification handler 46647c478bd9Sstevel@tonic-gate */ 46657c478bd9Sstevel@tonic-gate 46667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 46677c478bd9Sstevel@tonic-gate void 46687c478bd9Sstevel@tonic-gate mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error) 46697c478bd9Sstevel@tonic-gate { 46707c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 46717c478bd9Sstevel@tonic-gate mdi_client_t *ct; 46727c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 46737c478bd9Sstevel@tonic-gate 46747c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 46757c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 46767c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 46777c478bd9Sstevel@tonic-gate 46787c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 46797c478bd9Sstevel@tonic-gate switch (cmd) { 46807c478bd9Sstevel@tonic-gate case DDI_ATTACH: 46817c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 46827c478bd9Sstevel@tonic-gate "!pHCI post_attach: called %p\n", ph)); 46837c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 46847c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 46857c478bd9Sstevel@tonic-gate } else { 46867c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 46877c478bd9Sstevel@tonic-gate "!pHCI post_attach: failed error=%d\n", 46887c478bd9Sstevel@tonic-gate error)); 46897c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 46907c478bd9Sstevel@tonic-gate } 46917c478bd9Sstevel@tonic-gate break; 46927c478bd9Sstevel@tonic-gate 46937c478bd9Sstevel@tonic-gate case DDI_RESUME: 46947c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 46957c478bd9Sstevel@tonic-gate "!pHCI post_resume: called %p\n", ph)); 46967c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 46977c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 46987c478bd9Sstevel@tonic-gate } else { 46997c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47007c478bd9Sstevel@tonic-gate "!pHCI post_resume: failed error=%d\n", 47017c478bd9Sstevel@tonic-gate error)); 47027c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 47037c478bd9Sstevel@tonic-gate } 47047c478bd9Sstevel@tonic-gate break; 47057c478bd9Sstevel@tonic-gate } 47067c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 47077c478bd9Sstevel@tonic-gate } 47087c478bd9Sstevel@tonic-gate 47097c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 47107c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 47117c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 47127c478bd9Sstevel@tonic-gate 47137c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 47147c478bd9Sstevel@tonic-gate switch (cmd) { 47157c478bd9Sstevel@tonic-gate case DDI_ATTACH: 47167c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 47177c478bd9Sstevel@tonic-gate "!Client post_attach: called %p\n", ct)); 47187c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) { 47197c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47207c478bd9Sstevel@tonic-gate "!Client post_attach: failed error=%d\n", 47217c478bd9Sstevel@tonic-gate error)); 47227c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 47237c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, dip, 47247c478bd9Sstevel@tonic-gate "mdi_post_attach i_mdi_pm_reset_client\n")); 47257c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 47267c478bd9Sstevel@tonic-gate break; 47277c478bd9Sstevel@tonic-gate } 47287c478bd9Sstevel@tonic-gate 47297c478bd9Sstevel@tonic-gate /* 47307c478bd9Sstevel@tonic-gate * Client device has successfully attached. 47317c478bd9Sstevel@tonic-gate * Create kstats for any pathinfo structures 47327c478bd9Sstevel@tonic-gate * initially associated with this client. 47337c478bd9Sstevel@tonic-gate */ 47347c478bd9Sstevel@tonic-gate for (pip = ct->ct_path_head; pip != NULL; 47357c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *) 47367c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link) { 47377c478bd9Sstevel@tonic-gate (void) i_mdi_pi_kstat_create(pip); 47387c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 47397c478bd9Sstevel@tonic-gate } 47407c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 47417c478bd9Sstevel@tonic-gate break; 47427c478bd9Sstevel@tonic-gate 47437c478bd9Sstevel@tonic-gate case DDI_RESUME: 47447c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 47457c478bd9Sstevel@tonic-gate "!Client post_attach: called %p\n", ct)); 47467c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 47477c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 47487c478bd9Sstevel@tonic-gate } else { 47497c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 47507c478bd9Sstevel@tonic-gate "!Client post_resume: failed error=%d\n", 47517c478bd9Sstevel@tonic-gate error)); 47527c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 47537c478bd9Sstevel@tonic-gate } 47547c478bd9Sstevel@tonic-gate break; 47557c478bd9Sstevel@tonic-gate } 47567c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 47577c478bd9Sstevel@tonic-gate } 47587c478bd9Sstevel@tonic-gate } 47597c478bd9Sstevel@tonic-gate 47607c478bd9Sstevel@tonic-gate /* 47617c478bd9Sstevel@tonic-gate * mdi_pre_detach(): 47627c478bd9Sstevel@tonic-gate * Pre detach notification handler 47637c478bd9Sstevel@tonic-gate */ 47647c478bd9Sstevel@tonic-gate 47657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47667c478bd9Sstevel@tonic-gate int 47677c478bd9Sstevel@tonic-gate mdi_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 47687c478bd9Sstevel@tonic-gate { 47697c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 47707c478bd9Sstevel@tonic-gate 47717c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 47727c478bd9Sstevel@tonic-gate (void) i_mdi_client_pre_detach(dip, cmd); 47737c478bd9Sstevel@tonic-gate } 47747c478bd9Sstevel@tonic-gate 47757c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 47767c478bd9Sstevel@tonic-gate rv = i_mdi_phci_pre_detach(dip, cmd); 47777c478bd9Sstevel@tonic-gate } 47787c478bd9Sstevel@tonic-gate 47797c478bd9Sstevel@tonic-gate return (rv); 47807c478bd9Sstevel@tonic-gate } 47817c478bd9Sstevel@tonic-gate 47827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47837c478bd9Sstevel@tonic-gate static int 47847c478bd9Sstevel@tonic-gate i_mdi_phci_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 47857c478bd9Sstevel@tonic-gate { 47867c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 47877c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 47887c478bd9Sstevel@tonic-gate mdi_client_t *ct; 47897c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 47907c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 47917c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 47927c478bd9Sstevel@tonic-gate 47937c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 47947c478bd9Sstevel@tonic-gate if (ph == NULL) { 47957c478bd9Sstevel@tonic-gate return (rv); 47967c478bd9Sstevel@tonic-gate } 47977c478bd9Sstevel@tonic-gate 47987c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 47997c478bd9Sstevel@tonic-gate switch (cmd) { 48007c478bd9Sstevel@tonic-gate case DDI_DETACH: 48017c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 48027c478bd9Sstevel@tonic-gate "!pHCI pre_detach: called %p\n", ph)); 48037c478bd9Sstevel@tonic-gate if (!MDI_PHCI_IS_OFFLINE(ph)) { 48047c478bd9Sstevel@tonic-gate /* 48057c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes are still attached to 48067c478bd9Sstevel@tonic-gate * this pHCI. Fail the detach for this pHCI. 48077c478bd9Sstevel@tonic-gate */ 48087c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, dip, 48097c478bd9Sstevel@tonic-gate "!pHCI pre_detach: " 48107c478bd9Sstevel@tonic-gate "mdi_pathinfo nodes are still attached " 48117c478bd9Sstevel@tonic-gate "%p\n", ph)); 48127c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 48137c478bd9Sstevel@tonic-gate break; 48147c478bd9Sstevel@tonic-gate } 48157c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 48167c478bd9Sstevel@tonic-gate break; 48177c478bd9Sstevel@tonic-gate 48187c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 48197c478bd9Sstevel@tonic-gate /* 48207c478bd9Sstevel@tonic-gate * pHCI is getting suspended. Since mpxio client 48217c478bd9Sstevel@tonic-gate * devices may not be suspended at this point, to avoid 48227c478bd9Sstevel@tonic-gate * a potential stack overflow, it is important to suspend 48237c478bd9Sstevel@tonic-gate * client devices before pHCI can be suspended. 48247c478bd9Sstevel@tonic-gate */ 48257c478bd9Sstevel@tonic-gate 48267c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 48277c478bd9Sstevel@tonic-gate "!pHCI pre_suspend: called %p\n", ph)); 48287c478bd9Sstevel@tonic-gate /* 48297c478bd9Sstevel@tonic-gate * Suspend all the client devices accessible through this pHCI 48307c478bd9Sstevel@tonic-gate */ 48317c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 48327c478bd9Sstevel@tonic-gate while (pip != NULL && rv == DDI_SUCCESS) { 48337c478bd9Sstevel@tonic-gate dev_info_t *cdip; 48347c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 48357c478bd9Sstevel@tonic-gate next = 48367c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 48377c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 48387c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 48397c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 48407c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 48417c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct) == 0) && 48427c478bd9Sstevel@tonic-gate MDI_CLIENT_IS_SUSPENDED(ct) == 0) { 48437c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 48447c478bd9Sstevel@tonic-gate if ((rv = devi_detach(cdip, DDI_SUSPEND)) != 48457c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 48467c478bd9Sstevel@tonic-gate /* 48477c478bd9Sstevel@tonic-gate * Suspend of one of the client 48487c478bd9Sstevel@tonic-gate * device has failed. 48497c478bd9Sstevel@tonic-gate */ 48507c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 48517c478bd9Sstevel@tonic-gate "!Suspend of device (%s%d) failed.", 48527c478bd9Sstevel@tonic-gate ddi_driver_name(cdip), 48537c478bd9Sstevel@tonic-gate ddi_get_instance(cdip))); 48547c478bd9Sstevel@tonic-gate failed_pip = pip; 48557c478bd9Sstevel@tonic-gate break; 48567c478bd9Sstevel@tonic-gate } 48577c478bd9Sstevel@tonic-gate } else { 48587c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 48597c478bd9Sstevel@tonic-gate } 48607c478bd9Sstevel@tonic-gate pip = next; 48617c478bd9Sstevel@tonic-gate } 48627c478bd9Sstevel@tonic-gate 48637c478bd9Sstevel@tonic-gate if (rv == DDI_SUCCESS) { 48647c478bd9Sstevel@tonic-gate /* 48657c478bd9Sstevel@tonic-gate * Suspend of client devices is complete. Proceed 48667c478bd9Sstevel@tonic-gate * with pHCI suspend. 48677c478bd9Sstevel@tonic-gate */ 48687c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 48697c478bd9Sstevel@tonic-gate } else { 48707c478bd9Sstevel@tonic-gate /* 48717c478bd9Sstevel@tonic-gate * Revert back all the suspended client device states 48727c478bd9Sstevel@tonic-gate * to converse. 48737c478bd9Sstevel@tonic-gate */ 48747c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 48757c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 48767c478bd9Sstevel@tonic-gate dev_info_t *cdip; 48777c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 48787c478bd9Sstevel@tonic-gate next = 48797c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 48807c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 48817c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 48827c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 48837c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 48847c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_SUSPENDED(ct)) { 48857c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 48867c478bd9Sstevel@tonic-gate (void) devi_attach(cdip, DDI_RESUME); 48877c478bd9Sstevel@tonic-gate } else { 48887c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 48897c478bd9Sstevel@tonic-gate } 48907c478bd9Sstevel@tonic-gate pip = next; 48917c478bd9Sstevel@tonic-gate } 48927c478bd9Sstevel@tonic-gate } 48937c478bd9Sstevel@tonic-gate break; 48947c478bd9Sstevel@tonic-gate 48957c478bd9Sstevel@tonic-gate default: 48967c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 48977c478bd9Sstevel@tonic-gate break; 48987c478bd9Sstevel@tonic-gate } 48997c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 49007c478bd9Sstevel@tonic-gate return (rv); 49017c478bd9Sstevel@tonic-gate } 49027c478bd9Sstevel@tonic-gate 49037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49047c478bd9Sstevel@tonic-gate static int 49057c478bd9Sstevel@tonic-gate i_mdi_client_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 49067c478bd9Sstevel@tonic-gate { 49077c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 49087c478bd9Sstevel@tonic-gate mdi_client_t *ct; 49097c478bd9Sstevel@tonic-gate 49107c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 49117c478bd9Sstevel@tonic-gate if (ct == NULL) { 49127c478bd9Sstevel@tonic-gate return (rv); 49137c478bd9Sstevel@tonic-gate } 49147c478bd9Sstevel@tonic-gate 49157c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 49167c478bd9Sstevel@tonic-gate switch (cmd) { 49177c478bd9Sstevel@tonic-gate case DDI_DETACH: 49187c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 49197c478bd9Sstevel@tonic-gate "!Client pre_detach: called %p\n", ct)); 49207c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 49217c478bd9Sstevel@tonic-gate break; 49227c478bd9Sstevel@tonic-gate 49237c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 49247c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 49257c478bd9Sstevel@tonic-gate "!Client pre_suspend: called %p\n", ct)); 49267c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 49277c478bd9Sstevel@tonic-gate break; 49287c478bd9Sstevel@tonic-gate 49297c478bd9Sstevel@tonic-gate default: 49307c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 49317c478bd9Sstevel@tonic-gate break; 49327c478bd9Sstevel@tonic-gate } 49337c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 49347c478bd9Sstevel@tonic-gate return (rv); 49357c478bd9Sstevel@tonic-gate } 49367c478bd9Sstevel@tonic-gate 49377c478bd9Sstevel@tonic-gate /* 49387c478bd9Sstevel@tonic-gate * mdi_post_detach(): 49397c478bd9Sstevel@tonic-gate * Post detach notification handler 49407c478bd9Sstevel@tonic-gate */ 49417c478bd9Sstevel@tonic-gate 49427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49437c478bd9Sstevel@tonic-gate void 49447c478bd9Sstevel@tonic-gate mdi_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 49457c478bd9Sstevel@tonic-gate { 49467c478bd9Sstevel@tonic-gate /* 49477c478bd9Sstevel@tonic-gate * Detach/Suspend of mpxio component failed. Update our state 49487c478bd9Sstevel@tonic-gate * too 49497c478bd9Sstevel@tonic-gate */ 49507c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) 49517c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dip, cmd, error); 49527c478bd9Sstevel@tonic-gate 49537c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) 49547c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dip, cmd, error); 49557c478bd9Sstevel@tonic-gate } 49567c478bd9Sstevel@tonic-gate 49577c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49587c478bd9Sstevel@tonic-gate static void 49597c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 49607c478bd9Sstevel@tonic-gate { 49617c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 49627c478bd9Sstevel@tonic-gate 49637c478bd9Sstevel@tonic-gate /* 49647c478bd9Sstevel@tonic-gate * Detach/Suspend of phci component failed. Update our state 49657c478bd9Sstevel@tonic-gate * too 49667c478bd9Sstevel@tonic-gate */ 49677c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 49687c478bd9Sstevel@tonic-gate if (ph == NULL) { 49697c478bd9Sstevel@tonic-gate return; 49707c478bd9Sstevel@tonic-gate } 49717c478bd9Sstevel@tonic-gate 49727c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 49737c478bd9Sstevel@tonic-gate /* 49747c478bd9Sstevel@tonic-gate * Detach of pHCI failed. Restore back converse 49757c478bd9Sstevel@tonic-gate * state 49767c478bd9Sstevel@tonic-gate */ 49777c478bd9Sstevel@tonic-gate switch (cmd) { 49787c478bd9Sstevel@tonic-gate case DDI_DETACH: 49797c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 49807c478bd9Sstevel@tonic-gate "!pHCI post_detach: called %p\n", ph)); 49817c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 49827c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 49837c478bd9Sstevel@tonic-gate break; 49847c478bd9Sstevel@tonic-gate 49857c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 49867c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 49877c478bd9Sstevel@tonic-gate "!pHCI post_suspend: called %p\n", ph)); 49887c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 49897c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 49907c478bd9Sstevel@tonic-gate break; 49917c478bd9Sstevel@tonic-gate } 49927c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 49937c478bd9Sstevel@tonic-gate } 49947c478bd9Sstevel@tonic-gate 49957c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49967c478bd9Sstevel@tonic-gate static void 49977c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 49987c478bd9Sstevel@tonic-gate { 49997c478bd9Sstevel@tonic-gate mdi_client_t *ct; 50007c478bd9Sstevel@tonic-gate 50017c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 50027c478bd9Sstevel@tonic-gate if (ct == NULL) { 50037c478bd9Sstevel@tonic-gate return; 50047c478bd9Sstevel@tonic-gate } 50057c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 50067c478bd9Sstevel@tonic-gate /* 50077c478bd9Sstevel@tonic-gate * Detach of Client failed. Restore back converse 50087c478bd9Sstevel@tonic-gate * state 50097c478bd9Sstevel@tonic-gate */ 50107c478bd9Sstevel@tonic-gate switch (cmd) { 50117c478bd9Sstevel@tonic-gate case DDI_DETACH: 50127c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 50137c478bd9Sstevel@tonic-gate "!Client post_detach: called %p\n", ct)); 50147c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 50157c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 50167c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 50177c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 50187c478bd9Sstevel@tonic-gate } else { 50197c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 50207c478bd9Sstevel@tonic-gate "i_mdi_pm_reset_client\n")); 50217c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 50227c478bd9Sstevel@tonic-gate } 50237c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50247c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 50257c478bd9Sstevel@tonic-gate break; 50267c478bd9Sstevel@tonic-gate 50277c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 50287c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 50297c478bd9Sstevel@tonic-gate "!Client post_suspend: called %p\n", ct)); 50307c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 50317c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 50327c478bd9Sstevel@tonic-gate break; 50337c478bd9Sstevel@tonic-gate } 50347c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 50357c478bd9Sstevel@tonic-gate } 50367c478bd9Sstevel@tonic-gate 50377c478bd9Sstevel@tonic-gate /* 50387c478bd9Sstevel@tonic-gate * create and install per-path (client - pHCI) statistics 50397c478bd9Sstevel@tonic-gate * I/O stats supported: nread, nwritten, reads, and writes 50407c478bd9Sstevel@tonic-gate * Error stats - hard errors, soft errors, & transport errors 50417c478bd9Sstevel@tonic-gate */ 50427c478bd9Sstevel@tonic-gate static int 50437c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_create(mdi_pathinfo_t *pip) 50447c478bd9Sstevel@tonic-gate { 50457c478bd9Sstevel@tonic-gate 50467c478bd9Sstevel@tonic-gate dev_info_t *client = MDI_PI(pip)->pi_client->ct_dip; 50477c478bd9Sstevel@tonic-gate dev_info_t *ppath = MDI_PI(pip)->pi_phci->ph_dip; 50487c478bd9Sstevel@tonic-gate char ksname[KSTAT_STRLEN]; 50497c478bd9Sstevel@tonic-gate mdi_pathinfo_t *cpip; 50507c478bd9Sstevel@tonic-gate const char *err_postfix = ",err"; 50517c478bd9Sstevel@tonic-gate kstat_t *kiosp, *kerrsp; 50527c478bd9Sstevel@tonic-gate struct pi_errs *nsp; 50537c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 50547c478bd9Sstevel@tonic-gate 50557c478bd9Sstevel@tonic-gate ASSERT(client != NULL && ppath != NULL); 50567c478bd9Sstevel@tonic-gate 50577c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&(MDI_PI(pip)->pi_client->ct_mutex))); 50587c478bd9Sstevel@tonic-gate 50597c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_kstats != NULL) 50607c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 50617c478bd9Sstevel@tonic-gate 50627c478bd9Sstevel@tonic-gate for (cpip = MDI_PI(pip)->pi_client->ct_path_head; cpip != NULL; 50637c478bd9Sstevel@tonic-gate cpip = (mdi_pathinfo_t *)(MDI_PI(cpip)->pi_client_link)) { 50647c478bd9Sstevel@tonic-gate if (cpip == pip) 50657c478bd9Sstevel@tonic-gate continue; 50667c478bd9Sstevel@tonic-gate /* 50677c478bd9Sstevel@tonic-gate * We have found a different path with same parent 50687c478bd9Sstevel@tonic-gate * kstats for a given client-pHCI are common 50697c478bd9Sstevel@tonic-gate */ 50707c478bd9Sstevel@tonic-gate if ((MDI_PI(cpip)->pi_phci->ph_dip == ppath) && 50717c478bd9Sstevel@tonic-gate (MDI_PI(cpip)->pi_kstats != NULL)) { 50727c478bd9Sstevel@tonic-gate MDI_PI(cpip)->pi_kstats->pi_kstat_ref++; 50737c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = MDI_PI(cpip)->pi_kstats; 50747c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 50757c478bd9Sstevel@tonic-gate } 50767c478bd9Sstevel@tonic-gate } 50777c478bd9Sstevel@tonic-gate 50787c478bd9Sstevel@tonic-gate /* 50797c478bd9Sstevel@tonic-gate * stats are named as follows: TGTx.HBAy, e.g. "ssd0.fp0" 50807c478bd9Sstevel@tonic-gate * clamp length of name against max length of error kstat name 50817c478bd9Sstevel@tonic-gate */ 50827c478bd9Sstevel@tonic-gate if (snprintf(ksname, KSTAT_STRLEN, "%s%d.%s%d", 50837c478bd9Sstevel@tonic-gate ddi_driver_name(client), ddi_get_instance(client), 50847c478bd9Sstevel@tonic-gate ddi_driver_name(ppath), ddi_get_instance(ppath)) > 50857c478bd9Sstevel@tonic-gate (KSTAT_STRLEN - strlen(err_postfix))) { 50867c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 50877c478bd9Sstevel@tonic-gate } 50887c478bd9Sstevel@tonic-gate if ((kiosp = kstat_create("mdi", 0, ksname, "iopath", 50897c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, 0)) == NULL) { 50907c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 50917c478bd9Sstevel@tonic-gate } 50927c478bd9Sstevel@tonic-gate 50937c478bd9Sstevel@tonic-gate (void) strcat(ksname, err_postfix); 50947c478bd9Sstevel@tonic-gate kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors", 50957c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, 50967c478bd9Sstevel@tonic-gate sizeof (struct pi_errs) / sizeof (kstat_named_t), 0); 50977c478bd9Sstevel@tonic-gate 50987c478bd9Sstevel@tonic-gate if (kerrsp == NULL) { 50997c478bd9Sstevel@tonic-gate kstat_delete(kiosp); 51007c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 51017c478bd9Sstevel@tonic-gate } 51027c478bd9Sstevel@tonic-gate 51037c478bd9Sstevel@tonic-gate nsp = (struct pi_errs *)kerrsp->ks_data; 51047c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32); 51057c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32); 51067c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_transerrs, "Transport Errors", 51077c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51087c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy", 51097c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51107c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors", 51117c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51127c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources", 51137c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51147c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors", 51157c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51167c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State", 51177c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51187c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedfrom, "Failed From", 51197c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 51207c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32); 51217c478bd9Sstevel@tonic-gate 51227c478bd9Sstevel@tonic-gate mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP); 51237c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_ref = 1; 51247c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_iostats = kiosp; 51257c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_errstats = kerrsp; 51267c478bd9Sstevel@tonic-gate kstat_install(kiosp); 51277c478bd9Sstevel@tonic-gate kstat_install(kerrsp); 51287c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = mdi_statp; 51297c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 51307c478bd9Sstevel@tonic-gate } 51317c478bd9Sstevel@tonic-gate 51327c478bd9Sstevel@tonic-gate /* 51337c478bd9Sstevel@tonic-gate * destroy per-path properties 51347c478bd9Sstevel@tonic-gate */ 51357c478bd9Sstevel@tonic-gate static void 51367c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip) 51377c478bd9Sstevel@tonic-gate { 51387c478bd9Sstevel@tonic-gate 51397c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 51407c478bd9Sstevel@tonic-gate 51417c478bd9Sstevel@tonic-gate if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL) 51427c478bd9Sstevel@tonic-gate return; 51437c478bd9Sstevel@tonic-gate 51447c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 51457c478bd9Sstevel@tonic-gate 51467c478bd9Sstevel@tonic-gate /* 51477c478bd9Sstevel@tonic-gate * the kstat may be shared between multiple pathinfo nodes 51487c478bd9Sstevel@tonic-gate * decrement this pathinfo's usage, removing the kstats 51497c478bd9Sstevel@tonic-gate * themselves when the last pathinfo reference is removed. 51507c478bd9Sstevel@tonic-gate */ 51517c478bd9Sstevel@tonic-gate ASSERT(mdi_statp->pi_kstat_ref > 0); 51527c478bd9Sstevel@tonic-gate if (--mdi_statp->pi_kstat_ref != 0) 51537c478bd9Sstevel@tonic-gate return; 51547c478bd9Sstevel@tonic-gate 51557c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_iostats); 51567c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_errstats); 51577c478bd9Sstevel@tonic-gate kmem_free(mdi_statp, sizeof (*mdi_statp)); 51587c478bd9Sstevel@tonic-gate } 51597c478bd9Sstevel@tonic-gate 51607c478bd9Sstevel@tonic-gate /* 51617c478bd9Sstevel@tonic-gate * update I/O paths KSTATS 51627c478bd9Sstevel@tonic-gate */ 51637c478bd9Sstevel@tonic-gate void 51647c478bd9Sstevel@tonic-gate mdi_pi_kstat_iosupdate(mdi_pathinfo_t *pip, struct buf *bp) 51657c478bd9Sstevel@tonic-gate { 51667c478bd9Sstevel@tonic-gate kstat_t *iostatp; 51677c478bd9Sstevel@tonic-gate size_t xfer_cnt; 51687c478bd9Sstevel@tonic-gate 51697c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 51707c478bd9Sstevel@tonic-gate 51717c478bd9Sstevel@tonic-gate /* 51727c478bd9Sstevel@tonic-gate * I/O can be driven across a path prior to having path 51737c478bd9Sstevel@tonic-gate * statistics available, i.e. probe(9e). 51747c478bd9Sstevel@tonic-gate */ 51757c478bd9Sstevel@tonic-gate if (bp != NULL && MDI_PI(pip)->pi_kstats != NULL) { 51767c478bd9Sstevel@tonic-gate iostatp = MDI_PI(pip)->pi_kstats->pi_kstat_iostats; 51777c478bd9Sstevel@tonic-gate xfer_cnt = bp->b_bcount - bp->b_resid; 51787c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 51797c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->reads++; 51807c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nread += xfer_cnt; 51817c478bd9Sstevel@tonic-gate } else { 51827c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->writes++; 51837c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nwritten += xfer_cnt; 51847c478bd9Sstevel@tonic-gate } 51857c478bd9Sstevel@tonic-gate } 51867c478bd9Sstevel@tonic-gate } 51877c478bd9Sstevel@tonic-gate 51887c478bd9Sstevel@tonic-gate /* 51897c478bd9Sstevel@tonic-gate * disable the path to a particular pHCI (pHCI specified in the phci_path 51907c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 51917c478bd9Sstevel@tonic-gate * Disabling a path means that MPxIO will not select the disabled path for 51927c478bd9Sstevel@tonic-gate * routing any new I/O requests. 51937c478bd9Sstevel@tonic-gate */ 51947c478bd9Sstevel@tonic-gate int 51957c478bd9Sstevel@tonic-gate mdi_pi_disable(dev_info_t *cdip, dev_info_t *pdip, int flags) 51967c478bd9Sstevel@tonic-gate { 51977c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_DISABLE_OP)); 51987c478bd9Sstevel@tonic-gate } 51997c478bd9Sstevel@tonic-gate 52007c478bd9Sstevel@tonic-gate /* 52017c478bd9Sstevel@tonic-gate * Enable the path to a particular pHCI (pHCI specified in the phci_path 52027c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 52037c478bd9Sstevel@tonic-gate * Enabling a path means that MPxIO may select the enabled path for routing 52047c478bd9Sstevel@tonic-gate * future I/O requests, subject to other path state constraints. 52057c478bd9Sstevel@tonic-gate */ 52067c478bd9Sstevel@tonic-gate 52077c478bd9Sstevel@tonic-gate int 52087c478bd9Sstevel@tonic-gate mdi_pi_enable(dev_info_t *cdip, dev_info_t *pdip, int flags) 52097c478bd9Sstevel@tonic-gate { 52107c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_ENABLE_OP)); 52117c478bd9Sstevel@tonic-gate } 52127c478bd9Sstevel@tonic-gate 52137c478bd9Sstevel@tonic-gate 52147c478bd9Sstevel@tonic-gate /* 52157c478bd9Sstevel@tonic-gate * Common routine for doing enable/disable. 52167c478bd9Sstevel@tonic-gate */ 52177c478bd9Sstevel@tonic-gate int 52187c478bd9Sstevel@tonic-gate i_mdi_pi_enable_disable(dev_info_t *cdip, dev_info_t *pdip, int flags, int op) 52197c478bd9Sstevel@tonic-gate { 52207c478bd9Sstevel@tonic-gate 52217c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 52227c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 52237c478bd9Sstevel@tonic-gate mdi_client_t *ct; 52247c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next, *pip; 52257c478bd9Sstevel@tonic-gate int found_it; 52267c478bd9Sstevel@tonic-gate int (*f)() = NULL; 52277c478bd9Sstevel@tonic-gate int rv; 52287c478bd9Sstevel@tonic-gate int sync_flag = 0; 52297c478bd9Sstevel@tonic-gate 52307c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 52317c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 52327c478bd9Sstevel@tonic-gate " Operation = %d pdip = %p cdip = %p\n", op, pdip, cdip)); 52337c478bd9Sstevel@tonic-gate if (ph == NULL) { 52347c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 52357c478bd9Sstevel@tonic-gate " failed. ph = NULL operation = %d\n", op)); 52367c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 52377c478bd9Sstevel@tonic-gate } 52387c478bd9Sstevel@tonic-gate 52397c478bd9Sstevel@tonic-gate if ((op != MDI_ENABLE_OP) && (op != MDI_DISABLE_OP)) { 52407c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 52417c478bd9Sstevel@tonic-gate " Invalid operation = %d\n", op)); 52427c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 52437c478bd9Sstevel@tonic-gate } 52447c478bd9Sstevel@tonic-gate 52457c478bd9Sstevel@tonic-gate sync_flag = (flags << 8) & 0xf00; 52467c478bd9Sstevel@tonic-gate 52477c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 52487c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 52497c478bd9Sstevel@tonic-gate 52507c478bd9Sstevel@tonic-gate if (cdip == NULL) { 52517c478bd9Sstevel@tonic-gate /* 52527c478bd9Sstevel@tonic-gate * Need to mark the Phci as enabled/disabled. 52537c478bd9Sstevel@tonic-gate */ 52547c478bd9Sstevel@tonic-gate MDI_DEBUG(3, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 52557c478bd9Sstevel@tonic-gate "Operation %d for the phci\n", op)); 52567c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 52577c478bd9Sstevel@tonic-gate switch (flags) { 52587c478bd9Sstevel@tonic-gate case USER_DISABLE: 52597c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 52607c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_DISABLE(ph); 52617c478bd9Sstevel@tonic-gate else 52627c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_ENABLE(ph); 52637c478bd9Sstevel@tonic-gate break; 52647c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 52657c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 52667c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE(ph); 52677c478bd9Sstevel@tonic-gate else 52687c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE(ph); 52697c478bd9Sstevel@tonic-gate break; 52707c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 52717c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 52727c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE_TRANSIENT(ph); 52737c478bd9Sstevel@tonic-gate else 52747c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE_TRANSIENT(ph); 52757c478bd9Sstevel@tonic-gate break; 52767c478bd9Sstevel@tonic-gate default: 52777c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 52787c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 52797c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 52807c478bd9Sstevel@tonic-gate " Invalid flag argument= %d\n", flags)); 52817c478bd9Sstevel@tonic-gate } 52827c478bd9Sstevel@tonic-gate 52837c478bd9Sstevel@tonic-gate /* 52847c478bd9Sstevel@tonic-gate * Phci has been disabled. Now try to enable/disable 52857c478bd9Sstevel@tonic-gate * path info's to each client. 52867c478bd9Sstevel@tonic-gate */ 52877c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 52887c478bd9Sstevel@tonic-gate while (pip != NULL) { 52897c478bd9Sstevel@tonic-gate /* 52907c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 52917c478bd9Sstevel@tonic-gate * know that path is about to be enabled/disabled. 52927c478bd9Sstevel@tonic-gate */ 52937c478bd9Sstevel@tonic-gate if (f != NULL) { 52947c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 52957c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 52967c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 52977c478bd9Sstevel@tonic-gate op | MDI_BEFORE_STATE_CHANGE); 52987c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 52997c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 53007c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 53017c478bd9Sstevel@tonic-gate } 53027c478bd9Sstevel@tonic-gate } 53037c478bd9Sstevel@tonic-gate 53047c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 53057c478bd9Sstevel@tonic-gate next = 53067c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 53077c478bd9Sstevel@tonic-gate switch (flags) { 53087c478bd9Sstevel@tonic-gate case USER_DISABLE: 53097c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 53107c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 53117c478bd9Sstevel@tonic-gate else 53127c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_ENABLE(pip); 53137c478bd9Sstevel@tonic-gate break; 53147c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 53157c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 53167c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 53177c478bd9Sstevel@tonic-gate else 53187c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE(pip); 53197c478bd9Sstevel@tonic-gate break; 53207c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 53217c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) 53227c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 53237c478bd9Sstevel@tonic-gate else 53247c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE_TRANS(pip); 53257c478bd9Sstevel@tonic-gate break; 53267c478bd9Sstevel@tonic-gate } 53277c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 53287c478bd9Sstevel@tonic-gate /* 53297c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 53307c478bd9Sstevel@tonic-gate * know that path is now enabled/disabled. 53317c478bd9Sstevel@tonic-gate */ 53327c478bd9Sstevel@tonic-gate if (f != NULL) { 53337c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 53347c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 53357c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 53367c478bd9Sstevel@tonic-gate op | MDI_AFTER_STATE_CHANGE); 53377c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 53387c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 53397c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 53407c478bd9Sstevel@tonic-gate } 53417c478bd9Sstevel@tonic-gate } 53427c478bd9Sstevel@tonic-gate pip = next; 53437c478bd9Sstevel@tonic-gate } 53447c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 53457c478bd9Sstevel@tonic-gate } else { 53467c478bd9Sstevel@tonic-gate 53477c478bd9Sstevel@tonic-gate /* 53487c478bd9Sstevel@tonic-gate * Disable a specific client. 53497c478bd9Sstevel@tonic-gate */ 53507c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 53517c478bd9Sstevel@tonic-gate if (ct == NULL) { 53527c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 53537c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 53547c478bd9Sstevel@tonic-gate " failed. ct = NULL operation = %d\n", op)); 53557c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 53567c478bd9Sstevel@tonic-gate } 53577c478bd9Sstevel@tonic-gate 53587c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 53597c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 53607c478bd9Sstevel@tonic-gate found_it = 0; 53617c478bd9Sstevel@tonic-gate while (pip != NULL) { 53627c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 53637c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 53647c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 53657c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 53667c478bd9Sstevel@tonic-gate found_it = 1; 53677c478bd9Sstevel@tonic-gate break; 53687c478bd9Sstevel@tonic-gate } 53697c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 53707c478bd9Sstevel@tonic-gate pip = next; 53717c478bd9Sstevel@tonic-gate } 53727c478bd9Sstevel@tonic-gate 53737c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 53747c478bd9Sstevel@tonic-gate if (found_it == 0) { 53757c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 53767c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 53777c478bd9Sstevel@tonic-gate " failed. Could not find corresponding pip\n")); 53787c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 53797c478bd9Sstevel@tonic-gate } 53807c478bd9Sstevel@tonic-gate /* 53817c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 53827c478bd9Sstevel@tonic-gate * know that path is about to get enabled/disabled. 53837c478bd9Sstevel@tonic-gate */ 53847c478bd9Sstevel@tonic-gate if (f != NULL) { 53857c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 53867c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 53877c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 53887c478bd9Sstevel@tonic-gate op | MDI_BEFORE_STATE_CHANGE); 53897c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 53907c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 53917c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 53927c478bd9Sstevel@tonic-gate } 53937c478bd9Sstevel@tonic-gate } 53947c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 53957c478bd9Sstevel@tonic-gate switch (flags) { 53967c478bd9Sstevel@tonic-gate case USER_DISABLE: 53977c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 53987c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 53997c478bd9Sstevel@tonic-gate else 54007c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_ENABLE(pip); 54017c478bd9Sstevel@tonic-gate break; 54027c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 54037c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 54047c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 54057c478bd9Sstevel@tonic-gate else 54067c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE(pip); 54077c478bd9Sstevel@tonic-gate break; 54087c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 54097c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) 54107c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 54117c478bd9Sstevel@tonic-gate else 54127c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE_TRANS(pip); 54137c478bd9Sstevel@tonic-gate break; 54147c478bd9Sstevel@tonic-gate } 54157c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 54167c478bd9Sstevel@tonic-gate /* 54177c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 54187c478bd9Sstevel@tonic-gate * know that path is now enabled/disabled. 54197c478bd9Sstevel@tonic-gate */ 54207c478bd9Sstevel@tonic-gate if (f != NULL) { 54217c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 54227c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 54237c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 54247c478bd9Sstevel@tonic-gate op | MDI_AFTER_STATE_CHANGE); 54257c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 54267c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 54277c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 54287c478bd9Sstevel@tonic-gate } 54297c478bd9Sstevel@tonic-gate } 54307c478bd9Sstevel@tonic-gate } 54317c478bd9Sstevel@tonic-gate 54327c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 54337c478bd9Sstevel@tonic-gate " Returning success pdip = %p cdip = %p\n", op, pdip, cdip)); 54347c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 54357c478bd9Sstevel@tonic-gate } 54367c478bd9Sstevel@tonic-gate 54377c478bd9Sstevel@tonic-gate /*ARGSUSED3*/ 54387c478bd9Sstevel@tonic-gate int 54397c478bd9Sstevel@tonic-gate mdi_devi_config_one(dev_info_t *pdip, char *devnm, dev_info_t **cdipp, 54407c478bd9Sstevel@tonic-gate int flags, clock_t timeout) 54417c478bd9Sstevel@tonic-gate { 54427c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 54437c478bd9Sstevel@tonic-gate dev_info_t *dip; 54447c478bd9Sstevel@tonic-gate clock_t interval = drv_usectohz(100000); /* 0.1 sec */ 54457c478bd9Sstevel@tonic-gate char *paddr; 54467c478bd9Sstevel@tonic-gate 54477c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "configure device %s", devnm)); 54487c478bd9Sstevel@tonic-gate 54497c478bd9Sstevel@tonic-gate if (!MDI_PHCI(pdip)) 54507c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54517c478bd9Sstevel@tonic-gate 54527c478bd9Sstevel@tonic-gate paddr = strchr(devnm, '@'); 54537c478bd9Sstevel@tonic-gate if (paddr == NULL) 54547c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54557c478bd9Sstevel@tonic-gate 54567c478bd9Sstevel@tonic-gate paddr++; /* skip '@' */ 54577c478bd9Sstevel@tonic-gate pip = mdi_pi_find(pdip, NULL, paddr); 54587c478bd9Sstevel@tonic-gate while (pip == NULL && timeout > 0) { 54597c478bd9Sstevel@tonic-gate if (interval > timeout) 54607c478bd9Sstevel@tonic-gate interval = timeout; 54617c478bd9Sstevel@tonic-gate if (flags & NDI_DEVI_DEBUG) { 54627c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: %s timeout %ld %ld\n", 54637c478bd9Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip), 54647c478bd9Sstevel@tonic-gate paddr, interval, timeout); 54657c478bd9Sstevel@tonic-gate } 54667c478bd9Sstevel@tonic-gate delay(interval); 54677c478bd9Sstevel@tonic-gate timeout -= interval; 54687c478bd9Sstevel@tonic-gate interval += interval; 54697c478bd9Sstevel@tonic-gate pip = mdi_pi_find(pdip, NULL, paddr); 54707c478bd9Sstevel@tonic-gate } 54717c478bd9Sstevel@tonic-gate 54727c478bd9Sstevel@tonic-gate if (pip == NULL) 54737c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54747c478bd9Sstevel@tonic-gate dip = mdi_pi_get_client(pip); 54757c478bd9Sstevel@tonic-gate if (ndi_devi_online(dip, flags) != NDI_SUCCESS) 54767c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 54777c478bd9Sstevel@tonic-gate *cdipp = dip; 54787c478bd9Sstevel@tonic-gate 54797c478bd9Sstevel@tonic-gate /* TODO: holding should happen inside search functions */ 54807c478bd9Sstevel@tonic-gate ndi_hold_devi(dip); 54817c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 54827c478bd9Sstevel@tonic-gate } 54837c478bd9Sstevel@tonic-gate 54847c478bd9Sstevel@tonic-gate /* 54857c478bd9Sstevel@tonic-gate * Ensure phci powered up 54867c478bd9Sstevel@tonic-gate */ 54877c478bd9Sstevel@tonic-gate static void 54887c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(mdi_pathinfo_t *pip) 54897c478bd9Sstevel@tonic-gate { 54907c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 54917c478bd9Sstevel@tonic-gate 54927c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 54937c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 54947c478bd9Sstevel@tonic-gate 54957c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 54967c478bd9Sstevel@tonic-gate return; 54977c478bd9Sstevel@tonic-gate } 54987c478bd9Sstevel@tonic-gate 54997c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 55007c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_hold_pip for %s%d\n", 55017c478bd9Sstevel@tonic-gate ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 55027c478bd9Sstevel@tonic-gate if (ph_dip == NULL) { 55037c478bd9Sstevel@tonic-gate return; 55047c478bd9Sstevel@tonic-gate } 55057c478bd9Sstevel@tonic-gate 55067c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 55077c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 55087c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55097c478bd9Sstevel@tonic-gate pm_hold_power(ph_dip); 55107c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 55117c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55127c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 55137c478bd9Sstevel@tonic-gate 55147c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 1; 55157c478bd9Sstevel@tonic-gate } 55167c478bd9Sstevel@tonic-gate 55177c478bd9Sstevel@tonic-gate /* 55187c478bd9Sstevel@tonic-gate * Allow phci powered down 55197c478bd9Sstevel@tonic-gate */ 55207c478bd9Sstevel@tonic-gate static void 55217c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(mdi_pathinfo_t *pip) 55227c478bd9Sstevel@tonic-gate { 55237c478bd9Sstevel@tonic-gate dev_info_t *ph_dip = NULL; 55247c478bd9Sstevel@tonic-gate 55257c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 55267c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 55277c478bd9Sstevel@tonic-gate 55287c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 55297c478bd9Sstevel@tonic-gate return; 55307c478bd9Sstevel@tonic-gate } 55317c478bd9Sstevel@tonic-gate 55327c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 55337c478bd9Sstevel@tonic-gate ASSERT(ph_dip != NULL); 55347c478bd9Sstevel@tonic-gate 55357c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 55367c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_rele_pip for %s%d\n", 55377c478bd9Sstevel@tonic-gate ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 55387c478bd9Sstevel@tonic-gate 55397c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 55407c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55417c478bd9Sstevel@tonic-gate pm_rele_power(ph_dip); 55427c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 55437c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 55447c478bd9Sstevel@tonic-gate 55457c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 55467c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 0; 55477c478bd9Sstevel@tonic-gate } 55487c478bd9Sstevel@tonic-gate 55497c478bd9Sstevel@tonic-gate static void 55507c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(mdi_client_t *ct, int incr) 55517c478bd9Sstevel@tonic-gate { 55527c478bd9Sstevel@tonic-gate ASSERT(ct); 55537c478bd9Sstevel@tonic-gate 55547c478bd9Sstevel@tonic-gate ct->ct_power_cnt += incr; 55557c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_hold_client " 55567c478bd9Sstevel@tonic-gate "ct_power_cnt = %d incr = %d\n", ct->ct_power_cnt, incr)); 55577c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 55587c478bd9Sstevel@tonic-gate } 55597c478bd9Sstevel@tonic-gate 55607c478bd9Sstevel@tonic-gate static void 55617c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(mdi_client_t *ct) 55627c478bd9Sstevel@tonic-gate { 55637c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 55647c478bd9Sstevel@tonic-gate 55657c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ct->ct_mutex)); 55667c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 55677c478bd9Sstevel@tonic-gate while (pip != NULL) { 55687c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 55697c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 55707c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 55717c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 55727c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 55737c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 55747c478bd9Sstevel@tonic-gate } 55757c478bd9Sstevel@tonic-gate } 55767c478bd9Sstevel@tonic-gate 55777c478bd9Sstevel@tonic-gate static void 55787c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(mdi_client_t *ct, int decr) 55797c478bd9Sstevel@tonic-gate { 55807c478bd9Sstevel@tonic-gate ASSERT(ct); 55817c478bd9Sstevel@tonic-gate 55827c478bd9Sstevel@tonic-gate if (i_ddi_node_state(ct->ct_dip) >= DS_READY) { 55837c478bd9Sstevel@tonic-gate ct->ct_power_cnt -= decr; 55847c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_rele_client " 55857c478bd9Sstevel@tonic-gate "ct_power_cnt = %d decr = %d\n", ct->ct_power_cnt, decr)); 55867c478bd9Sstevel@tonic-gate } 55877c478bd9Sstevel@tonic-gate 55887c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 55897c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 55907c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 55917c478bd9Sstevel@tonic-gate return; 55927c478bd9Sstevel@tonic-gate } 55937c478bd9Sstevel@tonic-gate } 55947c478bd9Sstevel@tonic-gate 55957c478bd9Sstevel@tonic-gate static void 55967c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(mdi_client_t *ct) 55977c478bd9Sstevel@tonic-gate { 55987c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_reset_client " 55997c478bd9Sstevel@tonic-gate "ct_power_cnt = %d\n", ct->ct_power_cnt)); 56007c478bd9Sstevel@tonic-gate ct->ct_power_cnt = 0; 56017c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 56027c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 1; 56037c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 0; 56047c478bd9Sstevel@tonic-gate } 56057c478bd9Sstevel@tonic-gate 56067c478bd9Sstevel@tonic-gate static void 56077c478bd9Sstevel@tonic-gate i_mdi_pm_hold_all_phci(mdi_client_t *ct) 56087c478bd9Sstevel@tonic-gate { 56097c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 56107c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ct->ct_mutex)); 56117c478bd9Sstevel@tonic-gate 56127c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 56137c478bd9Sstevel@tonic-gate while (pip != NULL) { 56147c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 56157c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 56167c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 56177c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 56187c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 56197c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 56207c478bd9Sstevel@tonic-gate } 56217c478bd9Sstevel@tonic-gate } 56227c478bd9Sstevel@tonic-gate 56237c478bd9Sstevel@tonic-gate static int 56247c478bd9Sstevel@tonic-gate i_mdi_power_one_phci(mdi_pathinfo_t *pip) 56257c478bd9Sstevel@tonic-gate { 56267c478bd9Sstevel@tonic-gate int ret; 56277c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 56287c478bd9Sstevel@tonic-gate 56297c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 56307c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 56317c478bd9Sstevel@tonic-gate 56327c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 56337c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 56347c478bd9Sstevel@tonic-gate 56357c478bd9Sstevel@tonic-gate /* bring all components of phci to full power */ 56367c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 56377c478bd9Sstevel@tonic-gate "pm_powerup for %s%d\n", ddi_get_name(ph_dip), 56387c478bd9Sstevel@tonic-gate ddi_get_instance(ph_dip))); 56397c478bd9Sstevel@tonic-gate 56407c478bd9Sstevel@tonic-gate ret = pm_powerup(ph_dip); 56417c478bd9Sstevel@tonic-gate 56427c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 56437c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 56447c478bd9Sstevel@tonic-gate "pm_powerup FAILED for %s%d\n", 56457c478bd9Sstevel@tonic-gate ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 56467c478bd9Sstevel@tonic-gate 56477c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 56487c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 56497c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 56507c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 56517c478bd9Sstevel@tonic-gate } 56527c478bd9Sstevel@tonic-gate 56537c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 56547c478bd9Sstevel@tonic-gate } 56557c478bd9Sstevel@tonic-gate 56567c478bd9Sstevel@tonic-gate static int 56577c478bd9Sstevel@tonic-gate i_mdi_power_all_phci(mdi_client_t *ct) 56587c478bd9Sstevel@tonic-gate { 56597c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 56607c478bd9Sstevel@tonic-gate int succeeded = 0; 56617c478bd9Sstevel@tonic-gate 56627c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 56637c478bd9Sstevel@tonic-gate while (pip != NULL) { 56647c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 56657c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 56667c478bd9Sstevel@tonic-gate if (i_mdi_power_one_phci(pip) == MDI_SUCCESS) 56677c478bd9Sstevel@tonic-gate succeeded = 1; 56687c478bd9Sstevel@tonic-gate 56697c478bd9Sstevel@tonic-gate ASSERT(ct == MDI_PI(pip)->pi_client); 56707c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 56717c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 56727c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 56737c478bd9Sstevel@tonic-gate } 56747c478bd9Sstevel@tonic-gate 56757c478bd9Sstevel@tonic-gate return (succeeded ? MDI_SUCCESS : MDI_FAILURE); 56767c478bd9Sstevel@tonic-gate } 56777c478bd9Sstevel@tonic-gate 56787c478bd9Sstevel@tonic-gate /* 56797c478bd9Sstevel@tonic-gate * mdi_bus_power(): 56807c478bd9Sstevel@tonic-gate * 1. Place the phci(s) into powered up state so that 56817c478bd9Sstevel@tonic-gate * client can do power management 56827c478bd9Sstevel@tonic-gate * 2. Ensure phci powered up as client power managing 56837c478bd9Sstevel@tonic-gate * Return Values: 56847c478bd9Sstevel@tonic-gate * MDI_SUCCESS 56857c478bd9Sstevel@tonic-gate * MDI_FAILURE 56867c478bd9Sstevel@tonic-gate */ 56877c478bd9Sstevel@tonic-gate int 56887c478bd9Sstevel@tonic-gate mdi_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op, 56897c478bd9Sstevel@tonic-gate void *arg, void *result) 56907c478bd9Sstevel@tonic-gate { 56917c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 56927c478bd9Sstevel@tonic-gate pm_bp_child_pwrchg_t *bpc; 56937c478bd9Sstevel@tonic-gate mdi_client_t *ct; 56947c478bd9Sstevel@tonic-gate dev_info_t *cdip; 56957c478bd9Sstevel@tonic-gate pm_bp_has_changed_t *bphc; 56967c478bd9Sstevel@tonic-gate 56977c478bd9Sstevel@tonic-gate /* 56987c478bd9Sstevel@tonic-gate * BUS_POWER_NOINVOL not supported 56997c478bd9Sstevel@tonic-gate */ 57007c478bd9Sstevel@tonic-gate if (op == BUS_POWER_NOINVOL) 57017c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 57027c478bd9Sstevel@tonic-gate 57037c478bd9Sstevel@tonic-gate /* 57047c478bd9Sstevel@tonic-gate * ignore other OPs. 57057c478bd9Sstevel@tonic-gate * return quickly to save cou cycles on the ct processing 57067c478bd9Sstevel@tonic-gate */ 57077c478bd9Sstevel@tonic-gate switch (op) { 57087c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 57097c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 57107c478bd9Sstevel@tonic-gate bpc = (pm_bp_child_pwrchg_t *)arg; 57117c478bd9Sstevel@tonic-gate cdip = bpc->bpc_dip; 57127c478bd9Sstevel@tonic-gate break; 57137c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 57147c478bd9Sstevel@tonic-gate bphc = (pm_bp_has_changed_t *)arg; 57157c478bd9Sstevel@tonic-gate cdip = bphc->bphc_dip; 57167c478bd9Sstevel@tonic-gate break; 57177c478bd9Sstevel@tonic-gate default: 57187c478bd9Sstevel@tonic-gate return (pm_busop_bus_power(parent, impl_arg, op, arg, result)); 57197c478bd9Sstevel@tonic-gate } 57207c478bd9Sstevel@tonic-gate 57217c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(cdip)); 57227c478bd9Sstevel@tonic-gate 57237c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 57247c478bd9Sstevel@tonic-gate if (ct == NULL) 57257c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 57267c478bd9Sstevel@tonic-gate 57277c478bd9Sstevel@tonic-gate /* 57287c478bd9Sstevel@tonic-gate * wait till the mdi_pathinfo node state change are processed 57297c478bd9Sstevel@tonic-gate */ 57307c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 57317c478bd9Sstevel@tonic-gate switch (op) { 57327c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 57337c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 57347c478bd9Sstevel@tonic-gate "BUS_POWER_PRE_NOTIFICATION:" 57357c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 57367c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 57377c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp)); 57387c478bd9Sstevel@tonic-gate 57397c478bd9Sstevel@tonic-gate /* serialize power level change per client */ 57407c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 57417c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 57427c478bd9Sstevel@tonic-gate 57437c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_TRANSITION(ct); 57447c478bd9Sstevel@tonic-gate 57457c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 57467c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 57477c478bd9Sstevel@tonic-gate } 57487c478bd9Sstevel@tonic-gate 57497c478bd9Sstevel@tonic-gate /* 57507c478bd9Sstevel@tonic-gate * if new_level > 0: 57517c478bd9Sstevel@tonic-gate * - hold phci(s) 57527c478bd9Sstevel@tonic-gate * - power up phci(s) if not already 57537c478bd9Sstevel@tonic-gate * ignore power down 57547c478bd9Sstevel@tonic-gate */ 57557c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 57567c478bd9Sstevel@tonic-gate if (!DEVI_IS_ATTACHING(ct->ct_dip)) { 57577c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 57587c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 57597c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 57607c478bd9Sstevel@tonic-gate } 57617c478bd9Sstevel@tonic-gate } 57627c478bd9Sstevel@tonic-gate break; 57637c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 57647c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 57657c478bd9Sstevel@tonic-gate "BUS_POWER_POST_NOTIFICATION:" 57667c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d result=%d\n", 57677c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 57687c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp, 57697c478bd9Sstevel@tonic-gate *(int *)result)); 57707c478bd9Sstevel@tonic-gate 57717c478bd9Sstevel@tonic-gate if (*(int *)result == DDI_SUCCESS) { 57727c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 57737c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 57747c478bd9Sstevel@tonic-gate } else { 57757c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_DOWN(ct); 57767c478bd9Sstevel@tonic-gate } 57777c478bd9Sstevel@tonic-gate } 57787c478bd9Sstevel@tonic-gate 57797c478bd9Sstevel@tonic-gate /* release the hold we did in pre-notification */ 57807c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0 && (*(int *)result != DDI_SUCCESS) && 57817c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) { 57827c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 57837c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 57847c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 57857c478bd9Sstevel@tonic-gate } 57867c478bd9Sstevel@tonic-gate 57877c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel == 0 && (*(int *)result == DDI_SUCCESS)) { 57887c478bd9Sstevel@tonic-gate /* another thread might started attaching */ 57897c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 57907c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 57917c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 57927c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 57937c478bd9Sstevel@tonic-gate /* detaching has been taken care in pm_post_unconfig */ 57947c478bd9Sstevel@tonic-gate } else if (!DEVI_IS_DETACHING(ct->ct_dip)) { 57957c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 57967c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_reset_client\n")); 57977c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 57987c478bd9Sstevel@tonic-gate } 57997c478bd9Sstevel@tonic-gate } 58007c478bd9Sstevel@tonic-gate 58017c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_POWER_TRANSITION(ct); 58027c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_powerchange_cv); 58037c478bd9Sstevel@tonic-gate 58047c478bd9Sstevel@tonic-gate break; 58057c478bd9Sstevel@tonic-gate 58067c478bd9Sstevel@tonic-gate /* need to do more */ 58077c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 58087c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, "mdi_bus_power " 58097c478bd9Sstevel@tonic-gate "BUS_POWER_HAS_CHANGED:" 58107c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 58117c478bd9Sstevel@tonic-gate PM_NAME(bphc->bphc_dip), PM_ADDR(bphc->bphc_dip), 58127c478bd9Sstevel@tonic-gate bphc->bphc_olevel, bphc->bphc_nlevel, bphc->bphc_comp)); 58137c478bd9Sstevel@tonic-gate 58147c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel > 0 && 58157c478bd9Sstevel@tonic-gate bphc->bphc_nlevel > bphc->bphc_olevel) { 58167c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 58177c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 58187c478bd9Sstevel@tonic-gate } 58197c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 58207c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 58217c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 58227c478bd9Sstevel@tonic-gate } 58237c478bd9Sstevel@tonic-gate 58247c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel == 0 && bphc->bphc_olevel != -1) { 58257c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 58267c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 58277c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 58287c478bd9Sstevel@tonic-gate } 58297c478bd9Sstevel@tonic-gate break; 58307c478bd9Sstevel@tonic-gate } 58317c478bd9Sstevel@tonic-gate 58327c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 58337c478bd9Sstevel@tonic-gate return (ret); 58347c478bd9Sstevel@tonic-gate } 58357c478bd9Sstevel@tonic-gate 58367c478bd9Sstevel@tonic-gate static int 58377c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config_one(dev_info_t *child) 58387c478bd9Sstevel@tonic-gate { 58397c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 58407c478bd9Sstevel@tonic-gate mdi_client_t *ct; 58417c478bd9Sstevel@tonic-gate 58427c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 58437c478bd9Sstevel@tonic-gate if (ct == NULL) 58447c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 58457c478bd9Sstevel@tonic-gate 58467c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 58477c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 58487c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 58497c478bd9Sstevel@tonic-gate 58507c478bd9Sstevel@tonic-gate if (!MDI_CLIENT_IS_FAILED(ct)) { 58517c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 58527c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 58537c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one already configured\n")); 58547c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 58557c478bd9Sstevel@tonic-gate } 58567c478bd9Sstevel@tonic-gate 58577c478bd9Sstevel@tonic-gate if (ct->ct_powercnt_held) { 58587c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 58597c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 58607c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one ALREADY held\n")); 58617c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 58627c478bd9Sstevel@tonic-gate } 58637c478bd9Sstevel@tonic-gate 58647c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 58657c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 58667c478bd9Sstevel@tonic-gate } 58677c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 58687c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one i_mdi_pm_hold_client\n")); 58697c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 58707c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 1; 58717c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 58727c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 58737c478bd9Sstevel@tonic-gate return (ret); 58747c478bd9Sstevel@tonic-gate } 58757c478bd9Sstevel@tonic-gate 58767c478bd9Sstevel@tonic-gate static int 58777c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config(dev_info_t *parent, dev_info_t *child) 58787c478bd9Sstevel@tonic-gate { 58797c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 58807c478bd9Sstevel@tonic-gate dev_info_t *cdip; 58817c478bd9Sstevel@tonic-gate int circ; 58827c478bd9Sstevel@tonic-gate 58837c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 58847c478bd9Sstevel@tonic-gate 58857c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 58867c478bd9Sstevel@tonic-gate if (child) { 58877c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_config_one(child)); 58887c478bd9Sstevel@tonic-gate } 58897c478bd9Sstevel@tonic-gate 58907c478bd9Sstevel@tonic-gate /* devi_config_common */ 58917c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 58927c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 58937c478bd9Sstevel@tonic-gate while (cdip) { 58947c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 58957c478bd9Sstevel@tonic-gate 58967c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config_one(cdip); 58977c478bd9Sstevel@tonic-gate if (ret != MDI_SUCCESS) 58987c478bd9Sstevel@tonic-gate break; 58997c478bd9Sstevel@tonic-gate cdip = next; 59007c478bd9Sstevel@tonic-gate } 59017c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 59027c478bd9Sstevel@tonic-gate return (ret); 59037c478bd9Sstevel@tonic-gate } 59047c478bd9Sstevel@tonic-gate 59057c478bd9Sstevel@tonic-gate static int 59067c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig_one(dev_info_t *child, int *held, int flags) 59077c478bd9Sstevel@tonic-gate { 59087c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 59097c478bd9Sstevel@tonic-gate mdi_client_t *ct; 59107c478bd9Sstevel@tonic-gate 59117c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 59127c478bd9Sstevel@tonic-gate if (ct == NULL) 59137c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 59147c478bd9Sstevel@tonic-gate 59157c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 59167c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 59177c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 59187c478bd9Sstevel@tonic-gate 59197c478bd9Sstevel@tonic-gate if (i_ddi_node_state(ct->ct_dip) < DS_READY) { 59207c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59217c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig node detached already\n")); 59227c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59237c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 59247c478bd9Sstevel@tonic-gate } 59257c478bd9Sstevel@tonic-gate 59267c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_POWERED_DOWN(ct) && 59277c478bd9Sstevel@tonic-gate (flags & NDI_AUTODETACH)) { 59287c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59297c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig auto-modunload\n")); 59307c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59317c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 59327c478bd9Sstevel@tonic-gate } 59337c478bd9Sstevel@tonic-gate 59347c478bd9Sstevel@tonic-gate if (ct->ct_powercnt_held) { 59357c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59367c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig ct_powercnt_held\n")); 59377c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59387c478bd9Sstevel@tonic-gate *held = 1; 59397c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 59407c478bd9Sstevel@tonic-gate } 59417c478bd9Sstevel@tonic-gate 59427c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 59437c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 59447c478bd9Sstevel@tonic-gate } 59457c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 59467c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig i_mdi_pm_hold_client\n")); 59477c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 59487c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 1; 59497c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 59507c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 59517c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) 59527c478bd9Sstevel@tonic-gate *held = 1; 59537c478bd9Sstevel@tonic-gate return (ret); 59547c478bd9Sstevel@tonic-gate } 59557c478bd9Sstevel@tonic-gate 59567c478bd9Sstevel@tonic-gate static int 59577c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig(dev_info_t *parent, dev_info_t *child, int *held, 59587c478bd9Sstevel@tonic-gate int flags) 59597c478bd9Sstevel@tonic-gate { 59607c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 59617c478bd9Sstevel@tonic-gate dev_info_t *cdip; 59627c478bd9Sstevel@tonic-gate int circ; 59637c478bd9Sstevel@tonic-gate 59647c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 59657c478bd9Sstevel@tonic-gate *held = 0; 59667c478bd9Sstevel@tonic-gate 59677c478bd9Sstevel@tonic-gate /* ndi_devi_unconfig_one */ 59687c478bd9Sstevel@tonic-gate if (child) { 59697c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_unconfig_one(child, held, flags)); 59707c478bd9Sstevel@tonic-gate } 59717c478bd9Sstevel@tonic-gate 59727c478bd9Sstevel@tonic-gate /* devi_unconfig_common */ 59737c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 59747c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 59757c478bd9Sstevel@tonic-gate while (cdip) { 59767c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 59777c478bd9Sstevel@tonic-gate 59787c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig_one(cdip, held, flags); 59797c478bd9Sstevel@tonic-gate cdip = next; 59807c478bd9Sstevel@tonic-gate } 59817c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 59827c478bd9Sstevel@tonic-gate 59837c478bd9Sstevel@tonic-gate if (*held) 59847c478bd9Sstevel@tonic-gate ret = MDI_SUCCESS; 59857c478bd9Sstevel@tonic-gate 59867c478bd9Sstevel@tonic-gate return (ret); 59877c478bd9Sstevel@tonic-gate } 59887c478bd9Sstevel@tonic-gate 59897c478bd9Sstevel@tonic-gate static void 59907c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(dev_info_t *child) 59917c478bd9Sstevel@tonic-gate { 59927c478bd9Sstevel@tonic-gate mdi_client_t *ct; 59937c478bd9Sstevel@tonic-gate 59947c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 59957c478bd9Sstevel@tonic-gate if (ct == NULL) 59967c478bd9Sstevel@tonic-gate return; 59977c478bd9Sstevel@tonic-gate 59987c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 59997c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 60007c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 60017c478bd9Sstevel@tonic-gate 60027c478bd9Sstevel@tonic-gate if (ct->ct_powercnt_reset || !ct->ct_powercnt_held) { 60037c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60047c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config_one NOT held\n")); 60057c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60067c478bd9Sstevel@tonic-gate return; 60077c478bd9Sstevel@tonic-gate } 60087c478bd9Sstevel@tonic-gate 60097c478bd9Sstevel@tonic-gate /* client has not been updated */ 60107c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 60117c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60127c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config_one NOT configured\n")); 60137c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60147c478bd9Sstevel@tonic-gate return; 60157c478bd9Sstevel@tonic-gate } 60167c478bd9Sstevel@tonic-gate 60177c478bd9Sstevel@tonic-gate /* another thread might have powered it down or detached it */ 60187c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 60197c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) || 60207c478bd9Sstevel@tonic-gate (i_ddi_node_state(ct->ct_dip) < DS_READY && 60217c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 60227c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60237c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_reset_client\n")); 60247c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 60257c478bd9Sstevel@tonic-gate } else { 60267c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 60277c478bd9Sstevel@tonic-gate int valid_path_count = 0; 60287c478bd9Sstevel@tonic-gate 60297c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60307c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_rele_client\n")); 60317c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 60327c478bd9Sstevel@tonic-gate while (pip != NULL) { 60337c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 60347c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 60357c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 60367c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_ONLINE || 60377c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 60387c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_STANDBY) 60397c478bd9Sstevel@tonic-gate valid_path_count ++; 60407c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 60417c478bd9Sstevel@tonic-gate pip = next; 60427c478bd9Sstevel@tonic-gate } 60437c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, valid_path_count); 60447c478bd9Sstevel@tonic-gate } 60457c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 0; 60467c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60477c478bd9Sstevel@tonic-gate } 60487c478bd9Sstevel@tonic-gate 60497c478bd9Sstevel@tonic-gate static void 60507c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(dev_info_t *parent, dev_info_t *child) 60517c478bd9Sstevel@tonic-gate { 60527c478bd9Sstevel@tonic-gate int circ; 60537c478bd9Sstevel@tonic-gate dev_info_t *cdip; 60547c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 60557c478bd9Sstevel@tonic-gate 60567c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 60577c478bd9Sstevel@tonic-gate if (child) { 60587c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(child); 60597c478bd9Sstevel@tonic-gate return; 60607c478bd9Sstevel@tonic-gate } 60617c478bd9Sstevel@tonic-gate 60627c478bd9Sstevel@tonic-gate /* devi_config_common */ 60637c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 60647c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 60657c478bd9Sstevel@tonic-gate while (cdip) { 60667c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 60677c478bd9Sstevel@tonic-gate 60687c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(cdip); 60697c478bd9Sstevel@tonic-gate cdip = next; 60707c478bd9Sstevel@tonic-gate } 60717c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 60727c478bd9Sstevel@tonic-gate } 60737c478bd9Sstevel@tonic-gate 60747c478bd9Sstevel@tonic-gate static void 60757c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(dev_info_t *child) 60767c478bd9Sstevel@tonic-gate { 60777c478bd9Sstevel@tonic-gate mdi_client_t *ct; 60787c478bd9Sstevel@tonic-gate 60797c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 60807c478bd9Sstevel@tonic-gate if (ct == NULL) 60817c478bd9Sstevel@tonic-gate return; 60827c478bd9Sstevel@tonic-gate 60837c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 60847c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 60857c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 60867c478bd9Sstevel@tonic-gate 60877c478bd9Sstevel@tonic-gate if (!ct->ct_powercnt_held) { 60887c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 60897c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig NOT held\n")); 60907c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 60917c478bd9Sstevel@tonic-gate return; 60927c478bd9Sstevel@tonic-gate } 60937c478bd9Sstevel@tonic-gate 60947c478bd9Sstevel@tonic-gate /* failure detaching or another thread just attached it */ 60957c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 60967c478bd9Sstevel@tonic-gate i_ddi_node_state(ct->ct_dip) == DS_READY) || 60977c478bd9Sstevel@tonic-gate (i_ddi_node_state(ct->ct_dip) != DS_READY && 60987c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 60997c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 61007c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig i_mdi_pm_reset_client\n")); 61017c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 61027c478bd9Sstevel@tonic-gate } 61037c478bd9Sstevel@tonic-gate 61047c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 61057c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig not changed\n")); 61067c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 61077c478bd9Sstevel@tonic-gate } 61087c478bd9Sstevel@tonic-gate 61097c478bd9Sstevel@tonic-gate static void 61107c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(dev_info_t *parent, dev_info_t *child, int held) 61117c478bd9Sstevel@tonic-gate { 61127c478bd9Sstevel@tonic-gate int circ; 61137c478bd9Sstevel@tonic-gate dev_info_t *cdip; 61147c478bd9Sstevel@tonic-gate 61157c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 61167c478bd9Sstevel@tonic-gate 61177c478bd9Sstevel@tonic-gate if (!held) { 61187c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, parent, 61197c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig held = %d\n", held)); 61207c478bd9Sstevel@tonic-gate return; 61217c478bd9Sstevel@tonic-gate } 61227c478bd9Sstevel@tonic-gate 61237c478bd9Sstevel@tonic-gate if (child) { 61247c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(child); 61257c478bd9Sstevel@tonic-gate return; 61267c478bd9Sstevel@tonic-gate } 61277c478bd9Sstevel@tonic-gate 61287c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 61297c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 61307c478bd9Sstevel@tonic-gate while (cdip) { 61317c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 61327c478bd9Sstevel@tonic-gate 61337c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(cdip); 61347c478bd9Sstevel@tonic-gate cdip = next; 61357c478bd9Sstevel@tonic-gate } 61367c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 61377c478bd9Sstevel@tonic-gate } 61387c478bd9Sstevel@tonic-gate 61397c478bd9Sstevel@tonic-gate int 61407c478bd9Sstevel@tonic-gate mdi_power(dev_info_t *vdip, mdi_pm_op_t op, void *args, char *devnm, int flags) 61417c478bd9Sstevel@tonic-gate { 61427c478bd9Sstevel@tonic-gate int circ, ret = MDI_SUCCESS; 61437c478bd9Sstevel@tonic-gate dev_info_t *client_dip = NULL; 61447c478bd9Sstevel@tonic-gate mdi_client_t *ct; 61457c478bd9Sstevel@tonic-gate 61467c478bd9Sstevel@tonic-gate /* 61477c478bd9Sstevel@tonic-gate * Handling ndi_devi_config_one and ndi_devi_unconfig_one. 61487c478bd9Sstevel@tonic-gate * Power up pHCI for the named client device. 61497c478bd9Sstevel@tonic-gate * Note: Before the client is enumerated under vhci by phci, 61507c478bd9Sstevel@tonic-gate * client_dip can be NULL. Then proceed to power up all the 61517c478bd9Sstevel@tonic-gate * pHCIs. 61527c478bd9Sstevel@tonic-gate */ 61537c478bd9Sstevel@tonic-gate if (devnm != NULL) { 61547c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circ); 61557c478bd9Sstevel@tonic-gate client_dip = ndi_devi_findchild(vdip, devnm); 61567c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circ); 61577c478bd9Sstevel@tonic-gate } 61587c478bd9Sstevel@tonic-gate 61597c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, vdip, "mdi_power op = %d\n", op)); 61607c478bd9Sstevel@tonic-gate 61617c478bd9Sstevel@tonic-gate switch (op) { 61627c478bd9Sstevel@tonic-gate case MDI_PM_PRE_CONFIG: 61637c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config(vdip, client_dip); 61647c478bd9Sstevel@tonic-gate 61657c478bd9Sstevel@tonic-gate break; 61667c478bd9Sstevel@tonic-gate case MDI_PM_PRE_UNCONFIG: 61677c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig(vdip, client_dip, (int *)args, 61687c478bd9Sstevel@tonic-gate flags); 61697c478bd9Sstevel@tonic-gate 61707c478bd9Sstevel@tonic-gate break; 61717c478bd9Sstevel@tonic-gate case MDI_PM_POST_CONFIG: 61727c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(vdip, client_dip); 61737c478bd9Sstevel@tonic-gate 61747c478bd9Sstevel@tonic-gate break; 61757c478bd9Sstevel@tonic-gate case MDI_PM_POST_UNCONFIG: 61767c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(vdip, client_dip, *(int *)args); 61777c478bd9Sstevel@tonic-gate 61787c478bd9Sstevel@tonic-gate break; 61797c478bd9Sstevel@tonic-gate case MDI_PM_HOLD_POWER: 61807c478bd9Sstevel@tonic-gate case MDI_PM_RELE_POWER: 61817c478bd9Sstevel@tonic-gate ASSERT(args); 61827c478bd9Sstevel@tonic-gate 61837c478bd9Sstevel@tonic-gate client_dip = (dev_info_t *)args; 61847c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(client_dip)); 61857c478bd9Sstevel@tonic-gate 61867c478bd9Sstevel@tonic-gate ct = i_devi_get_client(client_dip); 61877c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 61887c478bd9Sstevel@tonic-gate 61897c478bd9Sstevel@tonic-gate if (op == MDI_PM_HOLD_POWER) { 61907c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 61917c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 61927c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 61937c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_hold_client\n")); 61947c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 61957c478bd9Sstevel@tonic-gate } 61967c478bd9Sstevel@tonic-gate } else { 61977c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 61987c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 61997c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_rele_client\n")); 62007c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 62017c478bd9Sstevel@tonic-gate } else { 62027c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 62037c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_reset_client\n")); 62047c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 62057c478bd9Sstevel@tonic-gate } 62067c478bd9Sstevel@tonic-gate } 62077c478bd9Sstevel@tonic-gate 62087c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 62097c478bd9Sstevel@tonic-gate break; 62107c478bd9Sstevel@tonic-gate default: 62117c478bd9Sstevel@tonic-gate break; 62127c478bd9Sstevel@tonic-gate } 62137c478bd9Sstevel@tonic-gate 62147c478bd9Sstevel@tonic-gate return (ret); 62157c478bd9Sstevel@tonic-gate } 62167c478bd9Sstevel@tonic-gate 62177c478bd9Sstevel@tonic-gate int 62187c478bd9Sstevel@tonic-gate mdi_component_is_vhci(dev_info_t *dip, const char **mdi_class) 62197c478bd9Sstevel@tonic-gate { 62207c478bd9Sstevel@tonic-gate mdi_vhci_t *vhci; 62217c478bd9Sstevel@tonic-gate 62227c478bd9Sstevel@tonic-gate if (!MDI_VHCI(dip)) 62237c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 62247c478bd9Sstevel@tonic-gate 62257c478bd9Sstevel@tonic-gate if (mdi_class) { 62267c478bd9Sstevel@tonic-gate vhci = DEVI(dip)->devi_mdi_xhci; 62277c478bd9Sstevel@tonic-gate ASSERT(vhci); 62287c478bd9Sstevel@tonic-gate *mdi_class = vhci->vh_class; 62297c478bd9Sstevel@tonic-gate } 62307c478bd9Sstevel@tonic-gate 62317c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 62327c478bd9Sstevel@tonic-gate } 62337c478bd9Sstevel@tonic-gate 62347c478bd9Sstevel@tonic-gate int 62357c478bd9Sstevel@tonic-gate mdi_component_is_phci(dev_info_t *dip, const char **mdi_class) 62367c478bd9Sstevel@tonic-gate { 62377c478bd9Sstevel@tonic-gate mdi_phci_t *phci; 62387c478bd9Sstevel@tonic-gate 62397c478bd9Sstevel@tonic-gate if (!MDI_PHCI(dip)) 62407c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 62417c478bd9Sstevel@tonic-gate 62427c478bd9Sstevel@tonic-gate if (mdi_class) { 62437c478bd9Sstevel@tonic-gate phci = DEVI(dip)->devi_mdi_xhci; 62447c478bd9Sstevel@tonic-gate ASSERT(phci); 62457c478bd9Sstevel@tonic-gate *mdi_class = phci->ph_vhci->vh_class; 62467c478bd9Sstevel@tonic-gate } 62477c478bd9Sstevel@tonic-gate 62487c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 62497c478bd9Sstevel@tonic-gate } 62507c478bd9Sstevel@tonic-gate 62517c478bd9Sstevel@tonic-gate int 62527c478bd9Sstevel@tonic-gate mdi_component_is_client(dev_info_t *dip, const char **mdi_class) 62537c478bd9Sstevel@tonic-gate { 62547c478bd9Sstevel@tonic-gate mdi_client_t *client; 62557c478bd9Sstevel@tonic-gate 62567c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(dip)) 62577c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 62587c478bd9Sstevel@tonic-gate 62597c478bd9Sstevel@tonic-gate if (mdi_class) { 62607c478bd9Sstevel@tonic-gate client = DEVI(dip)->devi_mdi_client; 62617c478bd9Sstevel@tonic-gate ASSERT(client); 62627c478bd9Sstevel@tonic-gate *mdi_class = client->ct_vhci->vh_class; 62637c478bd9Sstevel@tonic-gate } 62647c478bd9Sstevel@tonic-gate 62657c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 62667c478bd9Sstevel@tonic-gate } 62677c478bd9Sstevel@tonic-gate 62687c478bd9Sstevel@tonic-gate void * 62697c478bd9Sstevel@tonic-gate mdi_client_get_vhci_private(dev_info_t *dip) 62707c478bd9Sstevel@tonic-gate { 62717c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 62727c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 62737c478bd9Sstevel@tonic-gate mdi_client_t *ct; 62747c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 62757c478bd9Sstevel@tonic-gate return (ct->ct_vprivate); 62767c478bd9Sstevel@tonic-gate } 62777c478bd9Sstevel@tonic-gate return (NULL); 62787c478bd9Sstevel@tonic-gate } 62797c478bd9Sstevel@tonic-gate 62807c478bd9Sstevel@tonic-gate void 62817c478bd9Sstevel@tonic-gate mdi_client_set_vhci_private(dev_info_t *dip, void *data) 62827c478bd9Sstevel@tonic-gate { 62837c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 62847c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 62857c478bd9Sstevel@tonic-gate mdi_client_t *ct; 62867c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 62877c478bd9Sstevel@tonic-gate ct->ct_vprivate = data; 62887c478bd9Sstevel@tonic-gate } 62897c478bd9Sstevel@tonic-gate } 62907c478bd9Sstevel@tonic-gate /* 62917c478bd9Sstevel@tonic-gate * mdi_pi_get_vhci_private(): 62927c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 62937c478bd9Sstevel@tonic-gate * mdi_pathinfo node 62947c478bd9Sstevel@tonic-gate */ 62957c478bd9Sstevel@tonic-gate void * 62967c478bd9Sstevel@tonic-gate mdi_pi_get_vhci_private(mdi_pathinfo_t *pip) 62977c478bd9Sstevel@tonic-gate { 62987c478bd9Sstevel@tonic-gate caddr_t vprivate = NULL; 62997c478bd9Sstevel@tonic-gate if (pip) { 63007c478bd9Sstevel@tonic-gate vprivate = MDI_PI(pip)->pi_vprivate; 63017c478bd9Sstevel@tonic-gate } 63027c478bd9Sstevel@tonic-gate return (vprivate); 63037c478bd9Sstevel@tonic-gate } 63047c478bd9Sstevel@tonic-gate 63057c478bd9Sstevel@tonic-gate /* 63067c478bd9Sstevel@tonic-gate * mdi_pi_set_vhci_private(): 63077c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_pathinfo node 63087c478bd9Sstevel@tonic-gate */ 63097c478bd9Sstevel@tonic-gate void 63107c478bd9Sstevel@tonic-gate mdi_pi_set_vhci_private(mdi_pathinfo_t *pip, void *priv) 63117c478bd9Sstevel@tonic-gate { 63127c478bd9Sstevel@tonic-gate if (pip) { 63137c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = priv; 63147c478bd9Sstevel@tonic-gate } 63157c478bd9Sstevel@tonic-gate } 63167c478bd9Sstevel@tonic-gate 63177c478bd9Sstevel@tonic-gate /* 63187c478bd9Sstevel@tonic-gate * mdi_phci_get_vhci_private(): 63197c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 63207c478bd9Sstevel@tonic-gate * mdi_phci node 63217c478bd9Sstevel@tonic-gate */ 63227c478bd9Sstevel@tonic-gate void * 63237c478bd9Sstevel@tonic-gate mdi_phci_get_vhci_private(dev_info_t *dip) 63247c478bd9Sstevel@tonic-gate { 63257c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 63267c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 63277c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 63287c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 63297c478bd9Sstevel@tonic-gate return (ph->ph_vprivate); 63307c478bd9Sstevel@tonic-gate } 63317c478bd9Sstevel@tonic-gate return (NULL); 63327c478bd9Sstevel@tonic-gate } 63337c478bd9Sstevel@tonic-gate 63347c478bd9Sstevel@tonic-gate /* 63357c478bd9Sstevel@tonic-gate * mdi_phci_set_vhci_private(): 63367c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_phci node 63377c478bd9Sstevel@tonic-gate */ 63387c478bd9Sstevel@tonic-gate void 63397c478bd9Sstevel@tonic-gate mdi_phci_set_vhci_private(dev_info_t *dip, void *priv) 63407c478bd9Sstevel@tonic-gate { 63417c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 63427c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 63437c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 63447c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 63457c478bd9Sstevel@tonic-gate ph->ph_vprivate = priv; 63467c478bd9Sstevel@tonic-gate } 63477c478bd9Sstevel@tonic-gate } 6348*3c34adc5Sramat 6349*3c34adc5Sramat /* 6350*3c34adc5Sramat * List of vhci class names: 6351*3c34adc5Sramat * A vhci class name must be in this list only if the corresponding vhci 6352*3c34adc5Sramat * driver intends to use the mdi provided bus config implementation 6353*3c34adc5Sramat * (i.e., mdi_vhci_bus_config()). 6354*3c34adc5Sramat */ 6355*3c34adc5Sramat static char *vhci_class_list[] = { MDI_HCI_CLASS_SCSI, MDI_HCI_CLASS_IB }; 6356*3c34adc5Sramat #define N_VHCI_CLASSES (sizeof (vhci_class_list) / sizeof (char *)) 6357*3c34adc5Sramat 6358*3c34adc5Sramat /* 6359*3c34adc5Sramat * Built-in list of phci drivers for every vhci class. 6360*3c34adc5Sramat * All phci drivers expect iscsi have root device support. 6361*3c34adc5Sramat */ 6362*3c34adc5Sramat static mdi_phci_driver_info_t scsi_phci_driver_list[] = { 6363*3c34adc5Sramat { "fp", 1 }, 6364*3c34adc5Sramat { "iscsi", 0 }, 6365*3c34adc5Sramat { "ibsrp", 1 } 6366*3c34adc5Sramat }; 6367*3c34adc5Sramat 6368*3c34adc5Sramat static mdi_phci_driver_info_t ib_phci_driver_list[] = { "tavor", 1 }; 6369*3c34adc5Sramat 6370*3c34adc5Sramat /* 6371*3c34adc5Sramat * During boot time, the on-disk vhci cache for every vhci class is read 6372*3c34adc5Sramat * in the form of an nvlist and stored here. 6373*3c34adc5Sramat */ 6374*3c34adc5Sramat static nvlist_t *vhcache_nvl[N_VHCI_CLASSES]; 6375*3c34adc5Sramat 6376*3c34adc5Sramat /* nvpair names in vhci cache nvlist */ 6377*3c34adc5Sramat #define MDI_VHCI_CACHE_VERSION 1 6378*3c34adc5Sramat #define MDI_NVPNAME_VERSION "version" 6379*3c34adc5Sramat #define MDI_NVPNAME_PHCIS "phcis" 6380*3c34adc5Sramat #define MDI_NVPNAME_CTADDRMAP "clientaddrmap" 6381*3c34adc5Sramat 6382*3c34adc5Sramat typedef enum { 6383*3c34adc5Sramat VHCACHE_NOT_REBUILT, 6384*3c34adc5Sramat VHCACHE_PARTIALLY_BUILT, 6385*3c34adc5Sramat VHCACHE_FULLY_BUILT 6386*3c34adc5Sramat } vhcache_build_status_t; 6387*3c34adc5Sramat 6388*3c34adc5Sramat /* 6389*3c34adc5Sramat * Given vhci class name, return its on-disk vhci cache filename. 6390*3c34adc5Sramat * Memory for the returned filename which includes the full path is allocated 6391*3c34adc5Sramat * by this function. 6392*3c34adc5Sramat */ 6393*3c34adc5Sramat static char * 6394*3c34adc5Sramat vhclass2vhcache_filename(char *vhclass) 6395*3c34adc5Sramat { 6396*3c34adc5Sramat char *filename; 6397*3c34adc5Sramat int len; 6398*3c34adc5Sramat static char *fmt = "/etc/devices/mdi_%s_cache"; 6399*3c34adc5Sramat 6400*3c34adc5Sramat /* 6401*3c34adc5Sramat * fmt contains the on-disk vhci cache file name format; 6402*3c34adc5Sramat * for scsi_vhci the filename is "/etc/devices/mdi_scsi_vhci_cache". 6403*3c34adc5Sramat */ 6404*3c34adc5Sramat 6405*3c34adc5Sramat /* the -1 below is to account for "%s" in the format string */ 6406*3c34adc5Sramat len = strlen(fmt) + strlen(vhclass) - 1; 6407*3c34adc5Sramat filename = kmem_alloc(len, KM_SLEEP); 6408*3c34adc5Sramat (void) snprintf(filename, len, fmt, vhclass); 6409*3c34adc5Sramat ASSERT(len == (strlen(filename) + 1)); 6410*3c34adc5Sramat return (filename); 6411*3c34adc5Sramat } 6412*3c34adc5Sramat 6413*3c34adc5Sramat /* 6414*3c34adc5Sramat * initialize the vhci cache related data structures and read the on-disk 6415*3c34adc5Sramat * vhci cached data into memory. 6416*3c34adc5Sramat */ 6417*3c34adc5Sramat static void 6418*3c34adc5Sramat setup_vhci_cache(mdi_vhci_t *vh) 6419*3c34adc5Sramat { 6420*3c34adc5Sramat mdi_vhci_config_t *vhc; 6421*3c34adc5Sramat mdi_vhci_cache_t *vhcache; 6422*3c34adc5Sramat int i; 6423*3c34adc5Sramat nvlist_t *nvl = NULL; 6424*3c34adc5Sramat 6425*3c34adc5Sramat vhc = kmem_zalloc(sizeof (mdi_vhci_config_t), KM_SLEEP); 6426*3c34adc5Sramat vh->vh_config = vhc; 6427*3c34adc5Sramat vhcache = &vhc->vhc_vhcache; 6428*3c34adc5Sramat 6429*3c34adc5Sramat vhc->vhc_vhcache_filename = vhclass2vhcache_filename(vh->vh_class); 6430*3c34adc5Sramat 6431*3c34adc5Sramat mutex_init(&vhc->vhc_lock, NULL, MUTEX_DEFAULT, NULL); 6432*3c34adc5Sramat cv_init(&vhc->vhc_cv, NULL, CV_DRIVER, NULL); 6433*3c34adc5Sramat 6434*3c34adc5Sramat rw_init(&vhcache->vhcache_lock, NULL, RW_DRIVER, NULL); 6435*3c34adc5Sramat 6436*3c34adc5Sramat /* 6437*3c34adc5Sramat * Create string hash; same as mod_hash_create_strhash() except that 6438*3c34adc5Sramat * we use NULL key destructor. 6439*3c34adc5Sramat */ 6440*3c34adc5Sramat vhcache->vhcache_client_hash = mod_hash_create_extended(vh->vh_class, 6441*3c34adc5Sramat mdi_bus_config_cache_hash_size, 6442*3c34adc5Sramat mod_hash_null_keydtor, mod_hash_null_valdtor, 6443*3c34adc5Sramat mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 6444*3c34adc5Sramat 6445*3c34adc5Sramat setup_phci_driver_list(vh); 6446*3c34adc5Sramat 6447*3c34adc5Sramat /* 6448*3c34adc5Sramat * The on-disk vhci cache is read during booting prior to the 6449*3c34adc5Sramat * lights-out period by mdi_read_devices_files(). 6450*3c34adc5Sramat */ 6451*3c34adc5Sramat for (i = 0; i < N_VHCI_CLASSES; i++) { 6452*3c34adc5Sramat if (strcmp(vhci_class_list[i], vh->vh_class) == 0) { 6453*3c34adc5Sramat nvl = vhcache_nvl[i]; 6454*3c34adc5Sramat vhcache_nvl[i] = NULL; 6455*3c34adc5Sramat break; 6456*3c34adc5Sramat } 6457*3c34adc5Sramat } 6458*3c34adc5Sramat 6459*3c34adc5Sramat /* 6460*3c34adc5Sramat * this is to cover the case of some one manually causing unloading 6461*3c34adc5Sramat * (or detaching) and reloading (or attaching) of a vhci driver. 6462*3c34adc5Sramat */ 6463*3c34adc5Sramat if (nvl == NULL && modrootloaded) 6464*3c34adc5Sramat nvl = read_on_disk_vhci_cache(vh->vh_class); 6465*3c34adc5Sramat 6466*3c34adc5Sramat if (nvl != NULL) { 6467*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 6468*3c34adc5Sramat if (mainnvl_to_vhcache(vhcache, nvl) == MDI_SUCCESS) 6469*3c34adc5Sramat vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE; 6470*3c34adc5Sramat else { 6471*3c34adc5Sramat cmn_err(CE_WARN, 6472*3c34adc5Sramat "%s: data file corrupted, will recreate\n", 6473*3c34adc5Sramat vhc->vhc_vhcache_filename); 6474*3c34adc5Sramat } 6475*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 6476*3c34adc5Sramat nvlist_free(nvl); 6477*3c34adc5Sramat } 6478*3c34adc5Sramat 6479*3c34adc5Sramat vhc->vhc_cbid = callb_add(stop_vhcache_flush_thread, vhc, 6480*3c34adc5Sramat CB_CL_UADMIN_PRE_VFS, "mdi_vhcache_flush"); 6481*3c34adc5Sramat } 6482*3c34adc5Sramat 6483*3c34adc5Sramat /* 6484*3c34adc5Sramat * free all vhci cache related resources 6485*3c34adc5Sramat */ 6486*3c34adc5Sramat static int 6487*3c34adc5Sramat destroy_vhci_cache(mdi_vhci_t *vh) 6488*3c34adc5Sramat { 6489*3c34adc5Sramat mdi_vhci_config_t *vhc = vh->vh_config; 6490*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 6491*3c34adc5Sramat mdi_vhcache_phci_t *cphci, *cphci_next; 6492*3c34adc5Sramat mdi_vhcache_client_t *cct, *cct_next; 6493*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_next; 6494*3c34adc5Sramat 6495*3c34adc5Sramat if (stop_vhcache_async_threads(vhc) != MDI_SUCCESS) 6496*3c34adc5Sramat return (MDI_FAILURE); 6497*3c34adc5Sramat 6498*3c34adc5Sramat kmem_free(vhc->vhc_vhcache_filename, 6499*3c34adc5Sramat strlen(vhc->vhc_vhcache_filename) + 1); 6500*3c34adc5Sramat 6501*3c34adc5Sramat if (vhc->vhc_phci_driver_list) 6502*3c34adc5Sramat free_phci_driver_list(vhc); 6503*3c34adc5Sramat 6504*3c34adc5Sramat mod_hash_destroy_strhash(vhcache->vhcache_client_hash); 6505*3c34adc5Sramat 6506*3c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 6507*3c34adc5Sramat cphci = cphci_next) { 6508*3c34adc5Sramat cphci_next = cphci->cphci_next; 6509*3c34adc5Sramat free_vhcache_phci(cphci); 6510*3c34adc5Sramat } 6511*3c34adc5Sramat 6512*3c34adc5Sramat for (cct = vhcache->vhcache_client_head; cct != NULL; cct = cct_next) { 6513*3c34adc5Sramat cct_next = cct->cct_next; 6514*3c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi_next) { 6515*3c34adc5Sramat cpi_next = cpi->cpi_next; 6516*3c34adc5Sramat free_vhcache_pathinfo(cpi); 6517*3c34adc5Sramat } 6518*3c34adc5Sramat free_vhcache_client(cct); 6519*3c34adc5Sramat } 6520*3c34adc5Sramat 6521*3c34adc5Sramat rw_destroy(&vhcache->vhcache_lock); 6522*3c34adc5Sramat 6523*3c34adc5Sramat mutex_destroy(&vhc->vhc_lock); 6524*3c34adc5Sramat cv_destroy(&vhc->vhc_cv); 6525*3c34adc5Sramat kmem_free(vhc, sizeof (mdi_vhci_config_t)); 6526*3c34adc5Sramat return (MDI_SUCCESS); 6527*3c34adc5Sramat } 6528*3c34adc5Sramat 6529*3c34adc5Sramat /* 6530*3c34adc5Sramat * Setup the list of phci drivers associated with the specified vhci class. 6531*3c34adc5Sramat * MDI uses this information to rebuild bus config cache if in case the 6532*3c34adc5Sramat * cache is not available or corrupted. 6533*3c34adc5Sramat */ 6534*3c34adc5Sramat static void 6535*3c34adc5Sramat setup_phci_driver_list(mdi_vhci_t *vh) 6536*3c34adc5Sramat { 6537*3c34adc5Sramat mdi_vhci_config_t *vhc = vh->vh_config; 6538*3c34adc5Sramat mdi_phci_driver_info_t *driver_list; 6539*3c34adc5Sramat char **driver_list1; 6540*3c34adc5Sramat uint_t ndrivers, ndrivers1; 6541*3c34adc5Sramat int i, j; 6542*3c34adc5Sramat 6543*3c34adc5Sramat if (strcmp(vh->vh_class, MDI_HCI_CLASS_SCSI) == 0) { 6544*3c34adc5Sramat driver_list = scsi_phci_driver_list; 6545*3c34adc5Sramat ndrivers = sizeof (scsi_phci_driver_list) / 6546*3c34adc5Sramat sizeof (mdi_phci_driver_info_t); 6547*3c34adc5Sramat } else if (strcmp(vh->vh_class, MDI_HCI_CLASS_IB) == 0) { 6548*3c34adc5Sramat driver_list = ib_phci_driver_list; 6549*3c34adc5Sramat ndrivers = sizeof (ib_phci_driver_list) / 6550*3c34adc5Sramat sizeof (mdi_phci_driver_info_t); 6551*3c34adc5Sramat } else { 6552*3c34adc5Sramat driver_list = NULL; 6553*3c34adc5Sramat ndrivers = 0; 6554*3c34adc5Sramat } 6555*3c34adc5Sramat 6556*3c34adc5Sramat /* 6557*3c34adc5Sramat * The driver.conf file of a vhci driver can specify additional 6558*3c34adc5Sramat * phci drivers using a project private "phci-drivers" property. 6559*3c34adc5Sramat */ 6560*3c34adc5Sramat if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, vh->vh_dip, 6561*3c34adc5Sramat DDI_PROP_DONTPASS, "phci-drivers", &driver_list1, 6562*3c34adc5Sramat &ndrivers1) != DDI_PROP_SUCCESS) 6563*3c34adc5Sramat ndrivers1 = 0; 6564*3c34adc5Sramat 6565*3c34adc5Sramat vhc->vhc_nphci_drivers = ndrivers + ndrivers1; 6566*3c34adc5Sramat if (vhc->vhc_nphci_drivers == 0) 6567*3c34adc5Sramat return; 6568*3c34adc5Sramat 6569*3c34adc5Sramat vhc->vhc_phci_driver_list = kmem_alloc( 6570*3c34adc5Sramat sizeof (mdi_phci_driver_info_t) * vhc->vhc_nphci_drivers, KM_SLEEP); 6571*3c34adc5Sramat 6572*3c34adc5Sramat for (i = 0; i < ndrivers; i++) { 6573*3c34adc5Sramat vhc->vhc_phci_driver_list[i].phdriver_name = 6574*3c34adc5Sramat i_ddi_strdup(driver_list[i].phdriver_name, KM_SLEEP); 6575*3c34adc5Sramat vhc->vhc_phci_driver_list[i].phdriver_root_support = 6576*3c34adc5Sramat driver_list[i].phdriver_root_support; 6577*3c34adc5Sramat } 6578*3c34adc5Sramat 6579*3c34adc5Sramat for (j = 0; j < ndrivers1; j++, i++) { 6580*3c34adc5Sramat vhc->vhc_phci_driver_list[i].phdriver_name = 6581*3c34adc5Sramat i_ddi_strdup(driver_list1[j], KM_SLEEP); 6582*3c34adc5Sramat vhc->vhc_phci_driver_list[i].phdriver_root_support = 1; 6583*3c34adc5Sramat } 6584*3c34adc5Sramat 6585*3c34adc5Sramat if (ndrivers1) 6586*3c34adc5Sramat ddi_prop_free(driver_list1); 6587*3c34adc5Sramat } 6588*3c34adc5Sramat 6589*3c34adc5Sramat /* 6590*3c34adc5Sramat * Free the memory allocated for the phci driver list 6591*3c34adc5Sramat */ 6592*3c34adc5Sramat static void 6593*3c34adc5Sramat free_phci_driver_list(mdi_vhci_config_t *vhc) 6594*3c34adc5Sramat { 6595*3c34adc5Sramat int i; 6596*3c34adc5Sramat 6597*3c34adc5Sramat if (vhc->vhc_phci_driver_list == NULL) 6598*3c34adc5Sramat return; 6599*3c34adc5Sramat 6600*3c34adc5Sramat for (i = 0; i < vhc->vhc_nphci_drivers; i++) { 6601*3c34adc5Sramat kmem_free(vhc->vhc_phci_driver_list[i].phdriver_name, 6602*3c34adc5Sramat strlen(vhc->vhc_phci_driver_list[i].phdriver_name) + 1); 6603*3c34adc5Sramat } 6604*3c34adc5Sramat 6605*3c34adc5Sramat kmem_free(vhc->vhc_phci_driver_list, 6606*3c34adc5Sramat sizeof (mdi_phci_driver_info_t) * vhc->vhc_nphci_drivers); 6607*3c34adc5Sramat } 6608*3c34adc5Sramat 6609*3c34adc5Sramat /* 6610*3c34adc5Sramat * Stop all vhci cache related async threads and free their resources. 6611*3c34adc5Sramat */ 6612*3c34adc5Sramat static int 6613*3c34adc5Sramat stop_vhcache_async_threads(mdi_vhci_config_t *vhc) 6614*3c34adc5Sramat { 6615*3c34adc5Sramat mdi_async_client_config_t *acc, *acc_next; 6616*3c34adc5Sramat 6617*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 6618*3c34adc5Sramat vhc->vhc_flags |= MDI_VHC_EXIT; 6619*3c34adc5Sramat ASSERT(vhc->vhc_acc_thrcount >= 0); 6620*3c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 6621*3c34adc5Sramat 6622*3c34adc5Sramat while ((vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) || 6623*3c34adc5Sramat (vhc->vhc_flags & MDI_VHC_BUILD_VHCI_CACHE_THREAD) || 6624*3c34adc5Sramat vhc->vhc_acc_thrcount != 0) { 6625*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 6626*3c34adc5Sramat delay(1); 6627*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 6628*3c34adc5Sramat } 6629*3c34adc5Sramat 6630*3c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_EXIT; 6631*3c34adc5Sramat 6632*3c34adc5Sramat for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc_next) { 6633*3c34adc5Sramat acc_next = acc->acc_next; 6634*3c34adc5Sramat free_async_client_config(acc); 6635*3c34adc5Sramat } 6636*3c34adc5Sramat vhc->vhc_acc_list_head = NULL; 6637*3c34adc5Sramat vhc->vhc_acc_list_tail = NULL; 6638*3c34adc5Sramat vhc->vhc_acc_count = 0; 6639*3c34adc5Sramat 6640*3c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) { 6641*3c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 6642*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 6643*3c34adc5Sramat if (flush_vhcache(vhc, 0) != MDI_SUCCESS) { 6644*3c34adc5Sramat vhcache_dirty(vhc); 6645*3c34adc5Sramat return (MDI_FAILURE); 6646*3c34adc5Sramat } 6647*3c34adc5Sramat } else 6648*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 6649*3c34adc5Sramat 6650*3c34adc5Sramat if (callb_delete(vhc->vhc_cbid) != 0) 6651*3c34adc5Sramat return (MDI_FAILURE); 6652*3c34adc5Sramat 6653*3c34adc5Sramat return (MDI_SUCCESS); 6654*3c34adc5Sramat } 6655*3c34adc5Sramat 6656*3c34adc5Sramat /* 6657*3c34adc5Sramat * Stop vhci cache flush thread 6658*3c34adc5Sramat */ 6659*3c34adc5Sramat /* ARGSUSED */ 6660*3c34adc5Sramat static boolean_t 6661*3c34adc5Sramat stop_vhcache_flush_thread(void *arg, int code) 6662*3c34adc5Sramat { 6663*3c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 6664*3c34adc5Sramat 6665*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 6666*3c34adc5Sramat vhc->vhc_flags |= MDI_VHC_EXIT; 6667*3c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 6668*3c34adc5Sramat 6669*3c34adc5Sramat while (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) { 6670*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 6671*3c34adc5Sramat delay(1); 6672*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 6673*3c34adc5Sramat } 6674*3c34adc5Sramat 6675*3c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) { 6676*3c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 6677*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 6678*3c34adc5Sramat (void) flush_vhcache(vhc, 1); 6679*3c34adc5Sramat } else 6680*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 6681*3c34adc5Sramat 6682*3c34adc5Sramat return (B_TRUE); 6683*3c34adc5Sramat } 6684*3c34adc5Sramat 6685*3c34adc5Sramat /* 6686*3c34adc5Sramat * Enqueue the vhcache phci (cphci) at the tail of the list 6687*3c34adc5Sramat */ 6688*3c34adc5Sramat static void 6689*3c34adc5Sramat enqueue_vhcache_phci(mdi_vhci_cache_t *vhcache, mdi_vhcache_phci_t *cphci) 6690*3c34adc5Sramat { 6691*3c34adc5Sramat cphci->cphci_next = NULL; 6692*3c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) 6693*3c34adc5Sramat vhcache->vhcache_phci_head = cphci; 6694*3c34adc5Sramat else 6695*3c34adc5Sramat vhcache->vhcache_phci_tail->cphci_next = cphci; 6696*3c34adc5Sramat vhcache->vhcache_phci_tail = cphci; 6697*3c34adc5Sramat } 6698*3c34adc5Sramat 6699*3c34adc5Sramat /* 6700*3c34adc5Sramat * Enqueue the vhcache pathinfo (cpi) at the tail of the list 6701*3c34adc5Sramat */ 6702*3c34adc5Sramat static void 6703*3c34adc5Sramat enqueue_tail_vhcache_pathinfo(mdi_vhcache_client_t *cct, 6704*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi) 6705*3c34adc5Sramat { 6706*3c34adc5Sramat cpi->cpi_next = NULL; 6707*3c34adc5Sramat if (cct->cct_cpi_head == NULL) 6708*3c34adc5Sramat cct->cct_cpi_head = cpi; 6709*3c34adc5Sramat else 6710*3c34adc5Sramat cct->cct_cpi_tail->cpi_next = cpi; 6711*3c34adc5Sramat cct->cct_cpi_tail = cpi; 6712*3c34adc5Sramat } 6713*3c34adc5Sramat 6714*3c34adc5Sramat /* 6715*3c34adc5Sramat * Enqueue the vhcache pathinfo (cpi) at the correct location in the 6716*3c34adc5Sramat * ordered list. All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST 6717*3c34adc5Sramat * flag set come at the beginning of the list. All cpis which have this 6718*3c34adc5Sramat * flag set come at the end of the list. 6719*3c34adc5Sramat */ 6720*3c34adc5Sramat static void 6721*3c34adc5Sramat enqueue_vhcache_pathinfo(mdi_vhcache_client_t *cct, 6722*3c34adc5Sramat mdi_vhcache_pathinfo_t *newcpi) 6723*3c34adc5Sramat { 6724*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *prev_cpi; 6725*3c34adc5Sramat 6726*3c34adc5Sramat if (cct->cct_cpi_head == NULL || 6727*3c34adc5Sramat (newcpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST)) 6728*3c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, newcpi); 6729*3c34adc5Sramat else { 6730*3c34adc5Sramat for (cpi = cct->cct_cpi_head, prev_cpi = NULL; cpi != NULL && 6731*3c34adc5Sramat !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST); 6732*3c34adc5Sramat prev_cpi = cpi, cpi = cpi->cpi_next) 6733*3c34adc5Sramat ; 6734*3c34adc5Sramat 6735*3c34adc5Sramat if (prev_cpi == NULL) 6736*3c34adc5Sramat cct->cct_cpi_head = newcpi; 6737*3c34adc5Sramat else 6738*3c34adc5Sramat prev_cpi->cpi_next = newcpi; 6739*3c34adc5Sramat 6740*3c34adc5Sramat newcpi->cpi_next = cpi; 6741*3c34adc5Sramat 6742*3c34adc5Sramat if (cpi == NULL) 6743*3c34adc5Sramat cct->cct_cpi_tail = newcpi; 6744*3c34adc5Sramat } 6745*3c34adc5Sramat } 6746*3c34adc5Sramat 6747*3c34adc5Sramat /* 6748*3c34adc5Sramat * Enqueue the vhcache client (cct) at the tail of the list 6749*3c34adc5Sramat */ 6750*3c34adc5Sramat static void 6751*3c34adc5Sramat enqueue_vhcache_client(mdi_vhci_cache_t *vhcache, 6752*3c34adc5Sramat mdi_vhcache_client_t *cct) 6753*3c34adc5Sramat { 6754*3c34adc5Sramat cct->cct_next = NULL; 6755*3c34adc5Sramat if (vhcache->vhcache_client_head == NULL) 6756*3c34adc5Sramat vhcache->vhcache_client_head = cct; 6757*3c34adc5Sramat else 6758*3c34adc5Sramat vhcache->vhcache_client_tail->cct_next = cct; 6759*3c34adc5Sramat vhcache->vhcache_client_tail = cct; 6760*3c34adc5Sramat } 6761*3c34adc5Sramat 6762*3c34adc5Sramat static void 6763*3c34adc5Sramat free_string_array(char **str, int nelem) 6764*3c34adc5Sramat { 6765*3c34adc5Sramat int i; 6766*3c34adc5Sramat 6767*3c34adc5Sramat if (str) { 6768*3c34adc5Sramat for (i = 0; i < nelem; i++) { 6769*3c34adc5Sramat if (str[i]) 6770*3c34adc5Sramat kmem_free(str[i], strlen(str[i]) + 1); 6771*3c34adc5Sramat } 6772*3c34adc5Sramat kmem_free(str, sizeof (char *) * nelem); 6773*3c34adc5Sramat } 6774*3c34adc5Sramat } 6775*3c34adc5Sramat 6776*3c34adc5Sramat static void 6777*3c34adc5Sramat free_vhcache_phci(mdi_vhcache_phci_t *cphci) 6778*3c34adc5Sramat { 6779*3c34adc5Sramat kmem_free(cphci->cphci_path, strlen(cphci->cphci_path) + 1); 6780*3c34adc5Sramat kmem_free(cphci, sizeof (*cphci)); 6781*3c34adc5Sramat } 6782*3c34adc5Sramat 6783*3c34adc5Sramat static void 6784*3c34adc5Sramat free_vhcache_pathinfo(mdi_vhcache_pathinfo_t *cpi) 6785*3c34adc5Sramat { 6786*3c34adc5Sramat kmem_free(cpi->cpi_addr, strlen(cpi->cpi_addr) + 1); 6787*3c34adc5Sramat kmem_free(cpi, sizeof (*cpi)); 6788*3c34adc5Sramat } 6789*3c34adc5Sramat 6790*3c34adc5Sramat static void 6791*3c34adc5Sramat free_vhcache_client(mdi_vhcache_client_t *cct) 6792*3c34adc5Sramat { 6793*3c34adc5Sramat kmem_free(cct->cct_name_addr, strlen(cct->cct_name_addr) + 1); 6794*3c34adc5Sramat kmem_free(cct, sizeof (*cct)); 6795*3c34adc5Sramat } 6796*3c34adc5Sramat 6797*3c34adc5Sramat static char * 6798*3c34adc5Sramat vhcache_mknameaddr(char *ct_name, char *ct_addr, int *ret_len) 6799*3c34adc5Sramat { 6800*3c34adc5Sramat char *name_addr; 6801*3c34adc5Sramat int len; 6802*3c34adc5Sramat 6803*3c34adc5Sramat len = strlen(ct_name) + strlen(ct_addr) + 2; 6804*3c34adc5Sramat name_addr = kmem_alloc(len, KM_SLEEP); 6805*3c34adc5Sramat (void) snprintf(name_addr, len, "%s@%s", ct_name, ct_addr); 6806*3c34adc5Sramat 6807*3c34adc5Sramat if (ret_len) 6808*3c34adc5Sramat *ret_len = len; 6809*3c34adc5Sramat return (name_addr); 6810*3c34adc5Sramat } 6811*3c34adc5Sramat 6812*3c34adc5Sramat /* 6813*3c34adc5Sramat * Copy the contents of paddrnvl to vhci cache. 6814*3c34adc5Sramat * paddrnvl nvlist contains path information for a vhci client. 6815*3c34adc5Sramat * See the comment in mainnvl_to_vhcache() for the format of this nvlist. 6816*3c34adc5Sramat */ 6817*3c34adc5Sramat static void 6818*3c34adc5Sramat paddrnvl_to_vhcache(nvlist_t *nvl, mdi_vhcache_phci_t *cphci_list[], 6819*3c34adc5Sramat mdi_vhcache_client_t *cct) 6820*3c34adc5Sramat { 6821*3c34adc5Sramat nvpair_t *nvp = NULL; 6822*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 6823*3c34adc5Sramat uint_t nelem; 6824*3c34adc5Sramat uint32_t *val; 6825*3c34adc5Sramat 6826*3c34adc5Sramat while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 6827*3c34adc5Sramat ASSERT(nvpair_type(nvp) == DATA_TYPE_UINT32_ARRAY); 6828*3c34adc5Sramat cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP); 6829*3c34adc5Sramat cpi->cpi_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP); 6830*3c34adc5Sramat (void) nvpair_value_uint32_array(nvp, &val, &nelem); 6831*3c34adc5Sramat ASSERT(nelem == 2); 6832*3c34adc5Sramat cpi->cpi_cphci = cphci_list[val[0]]; 6833*3c34adc5Sramat cpi->cpi_flags = val[1]; 6834*3c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, cpi); 6835*3c34adc5Sramat } 6836*3c34adc5Sramat } 6837*3c34adc5Sramat 6838*3c34adc5Sramat /* 6839*3c34adc5Sramat * Copy the contents of caddrmapnvl to vhci cache. 6840*3c34adc5Sramat * caddrmapnvl nvlist contains vhci client address to phci client address 6841*3c34adc5Sramat * mappings. See the comment in mainnvl_to_vhcache() for the format of 6842*3c34adc5Sramat * this nvlist. 6843*3c34adc5Sramat */ 6844*3c34adc5Sramat static void 6845*3c34adc5Sramat caddrmapnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl, 6846*3c34adc5Sramat mdi_vhcache_phci_t *cphci_list[]) 6847*3c34adc5Sramat { 6848*3c34adc5Sramat nvpair_t *nvp = NULL; 6849*3c34adc5Sramat nvlist_t *paddrnvl; 6850*3c34adc5Sramat mdi_vhcache_client_t *cct; 6851*3c34adc5Sramat 6852*3c34adc5Sramat while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 6853*3c34adc5Sramat ASSERT(nvpair_type(nvp) == DATA_TYPE_NVLIST); 6854*3c34adc5Sramat cct = kmem_zalloc(sizeof (*cct), KM_SLEEP); 6855*3c34adc5Sramat cct->cct_name_addr = i_ddi_strdup(nvpair_name(nvp), KM_SLEEP); 6856*3c34adc5Sramat (void) nvpair_value_nvlist(nvp, &paddrnvl); 6857*3c34adc5Sramat paddrnvl_to_vhcache(paddrnvl, cphci_list, cct); 6858*3c34adc5Sramat /* the client must contain at least one path */ 6859*3c34adc5Sramat ASSERT(cct->cct_cpi_head != NULL); 6860*3c34adc5Sramat 6861*3c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 6862*3c34adc5Sramat (void) mod_hash_insert(vhcache->vhcache_client_hash, 6863*3c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct); 6864*3c34adc5Sramat } 6865*3c34adc5Sramat } 6866*3c34adc5Sramat 6867*3c34adc5Sramat /* 6868*3c34adc5Sramat * Copy the contents of the main nvlist to vhci cache. 6869*3c34adc5Sramat * 6870*3c34adc5Sramat * VHCI busconfig cached data is stored in the form of a nvlist on the disk. 6871*3c34adc5Sramat * The nvlist contains the mappings between the vhci client addresses and 6872*3c34adc5Sramat * their corresponding phci client addresses. 6873*3c34adc5Sramat * 6874*3c34adc5Sramat * The structure of the nvlist is as follows: 6875*3c34adc5Sramat * 6876*3c34adc5Sramat * Main nvlist: 6877*3c34adc5Sramat * NAME TYPE DATA 6878*3c34adc5Sramat * version int32 version number 6879*3c34adc5Sramat * phcis string array array of phci paths 6880*3c34adc5Sramat * clientaddrmap nvlist_t c2paddrs_nvl (see below) 6881*3c34adc5Sramat * 6882*3c34adc5Sramat * structure of c2paddrs_nvl: 6883*3c34adc5Sramat * NAME TYPE DATA 6884*3c34adc5Sramat * caddr1 nvlist_t paddrs_nvl1 6885*3c34adc5Sramat * caddr2 nvlist_t paddrs_nvl2 6886*3c34adc5Sramat * ... 6887*3c34adc5Sramat * where caddr1, caddr2, ... are vhci client name and addresses in the 6888*3c34adc5Sramat * form of "<clientname>@<clientaddress>". 6889*3c34adc5Sramat * (for example: "ssd@2000002037cd9f72"); 6890*3c34adc5Sramat * paddrs_nvl1, paddrs_nvl2, .. are nvlists that contain path information. 6891*3c34adc5Sramat * 6892*3c34adc5Sramat * structure of paddrs_nvl: 6893*3c34adc5Sramat * NAME TYPE DATA 6894*3c34adc5Sramat * pi_addr1 uint32_array (phci-id, cpi_flags) 6895*3c34adc5Sramat * pi_addr2 uint32_array (phci-id, cpi_flags) 6896*3c34adc5Sramat * ... 6897*3c34adc5Sramat * where pi_addr1, pi_addr2, ... are bus specific addresses of pathinfo nodes 6898*3c34adc5Sramat * (so called pi_addrs, for example: "w2100002037cd9f72,0"); 6899*3c34adc5Sramat * phci-ids are integers that identify PHCIs to which the 6900*3c34adc5Sramat * the bus specific address belongs to. These integers are used as an index 6901*3c34adc5Sramat * into to the phcis string array in the main nvlist to get the PHCI path. 6902*3c34adc5Sramat */ 6903*3c34adc5Sramat static int 6904*3c34adc5Sramat mainnvl_to_vhcache(mdi_vhci_cache_t *vhcache, nvlist_t *nvl) 6905*3c34adc5Sramat { 6906*3c34adc5Sramat char **phcis, **phci_namep; 6907*3c34adc5Sramat uint_t nphcis; 6908*3c34adc5Sramat mdi_vhcache_phci_t *cphci, **cphci_list; 6909*3c34adc5Sramat nvlist_t *caddrmapnvl; 6910*3c34adc5Sramat int32_t ver; 6911*3c34adc5Sramat int i; 6912*3c34adc5Sramat size_t cphci_list_size; 6913*3c34adc5Sramat 6914*3c34adc5Sramat ASSERT(RW_WRITE_HELD(&vhcache->vhcache_lock)); 6915*3c34adc5Sramat 6916*3c34adc5Sramat if (nvlist_lookup_int32(nvl, MDI_NVPNAME_VERSION, &ver) != 0 || 6917*3c34adc5Sramat ver != MDI_VHCI_CACHE_VERSION) 6918*3c34adc5Sramat return (MDI_FAILURE); 6919*3c34adc5Sramat 6920*3c34adc5Sramat if (nvlist_lookup_string_array(nvl, MDI_NVPNAME_PHCIS, &phcis, 6921*3c34adc5Sramat &nphcis) != 0) 6922*3c34adc5Sramat return (MDI_SUCCESS); 6923*3c34adc5Sramat 6924*3c34adc5Sramat ASSERT(nphcis > 0); 6925*3c34adc5Sramat 6926*3c34adc5Sramat cphci_list_size = sizeof (mdi_vhcache_phci_t *) * nphcis; 6927*3c34adc5Sramat cphci_list = kmem_alloc(cphci_list_size, KM_SLEEP); 6928*3c34adc5Sramat for (i = 0, phci_namep = phcis; i < nphcis; i++, phci_namep++) { 6929*3c34adc5Sramat cphci = kmem_zalloc(sizeof (mdi_vhcache_phci_t), KM_SLEEP); 6930*3c34adc5Sramat cphci->cphci_path = i_ddi_strdup(*phci_namep, KM_SLEEP); 6931*3c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 6932*3c34adc5Sramat cphci_list[i] = cphci; 6933*3c34adc5Sramat } 6934*3c34adc5Sramat 6935*3c34adc5Sramat ASSERT(vhcache->vhcache_phci_head != NULL); 6936*3c34adc5Sramat 6937*3c34adc5Sramat if (nvlist_lookup_nvlist(nvl, MDI_NVPNAME_CTADDRMAP, &caddrmapnvl) == 0) 6938*3c34adc5Sramat caddrmapnvl_to_vhcache(vhcache, caddrmapnvl, cphci_list); 6939*3c34adc5Sramat 6940*3c34adc5Sramat kmem_free(cphci_list, cphci_list_size); 6941*3c34adc5Sramat return (MDI_SUCCESS); 6942*3c34adc5Sramat } 6943*3c34adc5Sramat 6944*3c34adc5Sramat /* 6945*3c34adc5Sramat * Build paddrnvl for the specified client using the information in the 6946*3c34adc5Sramat * vhci cache and add it to the caddrmapnnvl. 6947*3c34adc5Sramat * Returns 0 on success, errno on failure. 6948*3c34adc5Sramat */ 6949*3c34adc5Sramat static int 6950*3c34adc5Sramat vhcache_to_paddrnvl(mdi_vhci_cache_t *vhcache, mdi_vhcache_client_t *cct, 6951*3c34adc5Sramat nvlist_t *caddrmapnvl) 6952*3c34adc5Sramat { 6953*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 6954*3c34adc5Sramat nvlist_t *nvl; 6955*3c34adc5Sramat int err; 6956*3c34adc5Sramat uint32_t val[2]; 6957*3c34adc5Sramat 6958*3c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 6959*3c34adc5Sramat 6960*3c34adc5Sramat if ((err = nvlist_alloc(&nvl, 0, KM_SLEEP)) != 0) 6961*3c34adc5Sramat return (err); 6962*3c34adc5Sramat 6963*3c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 6964*3c34adc5Sramat val[0] = cpi->cpi_cphci->cphci_id; 6965*3c34adc5Sramat val[1] = cpi->cpi_flags; 6966*3c34adc5Sramat if ((err = nvlist_add_uint32_array(nvl, cpi->cpi_addr, val, 2)) 6967*3c34adc5Sramat != 0) 6968*3c34adc5Sramat goto out; 6969*3c34adc5Sramat } 6970*3c34adc5Sramat 6971*3c34adc5Sramat err = nvlist_add_nvlist(caddrmapnvl, cct->cct_name_addr, nvl); 6972*3c34adc5Sramat out: 6973*3c34adc5Sramat nvlist_free(nvl); 6974*3c34adc5Sramat return (err); 6975*3c34adc5Sramat } 6976*3c34adc5Sramat 6977*3c34adc5Sramat /* 6978*3c34adc5Sramat * Build caddrmapnvl using the information in the vhci cache 6979*3c34adc5Sramat * and add it to the mainnvl. 6980*3c34adc5Sramat * Returns 0 on success, errno on failure. 6981*3c34adc5Sramat */ 6982*3c34adc5Sramat static int 6983*3c34adc5Sramat vhcache_to_caddrmapnvl(mdi_vhci_cache_t *vhcache, nvlist_t *mainnvl) 6984*3c34adc5Sramat { 6985*3c34adc5Sramat mdi_vhcache_client_t *cct; 6986*3c34adc5Sramat nvlist_t *nvl; 6987*3c34adc5Sramat int err; 6988*3c34adc5Sramat 6989*3c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 6990*3c34adc5Sramat 6991*3c34adc5Sramat if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0) 6992*3c34adc5Sramat return (err); 6993*3c34adc5Sramat 6994*3c34adc5Sramat for (cct = vhcache->vhcache_client_head; cct != NULL; 6995*3c34adc5Sramat cct = cct->cct_next) { 6996*3c34adc5Sramat if ((err = vhcache_to_paddrnvl(vhcache, cct, nvl)) != 0) 6997*3c34adc5Sramat goto out; 6998*3c34adc5Sramat } 6999*3c34adc5Sramat 7000*3c34adc5Sramat err = nvlist_add_nvlist(mainnvl, MDI_NVPNAME_CTADDRMAP, nvl); 7001*3c34adc5Sramat out: 7002*3c34adc5Sramat nvlist_free(nvl); 7003*3c34adc5Sramat return (err); 7004*3c34adc5Sramat } 7005*3c34adc5Sramat 7006*3c34adc5Sramat /* 7007*3c34adc5Sramat * Build nvlist using the information in the vhci cache. 7008*3c34adc5Sramat * See the comment in mainnvl_to_vhcache() for the format of the nvlist. 7009*3c34adc5Sramat * Returns nvl on success, NULL on failure. 7010*3c34adc5Sramat */ 7011*3c34adc5Sramat static nvlist_t * 7012*3c34adc5Sramat vhcache_to_mainnvl(mdi_vhci_cache_t *vhcache) 7013*3c34adc5Sramat { 7014*3c34adc5Sramat mdi_vhcache_phci_t *cphci; 7015*3c34adc5Sramat uint_t phci_count; 7016*3c34adc5Sramat char **phcis; 7017*3c34adc5Sramat nvlist_t *nvl; 7018*3c34adc5Sramat int err, i; 7019*3c34adc5Sramat 7020*3c34adc5Sramat if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) != 0) { 7021*3c34adc5Sramat nvl = NULL; 7022*3c34adc5Sramat goto out; 7023*3c34adc5Sramat } 7024*3c34adc5Sramat 7025*3c34adc5Sramat if ((err = nvlist_add_int32(nvl, MDI_NVPNAME_VERSION, 7026*3c34adc5Sramat MDI_VHCI_CACHE_VERSION)) != 0) 7027*3c34adc5Sramat goto out; 7028*3c34adc5Sramat 7029*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 7030*3c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) { 7031*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7032*3c34adc5Sramat return (nvl); 7033*3c34adc5Sramat } 7034*3c34adc5Sramat 7035*3c34adc5Sramat phci_count = 0; 7036*3c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 7037*3c34adc5Sramat cphci = cphci->cphci_next) 7038*3c34adc5Sramat cphci->cphci_id = phci_count++; 7039*3c34adc5Sramat 7040*3c34adc5Sramat /* build phci pathname list */ 7041*3c34adc5Sramat phcis = kmem_alloc(sizeof (char *) * phci_count, KM_SLEEP); 7042*3c34adc5Sramat for (cphci = vhcache->vhcache_phci_head, i = 0; cphci != NULL; 7043*3c34adc5Sramat cphci = cphci->cphci_next, i++) 7044*3c34adc5Sramat phcis[i] = i_ddi_strdup(cphci->cphci_path, KM_SLEEP); 7045*3c34adc5Sramat 7046*3c34adc5Sramat err = nvlist_add_string_array(nvl, MDI_NVPNAME_PHCIS, phcis, 7047*3c34adc5Sramat phci_count); 7048*3c34adc5Sramat free_string_array(phcis, phci_count); 7049*3c34adc5Sramat 7050*3c34adc5Sramat if (err == 0 && 7051*3c34adc5Sramat (err = vhcache_to_caddrmapnvl(vhcache, nvl)) == 0) { 7052*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7053*3c34adc5Sramat return (nvl); 7054*3c34adc5Sramat } 7055*3c34adc5Sramat 7056*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7057*3c34adc5Sramat out: 7058*3c34adc5Sramat if (nvl) 7059*3c34adc5Sramat nvlist_free(nvl); 7060*3c34adc5Sramat return (NULL); 7061*3c34adc5Sramat } 7062*3c34adc5Sramat 7063*3c34adc5Sramat /* 7064*3c34adc5Sramat * Lookup vhcache phci structure for the specified phci path. 7065*3c34adc5Sramat */ 7066*3c34adc5Sramat static mdi_vhcache_phci_t * 7067*3c34adc5Sramat lookup_vhcache_phci_by_name(mdi_vhci_cache_t *vhcache, char *phci_path) 7068*3c34adc5Sramat { 7069*3c34adc5Sramat mdi_vhcache_phci_t *cphci; 7070*3c34adc5Sramat 7071*3c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 7072*3c34adc5Sramat 7073*3c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 7074*3c34adc5Sramat cphci = cphci->cphci_next) { 7075*3c34adc5Sramat if (strcmp(cphci->cphci_path, phci_path) == 0) 7076*3c34adc5Sramat return (cphci); 7077*3c34adc5Sramat } 7078*3c34adc5Sramat 7079*3c34adc5Sramat return (NULL); 7080*3c34adc5Sramat } 7081*3c34adc5Sramat 7082*3c34adc5Sramat /* 7083*3c34adc5Sramat * Lookup vhcache phci structure for the specified phci. 7084*3c34adc5Sramat */ 7085*3c34adc5Sramat static mdi_vhcache_phci_t * 7086*3c34adc5Sramat lookup_vhcache_phci_by_addr(mdi_vhci_cache_t *vhcache, mdi_phci_t *ph) 7087*3c34adc5Sramat { 7088*3c34adc5Sramat mdi_vhcache_phci_t *cphci; 7089*3c34adc5Sramat 7090*3c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 7091*3c34adc5Sramat 7092*3c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 7093*3c34adc5Sramat cphci = cphci->cphci_next) { 7094*3c34adc5Sramat if (cphci->cphci_phci == ph) 7095*3c34adc5Sramat return (cphci); 7096*3c34adc5Sramat } 7097*3c34adc5Sramat 7098*3c34adc5Sramat return (NULL); 7099*3c34adc5Sramat } 7100*3c34adc5Sramat 7101*3c34adc5Sramat /* 7102*3c34adc5Sramat * Add the specified phci to the vhci cache if not already present. 7103*3c34adc5Sramat */ 7104*3c34adc5Sramat static void 7105*3c34adc5Sramat vhcache_phci_add(mdi_vhci_config_t *vhc, mdi_phci_t *ph) 7106*3c34adc5Sramat { 7107*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 7108*3c34adc5Sramat mdi_vhcache_phci_t *cphci; 7109*3c34adc5Sramat char *pathname; 7110*3c34adc5Sramat int cache_updated; 7111*3c34adc5Sramat 7112*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 7113*3c34adc5Sramat 7114*3c34adc5Sramat pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 7115*3c34adc5Sramat (void) ddi_pathname(ph->ph_dip, pathname); 7116*3c34adc5Sramat if ((cphci = lookup_vhcache_phci_by_name(vhcache, pathname)) 7117*3c34adc5Sramat != NULL) { 7118*3c34adc5Sramat cphci->cphci_phci = ph; 7119*3c34adc5Sramat cache_updated = 0; 7120*3c34adc5Sramat } else { 7121*3c34adc5Sramat cphci = kmem_zalloc(sizeof (*cphci), KM_SLEEP); 7122*3c34adc5Sramat cphci->cphci_path = i_ddi_strdup(pathname, KM_SLEEP); 7123*3c34adc5Sramat cphci->cphci_phci = ph; 7124*3c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 7125*3c34adc5Sramat cache_updated = 1; 7126*3c34adc5Sramat } 7127*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7128*3c34adc5Sramat 7129*3c34adc5Sramat kmem_free(pathname, MAXPATHLEN); 7130*3c34adc5Sramat if (cache_updated) 7131*3c34adc5Sramat vhcache_dirty(vhc); 7132*3c34adc5Sramat } 7133*3c34adc5Sramat 7134*3c34adc5Sramat /* 7135*3c34adc5Sramat * Remove the reference to the specified phci from the vhci cache. 7136*3c34adc5Sramat */ 7137*3c34adc5Sramat static void 7138*3c34adc5Sramat vhcache_phci_remove(mdi_vhci_config_t *vhc, mdi_phci_t *ph) 7139*3c34adc5Sramat { 7140*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 7141*3c34adc5Sramat mdi_vhcache_phci_t *cphci; 7142*3c34adc5Sramat 7143*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 7144*3c34adc5Sramat if ((cphci = lookup_vhcache_phci_by_addr(vhcache, ph)) != NULL) { 7145*3c34adc5Sramat /* do not remove the actual mdi_vhcache_phci structure */ 7146*3c34adc5Sramat cphci->cphci_phci = NULL; 7147*3c34adc5Sramat } 7148*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7149*3c34adc5Sramat } 7150*3c34adc5Sramat 7151*3c34adc5Sramat static void 7152*3c34adc5Sramat init_vhcache_lookup_token(mdi_vhcache_lookup_token_t *dst, 7153*3c34adc5Sramat mdi_vhcache_lookup_token_t *src) 7154*3c34adc5Sramat { 7155*3c34adc5Sramat if (src == NULL) { 7156*3c34adc5Sramat dst->lt_cct = NULL; 7157*3c34adc5Sramat dst->lt_cct_lookup_time = 0; 7158*3c34adc5Sramat } else { 7159*3c34adc5Sramat dst->lt_cct = src->lt_cct; 7160*3c34adc5Sramat dst->lt_cct_lookup_time = src->lt_cct_lookup_time; 7161*3c34adc5Sramat } 7162*3c34adc5Sramat } 7163*3c34adc5Sramat 7164*3c34adc5Sramat /* 7165*3c34adc5Sramat * Look up vhcache client for the specified client. 7166*3c34adc5Sramat */ 7167*3c34adc5Sramat static mdi_vhcache_client_t * 7168*3c34adc5Sramat lookup_vhcache_client(mdi_vhci_cache_t *vhcache, char *ct_name, char *ct_addr, 7169*3c34adc5Sramat mdi_vhcache_lookup_token_t *token) 7170*3c34adc5Sramat { 7171*3c34adc5Sramat mod_hash_val_t hv; 7172*3c34adc5Sramat char *name_addr; 7173*3c34adc5Sramat int len; 7174*3c34adc5Sramat 7175*3c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 7176*3c34adc5Sramat 7177*3c34adc5Sramat /* 7178*3c34adc5Sramat * If no vhcache clean occurred since the last lookup, we can 7179*3c34adc5Sramat * simply return the cct from the last lookup operation. 7180*3c34adc5Sramat * It works because ccts are never freed except during the vhcache 7181*3c34adc5Sramat * cleanup operation. 7182*3c34adc5Sramat */ 7183*3c34adc5Sramat if (token != NULL && 7184*3c34adc5Sramat vhcache->vhcache_clean_time < token->lt_cct_lookup_time) 7185*3c34adc5Sramat return (token->lt_cct); 7186*3c34adc5Sramat 7187*3c34adc5Sramat name_addr = vhcache_mknameaddr(ct_name, ct_addr, &len); 7188*3c34adc5Sramat if (mod_hash_find(vhcache->vhcache_client_hash, 7189*3c34adc5Sramat (mod_hash_key_t)name_addr, &hv) == 0) { 7190*3c34adc5Sramat if (token) { 7191*3c34adc5Sramat token->lt_cct = (mdi_vhcache_client_t *)hv; 7192*3c34adc5Sramat token->lt_cct_lookup_time = lbolt64; 7193*3c34adc5Sramat } 7194*3c34adc5Sramat } else { 7195*3c34adc5Sramat if (token) { 7196*3c34adc5Sramat token->lt_cct = NULL; 7197*3c34adc5Sramat token->lt_cct_lookup_time = 0; 7198*3c34adc5Sramat } 7199*3c34adc5Sramat hv = NULL; 7200*3c34adc5Sramat } 7201*3c34adc5Sramat kmem_free(name_addr, len); 7202*3c34adc5Sramat return ((mdi_vhcache_client_t *)hv); 7203*3c34adc5Sramat } 7204*3c34adc5Sramat 7205*3c34adc5Sramat /* 7206*3c34adc5Sramat * Add the specified path to the vhci cache if not already present. 7207*3c34adc5Sramat * Also add the vhcache client for the client corresponding to this path 7208*3c34adc5Sramat * if it doesn't already exist. 7209*3c34adc5Sramat */ 7210*3c34adc5Sramat static void 7211*3c34adc5Sramat vhcache_pi_add(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip) 7212*3c34adc5Sramat { 7213*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 7214*3c34adc5Sramat mdi_vhcache_client_t *cct; 7215*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 7216*3c34adc5Sramat mdi_phci_t *ph = pip->pi_phci; 7217*3c34adc5Sramat mdi_client_t *ct = pip->pi_client; 7218*3c34adc5Sramat int cache_updated = 0; 7219*3c34adc5Sramat 7220*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 7221*3c34adc5Sramat 7222*3c34adc5Sramat /* if vhcache client for this pip doesn't already exist, add it */ 7223*3c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid, 7224*3c34adc5Sramat NULL)) == NULL) { 7225*3c34adc5Sramat cct = kmem_zalloc(sizeof (*cct), KM_SLEEP); 7226*3c34adc5Sramat cct->cct_name_addr = vhcache_mknameaddr(ct->ct_drvname, 7227*3c34adc5Sramat ct->ct_guid, NULL); 7228*3c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 7229*3c34adc5Sramat (void) mod_hash_insert(vhcache->vhcache_client_hash, 7230*3c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr, (mod_hash_val_t)cct); 7231*3c34adc5Sramat cache_updated = 1; 7232*3c34adc5Sramat } 7233*3c34adc5Sramat 7234*3c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 7235*3c34adc5Sramat if (cpi->cpi_cphci->cphci_phci == ph && 7236*3c34adc5Sramat strcmp(cpi->cpi_addr, pip->pi_addr) == 0) { 7237*3c34adc5Sramat cpi->cpi_pip = pip; 7238*3c34adc5Sramat if (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST) { 7239*3c34adc5Sramat cpi->cpi_flags &= 7240*3c34adc5Sramat ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 7241*3c34adc5Sramat sort_vhcache_paths(cct); 7242*3c34adc5Sramat cache_updated = 1; 7243*3c34adc5Sramat } 7244*3c34adc5Sramat break; 7245*3c34adc5Sramat } 7246*3c34adc5Sramat } 7247*3c34adc5Sramat 7248*3c34adc5Sramat if (cpi == NULL) { 7249*3c34adc5Sramat cpi = kmem_zalloc(sizeof (*cpi), KM_SLEEP); 7250*3c34adc5Sramat cpi->cpi_addr = i_ddi_strdup(pip->pi_addr, KM_SLEEP); 7251*3c34adc5Sramat cpi->cpi_cphci = lookup_vhcache_phci_by_addr(vhcache, ph); 7252*3c34adc5Sramat ASSERT(cpi->cpi_cphci != NULL); 7253*3c34adc5Sramat cpi->cpi_pip = pip; 7254*3c34adc5Sramat enqueue_vhcache_pathinfo(cct, cpi); 7255*3c34adc5Sramat cache_updated = 1; 7256*3c34adc5Sramat } 7257*3c34adc5Sramat 7258*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7259*3c34adc5Sramat 7260*3c34adc5Sramat if (cache_updated) 7261*3c34adc5Sramat vhcache_dirty(vhc); 7262*3c34adc5Sramat } 7263*3c34adc5Sramat 7264*3c34adc5Sramat /* 7265*3c34adc5Sramat * Remove the reference to the specified path from the vhci cache. 7266*3c34adc5Sramat */ 7267*3c34adc5Sramat static void 7268*3c34adc5Sramat vhcache_pi_remove(mdi_vhci_config_t *vhc, struct mdi_pathinfo *pip) 7269*3c34adc5Sramat { 7270*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 7271*3c34adc5Sramat mdi_client_t *ct = pip->pi_client; 7272*3c34adc5Sramat mdi_vhcache_client_t *cct; 7273*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 7274*3c34adc5Sramat 7275*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 7276*3c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct->ct_drvname, ct->ct_guid, 7277*3c34adc5Sramat NULL)) != NULL) { 7278*3c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; 7279*3c34adc5Sramat cpi = cpi->cpi_next) { 7280*3c34adc5Sramat if (cpi->cpi_pip == pip) { 7281*3c34adc5Sramat cpi->cpi_pip = NULL; 7282*3c34adc5Sramat break; 7283*3c34adc5Sramat } 7284*3c34adc5Sramat } 7285*3c34adc5Sramat } 7286*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7287*3c34adc5Sramat } 7288*3c34adc5Sramat 7289*3c34adc5Sramat /* 7290*3c34adc5Sramat * Flush the vhci cache to disk. 7291*3c34adc5Sramat * Returns MDI_SUCCESS on success, MDI_FAILURE on failure. 7292*3c34adc5Sramat */ 7293*3c34adc5Sramat static int 7294*3c34adc5Sramat flush_vhcache(mdi_vhci_config_t *vhc, int force_flag) 7295*3c34adc5Sramat { 7296*3c34adc5Sramat nvlist_t *nvl; 7297*3c34adc5Sramat int err; 7298*3c34adc5Sramat int rv; 7299*3c34adc5Sramat 7300*3c34adc5Sramat /* 7301*3c34adc5Sramat * It is possible that the system may shutdown before 7302*3c34adc5Sramat * i_ddi_io_initialized (during stmsboot for example). To allow for 7303*3c34adc5Sramat * flushing the cache in this case do not check for 7304*3c34adc5Sramat * i_ddi_io_initialized when force flag is set. 7305*3c34adc5Sramat */ 7306*3c34adc5Sramat if (force_flag == 0 && !i_ddi_io_initialized()) 7307*3c34adc5Sramat return (MDI_FAILURE); 7308*3c34adc5Sramat 7309*3c34adc5Sramat if ((nvl = vhcache_to_mainnvl(&vhc->vhc_vhcache)) != NULL) { 7310*3c34adc5Sramat err = fwrite_nvlist(vhc->vhc_vhcache_filename, nvl); 7311*3c34adc5Sramat nvlist_free(nvl); 7312*3c34adc5Sramat } else 7313*3c34adc5Sramat err = EFAULT; 7314*3c34adc5Sramat 7315*3c34adc5Sramat rv = MDI_SUCCESS; 7316*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 7317*3c34adc5Sramat if (err != 0) { 7318*3c34adc5Sramat if (err == EROFS) { 7319*3c34adc5Sramat vhc->vhc_flags |= MDI_VHC_READONLY_FS; 7320*3c34adc5Sramat vhc->vhc_flags &= ~(MDI_VHC_VHCACHE_FLUSH_ERROR | 7321*3c34adc5Sramat MDI_VHC_VHCACHE_DIRTY); 7322*3c34adc5Sramat } else { 7323*3c34adc5Sramat if (!(vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR)) { 7324*3c34adc5Sramat cmn_err(CE_CONT, "%s: update failed\n", 7325*3c34adc5Sramat vhc->vhc_vhcache_filename); 7326*3c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_ERROR; 7327*3c34adc5Sramat } 7328*3c34adc5Sramat rv = MDI_FAILURE; 7329*3c34adc5Sramat } 7330*3c34adc5Sramat } else if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_ERROR) { 7331*3c34adc5Sramat cmn_err(CE_CONT, 7332*3c34adc5Sramat "%s: update now ok\n", vhc->vhc_vhcache_filename); 7333*3c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_ERROR; 7334*3c34adc5Sramat } 7335*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 7336*3c34adc5Sramat 7337*3c34adc5Sramat return (rv); 7338*3c34adc5Sramat } 7339*3c34adc5Sramat 7340*3c34adc5Sramat /* 7341*3c34adc5Sramat * Call flush_vhcache() to flush the vhci cache at the scheduled time. 7342*3c34adc5Sramat * Exits itself if left idle for the idle timeout period. 7343*3c34adc5Sramat */ 7344*3c34adc5Sramat static void 7345*3c34adc5Sramat vhcache_flush_thread(void *arg) 7346*3c34adc5Sramat { 7347*3c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 7348*3c34adc5Sramat clock_t idle_time, quit_at_ticks; 7349*3c34adc5Sramat callb_cpr_t cprinfo; 7350*3c34adc5Sramat 7351*3c34adc5Sramat /* number of seconds to sleep idle before exiting */ 7352*3c34adc5Sramat idle_time = mdi_vhcache_flush_daemon_idle_time * TICKS_PER_SECOND; 7353*3c34adc5Sramat 7354*3c34adc5Sramat CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr, 7355*3c34adc5Sramat "mdi_vhcache_flush"); 7356*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 7357*3c34adc5Sramat for (; ; ) { 7358*3c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 7359*3c34adc5Sramat (vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY)) { 7360*3c34adc5Sramat if (ddi_get_lbolt() < vhc->vhc_flush_at_ticks) { 7361*3c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 7362*3c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, 7363*3c34adc5Sramat &vhc->vhc_lock, vhc->vhc_flush_at_ticks); 7364*3c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 7365*3c34adc5Sramat } else { 7366*3c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_DIRTY; 7367*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 7368*3c34adc5Sramat 7369*3c34adc5Sramat if (flush_vhcache(vhc, 0) != MDI_SUCCESS) 7370*3c34adc5Sramat vhcache_dirty(vhc); 7371*3c34adc5Sramat 7372*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 7373*3c34adc5Sramat } 7374*3c34adc5Sramat } 7375*3c34adc5Sramat 7376*3c34adc5Sramat quit_at_ticks = ddi_get_lbolt() + idle_time; 7377*3c34adc5Sramat 7378*3c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 7379*3c34adc5Sramat !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY) && 7380*3c34adc5Sramat ddi_get_lbolt() < quit_at_ticks) { 7381*3c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 7382*3c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock, 7383*3c34adc5Sramat quit_at_ticks); 7384*3c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 7385*3c34adc5Sramat } 7386*3c34adc5Sramat 7387*3c34adc5Sramat if ((vhc->vhc_flags & MDI_VHC_EXIT) || 7388*3c34adc5Sramat !(vhc->vhc_flags & MDI_VHC_VHCACHE_DIRTY)) 7389*3c34adc5Sramat goto out; 7390*3c34adc5Sramat } 7391*3c34adc5Sramat 7392*3c34adc5Sramat out: 7393*3c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_VHCACHE_FLUSH_THREAD; 7394*3c34adc5Sramat /* CALLB_CPR_EXIT releases the vhc->vhc_lock */ 7395*3c34adc5Sramat CALLB_CPR_EXIT(&cprinfo); 7396*3c34adc5Sramat } 7397*3c34adc5Sramat 7398*3c34adc5Sramat /* 7399*3c34adc5Sramat * Make vhci cache dirty and schedule flushing by vhcache flush thread. 7400*3c34adc5Sramat */ 7401*3c34adc5Sramat static void 7402*3c34adc5Sramat vhcache_dirty(mdi_vhci_config_t *vhc) 7403*3c34adc5Sramat { 7404*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 7405*3c34adc5Sramat int create_thread; 7406*3c34adc5Sramat 7407*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 7408*3c34adc5Sramat /* do not flush cache until the cache is fully built */ 7409*3c34adc5Sramat if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) { 7410*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7411*3c34adc5Sramat return; 7412*3c34adc5Sramat } 7413*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7414*3c34adc5Sramat 7415*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 7416*3c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_READONLY_FS) { 7417*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 7418*3c34adc5Sramat return; 7419*3c34adc5Sramat } 7420*3c34adc5Sramat 7421*3c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_DIRTY; 7422*3c34adc5Sramat vhc->vhc_flush_at_ticks = ddi_get_lbolt() + 7423*3c34adc5Sramat mdi_vhcache_flush_delay * TICKS_PER_SECOND; 7424*3c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_VHCACHE_FLUSH_THREAD) { 7425*3c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 7426*3c34adc5Sramat create_thread = 0; 7427*3c34adc5Sramat } else { 7428*3c34adc5Sramat vhc->vhc_flags |= MDI_VHC_VHCACHE_FLUSH_THREAD; 7429*3c34adc5Sramat create_thread = 1; 7430*3c34adc5Sramat } 7431*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 7432*3c34adc5Sramat 7433*3c34adc5Sramat if (create_thread) 7434*3c34adc5Sramat (void) thread_create(NULL, 0, vhcache_flush_thread, vhc, 7435*3c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 7436*3c34adc5Sramat } 7437*3c34adc5Sramat 7438*3c34adc5Sramat /* 7439*3c34adc5Sramat * phci bus config structure - one for for each phci bus config operation that 7440*3c34adc5Sramat * we initiate on behalf of a vhci. 7441*3c34adc5Sramat */ 7442*3c34adc5Sramat typedef struct mdi_phci_bus_config_s { 7443*3c34adc5Sramat char *phbc_phci_path; 7444*3c34adc5Sramat struct mdi_vhci_bus_config_s *phbc_vhbusconfig; /* vhci bus config */ 7445*3c34adc5Sramat struct mdi_phci_bus_config_s *phbc_next; 7446*3c34adc5Sramat } mdi_phci_bus_config_t; 7447*3c34adc5Sramat 7448*3c34adc5Sramat /* vhci bus config structure - one for each vhci bus config operation */ 7449*3c34adc5Sramat typedef struct mdi_vhci_bus_config_s { 7450*3c34adc5Sramat ddi_bus_config_op_t vhbc_op; /* bus config op */ 7451*3c34adc5Sramat major_t vhbc_op_major; /* bus config op major */ 7452*3c34adc5Sramat uint_t vhbc_op_flags; /* bus config op flags */ 7453*3c34adc5Sramat kmutex_t vhbc_lock; 7454*3c34adc5Sramat kcondvar_t vhbc_cv; 7455*3c34adc5Sramat int vhbc_thr_count; 7456*3c34adc5Sramat } mdi_vhci_bus_config_t; 7457*3c34adc5Sramat 7458*3c34adc5Sramat /* 7459*3c34adc5Sramat * bus config the specified phci 7460*3c34adc5Sramat */ 7461*3c34adc5Sramat static void 7462*3c34adc5Sramat bus_config_phci(void *arg) 7463*3c34adc5Sramat { 7464*3c34adc5Sramat mdi_phci_bus_config_t *phbc = (mdi_phci_bus_config_t *)arg; 7465*3c34adc5Sramat mdi_vhci_bus_config_t *vhbc = phbc->phbc_vhbusconfig; 7466*3c34adc5Sramat dev_info_t *ph_dip; 7467*3c34adc5Sramat 7468*3c34adc5Sramat /* 7469*3c34adc5Sramat * first configure all path components upto phci and then configure 7470*3c34adc5Sramat * the phci children. 7471*3c34adc5Sramat */ 7472*3c34adc5Sramat if ((ph_dip = e_ddi_hold_devi_by_path(phbc->phbc_phci_path, 0)) 7473*3c34adc5Sramat != NULL) { 7474*3c34adc5Sramat if (vhbc->vhbc_op == BUS_CONFIG_DRIVER || 7475*3c34adc5Sramat vhbc->vhbc_op == BUS_UNCONFIG_DRIVER) { 7476*3c34adc5Sramat (void) ndi_devi_config_driver(ph_dip, 7477*3c34adc5Sramat vhbc->vhbc_op_flags, 7478*3c34adc5Sramat vhbc->vhbc_op_major); 7479*3c34adc5Sramat } else 7480*3c34adc5Sramat (void) ndi_devi_config(ph_dip, 7481*3c34adc5Sramat vhbc->vhbc_op_flags); 7482*3c34adc5Sramat 7483*3c34adc5Sramat /* release the hold that e_ddi_hold_devi_by_path() placed */ 7484*3c34adc5Sramat ndi_rele_devi(ph_dip); 7485*3c34adc5Sramat } 7486*3c34adc5Sramat 7487*3c34adc5Sramat kmem_free(phbc->phbc_phci_path, strlen(phbc->phbc_phci_path) + 1); 7488*3c34adc5Sramat kmem_free(phbc, sizeof (*phbc)); 7489*3c34adc5Sramat 7490*3c34adc5Sramat mutex_enter(&vhbc->vhbc_lock); 7491*3c34adc5Sramat vhbc->vhbc_thr_count--; 7492*3c34adc5Sramat if (vhbc->vhbc_thr_count == 0) 7493*3c34adc5Sramat cv_broadcast(&vhbc->vhbc_cv); 7494*3c34adc5Sramat mutex_exit(&vhbc->vhbc_lock); 7495*3c34adc5Sramat } 7496*3c34adc5Sramat 7497*3c34adc5Sramat /* 7498*3c34adc5Sramat * Bus config all phcis associated with the vhci in parallel. 7499*3c34adc5Sramat * op must be BUS_CONFIG_DRIVER or BUS_CONFIG_ALL. 7500*3c34adc5Sramat */ 7501*3c34adc5Sramat static void 7502*3c34adc5Sramat bus_config_all_phcis(mdi_vhci_cache_t *vhcache, uint_t flags, 7503*3c34adc5Sramat ddi_bus_config_op_t op, major_t maj) 7504*3c34adc5Sramat { 7505*3c34adc5Sramat mdi_phci_bus_config_t *phbc_head = NULL, *phbc, *phbc_next; 7506*3c34adc5Sramat mdi_vhci_bus_config_t *vhbc; 7507*3c34adc5Sramat mdi_vhcache_phci_t *cphci; 7508*3c34adc5Sramat 7509*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 7510*3c34adc5Sramat if (vhcache->vhcache_phci_head == NULL) { 7511*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7512*3c34adc5Sramat return; 7513*3c34adc5Sramat } 7514*3c34adc5Sramat 7515*3c34adc5Sramat vhbc = kmem_zalloc(sizeof (*vhbc), KM_SLEEP); 7516*3c34adc5Sramat 7517*3c34adc5Sramat for (cphci = vhcache->vhcache_phci_head; cphci != NULL; 7518*3c34adc5Sramat cphci = cphci->cphci_next) { 7519*3c34adc5Sramat phbc = kmem_zalloc(sizeof (*phbc), KM_SLEEP); 7520*3c34adc5Sramat phbc->phbc_phci_path = i_ddi_strdup(cphci->cphci_path, 7521*3c34adc5Sramat KM_SLEEP); 7522*3c34adc5Sramat phbc->phbc_vhbusconfig = vhbc; 7523*3c34adc5Sramat phbc->phbc_next = phbc_head; 7524*3c34adc5Sramat phbc_head = phbc; 7525*3c34adc5Sramat vhbc->vhbc_thr_count++; 7526*3c34adc5Sramat } 7527*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7528*3c34adc5Sramat 7529*3c34adc5Sramat vhbc->vhbc_op = op; 7530*3c34adc5Sramat vhbc->vhbc_op_major = maj; 7531*3c34adc5Sramat vhbc->vhbc_op_flags = NDI_NO_EVENT | 7532*3c34adc5Sramat (flags & (NDI_CONFIG_REPROBE | NDI_DRV_CONF_REPROBE)); 7533*3c34adc5Sramat mutex_init(&vhbc->vhbc_lock, NULL, MUTEX_DEFAULT, NULL); 7534*3c34adc5Sramat cv_init(&vhbc->vhbc_cv, NULL, CV_DRIVER, NULL); 7535*3c34adc5Sramat 7536*3c34adc5Sramat /* now create threads to initiate bus config on all phcis in parallel */ 7537*3c34adc5Sramat for (phbc = phbc_head; phbc != NULL; phbc = phbc_next) { 7538*3c34adc5Sramat phbc_next = phbc->phbc_next; 7539*3c34adc5Sramat if (mdi_mtc_off) 7540*3c34adc5Sramat bus_config_phci((void *)phbc); 7541*3c34adc5Sramat else 7542*3c34adc5Sramat (void) thread_create(NULL, 0, bus_config_phci, phbc, 7543*3c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 7544*3c34adc5Sramat } 7545*3c34adc5Sramat 7546*3c34adc5Sramat mutex_enter(&vhbc->vhbc_lock); 7547*3c34adc5Sramat /* wait until all threads exit */ 7548*3c34adc5Sramat while (vhbc->vhbc_thr_count > 0) 7549*3c34adc5Sramat cv_wait(&vhbc->vhbc_cv, &vhbc->vhbc_lock); 7550*3c34adc5Sramat mutex_exit(&vhbc->vhbc_lock); 7551*3c34adc5Sramat 7552*3c34adc5Sramat mutex_destroy(&vhbc->vhbc_lock); 7553*3c34adc5Sramat cv_destroy(&vhbc->vhbc_cv); 7554*3c34adc5Sramat kmem_free(vhbc, sizeof (*vhbc)); 7555*3c34adc5Sramat } 7556*3c34adc5Sramat 7557*3c34adc5Sramat /* 7558*3c34adc5Sramat * Perform BUS_CONFIG_ONE on the specified child of the phci. 7559*3c34adc5Sramat * The path includes the child component in addition to the phci path. 7560*3c34adc5Sramat */ 7561*3c34adc5Sramat static int 7562*3c34adc5Sramat bus_config_one_phci_child(char *path) 7563*3c34adc5Sramat { 7564*3c34adc5Sramat dev_info_t *ph_dip, *child; 7565*3c34adc5Sramat char *devnm; 7566*3c34adc5Sramat int rv = MDI_FAILURE; 7567*3c34adc5Sramat 7568*3c34adc5Sramat /* extract the child component of the phci */ 7569*3c34adc5Sramat devnm = strrchr(path, '/'); 7570*3c34adc5Sramat *devnm++ = '\0'; 7571*3c34adc5Sramat 7572*3c34adc5Sramat /* 7573*3c34adc5Sramat * first configure all path components upto phci and then 7574*3c34adc5Sramat * configure the phci child. 7575*3c34adc5Sramat */ 7576*3c34adc5Sramat if ((ph_dip = e_ddi_hold_devi_by_path(path, 0)) != NULL) { 7577*3c34adc5Sramat if (ndi_devi_config_one(ph_dip, devnm, &child, NDI_NO_EVENT) == 7578*3c34adc5Sramat NDI_SUCCESS) { 7579*3c34adc5Sramat /* 7580*3c34adc5Sramat * release the hold that ndi_devi_config_one() placed 7581*3c34adc5Sramat */ 7582*3c34adc5Sramat ndi_rele_devi(child); 7583*3c34adc5Sramat rv = MDI_SUCCESS; 7584*3c34adc5Sramat } 7585*3c34adc5Sramat 7586*3c34adc5Sramat /* release the hold that e_ddi_hold_devi_by_path() placed */ 7587*3c34adc5Sramat ndi_rele_devi(ph_dip); 7588*3c34adc5Sramat } 7589*3c34adc5Sramat 7590*3c34adc5Sramat devnm--; 7591*3c34adc5Sramat *devnm = '/'; 7592*3c34adc5Sramat return (rv); 7593*3c34adc5Sramat } 7594*3c34adc5Sramat 7595*3c34adc5Sramat /* 7596*3c34adc5Sramat * Build a list of phci client paths for the specified vhci client. 7597*3c34adc5Sramat * The list includes only those phci client paths which aren't configured yet. 7598*3c34adc5Sramat */ 7599*3c34adc5Sramat static mdi_phys_path_t * 7600*3c34adc5Sramat build_phclient_path_list(mdi_vhcache_client_t *cct, char *ct_name) 7601*3c34adc5Sramat { 7602*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 7603*3c34adc5Sramat mdi_phys_path_t *pp_head = NULL, *pp_tail = NULL, *pp; 7604*3c34adc5Sramat int config_path, len; 7605*3c34adc5Sramat 7606*3c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 7607*3c34adc5Sramat /* 7608*3c34adc5Sramat * include only those paths that aren't configured. 7609*3c34adc5Sramat */ 7610*3c34adc5Sramat config_path = 0; 7611*3c34adc5Sramat if (cpi->cpi_pip == NULL) 7612*3c34adc5Sramat config_path = 1; 7613*3c34adc5Sramat else { 7614*3c34adc5Sramat MDI_PI_LOCK(cpi->cpi_pip); 7615*3c34adc5Sramat if (MDI_PI_IS_INIT(cpi->cpi_pip)) 7616*3c34adc5Sramat config_path = 1; 7617*3c34adc5Sramat MDI_PI_UNLOCK(cpi->cpi_pip); 7618*3c34adc5Sramat } 7619*3c34adc5Sramat 7620*3c34adc5Sramat if (config_path) { 7621*3c34adc5Sramat pp = kmem_alloc(sizeof (*pp), KM_SLEEP); 7622*3c34adc5Sramat len = strlen(cpi->cpi_cphci->cphci_path) + 7623*3c34adc5Sramat strlen(ct_name) + strlen(cpi->cpi_addr) + 3; 7624*3c34adc5Sramat pp->phys_path = kmem_alloc(len, KM_SLEEP); 7625*3c34adc5Sramat (void) snprintf(pp->phys_path, len, "%s/%s@%s", 7626*3c34adc5Sramat cpi->cpi_cphci->cphci_path, ct_name, 7627*3c34adc5Sramat cpi->cpi_addr); 7628*3c34adc5Sramat pp->phys_path_next = NULL; 7629*3c34adc5Sramat 7630*3c34adc5Sramat if (pp_head == NULL) 7631*3c34adc5Sramat pp_head = pp; 7632*3c34adc5Sramat else 7633*3c34adc5Sramat pp_tail->phys_path_next = pp; 7634*3c34adc5Sramat pp_tail = pp; 7635*3c34adc5Sramat } 7636*3c34adc5Sramat } 7637*3c34adc5Sramat 7638*3c34adc5Sramat return (pp_head); 7639*3c34adc5Sramat } 7640*3c34adc5Sramat 7641*3c34adc5Sramat /* 7642*3c34adc5Sramat * Free the memory allocated for phci client path list. 7643*3c34adc5Sramat */ 7644*3c34adc5Sramat static void 7645*3c34adc5Sramat free_phclient_path_list(mdi_phys_path_t *pp_head) 7646*3c34adc5Sramat { 7647*3c34adc5Sramat mdi_phys_path_t *pp, *pp_next; 7648*3c34adc5Sramat 7649*3c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp_next) { 7650*3c34adc5Sramat pp_next = pp->phys_path_next; 7651*3c34adc5Sramat kmem_free(pp->phys_path, strlen(pp->phys_path) + 1); 7652*3c34adc5Sramat kmem_free(pp, sizeof (*pp)); 7653*3c34adc5Sramat } 7654*3c34adc5Sramat } 7655*3c34adc5Sramat 7656*3c34adc5Sramat /* 7657*3c34adc5Sramat * Allocated async client structure and initialize with the specified values. 7658*3c34adc5Sramat */ 7659*3c34adc5Sramat static mdi_async_client_config_t * 7660*3c34adc5Sramat alloc_async_client_config(char *ct_name, char *ct_addr, 7661*3c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 7662*3c34adc5Sramat { 7663*3c34adc5Sramat mdi_async_client_config_t *acc; 7664*3c34adc5Sramat 7665*3c34adc5Sramat acc = kmem_alloc(sizeof (*acc), KM_SLEEP); 7666*3c34adc5Sramat acc->acc_ct_name = i_ddi_strdup(ct_name, KM_SLEEP); 7667*3c34adc5Sramat acc->acc_ct_addr = i_ddi_strdup(ct_addr, KM_SLEEP); 7668*3c34adc5Sramat acc->acc_phclient_path_list_head = pp_head; 7669*3c34adc5Sramat init_vhcache_lookup_token(&acc->acc_token, tok); 7670*3c34adc5Sramat acc->acc_next = NULL; 7671*3c34adc5Sramat return (acc); 7672*3c34adc5Sramat } 7673*3c34adc5Sramat 7674*3c34adc5Sramat /* 7675*3c34adc5Sramat * Free the memory allocated for the async client structure and their members. 7676*3c34adc5Sramat */ 7677*3c34adc5Sramat static void 7678*3c34adc5Sramat free_async_client_config(mdi_async_client_config_t *acc) 7679*3c34adc5Sramat { 7680*3c34adc5Sramat if (acc->acc_phclient_path_list_head) 7681*3c34adc5Sramat free_phclient_path_list(acc->acc_phclient_path_list_head); 7682*3c34adc5Sramat kmem_free(acc->acc_ct_name, strlen(acc->acc_ct_name) + 1); 7683*3c34adc5Sramat kmem_free(acc->acc_ct_addr, strlen(acc->acc_ct_addr) + 1); 7684*3c34adc5Sramat kmem_free(acc, sizeof (*acc)); 7685*3c34adc5Sramat } 7686*3c34adc5Sramat 7687*3c34adc5Sramat /* 7688*3c34adc5Sramat * Sort vhcache pathinfos (cpis) of the specified client. 7689*3c34adc5Sramat * All cpis which do not have MDI_CPI_HINT_PATH_DOES_NOT_EXIST 7690*3c34adc5Sramat * flag set come at the beginning of the list. All cpis which have this 7691*3c34adc5Sramat * flag set come at the end of the list. 7692*3c34adc5Sramat */ 7693*3c34adc5Sramat static void 7694*3c34adc5Sramat sort_vhcache_paths(mdi_vhcache_client_t *cct) 7695*3c34adc5Sramat { 7696*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_next, *cpi_head; 7697*3c34adc5Sramat 7698*3c34adc5Sramat cpi_head = cct->cct_cpi_head; 7699*3c34adc5Sramat cct->cct_cpi_head = cct->cct_cpi_tail = NULL; 7700*3c34adc5Sramat for (cpi = cpi_head; cpi != NULL; cpi = cpi_next) { 7701*3c34adc5Sramat cpi_next = cpi->cpi_next; 7702*3c34adc5Sramat enqueue_vhcache_pathinfo(cct, cpi); 7703*3c34adc5Sramat } 7704*3c34adc5Sramat } 7705*3c34adc5Sramat 7706*3c34adc5Sramat /* 7707*3c34adc5Sramat * Verify whether MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag setting is correct for 7708*3c34adc5Sramat * every vhcache pathinfo of the specified client. If not adjust the flag 7709*3c34adc5Sramat * setting appropriately. 7710*3c34adc5Sramat * 7711*3c34adc5Sramat * Note that MDI_CPI_HINT_PATH_DOES_NOT_EXIST flag is persisted in the 7712*3c34adc5Sramat * on-disk vhci cache. So every time this flag is updated the cache must be 7713*3c34adc5Sramat * flushed. 7714*3c34adc5Sramat */ 7715*3c34adc5Sramat static void 7716*3c34adc5Sramat adjust_sort_vhcache_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 7717*3c34adc5Sramat mdi_vhcache_lookup_token_t *tok) 7718*3c34adc5Sramat { 7719*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 7720*3c34adc5Sramat mdi_vhcache_client_t *cct; 7721*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 7722*3c34adc5Sramat 7723*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 7724*3c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, tok)) 7725*3c34adc5Sramat == NULL) { 7726*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7727*3c34adc5Sramat return; 7728*3c34adc5Sramat } 7729*3c34adc5Sramat 7730*3c34adc5Sramat /* 7731*3c34adc5Sramat * to avoid unnecessary on-disk cache updates, first check if an 7732*3c34adc5Sramat * update is really needed. If no update is needed simply return. 7733*3c34adc5Sramat */ 7734*3c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 7735*3c34adc5Sramat if ((cpi->cpi_pip != NULL && 7736*3c34adc5Sramat (cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST)) || 7737*3c34adc5Sramat (cpi->cpi_pip == NULL && 7738*3c34adc5Sramat !(cpi->cpi_flags & MDI_CPI_HINT_PATH_DOES_NOT_EXIST))) { 7739*3c34adc5Sramat break; 7740*3c34adc5Sramat } 7741*3c34adc5Sramat } 7742*3c34adc5Sramat if (cpi == NULL) { 7743*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7744*3c34adc5Sramat return; 7745*3c34adc5Sramat } 7746*3c34adc5Sramat 7747*3c34adc5Sramat if (rw_tryupgrade(&vhcache->vhcache_lock) == 0) { 7748*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7749*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 7750*3c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, 7751*3c34adc5Sramat tok)) == NULL) { 7752*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7753*3c34adc5Sramat return; 7754*3c34adc5Sramat } 7755*3c34adc5Sramat } 7756*3c34adc5Sramat 7757*3c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 7758*3c34adc5Sramat if (cpi->cpi_pip != NULL) 7759*3c34adc5Sramat cpi->cpi_flags &= ~MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 7760*3c34adc5Sramat else 7761*3c34adc5Sramat cpi->cpi_flags |= MDI_CPI_HINT_PATH_DOES_NOT_EXIST; 7762*3c34adc5Sramat } 7763*3c34adc5Sramat sort_vhcache_paths(cct); 7764*3c34adc5Sramat 7765*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7766*3c34adc5Sramat vhcache_dirty(vhc); 7767*3c34adc5Sramat } 7768*3c34adc5Sramat 7769*3c34adc5Sramat /* 7770*3c34adc5Sramat * Configure all specified paths of the client. 7771*3c34adc5Sramat */ 7772*3c34adc5Sramat static void 7773*3c34adc5Sramat config_client_paths_sync(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 7774*3c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 7775*3c34adc5Sramat { 7776*3c34adc5Sramat mdi_phys_path_t *pp; 7777*3c34adc5Sramat 7778*3c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp->phys_path_next) 7779*3c34adc5Sramat (void) bus_config_one_phci_child(pp->phys_path); 7780*3c34adc5Sramat adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, tok); 7781*3c34adc5Sramat } 7782*3c34adc5Sramat 7783*3c34adc5Sramat /* 7784*3c34adc5Sramat * Dequeue elements from vhci async client config list and bus configure 7785*3c34adc5Sramat * their corresponding phci clients. 7786*3c34adc5Sramat */ 7787*3c34adc5Sramat static void 7788*3c34adc5Sramat config_client_paths_thread(void *arg) 7789*3c34adc5Sramat { 7790*3c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 7791*3c34adc5Sramat mdi_async_client_config_t *acc; 7792*3c34adc5Sramat clock_t quit_at_ticks; 7793*3c34adc5Sramat clock_t idle_time = mdi_async_config_idle_time * TICKS_PER_SECOND; 7794*3c34adc5Sramat callb_cpr_t cprinfo; 7795*3c34adc5Sramat 7796*3c34adc5Sramat CALLB_CPR_INIT(&cprinfo, &vhc->vhc_lock, callb_generic_cpr, 7797*3c34adc5Sramat "mdi_config_client_paths"); 7798*3c34adc5Sramat 7799*3c34adc5Sramat for (; ; ) { 7800*3c34adc5Sramat quit_at_ticks = ddi_get_lbolt() + idle_time; 7801*3c34adc5Sramat 7802*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 7803*3c34adc5Sramat while (!(vhc->vhc_flags & MDI_VHC_EXIT) && 7804*3c34adc5Sramat vhc->vhc_acc_list_head == NULL && 7805*3c34adc5Sramat ddi_get_lbolt() < quit_at_ticks) { 7806*3c34adc5Sramat CALLB_CPR_SAFE_BEGIN(&cprinfo); 7807*3c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock, 7808*3c34adc5Sramat quit_at_ticks); 7809*3c34adc5Sramat CALLB_CPR_SAFE_END(&cprinfo, &vhc->vhc_lock); 7810*3c34adc5Sramat } 7811*3c34adc5Sramat 7812*3c34adc5Sramat if ((vhc->vhc_flags & MDI_VHC_EXIT) || 7813*3c34adc5Sramat vhc->vhc_acc_list_head == NULL) 7814*3c34adc5Sramat goto out; 7815*3c34adc5Sramat 7816*3c34adc5Sramat acc = vhc->vhc_acc_list_head; 7817*3c34adc5Sramat vhc->vhc_acc_list_head = acc->acc_next; 7818*3c34adc5Sramat if (vhc->vhc_acc_list_head == NULL) 7819*3c34adc5Sramat vhc->vhc_acc_list_tail = NULL; 7820*3c34adc5Sramat vhc->vhc_acc_count--; 7821*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 7822*3c34adc5Sramat 7823*3c34adc5Sramat config_client_paths_sync(vhc, acc->acc_ct_name, 7824*3c34adc5Sramat acc->acc_ct_addr, acc->acc_phclient_path_list_head, 7825*3c34adc5Sramat &acc->acc_token); 7826*3c34adc5Sramat 7827*3c34adc5Sramat free_async_client_config(acc); 7828*3c34adc5Sramat } 7829*3c34adc5Sramat 7830*3c34adc5Sramat out: 7831*3c34adc5Sramat vhc->vhc_acc_thrcount--; 7832*3c34adc5Sramat /* CALLB_CPR_EXIT releases the vhc->vhc_lock */ 7833*3c34adc5Sramat CALLB_CPR_EXIT(&cprinfo); 7834*3c34adc5Sramat } 7835*3c34adc5Sramat 7836*3c34adc5Sramat /* 7837*3c34adc5Sramat * Arrange for all the phci client paths (pp_head) for the specified client 7838*3c34adc5Sramat * to be bus configured asynchronously by a thread. 7839*3c34adc5Sramat */ 7840*3c34adc5Sramat static void 7841*3c34adc5Sramat config_client_paths_async(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr, 7842*3c34adc5Sramat mdi_phys_path_t *pp_head, mdi_vhcache_lookup_token_t *tok) 7843*3c34adc5Sramat { 7844*3c34adc5Sramat mdi_async_client_config_t *acc, *newacc; 7845*3c34adc5Sramat int create_thread; 7846*3c34adc5Sramat 7847*3c34adc5Sramat if (pp_head == NULL) 7848*3c34adc5Sramat return; 7849*3c34adc5Sramat 7850*3c34adc5Sramat if (mdi_mtc_off) { 7851*3c34adc5Sramat config_client_paths_sync(vhc, ct_name, ct_addr, pp_head, tok); 7852*3c34adc5Sramat free_phclient_path_list(pp_head); 7853*3c34adc5Sramat return; 7854*3c34adc5Sramat } 7855*3c34adc5Sramat 7856*3c34adc5Sramat newacc = alloc_async_client_config(ct_name, ct_addr, pp_head, tok); 7857*3c34adc5Sramat ASSERT(newacc); 7858*3c34adc5Sramat 7859*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 7860*3c34adc5Sramat for (acc = vhc->vhc_acc_list_head; acc != NULL; acc = acc->acc_next) { 7861*3c34adc5Sramat if (strcmp(ct_name, acc->acc_ct_name) == 0 && 7862*3c34adc5Sramat strcmp(ct_addr, acc->acc_ct_addr) == 0) { 7863*3c34adc5Sramat free_async_client_config(newacc); 7864*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 7865*3c34adc5Sramat return; 7866*3c34adc5Sramat } 7867*3c34adc5Sramat } 7868*3c34adc5Sramat 7869*3c34adc5Sramat if (vhc->vhc_acc_list_head == NULL) 7870*3c34adc5Sramat vhc->vhc_acc_list_head = newacc; 7871*3c34adc5Sramat else 7872*3c34adc5Sramat vhc->vhc_acc_list_tail->acc_next = newacc; 7873*3c34adc5Sramat vhc->vhc_acc_list_tail = newacc; 7874*3c34adc5Sramat vhc->vhc_acc_count++; 7875*3c34adc5Sramat if (vhc->vhc_acc_count <= vhc->vhc_acc_thrcount) { 7876*3c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 7877*3c34adc5Sramat create_thread = 0; 7878*3c34adc5Sramat } else { 7879*3c34adc5Sramat vhc->vhc_acc_thrcount++; 7880*3c34adc5Sramat create_thread = 1; 7881*3c34adc5Sramat } 7882*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 7883*3c34adc5Sramat 7884*3c34adc5Sramat if (create_thread) 7885*3c34adc5Sramat (void) thread_create(NULL, 0, config_client_paths_thread, vhc, 7886*3c34adc5Sramat 0, &p0, TS_RUN, minclsyspri); 7887*3c34adc5Sramat } 7888*3c34adc5Sramat 7889*3c34adc5Sramat /* 7890*3c34adc5Sramat * Return number of online paths for the specified client. 7891*3c34adc5Sramat */ 7892*3c34adc5Sramat static int 7893*3c34adc5Sramat nonline_paths(mdi_vhcache_client_t *cct) 7894*3c34adc5Sramat { 7895*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi; 7896*3c34adc5Sramat int online_count = 0; 7897*3c34adc5Sramat 7898*3c34adc5Sramat for (cpi = cct->cct_cpi_head; cpi != NULL; cpi = cpi->cpi_next) { 7899*3c34adc5Sramat if (cpi->cpi_pip != NULL) { 7900*3c34adc5Sramat MDI_PI_LOCK(cpi->cpi_pip); 7901*3c34adc5Sramat if (cpi->cpi_pip->pi_state == MDI_PATHINFO_STATE_ONLINE) 7902*3c34adc5Sramat online_count++; 7903*3c34adc5Sramat MDI_PI_UNLOCK(cpi->cpi_pip); 7904*3c34adc5Sramat } 7905*3c34adc5Sramat } 7906*3c34adc5Sramat 7907*3c34adc5Sramat return (online_count); 7908*3c34adc5Sramat } 7909*3c34adc5Sramat 7910*3c34adc5Sramat /* 7911*3c34adc5Sramat * Bus configure all paths for the specified vhci client. 7912*3c34adc5Sramat * If at least one path for the client is already online, the remaining paths 7913*3c34adc5Sramat * will be configured asynchronously. Otherwise, it synchronously configures 7914*3c34adc5Sramat * the paths until at least one path is online and then rest of the paths 7915*3c34adc5Sramat * will be configured asynchronously. 7916*3c34adc5Sramat */ 7917*3c34adc5Sramat static void 7918*3c34adc5Sramat config_client_paths(mdi_vhci_config_t *vhc, char *ct_name, char *ct_addr) 7919*3c34adc5Sramat { 7920*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 7921*3c34adc5Sramat mdi_phys_path_t *pp_head, *pp; 7922*3c34adc5Sramat mdi_vhcache_client_t *cct; 7923*3c34adc5Sramat mdi_vhcache_lookup_token_t tok; 7924*3c34adc5Sramat 7925*3c34adc5Sramat ASSERT(RW_LOCK_HELD(&vhcache->vhcache_lock)); 7926*3c34adc5Sramat 7927*3c34adc5Sramat init_vhcache_lookup_token(&tok, NULL); 7928*3c34adc5Sramat 7929*3c34adc5Sramat if (ct_name == NULL || ct_addr == NULL || 7930*3c34adc5Sramat (cct = lookup_vhcache_client(vhcache, ct_name, ct_addr, &tok)) 7931*3c34adc5Sramat == NULL || 7932*3c34adc5Sramat (pp_head = build_phclient_path_list(cct, ct_name)) == NULL) { 7933*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7934*3c34adc5Sramat return; 7935*3c34adc5Sramat } 7936*3c34adc5Sramat 7937*3c34adc5Sramat /* if at least one path is online, configure the rest asynchronously */ 7938*3c34adc5Sramat if (nonline_paths(cct) > 0) { 7939*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7940*3c34adc5Sramat config_client_paths_async(vhc, ct_name, ct_addr, pp_head, &tok); 7941*3c34adc5Sramat return; 7942*3c34adc5Sramat } 7943*3c34adc5Sramat 7944*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7945*3c34adc5Sramat 7946*3c34adc5Sramat for (pp = pp_head; pp != NULL; pp = pp->phys_path_next) { 7947*3c34adc5Sramat if (bus_config_one_phci_child(pp->phys_path) == MDI_SUCCESS) { 7948*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 7949*3c34adc5Sramat 7950*3c34adc5Sramat if ((cct = lookup_vhcache_client(vhcache, ct_name, 7951*3c34adc5Sramat ct_addr, &tok)) == NULL) { 7952*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7953*3c34adc5Sramat goto out; 7954*3c34adc5Sramat } 7955*3c34adc5Sramat 7956*3c34adc5Sramat if (nonline_paths(cct) > 0 && 7957*3c34adc5Sramat pp->phys_path_next != NULL) { 7958*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7959*3c34adc5Sramat config_client_paths_async(vhc, ct_name, ct_addr, 7960*3c34adc5Sramat pp->phys_path_next, &tok); 7961*3c34adc5Sramat pp->phys_path_next = NULL; 7962*3c34adc5Sramat goto out; 7963*3c34adc5Sramat } 7964*3c34adc5Sramat 7965*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 7966*3c34adc5Sramat } 7967*3c34adc5Sramat } 7968*3c34adc5Sramat 7969*3c34adc5Sramat adjust_sort_vhcache_paths(vhc, ct_name, ct_addr, &tok); 7970*3c34adc5Sramat out: 7971*3c34adc5Sramat free_phclient_path_list(pp_head); 7972*3c34adc5Sramat } 7973*3c34adc5Sramat 7974*3c34adc5Sramat static void 7975*3c34adc5Sramat single_threaded_vhconfig_enter(mdi_vhci_config_t *vhc) 7976*3c34adc5Sramat { 7977*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 7978*3c34adc5Sramat while (vhc->vhc_flags & MDI_VHC_SINGLE_THREADED) 7979*3c34adc5Sramat cv_wait(&vhc->vhc_cv, &vhc->vhc_lock); 7980*3c34adc5Sramat vhc->vhc_flags |= MDI_VHC_SINGLE_THREADED; 7981*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 7982*3c34adc5Sramat } 7983*3c34adc5Sramat 7984*3c34adc5Sramat static void 7985*3c34adc5Sramat single_threaded_vhconfig_exit(mdi_vhci_config_t *vhc) 7986*3c34adc5Sramat { 7987*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 7988*3c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_SINGLE_THREADED; 7989*3c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 7990*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 7991*3c34adc5Sramat } 7992*3c34adc5Sramat 7993*3c34adc5Sramat /* 7994*3c34adc5Sramat * Attach the phci driver instances associated with the vhci: 7995*3c34adc5Sramat * If root is mounted attach all phci driver instances. 7996*3c34adc5Sramat * If root is not mounted, attach the instances of only those phci 7997*3c34adc5Sramat * drivers that have the root support. 7998*3c34adc5Sramat */ 7999*3c34adc5Sramat static void 8000*3c34adc5Sramat attach_phci_drivers(mdi_vhci_config_t *vhc, int root_mounted) 8001*3c34adc5Sramat { 8002*3c34adc5Sramat int i; 8003*3c34adc5Sramat major_t m; 8004*3c34adc5Sramat 8005*3c34adc5Sramat for (i = 0; i < vhc->vhc_nphci_drivers; i++) { 8006*3c34adc5Sramat if (root_mounted == 0 && 8007*3c34adc5Sramat vhc->vhc_phci_driver_list[i].phdriver_root_support == 0) 8008*3c34adc5Sramat continue; 8009*3c34adc5Sramat 8010*3c34adc5Sramat m = ddi_name_to_major( 8011*3c34adc5Sramat vhc->vhc_phci_driver_list[i].phdriver_name); 8012*3c34adc5Sramat if (m != (major_t)-1) { 8013*3c34adc5Sramat if (ddi_hold_installed_driver(m) != NULL) 8014*3c34adc5Sramat ddi_rele_driver(m); 8015*3c34adc5Sramat } 8016*3c34adc5Sramat } 8017*3c34adc5Sramat } 8018*3c34adc5Sramat 8019*3c34adc5Sramat /* 8020*3c34adc5Sramat * Build vhci cache: 8021*3c34adc5Sramat * 8022*3c34adc5Sramat * Attach phci driver instances and then drive BUS_CONFIG_ALL on 8023*3c34adc5Sramat * the phci driver instances. During this process the cache gets built. 8024*3c34adc5Sramat * 8025*3c34adc5Sramat * Cache is built fully if the root is mounted (i.e., root_mounted is nonzero). 8026*3c34adc5Sramat * 8027*3c34adc5Sramat * If the root is not mounted, phci drivers that do not have root support 8028*3c34adc5Sramat * are not attached. As a result the cache is built partially. The entries 8029*3c34adc5Sramat * in the cache reflect only those phci drivers that have root support. 8030*3c34adc5Sramat */ 8031*3c34adc5Sramat static vhcache_build_status_t 8032*3c34adc5Sramat build_vhci_cache(mdi_vhci_config_t *vhc, int root_mounted) 8033*3c34adc5Sramat { 8034*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 8035*3c34adc5Sramat 8036*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 8037*3c34adc5Sramat if (vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE) { 8038*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 8039*3c34adc5Sramat return (VHCACHE_NOT_REBUILT); 8040*3c34adc5Sramat } 8041*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 8042*3c34adc5Sramat 8043*3c34adc5Sramat attach_phci_drivers(vhc, root_mounted); 8044*3c34adc5Sramat bus_config_all_phcis(vhcache, NDI_DRV_CONF_REPROBE | NDI_NO_EVENT, 8045*3c34adc5Sramat BUS_CONFIG_ALL, (major_t)-1); 8046*3c34adc5Sramat 8047*3c34adc5Sramat if (root_mounted) { 8048*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 8049*3c34adc5Sramat vhcache->vhcache_flags |= MDI_VHCI_CACHE_SETUP_DONE; 8050*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 8051*3c34adc5Sramat vhcache_dirty(vhc); 8052*3c34adc5Sramat return (VHCACHE_FULLY_BUILT); 8053*3c34adc5Sramat } else 8054*3c34adc5Sramat return (VHCACHE_PARTIALLY_BUILT); 8055*3c34adc5Sramat } 8056*3c34adc5Sramat 8057*3c34adc5Sramat /* 8058*3c34adc5Sramat * Wait until the root is mounted and then build the vhci cache. 8059*3c34adc5Sramat */ 8060*3c34adc5Sramat static void 8061*3c34adc5Sramat build_vhci_cache_thread(void *arg) 8062*3c34adc5Sramat { 8063*3c34adc5Sramat mdi_vhci_config_t *vhc = (mdi_vhci_config_t *)arg; 8064*3c34adc5Sramat 8065*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 8066*3c34adc5Sramat while (!modrootloaded && !(vhc->vhc_flags & MDI_VHC_EXIT)) { 8067*3c34adc5Sramat (void) cv_timedwait(&vhc->vhc_cv, &vhc->vhc_lock, 8068*3c34adc5Sramat ddi_get_lbolt() + 10 * TICKS_PER_SECOND); 8069*3c34adc5Sramat } 8070*3c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_EXIT) 8071*3c34adc5Sramat goto out; 8072*3c34adc5Sramat 8073*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 8074*3c34adc5Sramat 8075*3c34adc5Sramat /* 8076*3c34adc5Sramat * Now that the root is mounted. So build_vhci_cache() will build 8077*3c34adc5Sramat * the full cache. 8078*3c34adc5Sramat */ 8079*3c34adc5Sramat (void) build_vhci_cache(vhc, 1); 8080*3c34adc5Sramat 8081*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 8082*3c34adc5Sramat out: 8083*3c34adc5Sramat vhc->vhc_flags &= ~MDI_VHC_BUILD_VHCI_CACHE_THREAD; 8084*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 8085*3c34adc5Sramat } 8086*3c34adc5Sramat 8087*3c34adc5Sramat /* 8088*3c34adc5Sramat * Build vhci cache - a wrapper for build_vhci_cache(). 8089*3c34adc5Sramat * 8090*3c34adc5Sramat * In a normal case on-disk vhci cache is read and setup during booting. 8091*3c34adc5Sramat * But if the on-disk vhci cache is not there or deleted or corrupted then 8092*3c34adc5Sramat * this function sets up the vhci cache. 8093*3c34adc5Sramat * 8094*3c34adc5Sramat * The cache is built fully if the root is mounted. 8095*3c34adc5Sramat * 8096*3c34adc5Sramat * If the root is not mounted, initially the cache is built reflecting only 8097*3c34adc5Sramat * those driver entries that have the root support. A separate thread is 8098*3c34adc5Sramat * created to handle the creation of full cache. This thread will wait 8099*3c34adc5Sramat * until the root is mounted and then rebuilds the cache. 8100*3c34adc5Sramat */ 8101*3c34adc5Sramat static int 8102*3c34adc5Sramat e_build_vhci_cache(mdi_vhci_config_t *vhc) 8103*3c34adc5Sramat { 8104*3c34adc5Sramat vhcache_build_status_t rv; 8105*3c34adc5Sramat 8106*3c34adc5Sramat single_threaded_vhconfig_enter(vhc); 8107*3c34adc5Sramat 8108*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 8109*3c34adc5Sramat if (vhc->vhc_flags & MDI_VHC_BUILD_VHCI_CACHE_THREAD) { 8110*3c34adc5Sramat if (modrootloaded) { 8111*3c34adc5Sramat cv_broadcast(&vhc->vhc_cv); 8112*3c34adc5Sramat /* wait until build vhci cache thread exits */ 8113*3c34adc5Sramat while (vhc->vhc_flags & MDI_VHC_BUILD_VHCI_CACHE_THREAD) 8114*3c34adc5Sramat cv_wait(&vhc->vhc_cv, &vhc->vhc_lock); 8115*3c34adc5Sramat rv = VHCACHE_FULLY_BUILT; 8116*3c34adc5Sramat } else { 8117*3c34adc5Sramat /* 8118*3c34adc5Sramat * The presense of MDI_VHC_BUILD_VHCI_CACHE_THREAD 8119*3c34adc5Sramat * flag indicates that the cache has already been 8120*3c34adc5Sramat * partially built. 8121*3c34adc5Sramat */ 8122*3c34adc5Sramat rv = VHCACHE_PARTIALLY_BUILT; 8123*3c34adc5Sramat } 8124*3c34adc5Sramat 8125*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 8126*3c34adc5Sramat single_threaded_vhconfig_exit(vhc); 8127*3c34adc5Sramat return (rv); 8128*3c34adc5Sramat } 8129*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 8130*3c34adc5Sramat 8131*3c34adc5Sramat rv = build_vhci_cache(vhc, modrootloaded); 8132*3c34adc5Sramat 8133*3c34adc5Sramat if (rv == VHCACHE_PARTIALLY_BUILT) { 8134*3c34adc5Sramat /* 8135*3c34adc5Sramat * create a thread; this thread will wait until the root is 8136*3c34adc5Sramat * mounted and then fully rebuilds the cache. 8137*3c34adc5Sramat */ 8138*3c34adc5Sramat mutex_enter(&vhc->vhc_lock); 8139*3c34adc5Sramat vhc->vhc_flags |= MDI_VHC_BUILD_VHCI_CACHE_THREAD; 8140*3c34adc5Sramat mutex_exit(&vhc->vhc_lock); 8141*3c34adc5Sramat (void) thread_create(NULL, 0, build_vhci_cache_thread, 8142*3c34adc5Sramat vhc, 0, &p0, TS_RUN, minclsyspri); 8143*3c34adc5Sramat } 8144*3c34adc5Sramat 8145*3c34adc5Sramat single_threaded_vhconfig_exit(vhc); 8146*3c34adc5Sramat return (rv); 8147*3c34adc5Sramat } 8148*3c34adc5Sramat 8149*3c34adc5Sramat /* 8150*3c34adc5Sramat * Generic vhci bus config implementation: 8151*3c34adc5Sramat * 8152*3c34adc5Sramat * Parameters 8153*3c34adc5Sramat * vdip vhci dip 8154*3c34adc5Sramat * flags bus config flags 8155*3c34adc5Sramat * op bus config operation 8156*3c34adc5Sramat * The remaining parameters are bus config operation specific 8157*3c34adc5Sramat * 8158*3c34adc5Sramat * for BUS_CONFIG_ONE 8159*3c34adc5Sramat * arg pointer to name@addr 8160*3c34adc5Sramat * child upon successful return from this function, *child will be 8161*3c34adc5Sramat * set to the configured and held devinfo child node of vdip. 8162*3c34adc5Sramat * ct_addr pointer to client address (i.e. GUID) 8163*3c34adc5Sramat * 8164*3c34adc5Sramat * for BUS_CONFIG_DRIVER 8165*3c34adc5Sramat * arg major number of the driver 8166*3c34adc5Sramat * child and ct_addr parameters are ignored 8167*3c34adc5Sramat * 8168*3c34adc5Sramat * for BUS_CONFIG_ALL 8169*3c34adc5Sramat * arg, child, and ct_addr parameters are ignored 8170*3c34adc5Sramat * 8171*3c34adc5Sramat * Note that for the rest of the bus config operations, this function simply 8172*3c34adc5Sramat * calls the framework provided default bus config routine. 8173*3c34adc5Sramat */ 8174*3c34adc5Sramat int 8175*3c34adc5Sramat mdi_vhci_bus_config(dev_info_t *vdip, uint_t flags, ddi_bus_config_op_t op, 8176*3c34adc5Sramat void *arg, dev_info_t **child, char *ct_addr) 8177*3c34adc5Sramat { 8178*3c34adc5Sramat mdi_vhci_t *vh = i_devi_get_vhci(vdip); 8179*3c34adc5Sramat mdi_vhci_config_t *vhc = vh->vh_config; 8180*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 8181*3c34adc5Sramat vhcache_build_status_t rv = VHCACHE_NOT_REBUILT; 8182*3c34adc5Sramat char *cp; 8183*3c34adc5Sramat 8184*3c34adc5Sramat /* 8185*3c34adc5Sramat * While bus configuring phcis, the phci driver interactions with MDI 8186*3c34adc5Sramat * cause child nodes to be enumerated under the vhci node for which 8187*3c34adc5Sramat * they need to ndi_devi_enter the vhci node. 8188*3c34adc5Sramat * 8189*3c34adc5Sramat * Unfortunately, to avoid the deadlock, we ourself can not wait for 8190*3c34adc5Sramat * for the bus config operations on phcis to finish while holding the 8191*3c34adc5Sramat * ndi_devi_enter lock. To avoid this deadlock, skip bus configs on 8192*3c34adc5Sramat * phcis and call the default framework provided bus config function 8193*3c34adc5Sramat * if we are called with ndi_devi_enter lock held. 8194*3c34adc5Sramat */ 8195*3c34adc5Sramat if (DEVI_BUSY_OWNED(vdip)) { 8196*3c34adc5Sramat MDI_DEBUG(2, (CE_NOTE, vdip, 8197*3c34adc5Sramat "!MDI: vhci bus config: vhci dip is busy owned\n")); 8198*3c34adc5Sramat goto default_bus_config; 8199*3c34adc5Sramat } 8200*3c34adc5Sramat 8201*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 8202*3c34adc5Sramat if (!(vhcache->vhcache_flags & MDI_VHCI_CACHE_SETUP_DONE)) { 8203*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 8204*3c34adc5Sramat rv = e_build_vhci_cache(vhc); 8205*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_READER); 8206*3c34adc5Sramat } 8207*3c34adc5Sramat 8208*3c34adc5Sramat switch (op) { 8209*3c34adc5Sramat case BUS_CONFIG_ONE: 8210*3c34adc5Sramat /* extract node name */ 8211*3c34adc5Sramat cp = (char *)arg; 8212*3c34adc5Sramat while (*cp != '\0' && *cp != '@') 8213*3c34adc5Sramat cp++; 8214*3c34adc5Sramat if (*cp == '@') { 8215*3c34adc5Sramat *cp = '\0'; 8216*3c34adc5Sramat config_client_paths(vhc, (char *)arg, ct_addr); 8217*3c34adc5Sramat /* config_client_paths() releases the cache_lock */ 8218*3c34adc5Sramat *cp = '@'; 8219*3c34adc5Sramat } else 8220*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 8221*3c34adc5Sramat break; 8222*3c34adc5Sramat 8223*3c34adc5Sramat case BUS_CONFIG_DRIVER: 8224*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 8225*3c34adc5Sramat if (rv == VHCACHE_NOT_REBUILT) 8226*3c34adc5Sramat bus_config_all_phcis(vhcache, flags, op, 8227*3c34adc5Sramat (major_t)(uintptr_t)arg); 8228*3c34adc5Sramat break; 8229*3c34adc5Sramat 8230*3c34adc5Sramat case BUS_CONFIG_ALL: 8231*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 8232*3c34adc5Sramat if (rv == VHCACHE_NOT_REBUILT) 8233*3c34adc5Sramat bus_config_all_phcis(vhcache, flags, op, -1); 8234*3c34adc5Sramat break; 8235*3c34adc5Sramat 8236*3c34adc5Sramat default: 8237*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 8238*3c34adc5Sramat break; 8239*3c34adc5Sramat } 8240*3c34adc5Sramat 8241*3c34adc5Sramat 8242*3c34adc5Sramat default_bus_config: 8243*3c34adc5Sramat /* 8244*3c34adc5Sramat * All requested child nodes are enumerated under the vhci. 8245*3c34adc5Sramat * Now configure them. 8246*3c34adc5Sramat */ 8247*3c34adc5Sramat if (ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 8248*3c34adc5Sramat NDI_SUCCESS) { 8249*3c34adc5Sramat return (MDI_SUCCESS); 8250*3c34adc5Sramat } 8251*3c34adc5Sramat 8252*3c34adc5Sramat return (MDI_FAILURE); 8253*3c34adc5Sramat } 8254*3c34adc5Sramat 8255*3c34adc5Sramat /* 8256*3c34adc5Sramat * Read the on-disk vhci cache into an nvlist for the specified vhci class. 8257*3c34adc5Sramat */ 8258*3c34adc5Sramat static nvlist_t * 8259*3c34adc5Sramat read_on_disk_vhci_cache(char *vhci_class) 8260*3c34adc5Sramat { 8261*3c34adc5Sramat nvlist_t *nvl; 8262*3c34adc5Sramat int err; 8263*3c34adc5Sramat char *filename; 8264*3c34adc5Sramat 8265*3c34adc5Sramat filename = vhclass2vhcache_filename(vhci_class); 8266*3c34adc5Sramat 8267*3c34adc5Sramat if ((err = fread_nvlist(filename, &nvl)) == 0) { 8268*3c34adc5Sramat kmem_free(filename, strlen(filename) + 1); 8269*3c34adc5Sramat return (nvl); 8270*3c34adc5Sramat } else if (err == EIO) 8271*3c34adc5Sramat cmn_err(CE_WARN, "%s: I/O error, will recreate\n", filename); 8272*3c34adc5Sramat else if (err == EINVAL) 8273*3c34adc5Sramat cmn_err(CE_WARN, 8274*3c34adc5Sramat "%s: data file corrupted, will recreate\n", filename); 8275*3c34adc5Sramat 8276*3c34adc5Sramat kmem_free(filename, strlen(filename) + 1); 8277*3c34adc5Sramat return (NULL); 8278*3c34adc5Sramat } 8279*3c34adc5Sramat 8280*3c34adc5Sramat /* 8281*3c34adc5Sramat * Read on-disk vhci cache into nvlists for all vhci classes. 8282*3c34adc5Sramat * Called during booting by i_ddi_read_devices_files(). 8283*3c34adc5Sramat */ 8284*3c34adc5Sramat void 8285*3c34adc5Sramat mdi_read_devices_files(void) 8286*3c34adc5Sramat { 8287*3c34adc5Sramat int i; 8288*3c34adc5Sramat 8289*3c34adc5Sramat for (i = 0; i < N_VHCI_CLASSES; i++) 8290*3c34adc5Sramat vhcache_nvl[i] = read_on_disk_vhci_cache(vhci_class_list[i]); 8291*3c34adc5Sramat } 8292*3c34adc5Sramat 8293*3c34adc5Sramat /* 8294*3c34adc5Sramat * Remove all stale entries from vhci cache. 8295*3c34adc5Sramat */ 8296*3c34adc5Sramat static void 8297*3c34adc5Sramat clean_vhcache(mdi_vhci_config_t *vhc) 8298*3c34adc5Sramat { 8299*3c34adc5Sramat mdi_vhci_cache_t *vhcache = &vhc->vhc_vhcache; 8300*3c34adc5Sramat mdi_vhcache_phci_t *cphci, *cphci_head, *cphci_next; 8301*3c34adc5Sramat mdi_vhcache_client_t *cct, *cct_head, *cct_next; 8302*3c34adc5Sramat mdi_vhcache_pathinfo_t *cpi, *cpi_head, *cpi_next; 8303*3c34adc5Sramat 8304*3c34adc5Sramat rw_enter(&vhcache->vhcache_lock, RW_WRITER); 8305*3c34adc5Sramat 8306*3c34adc5Sramat cct_head = vhcache->vhcache_client_head; 8307*3c34adc5Sramat vhcache->vhcache_client_head = vhcache->vhcache_client_tail = NULL; 8308*3c34adc5Sramat for (cct = cct_head; cct != NULL; cct = cct_next) { 8309*3c34adc5Sramat cct_next = cct->cct_next; 8310*3c34adc5Sramat 8311*3c34adc5Sramat cpi_head = cct->cct_cpi_head; 8312*3c34adc5Sramat cct->cct_cpi_head = cct->cct_cpi_tail = NULL; 8313*3c34adc5Sramat for (cpi = cpi_head; cpi != NULL; cpi = cpi_next) { 8314*3c34adc5Sramat cpi_next = cpi->cpi_next; 8315*3c34adc5Sramat if (cpi->cpi_pip != NULL) { 8316*3c34adc5Sramat ASSERT(cpi->cpi_cphci->cphci_phci != NULL); 8317*3c34adc5Sramat enqueue_tail_vhcache_pathinfo(cct, cpi); 8318*3c34adc5Sramat } else 8319*3c34adc5Sramat free_vhcache_pathinfo(cpi); 8320*3c34adc5Sramat } 8321*3c34adc5Sramat 8322*3c34adc5Sramat if (cct->cct_cpi_head != NULL) 8323*3c34adc5Sramat enqueue_vhcache_client(vhcache, cct); 8324*3c34adc5Sramat else { 8325*3c34adc5Sramat (void) mod_hash_destroy(vhcache->vhcache_client_hash, 8326*3c34adc5Sramat (mod_hash_key_t)cct->cct_name_addr); 8327*3c34adc5Sramat free_vhcache_client(cct); 8328*3c34adc5Sramat } 8329*3c34adc5Sramat } 8330*3c34adc5Sramat 8331*3c34adc5Sramat cphci_head = vhcache->vhcache_phci_head; 8332*3c34adc5Sramat vhcache->vhcache_phci_head = vhcache->vhcache_phci_tail = NULL; 8333*3c34adc5Sramat for (cphci = cphci_head; cphci != NULL; cphci = cphci_next) { 8334*3c34adc5Sramat cphci_next = cphci->cphci_next; 8335*3c34adc5Sramat if (cphci->cphci_phci != NULL) 8336*3c34adc5Sramat enqueue_vhcache_phci(vhcache, cphci); 8337*3c34adc5Sramat else 8338*3c34adc5Sramat free_vhcache_phci(cphci); 8339*3c34adc5Sramat } 8340*3c34adc5Sramat 8341*3c34adc5Sramat vhcache->vhcache_clean_time = lbolt64; 8342*3c34adc5Sramat rw_exit(&vhcache->vhcache_lock); 8343*3c34adc5Sramat vhcache_dirty(vhc); 8344*3c34adc5Sramat } 8345*3c34adc5Sramat 8346*3c34adc5Sramat /* 8347*3c34adc5Sramat * Remove all stale entries from vhci cache. 8348*3c34adc5Sramat * Called by i_ddi_clean_devices_files() during the execution of devfsadm -C 8349*3c34adc5Sramat */ 8350*3c34adc5Sramat void 8351*3c34adc5Sramat mdi_clean_vhcache(void) 8352*3c34adc5Sramat { 8353*3c34adc5Sramat mdi_vhci_t *vh; 8354*3c34adc5Sramat 8355*3c34adc5Sramat mutex_enter(&mdi_mutex); 8356*3c34adc5Sramat for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 8357*3c34adc5Sramat vh->vh_refcnt++; 8358*3c34adc5Sramat mutex_exit(&mdi_mutex); 8359*3c34adc5Sramat clean_vhcache(vh->vh_config); 8360*3c34adc5Sramat mutex_enter(&mdi_mutex); 8361*3c34adc5Sramat vh->vh_refcnt--; 8362*3c34adc5Sramat } 8363*3c34adc5Sramat mutex_exit(&mdi_mutex); 8364*3c34adc5Sramat } 8365