1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * Multipath driver interface (MDI) implementation; see mdi_impl.h for a more 30*7c478bd9Sstevel@tonic-gate * detailed discussion of the overall mpxio architecture. 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * Default locking order: 33*7c478bd9Sstevel@tonic-gate * 34*7c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_mutex, mdi_phci::ph_mutex)) 35*7c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_mutex, mdi_client::ct_mutex)) 36*7c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 37*7c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex)) 38*7c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 39*7c478bd9Sstevel@tonic-gate */ 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #include <sys/note.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/uio.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/buf.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/open.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/poll.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/ddipropdefs.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 62*7c478bd9Sstevel@tonic-gate #include <sys/sunmdi.h> 63*7c478bd9Sstevel@tonic-gate #include <sys/mdi_impldefs.h> 64*7c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 65*7c478bd9Sstevel@tonic-gate #include <sys/epm.h> 66*7c478bd9Sstevel@tonic-gate #include <sys/sunpm.h> 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 69*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 70*7c478bd9Sstevel@tonic-gate int mdi_debug = 1; 71*7c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) \ 72*7c478bd9Sstevel@tonic-gate if (mdi_debug >= (level)) i_mdi_log stmnt 73*7c478bd9Sstevel@tonic-gate static void i_mdi_log(int, dev_info_t *, const char *fmt, ...); 74*7c478bd9Sstevel@tonic-gate #else /* !DEBUG */ 75*7c478bd9Sstevel@tonic-gate #define MDI_DEBUG(level, stmnt) 76*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; 79*7c478bd9Sstevel@tonic-gate extern int modrootloaded; 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* 82*7c478bd9Sstevel@tonic-gate * Global mutex: 83*7c478bd9Sstevel@tonic-gate * Protects vHCI list and structure members, pHCI and Client lists. 84*7c478bd9Sstevel@tonic-gate */ 85*7c478bd9Sstevel@tonic-gate kmutex_t mdi_mutex; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* 88*7c478bd9Sstevel@tonic-gate * Registered vHCI class driver lists 89*7c478bd9Sstevel@tonic-gate */ 90*7c478bd9Sstevel@tonic-gate int mdi_vhci_count; 91*7c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_head; 92*7c478bd9Sstevel@tonic-gate mdi_vhci_t *mdi_vhci_tail; 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate /* 95*7c478bd9Sstevel@tonic-gate * Client Hash Table size 96*7c478bd9Sstevel@tonic-gate */ 97*7c478bd9Sstevel@tonic-gate static int mdi_client_table_size = CLIENT_HASH_TABLE_SIZE; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* 100*7c478bd9Sstevel@tonic-gate * taskq interface definitions 101*7c478bd9Sstevel@tonic-gate */ 102*7c478bd9Sstevel@tonic-gate #define MDI_TASKQ_N_THREADS 8 103*7c478bd9Sstevel@tonic-gate #define MDI_TASKQ_PRI minclsyspri 104*7c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MINALLOC (4*mdi_taskq_n_threads) 105*7c478bd9Sstevel@tonic-gate #define MDI_TASKQ_MAXALLOC (500*mdi_taskq_n_threads) 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate taskq_t *mdi_taskq; 108*7c478bd9Sstevel@tonic-gate static uint_t mdi_taskq_n_threads = MDI_TASKQ_N_THREADS; 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate static int mdi_max_bus_config_threads = 100; 111*7c478bd9Sstevel@tonic-gate /* 112*7c478bd9Sstevel@tonic-gate * To reduce unnecessary BUS_CONFIG_ALLs, do not BUS_CONFIG_ALL phcis in the 113*7c478bd9Sstevel@tonic-gate * context of a BUS_CONFIG_ONE if a BUS_CONFIG_ALL has already been performed 114*7c478bd9Sstevel@tonic-gate * in the last mdi_bus_config_timeout seconds. 115*7c478bd9Sstevel@tonic-gate */ 116*7c478bd9Sstevel@tonic-gate static int mdi_bus_config_timeout = 60; /* in seconds */ 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* 119*7c478bd9Sstevel@tonic-gate * MDI component property name/value string definitions 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate const char *mdi_component_prop = "mpxio-component"; 122*7c478bd9Sstevel@tonic-gate const char *mdi_component_prop_vhci = "vhci"; 123*7c478bd9Sstevel@tonic-gate const char *mdi_component_prop_phci = "phci"; 124*7c478bd9Sstevel@tonic-gate const char *mdi_component_prop_client = "client"; 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate /* 127*7c478bd9Sstevel@tonic-gate * MDI client global unique identifier property name 128*7c478bd9Sstevel@tonic-gate */ 129*7c478bd9Sstevel@tonic-gate const char *mdi_client_guid_prop = "client-guid"; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate /* 132*7c478bd9Sstevel@tonic-gate * MDI client load balancing property name/value string definitions 133*7c478bd9Sstevel@tonic-gate */ 134*7c478bd9Sstevel@tonic-gate const char *mdi_load_balance = "load-balance"; 135*7c478bd9Sstevel@tonic-gate const char *mdi_load_balance_none = "none"; 136*7c478bd9Sstevel@tonic-gate const char *mdi_load_balance_rr = "round-robin"; 137*7c478bd9Sstevel@tonic-gate const char *mdi_load_balance_lba = "logical-block"; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* 140*7c478bd9Sstevel@tonic-gate * Obsolete vHCI class definition; to be removed after Leadville update 141*7c478bd9Sstevel@tonic-gate */ 142*7c478bd9Sstevel@tonic-gate const char *mdi_vhci_class_scsi = MDI_HCI_CLASS_SCSI; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate static char vhci_greeting[] = 145*7c478bd9Sstevel@tonic-gate "\tThere already exists one vHCI driver for class %s\n" 146*7c478bd9Sstevel@tonic-gate "\tOnly one vHCI driver for each class is allowed\n"; 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * Static function prototypes 150*7c478bd9Sstevel@tonic-gate */ 151*7c478bd9Sstevel@tonic-gate static int i_mdi_phci_offline(dev_info_t *, uint_t); 152*7c478bd9Sstevel@tonic-gate static int i_mdi_client_offline(dev_info_t *, uint_t); 153*7c478bd9Sstevel@tonic-gate static int i_mdi_phci_pre_detach(dev_info_t *, ddi_detach_cmd_t); 154*7c478bd9Sstevel@tonic-gate static void i_mdi_phci_post_detach(dev_info_t *, 155*7c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 156*7c478bd9Sstevel@tonic-gate static int i_mdi_client_pre_detach(dev_info_t *, 157*7c478bd9Sstevel@tonic-gate ddi_detach_cmd_t); 158*7c478bd9Sstevel@tonic-gate static void i_mdi_client_post_detach(dev_info_t *, 159*7c478bd9Sstevel@tonic-gate ddi_detach_cmd_t, int); 160*7c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_pip(mdi_pathinfo_t *); 161*7c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_pip(mdi_pathinfo_t *); 162*7c478bd9Sstevel@tonic-gate static int i_mdi_lba_lb(mdi_client_t *ct, 163*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t **ret_pip, struct buf *buf); 164*7c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_client(mdi_client_t *, int); 165*7c478bd9Sstevel@tonic-gate static void i_mdi_pm_rele_client(mdi_client_t *, int); 166*7c478bd9Sstevel@tonic-gate static void i_mdi_pm_reset_client(mdi_client_t *); 167*7c478bd9Sstevel@tonic-gate static void i_mdi_pm_hold_all_phci(mdi_client_t *); 168*7c478bd9Sstevel@tonic-gate static int i_mdi_power_all_phci(mdi_client_t *); 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate /* 172*7c478bd9Sstevel@tonic-gate * Internal mdi_pathinfo node functions 173*7c478bd9Sstevel@tonic-gate */ 174*7c478bd9Sstevel@tonic-gate static int i_mdi_pi_kstat_create(mdi_pathinfo_t *); 175*7c478bd9Sstevel@tonic-gate static void i_mdi_pi_kstat_destroy(mdi_pathinfo_t *); 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_mdi_vhci_class2vhci(char *); 178*7c478bd9Sstevel@tonic-gate static mdi_vhci_t *i_devi_get_vhci(dev_info_t *); 179*7c478bd9Sstevel@tonic-gate static mdi_phci_t *i_devi_get_phci(dev_info_t *); 180*7c478bd9Sstevel@tonic-gate static void i_mdi_phci_lock(mdi_phci_t *, mdi_pathinfo_t *); 181*7c478bd9Sstevel@tonic-gate static void i_mdi_phci_get_client_lock(mdi_phci_t *, 182*7c478bd9Sstevel@tonic-gate mdi_client_t *); 183*7c478bd9Sstevel@tonic-gate static void i_mdi_phci_unlock(mdi_phci_t *); 184*7c478bd9Sstevel@tonic-gate static mdi_pathinfo_t *i_mdi_pi_alloc(mdi_phci_t *, char *, 185*7c478bd9Sstevel@tonic-gate mdi_client_t *, int); 186*7c478bd9Sstevel@tonic-gate static void i_mdi_phci_add_path(mdi_phci_t *, mdi_pathinfo_t *); 187*7c478bd9Sstevel@tonic-gate static void i_mdi_client_add_path(mdi_client_t *, mdi_pathinfo_t *); 188*7c478bd9Sstevel@tonic-gate static void i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *, 189*7c478bd9Sstevel@tonic-gate mdi_client_t *); 190*7c478bd9Sstevel@tonic-gate static void i_mdi_phci_remove_path(mdi_phci_t *, mdi_pathinfo_t *); 191*7c478bd9Sstevel@tonic-gate static void i_mdi_client_remove_path(mdi_client_t *, 192*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate static int i_mdi_pi_state_change(mdi_pathinfo_t *, 195*7c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t, int); 196*7c478bd9Sstevel@tonic-gate static int i_mdi_pi_offline(mdi_pathinfo_t *, int); 197*7c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_create(mdi_vhci_t *, char *, char *, 198*7c478bd9Sstevel@tonic-gate char **, int, int); 199*7c478bd9Sstevel@tonic-gate static dev_info_t *i_mdi_devinfo_find(mdi_vhci_t *, char *, char *); 200*7c478bd9Sstevel@tonic-gate static int i_mdi_devinfo_remove(dev_info_t *, dev_info_t *, int); 201*7c478bd9Sstevel@tonic-gate static int i_mdi_is_child_present(dev_info_t *, dev_info_t *); 202*7c478bd9Sstevel@tonic-gate static mdi_client_t *i_mdi_client_alloc(mdi_vhci_t *, char *, char *, int); 203*7c478bd9Sstevel@tonic-gate static void i_mdi_client_enlist_table(mdi_vhci_t *, mdi_client_t *); 204*7c478bd9Sstevel@tonic-gate static void i_mdi_client_delist_table(mdi_vhci_t *, mdi_client_t *); 205*7c478bd9Sstevel@tonic-gate static mdi_client_t *i_mdi_client_find(mdi_vhci_t *, char *); 206*7c478bd9Sstevel@tonic-gate static void i_mdi_client_update_state(mdi_client_t *); 207*7c478bd9Sstevel@tonic-gate static int i_mdi_client_compute_state(mdi_client_t *, 208*7c478bd9Sstevel@tonic-gate mdi_phci_t *); 209*7c478bd9Sstevel@tonic-gate static void i_mdi_client_lock(mdi_client_t *, mdi_pathinfo_t *); 210*7c478bd9Sstevel@tonic-gate static void i_mdi_client_unlock(mdi_client_t *); 211*7c478bd9Sstevel@tonic-gate static int i_mdi_client_free(mdi_vhci_t *, mdi_client_t *); 212*7c478bd9Sstevel@tonic-gate static mdi_client_t *i_devi_get_client(dev_info_t *); 213*7c478bd9Sstevel@tonic-gate static int i_mdi_pi_enable_disable(dev_info_t *, dev_info_t *, int, 214*7c478bd9Sstevel@tonic-gate int); 215*7c478bd9Sstevel@tonic-gate /* 216*7c478bd9Sstevel@tonic-gate * Failover related function prototypes 217*7c478bd9Sstevel@tonic-gate */ 218*7c478bd9Sstevel@tonic-gate static int i_mdi_failover(void *); 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate /* 221*7c478bd9Sstevel@tonic-gate * misc internal functions 222*7c478bd9Sstevel@tonic-gate */ 223*7c478bd9Sstevel@tonic-gate static int i_mdi_get_hash_key(char *); 224*7c478bd9Sstevel@tonic-gate static int i_map_nvlist_error_to_mdi(int); 225*7c478bd9Sstevel@tonic-gate static void i_mdi_report_path_state(mdi_client_t *, 226*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *); 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* called once when first vhci registers with mdi */ 229*7c478bd9Sstevel@tonic-gate static void 230*7c478bd9Sstevel@tonic-gate i_mdi_init() 231*7c478bd9Sstevel@tonic-gate { 232*7c478bd9Sstevel@tonic-gate static int initialized = 0; 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate if (initialized) 235*7c478bd9Sstevel@tonic-gate return; 236*7c478bd9Sstevel@tonic-gate initialized = 1; 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate mutex_init(&mdi_mutex, NULL, MUTEX_DEFAULT, NULL); 239*7c478bd9Sstevel@tonic-gate /* 240*7c478bd9Sstevel@tonic-gate * Create our taskq resources 241*7c478bd9Sstevel@tonic-gate */ 242*7c478bd9Sstevel@tonic-gate mdi_taskq = taskq_create("mdi_taskq", mdi_taskq_n_threads, 243*7c478bd9Sstevel@tonic-gate MDI_TASKQ_PRI, MDI_TASKQ_MINALLOC, MDI_TASKQ_MAXALLOC, 244*7c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE | TASKQ_CPR_SAFE); 245*7c478bd9Sstevel@tonic-gate ASSERT(mdi_taskq != NULL); /* taskq_create never fails */ 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate /* 249*7c478bd9Sstevel@tonic-gate * mdi_get_component_type(): 250*7c478bd9Sstevel@tonic-gate * Return mpxio component type 251*7c478bd9Sstevel@tonic-gate * Return Values: 252*7c478bd9Sstevel@tonic-gate * MDI_COMPONENT_NONE 253*7c478bd9Sstevel@tonic-gate * MDI_COMPONENT_VHCI 254*7c478bd9Sstevel@tonic-gate * MDI_COMPONENT_PHCI 255*7c478bd9Sstevel@tonic-gate * MDI_COMPONENT_CLIENT 256*7c478bd9Sstevel@tonic-gate * XXX This doesn't work under multi-level MPxIO and should be 257*7c478bd9Sstevel@tonic-gate * removed when clients migrate mdi_is_*() interfaces. 258*7c478bd9Sstevel@tonic-gate */ 259*7c478bd9Sstevel@tonic-gate int 260*7c478bd9Sstevel@tonic-gate mdi_get_component_type(dev_info_t *dip) 261*7c478bd9Sstevel@tonic-gate { 262*7c478bd9Sstevel@tonic-gate return (DEVI(dip)->devi_mdi_component); 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate /* 266*7c478bd9Sstevel@tonic-gate * mdi_vhci_register(): 267*7c478bd9Sstevel@tonic-gate * Register a vHCI module with the mpxio framework 268*7c478bd9Sstevel@tonic-gate * mdi_vhci_register() is called by vHCI drivers to register the 269*7c478bd9Sstevel@tonic-gate * 'class_driver' vHCI driver and its MDI entrypoints with the 270*7c478bd9Sstevel@tonic-gate * mpxio framework. The vHCI driver must call this interface as 271*7c478bd9Sstevel@tonic-gate * part of its attach(9e) handler. 272*7c478bd9Sstevel@tonic-gate * Competing threads may try to attach mdi_vhci_register() as 273*7c478bd9Sstevel@tonic-gate * the vHCI drivers are loaded and attached as a result of pHCI 274*7c478bd9Sstevel@tonic-gate * driver instance registration (mdi_phci_register()) with the 275*7c478bd9Sstevel@tonic-gate * framework. 276*7c478bd9Sstevel@tonic-gate * Return Values: 277*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 278*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 279*7c478bd9Sstevel@tonic-gate */ 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 282*7c478bd9Sstevel@tonic-gate int 283*7c478bd9Sstevel@tonic-gate mdi_vhci_register(char *class, dev_info_t *vdip, mdi_vhci_ops_t *vops, 284*7c478bd9Sstevel@tonic-gate int flags) 285*7c478bd9Sstevel@tonic-gate { 286*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate ASSERT(vops->vo_revision == MDI_VHCI_OPS_REV); 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate i_mdi_init(); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 293*7c478bd9Sstevel@tonic-gate /* 294*7c478bd9Sstevel@tonic-gate * Scan for already registered vhci 295*7c478bd9Sstevel@tonic-gate */ 296*7c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 297*7c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 298*7c478bd9Sstevel@tonic-gate /* 299*7c478bd9Sstevel@tonic-gate * vHCI has already been created. Check for valid 300*7c478bd9Sstevel@tonic-gate * vHCI ops registration. We only support one vHCI 301*7c478bd9Sstevel@tonic-gate * module per class 302*7c478bd9Sstevel@tonic-gate */ 303*7c478bd9Sstevel@tonic-gate if (vh->vh_ops != NULL) { 304*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 305*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, vhci_greeting, class); 306*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate break; 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate /* 313*7c478bd9Sstevel@tonic-gate * if not yet created, create the vHCI component 314*7c478bd9Sstevel@tonic-gate */ 315*7c478bd9Sstevel@tonic-gate if (vh == NULL) { 316*7c478bd9Sstevel@tonic-gate struct client_hash *hash = NULL; 317*7c478bd9Sstevel@tonic-gate char *load_balance; 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate /* 320*7c478bd9Sstevel@tonic-gate * Allocate and initialize the mdi extensions 321*7c478bd9Sstevel@tonic-gate */ 322*7c478bd9Sstevel@tonic-gate vh = kmem_zalloc(sizeof (mdi_vhci_t), KM_SLEEP); 323*7c478bd9Sstevel@tonic-gate hash = kmem_zalloc(mdi_client_table_size * sizeof (*hash), 324*7c478bd9Sstevel@tonic-gate KM_SLEEP); 325*7c478bd9Sstevel@tonic-gate vh->vh_client_table = hash; 326*7c478bd9Sstevel@tonic-gate vh->vh_class = kmem_zalloc(strlen(class) + 1, KM_SLEEP); 327*7c478bd9Sstevel@tonic-gate (void) strcpy(vh->vh_class, class); 328*7c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_RR; 329*7c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vdip, 330*7c478bd9Sstevel@tonic-gate 0, LOAD_BALANCE_PROP, &load_balance) == DDI_SUCCESS) { 331*7c478bd9Sstevel@tonic-gate if (strcmp(load_balance, LOAD_BALANCE_PROP_NONE) == 0) { 332*7c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_NONE; 333*7c478bd9Sstevel@tonic-gate } else if (strcmp(load_balance, LOAD_BALANCE_PROP_LBA) 334*7c478bd9Sstevel@tonic-gate == 0) { 335*7c478bd9Sstevel@tonic-gate vh->vh_lb = LOAD_BALANCE_LBA; 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate ddi_prop_free(load_balance); 338*7c478bd9Sstevel@tonic-gate } 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate /* 341*7c478bd9Sstevel@tonic-gate * Store the vHCI ops vectors 342*7c478bd9Sstevel@tonic-gate */ 343*7c478bd9Sstevel@tonic-gate vh->vh_dip = vdip; 344*7c478bd9Sstevel@tonic-gate vh->vh_ops = vops; 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate /* 347*7c478bd9Sstevel@tonic-gate * other members of vh_bus_config are initialized by 348*7c478bd9Sstevel@tonic-gate * the above kmem_zalloc of the vhci structure. 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate cv_init(&vh->vh_bus_config.vhc_cv, NULL, CV_DRIVER, NULL); 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate if (mdi_vhci_head == NULL) { 353*7c478bd9Sstevel@tonic-gate mdi_vhci_head = vh; 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate if (mdi_vhci_tail) { 356*7c478bd9Sstevel@tonic-gate mdi_vhci_tail->vh_next = vh; 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate mdi_vhci_tail = vh; 359*7c478bd9Sstevel@tonic-gate mdi_vhci_count++; 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate /* 363*7c478bd9Sstevel@tonic-gate * Claim the devfs node as a vhci component 364*7c478bd9Sstevel@tonic-gate */ 365*7c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component |= MDI_COMPONENT_VHCI; 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate /* 368*7c478bd9Sstevel@tonic-gate * Initialize our back reference from dev_info node 369*7c478bd9Sstevel@tonic-gate */ 370*7c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = (caddr_t)vh; 371*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 372*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate /* 376*7c478bd9Sstevel@tonic-gate * mdi_vhci_unregister(): 377*7c478bd9Sstevel@tonic-gate * Unregister a vHCI module from mpxio framework 378*7c478bd9Sstevel@tonic-gate * mdi_vhci_unregister() is called from the detach(9E) entrypoint 379*7c478bd9Sstevel@tonic-gate * of a vhci to unregister it from the framework. 380*7c478bd9Sstevel@tonic-gate * Return Values: 381*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 382*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 383*7c478bd9Sstevel@tonic-gate */ 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 386*7c478bd9Sstevel@tonic-gate int 387*7c478bd9Sstevel@tonic-gate mdi_vhci_unregister(dev_info_t *vdip, int flags) 388*7c478bd9Sstevel@tonic-gate { 389*7c478bd9Sstevel@tonic-gate mdi_vhci_t *found, *vh, *prev = NULL; 390*7c478bd9Sstevel@tonic-gate mdi_phci_config_t *phc, *next_phc; 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate /* 393*7c478bd9Sstevel@tonic-gate * Check for invalid VHCI 394*7c478bd9Sstevel@tonic-gate */ 395*7c478bd9Sstevel@tonic-gate if ((vh = i_devi_get_vhci(vdip)) == NULL) 396*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate /* 401*7c478bd9Sstevel@tonic-gate * Scan the list of registered vHCIs for a match 402*7c478bd9Sstevel@tonic-gate */ 403*7c478bd9Sstevel@tonic-gate for (found = mdi_vhci_head; found != NULL; found = found->vh_next) { 404*7c478bd9Sstevel@tonic-gate if (found == vh) 405*7c478bd9Sstevel@tonic-gate break; 406*7c478bd9Sstevel@tonic-gate prev = found; 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate if (found == NULL) { 410*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 411*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate /* 415*7c478bd9Sstevel@tonic-gate * Check the pHCI and client count. All the pHCIs and clients 416*7c478bd9Sstevel@tonic-gate * should have been unregistered, before a vHCI can be 417*7c478bd9Sstevel@tonic-gate * unregistered. 418*7c478bd9Sstevel@tonic-gate */ 419*7c478bd9Sstevel@tonic-gate if (vh->vh_phci_count || vh->vh_client_count) { 420*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 421*7c478bd9Sstevel@tonic-gate "!mdi_vhci_unregister: pHCI in registered state.\n")); 422*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 423*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 424*7c478bd9Sstevel@tonic-gate } 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate /* 427*7c478bd9Sstevel@tonic-gate * Remove the vHCI from the global list 428*7c478bd9Sstevel@tonic-gate */ 429*7c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_head) { 430*7c478bd9Sstevel@tonic-gate mdi_vhci_head = vh->vh_next; 431*7c478bd9Sstevel@tonic-gate } else { 432*7c478bd9Sstevel@tonic-gate prev->vh_next = vh->vh_next; 433*7c478bd9Sstevel@tonic-gate } 434*7c478bd9Sstevel@tonic-gate if (vh == mdi_vhci_tail) { 435*7c478bd9Sstevel@tonic-gate mdi_vhci_tail = prev; 436*7c478bd9Sstevel@tonic-gate } 437*7c478bd9Sstevel@tonic-gate 438*7c478bd9Sstevel@tonic-gate vh->vh_ops = NULL; 439*7c478bd9Sstevel@tonic-gate mdi_vhci_count--; 440*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 441*7c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_component &= ~MDI_COMPONENT_VHCI; 442*7c478bd9Sstevel@tonic-gate DEVI(vdip)->devi_mdi_xhci = NULL; 443*7c478bd9Sstevel@tonic-gate kmem_free(vh->vh_class, strlen(vh->vh_class)+1); 444*7c478bd9Sstevel@tonic-gate kmem_free(vh->vh_client_table, 445*7c478bd9Sstevel@tonic-gate mdi_client_table_size * sizeof (struct client_hash)); 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* 448*7c478bd9Sstevel@tonic-gate * there must be no more tasks on the bus config taskq as the vhci 449*7c478bd9Sstevel@tonic-gate * driver can not be detached while bus config is in progress. 450*7c478bd9Sstevel@tonic-gate */ 451*7c478bd9Sstevel@tonic-gate ASSERT(vh->vh_bus_config.vhc_start_time == 0); 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate if (vh->vh_bus_config.vhc_taskq != NULL) 454*7c478bd9Sstevel@tonic-gate taskq_destroy(vh->vh_bus_config.vhc_taskq); 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate for (phc = vh->vh_bus_config.vhc_phc; phc != NULL; phc = next_phc) { 457*7c478bd9Sstevel@tonic-gate next_phc = phc->phc_next; 458*7c478bd9Sstevel@tonic-gate kmem_free(phc, sizeof (*phc)); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate cv_destroy(&vh->vh_bus_config.vhc_cv); 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate kmem_free(vh, sizeof (mdi_vhci_t)); 464*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate /* 468*7c478bd9Sstevel@tonic-gate * i_mdi_vhci_class2vhci(): 469*7c478bd9Sstevel@tonic-gate * Look for a matching vHCI module given a vHCI class name 470*7c478bd9Sstevel@tonic-gate * Return Values: 471*7c478bd9Sstevel@tonic-gate * Handle to a vHCI component 472*7c478bd9Sstevel@tonic-gate * NULL 473*7c478bd9Sstevel@tonic-gate */ 474*7c478bd9Sstevel@tonic-gate static mdi_vhci_t * 475*7c478bd9Sstevel@tonic-gate i_mdi_vhci_class2vhci(char *class) 476*7c478bd9Sstevel@tonic-gate { 477*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&mdi_mutex)); 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 482*7c478bd9Sstevel@tonic-gate for (vh = mdi_vhci_head; vh != NULL; vh = vh->vh_next) { 483*7c478bd9Sstevel@tonic-gate if (strcmp(vh->vh_class, class) == 0) { 484*7c478bd9Sstevel@tonic-gate break; 485*7c478bd9Sstevel@tonic-gate } 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 488*7c478bd9Sstevel@tonic-gate return (vh); 489*7c478bd9Sstevel@tonic-gate } 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate /* 492*7c478bd9Sstevel@tonic-gate * i_devi_get_vhci(): 493*7c478bd9Sstevel@tonic-gate * Utility function to get the handle to a vHCI component 494*7c478bd9Sstevel@tonic-gate * Return Values: 495*7c478bd9Sstevel@tonic-gate * Handle to a vHCI component 496*7c478bd9Sstevel@tonic-gate * NULL 497*7c478bd9Sstevel@tonic-gate */ 498*7c478bd9Sstevel@tonic-gate mdi_vhci_t * 499*7c478bd9Sstevel@tonic-gate i_devi_get_vhci(dev_info_t *vdip) 500*7c478bd9Sstevel@tonic-gate { 501*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 502*7c478bd9Sstevel@tonic-gate if (MDI_VHCI(vdip)) { 503*7c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci; 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate return (vh); 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate /* 509*7c478bd9Sstevel@tonic-gate * mdi_phci_register(): 510*7c478bd9Sstevel@tonic-gate * Register a pHCI module with mpxio framework 511*7c478bd9Sstevel@tonic-gate * mdi_phci_register() is called by pHCI drivers to register with 512*7c478bd9Sstevel@tonic-gate * the mpxio framework and a specific 'class_driver' vHCI. The 513*7c478bd9Sstevel@tonic-gate * pHCI driver must call this interface as part of its attach(9e) 514*7c478bd9Sstevel@tonic-gate * handler. 515*7c478bd9Sstevel@tonic-gate * Return Values: 516*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 517*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 518*7c478bd9Sstevel@tonic-gate */ 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 521*7c478bd9Sstevel@tonic-gate int 522*7c478bd9Sstevel@tonic-gate mdi_phci_register(char *class, dev_info_t *pdip, int flags) 523*7c478bd9Sstevel@tonic-gate { 524*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 525*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 526*7c478bd9Sstevel@tonic-gate char *data; 527*7c478bd9Sstevel@tonic-gate char *pathname; 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 530*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, pathname); 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate /* 533*7c478bd9Sstevel@tonic-gate * Check for mpxio-disable property. Enable mpxio if the property is 534*7c478bd9Sstevel@tonic-gate * missing or not set to "yes". 535*7c478bd9Sstevel@tonic-gate * If the property is set to "yes" then emit a brief message. 536*7c478bd9Sstevel@tonic-gate */ 537*7c478bd9Sstevel@tonic-gate if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0, "mpxio-disable", 538*7c478bd9Sstevel@tonic-gate &data) == DDI_SUCCESS)) { 539*7c478bd9Sstevel@tonic-gate if (strcmp(data, "yes") == 0) { 540*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_CONT, pdip, 541*7c478bd9Sstevel@tonic-gate "?%s (%s%d) multipath capabilities " 542*7c478bd9Sstevel@tonic-gate "disabled via %s.conf.\n", pathname, 543*7c478bd9Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip), 544*7c478bd9Sstevel@tonic-gate ddi_driver_name(pdip))); 545*7c478bd9Sstevel@tonic-gate ddi_prop_free(data); 546*7c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 547*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate ddi_prop_free(data); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate /* 555*7c478bd9Sstevel@tonic-gate * Search for a matching vHCI 556*7c478bd9Sstevel@tonic-gate */ 557*7c478bd9Sstevel@tonic-gate vh = (mdi_vhci_t *)i_mdi_vhci_class2vhci(class); 558*7c478bd9Sstevel@tonic-gate if (vh == NULL) { 559*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate ph = kmem_zalloc(sizeof (mdi_phci_t), KM_SLEEP); 563*7c478bd9Sstevel@tonic-gate mutex_init(&ph->ph_mutex, NULL, MUTEX_DEFAULT, NULL); 564*7c478bd9Sstevel@tonic-gate ph->ph_dip = pdip; 565*7c478bd9Sstevel@tonic-gate ph->ph_vhci = vh; 566*7c478bd9Sstevel@tonic-gate ph->ph_next = NULL; 567*7c478bd9Sstevel@tonic-gate ph->ph_unstable = 0; 568*7c478bd9Sstevel@tonic-gate ph->ph_vprivate = 0; 569*7c478bd9Sstevel@tonic-gate cv_init(&ph->ph_unstable_cv, NULL, CV_DRIVER, NULL); 570*7c478bd9Sstevel@tonic-gate cv_init(&ph->ph_powerchange_cv, NULL, CV_DRIVER, NULL); 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_POWER_UP(ph); 573*7c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component |= MDI_COMPONENT_PHCI; 574*7c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = (caddr_t)ph; 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 577*7c478bd9Sstevel@tonic-gate if (vh->vh_phci_head == NULL) { 578*7c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph; 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate if (vh->vh_phci_tail) { 581*7c478bd9Sstevel@tonic-gate vh->vh_phci_tail->ph_next = ph; 582*7c478bd9Sstevel@tonic-gate } 583*7c478bd9Sstevel@tonic-gate vh->vh_phci_tail = ph; 584*7c478bd9Sstevel@tonic-gate vh->vh_phci_count++; 585*7c478bd9Sstevel@tonic-gate /* to force discovery of all phci children during busconfig */ 586*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_cutoff_time = -1; 587*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 588*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * mdi_phci_unregister(): 593*7c478bd9Sstevel@tonic-gate * Unregister a pHCI module from mpxio framework 594*7c478bd9Sstevel@tonic-gate * mdi_phci_unregister() is called by the pHCI drivers from their 595*7c478bd9Sstevel@tonic-gate * detach(9E) handler to unregister their instances from the 596*7c478bd9Sstevel@tonic-gate * framework. 597*7c478bd9Sstevel@tonic-gate * Return Values: 598*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 599*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 600*7c478bd9Sstevel@tonic-gate */ 601*7c478bd9Sstevel@tonic-gate 602*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 603*7c478bd9Sstevel@tonic-gate int 604*7c478bd9Sstevel@tonic-gate mdi_phci_unregister(dev_info_t *pdip, int flags) 605*7c478bd9Sstevel@tonic-gate { 606*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 607*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 608*7c478bd9Sstevel@tonic-gate mdi_phci_t *tmp; 609*7c478bd9Sstevel@tonic-gate mdi_phci_t *prev = NULL; 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 612*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 613*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 614*7c478bd9Sstevel@tonic-gate "!pHCI unregister: Not a valid pHCI")); 615*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 619*7c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 620*7c478bd9Sstevel@tonic-gate if (vh == NULL) { 621*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, pdip, 622*7c478bd9Sstevel@tonic-gate "!pHCI unregister: Not a valid vHCI")); 623*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 627*7c478bd9Sstevel@tonic-gate tmp = vh->vh_phci_head; 628*7c478bd9Sstevel@tonic-gate while (tmp) { 629*7c478bd9Sstevel@tonic-gate if (tmp == ph) { 630*7c478bd9Sstevel@tonic-gate break; 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate prev = tmp; 633*7c478bd9Sstevel@tonic-gate tmp = tmp->ph_next; 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_head) { 637*7c478bd9Sstevel@tonic-gate vh->vh_phci_head = ph->ph_next; 638*7c478bd9Sstevel@tonic-gate } else { 639*7c478bd9Sstevel@tonic-gate prev->ph_next = ph->ph_next; 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate if (ph == vh->vh_phci_tail) { 643*7c478bd9Sstevel@tonic-gate vh->vh_phci_tail = prev; 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate vh->vh_phci_count--; 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate /* 649*7c478bd9Sstevel@tonic-gate * If no busconfig is in progress, release the phci busconfig resources. 650*7c478bd9Sstevel@tonic-gate * We only need vh->vh_phci_count of busconfig resources. 651*7c478bd9Sstevel@tonic-gate */ 652*7c478bd9Sstevel@tonic-gate if (vh->vh_bus_config.vhc_start_time == 0 && 653*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc_cnt > vh->vh_phci_count) { 654*7c478bd9Sstevel@tonic-gate int count; 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate count = vh->vh_bus_config.vhc_phc_cnt - vh->vh_phci_count; 657*7c478bd9Sstevel@tonic-gate while (count--) { 658*7c478bd9Sstevel@tonic-gate mdi_phci_config_t *phc; 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate phc = vh->vh_bus_config.vhc_phc; 661*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc = phc->phc_next; 662*7c478bd9Sstevel@tonic-gate kmem_free(phc, sizeof (*phc)); 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc_cnt = vh->vh_phci_count; 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 668*7c478bd9Sstevel@tonic-gate 669*7c478bd9Sstevel@tonic-gate cv_destroy(&ph->ph_unstable_cv); 670*7c478bd9Sstevel@tonic-gate cv_destroy(&ph->ph_powerchange_cv); 671*7c478bd9Sstevel@tonic-gate mutex_destroy(&ph->ph_mutex); 672*7c478bd9Sstevel@tonic-gate kmem_free(ph, sizeof (mdi_phci_t)); 673*7c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_component &= ~MDI_COMPONENT_PHCI; 674*7c478bd9Sstevel@tonic-gate DEVI(pdip)->devi_mdi_xhci = NULL; 675*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 676*7c478bd9Sstevel@tonic-gate } 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate /* 679*7c478bd9Sstevel@tonic-gate * i_devi_get_phci(): 680*7c478bd9Sstevel@tonic-gate * Utility function to return the phci extensions. 681*7c478bd9Sstevel@tonic-gate */ 682*7c478bd9Sstevel@tonic-gate static mdi_phci_t * 683*7c478bd9Sstevel@tonic-gate i_devi_get_phci(dev_info_t *pdip) 684*7c478bd9Sstevel@tonic-gate { 685*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph = NULL; 686*7c478bd9Sstevel@tonic-gate if (MDI_PHCI(pdip)) { 687*7c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(pdip)->devi_mdi_xhci; 688*7c478bd9Sstevel@tonic-gate } 689*7c478bd9Sstevel@tonic-gate return (ph); 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* 693*7c478bd9Sstevel@tonic-gate * mdi_phci_path2devinfo(): 694*7c478bd9Sstevel@tonic-gate * Utility function to search for a valid phci device given 695*7c478bd9Sstevel@tonic-gate * the devfs pathname. 696*7c478bd9Sstevel@tonic-gate */ 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate dev_info_t * 699*7c478bd9Sstevel@tonic-gate mdi_phci_path2devinfo(dev_info_t *vdip, caddr_t pathname) 700*7c478bd9Sstevel@tonic-gate { 701*7c478bd9Sstevel@tonic-gate char *temp_pathname; 702*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 703*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 704*7c478bd9Sstevel@tonic-gate dev_info_t *pdip = NULL; 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate vh = i_devi_get_vhci(vdip); 707*7c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate if (vh == NULL) { 710*7c478bd9Sstevel@tonic-gate /* 711*7c478bd9Sstevel@tonic-gate * Invalid vHCI component, return failure 712*7c478bd9Sstevel@tonic-gate */ 713*7c478bd9Sstevel@tonic-gate return (NULL); 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 717*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 718*7c478bd9Sstevel@tonic-gate ph = vh->vh_phci_head; 719*7c478bd9Sstevel@tonic-gate while (ph != NULL) { 720*7c478bd9Sstevel@tonic-gate pdip = ph->ph_dip; 721*7c478bd9Sstevel@tonic-gate ASSERT(pdip != NULL); 722*7c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 723*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(pdip, temp_pathname); 724*7c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 725*7c478bd9Sstevel@tonic-gate break; 726*7c478bd9Sstevel@tonic-gate } 727*7c478bd9Sstevel@tonic-gate ph = ph->ph_next; 728*7c478bd9Sstevel@tonic-gate } 729*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 730*7c478bd9Sstevel@tonic-gate pdip = NULL; 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 733*7c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 734*7c478bd9Sstevel@tonic-gate return (pdip); 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate /* 738*7c478bd9Sstevel@tonic-gate * mdi_phci_get_path_count(): 739*7c478bd9Sstevel@tonic-gate * get number of path information nodes associated with a given 740*7c478bd9Sstevel@tonic-gate * pHCI device. 741*7c478bd9Sstevel@tonic-gate */ 742*7c478bd9Sstevel@tonic-gate int 743*7c478bd9Sstevel@tonic-gate mdi_phci_get_path_count(dev_info_t *pdip) 744*7c478bd9Sstevel@tonic-gate { 745*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 746*7c478bd9Sstevel@tonic-gate int count = 0; 747*7c478bd9Sstevel@tonic-gate 748*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 749*7c478bd9Sstevel@tonic-gate if (ph != NULL) { 750*7c478bd9Sstevel@tonic-gate count = ph->ph_path_count; 751*7c478bd9Sstevel@tonic-gate } 752*7c478bd9Sstevel@tonic-gate return (count); 753*7c478bd9Sstevel@tonic-gate } 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate /* 756*7c478bd9Sstevel@tonic-gate * i_mdi_phci_lock(): 757*7c478bd9Sstevel@tonic-gate * Lock a pHCI device 758*7c478bd9Sstevel@tonic-gate * Return Values: 759*7c478bd9Sstevel@tonic-gate * None 760*7c478bd9Sstevel@tonic-gate * Note: 761*7c478bd9Sstevel@tonic-gate * The default locking order is: 762*7c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_pathinfo::pi_mutex)) 763*7c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 764*7c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 765*7c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 766*7c478bd9Sstevel@tonic-gate */ 767*7c478bd9Sstevel@tonic-gate static void 768*7c478bd9Sstevel@tonic-gate i_mdi_phci_lock(mdi_phci_t *ph, mdi_pathinfo_t *pip) 769*7c478bd9Sstevel@tonic-gate { 770*7c478bd9Sstevel@tonic-gate if (pip) { 771*7c478bd9Sstevel@tonic-gate /* Reverse locking is requested. */ 772*7c478bd9Sstevel@tonic-gate while (MDI_PHCI_TRYLOCK(ph) == 0) { 773*7c478bd9Sstevel@tonic-gate /* 774*7c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 775*7c478bd9Sstevel@tonic-gate * after a small delay 776*7c478bd9Sstevel@tonic-gate */ 777*7c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 778*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 779*7c478bd9Sstevel@tonic-gate delay(1); 780*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 781*7c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 782*7c478bd9Sstevel@tonic-gate } 783*7c478bd9Sstevel@tonic-gate } else { 784*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 785*7c478bd9Sstevel@tonic-gate } 786*7c478bd9Sstevel@tonic-gate } 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate /* 789*7c478bd9Sstevel@tonic-gate * i_mdi_phci_get_client_lock(): 790*7c478bd9Sstevel@tonic-gate * Lock a pHCI device 791*7c478bd9Sstevel@tonic-gate * Return Values: 792*7c478bd9Sstevel@tonic-gate * None 793*7c478bd9Sstevel@tonic-gate * Note: 794*7c478bd9Sstevel@tonic-gate * The default locking order is: 795*7c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_phci::ph_mutex mdi_client::ct_mutex)) 796*7c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 797*7c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 798*7c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 799*7c478bd9Sstevel@tonic-gate */ 800*7c478bd9Sstevel@tonic-gate static void 801*7c478bd9Sstevel@tonic-gate i_mdi_phci_get_client_lock(mdi_phci_t *ph, mdi_client_t *ct) 802*7c478bd9Sstevel@tonic-gate { 803*7c478bd9Sstevel@tonic-gate if (ct) { 804*7c478bd9Sstevel@tonic-gate /* Reverse locking is requested. */ 805*7c478bd9Sstevel@tonic-gate while (MDI_PHCI_TRYLOCK(ph) == 0) { 806*7c478bd9Sstevel@tonic-gate /* 807*7c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 808*7c478bd9Sstevel@tonic-gate * after a small delay 809*7c478bd9Sstevel@tonic-gate */ 810*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 811*7c478bd9Sstevel@tonic-gate delay(1); 812*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate } else { 815*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 816*7c478bd9Sstevel@tonic-gate } 817*7c478bd9Sstevel@tonic-gate } 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate /* 820*7c478bd9Sstevel@tonic-gate * i_mdi_phci_unlock(): 821*7c478bd9Sstevel@tonic-gate * Unlock the pHCI component 822*7c478bd9Sstevel@tonic-gate */ 823*7c478bd9Sstevel@tonic-gate static void 824*7c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(mdi_phci_t *ph) 825*7c478bd9Sstevel@tonic-gate { 826*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 827*7c478bd9Sstevel@tonic-gate } 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate /* 830*7c478bd9Sstevel@tonic-gate * i_mdi_devinfo_create(): 831*7c478bd9Sstevel@tonic-gate * create client device's devinfo node 832*7c478bd9Sstevel@tonic-gate * Return Values: 833*7c478bd9Sstevel@tonic-gate * dev_info 834*7c478bd9Sstevel@tonic-gate * NULL 835*7c478bd9Sstevel@tonic-gate * Notes: 836*7c478bd9Sstevel@tonic-gate */ 837*7c478bd9Sstevel@tonic-gate static dev_info_t * 838*7c478bd9Sstevel@tonic-gate i_mdi_devinfo_create(mdi_vhci_t *vh, char *name, char *guid, 839*7c478bd9Sstevel@tonic-gate char **compatible, int ncompatible, int flags) 840*7c478bd9Sstevel@tonic-gate { 841*7c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate /* Verify for duplicate entry */ 846*7c478bd9Sstevel@tonic-gate cdip = i_mdi_devinfo_find(vh, name, guid); 847*7c478bd9Sstevel@tonic-gate ASSERT(cdip == NULL); 848*7c478bd9Sstevel@tonic-gate if (cdip) { 849*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 850*7c478bd9Sstevel@tonic-gate "i_mdi_devinfo_create: client dip %p already exists", 851*7c478bd9Sstevel@tonic-gate (void *)cdip); 852*7c478bd9Sstevel@tonic-gate } 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate if (flags == DDI_SLEEP) { 855*7c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(vh->vh_dip, name, 856*7c478bd9Sstevel@tonic-gate DEVI_SID_NODEID, &cdip); 857*7c478bd9Sstevel@tonic-gate } else { 858*7c478bd9Sstevel@tonic-gate (void) ndi_devi_alloc(vh->vh_dip, name, 859*7c478bd9Sstevel@tonic-gate DEVI_SID_NODEID, &cdip); 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate if (cdip == NULL) 862*7c478bd9Sstevel@tonic-gate goto fail; 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate /* 865*7c478bd9Sstevel@tonic-gate * Create component type and Global unique identifier 866*7c478bd9Sstevel@tonic-gate * properties 867*7c478bd9Sstevel@tonic-gate */ 868*7c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, 869*7c478bd9Sstevel@tonic-gate MDI_CLIENT_GUID_PROP, guid) != DDI_PROP_SUCCESS) { 870*7c478bd9Sstevel@tonic-gate goto fail; 871*7c478bd9Sstevel@tonic-gate } 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate /* Decorate the node with compatible property */ 874*7c478bd9Sstevel@tonic-gate if (compatible && 875*7c478bd9Sstevel@tonic-gate (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip, 876*7c478bd9Sstevel@tonic-gate "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS)) { 877*7c478bd9Sstevel@tonic-gate goto fail; 878*7c478bd9Sstevel@tonic-gate } 879*7c478bd9Sstevel@tonic-gate 880*7c478bd9Sstevel@tonic-gate return (cdip); 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate fail: 883*7c478bd9Sstevel@tonic-gate if (cdip) { 884*7c478bd9Sstevel@tonic-gate (void) ndi_prop_remove_all(cdip); 885*7c478bd9Sstevel@tonic-gate (void) ndi_devi_free(cdip); 886*7c478bd9Sstevel@tonic-gate } 887*7c478bd9Sstevel@tonic-gate return (NULL); 888*7c478bd9Sstevel@tonic-gate } 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate /* 891*7c478bd9Sstevel@tonic-gate * i_mdi_devinfo_find(): 892*7c478bd9Sstevel@tonic-gate * Find a matching devinfo node for given client node name 893*7c478bd9Sstevel@tonic-gate * and its guid. 894*7c478bd9Sstevel@tonic-gate * Return Values: 895*7c478bd9Sstevel@tonic-gate * Handle to a dev_info node or NULL 896*7c478bd9Sstevel@tonic-gate */ 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate static dev_info_t * 899*7c478bd9Sstevel@tonic-gate i_mdi_devinfo_find(mdi_vhci_t *vh, caddr_t name, char *guid) 900*7c478bd9Sstevel@tonic-gate { 901*7c478bd9Sstevel@tonic-gate char *data; 902*7c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 903*7c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 904*7c478bd9Sstevel@tonic-gate int circular; 905*7c478bd9Sstevel@tonic-gate 906*7c478bd9Sstevel@tonic-gate ndi_devi_enter(vh->vh_dip, &circular); 907*7c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vh->vh_dip)->devi_child; 908*7c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 909*7c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate if (strcmp(DEVI(cdip)->devi_node_name, name)) { 912*7c478bd9Sstevel@tonic-gate continue; 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip, 916*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, MDI_CLIENT_GUID_PROP, 917*7c478bd9Sstevel@tonic-gate &data) != DDI_PROP_SUCCESS) { 918*7c478bd9Sstevel@tonic-gate continue; 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate if (strcmp(data, guid) != 0) { 922*7c478bd9Sstevel@tonic-gate ddi_prop_free(data); 923*7c478bd9Sstevel@tonic-gate continue; 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate ddi_prop_free(data); 926*7c478bd9Sstevel@tonic-gate break; 927*7c478bd9Sstevel@tonic-gate } 928*7c478bd9Sstevel@tonic-gate ndi_devi_exit(vh->vh_dip, circular); 929*7c478bd9Sstevel@tonic-gate return (cdip); 930*7c478bd9Sstevel@tonic-gate } 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate /* 933*7c478bd9Sstevel@tonic-gate * i_mdi_devinfo_remove(): 934*7c478bd9Sstevel@tonic-gate * Remove a client device node 935*7c478bd9Sstevel@tonic-gate */ 936*7c478bd9Sstevel@tonic-gate static int 937*7c478bd9Sstevel@tonic-gate i_mdi_devinfo_remove(dev_info_t *vdip, dev_info_t *cdip, int flags) 938*7c478bd9Sstevel@tonic-gate { 939*7c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 940*7c478bd9Sstevel@tonic-gate if (i_mdi_is_child_present(vdip, cdip) == MDI_SUCCESS || 941*7c478bd9Sstevel@tonic-gate (flags & MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED)) { 942*7c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, NDI_DEVI_REMOVE); 943*7c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 944*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_devinfo_remove:" 945*7c478bd9Sstevel@tonic-gate " failed. cdip = %p\n", cdip)); 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate /* 948*7c478bd9Sstevel@tonic-gate * Convert to MDI error code 949*7c478bd9Sstevel@tonic-gate */ 950*7c478bd9Sstevel@tonic-gate switch (rv) { 951*7c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 952*7c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 953*7c478bd9Sstevel@tonic-gate break; 954*7c478bd9Sstevel@tonic-gate case NDI_BUSY: 955*7c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 956*7c478bd9Sstevel@tonic-gate break; 957*7c478bd9Sstevel@tonic-gate default: 958*7c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 959*7c478bd9Sstevel@tonic-gate break; 960*7c478bd9Sstevel@tonic-gate } 961*7c478bd9Sstevel@tonic-gate } 962*7c478bd9Sstevel@tonic-gate return (rv); 963*7c478bd9Sstevel@tonic-gate } 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate /* 966*7c478bd9Sstevel@tonic-gate * i_devi_get_client() 967*7c478bd9Sstevel@tonic-gate * Utility function to get mpxio component extensions 968*7c478bd9Sstevel@tonic-gate */ 969*7c478bd9Sstevel@tonic-gate static mdi_client_t * 970*7c478bd9Sstevel@tonic-gate i_devi_get_client(dev_info_t *cdip) 971*7c478bd9Sstevel@tonic-gate { 972*7c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 973*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT(cdip)) { 974*7c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(cdip)->devi_mdi_client; 975*7c478bd9Sstevel@tonic-gate } 976*7c478bd9Sstevel@tonic-gate return (ct); 977*7c478bd9Sstevel@tonic-gate } 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate /* 980*7c478bd9Sstevel@tonic-gate * i_mdi_is_child_present(): 981*7c478bd9Sstevel@tonic-gate * Search for the presence of client device dev_info node 982*7c478bd9Sstevel@tonic-gate */ 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate static int 985*7c478bd9Sstevel@tonic-gate i_mdi_is_child_present(dev_info_t *vdip, dev_info_t *cdip) 986*7c478bd9Sstevel@tonic-gate { 987*7c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 988*7c478bd9Sstevel@tonic-gate struct dev_info *dip; 989*7c478bd9Sstevel@tonic-gate int circular; 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 992*7c478bd9Sstevel@tonic-gate dip = DEVI(vdip)->devi_child; 993*7c478bd9Sstevel@tonic-gate while (dip) { 994*7c478bd9Sstevel@tonic-gate if (dip == DEVI(cdip)) { 995*7c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 996*7c478bd9Sstevel@tonic-gate break; 997*7c478bd9Sstevel@tonic-gate } 998*7c478bd9Sstevel@tonic-gate dip = dip->devi_sibling; 999*7c478bd9Sstevel@tonic-gate } 1000*7c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 1001*7c478bd9Sstevel@tonic-gate return (rv); 1002*7c478bd9Sstevel@tonic-gate } 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate 1005*7c478bd9Sstevel@tonic-gate /* 1006*7c478bd9Sstevel@tonic-gate * i_mdi_client_lock(): 1007*7c478bd9Sstevel@tonic-gate * Grab client component lock 1008*7c478bd9Sstevel@tonic-gate * Return Values: 1009*7c478bd9Sstevel@tonic-gate * None 1010*7c478bd9Sstevel@tonic-gate * Note: 1011*7c478bd9Sstevel@tonic-gate * The default locking order is: 1012*7c478bd9Sstevel@tonic-gate * _NOTE(LOCK_ORDER(mdi_client::ct_mutex mdi_pathinfo::pi_mutex)) 1013*7c478bd9Sstevel@tonic-gate * But there are number of situations where locks need to be 1014*7c478bd9Sstevel@tonic-gate * grabbed in reverse order. This routine implements try and lock 1015*7c478bd9Sstevel@tonic-gate * mechanism depending on the requested parameter option. 1016*7c478bd9Sstevel@tonic-gate */ 1017*7c478bd9Sstevel@tonic-gate 1018*7c478bd9Sstevel@tonic-gate static void 1019*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(mdi_client_t *ct, mdi_pathinfo_t *pip) 1020*7c478bd9Sstevel@tonic-gate { 1021*7c478bd9Sstevel@tonic-gate if (pip) { 1022*7c478bd9Sstevel@tonic-gate /* 1023*7c478bd9Sstevel@tonic-gate * Reverse locking is requested. 1024*7c478bd9Sstevel@tonic-gate */ 1025*7c478bd9Sstevel@tonic-gate while (MDI_CLIENT_TRYLOCK(ct) == 0) { 1026*7c478bd9Sstevel@tonic-gate /* 1027*7c478bd9Sstevel@tonic-gate * tryenter failed. Try to grab again 1028*7c478bd9Sstevel@tonic-gate * after a small delay 1029*7c478bd9Sstevel@tonic-gate */ 1030*7c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 1031*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 1032*7c478bd9Sstevel@tonic-gate delay(1); 1033*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 1034*7c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 1035*7c478bd9Sstevel@tonic-gate } 1036*7c478bd9Sstevel@tonic-gate } else { 1037*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 1038*7c478bd9Sstevel@tonic-gate } 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate /* 1042*7c478bd9Sstevel@tonic-gate * i_mdi_client_unlock(): 1043*7c478bd9Sstevel@tonic-gate * Unlock a client component 1044*7c478bd9Sstevel@tonic-gate */ 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate static void 1047*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(mdi_client_t *ct) 1048*7c478bd9Sstevel@tonic-gate { 1049*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1050*7c478bd9Sstevel@tonic-gate } 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate /* 1053*7c478bd9Sstevel@tonic-gate * i_mdi_client_alloc(): 1054*7c478bd9Sstevel@tonic-gate * Allocate and initialize a client structure. Caller should 1055*7c478bd9Sstevel@tonic-gate * hold the global mdi_mutex. 1056*7c478bd9Sstevel@tonic-gate * Return Values: 1057*7c478bd9Sstevel@tonic-gate * Handle to a client component 1058*7c478bd9Sstevel@tonic-gate */ 1059*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1060*7c478bd9Sstevel@tonic-gate static mdi_client_t * 1061*7c478bd9Sstevel@tonic-gate i_mdi_client_alloc(mdi_vhci_t *vh, char *name, char *lguid, int flags) 1062*7c478bd9Sstevel@tonic-gate { 1063*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 1064*7c478bd9Sstevel@tonic-gate char *drvname = NULL; 1065*7c478bd9Sstevel@tonic-gate char *guid = NULL; 1066*7c478bd9Sstevel@tonic-gate client_lb_args_t *lb_args = NULL; 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate /* 1071*7c478bd9Sstevel@tonic-gate * Allocate and initialize a component structure. 1072*7c478bd9Sstevel@tonic-gate */ 1073*7c478bd9Sstevel@tonic-gate ct = kmem_zalloc(sizeof (*ct), 1074*7c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 1075*7c478bd9Sstevel@tonic-gate if (ct == NULL) 1076*7c478bd9Sstevel@tonic-gate goto fail; 1077*7c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); 1078*7c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 1079*7c478bd9Sstevel@tonic-gate ct->ct_hprev = NULL; 1080*7c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 1081*7c478bd9Sstevel@tonic-gate ct->ct_vhci = vh; 1082*7c478bd9Sstevel@tonic-gate drvname = kmem_alloc(strlen(name) + 1, 1083*7c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 1084*7c478bd9Sstevel@tonic-gate if (drvname == NULL) 1085*7c478bd9Sstevel@tonic-gate goto fail; 1086*7c478bd9Sstevel@tonic-gate ct->ct_drvname = drvname; 1087*7c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_drvname, name); 1088*7c478bd9Sstevel@tonic-gate guid = kmem_alloc(strlen(lguid) + 1, 1089*7c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 1090*7c478bd9Sstevel@tonic-gate if (guid == NULL) 1091*7c478bd9Sstevel@tonic-gate goto fail; 1092*7c478bd9Sstevel@tonic-gate ct->ct_guid = guid; 1093*7c478bd9Sstevel@tonic-gate (void) strcpy(ct->ct_guid, lguid); 1094*7c478bd9Sstevel@tonic-gate ct->ct_cprivate = NULL; 1095*7c478bd9Sstevel@tonic-gate ct->ct_vprivate = NULL; 1096*7c478bd9Sstevel@tonic-gate ct->ct_flags = 0; 1097*7c478bd9Sstevel@tonic-gate ct->ct_state = MDI_CLIENT_STATE_FAILED; 1098*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 1099*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 1100*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 1101*7c478bd9Sstevel@tonic-gate ct->ct_failover_flags = 0; 1102*7c478bd9Sstevel@tonic-gate ct->ct_failover_status = 0; 1103*7c478bd9Sstevel@tonic-gate cv_init(&ct->ct_failover_cv, NULL, CV_DRIVER, NULL); 1104*7c478bd9Sstevel@tonic-gate ct->ct_unstable = 0; 1105*7c478bd9Sstevel@tonic-gate cv_init(&ct->ct_unstable_cv, NULL, CV_DRIVER, NULL); 1106*7c478bd9Sstevel@tonic-gate cv_init(&ct->ct_powerchange_cv, NULL, CV_DRIVER, NULL); 1107*7c478bd9Sstevel@tonic-gate ct->ct_lb = vh->vh_lb; 1108*7c478bd9Sstevel@tonic-gate lb_args = kmem_zalloc(sizeof (client_lb_args_t), 1109*7c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 1110*7c478bd9Sstevel@tonic-gate if (lb_args == NULL) 1111*7c478bd9Sstevel@tonic-gate goto fail; 1112*7c478bd9Sstevel@tonic-gate ct->ct_lb_args = lb_args; 1113*7c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = LOAD_BALANCE_DEFAULT_REGION_SIZE; 1114*7c478bd9Sstevel@tonic-gate ct->ct_path_count = 0; 1115*7c478bd9Sstevel@tonic-gate ct->ct_path_head = NULL; 1116*7c478bd9Sstevel@tonic-gate ct->ct_path_tail = NULL; 1117*7c478bd9Sstevel@tonic-gate ct->ct_path_last = NULL; 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate /* 1121*7c478bd9Sstevel@tonic-gate * Add this client component to our client hash queue 1122*7c478bd9Sstevel@tonic-gate */ 1123*7c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(vh, ct); 1124*7c478bd9Sstevel@tonic-gate return (ct); 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate fail: 1127*7c478bd9Sstevel@tonic-gate if (guid) 1128*7c478bd9Sstevel@tonic-gate kmem_free(guid, strlen(lguid) + 1); 1129*7c478bd9Sstevel@tonic-gate if (drvname) 1130*7c478bd9Sstevel@tonic-gate kmem_free(drvname, strlen(name) + 1); 1131*7c478bd9Sstevel@tonic-gate if (lb_args) 1132*7c478bd9Sstevel@tonic-gate kmem_free(lb_args, sizeof (client_lb_args_t)); 1133*7c478bd9Sstevel@tonic-gate kmem_free(ct, sizeof (*ct)); 1134*7c478bd9Sstevel@tonic-gate return (NULL); 1135*7c478bd9Sstevel@tonic-gate } 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate /* 1138*7c478bd9Sstevel@tonic-gate * i_mdi_client_enlist_table(): 1139*7c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. Caller 1140*7c478bd9Sstevel@tonic-gate * should hold the mdi_mutex 1141*7c478bd9Sstevel@tonic-gate */ 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate static void 1144*7c478bd9Sstevel@tonic-gate i_mdi_client_enlist_table(mdi_vhci_t *vh, mdi_client_t *ct) 1145*7c478bd9Sstevel@tonic-gate { 1146*7c478bd9Sstevel@tonic-gate int index; 1147*7c478bd9Sstevel@tonic-gate struct client_hash *head; 1148*7c478bd9Sstevel@tonic-gate 1149*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 1150*7c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(ct->ct_guid); 1151*7c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 1152*7c478bd9Sstevel@tonic-gate ct->ct_hnext = (mdi_client_t *)head->ct_hash_head; 1153*7c478bd9Sstevel@tonic-gate head->ct_hash_head = ct; 1154*7c478bd9Sstevel@tonic-gate head->ct_hash_count++; 1155*7c478bd9Sstevel@tonic-gate vh->vh_client_count++; 1156*7c478bd9Sstevel@tonic-gate } 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate /* 1159*7c478bd9Sstevel@tonic-gate * i_mdi_client_delist_table(): 1160*7c478bd9Sstevel@tonic-gate * Attach the client device to the client hash table. 1161*7c478bd9Sstevel@tonic-gate * Caller should hold the mdi_mutex 1162*7c478bd9Sstevel@tonic-gate */ 1163*7c478bd9Sstevel@tonic-gate 1164*7c478bd9Sstevel@tonic-gate static void 1165*7c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(mdi_vhci_t *vh, mdi_client_t *ct) 1166*7c478bd9Sstevel@tonic-gate { 1167*7c478bd9Sstevel@tonic-gate int index; 1168*7c478bd9Sstevel@tonic-gate char *guid; 1169*7c478bd9Sstevel@tonic-gate struct client_hash *head; 1170*7c478bd9Sstevel@tonic-gate mdi_client_t *next; 1171*7c478bd9Sstevel@tonic-gate mdi_client_t *last; 1172*7c478bd9Sstevel@tonic-gate 1173*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 1174*7c478bd9Sstevel@tonic-gate guid = ct->ct_guid; 1175*7c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 1176*7c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 1177*7c478bd9Sstevel@tonic-gate 1178*7c478bd9Sstevel@tonic-gate last = NULL; 1179*7c478bd9Sstevel@tonic-gate next = (mdi_client_t *)head->ct_hash_head; 1180*7c478bd9Sstevel@tonic-gate while (next != NULL) { 1181*7c478bd9Sstevel@tonic-gate if (next == ct) { 1182*7c478bd9Sstevel@tonic-gate break; 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate last = next; 1185*7c478bd9Sstevel@tonic-gate next = next->ct_hnext; 1186*7c478bd9Sstevel@tonic-gate } 1187*7c478bd9Sstevel@tonic-gate 1188*7c478bd9Sstevel@tonic-gate if (next) { 1189*7c478bd9Sstevel@tonic-gate head->ct_hash_count--; 1190*7c478bd9Sstevel@tonic-gate if (last == NULL) { 1191*7c478bd9Sstevel@tonic-gate head->ct_hash_head = ct->ct_hnext; 1192*7c478bd9Sstevel@tonic-gate } else { 1193*7c478bd9Sstevel@tonic-gate last->ct_hnext = ct->ct_hnext; 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate ct->ct_hnext = NULL; 1196*7c478bd9Sstevel@tonic-gate vh->vh_client_count--; 1197*7c478bd9Sstevel@tonic-gate } 1198*7c478bd9Sstevel@tonic-gate } 1199*7c478bd9Sstevel@tonic-gate 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate /* 1202*7c478bd9Sstevel@tonic-gate * i_mdi_client_free(): 1203*7c478bd9Sstevel@tonic-gate * Free a client component 1204*7c478bd9Sstevel@tonic-gate */ 1205*7c478bd9Sstevel@tonic-gate static int 1206*7c478bd9Sstevel@tonic-gate i_mdi_client_free(mdi_vhci_t *vh, mdi_client_t *ct) 1207*7c478bd9Sstevel@tonic-gate { 1208*7c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 1209*7c478bd9Sstevel@tonic-gate int flags = ct->ct_flags; 1210*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 1211*7c478bd9Sstevel@tonic-gate dev_info_t *vdip; 1212*7c478bd9Sstevel@tonic-gate 1213*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 1214*7c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 1215*7c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 1216*7c478bd9Sstevel@tonic-gate 1217*7c478bd9Sstevel@tonic-gate (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, MDI_CLIENT_GUID_PROP); 1218*7c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component &= ~MDI_COMPONENT_CLIENT; 1219*7c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = NULL; 1220*7c478bd9Sstevel@tonic-gate 1221*7c478bd9Sstevel@tonic-gate /* 1222*7c478bd9Sstevel@tonic-gate * Clear out back ref. to dev_info_t node 1223*7c478bd9Sstevel@tonic-gate */ 1224*7c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 1225*7c478bd9Sstevel@tonic-gate 1226*7c478bd9Sstevel@tonic-gate /* 1227*7c478bd9Sstevel@tonic-gate * Remove this client from our hash queue 1228*7c478bd9Sstevel@tonic-gate */ 1229*7c478bd9Sstevel@tonic-gate i_mdi_client_delist_table(vh, ct); 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate /* 1232*7c478bd9Sstevel@tonic-gate * Uninitialize and free the component 1233*7c478bd9Sstevel@tonic-gate */ 1234*7c478bd9Sstevel@tonic-gate kmem_free(ct->ct_drvname, strlen(ct->ct_drvname) + 1); 1235*7c478bd9Sstevel@tonic-gate kmem_free(ct->ct_guid, strlen(ct->ct_guid) + 1); 1236*7c478bd9Sstevel@tonic-gate kmem_free(ct->ct_lb_args, sizeof (client_lb_args_t)); 1237*7c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_failover_cv); 1238*7c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_unstable_cv); 1239*7c478bd9Sstevel@tonic-gate cv_destroy(&ct->ct_powerchange_cv); 1240*7c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_mutex); 1241*7c478bd9Sstevel@tonic-gate kmem_free(ct, sizeof (*ct)); 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate if (cdip != NULL) { 1244*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 1245*7c478bd9Sstevel@tonic-gate (void) i_mdi_devinfo_remove(vdip, cdip, flags); 1246*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 1247*7c478bd9Sstevel@tonic-gate } 1248*7c478bd9Sstevel@tonic-gate return (rv); 1249*7c478bd9Sstevel@tonic-gate } 1250*7c478bd9Sstevel@tonic-gate 1251*7c478bd9Sstevel@tonic-gate /* 1252*7c478bd9Sstevel@tonic-gate * i_mdi_client_find(): 1253*7c478bd9Sstevel@tonic-gate * Find the client structure corresponding to a given guid 1254*7c478bd9Sstevel@tonic-gate * Caller should hold the mdi_mutex 1255*7c478bd9Sstevel@tonic-gate */ 1256*7c478bd9Sstevel@tonic-gate static mdi_client_t * 1257*7c478bd9Sstevel@tonic-gate i_mdi_client_find(mdi_vhci_t *vh, char *guid) 1258*7c478bd9Sstevel@tonic-gate { 1259*7c478bd9Sstevel@tonic-gate int index; 1260*7c478bd9Sstevel@tonic-gate struct client_hash *head; 1261*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 1262*7c478bd9Sstevel@tonic-gate 1263*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mdi_mutex)); 1264*7c478bd9Sstevel@tonic-gate index = i_mdi_get_hash_key(guid); 1265*7c478bd9Sstevel@tonic-gate head = &vh->vh_client_table[index]; 1266*7c478bd9Sstevel@tonic-gate 1267*7c478bd9Sstevel@tonic-gate ct = head->ct_hash_head; 1268*7c478bd9Sstevel@tonic-gate while (ct != NULL) { 1269*7c478bd9Sstevel@tonic-gate if (strcmp(ct->ct_guid, guid) == 0) { 1270*7c478bd9Sstevel@tonic-gate break; 1271*7c478bd9Sstevel@tonic-gate } 1272*7c478bd9Sstevel@tonic-gate ct = ct->ct_hnext; 1273*7c478bd9Sstevel@tonic-gate } 1274*7c478bd9Sstevel@tonic-gate return (ct); 1275*7c478bd9Sstevel@tonic-gate } 1276*7c478bd9Sstevel@tonic-gate 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate /* 1280*7c478bd9Sstevel@tonic-gate * i_mdi_client_update_state(): 1281*7c478bd9Sstevel@tonic-gate * Compute and update client device state 1282*7c478bd9Sstevel@tonic-gate * Notes: 1283*7c478bd9Sstevel@tonic-gate * A client device can be in any of three possible states: 1284*7c478bd9Sstevel@tonic-gate * 1285*7c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_OPTIMAL - Client in optimal state with more 1286*7c478bd9Sstevel@tonic-gate * one online/standby paths. Can tolerate failures. 1287*7c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_DEGRADED - Client device in degraded state with 1288*7c478bd9Sstevel@tonic-gate * no alternate paths available as standby. A failure on the online 1289*7c478bd9Sstevel@tonic-gate * would result in loss of access to device data. 1290*7c478bd9Sstevel@tonic-gate * MDI_CLIENT_STATE_FAILED - Client device in failed state with 1291*7c478bd9Sstevel@tonic-gate * no paths available to access the device. 1292*7c478bd9Sstevel@tonic-gate */ 1293*7c478bd9Sstevel@tonic-gate static void 1294*7c478bd9Sstevel@tonic-gate i_mdi_client_update_state(mdi_client_t *ct) 1295*7c478bd9Sstevel@tonic-gate { 1296*7c478bd9Sstevel@tonic-gate int state; 1297*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_mutex)); 1298*7c478bd9Sstevel@tonic-gate state = i_mdi_client_compute_state(ct, NULL); 1299*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_STATE(ct, state); 1300*7c478bd9Sstevel@tonic-gate } 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate /* 1303*7c478bd9Sstevel@tonic-gate * i_mdi_client_compute_state(): 1304*7c478bd9Sstevel@tonic-gate * Compute client device state 1305*7c478bd9Sstevel@tonic-gate * 1306*7c478bd9Sstevel@tonic-gate * mdi_phci_t * Pointer to pHCI structure which should 1307*7c478bd9Sstevel@tonic-gate * while computing the new value. Used by 1308*7c478bd9Sstevel@tonic-gate * i_mdi_phci_offline() to find the new 1309*7c478bd9Sstevel@tonic-gate * client state after DR of a pHCI. 1310*7c478bd9Sstevel@tonic-gate */ 1311*7c478bd9Sstevel@tonic-gate static int 1312*7c478bd9Sstevel@tonic-gate i_mdi_client_compute_state(mdi_client_t *ct, mdi_phci_t *ph) 1313*7c478bd9Sstevel@tonic-gate { 1314*7c478bd9Sstevel@tonic-gate int state; 1315*7c478bd9Sstevel@tonic-gate int online_count = 0; 1316*7c478bd9Sstevel@tonic-gate int standby_count = 0; 1317*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_mutex)); 1320*7c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 1321*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 1322*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 1323*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 1324*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 1325*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 1326*7c478bd9Sstevel@tonic-gate pip = next; 1327*7c478bd9Sstevel@tonic-gate continue; 1328*7c478bd9Sstevel@tonic-gate } 1329*7c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 1330*7c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_ONLINE) 1331*7c478bd9Sstevel@tonic-gate online_count++; 1332*7c478bd9Sstevel@tonic-gate else if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 1333*7c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_STANDBY) 1334*7c478bd9Sstevel@tonic-gate standby_count++; 1335*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 1336*7c478bd9Sstevel@tonic-gate pip = next; 1337*7c478bd9Sstevel@tonic-gate } 1338*7c478bd9Sstevel@tonic-gate 1339*7c478bd9Sstevel@tonic-gate if (online_count == 0) { 1340*7c478bd9Sstevel@tonic-gate if (standby_count == 0) { 1341*7c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_FAILED; 1342*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!client state: failed" 1343*7c478bd9Sstevel@tonic-gate " ct = %p\n", ct)); 1344*7c478bd9Sstevel@tonic-gate } else if (standby_count == 1) { 1345*7c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 1346*7c478bd9Sstevel@tonic-gate } else { 1347*7c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 1348*7c478bd9Sstevel@tonic-gate } 1349*7c478bd9Sstevel@tonic-gate } else if (online_count == 1) { 1350*7c478bd9Sstevel@tonic-gate if (standby_count == 0) { 1351*7c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_DEGRADED; 1352*7c478bd9Sstevel@tonic-gate } else { 1353*7c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 1354*7c478bd9Sstevel@tonic-gate } 1355*7c478bd9Sstevel@tonic-gate } else { 1356*7c478bd9Sstevel@tonic-gate state = MDI_CLIENT_STATE_OPTIMAL; 1357*7c478bd9Sstevel@tonic-gate } 1358*7c478bd9Sstevel@tonic-gate return (state); 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate /* 1362*7c478bd9Sstevel@tonic-gate * i_mdi_client2devinfo(): 1363*7c478bd9Sstevel@tonic-gate * Utility function 1364*7c478bd9Sstevel@tonic-gate */ 1365*7c478bd9Sstevel@tonic-gate dev_info_t * 1366*7c478bd9Sstevel@tonic-gate i_mdi_client2devinfo(mdi_client_t *ct) 1367*7c478bd9Sstevel@tonic-gate { 1368*7c478bd9Sstevel@tonic-gate return (ct->ct_dip); 1369*7c478bd9Sstevel@tonic-gate } 1370*7c478bd9Sstevel@tonic-gate 1371*7c478bd9Sstevel@tonic-gate /* 1372*7c478bd9Sstevel@tonic-gate * mdi_client_path2_devinfo(): 1373*7c478bd9Sstevel@tonic-gate * Given the parent devinfo and child devfs pathname, search for 1374*7c478bd9Sstevel@tonic-gate * a valid devfs node handle. 1375*7c478bd9Sstevel@tonic-gate */ 1376*7c478bd9Sstevel@tonic-gate dev_info_t * 1377*7c478bd9Sstevel@tonic-gate mdi_client_path2devinfo(dev_info_t *vdip, char *pathname) 1378*7c478bd9Sstevel@tonic-gate { 1379*7c478bd9Sstevel@tonic-gate dev_info_t *cdip = NULL; 1380*7c478bd9Sstevel@tonic-gate dev_info_t *ndip = NULL; 1381*7c478bd9Sstevel@tonic-gate char *temp_pathname; 1382*7c478bd9Sstevel@tonic-gate int circular; 1383*7c478bd9Sstevel@tonic-gate 1384*7c478bd9Sstevel@tonic-gate /* 1385*7c478bd9Sstevel@tonic-gate * Allocate temp buffer 1386*7c478bd9Sstevel@tonic-gate */ 1387*7c478bd9Sstevel@tonic-gate temp_pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate /* 1390*7c478bd9Sstevel@tonic-gate * Lock parent against changes 1391*7c478bd9Sstevel@tonic-gate */ 1392*7c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circular); 1393*7c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(vdip)->devi_child; 1394*7c478bd9Sstevel@tonic-gate while ((cdip = ndip) != NULL) { 1395*7c478bd9Sstevel@tonic-gate ndip = (dev_info_t *)DEVI(cdip)->devi_sibling; 1396*7c478bd9Sstevel@tonic-gate 1397*7c478bd9Sstevel@tonic-gate *temp_pathname = '\0'; 1398*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(cdip, temp_pathname); 1399*7c478bd9Sstevel@tonic-gate if (strcmp(temp_pathname, pathname) == 0) { 1400*7c478bd9Sstevel@tonic-gate break; 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate } 1403*7c478bd9Sstevel@tonic-gate /* 1404*7c478bd9Sstevel@tonic-gate * Release devinfo lock 1405*7c478bd9Sstevel@tonic-gate */ 1406*7c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circular); 1407*7c478bd9Sstevel@tonic-gate 1408*7c478bd9Sstevel@tonic-gate /* 1409*7c478bd9Sstevel@tonic-gate * Free the temp buffer 1410*7c478bd9Sstevel@tonic-gate */ 1411*7c478bd9Sstevel@tonic-gate kmem_free(temp_pathname, MAXPATHLEN); 1412*7c478bd9Sstevel@tonic-gate return (cdip); 1413*7c478bd9Sstevel@tonic-gate } 1414*7c478bd9Sstevel@tonic-gate 1415*7c478bd9Sstevel@tonic-gate 1416*7c478bd9Sstevel@tonic-gate /* 1417*7c478bd9Sstevel@tonic-gate * mdi_client_get_path_count(): 1418*7c478bd9Sstevel@tonic-gate * Utility function to get number of path information nodes 1419*7c478bd9Sstevel@tonic-gate * associated with a given client device. 1420*7c478bd9Sstevel@tonic-gate */ 1421*7c478bd9Sstevel@tonic-gate int 1422*7c478bd9Sstevel@tonic-gate mdi_client_get_path_count(dev_info_t *cdip) 1423*7c478bd9Sstevel@tonic-gate { 1424*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 1425*7c478bd9Sstevel@tonic-gate int count = 0; 1426*7c478bd9Sstevel@tonic-gate 1427*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 1428*7c478bd9Sstevel@tonic-gate if (ct != NULL) { 1429*7c478bd9Sstevel@tonic-gate count = ct->ct_path_count; 1430*7c478bd9Sstevel@tonic-gate } 1431*7c478bd9Sstevel@tonic-gate return (count); 1432*7c478bd9Sstevel@tonic-gate } 1433*7c478bd9Sstevel@tonic-gate 1434*7c478bd9Sstevel@tonic-gate 1435*7c478bd9Sstevel@tonic-gate /* 1436*7c478bd9Sstevel@tonic-gate * i_mdi_get_hash_key(): 1437*7c478bd9Sstevel@tonic-gate * Create a hash using strings as keys 1438*7c478bd9Sstevel@tonic-gate * 1439*7c478bd9Sstevel@tonic-gate */ 1440*7c478bd9Sstevel@tonic-gate static int 1441*7c478bd9Sstevel@tonic-gate i_mdi_get_hash_key(char *str) 1442*7c478bd9Sstevel@tonic-gate { 1443*7c478bd9Sstevel@tonic-gate uint32_t g, hash = 0; 1444*7c478bd9Sstevel@tonic-gate char *p; 1445*7c478bd9Sstevel@tonic-gate 1446*7c478bd9Sstevel@tonic-gate for (p = str; *p != '\0'; p++) { 1447*7c478bd9Sstevel@tonic-gate g = *p; 1448*7c478bd9Sstevel@tonic-gate hash += g; 1449*7c478bd9Sstevel@tonic-gate } 1450*7c478bd9Sstevel@tonic-gate return (hash % (CLIENT_HASH_TABLE_SIZE - 1)); 1451*7c478bd9Sstevel@tonic-gate } 1452*7c478bd9Sstevel@tonic-gate 1453*7c478bd9Sstevel@tonic-gate /* 1454*7c478bd9Sstevel@tonic-gate * mdi_get_lb_policy(): 1455*7c478bd9Sstevel@tonic-gate * Get current load balancing policy for a given client device 1456*7c478bd9Sstevel@tonic-gate */ 1457*7c478bd9Sstevel@tonic-gate client_lb_t 1458*7c478bd9Sstevel@tonic-gate mdi_get_lb_policy(dev_info_t *cdip) 1459*7c478bd9Sstevel@tonic-gate { 1460*7c478bd9Sstevel@tonic-gate client_lb_t lb = LOAD_BALANCE_NONE; 1461*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 1462*7c478bd9Sstevel@tonic-gate 1463*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 1464*7c478bd9Sstevel@tonic-gate if (ct != NULL) { 1465*7c478bd9Sstevel@tonic-gate lb = ct->ct_lb; 1466*7c478bd9Sstevel@tonic-gate } 1467*7c478bd9Sstevel@tonic-gate return (lb); 1468*7c478bd9Sstevel@tonic-gate } 1469*7c478bd9Sstevel@tonic-gate 1470*7c478bd9Sstevel@tonic-gate /* 1471*7c478bd9Sstevel@tonic-gate * mdi_set_lb_region_size(): 1472*7c478bd9Sstevel@tonic-gate * Set current region size for the load-balance 1473*7c478bd9Sstevel@tonic-gate */ 1474*7c478bd9Sstevel@tonic-gate int 1475*7c478bd9Sstevel@tonic-gate mdi_set_lb_region_size(dev_info_t *cdip, int region_size) 1476*7c478bd9Sstevel@tonic-gate { 1477*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 1478*7c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 1479*7c478bd9Sstevel@tonic-gate 1480*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 1481*7c478bd9Sstevel@tonic-gate if (ct != NULL && ct->ct_lb_args != NULL) { 1482*7c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size = region_size; 1483*7c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 1484*7c478bd9Sstevel@tonic-gate } 1485*7c478bd9Sstevel@tonic-gate return (rv); 1486*7c478bd9Sstevel@tonic-gate } 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate /* 1489*7c478bd9Sstevel@tonic-gate * mdi_Set_lb_policy(): 1490*7c478bd9Sstevel@tonic-gate * Set current load balancing policy for a given client device 1491*7c478bd9Sstevel@tonic-gate */ 1492*7c478bd9Sstevel@tonic-gate int 1493*7c478bd9Sstevel@tonic-gate mdi_set_lb_policy(dev_info_t *cdip, client_lb_t lb) 1494*7c478bd9Sstevel@tonic-gate { 1495*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 1496*7c478bd9Sstevel@tonic-gate int rv = MDI_FAILURE; 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 1499*7c478bd9Sstevel@tonic-gate if (ct != NULL) { 1500*7c478bd9Sstevel@tonic-gate ct->ct_lb = lb; 1501*7c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 1502*7c478bd9Sstevel@tonic-gate } 1503*7c478bd9Sstevel@tonic-gate return (rv); 1504*7c478bd9Sstevel@tonic-gate } 1505*7c478bd9Sstevel@tonic-gate 1506*7c478bd9Sstevel@tonic-gate /* 1507*7c478bd9Sstevel@tonic-gate * mdi_failover(): 1508*7c478bd9Sstevel@tonic-gate * failover function called by the vHCI drivers to initiate 1509*7c478bd9Sstevel@tonic-gate * a failover operation. This is typically due to non-availability 1510*7c478bd9Sstevel@tonic-gate * of online paths to route I/O requests. Failover can be 1511*7c478bd9Sstevel@tonic-gate * triggered through user application also. 1512*7c478bd9Sstevel@tonic-gate * 1513*7c478bd9Sstevel@tonic-gate * The vHCI driver calls mdi_failover() to initiate a failover 1514*7c478bd9Sstevel@tonic-gate * operation. mdi_failover() calls back into the vHCI driver's 1515*7c478bd9Sstevel@tonic-gate * vo_failover() entry point to perform the actual failover 1516*7c478bd9Sstevel@tonic-gate * operation. The reason for requiring the vHCI driver to 1517*7c478bd9Sstevel@tonic-gate * initiate failover by calling mdi_failover(), instead of directly 1518*7c478bd9Sstevel@tonic-gate * executing vo_failover() itself, is to ensure that the mdi 1519*7c478bd9Sstevel@tonic-gate * framework can keep track of the client state properly. 1520*7c478bd9Sstevel@tonic-gate * Additionally, mdi_failover() provides as a convenience the 1521*7c478bd9Sstevel@tonic-gate * option of performing the failover operation synchronously or 1522*7c478bd9Sstevel@tonic-gate * asynchronously 1523*7c478bd9Sstevel@tonic-gate * 1524*7c478bd9Sstevel@tonic-gate * Upon successful completion of the failover operation, the 1525*7c478bd9Sstevel@tonic-gate * paths that were previously ONLINE will be in the STANDBY state, 1526*7c478bd9Sstevel@tonic-gate * and the newly activated paths will be in the ONLINE state. 1527*7c478bd9Sstevel@tonic-gate * 1528*7c478bd9Sstevel@tonic-gate * The flags modifier determines whether the activation is done 1529*7c478bd9Sstevel@tonic-gate * synchronously: MDI_FAILOVER_SYNC 1530*7c478bd9Sstevel@tonic-gate * Return Values: 1531*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 1532*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 1533*7c478bd9Sstevel@tonic-gate * MDI_BUSY 1534*7c478bd9Sstevel@tonic-gate */ 1535*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1536*7c478bd9Sstevel@tonic-gate int 1537*7c478bd9Sstevel@tonic-gate mdi_failover(dev_info_t *vdip, dev_info_t *cdip, int flags) 1538*7c478bd9Sstevel@tonic-gate { 1539*7c478bd9Sstevel@tonic-gate int rv; 1540*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 1541*7c478bd9Sstevel@tonic-gate 1542*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 1543*7c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 1544*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 1545*7c478bd9Sstevel@tonic-gate /* cdip is not a valid client device. Nothing more to do. */ 1546*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 1547*7c478bd9Sstevel@tonic-gate } 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 1550*7c478bd9Sstevel@tonic-gate 1551*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_PATH_FREE_IN_PROGRESS(ct)) { 1552*7c478bd9Sstevel@tonic-gate /* A path to the client is being freed */ 1553*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1554*7c478bd9Sstevel@tonic-gate return (MDI_BUSY); 1555*7c478bd9Sstevel@tonic-gate } 1556*7c478bd9Sstevel@tonic-gate 1557*7c478bd9Sstevel@tonic-gate 1558*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 1559*7c478bd9Sstevel@tonic-gate /* 1560*7c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 1561*7c478bd9Sstevel@tonic-gate */ 1562*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1563*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 1564*7c478bd9Sstevel@tonic-gate } 1565*7c478bd9Sstevel@tonic-gate 1566*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 1567*7c478bd9Sstevel@tonic-gate /* 1568*7c478bd9Sstevel@tonic-gate * Failover is already in progress; return BUSY 1569*7c478bd9Sstevel@tonic-gate */ 1570*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1571*7c478bd9Sstevel@tonic-gate return (MDI_BUSY); 1572*7c478bd9Sstevel@tonic-gate } 1573*7c478bd9Sstevel@tonic-gate /* 1574*7c478bd9Sstevel@tonic-gate * Make sure that mdi_pathinfo node state changes are processed. 1575*7c478bd9Sstevel@tonic-gate * We do not allow failovers to progress while client path state 1576*7c478bd9Sstevel@tonic-gate * changes are in progress 1577*7c478bd9Sstevel@tonic-gate */ 1578*7c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 1579*7c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 1580*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1581*7c478bd9Sstevel@tonic-gate return (MDI_BUSY); 1582*7c478bd9Sstevel@tonic-gate } else { 1583*7c478bd9Sstevel@tonic-gate while (ct->ct_unstable) 1584*7c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_unstable_cv, &ct->ct_mutex); 1585*7c478bd9Sstevel@tonic-gate } 1586*7c478bd9Sstevel@tonic-gate } 1587*7c478bd9Sstevel@tonic-gate 1588*7c478bd9Sstevel@tonic-gate /* 1589*7c478bd9Sstevel@tonic-gate * Client device is in stable state. Before proceeding, perform sanity 1590*7c478bd9Sstevel@tonic-gate * checks again. 1591*7c478bd9Sstevel@tonic-gate */ 1592*7c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct)) || (MDI_CLIENT_IS_FAILED(ct)) || 1593*7c478bd9Sstevel@tonic-gate (i_ddi_node_state(ct->ct_dip) < DS_READY)) { 1594*7c478bd9Sstevel@tonic-gate /* 1595*7c478bd9Sstevel@tonic-gate * Client is in failed state. Nothing more to do. 1596*7c478bd9Sstevel@tonic-gate */ 1597*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1598*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 1599*7c478bd9Sstevel@tonic-gate } 1600*7c478bd9Sstevel@tonic-gate 1601*7c478bd9Sstevel@tonic-gate /* 1602*7c478bd9Sstevel@tonic-gate * Set the client state as failover in progress. 1603*7c478bd9Sstevel@tonic-gate */ 1604*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_FAILOVER_IN_PROGRESS(ct); 1605*7c478bd9Sstevel@tonic-gate ct->ct_failover_flags = flags; 1606*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1607*7c478bd9Sstevel@tonic-gate 1608*7c478bd9Sstevel@tonic-gate if (flags == MDI_FAILOVER_ASYNC) { 1609*7c478bd9Sstevel@tonic-gate /* 1610*7c478bd9Sstevel@tonic-gate * Submit the initiate failover request via CPR safe 1611*7c478bd9Sstevel@tonic-gate * taskq threads. 1612*7c478bd9Sstevel@tonic-gate */ 1613*7c478bd9Sstevel@tonic-gate (void) taskq_dispatch(mdi_taskq, (task_func_t *)i_mdi_failover, 1614*7c478bd9Sstevel@tonic-gate ct, KM_SLEEP); 1615*7c478bd9Sstevel@tonic-gate return (MDI_ACCEPT); 1616*7c478bd9Sstevel@tonic-gate } else { 1617*7c478bd9Sstevel@tonic-gate /* 1618*7c478bd9Sstevel@tonic-gate * Synchronous failover mode. Typically invoked from the user 1619*7c478bd9Sstevel@tonic-gate * land. 1620*7c478bd9Sstevel@tonic-gate */ 1621*7c478bd9Sstevel@tonic-gate rv = i_mdi_failover(ct); 1622*7c478bd9Sstevel@tonic-gate } 1623*7c478bd9Sstevel@tonic-gate return (rv); 1624*7c478bd9Sstevel@tonic-gate } 1625*7c478bd9Sstevel@tonic-gate 1626*7c478bd9Sstevel@tonic-gate /* 1627*7c478bd9Sstevel@tonic-gate * i_mdi_failover(): 1628*7c478bd9Sstevel@tonic-gate * internal failover function. Invokes vHCI drivers failover 1629*7c478bd9Sstevel@tonic-gate * callback function and process the failover status 1630*7c478bd9Sstevel@tonic-gate * Return Values: 1631*7c478bd9Sstevel@tonic-gate * None 1632*7c478bd9Sstevel@tonic-gate * 1633*7c478bd9Sstevel@tonic-gate * Note: A client device in failover state can not be detached or freed. 1634*7c478bd9Sstevel@tonic-gate */ 1635*7c478bd9Sstevel@tonic-gate static int 1636*7c478bd9Sstevel@tonic-gate i_mdi_failover(void *arg) 1637*7c478bd9Sstevel@tonic-gate { 1638*7c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 1639*7c478bd9Sstevel@tonic-gate mdi_client_t *ct = (mdi_client_t *)arg; 1640*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = ct->ct_vhci; 1641*7c478bd9Sstevel@tonic-gate 1642*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&ct->ct_mutex)); 1643*7c478bd9Sstevel@tonic-gate 1644*7c478bd9Sstevel@tonic-gate if (vh->vh_ops->vo_failover != NULL) { 1645*7c478bd9Sstevel@tonic-gate /* 1646*7c478bd9Sstevel@tonic-gate * Call vHCI drivers callback routine 1647*7c478bd9Sstevel@tonic-gate */ 1648*7c478bd9Sstevel@tonic-gate rv = (*vh->vh_ops->vo_failover)(vh->vh_dip, ct->ct_dip, 1649*7c478bd9Sstevel@tonic-gate ct->ct_failover_flags); 1650*7c478bd9Sstevel@tonic-gate } 1651*7c478bd9Sstevel@tonic-gate 1652*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 1653*7c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_FAILOVER_IN_PROGRESS(ct); 1654*7c478bd9Sstevel@tonic-gate 1655*7c478bd9Sstevel@tonic-gate /* 1656*7c478bd9Sstevel@tonic-gate * Save the failover return status 1657*7c478bd9Sstevel@tonic-gate */ 1658*7c478bd9Sstevel@tonic-gate ct->ct_failover_status = rv; 1659*7c478bd9Sstevel@tonic-gate 1660*7c478bd9Sstevel@tonic-gate /* 1661*7c478bd9Sstevel@tonic-gate * As a result of failover, client status would have been changed. 1662*7c478bd9Sstevel@tonic-gate * Update the client state and wake up anyone waiting on this client 1663*7c478bd9Sstevel@tonic-gate * device. 1664*7c478bd9Sstevel@tonic-gate */ 1665*7c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 1666*7c478bd9Sstevel@tonic-gate 1667*7c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_failover_cv); 1668*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1669*7c478bd9Sstevel@tonic-gate return (rv); 1670*7c478bd9Sstevel@tonic-gate } 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate /* 1673*7c478bd9Sstevel@tonic-gate * Load balancing is logical block. 1674*7c478bd9Sstevel@tonic-gate * IOs within the range described by region_size 1675*7c478bd9Sstevel@tonic-gate * would go on the same path. This would improve the 1676*7c478bd9Sstevel@tonic-gate * performance by cache-hit on some of the RAID devices. 1677*7c478bd9Sstevel@tonic-gate * Search only for online paths(At some point we 1678*7c478bd9Sstevel@tonic-gate * may want to balance across target ports). 1679*7c478bd9Sstevel@tonic-gate * If no paths are found then default to round-robin. 1680*7c478bd9Sstevel@tonic-gate */ 1681*7c478bd9Sstevel@tonic-gate static int 1682*7c478bd9Sstevel@tonic-gate i_mdi_lba_lb(mdi_client_t *ct, mdi_pathinfo_t **ret_pip, struct buf *bp) 1683*7c478bd9Sstevel@tonic-gate { 1684*7c478bd9Sstevel@tonic-gate int path_index = -1; 1685*7c478bd9Sstevel@tonic-gate int online_path_count = 0; 1686*7c478bd9Sstevel@tonic-gate int online_nonpref_path_count = 0; 1687*7c478bd9Sstevel@tonic-gate int region_size = ct->ct_lb_args->region_size; 1688*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 1689*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 1690*7c478bd9Sstevel@tonic-gate int preferred, path_cnt; 1691*7c478bd9Sstevel@tonic-gate 1692*7c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 1693*7c478bd9Sstevel@tonic-gate while (pip) { 1694*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 1695*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_state == 1696*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && MDI_PI(pip)->pi_preferred) { 1697*7c478bd9Sstevel@tonic-gate online_path_count++; 1698*7c478bd9Sstevel@tonic-gate } else if (MDI_PI(pip)->pi_state == 1699*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && !MDI_PI(pip)->pi_preferred) { 1700*7c478bd9Sstevel@tonic-gate online_nonpref_path_count++; 1701*7c478bd9Sstevel@tonic-gate } 1702*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 1703*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 1704*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 1705*7c478bd9Sstevel@tonic-gate pip = next; 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate /* if found any online/preferred then use this type */ 1708*7c478bd9Sstevel@tonic-gate if (online_path_count > 0) { 1709*7c478bd9Sstevel@tonic-gate path_cnt = online_path_count; 1710*7c478bd9Sstevel@tonic-gate preferred = 1; 1711*7c478bd9Sstevel@tonic-gate } else if (online_nonpref_path_count > 0) { 1712*7c478bd9Sstevel@tonic-gate path_cnt = online_nonpref_path_count; 1713*7c478bd9Sstevel@tonic-gate preferred = 0; 1714*7c478bd9Sstevel@tonic-gate } else { 1715*7c478bd9Sstevel@tonic-gate path_cnt = 0; 1716*7c478bd9Sstevel@tonic-gate } 1717*7c478bd9Sstevel@tonic-gate if (path_cnt) { 1718*7c478bd9Sstevel@tonic-gate path_index = (bp->b_blkno >> region_size) % path_cnt; 1719*7c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 1720*7c478bd9Sstevel@tonic-gate while (pip && path_index != -1) { 1721*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 1722*7c478bd9Sstevel@tonic-gate if (path_index == 0 && 1723*7c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 1724*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE) && 1725*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == preferred) { 1726*7c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 1727*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 1728*7c478bd9Sstevel@tonic-gate *ret_pip = pip; 1729*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 1730*7c478bd9Sstevel@tonic-gate } 1731*7c478bd9Sstevel@tonic-gate path_index --; 1732*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *) 1733*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link; 1734*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 1735*7c478bd9Sstevel@tonic-gate pip = next; 1736*7c478bd9Sstevel@tonic-gate } 1737*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 1738*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 1739*7c478bd9Sstevel@tonic-gate "!lba %p, no pip !!\n", 1740*7c478bd9Sstevel@tonic-gate bp->b_blkno)); 1741*7c478bd9Sstevel@tonic-gate } else { 1742*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, NULL, 1743*7c478bd9Sstevel@tonic-gate "!lba %p, no pip for path_index, " 1744*7c478bd9Sstevel@tonic-gate "pip %p\n", pip)); 1745*7c478bd9Sstevel@tonic-gate } 1746*7c478bd9Sstevel@tonic-gate } 1747*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 1748*7c478bd9Sstevel@tonic-gate } 1749*7c478bd9Sstevel@tonic-gate 1750*7c478bd9Sstevel@tonic-gate /* 1751*7c478bd9Sstevel@tonic-gate * mdi_select_path(): 1752*7c478bd9Sstevel@tonic-gate * select a path to access a client device. 1753*7c478bd9Sstevel@tonic-gate * 1754*7c478bd9Sstevel@tonic-gate * mdi_select_path() function is called by the vHCI drivers to 1755*7c478bd9Sstevel@tonic-gate * select a path to route the I/O request to. The caller passes 1756*7c478bd9Sstevel@tonic-gate * the block I/O data transfer structure ("buf") as one of the 1757*7c478bd9Sstevel@tonic-gate * parameters. The mpxio framework uses the buf structure 1758*7c478bd9Sstevel@tonic-gate * contents to maintain per path statistics (total I/O size / 1759*7c478bd9Sstevel@tonic-gate * count pending). If more than one online paths are available to 1760*7c478bd9Sstevel@tonic-gate * select, the framework automatically selects a suitable path 1761*7c478bd9Sstevel@tonic-gate * for routing I/O request. If a failover operation is active for 1762*7c478bd9Sstevel@tonic-gate * this client device the call shall be failed with MDI_BUSY error 1763*7c478bd9Sstevel@tonic-gate * code. 1764*7c478bd9Sstevel@tonic-gate * 1765*7c478bd9Sstevel@tonic-gate * By default this function returns a suitable path in online 1766*7c478bd9Sstevel@tonic-gate * state based on the current load balancing policy. Currently 1767*7c478bd9Sstevel@tonic-gate * we support LOAD_BALANCE_NONE (Previously selected online path 1768*7c478bd9Sstevel@tonic-gate * will continue to be used till the path is usable) and 1769*7c478bd9Sstevel@tonic-gate * LOAD_BALANCE_RR (Online paths will be selected in a round 1770*7c478bd9Sstevel@tonic-gate * robin fashion), LOAD_BALANCE_LB(Online paths will be selected 1771*7c478bd9Sstevel@tonic-gate * based on the logical block). The load balancing 1772*7c478bd9Sstevel@tonic-gate * through vHCI drivers configuration file (driver.conf). 1773*7c478bd9Sstevel@tonic-gate * 1774*7c478bd9Sstevel@tonic-gate * vHCI drivers may override this default behavior by specifying 1775*7c478bd9Sstevel@tonic-gate * appropriate flags. If start_pip is specified (non NULL) is 1776*7c478bd9Sstevel@tonic-gate * used as start point to walk and find the next appropriate path. 1777*7c478bd9Sstevel@tonic-gate * The following values are currently defined: 1778*7c478bd9Sstevel@tonic-gate * MDI_SELECT_ONLINE_PATH (to select an ONLINE path) and/or 1779*7c478bd9Sstevel@tonic-gate * MDI_SELECT_STANDBY_PATH (to select an STANDBY path). 1780*7c478bd9Sstevel@tonic-gate * 1781*7c478bd9Sstevel@tonic-gate * The non-standard behavior is used by the scsi_vhci driver, 1782*7c478bd9Sstevel@tonic-gate * whenever it has to use a STANDBY/FAULTED path. Eg. during 1783*7c478bd9Sstevel@tonic-gate * attach of client devices (to avoid an unnecessary failover 1784*7c478bd9Sstevel@tonic-gate * when the STANDBY path comes up first), during failover 1785*7c478bd9Sstevel@tonic-gate * (to activate a STANDBY path as ONLINE). 1786*7c478bd9Sstevel@tonic-gate * 1787*7c478bd9Sstevel@tonic-gate * The selected path in returned in a held state (ref_cnt). 1788*7c478bd9Sstevel@tonic-gate * Caller should release the hold by calling mdi_rele_path(). 1789*7c478bd9Sstevel@tonic-gate * 1790*7c478bd9Sstevel@tonic-gate * Return Values: 1791*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS - Completed successfully 1792*7c478bd9Sstevel@tonic-gate * MDI_BUSY - Client device is busy failing over 1793*7c478bd9Sstevel@tonic-gate * MDI_NOPATH - Client device is online, but no valid path are 1794*7c478bd9Sstevel@tonic-gate * available to access this client device 1795*7c478bd9Sstevel@tonic-gate * MDI_FAILURE - Invalid client device or state 1796*7c478bd9Sstevel@tonic-gate * MDI_DEVI_ONLINING 1797*7c478bd9Sstevel@tonic-gate * - Client device (struct dev_info state) is in 1798*7c478bd9Sstevel@tonic-gate * onlining state. 1799*7c478bd9Sstevel@tonic-gate */ 1800*7c478bd9Sstevel@tonic-gate 1801*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1802*7c478bd9Sstevel@tonic-gate int 1803*7c478bd9Sstevel@tonic-gate mdi_select_path(dev_info_t *cdip, struct buf *bp, int flags, 1804*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start_pip, mdi_pathinfo_t **ret_pip) 1805*7c478bd9Sstevel@tonic-gate { 1806*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 1807*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 1808*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 1809*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *head; 1810*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *start; 1811*7c478bd9Sstevel@tonic-gate client_lb_t lbp; /* load balancing policy */ 1812*7c478bd9Sstevel@tonic-gate int sb = 1; /* standard behavior */ 1813*7c478bd9Sstevel@tonic-gate int preferred = 1; /* preferred path */ 1814*7c478bd9Sstevel@tonic-gate int cond, cont = 1; 1815*7c478bd9Sstevel@tonic-gate int retry = 0; 1816*7c478bd9Sstevel@tonic-gate 1817*7c478bd9Sstevel@tonic-gate if (flags != 0) { 1818*7c478bd9Sstevel@tonic-gate /* 1819*7c478bd9Sstevel@tonic-gate * disable default behavior 1820*7c478bd9Sstevel@tonic-gate */ 1821*7c478bd9Sstevel@tonic-gate sb = 0; 1822*7c478bd9Sstevel@tonic-gate } 1823*7c478bd9Sstevel@tonic-gate 1824*7c478bd9Sstevel@tonic-gate *ret_pip = NULL; 1825*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 1826*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 1827*7c478bd9Sstevel@tonic-gate /* mdi extensions are NULL, Nothing more to do */ 1828*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 1829*7c478bd9Sstevel@tonic-gate } 1830*7c478bd9Sstevel@tonic-gate 1831*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 1832*7c478bd9Sstevel@tonic-gate 1833*7c478bd9Sstevel@tonic-gate if (sb) { 1834*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 1835*7c478bd9Sstevel@tonic-gate /* 1836*7c478bd9Sstevel@tonic-gate * Client is not ready to accept any I/O requests. 1837*7c478bd9Sstevel@tonic-gate * Fail this request. 1838*7c478bd9Sstevel@tonic-gate */ 1839*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 1840*7c478bd9Sstevel@tonic-gate "client state offline ct = %p\n", ct)); 1841*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1842*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 1843*7c478bd9Sstevel@tonic-gate } 1844*7c478bd9Sstevel@tonic-gate 1845*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 1846*7c478bd9Sstevel@tonic-gate /* 1847*7c478bd9Sstevel@tonic-gate * Check for Failover is in progress. If so tell the 1848*7c478bd9Sstevel@tonic-gate * caller that this device is busy. 1849*7c478bd9Sstevel@tonic-gate */ 1850*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, cdip, "!mdi_select_path: " 1851*7c478bd9Sstevel@tonic-gate "client failover in progress ct = %p\n", ct)); 1852*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1853*7c478bd9Sstevel@tonic-gate return (MDI_BUSY); 1854*7c478bd9Sstevel@tonic-gate } 1855*7c478bd9Sstevel@tonic-gate 1856*7c478bd9Sstevel@tonic-gate /* 1857*7c478bd9Sstevel@tonic-gate * Check to see whether the client device is attached. 1858*7c478bd9Sstevel@tonic-gate * If not so, let the vHCI driver manually select a path 1859*7c478bd9Sstevel@tonic-gate * (standby) and let the probe/attach process to continue. 1860*7c478bd9Sstevel@tonic-gate */ 1861*7c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct)) || 1862*7c478bd9Sstevel@tonic-gate i_ddi_node_state(cdip) < DS_READY) { 1863*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, cdip, "!Devi is onlining\n")); 1864*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1865*7c478bd9Sstevel@tonic-gate return (MDI_DEVI_ONLINING); 1866*7c478bd9Sstevel@tonic-gate } 1867*7c478bd9Sstevel@tonic-gate } 1868*7c478bd9Sstevel@tonic-gate 1869*7c478bd9Sstevel@tonic-gate /* 1870*7c478bd9Sstevel@tonic-gate * Cache in the client list head. If head of the list is NULL 1871*7c478bd9Sstevel@tonic-gate * return MDI_NOPATH 1872*7c478bd9Sstevel@tonic-gate */ 1873*7c478bd9Sstevel@tonic-gate head = ct->ct_path_head; 1874*7c478bd9Sstevel@tonic-gate if (head == NULL) { 1875*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1876*7c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 1877*7c478bd9Sstevel@tonic-gate } 1878*7c478bd9Sstevel@tonic-gate 1879*7c478bd9Sstevel@tonic-gate /* 1880*7c478bd9Sstevel@tonic-gate * for non default behavior, bypass current 1881*7c478bd9Sstevel@tonic-gate * load balancing policy and always use LOAD_BALANCE_RR 1882*7c478bd9Sstevel@tonic-gate * except that the start point will be adjusted based 1883*7c478bd9Sstevel@tonic-gate * on the provided start_pip 1884*7c478bd9Sstevel@tonic-gate */ 1885*7c478bd9Sstevel@tonic-gate lbp = sb ? ct->ct_lb : LOAD_BALANCE_RR; 1886*7c478bd9Sstevel@tonic-gate 1887*7c478bd9Sstevel@tonic-gate switch (lbp) { 1888*7c478bd9Sstevel@tonic-gate case LOAD_BALANCE_NONE: 1889*7c478bd9Sstevel@tonic-gate /* 1890*7c478bd9Sstevel@tonic-gate * Load balancing is None or Alternate path mode 1891*7c478bd9Sstevel@tonic-gate * Start looking for a online mdi_pathinfo node starting from 1892*7c478bd9Sstevel@tonic-gate * last known selected path 1893*7c478bd9Sstevel@tonic-gate */ 1894*7c478bd9Sstevel@tonic-gate preferred = 1; 1895*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_last; 1896*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 1897*7c478bd9Sstevel@tonic-gate pip = head; 1898*7c478bd9Sstevel@tonic-gate } 1899*7c478bd9Sstevel@tonic-gate start = pip; 1900*7c478bd9Sstevel@tonic-gate do { 1901*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 1902*7c478bd9Sstevel@tonic-gate /* 1903*7c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 1904*7c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 1905*7c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 1906*7c478bd9Sstevel@tonic-gate */ 1907*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_state == 1908*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 1909*7c478bd9Sstevel@tonic-gate preferred == MDI_PI(pip)->pi_preferred) { 1910*7c478bd9Sstevel@tonic-gate /* 1911*7c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 1912*7c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 1913*7c478bd9Sstevel@tonic-gate */ 1914*7c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 1915*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 1916*7c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 1917*7c478bd9Sstevel@tonic-gate *ret_pip = pip; 1918*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1919*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 1920*7c478bd9Sstevel@tonic-gate } 1921*7c478bd9Sstevel@tonic-gate 1922*7c478bd9Sstevel@tonic-gate /* 1923*7c478bd9Sstevel@tonic-gate * Path is busy. 1924*7c478bd9Sstevel@tonic-gate */ 1925*7c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 1926*7c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 1927*7c478bd9Sstevel@tonic-gate retry = 1; 1928*7c478bd9Sstevel@tonic-gate /* 1929*7c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 1930*7c478bd9Sstevel@tonic-gate */ 1931*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 1932*7c478bd9Sstevel@tonic-gate if (next == NULL) { 1933*7c478bd9Sstevel@tonic-gate next = head; 1934*7c478bd9Sstevel@tonic-gate } 1935*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 1936*7c478bd9Sstevel@tonic-gate pip = next; 1937*7c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 1938*7c478bd9Sstevel@tonic-gate preferred = 0; 1939*7c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 1940*7c478bd9Sstevel@tonic-gate cont = 0; 1941*7c478bd9Sstevel@tonic-gate } 1942*7c478bd9Sstevel@tonic-gate } while (cont); 1943*7c478bd9Sstevel@tonic-gate break; 1944*7c478bd9Sstevel@tonic-gate 1945*7c478bd9Sstevel@tonic-gate case LOAD_BALANCE_LBA: 1946*7c478bd9Sstevel@tonic-gate /* 1947*7c478bd9Sstevel@tonic-gate * Make sure we are looking 1948*7c478bd9Sstevel@tonic-gate * for an online path. Otherwise, if it is for a STANDBY 1949*7c478bd9Sstevel@tonic-gate * path request, it will go through and fetch an ONLINE 1950*7c478bd9Sstevel@tonic-gate * path which is not desirable. 1951*7c478bd9Sstevel@tonic-gate */ 1952*7c478bd9Sstevel@tonic-gate if ((ct->ct_lb_args != NULL) && 1953*7c478bd9Sstevel@tonic-gate (ct->ct_lb_args->region_size) && bp && 1954*7c478bd9Sstevel@tonic-gate (sb || (flags == MDI_SELECT_ONLINE_PATH))) { 1955*7c478bd9Sstevel@tonic-gate if (i_mdi_lba_lb(ct, ret_pip, bp) 1956*7c478bd9Sstevel@tonic-gate == MDI_SUCCESS) { 1957*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1958*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 1959*7c478bd9Sstevel@tonic-gate } 1960*7c478bd9Sstevel@tonic-gate } 1961*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1962*7c478bd9Sstevel@tonic-gate case LOAD_BALANCE_RR: 1963*7c478bd9Sstevel@tonic-gate /* 1964*7c478bd9Sstevel@tonic-gate * Load balancing is Round Robin. Start looking for a online 1965*7c478bd9Sstevel@tonic-gate * mdi_pathinfo node starting from last known selected path 1966*7c478bd9Sstevel@tonic-gate * as the start point. If override flags are specified, 1967*7c478bd9Sstevel@tonic-gate * process accordingly. 1968*7c478bd9Sstevel@tonic-gate * If the search is already in effect(start_pip not null), 1969*7c478bd9Sstevel@tonic-gate * then lets just use the same path preference to continue the 1970*7c478bd9Sstevel@tonic-gate * traversal. 1971*7c478bd9Sstevel@tonic-gate */ 1972*7c478bd9Sstevel@tonic-gate 1973*7c478bd9Sstevel@tonic-gate if (start_pip != NULL) { 1974*7c478bd9Sstevel@tonic-gate preferred = MDI_PI(start_pip)->pi_preferred; 1975*7c478bd9Sstevel@tonic-gate } else { 1976*7c478bd9Sstevel@tonic-gate preferred = 1; 1977*7c478bd9Sstevel@tonic-gate } 1978*7c478bd9Sstevel@tonic-gate 1979*7c478bd9Sstevel@tonic-gate start = sb ? (mdi_pathinfo_t *)ct->ct_path_last : start_pip; 1980*7c478bd9Sstevel@tonic-gate if (start == NULL) { 1981*7c478bd9Sstevel@tonic-gate pip = head; 1982*7c478bd9Sstevel@tonic-gate } else { 1983*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(start)->pi_client_link; 1984*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 1985*7c478bd9Sstevel@tonic-gate if (!sb) { 1986*7c478bd9Sstevel@tonic-gate if (preferred == 0) { 1987*7c478bd9Sstevel@tonic-gate /* 1988*7c478bd9Sstevel@tonic-gate * Looks like we have completed 1989*7c478bd9Sstevel@tonic-gate * the traversal as preferred 1990*7c478bd9Sstevel@tonic-gate * value is 0. Time to bail out. 1991*7c478bd9Sstevel@tonic-gate */ 1992*7c478bd9Sstevel@tonic-gate *ret_pip = NULL; 1993*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 1994*7c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 1995*7c478bd9Sstevel@tonic-gate } else { 1996*7c478bd9Sstevel@tonic-gate /* 1997*7c478bd9Sstevel@tonic-gate * Looks like we reached the 1998*7c478bd9Sstevel@tonic-gate * end of the list. Lets enable 1999*7c478bd9Sstevel@tonic-gate * traversal of non preferred 2000*7c478bd9Sstevel@tonic-gate * paths. 2001*7c478bd9Sstevel@tonic-gate */ 2002*7c478bd9Sstevel@tonic-gate preferred = 0; 2003*7c478bd9Sstevel@tonic-gate } 2004*7c478bd9Sstevel@tonic-gate } 2005*7c478bd9Sstevel@tonic-gate pip = head; 2006*7c478bd9Sstevel@tonic-gate } 2007*7c478bd9Sstevel@tonic-gate } 2008*7c478bd9Sstevel@tonic-gate start = pip; 2009*7c478bd9Sstevel@tonic-gate do { 2010*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 2011*7c478bd9Sstevel@tonic-gate if (sb) { 2012*7c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 2013*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 2014*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 2015*7c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 2016*7c478bd9Sstevel@tonic-gate } else { 2017*7c478bd9Sstevel@tonic-gate if (flags == MDI_SELECT_ONLINE_PATH) { 2018*7c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 2019*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE && 2020*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 2021*7c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 2022*7c478bd9Sstevel@tonic-gate } else if (flags == MDI_SELECT_STANDBY_PATH) { 2023*7c478bd9Sstevel@tonic-gate cond = ((MDI_PI(pip)->pi_state == 2024*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY && 2025*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 2026*7c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 2027*7c478bd9Sstevel@tonic-gate } else if (flags == (MDI_SELECT_ONLINE_PATH | 2028*7c478bd9Sstevel@tonic-gate MDI_SELECT_STANDBY_PATH)) { 2029*7c478bd9Sstevel@tonic-gate cond = (((MDI_PI(pip)->pi_state == 2030*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_ONLINE || 2031*7c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state == 2032*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_STANDBY)) && 2033*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred == 2034*7c478bd9Sstevel@tonic-gate preferred) ? 1 : 0); 2035*7c478bd9Sstevel@tonic-gate } else { 2036*7c478bd9Sstevel@tonic-gate cond = 0; 2037*7c478bd9Sstevel@tonic-gate } 2038*7c478bd9Sstevel@tonic-gate } 2039*7c478bd9Sstevel@tonic-gate /* 2040*7c478bd9Sstevel@tonic-gate * No need to explicitly check if the path is disabled. 2041*7c478bd9Sstevel@tonic-gate * Since we are checking for state == ONLINE and the 2042*7c478bd9Sstevel@tonic-gate * same veriable is used for DISABLE/ENABLE information. 2043*7c478bd9Sstevel@tonic-gate */ 2044*7c478bd9Sstevel@tonic-gate if (cond) { 2045*7c478bd9Sstevel@tonic-gate /* 2046*7c478bd9Sstevel@tonic-gate * Return the path in hold state. Caller should 2047*7c478bd9Sstevel@tonic-gate * release the lock by calling mdi_rele_path() 2048*7c478bd9Sstevel@tonic-gate */ 2049*7c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 2050*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2051*7c478bd9Sstevel@tonic-gate if (sb) 2052*7c478bd9Sstevel@tonic-gate ct->ct_path_last = pip; 2053*7c478bd9Sstevel@tonic-gate *ret_pip = pip; 2054*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 2055*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 2056*7c478bd9Sstevel@tonic-gate } 2057*7c478bd9Sstevel@tonic-gate /* 2058*7c478bd9Sstevel@tonic-gate * Path is busy. 2059*7c478bd9Sstevel@tonic-gate */ 2060*7c478bd9Sstevel@tonic-gate if (MDI_PI_IS_DRV_DISABLE_TRANSIENT(pip) || 2061*7c478bd9Sstevel@tonic-gate MDI_PI_IS_TRANSIENT(pip)) 2062*7c478bd9Sstevel@tonic-gate retry = 1; 2063*7c478bd9Sstevel@tonic-gate 2064*7c478bd9Sstevel@tonic-gate /* 2065*7c478bd9Sstevel@tonic-gate * Keep looking for a next available online path 2066*7c478bd9Sstevel@tonic-gate */ 2067*7c478bd9Sstevel@tonic-gate do_again: 2068*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 2069*7c478bd9Sstevel@tonic-gate if (next == NULL) { 2070*7c478bd9Sstevel@tonic-gate if (!sb) { 2071*7c478bd9Sstevel@tonic-gate if (preferred == 1) { 2072*7c478bd9Sstevel@tonic-gate /* 2073*7c478bd9Sstevel@tonic-gate * Looks like we reached the 2074*7c478bd9Sstevel@tonic-gate * end of the list. Lets enable 2075*7c478bd9Sstevel@tonic-gate * traversal of non preferred 2076*7c478bd9Sstevel@tonic-gate * paths. 2077*7c478bd9Sstevel@tonic-gate */ 2078*7c478bd9Sstevel@tonic-gate preferred = 0; 2079*7c478bd9Sstevel@tonic-gate next = head; 2080*7c478bd9Sstevel@tonic-gate } else { 2081*7c478bd9Sstevel@tonic-gate /* 2082*7c478bd9Sstevel@tonic-gate * We have done both the passes 2083*7c478bd9Sstevel@tonic-gate * Preferred as well as for 2084*7c478bd9Sstevel@tonic-gate * Non-preferred. Bail out now. 2085*7c478bd9Sstevel@tonic-gate */ 2086*7c478bd9Sstevel@tonic-gate cont = 0; 2087*7c478bd9Sstevel@tonic-gate } 2088*7c478bd9Sstevel@tonic-gate } else { 2089*7c478bd9Sstevel@tonic-gate /* 2090*7c478bd9Sstevel@tonic-gate * Standard behavior case. 2091*7c478bd9Sstevel@tonic-gate */ 2092*7c478bd9Sstevel@tonic-gate next = head; 2093*7c478bd9Sstevel@tonic-gate } 2094*7c478bd9Sstevel@tonic-gate } 2095*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2096*7c478bd9Sstevel@tonic-gate if (cont == 0) { 2097*7c478bd9Sstevel@tonic-gate break; 2098*7c478bd9Sstevel@tonic-gate } 2099*7c478bd9Sstevel@tonic-gate pip = next; 2100*7c478bd9Sstevel@tonic-gate 2101*7c478bd9Sstevel@tonic-gate if (!sb) { 2102*7c478bd9Sstevel@tonic-gate /* 2103*7c478bd9Sstevel@tonic-gate * We need to handle the selection of 2104*7c478bd9Sstevel@tonic-gate * non-preferred path in the following 2105*7c478bd9Sstevel@tonic-gate * case: 2106*7c478bd9Sstevel@tonic-gate * 2107*7c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 2108*7c478bd9Sstevel@tonic-gate * | A : 1| - | B : 1| - | C : 0| - |NULL | 2109*7c478bd9Sstevel@tonic-gate * +------+ +------+ +------+ +-----+ 2110*7c478bd9Sstevel@tonic-gate * 2111*7c478bd9Sstevel@tonic-gate * If we start the search with B, we need to 2112*7c478bd9Sstevel@tonic-gate * skip beyond B to pick C which is non - 2113*7c478bd9Sstevel@tonic-gate * preferred in the second pass. The following 2114*7c478bd9Sstevel@tonic-gate * test, if true, will allow us to skip over 2115*7c478bd9Sstevel@tonic-gate * the 'start'(B in the example) to select 2116*7c478bd9Sstevel@tonic-gate * other non preferred elements. 2117*7c478bd9Sstevel@tonic-gate */ 2118*7c478bd9Sstevel@tonic-gate if ((start_pip != NULL) && (start_pip == pip) && 2119*7c478bd9Sstevel@tonic-gate (MDI_PI(start_pip)->pi_preferred 2120*7c478bd9Sstevel@tonic-gate != preferred)) { 2121*7c478bd9Sstevel@tonic-gate /* 2122*7c478bd9Sstevel@tonic-gate * try again after going past the start 2123*7c478bd9Sstevel@tonic-gate * pip 2124*7c478bd9Sstevel@tonic-gate */ 2125*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 2126*7c478bd9Sstevel@tonic-gate goto do_again; 2127*7c478bd9Sstevel@tonic-gate } 2128*7c478bd9Sstevel@tonic-gate } else { 2129*7c478bd9Sstevel@tonic-gate /* 2130*7c478bd9Sstevel@tonic-gate * Standard behavior case 2131*7c478bd9Sstevel@tonic-gate */ 2132*7c478bd9Sstevel@tonic-gate if (start == pip && preferred) { 2133*7c478bd9Sstevel@tonic-gate /* look for nonpreferred paths */ 2134*7c478bd9Sstevel@tonic-gate preferred = 0; 2135*7c478bd9Sstevel@tonic-gate } else if (start == pip && !preferred) { 2136*7c478bd9Sstevel@tonic-gate /* 2137*7c478bd9Sstevel@tonic-gate * Exit condition 2138*7c478bd9Sstevel@tonic-gate */ 2139*7c478bd9Sstevel@tonic-gate cont = 0; 2140*7c478bd9Sstevel@tonic-gate } 2141*7c478bd9Sstevel@tonic-gate } 2142*7c478bd9Sstevel@tonic-gate } while (cont); 2143*7c478bd9Sstevel@tonic-gate break; 2144*7c478bd9Sstevel@tonic-gate } 2145*7c478bd9Sstevel@tonic-gate 2146*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 2147*7c478bd9Sstevel@tonic-gate if (retry == 1) { 2148*7c478bd9Sstevel@tonic-gate return (MDI_BUSY); 2149*7c478bd9Sstevel@tonic-gate } else { 2150*7c478bd9Sstevel@tonic-gate return (MDI_NOPATH); 2151*7c478bd9Sstevel@tonic-gate } 2152*7c478bd9Sstevel@tonic-gate } 2153*7c478bd9Sstevel@tonic-gate 2154*7c478bd9Sstevel@tonic-gate /* 2155*7c478bd9Sstevel@tonic-gate * For a client, return the next available path to any phci 2156*7c478bd9Sstevel@tonic-gate * 2157*7c478bd9Sstevel@tonic-gate * Note: 2158*7c478bd9Sstevel@tonic-gate * Caller should hold the branch's devinfo node to get a consistent 2159*7c478bd9Sstevel@tonic-gate * snap shot of the mdi_pathinfo nodes. 2160*7c478bd9Sstevel@tonic-gate * 2161*7c478bd9Sstevel@tonic-gate * Please note that even the list is stable the mdi_pathinfo 2162*7c478bd9Sstevel@tonic-gate * node state and properties are volatile. The caller should lock 2163*7c478bd9Sstevel@tonic-gate * and unlock the nodes by calling mdi_pi_lock() and 2164*7c478bd9Sstevel@tonic-gate * mdi_pi_unlock() functions to get a stable properties. 2165*7c478bd9Sstevel@tonic-gate * 2166*7c478bd9Sstevel@tonic-gate * If there is a need to use the nodes beyond the hold of the 2167*7c478bd9Sstevel@tonic-gate * devinfo node period (For ex. I/O), then mdi_pathinfo node 2168*7c478bd9Sstevel@tonic-gate * need to be held against unexpected removal by calling 2169*7c478bd9Sstevel@tonic-gate * mdi_hold_path() and should be released by calling 2170*7c478bd9Sstevel@tonic-gate * mdi_rele_path() on completion. 2171*7c478bd9Sstevel@tonic-gate */ 2172*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 2173*7c478bd9Sstevel@tonic-gate mdi_get_next_phci_path(dev_info_t *ct_dip, mdi_pathinfo_t *pip) 2174*7c478bd9Sstevel@tonic-gate { 2175*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 2176*7c478bd9Sstevel@tonic-gate 2177*7c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(ct_dip)) 2178*7c478bd9Sstevel@tonic-gate return (NULL); 2179*7c478bd9Sstevel@tonic-gate 2180*7c478bd9Sstevel@tonic-gate /* 2181*7c478bd9Sstevel@tonic-gate * Walk through client link 2182*7c478bd9Sstevel@tonic-gate */ 2183*7c478bd9Sstevel@tonic-gate ct = (mdi_client_t *)DEVI(ct_dip)->devi_mdi_client; 2184*7c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 2185*7c478bd9Sstevel@tonic-gate 2186*7c478bd9Sstevel@tonic-gate if (pip == NULL) 2187*7c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ct->ct_path_head); 2188*7c478bd9Sstevel@tonic-gate 2189*7c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link); 2190*7c478bd9Sstevel@tonic-gate } 2191*7c478bd9Sstevel@tonic-gate 2192*7c478bd9Sstevel@tonic-gate /* 2193*7c478bd9Sstevel@tonic-gate * For a phci, return the next available path to any client 2194*7c478bd9Sstevel@tonic-gate * Note: ditto mdi_get_next_phci_path() 2195*7c478bd9Sstevel@tonic-gate */ 2196*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 2197*7c478bd9Sstevel@tonic-gate mdi_get_next_client_path(dev_info_t *ph_dip, mdi_pathinfo_t *pip) 2198*7c478bd9Sstevel@tonic-gate { 2199*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 2200*7c478bd9Sstevel@tonic-gate 2201*7c478bd9Sstevel@tonic-gate if (!MDI_PHCI(ph_dip)) 2202*7c478bd9Sstevel@tonic-gate return (NULL); 2203*7c478bd9Sstevel@tonic-gate 2204*7c478bd9Sstevel@tonic-gate /* 2205*7c478bd9Sstevel@tonic-gate * Walk through pHCI link 2206*7c478bd9Sstevel@tonic-gate */ 2207*7c478bd9Sstevel@tonic-gate ph = (mdi_phci_t *)DEVI(ph_dip)->devi_mdi_xhci; 2208*7c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 2209*7c478bd9Sstevel@tonic-gate 2210*7c478bd9Sstevel@tonic-gate if (pip == NULL) 2211*7c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)ph->ph_path_head); 2212*7c478bd9Sstevel@tonic-gate 2213*7c478bd9Sstevel@tonic-gate return ((mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link); 2214*7c478bd9Sstevel@tonic-gate } 2215*7c478bd9Sstevel@tonic-gate 2216*7c478bd9Sstevel@tonic-gate /* 2217*7c478bd9Sstevel@tonic-gate * mdi_get_nextpath(): 2218*7c478bd9Sstevel@tonic-gate * mdi_pathinfo node walker function. Get the next node from the 2219*7c478bd9Sstevel@tonic-gate * client or pHCI device list. 2220*7c478bd9Sstevel@tonic-gate * 2221*7c478bd9Sstevel@tonic-gate * XXX This is wrapper function for compatibility purposes only. 2222*7c478bd9Sstevel@tonic-gate * 2223*7c478bd9Sstevel@tonic-gate * It doesn't work under Multi-level MPxIO, where a dip 2224*7c478bd9Sstevel@tonic-gate * is both client and phci (which link should next_path follow?). 2225*7c478bd9Sstevel@tonic-gate * Once Leadville is modified to call mdi_get_next_phci/client_path, 2226*7c478bd9Sstevel@tonic-gate * this interface should be removed. 2227*7c478bd9Sstevel@tonic-gate */ 2228*7c478bd9Sstevel@tonic-gate void 2229*7c478bd9Sstevel@tonic-gate mdi_get_next_path(dev_info_t *dip, mdi_pathinfo_t *pip, 2230*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t **ret_pip) 2231*7c478bd9Sstevel@tonic-gate { 2232*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 2233*7c478bd9Sstevel@tonic-gate *ret_pip = mdi_get_next_phci_path(dip, pip); 2234*7c478bd9Sstevel@tonic-gate } else if (MDI_PHCI(dip)) { 2235*7c478bd9Sstevel@tonic-gate *ret_pip = mdi_get_next_client_path(dip, pip); 2236*7c478bd9Sstevel@tonic-gate } else { 2237*7c478bd9Sstevel@tonic-gate *ret_pip = NULL; 2238*7c478bd9Sstevel@tonic-gate } 2239*7c478bd9Sstevel@tonic-gate } 2240*7c478bd9Sstevel@tonic-gate 2241*7c478bd9Sstevel@tonic-gate /* 2242*7c478bd9Sstevel@tonic-gate * mdi_hold_path(): 2243*7c478bd9Sstevel@tonic-gate * Hold the mdi_pathinfo node against unwanted unexpected free. 2244*7c478bd9Sstevel@tonic-gate * Return Values: 2245*7c478bd9Sstevel@tonic-gate * None 2246*7c478bd9Sstevel@tonic-gate */ 2247*7c478bd9Sstevel@tonic-gate void 2248*7c478bd9Sstevel@tonic-gate mdi_hold_path(mdi_pathinfo_t *pip) 2249*7c478bd9Sstevel@tonic-gate { 2250*7c478bd9Sstevel@tonic-gate if (pip) { 2251*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 2252*7c478bd9Sstevel@tonic-gate MDI_PI_HOLD(pip); 2253*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2254*7c478bd9Sstevel@tonic-gate } 2255*7c478bd9Sstevel@tonic-gate } 2256*7c478bd9Sstevel@tonic-gate 2257*7c478bd9Sstevel@tonic-gate 2258*7c478bd9Sstevel@tonic-gate /* 2259*7c478bd9Sstevel@tonic-gate * mdi_rele_path(): 2260*7c478bd9Sstevel@tonic-gate * Release the mdi_pathinfo node which was selected 2261*7c478bd9Sstevel@tonic-gate * through mdi_select_path() mechanism or manually held by 2262*7c478bd9Sstevel@tonic-gate * calling mdi_hold_path(). 2263*7c478bd9Sstevel@tonic-gate * Return Values: 2264*7c478bd9Sstevel@tonic-gate * None 2265*7c478bd9Sstevel@tonic-gate */ 2266*7c478bd9Sstevel@tonic-gate void 2267*7c478bd9Sstevel@tonic-gate mdi_rele_path(mdi_pathinfo_t *pip) 2268*7c478bd9Sstevel@tonic-gate { 2269*7c478bd9Sstevel@tonic-gate if (pip) { 2270*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 2271*7c478bd9Sstevel@tonic-gate MDI_PI_RELE(pip); 2272*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_ref_cnt == 0) { 2273*7c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_ref_cv); 2274*7c478bd9Sstevel@tonic-gate } 2275*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2276*7c478bd9Sstevel@tonic-gate } 2277*7c478bd9Sstevel@tonic-gate } 2278*7c478bd9Sstevel@tonic-gate 2279*7c478bd9Sstevel@tonic-gate 2280*7c478bd9Sstevel@tonic-gate /* 2281*7c478bd9Sstevel@tonic-gate * mdi_pi_lock(): 2282*7c478bd9Sstevel@tonic-gate * Lock the mdi_pathinfo node. 2283*7c478bd9Sstevel@tonic-gate * Note: 2284*7c478bd9Sstevel@tonic-gate * The caller should release the lock by calling mdi_pi_unlock() 2285*7c478bd9Sstevel@tonic-gate */ 2286*7c478bd9Sstevel@tonic-gate void 2287*7c478bd9Sstevel@tonic-gate mdi_pi_lock(mdi_pathinfo_t *pip) 2288*7c478bd9Sstevel@tonic-gate { 2289*7c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 2290*7c478bd9Sstevel@tonic-gate if (pip) { 2291*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 2292*7c478bd9Sstevel@tonic-gate } 2293*7c478bd9Sstevel@tonic-gate } 2294*7c478bd9Sstevel@tonic-gate 2295*7c478bd9Sstevel@tonic-gate 2296*7c478bd9Sstevel@tonic-gate /* 2297*7c478bd9Sstevel@tonic-gate * mdi_pi_unlock(): 2298*7c478bd9Sstevel@tonic-gate * Unlock the mdi_pathinfo node. 2299*7c478bd9Sstevel@tonic-gate * Note: 2300*7c478bd9Sstevel@tonic-gate * The mdi_pathinfo node should have been locked with mdi_pi_lock() 2301*7c478bd9Sstevel@tonic-gate */ 2302*7c478bd9Sstevel@tonic-gate void 2303*7c478bd9Sstevel@tonic-gate mdi_pi_unlock(mdi_pathinfo_t *pip) 2304*7c478bd9Sstevel@tonic-gate { 2305*7c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 2306*7c478bd9Sstevel@tonic-gate if (pip) { 2307*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2308*7c478bd9Sstevel@tonic-gate } 2309*7c478bd9Sstevel@tonic-gate } 2310*7c478bd9Sstevel@tonic-gate 2311*7c478bd9Sstevel@tonic-gate /* 2312*7c478bd9Sstevel@tonic-gate * mdi_pi_find(): 2313*7c478bd9Sstevel@tonic-gate * Search the list of mdi_pathinfo nodes attached to the 2314*7c478bd9Sstevel@tonic-gate * pHCI/Client device node whose path address matches "paddr". 2315*7c478bd9Sstevel@tonic-gate * Returns a pointer to the mdi_pathinfo node if a matching node is 2316*7c478bd9Sstevel@tonic-gate * found. 2317*7c478bd9Sstevel@tonic-gate * Return Values: 2318*7c478bd9Sstevel@tonic-gate * mdi_pathinfo node handle 2319*7c478bd9Sstevel@tonic-gate * NULL 2320*7c478bd9Sstevel@tonic-gate * Notes: 2321*7c478bd9Sstevel@tonic-gate * Caller need not hold any locks to call this function. 2322*7c478bd9Sstevel@tonic-gate */ 2323*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t * 2324*7c478bd9Sstevel@tonic-gate mdi_pi_find(dev_info_t *pdip, char *caddr, char *paddr) 2325*7c478bd9Sstevel@tonic-gate { 2326*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 2327*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 2328*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 2329*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 2330*7c478bd9Sstevel@tonic-gate 2331*7c478bd9Sstevel@tonic-gate if ((pdip == NULL) || (paddr == NULL)) { 2332*7c478bd9Sstevel@tonic-gate return (NULL); 2333*7c478bd9Sstevel@tonic-gate } 2334*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 2335*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 2336*7c478bd9Sstevel@tonic-gate /* 2337*7c478bd9Sstevel@tonic-gate * Invalid pHCI device, Nothing more to do. 2338*7c478bd9Sstevel@tonic-gate */ 2339*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, NULL, 2340*7c478bd9Sstevel@tonic-gate "!mdi_pi_find: invalid phci")); 2341*7c478bd9Sstevel@tonic-gate return (NULL); 2342*7c478bd9Sstevel@tonic-gate } 2343*7c478bd9Sstevel@tonic-gate 2344*7c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 2345*7c478bd9Sstevel@tonic-gate if (vh == NULL) { 2346*7c478bd9Sstevel@tonic-gate /* 2347*7c478bd9Sstevel@tonic-gate * Invalid vHCI device, Nothing more to do. 2348*7c478bd9Sstevel@tonic-gate */ 2349*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, NULL, 2350*7c478bd9Sstevel@tonic-gate "!mdi_pi_find: invalid phci")); 2351*7c478bd9Sstevel@tonic-gate return (NULL); 2352*7c478bd9Sstevel@tonic-gate } 2353*7c478bd9Sstevel@tonic-gate 2354*7c478bd9Sstevel@tonic-gate /* 2355*7c478bd9Sstevel@tonic-gate * Look for client device identified by caddr (guid) 2356*7c478bd9Sstevel@tonic-gate */ 2357*7c478bd9Sstevel@tonic-gate if (caddr == NULL) { 2358*7c478bd9Sstevel@tonic-gate /* 2359*7c478bd9Sstevel@tonic-gate * Find a mdi_pathinfo node under pHCI list for a matching 2360*7c478bd9Sstevel@tonic-gate * unit address. 2361*7c478bd9Sstevel@tonic-gate */ 2362*7c478bd9Sstevel@tonic-gate mutex_enter(&ph->ph_mutex); 2363*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ph->ph_path_head; 2364*7c478bd9Sstevel@tonic-gate 2365*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 2366*7c478bd9Sstevel@tonic-gate if (strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 2367*7c478bd9Sstevel@tonic-gate break; 2368*7c478bd9Sstevel@tonic-gate } 2369*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 2370*7c478bd9Sstevel@tonic-gate } 2371*7c478bd9Sstevel@tonic-gate mutex_exit(&ph->ph_mutex); 2372*7c478bd9Sstevel@tonic-gate return (pip); 2373*7c478bd9Sstevel@tonic-gate } 2374*7c478bd9Sstevel@tonic-gate 2375*7c478bd9Sstevel@tonic-gate /* 2376*7c478bd9Sstevel@tonic-gate * Find the client device corresponding to 'caddr' 2377*7c478bd9Sstevel@tonic-gate */ 2378*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 2379*7c478bd9Sstevel@tonic-gate ct = i_mdi_client_find(vh, caddr); 2380*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 2381*7c478bd9Sstevel@tonic-gate /* 2382*7c478bd9Sstevel@tonic-gate * Client not found, Obviously mdi_pathinfo node has not been 2383*7c478bd9Sstevel@tonic-gate * created yet. 2384*7c478bd9Sstevel@tonic-gate */ 2385*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 2386*7c478bd9Sstevel@tonic-gate return (pip); 2387*7c478bd9Sstevel@tonic-gate } 2388*7c478bd9Sstevel@tonic-gate 2389*7c478bd9Sstevel@tonic-gate /* 2390*7c478bd9Sstevel@tonic-gate * Hold the client lock and look for a mdi_pathinfo node with matching 2391*7c478bd9Sstevel@tonic-gate * pHCI and paddr 2392*7c478bd9Sstevel@tonic-gate */ 2393*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 2394*7c478bd9Sstevel@tonic-gate 2395*7c478bd9Sstevel@tonic-gate /* 2396*7c478bd9Sstevel@tonic-gate * Release the global mutex as it is no more needed. Note: We always 2397*7c478bd9Sstevel@tonic-gate * respect the locking order while acquiring. 2398*7c478bd9Sstevel@tonic-gate */ 2399*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 2400*7c478bd9Sstevel@tonic-gate 2401*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 2402*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 2403*7c478bd9Sstevel@tonic-gate /* 2404*7c478bd9Sstevel@tonic-gate * Compare the unit address 2405*7c478bd9Sstevel@tonic-gate */ 2406*7c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 2407*7c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 2408*7c478bd9Sstevel@tonic-gate break; 2409*7c478bd9Sstevel@tonic-gate } 2410*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 2411*7c478bd9Sstevel@tonic-gate } 2412*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 2413*7c478bd9Sstevel@tonic-gate return (pip); 2414*7c478bd9Sstevel@tonic-gate } 2415*7c478bd9Sstevel@tonic-gate 2416*7c478bd9Sstevel@tonic-gate /* 2417*7c478bd9Sstevel@tonic-gate * mdi_pi_alloc(): 2418*7c478bd9Sstevel@tonic-gate * Allocate and initialize a new instance of a mdi_pathinfo node. 2419*7c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function identifies a 2420*7c478bd9Sstevel@tonic-gate * unique device path is capable of having properties attached 2421*7c478bd9Sstevel@tonic-gate * and passed to mdi_pi_online() to fully attach and online the 2422*7c478bd9Sstevel@tonic-gate * path and client device node. 2423*7c478bd9Sstevel@tonic-gate * The mdi_pathinfo node returned by this function must be 2424*7c478bd9Sstevel@tonic-gate * destroyed using mdi_pi_free() if the path is no longer 2425*7c478bd9Sstevel@tonic-gate * operational or if the caller fails to attach a client device 2426*7c478bd9Sstevel@tonic-gate * node when calling mdi_pi_online(). The framework will not free 2427*7c478bd9Sstevel@tonic-gate * the resources allocated. 2428*7c478bd9Sstevel@tonic-gate * This function can be called from both interrupt and kernel 2429*7c478bd9Sstevel@tonic-gate * contexts. DDI_NOSLEEP flag should be used while calling 2430*7c478bd9Sstevel@tonic-gate * from interrupt contexts. 2431*7c478bd9Sstevel@tonic-gate * Return Values: 2432*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 2433*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 2434*7c478bd9Sstevel@tonic-gate * MDI_NOMEM 2435*7c478bd9Sstevel@tonic-gate */ 2436*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2437*7c478bd9Sstevel@tonic-gate int 2438*7c478bd9Sstevel@tonic-gate mdi_pi_alloc_compatible(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 2439*7c478bd9Sstevel@tonic-gate char **compatible, int ncompatible, int flags, mdi_pathinfo_t **ret_pip) 2440*7c478bd9Sstevel@tonic-gate { 2441*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 2442*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 2443*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 2444*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 2445*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 2446*7c478bd9Sstevel@tonic-gate int rv = MDI_NOMEM; 2447*7c478bd9Sstevel@tonic-gate 2448*7c478bd9Sstevel@tonic-gate if (pdip == NULL || cname == NULL || caddr == NULL || paddr == NULL || 2449*7c478bd9Sstevel@tonic-gate ret_pip == NULL) { 2450*7c478bd9Sstevel@tonic-gate /* Nothing more to do */ 2451*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 2452*7c478bd9Sstevel@tonic-gate } 2453*7c478bd9Sstevel@tonic-gate 2454*7c478bd9Sstevel@tonic-gate *ret_pip = NULL; 2455*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 2456*7c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 2457*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 2458*7c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 2459*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2460*7c478bd9Sstevel@tonic-gate "!mdi_pi_alloc: invalid pHCI=%p", pdip)); 2461*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 2462*7c478bd9Sstevel@tonic-gate } 2463*7c478bd9Sstevel@tonic-gate 2464*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 2465*7c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 2466*7c478bd9Sstevel@tonic-gate if (vh == NULL) { 2467*7c478bd9Sstevel@tonic-gate /* Invalid vHCI device, return failure */ 2468*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2469*7c478bd9Sstevel@tonic-gate "!mdi_pi_alloc: invalid pHCI=%p", pdip)); 2470*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 2471*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 2472*7c478bd9Sstevel@tonic-gate } 2473*7c478bd9Sstevel@tonic-gate 2474*7c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 2475*7c478bd9Sstevel@tonic-gate /* 2476*7c478bd9Sstevel@tonic-gate * Do not allow new node creation when pHCI is in 2477*7c478bd9Sstevel@tonic-gate * offline/suspended states 2478*7c478bd9Sstevel@tonic-gate */ 2479*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2480*7c478bd9Sstevel@tonic-gate "mdi_pi_alloc: pHCI=%p is not ready", ph)); 2481*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 2482*7c478bd9Sstevel@tonic-gate return (MDI_BUSY); 2483*7c478bd9Sstevel@tonic-gate } 2484*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 2485*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 2486*7c478bd9Sstevel@tonic-gate 2487*7c478bd9Sstevel@tonic-gate /* 2488*7c478bd9Sstevel@tonic-gate * Look for a client device with matching guid identified by caddr, 2489*7c478bd9Sstevel@tonic-gate * If not found create one 2490*7c478bd9Sstevel@tonic-gate */ 2491*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 2492*7c478bd9Sstevel@tonic-gate ct = i_mdi_client_find(vh, caddr); 2493*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 2494*7c478bd9Sstevel@tonic-gate ct = i_mdi_client_alloc(vh, cname, caddr, flags); 2495*7c478bd9Sstevel@tonic-gate if (ct == NULL) 2496*7c478bd9Sstevel@tonic-gate goto fail; 2497*7c478bd9Sstevel@tonic-gate } 2498*7c478bd9Sstevel@tonic-gate 2499*7c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 2500*7c478bd9Sstevel@tonic-gate /* 2501*7c478bd9Sstevel@tonic-gate * Allocate a devinfo node 2502*7c478bd9Sstevel@tonic-gate */ 2503*7c478bd9Sstevel@tonic-gate ct->ct_dip = i_mdi_devinfo_create(vh, cname, caddr, 2504*7c478bd9Sstevel@tonic-gate compatible, ncompatible, flags); 2505*7c478bd9Sstevel@tonic-gate if (ct->ct_dip == NULL) { 2506*7c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(vh, ct); 2507*7c478bd9Sstevel@tonic-gate goto fail; 2508*7c478bd9Sstevel@tonic-gate } 2509*7c478bd9Sstevel@tonic-gate } 2510*7c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 2511*7c478bd9Sstevel@tonic-gate 2512*7c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_component |= MDI_COMPONENT_CLIENT; 2513*7c478bd9Sstevel@tonic-gate DEVI(cdip)->devi_mdi_client = (caddr_t)ct; 2514*7c478bd9Sstevel@tonic-gate 2515*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 2516*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 2517*7c478bd9Sstevel@tonic-gate /* 2518*7c478bd9Sstevel@tonic-gate * Compare the unit address 2519*7c478bd9Sstevel@tonic-gate */ 2520*7c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_phci == ph) && 2521*7c478bd9Sstevel@tonic-gate strcmp(MDI_PI(pip)->pi_addr, paddr) == 0) { 2522*7c478bd9Sstevel@tonic-gate break; 2523*7c478bd9Sstevel@tonic-gate } 2524*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 2525*7c478bd9Sstevel@tonic-gate } 2526*7c478bd9Sstevel@tonic-gate 2527*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 2528*7c478bd9Sstevel@tonic-gate /* 2529*7c478bd9Sstevel@tonic-gate * This is a new path for this client device. Allocate and 2530*7c478bd9Sstevel@tonic-gate * initialize a new pathinfo node 2531*7c478bd9Sstevel@tonic-gate */ 2532*7c478bd9Sstevel@tonic-gate pip = i_mdi_pi_alloc(ph, paddr, ct, flags); 2533*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 2534*7c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(vh, ct); 2535*7c478bd9Sstevel@tonic-gate goto fail; 2536*7c478bd9Sstevel@tonic-gate } 2537*7c478bd9Sstevel@tonic-gate } 2538*7c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 2539*7c478bd9Sstevel@tonic-gate 2540*7c478bd9Sstevel@tonic-gate fail: 2541*7c478bd9Sstevel@tonic-gate /* 2542*7c478bd9Sstevel@tonic-gate * Release the global mutex. 2543*7c478bd9Sstevel@tonic-gate */ 2544*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 2545*7c478bd9Sstevel@tonic-gate 2546*7c478bd9Sstevel@tonic-gate /* 2547*7c478bd9Sstevel@tonic-gate * Mark the pHCI as stable 2548*7c478bd9Sstevel@tonic-gate */ 2549*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 2550*7c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 2551*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 2552*7c478bd9Sstevel@tonic-gate *ret_pip = pip; 2553*7c478bd9Sstevel@tonic-gate return (rv); 2554*7c478bd9Sstevel@tonic-gate } 2555*7c478bd9Sstevel@tonic-gate 2556*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2557*7c478bd9Sstevel@tonic-gate int 2558*7c478bd9Sstevel@tonic-gate mdi_pi_alloc(dev_info_t *pdip, char *cname, char *caddr, char *paddr, 2559*7c478bd9Sstevel@tonic-gate int flags, mdi_pathinfo_t **ret_pip) 2560*7c478bd9Sstevel@tonic-gate { 2561*7c478bd9Sstevel@tonic-gate return (mdi_pi_alloc_compatible(pdip, cname, caddr, paddr, NULL, 0, 2562*7c478bd9Sstevel@tonic-gate flags, ret_pip)); 2563*7c478bd9Sstevel@tonic-gate } 2564*7c478bd9Sstevel@tonic-gate 2565*7c478bd9Sstevel@tonic-gate /* 2566*7c478bd9Sstevel@tonic-gate * i_mdi_pi_alloc(): 2567*7c478bd9Sstevel@tonic-gate * Allocate a mdi_pathinfo node and add to the pHCI path list 2568*7c478bd9Sstevel@tonic-gate * Return Values: 2569*7c478bd9Sstevel@tonic-gate * mdi_pathinfo 2570*7c478bd9Sstevel@tonic-gate */ 2571*7c478bd9Sstevel@tonic-gate 2572*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2573*7c478bd9Sstevel@tonic-gate static mdi_pathinfo_t * 2574*7c478bd9Sstevel@tonic-gate i_mdi_pi_alloc(mdi_phci_t *ph, char *paddr, mdi_client_t *ct, int flags) 2575*7c478bd9Sstevel@tonic-gate { 2576*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip = NULL; 2577*7c478bd9Sstevel@tonic-gate char *pi_addr = NULL; 2578*7c478bd9Sstevel@tonic-gate nvlist_t *pi_prop = NULL; 2579*7c478bd9Sstevel@tonic-gate 2580*7c478bd9Sstevel@tonic-gate int ct_circular; 2581*7c478bd9Sstevel@tonic-gate int ph_circular; 2582*7c478bd9Sstevel@tonic-gate 2583*7c478bd9Sstevel@tonic-gate pip = kmem_zalloc(sizeof (struct mdi_pathinfo), 2584*7c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 2585*7c478bd9Sstevel@tonic-gate if (pip == NULL) 2586*7c478bd9Sstevel@tonic-gate goto fail; 2587*7c478bd9Sstevel@tonic-gate mutex_init(&MDI_PI(pip)->pi_mutex, NULL, MUTEX_DEFAULT, NULL); 2588*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PATHINFO_STATE_INIT | 2589*7c478bd9Sstevel@tonic-gate MDI_PATHINFO_STATE_TRANSIENT; 2590*7c478bd9Sstevel@tonic-gate 2591*7c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_USER_DISABLED(ph)) 2592*7c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 2593*7c478bd9Sstevel@tonic-gate 2594*7c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED_TRANSIENT(ph)) 2595*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 2596*7c478bd9Sstevel@tonic-gate 2597*7c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_DRV_DISABLED(ph)) 2598*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 2599*7c478bd9Sstevel@tonic-gate 2600*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_old_state = MDI_PATHINFO_STATE_INIT; 2601*7c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_state_cv, NULL, CV_DEFAULT, NULL); 2602*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = ct; 2603*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = ph; 2604*7c478bd9Sstevel@tonic-gate pi_addr = 2605*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr = kmem_alloc(strlen(paddr) + 1, 2606*7c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 2607*7c478bd9Sstevel@tonic-gate if (pi_addr == NULL) 2608*7c478bd9Sstevel@tonic-gate goto fail; 2609*7c478bd9Sstevel@tonic-gate (void) strcpy(MDI_PI(pip)->pi_addr, paddr); 2610*7c478bd9Sstevel@tonic-gate (void) nvlist_alloc(&pi_prop, NV_UNIQUE_NAME, 2611*7c478bd9Sstevel@tonic-gate (flags == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 2612*7c478bd9Sstevel@tonic-gate if (pi_prop == NULL) 2613*7c478bd9Sstevel@tonic-gate goto fail; 2614*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_prop = pi_prop; 2615*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = NULL; 2616*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = NULL; 2617*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = NULL; 2618*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 2619*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 2620*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt = 0; 2621*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 2622*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = 1; 2623*7c478bd9Sstevel@tonic-gate cv_init(&MDI_PI(pip)->pi_ref_cv, NULL, CV_DEFAULT, NULL); 2624*7c478bd9Sstevel@tonic-gate 2625*7c478bd9Sstevel@tonic-gate /* 2626*7c478bd9Sstevel@tonic-gate * Lock both dev_info nodes against changes in parallel. 2627*7c478bd9Sstevel@tonic-gate */ 2628*7c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 2629*7c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 2630*7c478bd9Sstevel@tonic-gate 2631*7c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(ph, pip); 2632*7c478bd9Sstevel@tonic-gate i_mdi_client_add_path(ct, pip); 2633*7c478bd9Sstevel@tonic-gate 2634*7c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 2635*7c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 2636*7c478bd9Sstevel@tonic-gate 2637*7c478bd9Sstevel@tonic-gate return (pip); 2638*7c478bd9Sstevel@tonic-gate 2639*7c478bd9Sstevel@tonic-gate fail: 2640*7c478bd9Sstevel@tonic-gate if (pi_prop) 2641*7c478bd9Sstevel@tonic-gate (void) nvlist_free(pi_prop); 2642*7c478bd9Sstevel@tonic-gate if (pi_addr) 2643*7c478bd9Sstevel@tonic-gate kmem_free(pi_addr, strlen(paddr) + 1); 2644*7c478bd9Sstevel@tonic-gate kmem_free(pip, sizeof (struct mdi_pathinfo)); 2645*7c478bd9Sstevel@tonic-gate return (NULL); 2646*7c478bd9Sstevel@tonic-gate } 2647*7c478bd9Sstevel@tonic-gate 2648*7c478bd9Sstevel@tonic-gate /* 2649*7c478bd9Sstevel@tonic-gate * i_mdi_phci_add_path(): 2650*7c478bd9Sstevel@tonic-gate * Add a mdi_pathinfo node to pHCI list. 2651*7c478bd9Sstevel@tonic-gate * Notes: 2652*7c478bd9Sstevel@tonic-gate * Caller should per-pHCI mutex 2653*7c478bd9Sstevel@tonic-gate */ 2654*7c478bd9Sstevel@tonic-gate 2655*7c478bd9Sstevel@tonic-gate static void 2656*7c478bd9Sstevel@tonic-gate i_mdi_phci_add_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 2657*7c478bd9Sstevel@tonic-gate { 2658*7c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 2659*7c478bd9Sstevel@tonic-gate 2660*7c478bd9Sstevel@tonic-gate if (ph->ph_path_head == NULL) { 2661*7c478bd9Sstevel@tonic-gate ph->ph_path_head = pip; 2662*7c478bd9Sstevel@tonic-gate } else { 2663*7c478bd9Sstevel@tonic-gate MDI_PI(ph->ph_path_tail)->pi_phci_link = MDI_PI(pip); 2664*7c478bd9Sstevel@tonic-gate } 2665*7c478bd9Sstevel@tonic-gate ph->ph_path_tail = pip; 2666*7c478bd9Sstevel@tonic-gate ph->ph_path_count++; 2667*7c478bd9Sstevel@tonic-gate } 2668*7c478bd9Sstevel@tonic-gate 2669*7c478bd9Sstevel@tonic-gate /* 2670*7c478bd9Sstevel@tonic-gate * i_mdi_client_add_path(): 2671*7c478bd9Sstevel@tonic-gate * Add mdi_pathinfo node to client list 2672*7c478bd9Sstevel@tonic-gate */ 2673*7c478bd9Sstevel@tonic-gate 2674*7c478bd9Sstevel@tonic-gate static void 2675*7c478bd9Sstevel@tonic-gate i_mdi_client_add_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 2676*7c478bd9Sstevel@tonic-gate { 2677*7c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 2678*7c478bd9Sstevel@tonic-gate 2679*7c478bd9Sstevel@tonic-gate if (ct->ct_path_head == NULL) { 2680*7c478bd9Sstevel@tonic-gate ct->ct_path_head = pip; 2681*7c478bd9Sstevel@tonic-gate } else { 2682*7c478bd9Sstevel@tonic-gate MDI_PI(ct->ct_path_tail)->pi_client_link = MDI_PI(pip); 2683*7c478bd9Sstevel@tonic-gate } 2684*7c478bd9Sstevel@tonic-gate ct->ct_path_tail = pip; 2685*7c478bd9Sstevel@tonic-gate ct->ct_path_count++; 2686*7c478bd9Sstevel@tonic-gate } 2687*7c478bd9Sstevel@tonic-gate 2688*7c478bd9Sstevel@tonic-gate /* 2689*7c478bd9Sstevel@tonic-gate * mdi_pi_free(): 2690*7c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node and also client device node if this 2691*7c478bd9Sstevel@tonic-gate * is the last path to the device 2692*7c478bd9Sstevel@tonic-gate * Return Values: 2693*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 2694*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 2695*7c478bd9Sstevel@tonic-gate * MDI_BUSY 2696*7c478bd9Sstevel@tonic-gate */ 2697*7c478bd9Sstevel@tonic-gate 2698*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2699*7c478bd9Sstevel@tonic-gate int 2700*7c478bd9Sstevel@tonic-gate mdi_pi_free(mdi_pathinfo_t *pip, int flags) 2701*7c478bd9Sstevel@tonic-gate { 2702*7c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 2703*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 2704*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 2705*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 2706*7c478bd9Sstevel@tonic-gate int (*f)(); 2707*7c478bd9Sstevel@tonic-gate int client_held = 0; 2708*7c478bd9Sstevel@tonic-gate 2709*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 2710*7c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 2711*7c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 2712*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 2713*7c478bd9Sstevel@tonic-gate /* 2714*7c478bd9Sstevel@tonic-gate * Invalid pHCI device, return failure 2715*7c478bd9Sstevel@tonic-gate */ 2716*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2717*7c478bd9Sstevel@tonic-gate "!mdi_pi_free: invalid pHCI")); 2718*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2719*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 2720*7c478bd9Sstevel@tonic-gate } 2721*7c478bd9Sstevel@tonic-gate 2722*7c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 2723*7c478bd9Sstevel@tonic-gate ASSERT(vh != NULL); 2724*7c478bd9Sstevel@tonic-gate if (vh == NULL) { 2725*7c478bd9Sstevel@tonic-gate /* Invalid pHCI device, return failure */ 2726*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2727*7c478bd9Sstevel@tonic-gate "!mdi_pi_free: invalid vHCI")); 2728*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2729*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 2730*7c478bd9Sstevel@tonic-gate } 2731*7c478bd9Sstevel@tonic-gate 2732*7c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 2733*7c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 2734*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 2735*7c478bd9Sstevel@tonic-gate /* 2736*7c478bd9Sstevel@tonic-gate * Invalid Client device, return failure 2737*7c478bd9Sstevel@tonic-gate */ 2738*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2739*7c478bd9Sstevel@tonic-gate "!mdi_pi_free: invalid client")); 2740*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2741*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 2742*7c478bd9Sstevel@tonic-gate } 2743*7c478bd9Sstevel@tonic-gate 2744*7c478bd9Sstevel@tonic-gate /* 2745*7c478bd9Sstevel@tonic-gate * Check to see for busy condition. A mdi_pathinfo can only be freed 2746*7c478bd9Sstevel@tonic-gate * if the node state is either offline or init and the reference count 2747*7c478bd9Sstevel@tonic-gate * is zero. 2748*7c478bd9Sstevel@tonic-gate */ 2749*7c478bd9Sstevel@tonic-gate if (!(MDI_PI_IS_OFFLINE(pip) || MDI_PI_IS_INIT(pip) || 2750*7c478bd9Sstevel@tonic-gate MDI_PI_IS_INITING(pip))) { 2751*7c478bd9Sstevel@tonic-gate /* 2752*7c478bd9Sstevel@tonic-gate * Node is busy 2753*7c478bd9Sstevel@tonic-gate */ 2754*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2755*7c478bd9Sstevel@tonic-gate "!mdi_pi_free: pathinfo node is busy pip=%p", pip)); 2756*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2757*7c478bd9Sstevel@tonic-gate return (MDI_BUSY); 2758*7c478bd9Sstevel@tonic-gate } 2759*7c478bd9Sstevel@tonic-gate 2760*7c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 2761*7c478bd9Sstevel@tonic-gate /* 2762*7c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 2763*7c478bd9Sstevel@tonic-gate */ 2764*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, "!i_mdi_pi_free: " 2765*7c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 2766*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 2767*7c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 2768*7c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 2769*7c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 2770*7c478bd9Sstevel@tonic-gate /* 2771*7c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 2772*7c478bd9Sstevel@tonic-gate * being signaled. 2773*7c478bd9Sstevel@tonic-gate */ 2774*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, 2775*7c478bd9Sstevel@tonic-gate "!i_mdi_pi_free: " 2776*7c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 2777*7c478bd9Sstevel@tonic-gate pip)); 2778*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, ct->ct_vhci->vh_dip, 2779*7c478bd9Sstevel@tonic-gate "!i_mdi_pi_free: " 2780*7c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 2781*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 2782*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2783*7c478bd9Sstevel@tonic-gate return (MDI_BUSY); 2784*7c478bd9Sstevel@tonic-gate } 2785*7c478bd9Sstevel@tonic-gate } 2786*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 2787*7c478bd9Sstevel@tonic-gate client_held = 1; 2788*7c478bd9Sstevel@tonic-gate } 2789*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2790*7c478bd9Sstevel@tonic-gate 2791*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 2792*7c478bd9Sstevel@tonic-gate 2793*7c478bd9Sstevel@tonic-gate /* Prevent further failovers till mdi_mutex is held */ 2794*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_PATH_FREE_IN_PROGRESS(ct); 2795*7c478bd9Sstevel@tonic-gate 2796*7c478bd9Sstevel@tonic-gate /* 2797*7c478bd9Sstevel@tonic-gate * Wait till failover is complete before removing this node. 2798*7c478bd9Sstevel@tonic-gate */ 2799*7c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 2800*7c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 2801*7c478bd9Sstevel@tonic-gate 2802*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 2803*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 2804*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 2805*7c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_PATH_FREE_IN_PROGRESS(ct); 2806*7c478bd9Sstevel@tonic-gate 2807*7c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_INITING(pip)) { 2808*7c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_uninit; 2809*7c478bd9Sstevel@tonic-gate if (f != NULL) { 2810*7c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 2811*7c478bd9Sstevel@tonic-gate } 2812*7c478bd9Sstevel@tonic-gate } 2813*7c478bd9Sstevel@tonic-gate /* 2814*7c478bd9Sstevel@tonic-gate * If vo_pi_uninit() completed successfully. 2815*7c478bd9Sstevel@tonic-gate */ 2816*7c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 2817*7c478bd9Sstevel@tonic-gate if (client_held) { 2818*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_free " 2819*7c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 2820*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 2821*7c478bd9Sstevel@tonic-gate } 2822*7c478bd9Sstevel@tonic-gate i_mdi_pi_free(ph, pip, ct); 2823*7c478bd9Sstevel@tonic-gate if (ct->ct_path_count == 0) { 2824*7c478bd9Sstevel@tonic-gate /* 2825*7c478bd9Sstevel@tonic-gate * Client lost its last path. 2826*7c478bd9Sstevel@tonic-gate * Clean up the client device 2827*7c478bd9Sstevel@tonic-gate */ 2828*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 2829*7c478bd9Sstevel@tonic-gate (void) i_mdi_client_free(ct->ct_vhci, ct); 2830*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 2831*7c478bd9Sstevel@tonic-gate return (rv); 2832*7c478bd9Sstevel@tonic-gate } 2833*7c478bd9Sstevel@tonic-gate } 2834*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 2835*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 2836*7c478bd9Sstevel@tonic-gate return (rv); 2837*7c478bd9Sstevel@tonic-gate } 2838*7c478bd9Sstevel@tonic-gate 2839*7c478bd9Sstevel@tonic-gate /* 2840*7c478bd9Sstevel@tonic-gate * i_mdi_pi_free(): 2841*7c478bd9Sstevel@tonic-gate * Free the mdi_pathinfo node 2842*7c478bd9Sstevel@tonic-gate */ 2843*7c478bd9Sstevel@tonic-gate static void 2844*7c478bd9Sstevel@tonic-gate i_mdi_pi_free(mdi_phci_t *ph, mdi_pathinfo_t *pip, mdi_client_t *ct) 2845*7c478bd9Sstevel@tonic-gate { 2846*7c478bd9Sstevel@tonic-gate int ct_circular; 2847*7c478bd9Sstevel@tonic-gate int ph_circular; 2848*7c478bd9Sstevel@tonic-gate 2849*7c478bd9Sstevel@tonic-gate /* 2850*7c478bd9Sstevel@tonic-gate * remove any per-path kstats 2851*7c478bd9Sstevel@tonic-gate */ 2852*7c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(pip); 2853*7c478bd9Sstevel@tonic-gate 2854*7c478bd9Sstevel@tonic-gate ndi_devi_enter(ct->ct_dip, &ct_circular); 2855*7c478bd9Sstevel@tonic-gate ndi_devi_enter(ph->ph_dip, &ph_circular); 2856*7c478bd9Sstevel@tonic-gate 2857*7c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(ct, pip); 2858*7c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(ph, pip); 2859*7c478bd9Sstevel@tonic-gate 2860*7c478bd9Sstevel@tonic-gate ndi_devi_exit(ph->ph_dip, ph_circular); 2861*7c478bd9Sstevel@tonic-gate ndi_devi_exit(ct->ct_dip, ct_circular); 2862*7c478bd9Sstevel@tonic-gate 2863*7c478bd9Sstevel@tonic-gate mutex_destroy(&MDI_PI(pip)->pi_mutex); 2864*7c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_state_cv); 2865*7c478bd9Sstevel@tonic-gate cv_destroy(&MDI_PI(pip)->pi_ref_cv); 2866*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_addr) { 2867*7c478bd9Sstevel@tonic-gate kmem_free(MDI_PI(pip)->pi_addr, 2868*7c478bd9Sstevel@tonic-gate strlen(MDI_PI(pip)->pi_addr) + 1); 2869*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr = NULL; 2870*7c478bd9Sstevel@tonic-gate } 2871*7c478bd9Sstevel@tonic-gate 2872*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop) { 2873*7c478bd9Sstevel@tonic-gate (void) nvlist_free(MDI_PI(pip)->pi_prop); 2874*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_prop = NULL; 2875*7c478bd9Sstevel@tonic-gate } 2876*7c478bd9Sstevel@tonic-gate kmem_free(pip, sizeof (struct mdi_pathinfo)); 2877*7c478bd9Sstevel@tonic-gate } 2878*7c478bd9Sstevel@tonic-gate 2879*7c478bd9Sstevel@tonic-gate 2880*7c478bd9Sstevel@tonic-gate /* 2881*7c478bd9Sstevel@tonic-gate * i_mdi_phci_remove_path(): 2882*7c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from pHCI list. 2883*7c478bd9Sstevel@tonic-gate * Notes: 2884*7c478bd9Sstevel@tonic-gate * Caller should hold per-pHCI mutex 2885*7c478bd9Sstevel@tonic-gate */ 2886*7c478bd9Sstevel@tonic-gate 2887*7c478bd9Sstevel@tonic-gate static void 2888*7c478bd9Sstevel@tonic-gate i_mdi_phci_remove_path(mdi_phci_t *ph, mdi_pathinfo_t *pip) 2889*7c478bd9Sstevel@tonic-gate { 2890*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 2891*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path = NULL; 2892*7c478bd9Sstevel@tonic-gate 2893*7c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ph->ph_dip)); 2894*7c478bd9Sstevel@tonic-gate 2895*7c478bd9Sstevel@tonic-gate path = ph->ph_path_head; 2896*7c478bd9Sstevel@tonic-gate while (path != NULL) { 2897*7c478bd9Sstevel@tonic-gate if (path == pip) { 2898*7c478bd9Sstevel@tonic-gate break; 2899*7c478bd9Sstevel@tonic-gate } 2900*7c478bd9Sstevel@tonic-gate prev = path; 2901*7c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 2902*7c478bd9Sstevel@tonic-gate } 2903*7c478bd9Sstevel@tonic-gate 2904*7c478bd9Sstevel@tonic-gate if (path) { 2905*7c478bd9Sstevel@tonic-gate ph->ph_path_count--; 2906*7c478bd9Sstevel@tonic-gate if (prev) { 2907*7c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_phci_link = MDI_PI(path)->pi_phci_link; 2908*7c478bd9Sstevel@tonic-gate } else { 2909*7c478bd9Sstevel@tonic-gate ph->ph_path_head = 2910*7c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_phci_link; 2911*7c478bd9Sstevel@tonic-gate } 2912*7c478bd9Sstevel@tonic-gate if (ph->ph_path_tail == path) { 2913*7c478bd9Sstevel@tonic-gate ph->ph_path_tail = prev; 2914*7c478bd9Sstevel@tonic-gate } 2915*7c478bd9Sstevel@tonic-gate } 2916*7c478bd9Sstevel@tonic-gate 2917*7c478bd9Sstevel@tonic-gate /* 2918*7c478bd9Sstevel@tonic-gate * Clear the pHCI link 2919*7c478bd9Sstevel@tonic-gate */ 2920*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci_link = NULL; 2921*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_phci = NULL; 2922*7c478bd9Sstevel@tonic-gate } 2923*7c478bd9Sstevel@tonic-gate 2924*7c478bd9Sstevel@tonic-gate /* 2925*7c478bd9Sstevel@tonic-gate * i_mdi_client_remove_path(): 2926*7c478bd9Sstevel@tonic-gate * Remove a mdi_pathinfo node from client path list. 2927*7c478bd9Sstevel@tonic-gate */ 2928*7c478bd9Sstevel@tonic-gate 2929*7c478bd9Sstevel@tonic-gate static void 2930*7c478bd9Sstevel@tonic-gate i_mdi_client_remove_path(mdi_client_t *ct, mdi_pathinfo_t *pip) 2931*7c478bd9Sstevel@tonic-gate { 2932*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *prev = NULL; 2933*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *path; 2934*7c478bd9Sstevel@tonic-gate 2935*7c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(ct->ct_dip)); 2936*7c478bd9Sstevel@tonic-gate 2937*7c478bd9Sstevel@tonic-gate path = ct->ct_path_head; 2938*7c478bd9Sstevel@tonic-gate while (path != NULL) { 2939*7c478bd9Sstevel@tonic-gate if (path == pip) { 2940*7c478bd9Sstevel@tonic-gate break; 2941*7c478bd9Sstevel@tonic-gate } 2942*7c478bd9Sstevel@tonic-gate prev = path; 2943*7c478bd9Sstevel@tonic-gate path = (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 2944*7c478bd9Sstevel@tonic-gate } 2945*7c478bd9Sstevel@tonic-gate 2946*7c478bd9Sstevel@tonic-gate if (path) { 2947*7c478bd9Sstevel@tonic-gate ct->ct_path_count--; 2948*7c478bd9Sstevel@tonic-gate if (prev) { 2949*7c478bd9Sstevel@tonic-gate MDI_PI(prev)->pi_client_link = 2950*7c478bd9Sstevel@tonic-gate MDI_PI(path)->pi_client_link; 2951*7c478bd9Sstevel@tonic-gate } else { 2952*7c478bd9Sstevel@tonic-gate ct->ct_path_head = 2953*7c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(path)->pi_client_link; 2954*7c478bd9Sstevel@tonic-gate } 2955*7c478bd9Sstevel@tonic-gate if (ct->ct_path_tail == path) { 2956*7c478bd9Sstevel@tonic-gate ct->ct_path_tail = prev; 2957*7c478bd9Sstevel@tonic-gate } 2958*7c478bd9Sstevel@tonic-gate if (ct->ct_path_last == path) { 2959*7c478bd9Sstevel@tonic-gate ct->ct_path_last = ct->ct_path_head; 2960*7c478bd9Sstevel@tonic-gate } 2961*7c478bd9Sstevel@tonic-gate } 2962*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link = NULL; 2963*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client = NULL; 2964*7c478bd9Sstevel@tonic-gate } 2965*7c478bd9Sstevel@tonic-gate 2966*7c478bd9Sstevel@tonic-gate /* 2967*7c478bd9Sstevel@tonic-gate * i_mdi_pi_state_change(): 2968*7c478bd9Sstevel@tonic-gate * online a mdi_pathinfo node 2969*7c478bd9Sstevel@tonic-gate * 2970*7c478bd9Sstevel@tonic-gate * Return Values: 2971*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 2972*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 2973*7c478bd9Sstevel@tonic-gate */ 2974*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2975*7c478bd9Sstevel@tonic-gate static int 2976*7c478bd9Sstevel@tonic-gate i_mdi_pi_state_change(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state, int flag) 2977*7c478bd9Sstevel@tonic-gate { 2978*7c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 2979*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 2980*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 2981*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 2982*7c478bd9Sstevel@tonic-gate int (*f)(); 2983*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 2984*7c478bd9Sstevel@tonic-gate 2985*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 2986*7c478bd9Sstevel@tonic-gate 2987*7c478bd9Sstevel@tonic-gate ph = MDI_PI(pip)->pi_phci; 2988*7c478bd9Sstevel@tonic-gate ASSERT(ph); 2989*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 2990*7c478bd9Sstevel@tonic-gate /* 2991*7c478bd9Sstevel@tonic-gate * Invalid pHCI device, fail the request 2992*7c478bd9Sstevel@tonic-gate */ 2993*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 2994*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 2995*7c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: invalid phci")); 2996*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 2997*7c478bd9Sstevel@tonic-gate } 2998*7c478bd9Sstevel@tonic-gate 2999*7c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 3000*7c478bd9Sstevel@tonic-gate ASSERT(vh); 3001*7c478bd9Sstevel@tonic-gate if (vh == NULL) { 3002*7c478bd9Sstevel@tonic-gate /* 3003*7c478bd9Sstevel@tonic-gate * Invalid vHCI device, fail the request 3004*7c478bd9Sstevel@tonic-gate */ 3005*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3006*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 3007*7c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: invalid vhci")); 3008*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 3009*7c478bd9Sstevel@tonic-gate } 3010*7c478bd9Sstevel@tonic-gate 3011*7c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 3012*7c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 3013*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 3014*7c478bd9Sstevel@tonic-gate /* 3015*7c478bd9Sstevel@tonic-gate * Invalid client device, fail the request 3016*7c478bd9Sstevel@tonic-gate */ 3017*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3018*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 3019*7c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: invalid client")); 3020*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 3021*7c478bd9Sstevel@tonic-gate } 3022*7c478bd9Sstevel@tonic-gate 3023*7c478bd9Sstevel@tonic-gate /* 3024*7c478bd9Sstevel@tonic-gate * If this path has not been initialized yet, Callback vHCI driver's 3025*7c478bd9Sstevel@tonic-gate * pathinfo node initialize entry point 3026*7c478bd9Sstevel@tonic-gate */ 3027*7c478bd9Sstevel@tonic-gate 3028*7c478bd9Sstevel@tonic-gate if (MDI_PI_IS_INITING(pip)) { 3029*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3030*7c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_init; 3031*7c478bd9Sstevel@tonic-gate if (f != NULL) { 3032*7c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0); 3033*7c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 3034*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, vh->vh_dip, 3035*7c478bd9Sstevel@tonic-gate "!vo_pi_init: failed vHCI=0x%p, pip=0x%p", 3036*7c478bd9Sstevel@tonic-gate vh, pip)); 3037*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 3038*7c478bd9Sstevel@tonic-gate } 3039*7c478bd9Sstevel@tonic-gate } 3040*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3041*7c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 3042*7c478bd9Sstevel@tonic-gate } 3043*7c478bd9Sstevel@tonic-gate 3044*7c478bd9Sstevel@tonic-gate /* 3045*7c478bd9Sstevel@tonic-gate * Do not allow state transition when pHCI is in offline/suspended 3046*7c478bd9Sstevel@tonic-gate * states 3047*7c478bd9Sstevel@tonic-gate */ 3048*7c478bd9Sstevel@tonic-gate i_mdi_phci_lock(ph, pip); 3049*7c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_READY(ph) == 0) { 3050*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, NULL, 3051*7c478bd9Sstevel@tonic-gate "!mdi_pi_state_change: pHCI not ready, pHCI=%p", ph)); 3052*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3053*7c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 3054*7c478bd9Sstevel@tonic-gate return (MDI_BUSY); 3055*7c478bd9Sstevel@tonic-gate } 3056*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNSTABLE(ph); 3057*7c478bd9Sstevel@tonic-gate i_mdi_phci_unlock(ph); 3058*7c478bd9Sstevel@tonic-gate 3059*7c478bd9Sstevel@tonic-gate /* 3060*7c478bd9Sstevel@tonic-gate * Check if mdi_pathinfo state is in transient state. 3061*7c478bd9Sstevel@tonic-gate * If yes, offlining is in progress and wait till transient state is 3062*7c478bd9Sstevel@tonic-gate * cleared. 3063*7c478bd9Sstevel@tonic-gate */ 3064*7c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 3065*7c478bd9Sstevel@tonic-gate while (MDI_PI_IS_TRANSIENT(pip)) { 3066*7c478bd9Sstevel@tonic-gate cv_wait(&MDI_PI(pip)->pi_state_cv, 3067*7c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex); 3068*7c478bd9Sstevel@tonic-gate } 3069*7c478bd9Sstevel@tonic-gate } 3070*7c478bd9Sstevel@tonic-gate 3071*7c478bd9Sstevel@tonic-gate /* 3072*7c478bd9Sstevel@tonic-gate * Grab the client lock in reverse order sequence and release the 3073*7c478bd9Sstevel@tonic-gate * mdi_pathinfo mutex. 3074*7c478bd9Sstevel@tonic-gate */ 3075*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 3076*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3077*7c478bd9Sstevel@tonic-gate 3078*7c478bd9Sstevel@tonic-gate /* 3079*7c478bd9Sstevel@tonic-gate * Wait till failover state is cleared 3080*7c478bd9Sstevel@tonic-gate */ 3081*7c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) 3082*7c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_failover_cv, &ct->ct_mutex); 3083*7c478bd9Sstevel@tonic-gate 3084*7c478bd9Sstevel@tonic-gate /* 3085*7c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 3086*7c478bd9Sstevel@tonic-gate */ 3087*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3088*7c478bd9Sstevel@tonic-gate switch (state) { 3089*7c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_ONLINE: 3090*7c478bd9Sstevel@tonic-gate MDI_PI_SET_ONLINING(pip); 3091*7c478bd9Sstevel@tonic-gate break; 3092*7c478bd9Sstevel@tonic-gate 3093*7c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_STANDBY: 3094*7c478bd9Sstevel@tonic-gate MDI_PI_SET_STANDBYING(pip); 3095*7c478bd9Sstevel@tonic-gate break; 3096*7c478bd9Sstevel@tonic-gate 3097*7c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_FAULT: 3098*7c478bd9Sstevel@tonic-gate /* 3099*7c478bd9Sstevel@tonic-gate * Mark the pathinfo state as FAULTED 3100*7c478bd9Sstevel@tonic-gate */ 3101*7c478bd9Sstevel@tonic-gate MDI_PI_SET_FAULTING(pip); 3102*7c478bd9Sstevel@tonic-gate MDI_PI_ERRSTAT(pip, MDI_PI_HARDERR); 3103*7c478bd9Sstevel@tonic-gate break; 3104*7c478bd9Sstevel@tonic-gate 3105*7c478bd9Sstevel@tonic-gate case MDI_PATHINFO_STATE_OFFLINE: 3106*7c478bd9Sstevel@tonic-gate /* 3107*7c478bd9Sstevel@tonic-gate * ndi_devi_offline() cannot hold pip or ct locks. 3108*7c478bd9Sstevel@tonic-gate */ 3109*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3110*7c478bd9Sstevel@tonic-gate /* 3111*7c478bd9Sstevel@tonic-gate * Do not offline if path will become last path and path 3112*7c478bd9Sstevel@tonic-gate * is busy for user initiated events. 3113*7c478bd9Sstevel@tonic-gate */ 3114*7c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 3115*7c478bd9Sstevel@tonic-gate if ((flag & NDI_DEVI_REMOVE) && 3116*7c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED)) { 3117*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 3118*7c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 3119*7c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 3120*7c478bd9Sstevel@tonic-gate /* 3121*7c478bd9Sstevel@tonic-gate * Convert to MDI error code 3122*7c478bd9Sstevel@tonic-gate */ 3123*7c478bd9Sstevel@tonic-gate switch (rv) { 3124*7c478bd9Sstevel@tonic-gate case NDI_BUSY: 3125*7c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 3126*7c478bd9Sstevel@tonic-gate break; 3127*7c478bd9Sstevel@tonic-gate default: 3128*7c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 3129*7c478bd9Sstevel@tonic-gate break; 3130*7c478bd9Sstevel@tonic-gate } 3131*7c478bd9Sstevel@tonic-gate goto state_change_exit; 3132*7c478bd9Sstevel@tonic-gate } else { 3133*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 3134*7c478bd9Sstevel@tonic-gate } 3135*7c478bd9Sstevel@tonic-gate } 3136*7c478bd9Sstevel@tonic-gate /* 3137*7c478bd9Sstevel@tonic-gate * Mark the mdi_pathinfo node state as transient 3138*7c478bd9Sstevel@tonic-gate */ 3139*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3140*7c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 3141*7c478bd9Sstevel@tonic-gate break; 3142*7c478bd9Sstevel@tonic-gate } 3143*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3144*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNSTABLE(ct); 3145*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 3146*7c478bd9Sstevel@tonic-gate 3147*7c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 3148*7c478bd9Sstevel@tonic-gate if (f != NULL) { 3149*7c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, state, 0, flag); 3150*7c478bd9Sstevel@tonic-gate if (rv == MDI_NOT_SUPPORTED) { 3151*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DEV_NOT_SUPPORTED(ct); 3152*7c478bd9Sstevel@tonic-gate } 3153*7c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 3154*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 3155*7c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 3156*7c478bd9Sstevel@tonic-gate } 3157*7c478bd9Sstevel@tonic-gate } 3158*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 3159*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3160*7c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 3161*7c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 3162*7c478bd9Sstevel@tonic-gate MDI_PI_CLEAR_TRANSIENT(pip); 3163*7c478bd9Sstevel@tonic-gate } else { 3164*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = MDI_PI_OLD_STATE(pip); 3165*7c478bd9Sstevel@tonic-gate } 3166*7c478bd9Sstevel@tonic-gate } 3167*7c478bd9Sstevel@tonic-gate 3168*7c478bd9Sstevel@tonic-gate /* 3169*7c478bd9Sstevel@tonic-gate * Wake anyone waiting for this mdi_pathinfo node 3170*7c478bd9Sstevel@tonic-gate */ 3171*7c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 3172*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3173*7c478bd9Sstevel@tonic-gate 3174*7c478bd9Sstevel@tonic-gate /* 3175*7c478bd9Sstevel@tonic-gate * Mark the client device as stable 3176*7c478bd9Sstevel@tonic-gate */ 3177*7c478bd9Sstevel@tonic-gate MDI_CLIENT_STABLE(ct); 3178*7c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 3179*7c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 3180*7c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 3181*7c478bd9Sstevel@tonic-gate 3182*7c478bd9Sstevel@tonic-gate /* 3183*7c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 3184*7c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 3185*7c478bd9Sstevel@tonic-gate * state accordingly 3186*7c478bd9Sstevel@tonic-gate */ 3187*7c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 3188*7c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 3189*7c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 3190*7c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 3191*7c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 3192*7c478bd9Sstevel@tonic-gate if (cdip && 3193*7c478bd9Sstevel@tonic-gate (i_ddi_node_state(cdip) < DS_READY) && 3194*7c478bd9Sstevel@tonic-gate ((state == MDI_PATHINFO_STATE_ONLINE) || 3195*7c478bd9Sstevel@tonic-gate (state == MDI_PATHINFO_STATE_STANDBY))) { 3196*7c478bd9Sstevel@tonic-gate 3197*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 3198*7c478bd9Sstevel@tonic-gate /* 3199*7c478bd9Sstevel@tonic-gate * Must do ndi_devi_online() through 3200*7c478bd9Sstevel@tonic-gate * hotplug thread for deferred 3201*7c478bd9Sstevel@tonic-gate * attach mechanism to work 3202*7c478bd9Sstevel@tonic-gate */ 3203*7c478bd9Sstevel@tonic-gate rv = ndi_devi_online(cdip, 0); 3204*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 3205*7c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && 3206*7c478bd9Sstevel@tonic-gate (MDI_CLIENT_STATE(ct) == 3207*7c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_DEGRADED)) { 3208*7c478bd9Sstevel@tonic-gate /* 3209*7c478bd9Sstevel@tonic-gate * ndi_devi_online failed. 3210*7c478bd9Sstevel@tonic-gate * Reset client flags to 3211*7c478bd9Sstevel@tonic-gate * offline. 3212*7c478bd9Sstevel@tonic-gate */ 3213*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 3214*7c478bd9Sstevel@tonic-gate "!ndi_devi_online: failed " 3215*7c478bd9Sstevel@tonic-gate " Error: %x", rv)); 3216*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 3217*7c478bd9Sstevel@tonic-gate } 3218*7c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 3219*7c478bd9Sstevel@tonic-gate /* Reset the path state */ 3220*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3221*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = 3222*7c478bd9Sstevel@tonic-gate MDI_PI_OLD_STATE(pip); 3223*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3224*7c478bd9Sstevel@tonic-gate } 3225*7c478bd9Sstevel@tonic-gate } 3226*7c478bd9Sstevel@tonic-gate break; 3227*7c478bd9Sstevel@tonic-gate 3228*7c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 3229*7c478bd9Sstevel@tonic-gate /* 3230*7c478bd9Sstevel@tonic-gate * This is the last path case for 3231*7c478bd9Sstevel@tonic-gate * non-user initiated events. 3232*7c478bd9Sstevel@tonic-gate */ 3233*7c478bd9Sstevel@tonic-gate if (((flag & NDI_DEVI_REMOVE) == 0) && 3234*7c478bd9Sstevel@tonic-gate cdip && (i_ddi_node_state(cdip) >= 3235*7c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 3236*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 3237*7c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 3238*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, NULL); 3239*7c478bd9Sstevel@tonic-gate 3240*7c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 3241*7c478bd9Sstevel@tonic-gate /* 3242*7c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 3243*7c478bd9Sstevel@tonic-gate * Reset client flags to 3244*7c478bd9Sstevel@tonic-gate * online as the path could not 3245*7c478bd9Sstevel@tonic-gate * be offlined. 3246*7c478bd9Sstevel@tonic-gate */ 3247*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, cdip, 3248*7c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 3249*7c478bd9Sstevel@tonic-gate " Error: %x", rv)); 3250*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 3251*7c478bd9Sstevel@tonic-gate } 3252*7c478bd9Sstevel@tonic-gate } 3253*7c478bd9Sstevel@tonic-gate break; 3254*7c478bd9Sstevel@tonic-gate } 3255*7c478bd9Sstevel@tonic-gate /* 3256*7c478bd9Sstevel@tonic-gate * Convert to MDI error code 3257*7c478bd9Sstevel@tonic-gate */ 3258*7c478bd9Sstevel@tonic-gate switch (rv) { 3259*7c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 3260*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 3261*7c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 3262*7c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 3263*7c478bd9Sstevel@tonic-gate break; 3264*7c478bd9Sstevel@tonic-gate case NDI_BUSY: 3265*7c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 3266*7c478bd9Sstevel@tonic-gate break; 3267*7c478bd9Sstevel@tonic-gate default: 3268*7c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 3269*7c478bd9Sstevel@tonic-gate break; 3270*7c478bd9Sstevel@tonic-gate } 3271*7c478bd9Sstevel@tonic-gate } 3272*7c478bd9Sstevel@tonic-gate } 3273*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 3274*7c478bd9Sstevel@tonic-gate 3275*7c478bd9Sstevel@tonic-gate state_change_exit: 3276*7c478bd9Sstevel@tonic-gate /* 3277*7c478bd9Sstevel@tonic-gate * Mark the pHCI as stable again. 3278*7c478bd9Sstevel@tonic-gate */ 3279*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 3280*7c478bd9Sstevel@tonic-gate MDI_PHCI_STABLE(ph); 3281*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 3282*7c478bd9Sstevel@tonic-gate return (rv); 3283*7c478bd9Sstevel@tonic-gate } 3284*7c478bd9Sstevel@tonic-gate 3285*7c478bd9Sstevel@tonic-gate /* 3286*7c478bd9Sstevel@tonic-gate * mdi_pi_online(): 3287*7c478bd9Sstevel@tonic-gate * Place the path_info node in the online state. The path is 3288*7c478bd9Sstevel@tonic-gate * now available to be selected by mdi_select_path() for 3289*7c478bd9Sstevel@tonic-gate * transporting I/O requests to client devices. 3290*7c478bd9Sstevel@tonic-gate * Return Values: 3291*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 3292*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 3293*7c478bd9Sstevel@tonic-gate */ 3294*7c478bd9Sstevel@tonic-gate int 3295*7c478bd9Sstevel@tonic-gate mdi_pi_online(mdi_pathinfo_t *pip, int flags) 3296*7c478bd9Sstevel@tonic-gate { 3297*7c478bd9Sstevel@tonic-gate mdi_client_t *ct = MDI_PI(pip)->pi_client; 3298*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 3299*7c478bd9Sstevel@tonic-gate int client_held = 0; 3300*7c478bd9Sstevel@tonic-gate int rv; 3301*7c478bd9Sstevel@tonic-gate 3302*7c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 3303*7c478bd9Sstevel@tonic-gate rv = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_ONLINE, flags); 3304*7c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) 3305*7c478bd9Sstevel@tonic-gate return (rv); 3306*7c478bd9Sstevel@tonic-gate 3307*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3308*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 3309*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 3310*7c478bd9Sstevel@tonic-gate "i_mdi_pm_hold_pip\n")); 3311*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 3312*7c478bd9Sstevel@tonic-gate client_held = 1; 3313*7c478bd9Sstevel@tonic-gate } 3314*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3315*7c478bd9Sstevel@tonic-gate 3316*7c478bd9Sstevel@tonic-gate if (client_held) { 3317*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 3318*7c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 3319*7c478bd9Sstevel@tonic-gate rv = i_mdi_power_all_phci(ct); 3320*7c478bd9Sstevel@tonic-gate } 3321*7c478bd9Sstevel@tonic-gate 3322*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "mdi_pi_online " 3323*7c478bd9Sstevel@tonic-gate "i_mdi_pm_hold_client\n")); 3324*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 3325*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 3326*7c478bd9Sstevel@tonic-gate } 3327*7c478bd9Sstevel@tonic-gate 3328*7c478bd9Sstevel@tonic-gate /* 3329*7c478bd9Sstevel@tonic-gate * Create the per-path (pathinfo) IO and error kstats which 3330*7c478bd9Sstevel@tonic-gate * are reported via iostat(1m). 3331*7c478bd9Sstevel@tonic-gate * 3332*7c478bd9Sstevel@tonic-gate * Defer creating the per-path kstats if device is not yet 3333*7c478bd9Sstevel@tonic-gate * attached; the names of the kstats are constructed in part 3334*7c478bd9Sstevel@tonic-gate * using the devices instance number which is assigned during 3335*7c478bd9Sstevel@tonic-gate * process of attaching the client device. 3336*7c478bd9Sstevel@tonic-gate * 3337*7c478bd9Sstevel@tonic-gate * The framework post_attach handler, mdi_post_attach(), is 3338*7c478bd9Sstevel@tonic-gate * is responsible for initializing the client's pathinfo list 3339*7c478bd9Sstevel@tonic-gate * once successfully attached. 3340*7c478bd9Sstevel@tonic-gate */ 3341*7c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 3342*7c478bd9Sstevel@tonic-gate ASSERT(cdip); 3343*7c478bd9Sstevel@tonic-gate if (cdip == NULL || (i_ddi_node_state(cdip) < DS_ATTACHED)) 3344*7c478bd9Sstevel@tonic-gate return (rv); 3345*7c478bd9Sstevel@tonic-gate 3346*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 3347*7c478bd9Sstevel@tonic-gate rv = i_mdi_pi_kstat_create(pip); 3348*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 3349*7c478bd9Sstevel@tonic-gate return (rv); 3350*7c478bd9Sstevel@tonic-gate } 3351*7c478bd9Sstevel@tonic-gate 3352*7c478bd9Sstevel@tonic-gate /* 3353*7c478bd9Sstevel@tonic-gate * mdi_pi_standby(): 3354*7c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in standby state 3355*7c478bd9Sstevel@tonic-gate * 3356*7c478bd9Sstevel@tonic-gate * Return Values: 3357*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 3358*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 3359*7c478bd9Sstevel@tonic-gate */ 3360*7c478bd9Sstevel@tonic-gate int 3361*7c478bd9Sstevel@tonic-gate mdi_pi_standby(mdi_pathinfo_t *pip, int flags) 3362*7c478bd9Sstevel@tonic-gate { 3363*7c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_STANDBY, flags)); 3364*7c478bd9Sstevel@tonic-gate } 3365*7c478bd9Sstevel@tonic-gate 3366*7c478bd9Sstevel@tonic-gate /* 3367*7c478bd9Sstevel@tonic-gate * mdi_pi_fault(): 3368*7c478bd9Sstevel@tonic-gate * Place the mdi_pathinfo node in fault'ed state 3369*7c478bd9Sstevel@tonic-gate * Return Values: 3370*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 3371*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 3372*7c478bd9Sstevel@tonic-gate */ 3373*7c478bd9Sstevel@tonic-gate int 3374*7c478bd9Sstevel@tonic-gate mdi_pi_fault(mdi_pathinfo_t *pip, int flags) 3375*7c478bd9Sstevel@tonic-gate { 3376*7c478bd9Sstevel@tonic-gate return (i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_FAULT, flags)); 3377*7c478bd9Sstevel@tonic-gate } 3378*7c478bd9Sstevel@tonic-gate 3379*7c478bd9Sstevel@tonic-gate /* 3380*7c478bd9Sstevel@tonic-gate * mdi_pi_offline(): 3381*7c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node. 3382*7c478bd9Sstevel@tonic-gate * Return Values: 3383*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 3384*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 3385*7c478bd9Sstevel@tonic-gate */ 3386*7c478bd9Sstevel@tonic-gate int 3387*7c478bd9Sstevel@tonic-gate mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 3388*7c478bd9Sstevel@tonic-gate { 3389*7c478bd9Sstevel@tonic-gate int ret, client_held = 0; 3390*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 3391*7c478bd9Sstevel@tonic-gate 3392*7c478bd9Sstevel@tonic-gate ret = i_mdi_pi_state_change(pip, MDI_PATHINFO_STATE_OFFLINE, flags); 3393*7c478bd9Sstevel@tonic-gate 3394*7c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) { 3395*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3396*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 3397*7c478bd9Sstevel@tonic-gate client_held = 1; 3398*7c478bd9Sstevel@tonic-gate } 3399*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3400*7c478bd9Sstevel@tonic-gate 3401*7c478bd9Sstevel@tonic-gate if (client_held) { 3402*7c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 3403*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 3404*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, 3405*7c478bd9Sstevel@tonic-gate "mdi_pi_offline i_mdi_pm_rele_client\n")); 3406*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, 1); 3407*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 3408*7c478bd9Sstevel@tonic-gate } 3409*7c478bd9Sstevel@tonic-gate } 3410*7c478bd9Sstevel@tonic-gate 3411*7c478bd9Sstevel@tonic-gate return (ret); 3412*7c478bd9Sstevel@tonic-gate } 3413*7c478bd9Sstevel@tonic-gate 3414*7c478bd9Sstevel@tonic-gate /* 3415*7c478bd9Sstevel@tonic-gate * i_mdi_pi_offline(): 3416*7c478bd9Sstevel@tonic-gate * Offline a mdi_pathinfo node and call the vHCI driver's callback 3417*7c478bd9Sstevel@tonic-gate */ 3418*7c478bd9Sstevel@tonic-gate static int 3419*7c478bd9Sstevel@tonic-gate i_mdi_pi_offline(mdi_pathinfo_t *pip, int flags) 3420*7c478bd9Sstevel@tonic-gate { 3421*7c478bd9Sstevel@tonic-gate dev_info_t *vdip = NULL; 3422*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 3423*7c478bd9Sstevel@tonic-gate mdi_client_t *ct = NULL; 3424*7c478bd9Sstevel@tonic-gate int (*f)(); 3425*7c478bd9Sstevel@tonic-gate int rv; 3426*7c478bd9Sstevel@tonic-gate 3427*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3428*7c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 3429*7c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 3430*7c478bd9Sstevel@tonic-gate 3431*7c478bd9Sstevel@tonic-gate while (MDI_PI(pip)->pi_ref_cnt != 0) { 3432*7c478bd9Sstevel@tonic-gate /* 3433*7c478bd9Sstevel@tonic-gate * Give a chance for pending I/Os to complete. 3434*7c478bd9Sstevel@tonic-gate */ 3435*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 3436*7c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 3437*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 3438*7c478bd9Sstevel@tonic-gate if (cv_timedwait(&MDI_PI(pip)->pi_ref_cv, 3439*7c478bd9Sstevel@tonic-gate &MDI_PI(pip)->pi_mutex, 3440*7c478bd9Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(60 * 1000000)) == -1) { 3441*7c478bd9Sstevel@tonic-gate /* 3442*7c478bd9Sstevel@tonic-gate * The timeout time reached without ref_cnt being zero 3443*7c478bd9Sstevel@tonic-gate * being signaled. 3444*7c478bd9Sstevel@tonic-gate */ 3445*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 3446*7c478bd9Sstevel@tonic-gate "Timeout reached on path %p without the cond\n", 3447*7c478bd9Sstevel@tonic-gate pip)); 3448*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, vdip, "!i_mdi_pi_offline: " 3449*7c478bd9Sstevel@tonic-gate "%d cmds still pending on path: %p\n", 3450*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_ref_cnt, pip)); 3451*7c478bd9Sstevel@tonic-gate } 3452*7c478bd9Sstevel@tonic-gate } 3453*7c478bd9Sstevel@tonic-gate vh = ct->ct_vhci; 3454*7c478bd9Sstevel@tonic-gate vdip = vh->vh_dip; 3455*7c478bd9Sstevel@tonic-gate 3456*7c478bd9Sstevel@tonic-gate /* 3457*7c478bd9Sstevel@tonic-gate * Notify vHCI that has registered this event 3458*7c478bd9Sstevel@tonic-gate */ 3459*7c478bd9Sstevel@tonic-gate ASSERT(vh->vh_ops); 3460*7c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 3461*7c478bd9Sstevel@tonic-gate 3462*7c478bd9Sstevel@tonic-gate if (f != NULL) { 3463*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3464*7c478bd9Sstevel@tonic-gate if ((rv = (*f)(vdip, pip, MDI_PATHINFO_STATE_OFFLINE, 0, 3465*7c478bd9Sstevel@tonic-gate flags)) != MDI_SUCCESS) { 3466*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, vdip, "!vo_path_offline failed " 3467*7c478bd9Sstevel@tonic-gate "vdip 0x%x, pip 0x%x", vdip, pip)); 3468*7c478bd9Sstevel@tonic-gate } 3469*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3470*7c478bd9Sstevel@tonic-gate } 3471*7c478bd9Sstevel@tonic-gate 3472*7c478bd9Sstevel@tonic-gate /* 3473*7c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state and clear the transient condition 3474*7c478bd9Sstevel@tonic-gate */ 3475*7c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINE(pip); 3476*7c478bd9Sstevel@tonic-gate cv_broadcast(&MDI_PI(pip)->pi_state_cv); 3477*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3478*7c478bd9Sstevel@tonic-gate 3479*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 3480*7c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS) { 3481*7c478bd9Sstevel@tonic-gate if (ct->ct_unstable == 0) { 3482*7c478bd9Sstevel@tonic-gate dev_info_t *cdip = ct->ct_dip; 3483*7c478bd9Sstevel@tonic-gate 3484*7c478bd9Sstevel@tonic-gate /* 3485*7c478bd9Sstevel@tonic-gate * Onlining the mdi_pathinfo node will impact the 3486*7c478bd9Sstevel@tonic-gate * client state Update the client and dev_info node 3487*7c478bd9Sstevel@tonic-gate * state accordingly 3488*7c478bd9Sstevel@tonic-gate */ 3489*7c478bd9Sstevel@tonic-gate i_mdi_client_update_state(ct); 3490*7c478bd9Sstevel@tonic-gate rv = NDI_SUCCESS; 3491*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 3492*7c478bd9Sstevel@tonic-gate if (cdip && 3493*7c478bd9Sstevel@tonic-gate (i_ddi_node_state(cdip) >= 3494*7c478bd9Sstevel@tonic-gate DS_INITIALIZED)) { 3495*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 3496*7c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 0); 3497*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 3498*7c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) { 3499*7c478bd9Sstevel@tonic-gate /* 3500*7c478bd9Sstevel@tonic-gate * ndi_devi_offline failed. 3501*7c478bd9Sstevel@tonic-gate * Reset client flags to 3502*7c478bd9Sstevel@tonic-gate * online. 3503*7c478bd9Sstevel@tonic-gate */ 3504*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, cdip, 3505*7c478bd9Sstevel@tonic-gate "!ndi_devi_offline: failed " 3506*7c478bd9Sstevel@tonic-gate " Error: %x", rv)); 3507*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 3508*7c478bd9Sstevel@tonic-gate } 3509*7c478bd9Sstevel@tonic-gate } 3510*7c478bd9Sstevel@tonic-gate } 3511*7c478bd9Sstevel@tonic-gate /* 3512*7c478bd9Sstevel@tonic-gate * Convert to MDI error code 3513*7c478bd9Sstevel@tonic-gate */ 3514*7c478bd9Sstevel@tonic-gate switch (rv) { 3515*7c478bd9Sstevel@tonic-gate case NDI_SUCCESS: 3516*7c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 3517*7c478bd9Sstevel@tonic-gate break; 3518*7c478bd9Sstevel@tonic-gate case NDI_BUSY: 3519*7c478bd9Sstevel@tonic-gate rv = MDI_BUSY; 3520*7c478bd9Sstevel@tonic-gate break; 3521*7c478bd9Sstevel@tonic-gate default: 3522*7c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 3523*7c478bd9Sstevel@tonic-gate break; 3524*7c478bd9Sstevel@tonic-gate } 3525*7c478bd9Sstevel@tonic-gate } 3526*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_REPORT_DEV_NEEDED(ct); 3527*7c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 3528*7c478bd9Sstevel@tonic-gate } 3529*7c478bd9Sstevel@tonic-gate 3530*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 3531*7c478bd9Sstevel@tonic-gate 3532*7c478bd9Sstevel@tonic-gate /* 3533*7c478bd9Sstevel@tonic-gate * Change in the mdi_pathinfo node state will impact the client state 3534*7c478bd9Sstevel@tonic-gate */ 3535*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "!i_mdi_pi_offline ct = %p pip = %p", 3536*7c478bd9Sstevel@tonic-gate ct, pip)); 3537*7c478bd9Sstevel@tonic-gate return (rv); 3538*7c478bd9Sstevel@tonic-gate } 3539*7c478bd9Sstevel@tonic-gate 3540*7c478bd9Sstevel@tonic-gate 3541*7c478bd9Sstevel@tonic-gate /* 3542*7c478bd9Sstevel@tonic-gate * mdi_pi_get_addr(): 3543*7c478bd9Sstevel@tonic-gate * Get the unit address associated with a mdi_pathinfo node 3544*7c478bd9Sstevel@tonic-gate * 3545*7c478bd9Sstevel@tonic-gate * Return Values: 3546*7c478bd9Sstevel@tonic-gate * char * 3547*7c478bd9Sstevel@tonic-gate */ 3548*7c478bd9Sstevel@tonic-gate char * 3549*7c478bd9Sstevel@tonic-gate mdi_pi_get_addr(mdi_pathinfo_t *pip) 3550*7c478bd9Sstevel@tonic-gate { 3551*7c478bd9Sstevel@tonic-gate char *addr; 3552*7c478bd9Sstevel@tonic-gate 3553*7c478bd9Sstevel@tonic-gate if (pip == NULL) 3554*7c478bd9Sstevel@tonic-gate return (NULL); 3555*7c478bd9Sstevel@tonic-gate 3556*7c478bd9Sstevel@tonic-gate addr = MDI_PI(pip)->pi_addr; 3557*7c478bd9Sstevel@tonic-gate 3558*7c478bd9Sstevel@tonic-gate /* 3559*7c478bd9Sstevel@tonic-gate * XXX To be removed when libg_fc is updated to 3560*7c478bd9Sstevel@tonic-gate * skip leading 'w' in NWS consolidation. 3561*7c478bd9Sstevel@tonic-gate */ 3562*7c478bd9Sstevel@tonic-gate if (*addr == 'w') 3563*7c478bd9Sstevel@tonic-gate addr += 1; 3564*7c478bd9Sstevel@tonic-gate 3565*7c478bd9Sstevel@tonic-gate return (addr); 3566*7c478bd9Sstevel@tonic-gate } 3567*7c478bd9Sstevel@tonic-gate 3568*7c478bd9Sstevel@tonic-gate /* 3569*7c478bd9Sstevel@tonic-gate * mdi_pi_get_client(): 3570*7c478bd9Sstevel@tonic-gate * Get the client devinfo associated with a mdi_pathinfo node 3571*7c478bd9Sstevel@tonic-gate * 3572*7c478bd9Sstevel@tonic-gate * Return Values: 3573*7c478bd9Sstevel@tonic-gate * Handle to client device dev_info node 3574*7c478bd9Sstevel@tonic-gate */ 3575*7c478bd9Sstevel@tonic-gate dev_info_t * 3576*7c478bd9Sstevel@tonic-gate mdi_pi_get_client(mdi_pathinfo_t *pip) 3577*7c478bd9Sstevel@tonic-gate { 3578*7c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 3579*7c478bd9Sstevel@tonic-gate if (pip) { 3580*7c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_client->ct_dip; 3581*7c478bd9Sstevel@tonic-gate } 3582*7c478bd9Sstevel@tonic-gate return (dip); 3583*7c478bd9Sstevel@tonic-gate } 3584*7c478bd9Sstevel@tonic-gate 3585*7c478bd9Sstevel@tonic-gate /* 3586*7c478bd9Sstevel@tonic-gate * mdi_pi_get_phci(): 3587*7c478bd9Sstevel@tonic-gate * Get the pHCI devinfo associated with the mdi_pathinfo node 3588*7c478bd9Sstevel@tonic-gate * Return Values: 3589*7c478bd9Sstevel@tonic-gate * Handle to dev_info node 3590*7c478bd9Sstevel@tonic-gate */ 3591*7c478bd9Sstevel@tonic-gate dev_info_t * 3592*7c478bd9Sstevel@tonic-gate mdi_pi_get_phci(mdi_pathinfo_t *pip) 3593*7c478bd9Sstevel@tonic-gate { 3594*7c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 3595*7c478bd9Sstevel@tonic-gate if (pip) { 3596*7c478bd9Sstevel@tonic-gate dip = MDI_PI(pip)->pi_phci->ph_dip; 3597*7c478bd9Sstevel@tonic-gate } 3598*7c478bd9Sstevel@tonic-gate return (dip); 3599*7c478bd9Sstevel@tonic-gate } 3600*7c478bd9Sstevel@tonic-gate 3601*7c478bd9Sstevel@tonic-gate /* 3602*7c478bd9Sstevel@tonic-gate * mdi_pi_get_client_private(): 3603*7c478bd9Sstevel@tonic-gate * Get the client private information associated with the 3604*7c478bd9Sstevel@tonic-gate * mdi_pathinfo node 3605*7c478bd9Sstevel@tonic-gate */ 3606*7c478bd9Sstevel@tonic-gate void * 3607*7c478bd9Sstevel@tonic-gate mdi_pi_get_client_private(mdi_pathinfo_t *pip) 3608*7c478bd9Sstevel@tonic-gate { 3609*7c478bd9Sstevel@tonic-gate void *cprivate = NULL; 3610*7c478bd9Sstevel@tonic-gate if (pip) { 3611*7c478bd9Sstevel@tonic-gate cprivate = MDI_PI(pip)->pi_cprivate; 3612*7c478bd9Sstevel@tonic-gate } 3613*7c478bd9Sstevel@tonic-gate return (cprivate); 3614*7c478bd9Sstevel@tonic-gate } 3615*7c478bd9Sstevel@tonic-gate 3616*7c478bd9Sstevel@tonic-gate /* 3617*7c478bd9Sstevel@tonic-gate * mdi_pi_set_client_private(): 3618*7c478bd9Sstevel@tonic-gate * Set the client private information in the mdi_pathinfo node 3619*7c478bd9Sstevel@tonic-gate */ 3620*7c478bd9Sstevel@tonic-gate void 3621*7c478bd9Sstevel@tonic-gate mdi_pi_set_client_private(mdi_pathinfo_t *pip, void *priv) 3622*7c478bd9Sstevel@tonic-gate { 3623*7c478bd9Sstevel@tonic-gate if (pip) { 3624*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_cprivate = priv; 3625*7c478bd9Sstevel@tonic-gate } 3626*7c478bd9Sstevel@tonic-gate } 3627*7c478bd9Sstevel@tonic-gate 3628*7c478bd9Sstevel@tonic-gate /* 3629*7c478bd9Sstevel@tonic-gate * mdi_pi_get_phci_private(): 3630*7c478bd9Sstevel@tonic-gate * Get the pHCI private information associated with the 3631*7c478bd9Sstevel@tonic-gate * mdi_pathinfo node 3632*7c478bd9Sstevel@tonic-gate */ 3633*7c478bd9Sstevel@tonic-gate caddr_t 3634*7c478bd9Sstevel@tonic-gate mdi_pi_get_phci_private(mdi_pathinfo_t *pip) 3635*7c478bd9Sstevel@tonic-gate { 3636*7c478bd9Sstevel@tonic-gate caddr_t pprivate = NULL; 3637*7c478bd9Sstevel@tonic-gate if (pip) { 3638*7c478bd9Sstevel@tonic-gate pprivate = MDI_PI(pip)->pi_pprivate; 3639*7c478bd9Sstevel@tonic-gate } 3640*7c478bd9Sstevel@tonic-gate return (pprivate); 3641*7c478bd9Sstevel@tonic-gate } 3642*7c478bd9Sstevel@tonic-gate 3643*7c478bd9Sstevel@tonic-gate /* 3644*7c478bd9Sstevel@tonic-gate * mdi_pi_set_phci_private(): 3645*7c478bd9Sstevel@tonic-gate * Set the pHCI private information in the mdi_pathinfo node 3646*7c478bd9Sstevel@tonic-gate */ 3647*7c478bd9Sstevel@tonic-gate void 3648*7c478bd9Sstevel@tonic-gate mdi_pi_set_phci_private(mdi_pathinfo_t *pip, caddr_t priv) 3649*7c478bd9Sstevel@tonic-gate { 3650*7c478bd9Sstevel@tonic-gate if (pip) { 3651*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pprivate = priv; 3652*7c478bd9Sstevel@tonic-gate } 3653*7c478bd9Sstevel@tonic-gate } 3654*7c478bd9Sstevel@tonic-gate 3655*7c478bd9Sstevel@tonic-gate /* 3656*7c478bd9Sstevel@tonic-gate * mdi_pi_get_state(): 3657*7c478bd9Sstevel@tonic-gate * Get the mdi_pathinfo node state. Transient states are internal 3658*7c478bd9Sstevel@tonic-gate * and not provided to the users 3659*7c478bd9Sstevel@tonic-gate */ 3660*7c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t 3661*7c478bd9Sstevel@tonic-gate mdi_pi_get_state(mdi_pathinfo_t *pip) 3662*7c478bd9Sstevel@tonic-gate { 3663*7c478bd9Sstevel@tonic-gate mdi_pathinfo_state_t state = MDI_PATHINFO_STATE_INIT; 3664*7c478bd9Sstevel@tonic-gate 3665*7c478bd9Sstevel@tonic-gate if (pip) { 3666*7c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 3667*7c478bd9Sstevel@tonic-gate /* 3668*7c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 3669*7c478bd9Sstevel@tonic-gate * last good state. 3670*7c478bd9Sstevel@tonic-gate */ 3671*7c478bd9Sstevel@tonic-gate state = MDI_PI_OLD_STATE(pip); 3672*7c478bd9Sstevel@tonic-gate } else { 3673*7c478bd9Sstevel@tonic-gate state = MDI_PI_STATE(pip); 3674*7c478bd9Sstevel@tonic-gate } 3675*7c478bd9Sstevel@tonic-gate } 3676*7c478bd9Sstevel@tonic-gate return (state); 3677*7c478bd9Sstevel@tonic-gate } 3678*7c478bd9Sstevel@tonic-gate 3679*7c478bd9Sstevel@tonic-gate /* 3680*7c478bd9Sstevel@tonic-gate * Note that the following function needs to be the new interface for 3681*7c478bd9Sstevel@tonic-gate * mdi_pi_get_state when mpxio gets integrated to ON. 3682*7c478bd9Sstevel@tonic-gate */ 3683*7c478bd9Sstevel@tonic-gate int 3684*7c478bd9Sstevel@tonic-gate mdi_pi_get_state2(mdi_pathinfo_t *pip, mdi_pathinfo_state_t *state, 3685*7c478bd9Sstevel@tonic-gate uint32_t *ext_state) 3686*7c478bd9Sstevel@tonic-gate { 3687*7c478bd9Sstevel@tonic-gate *state = MDI_PATHINFO_STATE_INIT; 3688*7c478bd9Sstevel@tonic-gate 3689*7c478bd9Sstevel@tonic-gate if (pip) { 3690*7c478bd9Sstevel@tonic-gate if (MDI_PI_IS_TRANSIENT(pip)) { 3691*7c478bd9Sstevel@tonic-gate /* 3692*7c478bd9Sstevel@tonic-gate * mdi_pathinfo is in state transition. Return the 3693*7c478bd9Sstevel@tonic-gate * last good state. 3694*7c478bd9Sstevel@tonic-gate */ 3695*7c478bd9Sstevel@tonic-gate *state = MDI_PI_OLD_STATE(pip); 3696*7c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_OLD_EXT_STATE(pip); 3697*7c478bd9Sstevel@tonic-gate } else { 3698*7c478bd9Sstevel@tonic-gate *state = MDI_PI_STATE(pip); 3699*7c478bd9Sstevel@tonic-gate *ext_state = MDI_PI_EXT_STATE(pip); 3700*7c478bd9Sstevel@tonic-gate } 3701*7c478bd9Sstevel@tonic-gate } 3702*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 3703*7c478bd9Sstevel@tonic-gate } 3704*7c478bd9Sstevel@tonic-gate 3705*7c478bd9Sstevel@tonic-gate /* 3706*7c478bd9Sstevel@tonic-gate * mdi_pi_get_preferred: 3707*7c478bd9Sstevel@tonic-gate * Get the preferred path flag 3708*7c478bd9Sstevel@tonic-gate */ 3709*7c478bd9Sstevel@tonic-gate int 3710*7c478bd9Sstevel@tonic-gate mdi_pi_get_preferred(mdi_pathinfo_t *pip) 3711*7c478bd9Sstevel@tonic-gate { 3712*7c478bd9Sstevel@tonic-gate if (pip) { 3713*7c478bd9Sstevel@tonic-gate return (MDI_PI(pip)->pi_preferred); 3714*7c478bd9Sstevel@tonic-gate } 3715*7c478bd9Sstevel@tonic-gate return (0); 3716*7c478bd9Sstevel@tonic-gate } 3717*7c478bd9Sstevel@tonic-gate 3718*7c478bd9Sstevel@tonic-gate /* 3719*7c478bd9Sstevel@tonic-gate * mdi_pi_set_preferred: 3720*7c478bd9Sstevel@tonic-gate * Set the preferred path flag 3721*7c478bd9Sstevel@tonic-gate */ 3722*7c478bd9Sstevel@tonic-gate void 3723*7c478bd9Sstevel@tonic-gate mdi_pi_set_preferred(mdi_pathinfo_t *pip, int preferred) 3724*7c478bd9Sstevel@tonic-gate { 3725*7c478bd9Sstevel@tonic-gate if (pip) { 3726*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_preferred = preferred; 3727*7c478bd9Sstevel@tonic-gate } 3728*7c478bd9Sstevel@tonic-gate } 3729*7c478bd9Sstevel@tonic-gate 3730*7c478bd9Sstevel@tonic-gate 3731*7c478bd9Sstevel@tonic-gate /* 3732*7c478bd9Sstevel@tonic-gate * mdi_pi_set_state(): 3733*7c478bd9Sstevel@tonic-gate * Set the mdi_pathinfo node state 3734*7c478bd9Sstevel@tonic-gate */ 3735*7c478bd9Sstevel@tonic-gate void 3736*7c478bd9Sstevel@tonic-gate mdi_pi_set_state(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state) 3737*7c478bd9Sstevel@tonic-gate { 3738*7c478bd9Sstevel@tonic-gate uint32_t ext_state; 3739*7c478bd9Sstevel@tonic-gate 3740*7c478bd9Sstevel@tonic-gate if (pip) { 3741*7c478bd9Sstevel@tonic-gate ext_state = MDI_PI(pip)->pi_state & MDI_PATHINFO_EXT_STATE_MASK; 3742*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state = state; 3743*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_state |= ext_state; 3744*7c478bd9Sstevel@tonic-gate } 3745*7c478bd9Sstevel@tonic-gate } 3746*7c478bd9Sstevel@tonic-gate 3747*7c478bd9Sstevel@tonic-gate /* 3748*7c478bd9Sstevel@tonic-gate * Property functions: 3749*7c478bd9Sstevel@tonic-gate */ 3750*7c478bd9Sstevel@tonic-gate 3751*7c478bd9Sstevel@tonic-gate int 3752*7c478bd9Sstevel@tonic-gate i_map_nvlist_error_to_mdi(int val) 3753*7c478bd9Sstevel@tonic-gate { 3754*7c478bd9Sstevel@tonic-gate int rv; 3755*7c478bd9Sstevel@tonic-gate 3756*7c478bd9Sstevel@tonic-gate switch (val) { 3757*7c478bd9Sstevel@tonic-gate case 0: 3758*7c478bd9Sstevel@tonic-gate rv = DDI_PROP_SUCCESS; 3759*7c478bd9Sstevel@tonic-gate break; 3760*7c478bd9Sstevel@tonic-gate case EINVAL: 3761*7c478bd9Sstevel@tonic-gate case ENOTSUP: 3762*7c478bd9Sstevel@tonic-gate rv = DDI_PROP_INVAL_ARG; 3763*7c478bd9Sstevel@tonic-gate break; 3764*7c478bd9Sstevel@tonic-gate case ENOMEM: 3765*7c478bd9Sstevel@tonic-gate rv = DDI_PROP_NO_MEMORY; 3766*7c478bd9Sstevel@tonic-gate break; 3767*7c478bd9Sstevel@tonic-gate default: 3768*7c478bd9Sstevel@tonic-gate rv = DDI_PROP_NOT_FOUND; 3769*7c478bd9Sstevel@tonic-gate break; 3770*7c478bd9Sstevel@tonic-gate } 3771*7c478bd9Sstevel@tonic-gate return (rv); 3772*7c478bd9Sstevel@tonic-gate } 3773*7c478bd9Sstevel@tonic-gate 3774*7c478bd9Sstevel@tonic-gate /* 3775*7c478bd9Sstevel@tonic-gate * mdi_pi_get_next_prop(): 3776*7c478bd9Sstevel@tonic-gate * Property walk function. The caller should hold mdi_pi_lock() 3777*7c478bd9Sstevel@tonic-gate * and release by calling mdi_pi_unlock() at the end of walk to 3778*7c478bd9Sstevel@tonic-gate * get a consistent value. 3779*7c478bd9Sstevel@tonic-gate */ 3780*7c478bd9Sstevel@tonic-gate 3781*7c478bd9Sstevel@tonic-gate nvpair_t * 3782*7c478bd9Sstevel@tonic-gate mdi_pi_get_next_prop(mdi_pathinfo_t *pip, nvpair_t *prev) 3783*7c478bd9Sstevel@tonic-gate { 3784*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 3785*7c478bd9Sstevel@tonic-gate return (NULL); 3786*7c478bd9Sstevel@tonic-gate } 3787*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 3788*7c478bd9Sstevel@tonic-gate return (nvlist_next_nvpair(MDI_PI(pip)->pi_prop, prev)); 3789*7c478bd9Sstevel@tonic-gate } 3790*7c478bd9Sstevel@tonic-gate 3791*7c478bd9Sstevel@tonic-gate /* 3792*7c478bd9Sstevel@tonic-gate * mdi_prop_remove(): 3793*7c478bd9Sstevel@tonic-gate * Remove the named property from the named list. 3794*7c478bd9Sstevel@tonic-gate */ 3795*7c478bd9Sstevel@tonic-gate 3796*7c478bd9Sstevel@tonic-gate int 3797*7c478bd9Sstevel@tonic-gate mdi_prop_remove(mdi_pathinfo_t *pip, char *name) 3798*7c478bd9Sstevel@tonic-gate { 3799*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 3800*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 3801*7c478bd9Sstevel@tonic-gate } 3802*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 3803*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3804*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 3805*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3806*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 3807*7c478bd9Sstevel@tonic-gate } 3808*7c478bd9Sstevel@tonic-gate if (name) { 3809*7c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, name); 3810*7c478bd9Sstevel@tonic-gate } else { 3811*7c478bd9Sstevel@tonic-gate char nvp_name[MAXNAMELEN]; 3812*7c478bd9Sstevel@tonic-gate nvpair_t *nvp; 3813*7c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, NULL); 3814*7c478bd9Sstevel@tonic-gate while (nvp) { 3815*7c478bd9Sstevel@tonic-gate nvpair_t *next; 3816*7c478bd9Sstevel@tonic-gate next = nvlist_next_nvpair(MDI_PI(pip)->pi_prop, nvp); 3817*7c478bd9Sstevel@tonic-gate (void) snprintf(nvp_name, MAXNAMELEN, "%s", 3818*7c478bd9Sstevel@tonic-gate nvpair_name(nvp)); 3819*7c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(MDI_PI(pip)->pi_prop, 3820*7c478bd9Sstevel@tonic-gate nvp_name); 3821*7c478bd9Sstevel@tonic-gate nvp = next; 3822*7c478bd9Sstevel@tonic-gate } 3823*7c478bd9Sstevel@tonic-gate } 3824*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3825*7c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 3826*7c478bd9Sstevel@tonic-gate } 3827*7c478bd9Sstevel@tonic-gate 3828*7c478bd9Sstevel@tonic-gate /* 3829*7c478bd9Sstevel@tonic-gate * mdi_prop_size(): 3830*7c478bd9Sstevel@tonic-gate * Get buffer size needed to pack the property data. 3831*7c478bd9Sstevel@tonic-gate * Caller should hold the mdi_pathinfo_t lock to get a consistent 3832*7c478bd9Sstevel@tonic-gate * buffer size. 3833*7c478bd9Sstevel@tonic-gate */ 3834*7c478bd9Sstevel@tonic-gate 3835*7c478bd9Sstevel@tonic-gate int 3836*7c478bd9Sstevel@tonic-gate mdi_prop_size(mdi_pathinfo_t *pip, size_t *buflenp) 3837*7c478bd9Sstevel@tonic-gate { 3838*7c478bd9Sstevel@tonic-gate int rv; 3839*7c478bd9Sstevel@tonic-gate size_t bufsize; 3840*7c478bd9Sstevel@tonic-gate 3841*7c478bd9Sstevel@tonic-gate *buflenp = 0; 3842*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 3843*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 3844*7c478bd9Sstevel@tonic-gate } 3845*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 3846*7c478bd9Sstevel@tonic-gate rv = nvlist_size(MDI_PI(pip)->pi_prop, 3847*7c478bd9Sstevel@tonic-gate &bufsize, NV_ENCODE_NATIVE); 3848*7c478bd9Sstevel@tonic-gate *buflenp = bufsize; 3849*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 3850*7c478bd9Sstevel@tonic-gate } 3851*7c478bd9Sstevel@tonic-gate 3852*7c478bd9Sstevel@tonic-gate /* 3853*7c478bd9Sstevel@tonic-gate * mdi_prop_pack(): 3854*7c478bd9Sstevel@tonic-gate * pack the property list. The caller should hold the 3855*7c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node to get a consistent data 3856*7c478bd9Sstevel@tonic-gate */ 3857*7c478bd9Sstevel@tonic-gate 3858*7c478bd9Sstevel@tonic-gate int 3859*7c478bd9Sstevel@tonic-gate mdi_prop_pack(mdi_pathinfo_t *pip, char **bufp, uint_t buflen) 3860*7c478bd9Sstevel@tonic-gate { 3861*7c478bd9Sstevel@tonic-gate int rv; 3862*7c478bd9Sstevel@tonic-gate size_t bufsize; 3863*7c478bd9Sstevel@tonic-gate 3864*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || MDI_PI(pip)->pi_prop == NULL) { 3865*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 3866*7c478bd9Sstevel@tonic-gate } 3867*7c478bd9Sstevel@tonic-gate 3868*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 3869*7c478bd9Sstevel@tonic-gate 3870*7c478bd9Sstevel@tonic-gate bufsize = buflen; 3871*7c478bd9Sstevel@tonic-gate rv = nvlist_pack(MDI_PI(pip)->pi_prop, bufp, (size_t *)&bufsize, 3872*7c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE, KM_SLEEP); 3873*7c478bd9Sstevel@tonic-gate 3874*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 3875*7c478bd9Sstevel@tonic-gate } 3876*7c478bd9Sstevel@tonic-gate 3877*7c478bd9Sstevel@tonic-gate /* 3878*7c478bd9Sstevel@tonic-gate * mdi_prop_update_byte(): 3879*7c478bd9Sstevel@tonic-gate * Create/Update a byte property 3880*7c478bd9Sstevel@tonic-gate */ 3881*7c478bd9Sstevel@tonic-gate int 3882*7c478bd9Sstevel@tonic-gate mdi_prop_update_byte(mdi_pathinfo_t *pip, char *name, uchar_t data) 3883*7c478bd9Sstevel@tonic-gate { 3884*7c478bd9Sstevel@tonic-gate int rv; 3885*7c478bd9Sstevel@tonic-gate 3886*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 3887*7c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 3888*7c478bd9Sstevel@tonic-gate } 3889*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 3890*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3891*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 3892*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3893*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 3894*7c478bd9Sstevel@tonic-gate } 3895*7c478bd9Sstevel@tonic-gate rv = nvlist_add_byte(MDI_PI(pip)->pi_prop, name, data); 3896*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3897*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 3898*7c478bd9Sstevel@tonic-gate } 3899*7c478bd9Sstevel@tonic-gate 3900*7c478bd9Sstevel@tonic-gate /* 3901*7c478bd9Sstevel@tonic-gate * mdi_prop_update_byte_array(): 3902*7c478bd9Sstevel@tonic-gate * Create/Update a byte array property 3903*7c478bd9Sstevel@tonic-gate */ 3904*7c478bd9Sstevel@tonic-gate int 3905*7c478bd9Sstevel@tonic-gate mdi_prop_update_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t *data, 3906*7c478bd9Sstevel@tonic-gate uint_t nelements) 3907*7c478bd9Sstevel@tonic-gate { 3908*7c478bd9Sstevel@tonic-gate int rv; 3909*7c478bd9Sstevel@tonic-gate 3910*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 3911*7c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 3912*7c478bd9Sstevel@tonic-gate } 3913*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 3914*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3915*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 3916*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3917*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 3918*7c478bd9Sstevel@tonic-gate } 3919*7c478bd9Sstevel@tonic-gate rv = nvlist_add_byte_array(MDI_PI(pip)->pi_prop, name, data, nelements); 3920*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3921*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 3922*7c478bd9Sstevel@tonic-gate } 3923*7c478bd9Sstevel@tonic-gate 3924*7c478bd9Sstevel@tonic-gate /* 3925*7c478bd9Sstevel@tonic-gate * mdi_prop_update_int(): 3926*7c478bd9Sstevel@tonic-gate * Create/Update a 32 bit integer property 3927*7c478bd9Sstevel@tonic-gate */ 3928*7c478bd9Sstevel@tonic-gate int 3929*7c478bd9Sstevel@tonic-gate mdi_prop_update_int(mdi_pathinfo_t *pip, char *name, int data) 3930*7c478bd9Sstevel@tonic-gate { 3931*7c478bd9Sstevel@tonic-gate int rv; 3932*7c478bd9Sstevel@tonic-gate 3933*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 3934*7c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 3935*7c478bd9Sstevel@tonic-gate } 3936*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 3937*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3938*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 3939*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3940*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 3941*7c478bd9Sstevel@tonic-gate } 3942*7c478bd9Sstevel@tonic-gate rv = nvlist_add_int32(MDI_PI(pip)->pi_prop, name, (int32_t)data); 3943*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3944*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 3945*7c478bd9Sstevel@tonic-gate } 3946*7c478bd9Sstevel@tonic-gate 3947*7c478bd9Sstevel@tonic-gate /* 3948*7c478bd9Sstevel@tonic-gate * mdi_prop_update_int64(): 3949*7c478bd9Sstevel@tonic-gate * Create/Update a 64 bit integer property 3950*7c478bd9Sstevel@tonic-gate */ 3951*7c478bd9Sstevel@tonic-gate int 3952*7c478bd9Sstevel@tonic-gate mdi_prop_update_int64(mdi_pathinfo_t *pip, char *name, int64_t data) 3953*7c478bd9Sstevel@tonic-gate { 3954*7c478bd9Sstevel@tonic-gate int rv; 3955*7c478bd9Sstevel@tonic-gate 3956*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 3957*7c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 3958*7c478bd9Sstevel@tonic-gate } 3959*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 3960*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3961*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 3962*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3963*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 3964*7c478bd9Sstevel@tonic-gate } 3965*7c478bd9Sstevel@tonic-gate rv = nvlist_add_int64(MDI_PI(pip)->pi_prop, name, data); 3966*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3967*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 3968*7c478bd9Sstevel@tonic-gate } 3969*7c478bd9Sstevel@tonic-gate 3970*7c478bd9Sstevel@tonic-gate /* 3971*7c478bd9Sstevel@tonic-gate * mdi_prop_update_int_array(): 3972*7c478bd9Sstevel@tonic-gate * Create/Update a int array property 3973*7c478bd9Sstevel@tonic-gate */ 3974*7c478bd9Sstevel@tonic-gate int 3975*7c478bd9Sstevel@tonic-gate mdi_prop_update_int_array(mdi_pathinfo_t *pip, char *name, int *data, 3976*7c478bd9Sstevel@tonic-gate uint_t nelements) 3977*7c478bd9Sstevel@tonic-gate { 3978*7c478bd9Sstevel@tonic-gate int rv; 3979*7c478bd9Sstevel@tonic-gate 3980*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 3981*7c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 3982*7c478bd9Sstevel@tonic-gate } 3983*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 3984*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 3985*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 3986*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3987*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 3988*7c478bd9Sstevel@tonic-gate } 3989*7c478bd9Sstevel@tonic-gate rv = nvlist_add_int32_array(MDI_PI(pip)->pi_prop, name, (int32_t *)data, 3990*7c478bd9Sstevel@tonic-gate nelements); 3991*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 3992*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 3993*7c478bd9Sstevel@tonic-gate } 3994*7c478bd9Sstevel@tonic-gate 3995*7c478bd9Sstevel@tonic-gate /* 3996*7c478bd9Sstevel@tonic-gate * mdi_prop_update_string(): 3997*7c478bd9Sstevel@tonic-gate * Create/Update a string property 3998*7c478bd9Sstevel@tonic-gate */ 3999*7c478bd9Sstevel@tonic-gate int 4000*7c478bd9Sstevel@tonic-gate mdi_prop_update_string(mdi_pathinfo_t *pip, char *name, char *data) 4001*7c478bd9Sstevel@tonic-gate { 4002*7c478bd9Sstevel@tonic-gate int rv; 4003*7c478bd9Sstevel@tonic-gate 4004*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 4005*7c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 4006*7c478bd9Sstevel@tonic-gate } 4007*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 4008*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 4009*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 4010*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4011*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 4012*7c478bd9Sstevel@tonic-gate } 4013*7c478bd9Sstevel@tonic-gate rv = nvlist_add_string(MDI_PI(pip)->pi_prop, name, data); 4014*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4015*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 4016*7c478bd9Sstevel@tonic-gate } 4017*7c478bd9Sstevel@tonic-gate 4018*7c478bd9Sstevel@tonic-gate /* 4019*7c478bd9Sstevel@tonic-gate * mdi_prop_update_string_array(): 4020*7c478bd9Sstevel@tonic-gate * Create/Update a string array property 4021*7c478bd9Sstevel@tonic-gate */ 4022*7c478bd9Sstevel@tonic-gate int 4023*7c478bd9Sstevel@tonic-gate mdi_prop_update_string_array(mdi_pathinfo_t *pip, char *name, char **data, 4024*7c478bd9Sstevel@tonic-gate uint_t nelements) 4025*7c478bd9Sstevel@tonic-gate { 4026*7c478bd9Sstevel@tonic-gate int rv; 4027*7c478bd9Sstevel@tonic-gate 4028*7c478bd9Sstevel@tonic-gate if (pip == NULL) { 4029*7c478bd9Sstevel@tonic-gate return (DDI_PROP_INVAL_ARG); 4030*7c478bd9Sstevel@tonic-gate } 4031*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 4032*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 4033*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_prop == NULL) { 4034*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4035*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 4036*7c478bd9Sstevel@tonic-gate } 4037*7c478bd9Sstevel@tonic-gate rv = nvlist_add_string_array(MDI_PI(pip)->pi_prop, name, data, 4038*7c478bd9Sstevel@tonic-gate nelements); 4039*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4040*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 4041*7c478bd9Sstevel@tonic-gate } 4042*7c478bd9Sstevel@tonic-gate 4043*7c478bd9Sstevel@tonic-gate /* 4044*7c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte(): 4045*7c478bd9Sstevel@tonic-gate * Look for byte property identified by name. The data returned 4046*7c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 4047*7c478bd9Sstevel@tonic-gate * is alive. 4048*7c478bd9Sstevel@tonic-gate */ 4049*7c478bd9Sstevel@tonic-gate int 4050*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte(mdi_pathinfo_t *pip, char *name, uchar_t *data) 4051*7c478bd9Sstevel@tonic-gate { 4052*7c478bd9Sstevel@tonic-gate int rv; 4053*7c478bd9Sstevel@tonic-gate 4054*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 4055*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 4056*7c478bd9Sstevel@tonic-gate } 4057*7c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte(MDI_PI(pip)->pi_prop, name, data); 4058*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 4059*7c478bd9Sstevel@tonic-gate } 4060*7c478bd9Sstevel@tonic-gate 4061*7c478bd9Sstevel@tonic-gate 4062*7c478bd9Sstevel@tonic-gate /* 4063*7c478bd9Sstevel@tonic-gate * mdi_prop_lookup_byte_array(): 4064*7c478bd9Sstevel@tonic-gate * Look for byte array property identified by name. The data 4065*7c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 4066*7c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 4067*7c478bd9Sstevel@tonic-gate */ 4068*7c478bd9Sstevel@tonic-gate int 4069*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_byte_array(mdi_pathinfo_t *pip, char *name, uchar_t **data, 4070*7c478bd9Sstevel@tonic-gate uint_t *nelements) 4071*7c478bd9Sstevel@tonic-gate { 4072*7c478bd9Sstevel@tonic-gate int rv; 4073*7c478bd9Sstevel@tonic-gate 4074*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 4075*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 4076*7c478bd9Sstevel@tonic-gate } 4077*7c478bd9Sstevel@tonic-gate rv = nvlist_lookup_byte_array(MDI_PI(pip)->pi_prop, name, data, 4078*7c478bd9Sstevel@tonic-gate nelements); 4079*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 4080*7c478bd9Sstevel@tonic-gate } 4081*7c478bd9Sstevel@tonic-gate 4082*7c478bd9Sstevel@tonic-gate /* 4083*7c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int(): 4084*7c478bd9Sstevel@tonic-gate * Look for int property identified by name. The data returned 4085*7c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t 4086*7c478bd9Sstevel@tonic-gate * node is alive. 4087*7c478bd9Sstevel@tonic-gate */ 4088*7c478bd9Sstevel@tonic-gate int 4089*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_int(mdi_pathinfo_t *pip, char *name, int *data) 4090*7c478bd9Sstevel@tonic-gate { 4091*7c478bd9Sstevel@tonic-gate int rv; 4092*7c478bd9Sstevel@tonic-gate 4093*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 4094*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 4095*7c478bd9Sstevel@tonic-gate } 4096*7c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32(MDI_PI(pip)->pi_prop, name, (int32_t *)data); 4097*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 4098*7c478bd9Sstevel@tonic-gate } 4099*7c478bd9Sstevel@tonic-gate 4100*7c478bd9Sstevel@tonic-gate /* 4101*7c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int64(): 4102*7c478bd9Sstevel@tonic-gate * Look for int64 property identified by name. The data returned 4103*7c478bd9Sstevel@tonic-gate * is the actual property and valid as long as mdi_pathinfo_t node 4104*7c478bd9Sstevel@tonic-gate * is alive. 4105*7c478bd9Sstevel@tonic-gate */ 4106*7c478bd9Sstevel@tonic-gate int 4107*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_int64(mdi_pathinfo_t *pip, char *name, int64_t *data) 4108*7c478bd9Sstevel@tonic-gate { 4109*7c478bd9Sstevel@tonic-gate int rv; 4110*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 4111*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 4112*7c478bd9Sstevel@tonic-gate } 4113*7c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int64(MDI_PI(pip)->pi_prop, name, data); 4114*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 4115*7c478bd9Sstevel@tonic-gate } 4116*7c478bd9Sstevel@tonic-gate 4117*7c478bd9Sstevel@tonic-gate /* 4118*7c478bd9Sstevel@tonic-gate * mdi_prop_lookup_int_array(): 4119*7c478bd9Sstevel@tonic-gate * Look for int array property identified by name. The data 4120*7c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 4121*7c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 4122*7c478bd9Sstevel@tonic-gate */ 4123*7c478bd9Sstevel@tonic-gate int 4124*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_int_array(mdi_pathinfo_t *pip, char *name, int **data, 4125*7c478bd9Sstevel@tonic-gate uint_t *nelements) 4126*7c478bd9Sstevel@tonic-gate { 4127*7c478bd9Sstevel@tonic-gate int rv; 4128*7c478bd9Sstevel@tonic-gate 4129*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 4130*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 4131*7c478bd9Sstevel@tonic-gate } 4132*7c478bd9Sstevel@tonic-gate rv = nvlist_lookup_int32_array(MDI_PI(pip)->pi_prop, name, 4133*7c478bd9Sstevel@tonic-gate (int32_t **)data, nelements); 4134*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 4135*7c478bd9Sstevel@tonic-gate } 4136*7c478bd9Sstevel@tonic-gate 4137*7c478bd9Sstevel@tonic-gate /* 4138*7c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string(): 4139*7c478bd9Sstevel@tonic-gate * Look for string property identified by name. The data 4140*7c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 4141*7c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 4142*7c478bd9Sstevel@tonic-gate */ 4143*7c478bd9Sstevel@tonic-gate int 4144*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_string(mdi_pathinfo_t *pip, char *name, char **data) 4145*7c478bd9Sstevel@tonic-gate { 4146*7c478bd9Sstevel@tonic-gate int rv; 4147*7c478bd9Sstevel@tonic-gate 4148*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 4149*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 4150*7c478bd9Sstevel@tonic-gate } 4151*7c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string(MDI_PI(pip)->pi_prop, name, data); 4152*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 4153*7c478bd9Sstevel@tonic-gate } 4154*7c478bd9Sstevel@tonic-gate 4155*7c478bd9Sstevel@tonic-gate /* 4156*7c478bd9Sstevel@tonic-gate * mdi_prop_lookup_string_array(): 4157*7c478bd9Sstevel@tonic-gate * Look for string array property identified by name. The data 4158*7c478bd9Sstevel@tonic-gate * returned is the actual property and valid as long as 4159*7c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is alive. 4160*7c478bd9Sstevel@tonic-gate */ 4161*7c478bd9Sstevel@tonic-gate 4162*7c478bd9Sstevel@tonic-gate int 4163*7c478bd9Sstevel@tonic-gate mdi_prop_lookup_string_array(mdi_pathinfo_t *pip, char *name, char ***data, 4164*7c478bd9Sstevel@tonic-gate uint_t *nelements) 4165*7c478bd9Sstevel@tonic-gate { 4166*7c478bd9Sstevel@tonic-gate int rv; 4167*7c478bd9Sstevel@tonic-gate 4168*7c478bd9Sstevel@tonic-gate if ((pip == NULL) || (MDI_PI(pip)->pi_prop == NULL)) { 4169*7c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 4170*7c478bd9Sstevel@tonic-gate } 4171*7c478bd9Sstevel@tonic-gate rv = nvlist_lookup_string_array(MDI_PI(pip)->pi_prop, name, data, 4172*7c478bd9Sstevel@tonic-gate nelements); 4173*7c478bd9Sstevel@tonic-gate return (i_map_nvlist_error_to_mdi(rv)); 4174*7c478bd9Sstevel@tonic-gate } 4175*7c478bd9Sstevel@tonic-gate 4176*7c478bd9Sstevel@tonic-gate /* 4177*7c478bd9Sstevel@tonic-gate * mdi_prop_free(): 4178*7c478bd9Sstevel@tonic-gate * Symmetrical function to ddi_prop_free(). nvlist_lookup_xx() 4179*7c478bd9Sstevel@tonic-gate * functions return the pointer to actual property data and not a 4180*7c478bd9Sstevel@tonic-gate * copy of it. So the data returned is valid as long as 4181*7c478bd9Sstevel@tonic-gate * mdi_pathinfo_t node is valid. 4182*7c478bd9Sstevel@tonic-gate */ 4183*7c478bd9Sstevel@tonic-gate 4184*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4185*7c478bd9Sstevel@tonic-gate int 4186*7c478bd9Sstevel@tonic-gate mdi_prop_free(void *data) 4187*7c478bd9Sstevel@tonic-gate { 4188*7c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 4189*7c478bd9Sstevel@tonic-gate } 4190*7c478bd9Sstevel@tonic-gate 4191*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4192*7c478bd9Sstevel@tonic-gate static void 4193*7c478bd9Sstevel@tonic-gate i_mdi_report_path_state(mdi_client_t *ct, mdi_pathinfo_t *pip) 4194*7c478bd9Sstevel@tonic-gate { 4195*7c478bd9Sstevel@tonic-gate char *phci_path, *ct_path; 4196*7c478bd9Sstevel@tonic-gate char *ct_status; 4197*7c478bd9Sstevel@tonic-gate char *status; 4198*7c478bd9Sstevel@tonic-gate dev_info_t *dip = ct->ct_dip; 4199*7c478bd9Sstevel@tonic-gate char lb_buf[64]; 4200*7c478bd9Sstevel@tonic-gate 4201*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_mutex)); 4202*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (ddi_get_instance(dip) == -1) || 4203*7c478bd9Sstevel@tonic-gate (MDI_CLIENT_IS_REPORT_DEV_NEEDED(ct) == 0)) { 4204*7c478bd9Sstevel@tonic-gate return; 4205*7c478bd9Sstevel@tonic-gate } 4206*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_OPTIMAL) { 4207*7c478bd9Sstevel@tonic-gate ct_status = "optimal"; 4208*7c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_DEGRADED) { 4209*7c478bd9Sstevel@tonic-gate ct_status = "degraded"; 4210*7c478bd9Sstevel@tonic-gate } else if (MDI_CLIENT_STATE(ct) == MDI_CLIENT_STATE_FAILED) { 4211*7c478bd9Sstevel@tonic-gate ct_status = "failed"; 4212*7c478bd9Sstevel@tonic-gate } else { 4213*7c478bd9Sstevel@tonic-gate ct_status = "unknown"; 4214*7c478bd9Sstevel@tonic-gate } 4215*7c478bd9Sstevel@tonic-gate 4216*7c478bd9Sstevel@tonic-gate if (MDI_PI_IS_OFFLINE(pip)) { 4217*7c478bd9Sstevel@tonic-gate status = "offline"; 4218*7c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_ONLINE(pip)) { 4219*7c478bd9Sstevel@tonic-gate status = "online"; 4220*7c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_STANDBY(pip)) { 4221*7c478bd9Sstevel@tonic-gate status = "standby"; 4222*7c478bd9Sstevel@tonic-gate } else if (MDI_PI_IS_FAULT(pip)) { 4223*7c478bd9Sstevel@tonic-gate status = "faulted"; 4224*7c478bd9Sstevel@tonic-gate } else { 4225*7c478bd9Sstevel@tonic-gate status = "unknown"; 4226*7c478bd9Sstevel@tonic-gate } 4227*7c478bd9Sstevel@tonic-gate 4228*7c478bd9Sstevel@tonic-gate if (ct->ct_lb == LOAD_BALANCE_LBA) { 4229*7c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 4230*7c478bd9Sstevel@tonic-gate "%s, region-size: %d", mdi_load_balance_lba, 4231*7c478bd9Sstevel@tonic-gate ct->ct_lb_args->region_size); 4232*7c478bd9Sstevel@tonic-gate } else if (ct->ct_lb == LOAD_BALANCE_NONE) { 4233*7c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), 4234*7c478bd9Sstevel@tonic-gate "%s", mdi_load_balance_none); 4235*7c478bd9Sstevel@tonic-gate } else { 4236*7c478bd9Sstevel@tonic-gate (void) snprintf(lb_buf, sizeof (lb_buf), "%s", 4237*7c478bd9Sstevel@tonic-gate mdi_load_balance_rr); 4238*7c478bd9Sstevel@tonic-gate } 4239*7c478bd9Sstevel@tonic-gate 4240*7c478bd9Sstevel@tonic-gate if (dip) { 4241*7c478bd9Sstevel@tonic-gate ct_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 4242*7c478bd9Sstevel@tonic-gate phci_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 4243*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s (%s%d) multipath status: %s, " 4244*7c478bd9Sstevel@tonic-gate "path %s (%s%d) to target address: %s is %s" 4245*7c478bd9Sstevel@tonic-gate " Load balancing: %s\n", 4246*7c478bd9Sstevel@tonic-gate ddi_pathname(dip, ct_path), ddi_driver_name(dip), 4247*7c478bd9Sstevel@tonic-gate ddi_get_instance(dip), ct_status, 4248*7c478bd9Sstevel@tonic-gate ddi_pathname(MDI_PI(pip)->pi_phci->ph_dip, phci_path), 4249*7c478bd9Sstevel@tonic-gate ddi_driver_name(MDI_PI(pip)->pi_phci->ph_dip), 4250*7c478bd9Sstevel@tonic-gate ddi_get_instance(MDI_PI(pip)->pi_phci->ph_dip), 4251*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_addr, status, lb_buf); 4252*7c478bd9Sstevel@tonic-gate kmem_free(phci_path, MAXPATHLEN); 4253*7c478bd9Sstevel@tonic-gate kmem_free(ct_path, MAXPATHLEN); 4254*7c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_REPORT_DEV_NEEDED(ct); 4255*7c478bd9Sstevel@tonic-gate } 4256*7c478bd9Sstevel@tonic-gate } 4257*7c478bd9Sstevel@tonic-gate 4258*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 4259*7c478bd9Sstevel@tonic-gate /* 4260*7c478bd9Sstevel@tonic-gate * i_mdi_log(): 4261*7c478bd9Sstevel@tonic-gate * Utility function for error message management 4262*7c478bd9Sstevel@tonic-gate * 4263*7c478bd9Sstevel@tonic-gate */ 4264*7c478bd9Sstevel@tonic-gate 4265*7c478bd9Sstevel@tonic-gate /*VARARGS3*/ 4266*7c478bd9Sstevel@tonic-gate static void 4267*7c478bd9Sstevel@tonic-gate i_mdi_log(int level, dev_info_t *dip, const char *fmt, ...) 4268*7c478bd9Sstevel@tonic-gate { 4269*7c478bd9Sstevel@tonic-gate char buf[MAXNAMELEN]; 4270*7c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 4271*7c478bd9Sstevel@tonic-gate va_list ap; 4272*7c478bd9Sstevel@tonic-gate int log_only = 0; 4273*7c478bd9Sstevel@tonic-gate int boot_only = 0; 4274*7c478bd9Sstevel@tonic-gate int console_only = 0; 4275*7c478bd9Sstevel@tonic-gate 4276*7c478bd9Sstevel@tonic-gate if (dip) { 4277*7c478bd9Sstevel@tonic-gate if (level == CE_PANIC || level == CE_WARN || level == CE_NOTE) { 4278*7c478bd9Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "%s%d:\n", 4279*7c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip)); 4280*7c478bd9Sstevel@tonic-gate } else { 4281*7c478bd9Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "%s%d:", 4282*7c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip)); 4283*7c478bd9Sstevel@tonic-gate } 4284*7c478bd9Sstevel@tonic-gate } else { 4285*7c478bd9Sstevel@tonic-gate name[0] = '\0'; 4286*7c478bd9Sstevel@tonic-gate } 4287*7c478bd9Sstevel@tonic-gate 4288*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 4289*7c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, MAXNAMELEN, fmt, ap); 4290*7c478bd9Sstevel@tonic-gate va_end(ap); 4291*7c478bd9Sstevel@tonic-gate 4292*7c478bd9Sstevel@tonic-gate switch (buf[0]) { 4293*7c478bd9Sstevel@tonic-gate case '!': 4294*7c478bd9Sstevel@tonic-gate log_only = 1; 4295*7c478bd9Sstevel@tonic-gate break; 4296*7c478bd9Sstevel@tonic-gate case '?': 4297*7c478bd9Sstevel@tonic-gate boot_only = 1; 4298*7c478bd9Sstevel@tonic-gate break; 4299*7c478bd9Sstevel@tonic-gate case '^': 4300*7c478bd9Sstevel@tonic-gate console_only = 1; 4301*7c478bd9Sstevel@tonic-gate break; 4302*7c478bd9Sstevel@tonic-gate } 4303*7c478bd9Sstevel@tonic-gate 4304*7c478bd9Sstevel@tonic-gate switch (level) { 4305*7c478bd9Sstevel@tonic-gate case CE_NOTE: 4306*7c478bd9Sstevel@tonic-gate level = CE_CONT; 4307*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 4308*7c478bd9Sstevel@tonic-gate case CE_CONT: 4309*7c478bd9Sstevel@tonic-gate case CE_WARN: 4310*7c478bd9Sstevel@tonic-gate case CE_PANIC: 4311*7c478bd9Sstevel@tonic-gate if (boot_only) { 4312*7c478bd9Sstevel@tonic-gate cmn_err(level, "?%s\t%s", name, &buf[1]); 4313*7c478bd9Sstevel@tonic-gate } else if (console_only) { 4314*7c478bd9Sstevel@tonic-gate cmn_err(level, "^%s\t%s", name, &buf[1]); 4315*7c478bd9Sstevel@tonic-gate } else if (log_only) { 4316*7c478bd9Sstevel@tonic-gate cmn_err(level, "!%s\t%s", name, &buf[1]); 4317*7c478bd9Sstevel@tonic-gate } else { 4318*7c478bd9Sstevel@tonic-gate cmn_err(level, "%s\t%s", name, buf); 4319*7c478bd9Sstevel@tonic-gate } 4320*7c478bd9Sstevel@tonic-gate break; 4321*7c478bd9Sstevel@tonic-gate default: 4322*7c478bd9Sstevel@tonic-gate cmn_err(level, "%s\t%s", name, buf); 4323*7c478bd9Sstevel@tonic-gate break; 4324*7c478bd9Sstevel@tonic-gate } 4325*7c478bd9Sstevel@tonic-gate } 4326*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 4327*7c478bd9Sstevel@tonic-gate 4328*7c478bd9Sstevel@tonic-gate void 4329*7c478bd9Sstevel@tonic-gate i_mdi_client_online(dev_info_t *ct_dip) 4330*7c478bd9Sstevel@tonic-gate { 4331*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 4332*7c478bd9Sstevel@tonic-gate 4333*7c478bd9Sstevel@tonic-gate /* 4334*7c478bd9Sstevel@tonic-gate * Client online notification. Mark client state as online 4335*7c478bd9Sstevel@tonic-gate * restore our binding with dev_info node 4336*7c478bd9Sstevel@tonic-gate */ 4337*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(ct_dip); 4338*7c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 4339*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 4340*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ONLINE(ct); 4341*7c478bd9Sstevel@tonic-gate /* catch for any memory leaks */ 4342*7c478bd9Sstevel@tonic-gate ASSERT((ct->ct_dip == NULL) || (ct->ct_dip == ct_dip)); 4343*7c478bd9Sstevel@tonic-gate ct->ct_dip = ct_dip; 4344*7c478bd9Sstevel@tonic-gate 4345*7c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) 4346*7c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 4347*7c478bd9Sstevel@tonic-gate 4348*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct_dip, "i_mdi_client_online " 4349*7c478bd9Sstevel@tonic-gate "i_mdi_pm_hold_client\n")); 4350*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, 1); 4351*7c478bd9Sstevel@tonic-gate 4352*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 4353*7c478bd9Sstevel@tonic-gate } 4354*7c478bd9Sstevel@tonic-gate 4355*7c478bd9Sstevel@tonic-gate void 4356*7c478bd9Sstevel@tonic-gate i_mdi_phci_online(dev_info_t *ph_dip) 4357*7c478bd9Sstevel@tonic-gate { 4358*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 4359*7c478bd9Sstevel@tonic-gate 4360*7c478bd9Sstevel@tonic-gate /* pHCI online notification. Mark state accordingly */ 4361*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(ph_dip); 4362*7c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 4363*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 4364*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 4365*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4366*7c478bd9Sstevel@tonic-gate } 4367*7c478bd9Sstevel@tonic-gate 4368*7c478bd9Sstevel@tonic-gate /* 4369*7c478bd9Sstevel@tonic-gate * mdi_devi_online(): 4370*7c478bd9Sstevel@tonic-gate * Online notification from NDI framework on pHCI/client 4371*7c478bd9Sstevel@tonic-gate * device online. 4372*7c478bd9Sstevel@tonic-gate * Return Values: 4373*7c478bd9Sstevel@tonic-gate * NDI_SUCCESS 4374*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 4375*7c478bd9Sstevel@tonic-gate */ 4376*7c478bd9Sstevel@tonic-gate 4377*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4378*7c478bd9Sstevel@tonic-gate int 4379*7c478bd9Sstevel@tonic-gate mdi_devi_online(dev_info_t *dip, uint_t flags) 4380*7c478bd9Sstevel@tonic-gate { 4381*7c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 4382*7c478bd9Sstevel@tonic-gate i_mdi_phci_online(dip); 4383*7c478bd9Sstevel@tonic-gate } 4384*7c478bd9Sstevel@tonic-gate 4385*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 4386*7c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 4387*7c478bd9Sstevel@tonic-gate } 4388*7c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 4389*7c478bd9Sstevel@tonic-gate } 4390*7c478bd9Sstevel@tonic-gate 4391*7c478bd9Sstevel@tonic-gate /* 4392*7c478bd9Sstevel@tonic-gate * mdi_devi_offline(): 4393*7c478bd9Sstevel@tonic-gate * Offline notification from NDI framework on pHCI/Client device 4394*7c478bd9Sstevel@tonic-gate * offline. 4395*7c478bd9Sstevel@tonic-gate * 4396*7c478bd9Sstevel@tonic-gate * Return Values: 4397*7c478bd9Sstevel@tonic-gate * NDI_SUCCESS 4398*7c478bd9Sstevel@tonic-gate * NDI_FAILURE 4399*7c478bd9Sstevel@tonic-gate */ 4400*7c478bd9Sstevel@tonic-gate 4401*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4402*7c478bd9Sstevel@tonic-gate int 4403*7c478bd9Sstevel@tonic-gate mdi_devi_offline(dev_info_t *dip, uint_t flags) 4404*7c478bd9Sstevel@tonic-gate { 4405*7c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 4406*7c478bd9Sstevel@tonic-gate 4407*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 4408*7c478bd9Sstevel@tonic-gate rv = i_mdi_client_offline(dip, flags); 4409*7c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) 4410*7c478bd9Sstevel@tonic-gate return (rv); 4411*7c478bd9Sstevel@tonic-gate } 4412*7c478bd9Sstevel@tonic-gate 4413*7c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 4414*7c478bd9Sstevel@tonic-gate rv = i_mdi_phci_offline(dip, flags); 4415*7c478bd9Sstevel@tonic-gate if ((rv != NDI_SUCCESS) && MDI_CLIENT(dip)) { 4416*7c478bd9Sstevel@tonic-gate /* set client back online */ 4417*7c478bd9Sstevel@tonic-gate i_mdi_client_online(dip); 4418*7c478bd9Sstevel@tonic-gate } 4419*7c478bd9Sstevel@tonic-gate } 4420*7c478bd9Sstevel@tonic-gate 4421*7c478bd9Sstevel@tonic-gate return (rv); 4422*7c478bd9Sstevel@tonic-gate } 4423*7c478bd9Sstevel@tonic-gate 4424*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4425*7c478bd9Sstevel@tonic-gate static int 4426*7c478bd9Sstevel@tonic-gate i_mdi_phci_offline(dev_info_t *dip, uint_t flags) 4427*7c478bd9Sstevel@tonic-gate { 4428*7c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 4429*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 4430*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 4431*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 4432*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 4433*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 4434*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 4435*7c478bd9Sstevel@tonic-gate 4436*7c478bd9Sstevel@tonic-gate /* 4437*7c478bd9Sstevel@tonic-gate * pHCI component offline notification 4438*7c478bd9Sstevel@tonic-gate * Make sure that this pHCI instance is free to be offlined. 4439*7c478bd9Sstevel@tonic-gate * If it is OK to proceed, Offline and remove all the child 4440*7c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes. This process automatically offlines 4441*7c478bd9Sstevel@tonic-gate * corresponding client devices, for which this pHCI provides 4442*7c478bd9Sstevel@tonic-gate * critical services. 4443*7c478bd9Sstevel@tonic-gate */ 4444*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, "!mdi_phci_offline called %p\n", 4445*7c478bd9Sstevel@tonic-gate dip)); 4446*7c478bd9Sstevel@tonic-gate 4447*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 4448*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 4449*7c478bd9Sstevel@tonic-gate return (rv); 4450*7c478bd9Sstevel@tonic-gate } 4451*7c478bd9Sstevel@tonic-gate 4452*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 4453*7c478bd9Sstevel@tonic-gate 4454*7c478bd9Sstevel@tonic-gate if (MDI_PHCI_IS_OFFLINE(ph)) { 4455*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, "!pHCI %p already offlined", ph)); 4456*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4457*7c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 4458*7c478bd9Sstevel@tonic-gate } 4459*7c478bd9Sstevel@tonic-gate 4460*7c478bd9Sstevel@tonic-gate /* 4461*7c478bd9Sstevel@tonic-gate * Check to see if the pHCI can be offlined 4462*7c478bd9Sstevel@tonic-gate */ 4463*7c478bd9Sstevel@tonic-gate if (ph->ph_unstable) { 4464*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 4465*7c478bd9Sstevel@tonic-gate "!One or more target devices are in transient " 4466*7c478bd9Sstevel@tonic-gate "state. This device can not be removed at " 4467*7c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 4468*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4469*7c478bd9Sstevel@tonic-gate return (NDI_BUSY); 4470*7c478bd9Sstevel@tonic-gate } 4471*7c478bd9Sstevel@tonic-gate 4472*7c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 4473*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 4474*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 4475*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 4476*7c478bd9Sstevel@tonic-gate /* 4477*7c478bd9Sstevel@tonic-gate * The mdi_pathinfo state is OK. Check the client state. 4478*7c478bd9Sstevel@tonic-gate * If failover in progress fail the pHCI from offlining 4479*7c478bd9Sstevel@tonic-gate */ 4480*7c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 4481*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 4482*7c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) || 4483*7c478bd9Sstevel@tonic-gate (ct->ct_unstable)) { 4484*7c478bd9Sstevel@tonic-gate /* 4485*7c478bd9Sstevel@tonic-gate * Failover is in progress, Fail the DR 4486*7c478bd9Sstevel@tonic-gate */ 4487*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 4488*7c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 4489*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 4490*7c478bd9Sstevel@tonic-gate "This device can not be removed at " 4491*7c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 4492*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4493*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 4494*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4495*7c478bd9Sstevel@tonic-gate return (NDI_BUSY); 4496*7c478bd9Sstevel@tonic-gate } 4497*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4498*7c478bd9Sstevel@tonic-gate 4499*7c478bd9Sstevel@tonic-gate /* 4500*7c478bd9Sstevel@tonic-gate * Check to see of we are removing the last path of this 4501*7c478bd9Sstevel@tonic-gate * client device... 4502*7c478bd9Sstevel@tonic-gate */ 4503*7c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 4504*7c478bd9Sstevel@tonic-gate if (cdip && (i_ddi_node_state(cdip) >= DS_INITIALIZED) && 4505*7c478bd9Sstevel@tonic-gate (i_mdi_client_compute_state(ct, ph) == 4506*7c478bd9Sstevel@tonic-gate MDI_CLIENT_STATE_FAILED)) { 4507*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 4508*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4509*7c478bd9Sstevel@tonic-gate if (ndi_devi_offline(cdip, 0) != NDI_SUCCESS) { 4510*7c478bd9Sstevel@tonic-gate /* 4511*7c478bd9Sstevel@tonic-gate * ndi_devi_offline() failed. 4512*7c478bd9Sstevel@tonic-gate * This pHCI provides the critical path 4513*7c478bd9Sstevel@tonic-gate * to one or more client devices. 4514*7c478bd9Sstevel@tonic-gate * Return busy. 4515*7c478bd9Sstevel@tonic-gate */ 4516*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 4517*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 4518*7c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 4519*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 4520*7c478bd9Sstevel@tonic-gate "This device can not be removed at " 4521*7c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 4522*7c478bd9Sstevel@tonic-gate failed_pip = pip; 4523*7c478bd9Sstevel@tonic-gate break; 4524*7c478bd9Sstevel@tonic-gate } else { 4525*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 4526*7c478bd9Sstevel@tonic-gate pip = next; 4527*7c478bd9Sstevel@tonic-gate } 4528*7c478bd9Sstevel@tonic-gate } else { 4529*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 4530*7c478bd9Sstevel@tonic-gate pip = next; 4531*7c478bd9Sstevel@tonic-gate } 4532*7c478bd9Sstevel@tonic-gate } 4533*7c478bd9Sstevel@tonic-gate 4534*7c478bd9Sstevel@tonic-gate if (failed_pip) { 4535*7c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 4536*7c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 4537*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 4538*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 4539*7c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 4540*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 4541*7c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 4542*7c478bd9Sstevel@tonic-gate switch (MDI_CLIENT_STATE(ct)) { 4543*7c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_OPTIMAL: 4544*7c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_DEGRADED: 4545*7c478bd9Sstevel@tonic-gate if (cdip) { 4546*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4547*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 4548*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4549*7c478bd9Sstevel@tonic-gate (void) ndi_devi_online(cdip, 0); 4550*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 4551*7c478bd9Sstevel@tonic-gate pip = next; 4552*7c478bd9Sstevel@tonic-gate continue; 4553*7c478bd9Sstevel@tonic-gate } 4554*7c478bd9Sstevel@tonic-gate break; 4555*7c478bd9Sstevel@tonic-gate 4556*7c478bd9Sstevel@tonic-gate case MDI_CLIENT_STATE_FAILED: 4557*7c478bd9Sstevel@tonic-gate if (cdip) { 4558*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4559*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 4560*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4561*7c478bd9Sstevel@tonic-gate (void) ndi_devi_offline(cdip, 0); 4562*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 4563*7c478bd9Sstevel@tonic-gate pip = next; 4564*7c478bd9Sstevel@tonic-gate continue; 4565*7c478bd9Sstevel@tonic-gate } 4566*7c478bd9Sstevel@tonic-gate break; 4567*7c478bd9Sstevel@tonic-gate } 4568*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4569*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 4570*7c478bd9Sstevel@tonic-gate pip = next; 4571*7c478bd9Sstevel@tonic-gate } 4572*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4573*7c478bd9Sstevel@tonic-gate return (NDI_BUSY); 4574*7c478bd9Sstevel@tonic-gate } 4575*7c478bd9Sstevel@tonic-gate 4576*7c478bd9Sstevel@tonic-gate /* 4577*7c478bd9Sstevel@tonic-gate * Mark the pHCI as offline 4578*7c478bd9Sstevel@tonic-gate */ 4579*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_OFFLINE(ph); 4580*7c478bd9Sstevel@tonic-gate 4581*7c478bd9Sstevel@tonic-gate /* 4582*7c478bd9Sstevel@tonic-gate * Mark the child mdi_pathinfo nodes as transient 4583*7c478bd9Sstevel@tonic-gate */ 4584*7c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 4585*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 4586*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 4587*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 4588*7c478bd9Sstevel@tonic-gate MDI_PI_SET_OFFLINING(pip); 4589*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4590*7c478bd9Sstevel@tonic-gate pip = next; 4591*7c478bd9Sstevel@tonic-gate } 4592*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4593*7c478bd9Sstevel@tonic-gate /* 4594*7c478bd9Sstevel@tonic-gate * Give a chance for any pending commands to execute 4595*7c478bd9Sstevel@tonic-gate */ 4596*7c478bd9Sstevel@tonic-gate delay(1); 4597*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 4598*7c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 4599*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 4600*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 4601*7c478bd9Sstevel@tonic-gate (void) i_mdi_pi_offline(pip, flags); 4602*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 4603*7c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 4604*7c478bd9Sstevel@tonic-gate if (!MDI_PI_IS_OFFLINE(pip)) { 4605*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 4606*7c478bd9Sstevel@tonic-gate "!pHCI device (%s%d) is Busy. %s", 4607*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 4608*7c478bd9Sstevel@tonic-gate "This device can not be removed at " 4609*7c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 4610*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4611*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ONLINE(ph); 4612*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4613*7c478bd9Sstevel@tonic-gate return (NDI_BUSY); 4614*7c478bd9Sstevel@tonic-gate } 4615*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4616*7c478bd9Sstevel@tonic-gate pip = next; 4617*7c478bd9Sstevel@tonic-gate } 4618*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4619*7c478bd9Sstevel@tonic-gate 4620*7c478bd9Sstevel@tonic-gate return (rv); 4621*7c478bd9Sstevel@tonic-gate } 4622*7c478bd9Sstevel@tonic-gate 4623*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4624*7c478bd9Sstevel@tonic-gate static int 4625*7c478bd9Sstevel@tonic-gate i_mdi_client_offline(dev_info_t *dip, uint_t flags) 4626*7c478bd9Sstevel@tonic-gate { 4627*7c478bd9Sstevel@tonic-gate int rv = NDI_SUCCESS; 4628*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 4629*7c478bd9Sstevel@tonic-gate 4630*7c478bd9Sstevel@tonic-gate /* 4631*7c478bd9Sstevel@tonic-gate * Client component to go offline. Make sure that we are 4632*7c478bd9Sstevel@tonic-gate * not in failing over state and update client state 4633*7c478bd9Sstevel@tonic-gate * accordingly 4634*7c478bd9Sstevel@tonic-gate */ 4635*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, "!i_mdi_client_offline called %p\n", 4636*7c478bd9Sstevel@tonic-gate dip)); 4637*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 4638*7c478bd9Sstevel@tonic-gate if (ct != NULL) { 4639*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 4640*7c478bd9Sstevel@tonic-gate if (ct->ct_unstable) { 4641*7c478bd9Sstevel@tonic-gate /* 4642*7c478bd9Sstevel@tonic-gate * One or more paths are in transient state, 4643*7c478bd9Sstevel@tonic-gate * Dont allow offline of a client device 4644*7c478bd9Sstevel@tonic-gate */ 4645*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 4646*7c478bd9Sstevel@tonic-gate "!One or more paths to this device is " 4647*7c478bd9Sstevel@tonic-gate "in transient state. This device can not " 4648*7c478bd9Sstevel@tonic-gate "be removed at this moment. " 4649*7c478bd9Sstevel@tonic-gate "Please try again later.")); 4650*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 4651*7c478bd9Sstevel@tonic-gate return (NDI_BUSY); 4652*7c478bd9Sstevel@tonic-gate } 4653*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILOVER_IN_PROGRESS(ct)) { 4654*7c478bd9Sstevel@tonic-gate /* 4655*7c478bd9Sstevel@tonic-gate * Failover is in progress, Dont allow DR of 4656*7c478bd9Sstevel@tonic-gate * a client device 4657*7c478bd9Sstevel@tonic-gate */ 4658*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 4659*7c478bd9Sstevel@tonic-gate "!Client device (%s%d) is Busy. %s", 4660*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 4661*7c478bd9Sstevel@tonic-gate "This device can not be removed at " 4662*7c478bd9Sstevel@tonic-gate "this moment. Please try again later.")); 4663*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 4664*7c478bd9Sstevel@tonic-gate return (NDI_BUSY); 4665*7c478bd9Sstevel@tonic-gate } 4666*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_OFFLINE(ct); 4667*7c478bd9Sstevel@tonic-gate 4668*7c478bd9Sstevel@tonic-gate /* 4669*7c478bd9Sstevel@tonic-gate * Unbind our relationship with the dev_info node 4670*7c478bd9Sstevel@tonic-gate */ 4671*7c478bd9Sstevel@tonic-gate if (flags & NDI_DEVI_REMOVE) { 4672*7c478bd9Sstevel@tonic-gate ct->ct_dip = NULL; 4673*7c478bd9Sstevel@tonic-gate } 4674*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 4675*7c478bd9Sstevel@tonic-gate } 4676*7c478bd9Sstevel@tonic-gate return (rv); 4677*7c478bd9Sstevel@tonic-gate } 4678*7c478bd9Sstevel@tonic-gate 4679*7c478bd9Sstevel@tonic-gate /* 4680*7c478bd9Sstevel@tonic-gate * mdi_pre_attach(): 4681*7c478bd9Sstevel@tonic-gate * Pre attach() notification handler 4682*7c478bd9Sstevel@tonic-gate */ 4683*7c478bd9Sstevel@tonic-gate 4684*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4685*7c478bd9Sstevel@tonic-gate int 4686*7c478bd9Sstevel@tonic-gate mdi_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4687*7c478bd9Sstevel@tonic-gate { 4688*7c478bd9Sstevel@tonic-gate /* don't support old DDI_PM_RESUME */ 4689*7c478bd9Sstevel@tonic-gate if ((DEVI(dip)->devi_mdi_component != MDI_COMPONENT_NONE) && 4690*7c478bd9Sstevel@tonic-gate (cmd == DDI_PM_RESUME)) 4691*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4692*7c478bd9Sstevel@tonic-gate 4693*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4694*7c478bd9Sstevel@tonic-gate } 4695*7c478bd9Sstevel@tonic-gate 4696*7c478bd9Sstevel@tonic-gate /* 4697*7c478bd9Sstevel@tonic-gate * mdi_post_attach(): 4698*7c478bd9Sstevel@tonic-gate * Post attach() notification handler 4699*7c478bd9Sstevel@tonic-gate */ 4700*7c478bd9Sstevel@tonic-gate 4701*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4702*7c478bd9Sstevel@tonic-gate void 4703*7c478bd9Sstevel@tonic-gate mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error) 4704*7c478bd9Sstevel@tonic-gate { 4705*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 4706*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 4707*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 4708*7c478bd9Sstevel@tonic-gate 4709*7c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 4710*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 4711*7c478bd9Sstevel@tonic-gate ASSERT(ph != NULL); 4712*7c478bd9Sstevel@tonic-gate 4713*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 4714*7c478bd9Sstevel@tonic-gate switch (cmd) { 4715*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 4716*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4717*7c478bd9Sstevel@tonic-gate "!pHCI post_attach: called %p\n", ph)); 4718*7c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 4719*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 4720*7c478bd9Sstevel@tonic-gate } else { 4721*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 4722*7c478bd9Sstevel@tonic-gate "!pHCI post_attach: failed error=%d\n", 4723*7c478bd9Sstevel@tonic-gate error)); 4724*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 4725*7c478bd9Sstevel@tonic-gate } 4726*7c478bd9Sstevel@tonic-gate break; 4727*7c478bd9Sstevel@tonic-gate 4728*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 4729*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4730*7c478bd9Sstevel@tonic-gate "!pHCI post_resume: called %p\n", ph)); 4731*7c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 4732*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 4733*7c478bd9Sstevel@tonic-gate } else { 4734*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 4735*7c478bd9Sstevel@tonic-gate "!pHCI post_resume: failed error=%d\n", 4736*7c478bd9Sstevel@tonic-gate error)); 4737*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 4738*7c478bd9Sstevel@tonic-gate } 4739*7c478bd9Sstevel@tonic-gate break; 4740*7c478bd9Sstevel@tonic-gate } 4741*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4742*7c478bd9Sstevel@tonic-gate } 4743*7c478bd9Sstevel@tonic-gate 4744*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 4745*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 4746*7c478bd9Sstevel@tonic-gate ASSERT(ct != NULL); 4747*7c478bd9Sstevel@tonic-gate 4748*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 4749*7c478bd9Sstevel@tonic-gate switch (cmd) { 4750*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 4751*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4752*7c478bd9Sstevel@tonic-gate "!Client post_attach: called %p\n", ct)); 4753*7c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) { 4754*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 4755*7c478bd9Sstevel@tonic-gate "!Client post_attach: failed error=%d\n", 4756*7c478bd9Sstevel@tonic-gate error)); 4757*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 4758*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_WARN, dip, 4759*7c478bd9Sstevel@tonic-gate "mdi_post_attach i_mdi_pm_reset_client\n")); 4760*7c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 4761*7c478bd9Sstevel@tonic-gate break; 4762*7c478bd9Sstevel@tonic-gate } 4763*7c478bd9Sstevel@tonic-gate 4764*7c478bd9Sstevel@tonic-gate /* 4765*7c478bd9Sstevel@tonic-gate * Client device has successfully attached. 4766*7c478bd9Sstevel@tonic-gate * Create kstats for any pathinfo structures 4767*7c478bd9Sstevel@tonic-gate * initially associated with this client. 4768*7c478bd9Sstevel@tonic-gate */ 4769*7c478bd9Sstevel@tonic-gate for (pip = ct->ct_path_head; pip != NULL; 4770*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *) 4771*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_client_link) { 4772*7c478bd9Sstevel@tonic-gate (void) i_mdi_pi_kstat_create(pip); 4773*7c478bd9Sstevel@tonic-gate i_mdi_report_path_state(ct, pip); 4774*7c478bd9Sstevel@tonic-gate } 4775*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 4776*7c478bd9Sstevel@tonic-gate break; 4777*7c478bd9Sstevel@tonic-gate 4778*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 4779*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4780*7c478bd9Sstevel@tonic-gate "!Client post_attach: called %p\n", ct)); 4781*7c478bd9Sstevel@tonic-gate if (error == DDI_SUCCESS) { 4782*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 4783*7c478bd9Sstevel@tonic-gate } else { 4784*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, dip, 4785*7c478bd9Sstevel@tonic-gate "!Client post_resume: failed error=%d\n", 4786*7c478bd9Sstevel@tonic-gate error)); 4787*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 4788*7c478bd9Sstevel@tonic-gate } 4789*7c478bd9Sstevel@tonic-gate break; 4790*7c478bd9Sstevel@tonic-gate } 4791*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 4792*7c478bd9Sstevel@tonic-gate } 4793*7c478bd9Sstevel@tonic-gate } 4794*7c478bd9Sstevel@tonic-gate 4795*7c478bd9Sstevel@tonic-gate /* 4796*7c478bd9Sstevel@tonic-gate * mdi_pre_detach(): 4797*7c478bd9Sstevel@tonic-gate * Pre detach notification handler 4798*7c478bd9Sstevel@tonic-gate */ 4799*7c478bd9Sstevel@tonic-gate 4800*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4801*7c478bd9Sstevel@tonic-gate int 4802*7c478bd9Sstevel@tonic-gate mdi_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4803*7c478bd9Sstevel@tonic-gate { 4804*7c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 4805*7c478bd9Sstevel@tonic-gate 4806*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) { 4807*7c478bd9Sstevel@tonic-gate (void) i_mdi_client_pre_detach(dip, cmd); 4808*7c478bd9Sstevel@tonic-gate } 4809*7c478bd9Sstevel@tonic-gate 4810*7c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) { 4811*7c478bd9Sstevel@tonic-gate rv = i_mdi_phci_pre_detach(dip, cmd); 4812*7c478bd9Sstevel@tonic-gate } 4813*7c478bd9Sstevel@tonic-gate 4814*7c478bd9Sstevel@tonic-gate return (rv); 4815*7c478bd9Sstevel@tonic-gate } 4816*7c478bd9Sstevel@tonic-gate 4817*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4818*7c478bd9Sstevel@tonic-gate static int 4819*7c478bd9Sstevel@tonic-gate i_mdi_phci_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4820*7c478bd9Sstevel@tonic-gate { 4821*7c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 4822*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 4823*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 4824*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 4825*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *failed_pip = NULL; 4826*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next; 4827*7c478bd9Sstevel@tonic-gate 4828*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 4829*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 4830*7c478bd9Sstevel@tonic-gate return (rv); 4831*7c478bd9Sstevel@tonic-gate } 4832*7c478bd9Sstevel@tonic-gate 4833*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 4834*7c478bd9Sstevel@tonic-gate switch (cmd) { 4835*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 4836*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4837*7c478bd9Sstevel@tonic-gate "!pHCI pre_detach: called %p\n", ph)); 4838*7c478bd9Sstevel@tonic-gate if (!MDI_PHCI_IS_OFFLINE(ph)) { 4839*7c478bd9Sstevel@tonic-gate /* 4840*7c478bd9Sstevel@tonic-gate * mdi_pathinfo nodes are still attached to 4841*7c478bd9Sstevel@tonic-gate * this pHCI. Fail the detach for this pHCI. 4842*7c478bd9Sstevel@tonic-gate */ 4843*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, dip, 4844*7c478bd9Sstevel@tonic-gate "!pHCI pre_detach: " 4845*7c478bd9Sstevel@tonic-gate "mdi_pathinfo nodes are still attached " 4846*7c478bd9Sstevel@tonic-gate "%p\n", ph)); 4847*7c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 4848*7c478bd9Sstevel@tonic-gate break; 4849*7c478bd9Sstevel@tonic-gate } 4850*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DETACH(ph); 4851*7c478bd9Sstevel@tonic-gate break; 4852*7c478bd9Sstevel@tonic-gate 4853*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 4854*7c478bd9Sstevel@tonic-gate /* 4855*7c478bd9Sstevel@tonic-gate * pHCI is getting suspended. Since mpxio client 4856*7c478bd9Sstevel@tonic-gate * devices may not be suspended at this point, to avoid 4857*7c478bd9Sstevel@tonic-gate * a potential stack overflow, it is important to suspend 4858*7c478bd9Sstevel@tonic-gate * client devices before pHCI can be suspended. 4859*7c478bd9Sstevel@tonic-gate */ 4860*7c478bd9Sstevel@tonic-gate 4861*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4862*7c478bd9Sstevel@tonic-gate "!pHCI pre_suspend: called %p\n", ph)); 4863*7c478bd9Sstevel@tonic-gate /* 4864*7c478bd9Sstevel@tonic-gate * Suspend all the client devices accessible through this pHCI 4865*7c478bd9Sstevel@tonic-gate */ 4866*7c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 4867*7c478bd9Sstevel@tonic-gate while (pip != NULL && rv == DDI_SUCCESS) { 4868*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 4869*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 4870*7c478bd9Sstevel@tonic-gate next = 4871*7c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 4872*7c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 4873*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 4874*7c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 4875*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4876*7c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_DETACHED(ct) == 0) && 4877*7c478bd9Sstevel@tonic-gate MDI_CLIENT_IS_SUSPENDED(ct) == 0) { 4878*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 4879*7c478bd9Sstevel@tonic-gate if ((rv = devi_detach(cdip, DDI_SUSPEND)) != 4880*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 4881*7c478bd9Sstevel@tonic-gate /* 4882*7c478bd9Sstevel@tonic-gate * Suspend of one of the client 4883*7c478bd9Sstevel@tonic-gate * device has failed. 4884*7c478bd9Sstevel@tonic-gate */ 4885*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_WARN, dip, 4886*7c478bd9Sstevel@tonic-gate "!Suspend of device (%s%d) failed.", 4887*7c478bd9Sstevel@tonic-gate ddi_driver_name(cdip), 4888*7c478bd9Sstevel@tonic-gate ddi_get_instance(cdip))); 4889*7c478bd9Sstevel@tonic-gate failed_pip = pip; 4890*7c478bd9Sstevel@tonic-gate break; 4891*7c478bd9Sstevel@tonic-gate } 4892*7c478bd9Sstevel@tonic-gate } else { 4893*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 4894*7c478bd9Sstevel@tonic-gate } 4895*7c478bd9Sstevel@tonic-gate pip = next; 4896*7c478bd9Sstevel@tonic-gate } 4897*7c478bd9Sstevel@tonic-gate 4898*7c478bd9Sstevel@tonic-gate if (rv == DDI_SUCCESS) { 4899*7c478bd9Sstevel@tonic-gate /* 4900*7c478bd9Sstevel@tonic-gate * Suspend of client devices is complete. Proceed 4901*7c478bd9Sstevel@tonic-gate * with pHCI suspend. 4902*7c478bd9Sstevel@tonic-gate */ 4903*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_SUSPEND(ph); 4904*7c478bd9Sstevel@tonic-gate } else { 4905*7c478bd9Sstevel@tonic-gate /* 4906*7c478bd9Sstevel@tonic-gate * Revert back all the suspended client device states 4907*7c478bd9Sstevel@tonic-gate * to converse. 4908*7c478bd9Sstevel@tonic-gate */ 4909*7c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 4910*7c478bd9Sstevel@tonic-gate while (pip != failed_pip) { 4911*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 4912*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 4913*7c478bd9Sstevel@tonic-gate next = 4914*7c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 4915*7c478bd9Sstevel@tonic-gate ct = MDI_PI(pip)->pi_client; 4916*7c478bd9Sstevel@tonic-gate i_mdi_client_lock(ct, pip); 4917*7c478bd9Sstevel@tonic-gate cdip = ct->ct_dip; 4918*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 4919*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_SUSPENDED(ct)) { 4920*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 4921*7c478bd9Sstevel@tonic-gate (void) devi_attach(cdip, DDI_RESUME); 4922*7c478bd9Sstevel@tonic-gate } else { 4923*7c478bd9Sstevel@tonic-gate i_mdi_client_unlock(ct); 4924*7c478bd9Sstevel@tonic-gate } 4925*7c478bd9Sstevel@tonic-gate pip = next; 4926*7c478bd9Sstevel@tonic-gate } 4927*7c478bd9Sstevel@tonic-gate } 4928*7c478bd9Sstevel@tonic-gate break; 4929*7c478bd9Sstevel@tonic-gate 4930*7c478bd9Sstevel@tonic-gate default: 4931*7c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 4932*7c478bd9Sstevel@tonic-gate break; 4933*7c478bd9Sstevel@tonic-gate } 4934*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 4935*7c478bd9Sstevel@tonic-gate return (rv); 4936*7c478bd9Sstevel@tonic-gate } 4937*7c478bd9Sstevel@tonic-gate 4938*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4939*7c478bd9Sstevel@tonic-gate static int 4940*7c478bd9Sstevel@tonic-gate i_mdi_client_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4941*7c478bd9Sstevel@tonic-gate { 4942*7c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 4943*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 4944*7c478bd9Sstevel@tonic-gate 4945*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 4946*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 4947*7c478bd9Sstevel@tonic-gate return (rv); 4948*7c478bd9Sstevel@tonic-gate } 4949*7c478bd9Sstevel@tonic-gate 4950*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 4951*7c478bd9Sstevel@tonic-gate switch (cmd) { 4952*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 4953*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4954*7c478bd9Sstevel@tonic-gate "!Client pre_detach: called %p\n", ct)); 4955*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_DETACH(ct); 4956*7c478bd9Sstevel@tonic-gate break; 4957*7c478bd9Sstevel@tonic-gate 4958*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 4959*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 4960*7c478bd9Sstevel@tonic-gate "!Client pre_suspend: called %p\n", ct)); 4961*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_SUSPEND(ct); 4962*7c478bd9Sstevel@tonic-gate break; 4963*7c478bd9Sstevel@tonic-gate 4964*7c478bd9Sstevel@tonic-gate default: 4965*7c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 4966*7c478bd9Sstevel@tonic-gate break; 4967*7c478bd9Sstevel@tonic-gate } 4968*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 4969*7c478bd9Sstevel@tonic-gate return (rv); 4970*7c478bd9Sstevel@tonic-gate } 4971*7c478bd9Sstevel@tonic-gate 4972*7c478bd9Sstevel@tonic-gate /* 4973*7c478bd9Sstevel@tonic-gate * mdi_post_detach(): 4974*7c478bd9Sstevel@tonic-gate * Post detach notification handler 4975*7c478bd9Sstevel@tonic-gate */ 4976*7c478bd9Sstevel@tonic-gate 4977*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4978*7c478bd9Sstevel@tonic-gate void 4979*7c478bd9Sstevel@tonic-gate mdi_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 4980*7c478bd9Sstevel@tonic-gate { 4981*7c478bd9Sstevel@tonic-gate /* 4982*7c478bd9Sstevel@tonic-gate * Detach/Suspend of mpxio component failed. Update our state 4983*7c478bd9Sstevel@tonic-gate * too 4984*7c478bd9Sstevel@tonic-gate */ 4985*7c478bd9Sstevel@tonic-gate if (MDI_PHCI(dip)) 4986*7c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dip, cmd, error); 4987*7c478bd9Sstevel@tonic-gate 4988*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT(dip)) 4989*7c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dip, cmd, error); 4990*7c478bd9Sstevel@tonic-gate } 4991*7c478bd9Sstevel@tonic-gate 4992*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4993*7c478bd9Sstevel@tonic-gate static void 4994*7c478bd9Sstevel@tonic-gate i_mdi_phci_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 4995*7c478bd9Sstevel@tonic-gate { 4996*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 4997*7c478bd9Sstevel@tonic-gate 4998*7c478bd9Sstevel@tonic-gate /* 4999*7c478bd9Sstevel@tonic-gate * Detach/Suspend of phci component failed. Update our state 5000*7c478bd9Sstevel@tonic-gate * too 5001*7c478bd9Sstevel@tonic-gate */ 5002*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 5003*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 5004*7c478bd9Sstevel@tonic-gate return; 5005*7c478bd9Sstevel@tonic-gate } 5006*7c478bd9Sstevel@tonic-gate 5007*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 5008*7c478bd9Sstevel@tonic-gate /* 5009*7c478bd9Sstevel@tonic-gate * Detach of pHCI failed. Restore back converse 5010*7c478bd9Sstevel@tonic-gate * state 5011*7c478bd9Sstevel@tonic-gate */ 5012*7c478bd9Sstevel@tonic-gate switch (cmd) { 5013*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 5014*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 5015*7c478bd9Sstevel@tonic-gate "!pHCI post_detach: called %p\n", ph)); 5016*7c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 5017*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_ATTACH(ph); 5018*7c478bd9Sstevel@tonic-gate break; 5019*7c478bd9Sstevel@tonic-gate 5020*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 5021*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 5022*7c478bd9Sstevel@tonic-gate "!pHCI post_suspend: called %p\n", ph)); 5023*7c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 5024*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_RESUME(ph); 5025*7c478bd9Sstevel@tonic-gate break; 5026*7c478bd9Sstevel@tonic-gate } 5027*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 5028*7c478bd9Sstevel@tonic-gate } 5029*7c478bd9Sstevel@tonic-gate 5030*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5031*7c478bd9Sstevel@tonic-gate static void 5032*7c478bd9Sstevel@tonic-gate i_mdi_client_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error) 5033*7c478bd9Sstevel@tonic-gate { 5034*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 5035*7c478bd9Sstevel@tonic-gate 5036*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 5037*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 5038*7c478bd9Sstevel@tonic-gate return; 5039*7c478bd9Sstevel@tonic-gate } 5040*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 5041*7c478bd9Sstevel@tonic-gate /* 5042*7c478bd9Sstevel@tonic-gate * Detach of Client failed. Restore back converse 5043*7c478bd9Sstevel@tonic-gate * state 5044*7c478bd9Sstevel@tonic-gate */ 5045*7c478bd9Sstevel@tonic-gate switch (cmd) { 5046*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 5047*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 5048*7c478bd9Sstevel@tonic-gate "!Client post_detach: called %p\n", ct)); 5049*7c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 5050*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 5051*7c478bd9Sstevel@tonic-gate "i_mdi_pm_rele_client\n")); 5052*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 5053*7c478bd9Sstevel@tonic-gate } else { 5054*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, dip, "i_mdi_client_post_detach " 5055*7c478bd9Sstevel@tonic-gate "i_mdi_pm_reset_client\n")); 5056*7c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 5057*7c478bd9Sstevel@tonic-gate } 5058*7c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 5059*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_ATTACH(ct); 5060*7c478bd9Sstevel@tonic-gate break; 5061*7c478bd9Sstevel@tonic-gate 5062*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 5063*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, dip, 5064*7c478bd9Sstevel@tonic-gate "!Client post_suspend: called %p\n", ct)); 5065*7c478bd9Sstevel@tonic-gate if (error != DDI_SUCCESS) 5066*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_RESUME(ct); 5067*7c478bd9Sstevel@tonic-gate break; 5068*7c478bd9Sstevel@tonic-gate } 5069*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5070*7c478bd9Sstevel@tonic-gate } 5071*7c478bd9Sstevel@tonic-gate 5072*7c478bd9Sstevel@tonic-gate /* 5073*7c478bd9Sstevel@tonic-gate * create and install per-path (client - pHCI) statistics 5074*7c478bd9Sstevel@tonic-gate * I/O stats supported: nread, nwritten, reads, and writes 5075*7c478bd9Sstevel@tonic-gate * Error stats - hard errors, soft errors, & transport errors 5076*7c478bd9Sstevel@tonic-gate */ 5077*7c478bd9Sstevel@tonic-gate static int 5078*7c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_create(mdi_pathinfo_t *pip) 5079*7c478bd9Sstevel@tonic-gate { 5080*7c478bd9Sstevel@tonic-gate 5081*7c478bd9Sstevel@tonic-gate dev_info_t *client = MDI_PI(pip)->pi_client->ct_dip; 5082*7c478bd9Sstevel@tonic-gate dev_info_t *ppath = MDI_PI(pip)->pi_phci->ph_dip; 5083*7c478bd9Sstevel@tonic-gate char ksname[KSTAT_STRLEN]; 5084*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *cpip; 5085*7c478bd9Sstevel@tonic-gate const char *err_postfix = ",err"; 5086*7c478bd9Sstevel@tonic-gate kstat_t *kiosp, *kerrsp; 5087*7c478bd9Sstevel@tonic-gate struct pi_errs *nsp; 5088*7c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 5089*7c478bd9Sstevel@tonic-gate 5090*7c478bd9Sstevel@tonic-gate ASSERT(client != NULL && ppath != NULL); 5091*7c478bd9Sstevel@tonic-gate 5092*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&(MDI_PI(pip)->pi_client->ct_mutex))); 5093*7c478bd9Sstevel@tonic-gate 5094*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_kstats != NULL) 5095*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5096*7c478bd9Sstevel@tonic-gate 5097*7c478bd9Sstevel@tonic-gate for (cpip = MDI_PI(pip)->pi_client->ct_path_head; cpip != NULL; 5098*7c478bd9Sstevel@tonic-gate cpip = (mdi_pathinfo_t *)(MDI_PI(cpip)->pi_client_link)) { 5099*7c478bd9Sstevel@tonic-gate if (cpip == pip) 5100*7c478bd9Sstevel@tonic-gate continue; 5101*7c478bd9Sstevel@tonic-gate /* 5102*7c478bd9Sstevel@tonic-gate * We have found a different path with same parent 5103*7c478bd9Sstevel@tonic-gate * kstats for a given client-pHCI are common 5104*7c478bd9Sstevel@tonic-gate */ 5105*7c478bd9Sstevel@tonic-gate if ((MDI_PI(cpip)->pi_phci->ph_dip == ppath) && 5106*7c478bd9Sstevel@tonic-gate (MDI_PI(cpip)->pi_kstats != NULL)) { 5107*7c478bd9Sstevel@tonic-gate MDI_PI(cpip)->pi_kstats->pi_kstat_ref++; 5108*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = MDI_PI(cpip)->pi_kstats; 5109*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5110*7c478bd9Sstevel@tonic-gate } 5111*7c478bd9Sstevel@tonic-gate } 5112*7c478bd9Sstevel@tonic-gate 5113*7c478bd9Sstevel@tonic-gate /* 5114*7c478bd9Sstevel@tonic-gate * stats are named as follows: TGTx.HBAy, e.g. "ssd0.fp0" 5115*7c478bd9Sstevel@tonic-gate * clamp length of name against max length of error kstat name 5116*7c478bd9Sstevel@tonic-gate */ 5117*7c478bd9Sstevel@tonic-gate if (snprintf(ksname, KSTAT_STRLEN, "%s%d.%s%d", 5118*7c478bd9Sstevel@tonic-gate ddi_driver_name(client), ddi_get_instance(client), 5119*7c478bd9Sstevel@tonic-gate ddi_driver_name(ppath), ddi_get_instance(ppath)) > 5120*7c478bd9Sstevel@tonic-gate (KSTAT_STRLEN - strlen(err_postfix))) { 5121*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5122*7c478bd9Sstevel@tonic-gate } 5123*7c478bd9Sstevel@tonic-gate if ((kiosp = kstat_create("mdi", 0, ksname, "iopath", 5124*7c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, 0)) == NULL) { 5125*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5126*7c478bd9Sstevel@tonic-gate } 5127*7c478bd9Sstevel@tonic-gate 5128*7c478bd9Sstevel@tonic-gate (void) strcat(ksname, err_postfix); 5129*7c478bd9Sstevel@tonic-gate kerrsp = kstat_create("mdi", 0, ksname, "iopath_errors", 5130*7c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, 5131*7c478bd9Sstevel@tonic-gate sizeof (struct pi_errs) / sizeof (kstat_named_t), 0); 5132*7c478bd9Sstevel@tonic-gate 5133*7c478bd9Sstevel@tonic-gate if (kerrsp == NULL) { 5134*7c478bd9Sstevel@tonic-gate kstat_delete(kiosp); 5135*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5136*7c478bd9Sstevel@tonic-gate } 5137*7c478bd9Sstevel@tonic-gate 5138*7c478bd9Sstevel@tonic-gate nsp = (struct pi_errs *)kerrsp->ks_data; 5139*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_softerrs, "Soft Errors", KSTAT_DATA_UINT32); 5140*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_harderrs, "Hard Errors", KSTAT_DATA_UINT32); 5141*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_transerrs, "Transport Errors", 5142*7c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 5143*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_busy, "Interconnect Busy", 5144*7c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 5145*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_icnt_errors, "Interconnect Errors", 5146*7c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 5147*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_rsrc, "pHCI No Resources", 5148*7c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 5149*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_localerr, "pHCI Local Errors", 5150*7c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 5151*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_phci_invstate, "pHCI Invalid State", 5152*7c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 5153*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedfrom, "Failed From", 5154*7c478bd9Sstevel@tonic-gate KSTAT_DATA_UINT32); 5155*7c478bd9Sstevel@tonic-gate kstat_named_init(&nsp->pi_failedto, "Failed To", KSTAT_DATA_UINT32); 5156*7c478bd9Sstevel@tonic-gate 5157*7c478bd9Sstevel@tonic-gate mdi_statp = kmem_alloc(sizeof (*mdi_statp), KM_SLEEP); 5158*7c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_ref = 1; 5159*7c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_iostats = kiosp; 5160*7c478bd9Sstevel@tonic-gate mdi_statp->pi_kstat_errstats = kerrsp; 5161*7c478bd9Sstevel@tonic-gate kstat_install(kiosp); 5162*7c478bd9Sstevel@tonic-gate kstat_install(kerrsp); 5163*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = mdi_statp; 5164*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5165*7c478bd9Sstevel@tonic-gate } 5166*7c478bd9Sstevel@tonic-gate 5167*7c478bd9Sstevel@tonic-gate /* 5168*7c478bd9Sstevel@tonic-gate * destroy per-path properties 5169*7c478bd9Sstevel@tonic-gate */ 5170*7c478bd9Sstevel@tonic-gate static void 5171*7c478bd9Sstevel@tonic-gate i_mdi_pi_kstat_destroy(mdi_pathinfo_t *pip) 5172*7c478bd9Sstevel@tonic-gate { 5173*7c478bd9Sstevel@tonic-gate 5174*7c478bd9Sstevel@tonic-gate struct mdi_pi_kstats *mdi_statp; 5175*7c478bd9Sstevel@tonic-gate 5176*7c478bd9Sstevel@tonic-gate if ((mdi_statp = MDI_PI(pip)->pi_kstats) == NULL) 5177*7c478bd9Sstevel@tonic-gate return; 5178*7c478bd9Sstevel@tonic-gate 5179*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_kstats = NULL; 5180*7c478bd9Sstevel@tonic-gate 5181*7c478bd9Sstevel@tonic-gate /* 5182*7c478bd9Sstevel@tonic-gate * the kstat may be shared between multiple pathinfo nodes 5183*7c478bd9Sstevel@tonic-gate * decrement this pathinfo's usage, removing the kstats 5184*7c478bd9Sstevel@tonic-gate * themselves when the last pathinfo reference is removed. 5185*7c478bd9Sstevel@tonic-gate */ 5186*7c478bd9Sstevel@tonic-gate ASSERT(mdi_statp->pi_kstat_ref > 0); 5187*7c478bd9Sstevel@tonic-gate if (--mdi_statp->pi_kstat_ref != 0) 5188*7c478bd9Sstevel@tonic-gate return; 5189*7c478bd9Sstevel@tonic-gate 5190*7c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_iostats); 5191*7c478bd9Sstevel@tonic-gate kstat_delete(mdi_statp->pi_kstat_errstats); 5192*7c478bd9Sstevel@tonic-gate kmem_free(mdi_statp, sizeof (*mdi_statp)); 5193*7c478bd9Sstevel@tonic-gate } 5194*7c478bd9Sstevel@tonic-gate 5195*7c478bd9Sstevel@tonic-gate /* 5196*7c478bd9Sstevel@tonic-gate * update I/O paths KSTATS 5197*7c478bd9Sstevel@tonic-gate */ 5198*7c478bd9Sstevel@tonic-gate void 5199*7c478bd9Sstevel@tonic-gate mdi_pi_kstat_iosupdate(mdi_pathinfo_t *pip, struct buf *bp) 5200*7c478bd9Sstevel@tonic-gate { 5201*7c478bd9Sstevel@tonic-gate kstat_t *iostatp; 5202*7c478bd9Sstevel@tonic-gate size_t xfer_cnt; 5203*7c478bd9Sstevel@tonic-gate 5204*7c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 5205*7c478bd9Sstevel@tonic-gate 5206*7c478bd9Sstevel@tonic-gate /* 5207*7c478bd9Sstevel@tonic-gate * I/O can be driven across a path prior to having path 5208*7c478bd9Sstevel@tonic-gate * statistics available, i.e. probe(9e). 5209*7c478bd9Sstevel@tonic-gate */ 5210*7c478bd9Sstevel@tonic-gate if (bp != NULL && MDI_PI(pip)->pi_kstats != NULL) { 5211*7c478bd9Sstevel@tonic-gate iostatp = MDI_PI(pip)->pi_kstats->pi_kstat_iostats; 5212*7c478bd9Sstevel@tonic-gate xfer_cnt = bp->b_bcount - bp->b_resid; 5213*7c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 5214*7c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->reads++; 5215*7c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nread += xfer_cnt; 5216*7c478bd9Sstevel@tonic-gate } else { 5217*7c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->writes++; 5218*7c478bd9Sstevel@tonic-gate KSTAT_IO_PTR(iostatp)->nwritten += xfer_cnt; 5219*7c478bd9Sstevel@tonic-gate } 5220*7c478bd9Sstevel@tonic-gate } 5221*7c478bd9Sstevel@tonic-gate } 5222*7c478bd9Sstevel@tonic-gate 5223*7c478bd9Sstevel@tonic-gate /* 5224*7c478bd9Sstevel@tonic-gate * disable the path to a particular pHCI (pHCI specified in the phci_path 5225*7c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 5226*7c478bd9Sstevel@tonic-gate * Disabling a path means that MPxIO will not select the disabled path for 5227*7c478bd9Sstevel@tonic-gate * routing any new I/O requests. 5228*7c478bd9Sstevel@tonic-gate */ 5229*7c478bd9Sstevel@tonic-gate int 5230*7c478bd9Sstevel@tonic-gate mdi_pi_disable(dev_info_t *cdip, dev_info_t *pdip, int flags) 5231*7c478bd9Sstevel@tonic-gate { 5232*7c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_DISABLE_OP)); 5233*7c478bd9Sstevel@tonic-gate } 5234*7c478bd9Sstevel@tonic-gate 5235*7c478bd9Sstevel@tonic-gate /* 5236*7c478bd9Sstevel@tonic-gate * Enable the path to a particular pHCI (pHCI specified in the phci_path 5237*7c478bd9Sstevel@tonic-gate * argument) for a particular client (specified in the client_path argument). 5238*7c478bd9Sstevel@tonic-gate * Enabling a path means that MPxIO may select the enabled path for routing 5239*7c478bd9Sstevel@tonic-gate * future I/O requests, subject to other path state constraints. 5240*7c478bd9Sstevel@tonic-gate */ 5241*7c478bd9Sstevel@tonic-gate 5242*7c478bd9Sstevel@tonic-gate int 5243*7c478bd9Sstevel@tonic-gate mdi_pi_enable(dev_info_t *cdip, dev_info_t *pdip, int flags) 5244*7c478bd9Sstevel@tonic-gate { 5245*7c478bd9Sstevel@tonic-gate return (i_mdi_pi_enable_disable(cdip, pdip, flags, MDI_ENABLE_OP)); 5246*7c478bd9Sstevel@tonic-gate } 5247*7c478bd9Sstevel@tonic-gate 5248*7c478bd9Sstevel@tonic-gate 5249*7c478bd9Sstevel@tonic-gate /* 5250*7c478bd9Sstevel@tonic-gate * Common routine for doing enable/disable. 5251*7c478bd9Sstevel@tonic-gate */ 5252*7c478bd9Sstevel@tonic-gate int 5253*7c478bd9Sstevel@tonic-gate i_mdi_pi_enable_disable(dev_info_t *cdip, dev_info_t *pdip, int flags, int op) 5254*7c478bd9Sstevel@tonic-gate { 5255*7c478bd9Sstevel@tonic-gate 5256*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 5257*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh = NULL; 5258*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 5259*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *next, *pip; 5260*7c478bd9Sstevel@tonic-gate int found_it; 5261*7c478bd9Sstevel@tonic-gate int (*f)() = NULL; 5262*7c478bd9Sstevel@tonic-gate int rv; 5263*7c478bd9Sstevel@tonic-gate int sync_flag = 0; 5264*7c478bd9Sstevel@tonic-gate 5265*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(pdip); 5266*7c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5267*7c478bd9Sstevel@tonic-gate " Operation = %d pdip = %p cdip = %p\n", op, pdip, cdip)); 5268*7c478bd9Sstevel@tonic-gate if (ph == NULL) { 5269*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5270*7c478bd9Sstevel@tonic-gate " failed. ph = NULL operation = %d\n", op)); 5271*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5272*7c478bd9Sstevel@tonic-gate } 5273*7c478bd9Sstevel@tonic-gate 5274*7c478bd9Sstevel@tonic-gate if ((op != MDI_ENABLE_OP) && (op != MDI_DISABLE_OP)) { 5275*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5276*7c478bd9Sstevel@tonic-gate " Invalid operation = %d\n", op)); 5277*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5278*7c478bd9Sstevel@tonic-gate } 5279*7c478bd9Sstevel@tonic-gate 5280*7c478bd9Sstevel@tonic-gate sync_flag = (flags << 8) & 0xf00; 5281*7c478bd9Sstevel@tonic-gate 5282*7c478bd9Sstevel@tonic-gate vh = ph->ph_vhci; 5283*7c478bd9Sstevel@tonic-gate f = vh->vh_ops->vo_pi_state_change; 5284*7c478bd9Sstevel@tonic-gate 5285*7c478bd9Sstevel@tonic-gate if (cdip == NULL) { 5286*7c478bd9Sstevel@tonic-gate /* 5287*7c478bd9Sstevel@tonic-gate * Need to mark the Phci as enabled/disabled. 5288*7c478bd9Sstevel@tonic-gate */ 5289*7c478bd9Sstevel@tonic-gate MDI_DEBUG(3, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5290*7c478bd9Sstevel@tonic-gate "Operation %d for the phci\n", op)); 5291*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 5292*7c478bd9Sstevel@tonic-gate switch (flags) { 5293*7c478bd9Sstevel@tonic-gate case USER_DISABLE: 5294*7c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 5295*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_DISABLE(ph); 5296*7c478bd9Sstevel@tonic-gate else 5297*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_USER_ENABLE(ph); 5298*7c478bd9Sstevel@tonic-gate break; 5299*7c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 5300*7c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 5301*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE(ph); 5302*7c478bd9Sstevel@tonic-gate else 5303*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE(ph); 5304*7c478bd9Sstevel@tonic-gate break; 5305*7c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 5306*7c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 5307*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_DISABLE_TRANSIENT(ph); 5308*7c478bd9Sstevel@tonic-gate else 5309*7c478bd9Sstevel@tonic-gate MDI_PHCI_SET_DRV_ENABLE_TRANSIENT(ph); 5310*7c478bd9Sstevel@tonic-gate break; 5311*7c478bd9Sstevel@tonic-gate default: 5312*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 5313*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 5314*7c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 5315*7c478bd9Sstevel@tonic-gate " Invalid flag argument= %d\n", flags)); 5316*7c478bd9Sstevel@tonic-gate } 5317*7c478bd9Sstevel@tonic-gate 5318*7c478bd9Sstevel@tonic-gate /* 5319*7c478bd9Sstevel@tonic-gate * Phci has been disabled. Now try to enable/disable 5320*7c478bd9Sstevel@tonic-gate * path info's to each client. 5321*7c478bd9Sstevel@tonic-gate */ 5322*7c478bd9Sstevel@tonic-gate pip = ph->ph_path_head; 5323*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 5324*7c478bd9Sstevel@tonic-gate /* 5325*7c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 5326*7c478bd9Sstevel@tonic-gate * know that path is about to be enabled/disabled. 5327*7c478bd9Sstevel@tonic-gate */ 5328*7c478bd9Sstevel@tonic-gate if (f != NULL) { 5329*7c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 5330*7c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 5331*7c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 5332*7c478bd9Sstevel@tonic-gate op | MDI_BEFORE_STATE_CHANGE); 5333*7c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 5334*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 5335*7c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 5336*7c478bd9Sstevel@tonic-gate } 5337*7c478bd9Sstevel@tonic-gate } 5338*7c478bd9Sstevel@tonic-gate 5339*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 5340*7c478bd9Sstevel@tonic-gate next = 5341*7c478bd9Sstevel@tonic-gate (mdi_pathinfo_t *)MDI_PI(pip)->pi_phci_link; 5342*7c478bd9Sstevel@tonic-gate switch (flags) { 5343*7c478bd9Sstevel@tonic-gate case USER_DISABLE: 5344*7c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 5345*7c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 5346*7c478bd9Sstevel@tonic-gate else 5347*7c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_ENABLE(pip); 5348*7c478bd9Sstevel@tonic-gate break; 5349*7c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 5350*7c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 5351*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 5352*7c478bd9Sstevel@tonic-gate else 5353*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE(pip); 5354*7c478bd9Sstevel@tonic-gate break; 5355*7c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 5356*7c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) 5357*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 5358*7c478bd9Sstevel@tonic-gate else 5359*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE_TRANS(pip); 5360*7c478bd9Sstevel@tonic-gate break; 5361*7c478bd9Sstevel@tonic-gate } 5362*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5363*7c478bd9Sstevel@tonic-gate /* 5364*7c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 5365*7c478bd9Sstevel@tonic-gate * know that path is now enabled/disabled. 5366*7c478bd9Sstevel@tonic-gate */ 5367*7c478bd9Sstevel@tonic-gate if (f != NULL) { 5368*7c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 5369*7c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 5370*7c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 5371*7c478bd9Sstevel@tonic-gate op | MDI_AFTER_STATE_CHANGE); 5372*7c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 5373*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 5374*7c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 5375*7c478bd9Sstevel@tonic-gate } 5376*7c478bd9Sstevel@tonic-gate } 5377*7c478bd9Sstevel@tonic-gate pip = next; 5378*7c478bd9Sstevel@tonic-gate } 5379*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 5380*7c478bd9Sstevel@tonic-gate } else { 5381*7c478bd9Sstevel@tonic-gate 5382*7c478bd9Sstevel@tonic-gate /* 5383*7c478bd9Sstevel@tonic-gate * Disable a specific client. 5384*7c478bd9Sstevel@tonic-gate */ 5385*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 5386*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 5387*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 5388*7c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 5389*7c478bd9Sstevel@tonic-gate " failed. ct = NULL operation = %d\n", op)); 5390*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5391*7c478bd9Sstevel@tonic-gate } 5392*7c478bd9Sstevel@tonic-gate 5393*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 5394*7c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 5395*7c478bd9Sstevel@tonic-gate found_it = 0; 5396*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 5397*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 5398*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 5399*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_phci == ph) { 5400*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5401*7c478bd9Sstevel@tonic-gate found_it = 1; 5402*7c478bd9Sstevel@tonic-gate break; 5403*7c478bd9Sstevel@tonic-gate } 5404*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5405*7c478bd9Sstevel@tonic-gate pip = next; 5406*7c478bd9Sstevel@tonic-gate } 5407*7c478bd9Sstevel@tonic-gate 5408*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5409*7c478bd9Sstevel@tonic-gate if (found_it == 0) { 5410*7c478bd9Sstevel@tonic-gate MDI_DEBUG(1, (CE_NOTE, NULL, 5411*7c478bd9Sstevel@tonic-gate "!i_mdi_pi_enable_disable:" 5412*7c478bd9Sstevel@tonic-gate " failed. Could not find corresponding pip\n")); 5413*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5414*7c478bd9Sstevel@tonic-gate } 5415*7c478bd9Sstevel@tonic-gate /* 5416*7c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 5417*7c478bd9Sstevel@tonic-gate * know that path is about to get enabled/disabled. 5418*7c478bd9Sstevel@tonic-gate */ 5419*7c478bd9Sstevel@tonic-gate if (f != NULL) { 5420*7c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 5421*7c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 5422*7c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 5423*7c478bd9Sstevel@tonic-gate op | MDI_BEFORE_STATE_CHANGE); 5424*7c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 5425*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 5426*7c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 5427*7c478bd9Sstevel@tonic-gate } 5428*7c478bd9Sstevel@tonic-gate } 5429*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 5430*7c478bd9Sstevel@tonic-gate switch (flags) { 5431*7c478bd9Sstevel@tonic-gate case USER_DISABLE: 5432*7c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 5433*7c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_DISABLE(pip); 5434*7c478bd9Sstevel@tonic-gate else 5435*7c478bd9Sstevel@tonic-gate MDI_PI_SET_USER_ENABLE(pip); 5436*7c478bd9Sstevel@tonic-gate break; 5437*7c478bd9Sstevel@tonic-gate case DRIVER_DISABLE: 5438*7c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP) 5439*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE(pip); 5440*7c478bd9Sstevel@tonic-gate else 5441*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE(pip); 5442*7c478bd9Sstevel@tonic-gate break; 5443*7c478bd9Sstevel@tonic-gate case DRIVER_DISABLE_TRANSIENT: 5444*7c478bd9Sstevel@tonic-gate if (op == MDI_DISABLE_OP && rv == MDI_SUCCESS) 5445*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_DISABLE_TRANS(pip); 5446*7c478bd9Sstevel@tonic-gate else 5447*7c478bd9Sstevel@tonic-gate MDI_PI_SET_DRV_ENABLE_TRANS(pip); 5448*7c478bd9Sstevel@tonic-gate break; 5449*7c478bd9Sstevel@tonic-gate } 5450*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5451*7c478bd9Sstevel@tonic-gate /* 5452*7c478bd9Sstevel@tonic-gate * Do a callback into the mdi consumer to let it 5453*7c478bd9Sstevel@tonic-gate * know that path is now enabled/disabled. 5454*7c478bd9Sstevel@tonic-gate */ 5455*7c478bd9Sstevel@tonic-gate if (f != NULL) { 5456*7c478bd9Sstevel@tonic-gate rv = (*f)(vh->vh_dip, pip, 0, 5457*7c478bd9Sstevel@tonic-gate MDI_PI_EXT_STATE(pip), 5458*7c478bd9Sstevel@tonic-gate MDI_EXT_STATE_CHANGE | sync_flag | 5459*7c478bd9Sstevel@tonic-gate op | MDI_AFTER_STATE_CHANGE); 5460*7c478bd9Sstevel@tonic-gate if (rv != MDI_SUCCESS) { 5461*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_WARN, vh->vh_dip, 5462*7c478bd9Sstevel@tonic-gate "!vo_pi_state_change: failed rv = %x", rv)); 5463*7c478bd9Sstevel@tonic-gate } 5464*7c478bd9Sstevel@tonic-gate } 5465*7c478bd9Sstevel@tonic-gate } 5466*7c478bd9Sstevel@tonic-gate 5467*7c478bd9Sstevel@tonic-gate MDI_DEBUG(5, (CE_NOTE, NULL, "!i_mdi_pi_enable_disable:" 5468*7c478bd9Sstevel@tonic-gate " Returning success pdip = %p cdip = %p\n", op, pdip, cdip)); 5469*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5470*7c478bd9Sstevel@tonic-gate } 5471*7c478bd9Sstevel@tonic-gate 5472*7c478bd9Sstevel@tonic-gate /*ARGSUSED3*/ 5473*7c478bd9Sstevel@tonic-gate int 5474*7c478bd9Sstevel@tonic-gate mdi_devi_config_one(dev_info_t *pdip, char *devnm, dev_info_t **cdipp, 5475*7c478bd9Sstevel@tonic-gate int flags, clock_t timeout) 5476*7c478bd9Sstevel@tonic-gate { 5477*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 5478*7c478bd9Sstevel@tonic-gate dev_info_t *dip; 5479*7c478bd9Sstevel@tonic-gate clock_t interval = drv_usectohz(100000); /* 0.1 sec */ 5480*7c478bd9Sstevel@tonic-gate char *paddr; 5481*7c478bd9Sstevel@tonic-gate 5482*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, NULL, "configure device %s", devnm)); 5483*7c478bd9Sstevel@tonic-gate 5484*7c478bd9Sstevel@tonic-gate if (!MDI_PHCI(pdip)) 5485*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5486*7c478bd9Sstevel@tonic-gate 5487*7c478bd9Sstevel@tonic-gate paddr = strchr(devnm, '@'); 5488*7c478bd9Sstevel@tonic-gate if (paddr == NULL) 5489*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5490*7c478bd9Sstevel@tonic-gate 5491*7c478bd9Sstevel@tonic-gate paddr++; /* skip '@' */ 5492*7c478bd9Sstevel@tonic-gate pip = mdi_pi_find(pdip, NULL, paddr); 5493*7c478bd9Sstevel@tonic-gate while (pip == NULL && timeout > 0) { 5494*7c478bd9Sstevel@tonic-gate if (interval > timeout) 5495*7c478bd9Sstevel@tonic-gate interval = timeout; 5496*7c478bd9Sstevel@tonic-gate if (flags & NDI_DEVI_DEBUG) { 5497*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: %s timeout %ld %ld\n", 5498*7c478bd9Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip), 5499*7c478bd9Sstevel@tonic-gate paddr, interval, timeout); 5500*7c478bd9Sstevel@tonic-gate } 5501*7c478bd9Sstevel@tonic-gate delay(interval); 5502*7c478bd9Sstevel@tonic-gate timeout -= interval; 5503*7c478bd9Sstevel@tonic-gate interval += interval; 5504*7c478bd9Sstevel@tonic-gate pip = mdi_pi_find(pdip, NULL, paddr); 5505*7c478bd9Sstevel@tonic-gate } 5506*7c478bd9Sstevel@tonic-gate 5507*7c478bd9Sstevel@tonic-gate if (pip == NULL) 5508*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5509*7c478bd9Sstevel@tonic-gate dip = mdi_pi_get_client(pip); 5510*7c478bd9Sstevel@tonic-gate if (ndi_devi_online(dip, flags) != NDI_SUCCESS) 5511*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5512*7c478bd9Sstevel@tonic-gate *cdipp = dip; 5513*7c478bd9Sstevel@tonic-gate 5514*7c478bd9Sstevel@tonic-gate /* TODO: holding should happen inside search functions */ 5515*7c478bd9Sstevel@tonic-gate ndi_hold_devi(dip); 5516*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5517*7c478bd9Sstevel@tonic-gate } 5518*7c478bd9Sstevel@tonic-gate 5519*7c478bd9Sstevel@tonic-gate /* 5520*7c478bd9Sstevel@tonic-gate * Ensure phci powered up 5521*7c478bd9Sstevel@tonic-gate */ 5522*7c478bd9Sstevel@tonic-gate static void 5523*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(mdi_pathinfo_t *pip) 5524*7c478bd9Sstevel@tonic-gate { 5525*7c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 5526*7c478bd9Sstevel@tonic-gate 5527*7c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 5528*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 5529*7c478bd9Sstevel@tonic-gate 5530*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held) { 5531*7c478bd9Sstevel@tonic-gate return; 5532*7c478bd9Sstevel@tonic-gate } 5533*7c478bd9Sstevel@tonic-gate 5534*7c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 5535*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_hold_pip for %s%d\n", 5536*7c478bd9Sstevel@tonic-gate ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 5537*7c478bd9Sstevel@tonic-gate if (ph_dip == NULL) { 5538*7c478bd9Sstevel@tonic-gate return; 5539*7c478bd9Sstevel@tonic-gate } 5540*7c478bd9Sstevel@tonic-gate 5541*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5542*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 5543*7c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 5544*7c478bd9Sstevel@tonic-gate pm_hold_power(ph_dip); 5545*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 5546*7c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 5547*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 5548*7c478bd9Sstevel@tonic-gate 5549*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 1; 5550*7c478bd9Sstevel@tonic-gate } 5551*7c478bd9Sstevel@tonic-gate 5552*7c478bd9Sstevel@tonic-gate /* 5553*7c478bd9Sstevel@tonic-gate * Allow phci powered down 5554*7c478bd9Sstevel@tonic-gate */ 5555*7c478bd9Sstevel@tonic-gate static void 5556*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(mdi_pathinfo_t *pip) 5557*7c478bd9Sstevel@tonic-gate { 5558*7c478bd9Sstevel@tonic-gate dev_info_t *ph_dip = NULL; 5559*7c478bd9Sstevel@tonic-gate 5560*7c478bd9Sstevel@tonic-gate ASSERT(pip != NULL); 5561*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&MDI_PI(pip)->pi_mutex)); 5562*7c478bd9Sstevel@tonic-gate 5563*7c478bd9Sstevel@tonic-gate if (MDI_PI(pip)->pi_pm_held == 0) { 5564*7c478bd9Sstevel@tonic-gate return; 5565*7c478bd9Sstevel@tonic-gate } 5566*7c478bd9Sstevel@tonic-gate 5567*7c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 5568*7c478bd9Sstevel@tonic-gate ASSERT(ph_dip != NULL); 5569*7c478bd9Sstevel@tonic-gate 5570*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5571*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_pm_rele_pip for %s%d\n", 5572*7c478bd9Sstevel@tonic-gate ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 5573*7c478bd9Sstevel@tonic-gate 5574*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt was %d\n", 5575*7c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 5576*7c478bd9Sstevel@tonic-gate pm_rele_power(ph_dip); 5577*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "kidsupcnt is %d\n", 5578*7c478bd9Sstevel@tonic-gate DEVI(ph_dip)->devi_pm_kidsupcnt)); 5579*7c478bd9Sstevel@tonic-gate 5580*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 5581*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_pm_held = 0; 5582*7c478bd9Sstevel@tonic-gate } 5583*7c478bd9Sstevel@tonic-gate 5584*7c478bd9Sstevel@tonic-gate static void 5585*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(mdi_client_t *ct, int incr) 5586*7c478bd9Sstevel@tonic-gate { 5587*7c478bd9Sstevel@tonic-gate ASSERT(ct); 5588*7c478bd9Sstevel@tonic-gate 5589*7c478bd9Sstevel@tonic-gate ct->ct_power_cnt += incr; 5590*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_hold_client " 5591*7c478bd9Sstevel@tonic-gate "ct_power_cnt = %d incr = %d\n", ct->ct_power_cnt, incr)); 5592*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 5593*7c478bd9Sstevel@tonic-gate } 5594*7c478bd9Sstevel@tonic-gate 5595*7c478bd9Sstevel@tonic-gate static void 5596*7c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(mdi_client_t *ct) 5597*7c478bd9Sstevel@tonic-gate { 5598*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 5599*7c478bd9Sstevel@tonic-gate 5600*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ct->ct_mutex)); 5601*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 5602*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 5603*7c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 5604*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 5605*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 5606*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5607*7c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 5608*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 5609*7c478bd9Sstevel@tonic-gate } 5610*7c478bd9Sstevel@tonic-gate } 5611*7c478bd9Sstevel@tonic-gate 5612*7c478bd9Sstevel@tonic-gate static void 5613*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(mdi_client_t *ct, int decr) 5614*7c478bd9Sstevel@tonic-gate { 5615*7c478bd9Sstevel@tonic-gate ASSERT(ct); 5616*7c478bd9Sstevel@tonic-gate 5617*7c478bd9Sstevel@tonic-gate if (i_ddi_node_state(ct->ct_dip) >= DS_READY) { 5618*7c478bd9Sstevel@tonic-gate ct->ct_power_cnt -= decr; 5619*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_rele_client " 5620*7c478bd9Sstevel@tonic-gate "ct_power_cnt = %d decr = %d\n", ct->ct_power_cnt, decr)); 5621*7c478bd9Sstevel@tonic-gate } 5622*7c478bd9Sstevel@tonic-gate 5623*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_power_cnt >= 0); 5624*7c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 5625*7c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 5626*7c478bd9Sstevel@tonic-gate return; 5627*7c478bd9Sstevel@tonic-gate } 5628*7c478bd9Sstevel@tonic-gate } 5629*7c478bd9Sstevel@tonic-gate 5630*7c478bd9Sstevel@tonic-gate static void 5631*7c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(mdi_client_t *ct) 5632*7c478bd9Sstevel@tonic-gate { 5633*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ct->ct_dip, "i_mdi_pm_reset_client " 5634*7c478bd9Sstevel@tonic-gate "ct_power_cnt = %d\n", ct->ct_power_cnt)); 5635*7c478bd9Sstevel@tonic-gate ct->ct_power_cnt = 0; 5636*7c478bd9Sstevel@tonic-gate i_mdi_rele_all_phci(ct); 5637*7c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 1; 5638*7c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 0; 5639*7c478bd9Sstevel@tonic-gate } 5640*7c478bd9Sstevel@tonic-gate 5641*7c478bd9Sstevel@tonic-gate static void 5642*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_all_phci(mdi_client_t *ct) 5643*7c478bd9Sstevel@tonic-gate { 5644*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 5645*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ct->ct_mutex)); 5646*7c478bd9Sstevel@tonic-gate 5647*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 5648*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 5649*7c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 5650*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 5651*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 5652*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5653*7c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 5654*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 5655*7c478bd9Sstevel@tonic-gate } 5656*7c478bd9Sstevel@tonic-gate } 5657*7c478bd9Sstevel@tonic-gate 5658*7c478bd9Sstevel@tonic-gate static int 5659*7c478bd9Sstevel@tonic-gate i_mdi_power_one_phci(mdi_pathinfo_t *pip) 5660*7c478bd9Sstevel@tonic-gate { 5661*7c478bd9Sstevel@tonic-gate int ret; 5662*7c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 5663*7c478bd9Sstevel@tonic-gate 5664*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 5665*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_pip(pip); 5666*7c478bd9Sstevel@tonic-gate 5667*7c478bd9Sstevel@tonic-gate ph_dip = mdi_pi_get_phci(pip); 5668*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5669*7c478bd9Sstevel@tonic-gate 5670*7c478bd9Sstevel@tonic-gate /* bring all components of phci to full power */ 5671*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 5672*7c478bd9Sstevel@tonic-gate "pm_powerup for %s%d\n", ddi_get_name(ph_dip), 5673*7c478bd9Sstevel@tonic-gate ddi_get_instance(ph_dip))); 5674*7c478bd9Sstevel@tonic-gate 5675*7c478bd9Sstevel@tonic-gate ret = pm_powerup(ph_dip); 5676*7c478bd9Sstevel@tonic-gate 5677*7c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 5678*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, ph_dip, "i_mdi_power_one_phci " 5679*7c478bd9Sstevel@tonic-gate "pm_powerup FAILED for %s%d\n", 5680*7c478bd9Sstevel@tonic-gate ddi_get_name(ph_dip), ddi_get_instance(ph_dip))); 5681*7c478bd9Sstevel@tonic-gate 5682*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 5683*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_pip(pip); 5684*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 5685*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5686*7c478bd9Sstevel@tonic-gate } 5687*7c478bd9Sstevel@tonic-gate 5688*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5689*7c478bd9Sstevel@tonic-gate } 5690*7c478bd9Sstevel@tonic-gate 5691*7c478bd9Sstevel@tonic-gate static int 5692*7c478bd9Sstevel@tonic-gate i_mdi_power_all_phci(mdi_client_t *ct) 5693*7c478bd9Sstevel@tonic-gate { 5694*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip; 5695*7c478bd9Sstevel@tonic-gate int succeeded = 0; 5696*7c478bd9Sstevel@tonic-gate 5697*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ct->ct_path_head; 5698*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 5699*7c478bd9Sstevel@tonic-gate mdi_hold_path(pip); 5700*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5701*7c478bd9Sstevel@tonic-gate if (i_mdi_power_one_phci(pip) == MDI_SUCCESS) 5702*7c478bd9Sstevel@tonic-gate succeeded = 1; 5703*7c478bd9Sstevel@tonic-gate 5704*7c478bd9Sstevel@tonic-gate ASSERT(ct == MDI_PI(pip)->pi_client); 5705*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 5706*7c478bd9Sstevel@tonic-gate mdi_rele_path(pip); 5707*7c478bd9Sstevel@tonic-gate pip = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 5708*7c478bd9Sstevel@tonic-gate } 5709*7c478bd9Sstevel@tonic-gate 5710*7c478bd9Sstevel@tonic-gate return (succeeded ? MDI_SUCCESS : MDI_FAILURE); 5711*7c478bd9Sstevel@tonic-gate } 5712*7c478bd9Sstevel@tonic-gate 5713*7c478bd9Sstevel@tonic-gate /* 5714*7c478bd9Sstevel@tonic-gate * mdi_bus_power(): 5715*7c478bd9Sstevel@tonic-gate * 1. Place the phci(s) into powered up state so that 5716*7c478bd9Sstevel@tonic-gate * client can do power management 5717*7c478bd9Sstevel@tonic-gate * 2. Ensure phci powered up as client power managing 5718*7c478bd9Sstevel@tonic-gate * Return Values: 5719*7c478bd9Sstevel@tonic-gate * MDI_SUCCESS 5720*7c478bd9Sstevel@tonic-gate * MDI_FAILURE 5721*7c478bd9Sstevel@tonic-gate */ 5722*7c478bd9Sstevel@tonic-gate int 5723*7c478bd9Sstevel@tonic-gate mdi_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op, 5724*7c478bd9Sstevel@tonic-gate void *arg, void *result) 5725*7c478bd9Sstevel@tonic-gate { 5726*7c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 5727*7c478bd9Sstevel@tonic-gate pm_bp_child_pwrchg_t *bpc; 5728*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 5729*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 5730*7c478bd9Sstevel@tonic-gate pm_bp_has_changed_t *bphc; 5731*7c478bd9Sstevel@tonic-gate 5732*7c478bd9Sstevel@tonic-gate /* 5733*7c478bd9Sstevel@tonic-gate * BUS_POWER_NOINVOL not supported 5734*7c478bd9Sstevel@tonic-gate */ 5735*7c478bd9Sstevel@tonic-gate if (op == BUS_POWER_NOINVOL) 5736*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5737*7c478bd9Sstevel@tonic-gate 5738*7c478bd9Sstevel@tonic-gate /* 5739*7c478bd9Sstevel@tonic-gate * ignore other OPs. 5740*7c478bd9Sstevel@tonic-gate * return quickly to save cou cycles on the ct processing 5741*7c478bd9Sstevel@tonic-gate */ 5742*7c478bd9Sstevel@tonic-gate switch (op) { 5743*7c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 5744*7c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 5745*7c478bd9Sstevel@tonic-gate bpc = (pm_bp_child_pwrchg_t *)arg; 5746*7c478bd9Sstevel@tonic-gate cdip = bpc->bpc_dip; 5747*7c478bd9Sstevel@tonic-gate break; 5748*7c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 5749*7c478bd9Sstevel@tonic-gate bphc = (pm_bp_has_changed_t *)arg; 5750*7c478bd9Sstevel@tonic-gate cdip = bphc->bphc_dip; 5751*7c478bd9Sstevel@tonic-gate break; 5752*7c478bd9Sstevel@tonic-gate default: 5753*7c478bd9Sstevel@tonic-gate return (pm_busop_bus_power(parent, impl_arg, op, arg, result)); 5754*7c478bd9Sstevel@tonic-gate } 5755*7c478bd9Sstevel@tonic-gate 5756*7c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(cdip)); 5757*7c478bd9Sstevel@tonic-gate 5758*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(cdip); 5759*7c478bd9Sstevel@tonic-gate if (ct == NULL) 5760*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5761*7c478bd9Sstevel@tonic-gate 5762*7c478bd9Sstevel@tonic-gate /* 5763*7c478bd9Sstevel@tonic-gate * wait till the mdi_pathinfo node state change are processed 5764*7c478bd9Sstevel@tonic-gate */ 5765*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 5766*7c478bd9Sstevel@tonic-gate switch (op) { 5767*7c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 5768*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 5769*7c478bd9Sstevel@tonic-gate "BUS_POWER_PRE_NOTIFICATION:" 5770*7c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 5771*7c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 5772*7c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp)); 5773*7c478bd9Sstevel@tonic-gate 5774*7c478bd9Sstevel@tonic-gate /* serialize power level change per client */ 5775*7c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 5776*7c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 5777*7c478bd9Sstevel@tonic-gate 5778*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_TRANSITION(ct); 5779*7c478bd9Sstevel@tonic-gate 5780*7c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 5781*7c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 5782*7c478bd9Sstevel@tonic-gate } 5783*7c478bd9Sstevel@tonic-gate 5784*7c478bd9Sstevel@tonic-gate /* 5785*7c478bd9Sstevel@tonic-gate * if new_level > 0: 5786*7c478bd9Sstevel@tonic-gate * - hold phci(s) 5787*7c478bd9Sstevel@tonic-gate * - power up phci(s) if not already 5788*7c478bd9Sstevel@tonic-gate * ignore power down 5789*7c478bd9Sstevel@tonic-gate */ 5790*7c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 5791*7c478bd9Sstevel@tonic-gate if (!DEVI_IS_ATTACHING(ct->ct_dip)) { 5792*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 5793*7c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 5794*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 5795*7c478bd9Sstevel@tonic-gate } 5796*7c478bd9Sstevel@tonic-gate } 5797*7c478bd9Sstevel@tonic-gate break; 5798*7c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 5799*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, "mdi_bus_power " 5800*7c478bd9Sstevel@tonic-gate "BUS_POWER_POST_NOTIFICATION:" 5801*7c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d result=%d\n", 5802*7c478bd9Sstevel@tonic-gate PM_NAME(bpc->bpc_dip), PM_ADDR(bpc->bpc_dip), 5803*7c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, bpc->bpc_comp, 5804*7c478bd9Sstevel@tonic-gate *(int *)result)); 5805*7c478bd9Sstevel@tonic-gate 5806*7c478bd9Sstevel@tonic-gate if (*(int *)result == DDI_SUCCESS) { 5807*7c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0) { 5808*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_UP(ct); 5809*7c478bd9Sstevel@tonic-gate } else { 5810*7c478bd9Sstevel@tonic-gate MDI_CLIENT_SET_POWER_DOWN(ct); 5811*7c478bd9Sstevel@tonic-gate } 5812*7c478bd9Sstevel@tonic-gate } 5813*7c478bd9Sstevel@tonic-gate 5814*7c478bd9Sstevel@tonic-gate /* release the hold we did in pre-notification */ 5815*7c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel > 0 && (*(int *)result != DDI_SUCCESS) && 5816*7c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) { 5817*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 5818*7c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 5819*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 5820*7c478bd9Sstevel@tonic-gate } 5821*7c478bd9Sstevel@tonic-gate 5822*7c478bd9Sstevel@tonic-gate if (bpc->bpc_nlevel == 0 && (*(int *)result == DDI_SUCCESS)) { 5823*7c478bd9Sstevel@tonic-gate /* another thread might started attaching */ 5824*7c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 5825*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 5826*7c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 5827*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 5828*7c478bd9Sstevel@tonic-gate /* detaching has been taken care in pm_post_unconfig */ 5829*7c478bd9Sstevel@tonic-gate } else if (!DEVI_IS_DETACHING(ct->ct_dip)) { 5830*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bpc->bpc_dip, 5831*7c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_reset_client\n")); 5832*7c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 5833*7c478bd9Sstevel@tonic-gate } 5834*7c478bd9Sstevel@tonic-gate } 5835*7c478bd9Sstevel@tonic-gate 5836*7c478bd9Sstevel@tonic-gate MDI_CLIENT_CLEAR_POWER_TRANSITION(ct); 5837*7c478bd9Sstevel@tonic-gate cv_broadcast(&ct->ct_powerchange_cv); 5838*7c478bd9Sstevel@tonic-gate 5839*7c478bd9Sstevel@tonic-gate break; 5840*7c478bd9Sstevel@tonic-gate 5841*7c478bd9Sstevel@tonic-gate /* need to do more */ 5842*7c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 5843*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, "mdi_bus_power " 5844*7c478bd9Sstevel@tonic-gate "BUS_POWER_HAS_CHANGED:" 5845*7c478bd9Sstevel@tonic-gate "%s@%s, olevel=%d, nlevel=%d, comp=%d\n", 5846*7c478bd9Sstevel@tonic-gate PM_NAME(bphc->bphc_dip), PM_ADDR(bphc->bphc_dip), 5847*7c478bd9Sstevel@tonic-gate bphc->bphc_olevel, bphc->bphc_nlevel, bphc->bphc_comp)); 5848*7c478bd9Sstevel@tonic-gate 5849*7c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel > 0 && 5850*7c478bd9Sstevel@tonic-gate bphc->bphc_nlevel > bphc->bphc_olevel) { 5851*7c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 5852*7c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 5853*7c478bd9Sstevel@tonic-gate } 5854*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 5855*7c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_hold_client\n")); 5856*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 5857*7c478bd9Sstevel@tonic-gate } 5858*7c478bd9Sstevel@tonic-gate 5859*7c478bd9Sstevel@tonic-gate if (bphc->bphc_nlevel == 0 && bphc->bphc_olevel != -1) { 5860*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, bphc->bphc_dip, 5861*7c478bd9Sstevel@tonic-gate "mdi_bus_power i_mdi_pm_rele_client\n")); 5862*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 5863*7c478bd9Sstevel@tonic-gate } 5864*7c478bd9Sstevel@tonic-gate break; 5865*7c478bd9Sstevel@tonic-gate } 5866*7c478bd9Sstevel@tonic-gate 5867*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5868*7c478bd9Sstevel@tonic-gate return (ret); 5869*7c478bd9Sstevel@tonic-gate } 5870*7c478bd9Sstevel@tonic-gate 5871*7c478bd9Sstevel@tonic-gate static int 5872*7c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config_one(dev_info_t *child) 5873*7c478bd9Sstevel@tonic-gate { 5874*7c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 5875*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 5876*7c478bd9Sstevel@tonic-gate 5877*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 5878*7c478bd9Sstevel@tonic-gate if (ct == NULL) 5879*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5880*7c478bd9Sstevel@tonic-gate 5881*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 5882*7c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 5883*7c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 5884*7c478bd9Sstevel@tonic-gate 5885*7c478bd9Sstevel@tonic-gate if (!MDI_CLIENT_IS_FAILED(ct)) { 5886*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5887*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 5888*7c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one already configured\n")); 5889*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5890*7c478bd9Sstevel@tonic-gate } 5891*7c478bd9Sstevel@tonic-gate 5892*7c478bd9Sstevel@tonic-gate if (ct->ct_powercnt_held) { 5893*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5894*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 5895*7c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one ALREADY held\n")); 5896*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5897*7c478bd9Sstevel@tonic-gate } 5898*7c478bd9Sstevel@tonic-gate 5899*7c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 5900*7c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 5901*7c478bd9Sstevel@tonic-gate } 5902*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 5903*7c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_config_one i_mdi_pm_hold_client\n")); 5904*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 5905*7c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 1; 5906*7c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 5907*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5908*7c478bd9Sstevel@tonic-gate return (ret); 5909*7c478bd9Sstevel@tonic-gate } 5910*7c478bd9Sstevel@tonic-gate 5911*7c478bd9Sstevel@tonic-gate static int 5912*7c478bd9Sstevel@tonic-gate i_mdi_pm_pre_config(dev_info_t *parent, dev_info_t *child) 5913*7c478bd9Sstevel@tonic-gate { 5914*7c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 5915*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 5916*7c478bd9Sstevel@tonic-gate int circ; 5917*7c478bd9Sstevel@tonic-gate 5918*7c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 5919*7c478bd9Sstevel@tonic-gate 5920*7c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 5921*7c478bd9Sstevel@tonic-gate if (child) { 5922*7c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_config_one(child)); 5923*7c478bd9Sstevel@tonic-gate } 5924*7c478bd9Sstevel@tonic-gate 5925*7c478bd9Sstevel@tonic-gate /* devi_config_common */ 5926*7c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 5927*7c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 5928*7c478bd9Sstevel@tonic-gate while (cdip) { 5929*7c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 5930*7c478bd9Sstevel@tonic-gate 5931*7c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config_one(cdip); 5932*7c478bd9Sstevel@tonic-gate if (ret != MDI_SUCCESS) 5933*7c478bd9Sstevel@tonic-gate break; 5934*7c478bd9Sstevel@tonic-gate cdip = next; 5935*7c478bd9Sstevel@tonic-gate } 5936*7c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 5937*7c478bd9Sstevel@tonic-gate return (ret); 5938*7c478bd9Sstevel@tonic-gate } 5939*7c478bd9Sstevel@tonic-gate 5940*7c478bd9Sstevel@tonic-gate static int 5941*7c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig_one(dev_info_t *child, int *held, int flags) 5942*7c478bd9Sstevel@tonic-gate { 5943*7c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 5944*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 5945*7c478bd9Sstevel@tonic-gate 5946*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 5947*7c478bd9Sstevel@tonic-gate if (ct == NULL) 5948*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5949*7c478bd9Sstevel@tonic-gate 5950*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 5951*7c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 5952*7c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 5953*7c478bd9Sstevel@tonic-gate 5954*7c478bd9Sstevel@tonic-gate if (i_ddi_node_state(ct->ct_dip) < DS_READY) { 5955*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 5956*7c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig node detached already\n")); 5957*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5958*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5959*7c478bd9Sstevel@tonic-gate } 5960*7c478bd9Sstevel@tonic-gate 5961*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_POWERED_DOWN(ct) && 5962*7c478bd9Sstevel@tonic-gate (flags & NDI_AUTODETACH)) { 5963*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 5964*7c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig auto-modunload\n")); 5965*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5966*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 5967*7c478bd9Sstevel@tonic-gate } 5968*7c478bd9Sstevel@tonic-gate 5969*7c478bd9Sstevel@tonic-gate if (ct->ct_powercnt_held) { 5970*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 5971*7c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig ct_powercnt_held\n")); 5972*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5973*7c478bd9Sstevel@tonic-gate *held = 1; 5974*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 5975*7c478bd9Sstevel@tonic-gate } 5976*7c478bd9Sstevel@tonic-gate 5977*7c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 5978*7c478bd9Sstevel@tonic-gate ret = i_mdi_power_all_phci(ct); 5979*7c478bd9Sstevel@tonic-gate } 5980*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 5981*7c478bd9Sstevel@tonic-gate "i_mdi_pm_pre_unconfig i_mdi_pm_hold_client\n")); 5982*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 5983*7c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 1; 5984*7c478bd9Sstevel@tonic-gate ct->ct_powercnt_reset = 0; 5985*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 5986*7c478bd9Sstevel@tonic-gate if (ret == MDI_SUCCESS) 5987*7c478bd9Sstevel@tonic-gate *held = 1; 5988*7c478bd9Sstevel@tonic-gate return (ret); 5989*7c478bd9Sstevel@tonic-gate } 5990*7c478bd9Sstevel@tonic-gate 5991*7c478bd9Sstevel@tonic-gate static int 5992*7c478bd9Sstevel@tonic-gate i_mdi_pm_pre_unconfig(dev_info_t *parent, dev_info_t *child, int *held, 5993*7c478bd9Sstevel@tonic-gate int flags) 5994*7c478bd9Sstevel@tonic-gate { 5995*7c478bd9Sstevel@tonic-gate int ret = MDI_SUCCESS; 5996*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 5997*7c478bd9Sstevel@tonic-gate int circ; 5998*7c478bd9Sstevel@tonic-gate 5999*7c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 6000*7c478bd9Sstevel@tonic-gate *held = 0; 6001*7c478bd9Sstevel@tonic-gate 6002*7c478bd9Sstevel@tonic-gate /* ndi_devi_unconfig_one */ 6003*7c478bd9Sstevel@tonic-gate if (child) { 6004*7c478bd9Sstevel@tonic-gate return (i_mdi_pm_pre_unconfig_one(child, held, flags)); 6005*7c478bd9Sstevel@tonic-gate } 6006*7c478bd9Sstevel@tonic-gate 6007*7c478bd9Sstevel@tonic-gate /* devi_unconfig_common */ 6008*7c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 6009*7c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 6010*7c478bd9Sstevel@tonic-gate while (cdip) { 6011*7c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 6012*7c478bd9Sstevel@tonic-gate 6013*7c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig_one(cdip, held, flags); 6014*7c478bd9Sstevel@tonic-gate cdip = next; 6015*7c478bd9Sstevel@tonic-gate } 6016*7c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 6017*7c478bd9Sstevel@tonic-gate 6018*7c478bd9Sstevel@tonic-gate if (*held) 6019*7c478bd9Sstevel@tonic-gate ret = MDI_SUCCESS; 6020*7c478bd9Sstevel@tonic-gate 6021*7c478bd9Sstevel@tonic-gate return (ret); 6022*7c478bd9Sstevel@tonic-gate } 6023*7c478bd9Sstevel@tonic-gate 6024*7c478bd9Sstevel@tonic-gate static void 6025*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(dev_info_t *child) 6026*7c478bd9Sstevel@tonic-gate { 6027*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 6028*7c478bd9Sstevel@tonic-gate 6029*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 6030*7c478bd9Sstevel@tonic-gate if (ct == NULL) 6031*7c478bd9Sstevel@tonic-gate return; 6032*7c478bd9Sstevel@tonic-gate 6033*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 6034*7c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 6035*7c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 6036*7c478bd9Sstevel@tonic-gate 6037*7c478bd9Sstevel@tonic-gate if (ct->ct_powercnt_reset || !ct->ct_powercnt_held) { 6038*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 6039*7c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config_one NOT held\n")); 6040*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 6041*7c478bd9Sstevel@tonic-gate return; 6042*7c478bd9Sstevel@tonic-gate } 6043*7c478bd9Sstevel@tonic-gate 6044*7c478bd9Sstevel@tonic-gate /* client has not been updated */ 6045*7c478bd9Sstevel@tonic-gate if (MDI_CLIENT_IS_FAILED(ct)) { 6046*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 6047*7c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config_one NOT configured\n")); 6048*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 6049*7c478bd9Sstevel@tonic-gate return; 6050*7c478bd9Sstevel@tonic-gate } 6051*7c478bd9Sstevel@tonic-gate 6052*7c478bd9Sstevel@tonic-gate /* another thread might have powered it down or detached it */ 6053*7c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 6054*7c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip)) || 6055*7c478bd9Sstevel@tonic-gate (i_ddi_node_state(ct->ct_dip) < DS_READY && 6056*7c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 6057*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 6058*7c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_reset_client\n")); 6059*7c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 6060*7c478bd9Sstevel@tonic-gate } else { 6061*7c478bd9Sstevel@tonic-gate mdi_pathinfo_t *pip, *next; 6062*7c478bd9Sstevel@tonic-gate int valid_path_count = 0; 6063*7c478bd9Sstevel@tonic-gate 6064*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 6065*7c478bd9Sstevel@tonic-gate "i_mdi_pm_post_config i_mdi_pm_rele_client\n")); 6066*7c478bd9Sstevel@tonic-gate pip = ct->ct_path_head; 6067*7c478bd9Sstevel@tonic-gate while (pip != NULL) { 6068*7c478bd9Sstevel@tonic-gate MDI_PI_LOCK(pip); 6069*7c478bd9Sstevel@tonic-gate next = (mdi_pathinfo_t *)MDI_PI(pip)->pi_client_link; 6070*7c478bd9Sstevel@tonic-gate if ((MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 6071*7c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_ONLINE || 6072*7c478bd9Sstevel@tonic-gate (MDI_PI(pip)->pi_state & MDI_PATHINFO_STATE_MASK) 6073*7c478bd9Sstevel@tonic-gate == MDI_PATHINFO_STATE_STANDBY) 6074*7c478bd9Sstevel@tonic-gate valid_path_count ++; 6075*7c478bd9Sstevel@tonic-gate MDI_PI_UNLOCK(pip); 6076*7c478bd9Sstevel@tonic-gate pip = next; 6077*7c478bd9Sstevel@tonic-gate } 6078*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, valid_path_count); 6079*7c478bd9Sstevel@tonic-gate } 6080*7c478bd9Sstevel@tonic-gate ct->ct_powercnt_held = 0; 6081*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 6082*7c478bd9Sstevel@tonic-gate } 6083*7c478bd9Sstevel@tonic-gate 6084*7c478bd9Sstevel@tonic-gate static void 6085*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(dev_info_t *parent, dev_info_t *child) 6086*7c478bd9Sstevel@tonic-gate { 6087*7c478bd9Sstevel@tonic-gate int circ; 6088*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 6089*7c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 6090*7c478bd9Sstevel@tonic-gate 6091*7c478bd9Sstevel@tonic-gate /* ndi_devi_config_one */ 6092*7c478bd9Sstevel@tonic-gate if (child) { 6093*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(child); 6094*7c478bd9Sstevel@tonic-gate return; 6095*7c478bd9Sstevel@tonic-gate } 6096*7c478bd9Sstevel@tonic-gate 6097*7c478bd9Sstevel@tonic-gate /* devi_config_common */ 6098*7c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 6099*7c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 6100*7c478bd9Sstevel@tonic-gate while (cdip) { 6101*7c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 6102*7c478bd9Sstevel@tonic-gate 6103*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_config_one(cdip); 6104*7c478bd9Sstevel@tonic-gate cdip = next; 6105*7c478bd9Sstevel@tonic-gate } 6106*7c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 6107*7c478bd9Sstevel@tonic-gate } 6108*7c478bd9Sstevel@tonic-gate 6109*7c478bd9Sstevel@tonic-gate static void 6110*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(dev_info_t *child) 6111*7c478bd9Sstevel@tonic-gate { 6112*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 6113*7c478bd9Sstevel@tonic-gate 6114*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(child); 6115*7c478bd9Sstevel@tonic-gate if (ct == NULL) 6116*7c478bd9Sstevel@tonic-gate return; 6117*7c478bd9Sstevel@tonic-gate 6118*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 6119*7c478bd9Sstevel@tonic-gate while (MDI_CLIENT_IS_POWER_TRANSITION(ct)) 6120*7c478bd9Sstevel@tonic-gate cv_wait(&ct->ct_powerchange_cv, &ct->ct_mutex); 6121*7c478bd9Sstevel@tonic-gate 6122*7c478bd9Sstevel@tonic-gate if (!ct->ct_powercnt_held) { 6123*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 6124*7c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig NOT held\n")); 6125*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 6126*7c478bd9Sstevel@tonic-gate return; 6127*7c478bd9Sstevel@tonic-gate } 6128*7c478bd9Sstevel@tonic-gate 6129*7c478bd9Sstevel@tonic-gate /* failure detaching or another thread just attached it */ 6130*7c478bd9Sstevel@tonic-gate if ((MDI_CLIENT_IS_POWERED_DOWN(ct) && 6131*7c478bd9Sstevel@tonic-gate i_ddi_node_state(ct->ct_dip) == DS_READY) || 6132*7c478bd9Sstevel@tonic-gate (i_ddi_node_state(ct->ct_dip) != DS_READY && 6133*7c478bd9Sstevel@tonic-gate !DEVI_IS_ATTACHING(ct->ct_dip))) { 6134*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 6135*7c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig i_mdi_pm_reset_client\n")); 6136*7c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 6137*7c478bd9Sstevel@tonic-gate } 6138*7c478bd9Sstevel@tonic-gate 6139*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, child, 6140*7c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig not changed\n")); 6141*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 6142*7c478bd9Sstevel@tonic-gate } 6143*7c478bd9Sstevel@tonic-gate 6144*7c478bd9Sstevel@tonic-gate static void 6145*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(dev_info_t *parent, dev_info_t *child, int held) 6146*7c478bd9Sstevel@tonic-gate { 6147*7c478bd9Sstevel@tonic-gate int circ; 6148*7c478bd9Sstevel@tonic-gate dev_info_t *cdip; 6149*7c478bd9Sstevel@tonic-gate 6150*7c478bd9Sstevel@tonic-gate ASSERT(MDI_VHCI(parent)); 6151*7c478bd9Sstevel@tonic-gate 6152*7c478bd9Sstevel@tonic-gate if (!held) { 6153*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, parent, 6154*7c478bd9Sstevel@tonic-gate "i_mdi_pm_post_unconfig held = %d\n", held)); 6155*7c478bd9Sstevel@tonic-gate return; 6156*7c478bd9Sstevel@tonic-gate } 6157*7c478bd9Sstevel@tonic-gate 6158*7c478bd9Sstevel@tonic-gate if (child) { 6159*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(child); 6160*7c478bd9Sstevel@tonic-gate return; 6161*7c478bd9Sstevel@tonic-gate } 6162*7c478bd9Sstevel@tonic-gate 6163*7c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 6164*7c478bd9Sstevel@tonic-gate cdip = ddi_get_child(parent); 6165*7c478bd9Sstevel@tonic-gate while (cdip) { 6166*7c478bd9Sstevel@tonic-gate dev_info_t *next = ddi_get_next_sibling(cdip); 6167*7c478bd9Sstevel@tonic-gate 6168*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig_one(cdip); 6169*7c478bd9Sstevel@tonic-gate cdip = next; 6170*7c478bd9Sstevel@tonic-gate } 6171*7c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 6172*7c478bd9Sstevel@tonic-gate } 6173*7c478bd9Sstevel@tonic-gate 6174*7c478bd9Sstevel@tonic-gate int 6175*7c478bd9Sstevel@tonic-gate mdi_power(dev_info_t *vdip, mdi_pm_op_t op, void *args, char *devnm, int flags) 6176*7c478bd9Sstevel@tonic-gate { 6177*7c478bd9Sstevel@tonic-gate int circ, ret = MDI_SUCCESS; 6178*7c478bd9Sstevel@tonic-gate dev_info_t *client_dip = NULL; 6179*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 6180*7c478bd9Sstevel@tonic-gate 6181*7c478bd9Sstevel@tonic-gate /* 6182*7c478bd9Sstevel@tonic-gate * Handling ndi_devi_config_one and ndi_devi_unconfig_one. 6183*7c478bd9Sstevel@tonic-gate * Power up pHCI for the named client device. 6184*7c478bd9Sstevel@tonic-gate * Note: Before the client is enumerated under vhci by phci, 6185*7c478bd9Sstevel@tonic-gate * client_dip can be NULL. Then proceed to power up all the 6186*7c478bd9Sstevel@tonic-gate * pHCIs. 6187*7c478bd9Sstevel@tonic-gate */ 6188*7c478bd9Sstevel@tonic-gate if (devnm != NULL) { 6189*7c478bd9Sstevel@tonic-gate ndi_devi_enter(vdip, &circ); 6190*7c478bd9Sstevel@tonic-gate client_dip = ndi_devi_findchild(vdip, devnm); 6191*7c478bd9Sstevel@tonic-gate ndi_devi_exit(vdip, circ); 6192*7c478bd9Sstevel@tonic-gate } 6193*7c478bd9Sstevel@tonic-gate 6194*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, vdip, "mdi_power op = %d\n", op)); 6195*7c478bd9Sstevel@tonic-gate 6196*7c478bd9Sstevel@tonic-gate switch (op) { 6197*7c478bd9Sstevel@tonic-gate case MDI_PM_PRE_CONFIG: 6198*7c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_config(vdip, client_dip); 6199*7c478bd9Sstevel@tonic-gate 6200*7c478bd9Sstevel@tonic-gate break; 6201*7c478bd9Sstevel@tonic-gate case MDI_PM_PRE_UNCONFIG: 6202*7c478bd9Sstevel@tonic-gate ret = i_mdi_pm_pre_unconfig(vdip, client_dip, (int *)args, 6203*7c478bd9Sstevel@tonic-gate flags); 6204*7c478bd9Sstevel@tonic-gate 6205*7c478bd9Sstevel@tonic-gate break; 6206*7c478bd9Sstevel@tonic-gate case MDI_PM_POST_CONFIG: 6207*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_config(vdip, client_dip); 6208*7c478bd9Sstevel@tonic-gate 6209*7c478bd9Sstevel@tonic-gate break; 6210*7c478bd9Sstevel@tonic-gate case MDI_PM_POST_UNCONFIG: 6211*7c478bd9Sstevel@tonic-gate i_mdi_pm_post_unconfig(vdip, client_dip, *(int *)args); 6212*7c478bd9Sstevel@tonic-gate 6213*7c478bd9Sstevel@tonic-gate break; 6214*7c478bd9Sstevel@tonic-gate case MDI_PM_HOLD_POWER: 6215*7c478bd9Sstevel@tonic-gate case MDI_PM_RELE_POWER: 6216*7c478bd9Sstevel@tonic-gate ASSERT(args); 6217*7c478bd9Sstevel@tonic-gate 6218*7c478bd9Sstevel@tonic-gate client_dip = (dev_info_t *)args; 6219*7c478bd9Sstevel@tonic-gate ASSERT(MDI_CLIENT(client_dip)); 6220*7c478bd9Sstevel@tonic-gate 6221*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(client_dip); 6222*7c478bd9Sstevel@tonic-gate MDI_CLIENT_LOCK(ct); 6223*7c478bd9Sstevel@tonic-gate 6224*7c478bd9Sstevel@tonic-gate if (op == MDI_PM_HOLD_POWER) { 6225*7c478bd9Sstevel@tonic-gate if (ct->ct_power_cnt == 0) { 6226*7c478bd9Sstevel@tonic-gate (void) i_mdi_power_all_phci(ct); 6227*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 6228*7c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_hold_client\n")); 6229*7c478bd9Sstevel@tonic-gate i_mdi_pm_hold_client(ct, ct->ct_path_count); 6230*7c478bd9Sstevel@tonic-gate } 6231*7c478bd9Sstevel@tonic-gate } else { 6232*7c478bd9Sstevel@tonic-gate if (DEVI_IS_ATTACHING(ct->ct_dip)) { 6233*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 6234*7c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_rele_client\n")); 6235*7c478bd9Sstevel@tonic-gate i_mdi_pm_rele_client(ct, ct->ct_path_count); 6236*7c478bd9Sstevel@tonic-gate } else { 6237*7c478bd9Sstevel@tonic-gate MDI_DEBUG(4, (CE_NOTE, client_dip, 6238*7c478bd9Sstevel@tonic-gate "mdi_power i_mdi_pm_reset_client\n")); 6239*7c478bd9Sstevel@tonic-gate i_mdi_pm_reset_client(ct); 6240*7c478bd9Sstevel@tonic-gate } 6241*7c478bd9Sstevel@tonic-gate } 6242*7c478bd9Sstevel@tonic-gate 6243*7c478bd9Sstevel@tonic-gate MDI_CLIENT_UNLOCK(ct); 6244*7c478bd9Sstevel@tonic-gate break; 6245*7c478bd9Sstevel@tonic-gate default: 6246*7c478bd9Sstevel@tonic-gate break; 6247*7c478bd9Sstevel@tonic-gate } 6248*7c478bd9Sstevel@tonic-gate 6249*7c478bd9Sstevel@tonic-gate return (ret); 6250*7c478bd9Sstevel@tonic-gate } 6251*7c478bd9Sstevel@tonic-gate 6252*7c478bd9Sstevel@tonic-gate int 6253*7c478bd9Sstevel@tonic-gate mdi_component_is_vhci(dev_info_t *dip, const char **mdi_class) 6254*7c478bd9Sstevel@tonic-gate { 6255*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vhci; 6256*7c478bd9Sstevel@tonic-gate 6257*7c478bd9Sstevel@tonic-gate if (!MDI_VHCI(dip)) 6258*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6259*7c478bd9Sstevel@tonic-gate 6260*7c478bd9Sstevel@tonic-gate if (mdi_class) { 6261*7c478bd9Sstevel@tonic-gate vhci = DEVI(dip)->devi_mdi_xhci; 6262*7c478bd9Sstevel@tonic-gate ASSERT(vhci); 6263*7c478bd9Sstevel@tonic-gate *mdi_class = vhci->vh_class; 6264*7c478bd9Sstevel@tonic-gate } 6265*7c478bd9Sstevel@tonic-gate 6266*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6267*7c478bd9Sstevel@tonic-gate } 6268*7c478bd9Sstevel@tonic-gate 6269*7c478bd9Sstevel@tonic-gate int 6270*7c478bd9Sstevel@tonic-gate mdi_component_is_phci(dev_info_t *dip, const char **mdi_class) 6271*7c478bd9Sstevel@tonic-gate { 6272*7c478bd9Sstevel@tonic-gate mdi_phci_t *phci; 6273*7c478bd9Sstevel@tonic-gate 6274*7c478bd9Sstevel@tonic-gate if (!MDI_PHCI(dip)) 6275*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6276*7c478bd9Sstevel@tonic-gate 6277*7c478bd9Sstevel@tonic-gate if (mdi_class) { 6278*7c478bd9Sstevel@tonic-gate phci = DEVI(dip)->devi_mdi_xhci; 6279*7c478bd9Sstevel@tonic-gate ASSERT(phci); 6280*7c478bd9Sstevel@tonic-gate *mdi_class = phci->ph_vhci->vh_class; 6281*7c478bd9Sstevel@tonic-gate } 6282*7c478bd9Sstevel@tonic-gate 6283*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6284*7c478bd9Sstevel@tonic-gate } 6285*7c478bd9Sstevel@tonic-gate 6286*7c478bd9Sstevel@tonic-gate int 6287*7c478bd9Sstevel@tonic-gate mdi_component_is_client(dev_info_t *dip, const char **mdi_class) 6288*7c478bd9Sstevel@tonic-gate { 6289*7c478bd9Sstevel@tonic-gate mdi_client_t *client; 6290*7c478bd9Sstevel@tonic-gate 6291*7c478bd9Sstevel@tonic-gate if (!MDI_CLIENT(dip)) 6292*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6293*7c478bd9Sstevel@tonic-gate 6294*7c478bd9Sstevel@tonic-gate if (mdi_class) { 6295*7c478bd9Sstevel@tonic-gate client = DEVI(dip)->devi_mdi_client; 6296*7c478bd9Sstevel@tonic-gate ASSERT(client); 6297*7c478bd9Sstevel@tonic-gate *mdi_class = client->ct_vhci->vh_class; 6298*7c478bd9Sstevel@tonic-gate } 6299*7c478bd9Sstevel@tonic-gate 6300*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6301*7c478bd9Sstevel@tonic-gate } 6302*7c478bd9Sstevel@tonic-gate 6303*7c478bd9Sstevel@tonic-gate /* 6304*7c478bd9Sstevel@tonic-gate * XXX This list should include all phci drivers needed during boot time 6305*7c478bd9Sstevel@tonic-gate * though it currently contains "fp" only. 6306*7c478bd9Sstevel@tonic-gate * Hopefully, the mechanism provided here will be replaced with a better 6307*7c478bd9Sstevel@tonic-gate * mechanism by vhci driven enumeration project. 6308*7c478bd9Sstevel@tonic-gate */ 6309*7c478bd9Sstevel@tonic-gate static char *phci_driver_list[] = { "fp" }; 6310*7c478bd9Sstevel@tonic-gate #define N_PHCI_DRIVERS (sizeof (phci_driver_list) / sizeof (char *)) 6311*7c478bd9Sstevel@tonic-gate 6312*7c478bd9Sstevel@tonic-gate static void 6313*7c478bd9Sstevel@tonic-gate i_mdi_attach_phci_drivers() 6314*7c478bd9Sstevel@tonic-gate { 6315*7c478bd9Sstevel@tonic-gate int i; 6316*7c478bd9Sstevel@tonic-gate major_t m; 6317*7c478bd9Sstevel@tonic-gate 6318*7c478bd9Sstevel@tonic-gate for (i = 0; i < N_PHCI_DRIVERS; i++) { 6319*7c478bd9Sstevel@tonic-gate m = ddi_name_to_major(phci_driver_list[i]); 6320*7c478bd9Sstevel@tonic-gate if (m != (major_t)-1) { 6321*7c478bd9Sstevel@tonic-gate if (ddi_hold_installed_driver(m) != NULL) 6322*7c478bd9Sstevel@tonic-gate ddi_rele_driver(m); 6323*7c478bd9Sstevel@tonic-gate } 6324*7c478bd9Sstevel@tonic-gate } 6325*7c478bd9Sstevel@tonic-gate } 6326*7c478bd9Sstevel@tonic-gate 6327*7c478bd9Sstevel@tonic-gate /* bus config the specified phci */ 6328*7c478bd9Sstevel@tonic-gate static void 6329*7c478bd9Sstevel@tonic-gate i_mdi_phci_bus_config(void *arg) 6330*7c478bd9Sstevel@tonic-gate { 6331*7c478bd9Sstevel@tonic-gate mdi_phci_config_t *phc = (mdi_phci_config_t *)arg; 6332*7c478bd9Sstevel@tonic-gate mdi_vhci_config_t *vhc; 6333*7c478bd9Sstevel@tonic-gate dev_info_t *ph_dip; 6334*7c478bd9Sstevel@tonic-gate int rv; 6335*7c478bd9Sstevel@tonic-gate 6336*7c478bd9Sstevel@tonic-gate ASSERT(phc); 6337*7c478bd9Sstevel@tonic-gate vhc = phc->phc_vhc; 6338*7c478bd9Sstevel@tonic-gate ASSERT(vhc->vhc_op == BUS_CONFIG_ALL || 6339*7c478bd9Sstevel@tonic-gate vhc->vhc_op == BUS_CONFIG_DRIVER); 6340*7c478bd9Sstevel@tonic-gate 6341*7c478bd9Sstevel@tonic-gate /* 6342*7c478bd9Sstevel@tonic-gate * Must have already held the phci parent in 6343*7c478bd9Sstevel@tonic-gate * i_mdi_bus_config_all_phcis(). 6344*7c478bd9Sstevel@tonic-gate * First configure the phci itself. 6345*7c478bd9Sstevel@tonic-gate */ 6346*7c478bd9Sstevel@tonic-gate rv = ndi_devi_config_one(phc->phc_parent_dip, phc->phc_devnm + 1, 6347*7c478bd9Sstevel@tonic-gate &ph_dip, vhc->vhc_flags); 6348*7c478bd9Sstevel@tonic-gate 6349*7c478bd9Sstevel@tonic-gate /* release the hold that i_mdi_bus_config_all_phcis() placed */ 6350*7c478bd9Sstevel@tonic-gate ndi_rele_devi(phc->phc_parent_dip); 6351*7c478bd9Sstevel@tonic-gate 6352*7c478bd9Sstevel@tonic-gate if (rv == NDI_SUCCESS) { 6353*7c478bd9Sstevel@tonic-gate /* now bus config the phci */ 6354*7c478bd9Sstevel@tonic-gate if (vhc->vhc_op == BUS_CONFIG_DRIVER) { 6355*7c478bd9Sstevel@tonic-gate (void) ndi_devi_config_driver(ph_dip, vhc->vhc_flags, 6356*7c478bd9Sstevel@tonic-gate vhc->vhc_major); 6357*7c478bd9Sstevel@tonic-gate } else 6358*7c478bd9Sstevel@tonic-gate (void) ndi_devi_config(ph_dip, vhc->vhc_flags); 6359*7c478bd9Sstevel@tonic-gate 6360*7c478bd9Sstevel@tonic-gate /* release the hold that ndi_devi_config_one() placed */ 6361*7c478bd9Sstevel@tonic-gate ndi_rele_devi(ph_dip); 6362*7c478bd9Sstevel@tonic-gate } 6363*7c478bd9Sstevel@tonic-gate } 6364*7c478bd9Sstevel@tonic-gate 6365*7c478bd9Sstevel@tonic-gate /* 6366*7c478bd9Sstevel@tonic-gate * Bus config all registered phcis associated with the vhci in parallel. 6367*7c478bd9Sstevel@tonic-gate * This process guarantees that the child nodes are enumerated under the vhci, 6368*7c478bd9Sstevel@tonic-gate * but not necessarily attached. 6369*7c478bd9Sstevel@tonic-gate * op must be BUS_CONFIG_DRIVER or BUS_CONFIG_ALL. 6370*7c478bd9Sstevel@tonic-gate */ 6371*7c478bd9Sstevel@tonic-gate static int 6372*7c478bd9Sstevel@tonic-gate i_mdi_bus_config_all_phcis(dev_info_t *vdip, uint_t flags, 6373*7c478bd9Sstevel@tonic-gate ddi_bus_config_op_t op, major_t maj, int optimize) 6374*7c478bd9Sstevel@tonic-gate { 6375*7c478bd9Sstevel@tonic-gate mdi_vhci_t *vh; 6376*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 6377*7c478bd9Sstevel@tonic-gate mdi_phci_config_t *phc; 6378*7c478bd9Sstevel@tonic-gate int64_t req_time; 6379*7c478bd9Sstevel@tonic-gate int phci_count, rv; 6380*7c478bd9Sstevel@tonic-gate static int first_time = 1; 6381*7c478bd9Sstevel@tonic-gate 6382*7c478bd9Sstevel@tonic-gate ASSERT(op == BUS_CONFIG_ALL || op == BUS_CONFIG_DRIVER); 6383*7c478bd9Sstevel@tonic-gate ASSERT(!DEVI_BUSY_OWNED(vdip)); 6384*7c478bd9Sstevel@tonic-gate 6385*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, 6386*7c478bd9Sstevel@tonic-gate "!MDI: %s on all phcis: major = %d, flags = 0x%x, optimize = %d\n", 6387*7c478bd9Sstevel@tonic-gate (op == BUS_CONFIG_DRIVER) ? "BUS_CONFIG_DRIVER" : "BUS_CONFIG_ALL", 6388*7c478bd9Sstevel@tonic-gate (int)maj, flags, optimize)); 6389*7c478bd9Sstevel@tonic-gate 6390*7c478bd9Sstevel@tonic-gate vh = i_devi_get_vhci(vdip); 6391*7c478bd9Sstevel@tonic-gate ASSERT(vh); 6392*7c478bd9Sstevel@tonic-gate 6393*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 6394*7c478bd9Sstevel@tonic-gate 6395*7c478bd9Sstevel@tonic-gate req_time = lbolt64; 6396*7c478bd9Sstevel@tonic-gate 6397*7c478bd9Sstevel@tonic-gate /* 6398*7c478bd9Sstevel@tonic-gate * Reduce unnecessary BUS_CONFIG_ALLs when opening stale 6399*7c478bd9Sstevel@tonic-gate * /dev/[r]dsk links. 6400*7c478bd9Sstevel@tonic-gate */ 6401*7c478bd9Sstevel@tonic-gate if (optimize && (req_time < vh->vh_bus_config.vhc_cutoff_time)) { 6402*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6403*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6404*7c478bd9Sstevel@tonic-gate } 6405*7c478bd9Sstevel@tonic-gate 6406*7c478bd9Sstevel@tonic-gate /* 6407*7c478bd9Sstevel@tonic-gate * To initiate bus configs on all phcis in parallel, create a taskq 6408*7c478bd9Sstevel@tonic-gate * with multiple threads. Since creation of a taskq is a heavy weight 6409*7c478bd9Sstevel@tonic-gate * operation, taskq is created once per vhci and destroyed only when 6410*7c478bd9Sstevel@tonic-gate * vhci unregisters with mdi. 6411*7c478bd9Sstevel@tonic-gate * 6412*7c478bd9Sstevel@tonic-gate * If multiple bus config requests arrive at a time, bus configs on 6413*7c478bd9Sstevel@tonic-gate * phcis are initiated on behalf of one of the requests. Other requests 6414*7c478bd9Sstevel@tonic-gate * wait until the bus configs on phcis is done. 6415*7c478bd9Sstevel@tonic-gate * 6416*7c478bd9Sstevel@tonic-gate * When a BUS_CONFIG_ALL on phcis completes, the following is done 6417*7c478bd9Sstevel@tonic-gate * to avoid more of unnecessary bus configs. 6418*7c478bd9Sstevel@tonic-gate * 6419*7c478bd9Sstevel@tonic-gate * o all BUS_CONFIG_ALL requests currently waiting with optimize 6420*7c478bd9Sstevel@tonic-gate * flag set are returned, i.e., no new BUS_CONFIG_ALL is initiated 6421*7c478bd9Sstevel@tonic-gate * on phcis on behalf of these requests. 6422*7c478bd9Sstevel@tonic-gate * 6423*7c478bd9Sstevel@tonic-gate * o all BUS_CONFIG_ALL or BUS_CONFIG_DRIVER requests currently 6424*7c478bd9Sstevel@tonic-gate * waiting but have arrived prior to initiating BUS_CONFIG_ALL on 6425*7c478bd9Sstevel@tonic-gate * phcis are also returned. 6426*7c478bd9Sstevel@tonic-gate * 6427*7c478bd9Sstevel@tonic-gate * In other cases a new BUS_CONFIG_ALL or BUS_CONFIG_DRIVER is 6428*7c478bd9Sstevel@tonic-gate * initiated on phcis on behalf of a new request. 6429*7c478bd9Sstevel@tonic-gate */ 6430*7c478bd9Sstevel@tonic-gate 6431*7c478bd9Sstevel@tonic-gate /* check if a bus config on phcis is in progress */ 6432*7c478bd9Sstevel@tonic-gate while (vh->vh_bus_config.vhc_start_time != 0) { 6433*7c478bd9Sstevel@tonic-gate ddi_bus_config_op_t current_op; 6434*7c478bd9Sstevel@tonic-gate int64_t start_time; 6435*7c478bd9Sstevel@tonic-gate 6436*7c478bd9Sstevel@tonic-gate current_op = vh->vh_bus_config.vhc_op; 6437*7c478bd9Sstevel@tonic-gate start_time = vh->vh_bus_config.vhc_start_time; 6438*7c478bd9Sstevel@tonic-gate 6439*7c478bd9Sstevel@tonic-gate /* wait until the current bus configs on phcis are done */ 6440*7c478bd9Sstevel@tonic-gate while (vh->vh_bus_config.vhc_start_time == start_time) 6441*7c478bd9Sstevel@tonic-gate cv_wait(&vh->vh_bus_config.vhc_cv, &mdi_mutex); 6442*7c478bd9Sstevel@tonic-gate 6443*7c478bd9Sstevel@tonic-gate if (current_op == BUS_CONFIG_ALL && 6444*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_cutoff_time > 0 && (optimize || 6445*7c478bd9Sstevel@tonic-gate req_time < start_time)) { 6446*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6447*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6448*7c478bd9Sstevel@tonic-gate } 6449*7c478bd9Sstevel@tonic-gate } 6450*7c478bd9Sstevel@tonic-gate 6451*7c478bd9Sstevel@tonic-gate /* 6452*7c478bd9Sstevel@tonic-gate * At this point we are single threaded until vh_bus_config.start_time 6453*7c478bd9Sstevel@tonic-gate * is reset to 0 at the end of this function. 6454*7c478bd9Sstevel@tonic-gate */ 6455*7c478bd9Sstevel@tonic-gate 6456*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_op = op; 6457*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_major = maj; 6458*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_flags = flags; 6459*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_start_time = lbolt64; 6460*7c478bd9Sstevel@tonic-gate 6461*7c478bd9Sstevel@tonic-gate if (first_time && strcmp(vh->vh_class, MDI_HCI_CLASS_SCSI) == 0) { 6462*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6463*7c478bd9Sstevel@tonic-gate i_mdi_attach_phci_drivers(); 6464*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 6465*7c478bd9Sstevel@tonic-gate first_time = 0; 6466*7c478bd9Sstevel@tonic-gate } 6467*7c478bd9Sstevel@tonic-gate 6468*7c478bd9Sstevel@tonic-gate ASSERT(vh->vh_phci_count >= 0); 6469*7c478bd9Sstevel@tonic-gate if (vh->vh_phci_count == 0) { 6470*7c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 6471*7c478bd9Sstevel@tonic-gate goto out1; 6472*7c478bd9Sstevel@tonic-gate } 6473*7c478bd9Sstevel@tonic-gate 6474*7c478bd9Sstevel@tonic-gate /* 6475*7c478bd9Sstevel@tonic-gate * Create a taskq to initiate bus configs in parallel on phcis. 6476*7c478bd9Sstevel@tonic-gate * Taskq allocation can be done in mdi_vhci_register() routine 6477*7c478bd9Sstevel@tonic-gate * instead of here. For most systems, doing it here on demand saves 6478*7c478bd9Sstevel@tonic-gate * resources as this code path is never called most of the times. 6479*7c478bd9Sstevel@tonic-gate */ 6480*7c478bd9Sstevel@tonic-gate if (vh->vh_bus_config.vhc_taskq == NULL) { 6481*7c478bd9Sstevel@tonic-gate /* 6482*7c478bd9Sstevel@tonic-gate * it is ok even if vh->vh_phci_count changes after we release 6483*7c478bd9Sstevel@tonic-gate * the mdi_mutex as phci_count is used just as an 6484*7c478bd9Sstevel@tonic-gate * advisory number to taskq_create. 6485*7c478bd9Sstevel@tonic-gate */ 6486*7c478bd9Sstevel@tonic-gate phci_count = vh->vh_phci_count; 6487*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6488*7c478bd9Sstevel@tonic-gate 6489*7c478bd9Sstevel@tonic-gate /* 6490*7c478bd9Sstevel@tonic-gate * As we are single threaded, it is ok to access the 6491*7c478bd9Sstevel@tonic-gate * vh_bus_config.taskq member of vh outside of mdi_mutex 6492*7c478bd9Sstevel@tonic-gate */ 6493*7c478bd9Sstevel@tonic-gate if ((vh->vh_bus_config.vhc_taskq = taskq_create( 6494*7c478bd9Sstevel@tonic-gate "mdi_bus_config_taskq", mdi_max_bus_config_threads, 6495*7c478bd9Sstevel@tonic-gate MDI_TASKQ_PRI, phci_count, INT_MAX, 6496*7c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE | TASKQ_DYNAMIC)) == NULL) { 6497*7c478bd9Sstevel@tonic-gate rv = MDI_FAILURE; 6498*7c478bd9Sstevel@tonic-gate goto out; 6499*7c478bd9Sstevel@tonic-gate } 6500*7c478bd9Sstevel@tonic-gate 6501*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 6502*7c478bd9Sstevel@tonic-gate } 6503*7c478bd9Sstevel@tonic-gate 6504*7c478bd9Sstevel@tonic-gate /* allocate at least vh->vh_phci_count phci bus config structures */ 6505*7c478bd9Sstevel@tonic-gate while (vh->vh_bus_config.vhc_phc_cnt < vh->vh_phci_count) { 6506*7c478bd9Sstevel@tonic-gate int count; 6507*7c478bd9Sstevel@tonic-gate 6508*7c478bd9Sstevel@tonic-gate count = vh->vh_phci_count - vh->vh_bus_config.vhc_phc_cnt; 6509*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6510*7c478bd9Sstevel@tonic-gate while (count--) { 6511*7c478bd9Sstevel@tonic-gate phc = kmem_alloc(sizeof (*phc), KM_SLEEP); 6512*7c478bd9Sstevel@tonic-gate phc->phc_vhc = &vh->vh_bus_config; 6513*7c478bd9Sstevel@tonic-gate /* 6514*7c478bd9Sstevel@tonic-gate * there is no need to hold a lock here as we 6515*7c478bd9Sstevel@tonic-gate * are single threaded and no one else manipulates 6516*7c478bd9Sstevel@tonic-gate * the list while we are here. 6517*7c478bd9Sstevel@tonic-gate */ 6518*7c478bd9Sstevel@tonic-gate phc->phc_next = vh->vh_bus_config.vhc_phc; 6519*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc = phc; 6520*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_phc_cnt++; 6521*7c478bd9Sstevel@tonic-gate } 6522*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 6523*7c478bd9Sstevel@tonic-gate /* 6524*7c478bd9Sstevel@tonic-gate * as new phcis could register with mdi after we dropped 6525*7c478bd9Sstevel@tonic-gate * the mdi_mutex, we need to recheck the vh->vh_phci_count. 6526*7c478bd9Sstevel@tonic-gate * Hence the while loop. 6527*7c478bd9Sstevel@tonic-gate */ 6528*7c478bd9Sstevel@tonic-gate } 6529*7c478bd9Sstevel@tonic-gate 6530*7c478bd9Sstevel@tonic-gate for (ph = vh->vh_phci_head, phc = vh->vh_bus_config.vhc_phc; 6531*7c478bd9Sstevel@tonic-gate ph != NULL; ph = ph->ph_next, phc = phc->phc_next) { 6532*7c478bd9Sstevel@tonic-gate 6533*7c478bd9Sstevel@tonic-gate ASSERT(phc != NULL); 6534*7c478bd9Sstevel@tonic-gate 6535*7c478bd9Sstevel@tonic-gate /* build a phci config handle to be passed to a taskq thread */ 6536*7c478bd9Sstevel@tonic-gate MDI_PHCI_LOCK(ph); 6537*7c478bd9Sstevel@tonic-gate ASSERT(ph->ph_dip); 6538*7c478bd9Sstevel@tonic-gate 6539*7c478bd9Sstevel@tonic-gate /* 6540*7c478bd9Sstevel@tonic-gate * We need to hold the phci dip before bus configuring the phci. 6541*7c478bd9Sstevel@tonic-gate * But placing a hold on the phci dip is not safe here due to 6542*7c478bd9Sstevel@tonic-gate * the race with phci detach. To get around this race, 6543*7c478bd9Sstevel@tonic-gate * we place a hold on the phci dip's parent and note down 6544*7c478bd9Sstevel@tonic-gate * the phci's name@addr. Later, in i_mdi_phci_bus_config(), 6545*7c478bd9Sstevel@tonic-gate * we'll first configure the phci itself before bus 6546*7c478bd9Sstevel@tonic-gate * configuring the phci. 6547*7c478bd9Sstevel@tonic-gate */ 6548*7c478bd9Sstevel@tonic-gate phc->phc_parent_dip = ddi_get_parent(ph->ph_dip); 6549*7c478bd9Sstevel@tonic-gate ndi_hold_devi(phc->phc_parent_dip); 6550*7c478bd9Sstevel@tonic-gate (void) ddi_deviname(ph->ph_dip, phc->phc_devnm); 6551*7c478bd9Sstevel@tonic-gate MDI_PHCI_UNLOCK(ph); 6552*7c478bd9Sstevel@tonic-gate } 6553*7c478bd9Sstevel@tonic-gate 6554*7c478bd9Sstevel@tonic-gate phci_count = vh->vh_phci_count; 6555*7c478bd9Sstevel@tonic-gate if (vh->vh_bus_config.vhc_cutoff_time == -1) 6556*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_cutoff_time = 0; 6557*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6558*7c478bd9Sstevel@tonic-gate 6559*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, 6560*7c478bd9Sstevel@tonic-gate "!MDI: initiating %s on all phcis, major = %d, flags = 0x%x\n", 6561*7c478bd9Sstevel@tonic-gate (op == BUS_CONFIG_DRIVER) ? "BUS_CONFIG_DRIVER" : "BUS_CONFIG_ALL", 6562*7c478bd9Sstevel@tonic-gate (int)maj, flags)); 6563*7c478bd9Sstevel@tonic-gate 6564*7c478bd9Sstevel@tonic-gate /* 6565*7c478bd9Sstevel@tonic-gate * again, no need to hold a lock here as we are single threaded and 6566*7c478bd9Sstevel@tonic-gate * no one else manipulates the list while we are here. 6567*7c478bd9Sstevel@tonic-gate */ 6568*7c478bd9Sstevel@tonic-gate for (phc = vh->vh_bus_config.vhc_phc; phci_count--; 6569*7c478bd9Sstevel@tonic-gate phc = phc->phc_next) { 6570*7c478bd9Sstevel@tonic-gate (void) taskq_dispatch(vh->vh_bus_config.vhc_taskq, 6571*7c478bd9Sstevel@tonic-gate i_mdi_phci_bus_config, phc, TQ_SLEEP); 6572*7c478bd9Sstevel@tonic-gate } 6573*7c478bd9Sstevel@tonic-gate 6574*7c478bd9Sstevel@tonic-gate /* wait until all phci bus configs are done */ 6575*7c478bd9Sstevel@tonic-gate taskq_wait(vh->vh_bus_config.vhc_taskq); 6576*7c478bd9Sstevel@tonic-gate rv = MDI_SUCCESS; 6577*7c478bd9Sstevel@tonic-gate 6578*7c478bd9Sstevel@tonic-gate out: 6579*7c478bd9Sstevel@tonic-gate mutex_enter(&mdi_mutex); 6580*7c478bd9Sstevel@tonic-gate out1: 6581*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_start_time = 0; 6582*7c478bd9Sstevel@tonic-gate if (op == BUS_CONFIG_ALL && vh->vh_bus_config.vhc_cutoff_time != -1) { 6583*7c478bd9Sstevel@tonic-gate vh->vh_bus_config.vhc_cutoff_time = lbolt64 + 6584*7c478bd9Sstevel@tonic-gate (int64_t)drv_usectohz(mdi_bus_config_timeout * 1000000); 6585*7c478bd9Sstevel@tonic-gate } 6586*7c478bd9Sstevel@tonic-gate cv_broadcast(&vh->vh_bus_config.vhc_cv); 6587*7c478bd9Sstevel@tonic-gate mutex_exit(&mdi_mutex); 6588*7c478bd9Sstevel@tonic-gate 6589*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, "!MDI: %s on all phcis %s\n", 6590*7c478bd9Sstevel@tonic-gate (op == BUS_CONFIG_DRIVER) ? "BUS_CONFIG_DRIVER" : "BUS_CONFIG_ALL", 6591*7c478bd9Sstevel@tonic-gate (rv == MDI_SUCCESS) ? "successful" : "failed")); 6592*7c478bd9Sstevel@tonic-gate 6593*7c478bd9Sstevel@tonic-gate return (rv); 6594*7c478bd9Sstevel@tonic-gate } 6595*7c478bd9Sstevel@tonic-gate 6596*7c478bd9Sstevel@tonic-gate /* 6597*7c478bd9Sstevel@tonic-gate * A simple bus config implementation for vhcis with the assumption that all 6598*7c478bd9Sstevel@tonic-gate * phcis are always registered with MDI. 6599*7c478bd9Sstevel@tonic-gate * 6600*7c478bd9Sstevel@tonic-gate * BUS_CONFIG_ALL 6601*7c478bd9Sstevel@tonic-gate * 6602*7c478bd9Sstevel@tonic-gate * Do BUS_CONFIG_ALL on all phcis associated with the vhci. 6603*7c478bd9Sstevel@tonic-gate * 6604*7c478bd9Sstevel@tonic-gate * BUS_CONFIG_DRIVER 6605*7c478bd9Sstevel@tonic-gate * 6606*7c478bd9Sstevel@tonic-gate * Do BUS_CONFIG_DRIVER on all phcis associated with the vhci. 6607*7c478bd9Sstevel@tonic-gate * 6608*7c478bd9Sstevel@tonic-gate * BUS_CONFIG_ONE 6609*7c478bd9Sstevel@tonic-gate * 6610*7c478bd9Sstevel@tonic-gate * If the requested child has already been enumerated under the vhci 6611*7c478bd9Sstevel@tonic-gate * configure the child and return. Otherwise do BUS_CONFIG_ALL on all 6612*7c478bd9Sstevel@tonic-gate * phcis associated with the vhci. 6613*7c478bd9Sstevel@tonic-gate */ 6614*7c478bd9Sstevel@tonic-gate int 6615*7c478bd9Sstevel@tonic-gate mdi_vhci_bus_config(dev_info_t *vdip, uint_t flags, ddi_bus_config_op_t op, 6616*7c478bd9Sstevel@tonic-gate void *arg, dev_info_t **child) 6617*7c478bd9Sstevel@tonic-gate { 6618*7c478bd9Sstevel@tonic-gate int rv = MDI_SUCCESS; 6619*7c478bd9Sstevel@tonic-gate 6620*7c478bd9Sstevel@tonic-gate /* 6621*7c478bd9Sstevel@tonic-gate * While bus configuring phcis, the phci driver interactions with MDI 6622*7c478bd9Sstevel@tonic-gate * cause child nodes to be enumerated under the vhci node for which 6623*7c478bd9Sstevel@tonic-gate * they need to ndi_devi_enter the vhci node. 6624*7c478bd9Sstevel@tonic-gate * 6625*7c478bd9Sstevel@tonic-gate * Unfortunately, to avoid the deadlock, we ourself can not wait for 6626*7c478bd9Sstevel@tonic-gate * for the bus config operations on phcis to finish while holding the 6627*7c478bd9Sstevel@tonic-gate * ndi_devi_enter lock. To avoid this deadlock, skip bus configs on 6628*7c478bd9Sstevel@tonic-gate * phcis and call the default framework provided bus config function 6629*7c478bd9Sstevel@tonic-gate * if we are called with ndi_devi_enter lock held. 6630*7c478bd9Sstevel@tonic-gate */ 6631*7c478bd9Sstevel@tonic-gate if (DEVI_BUSY_OWNED(vdip)) { 6632*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, 6633*7c478bd9Sstevel@tonic-gate "!MDI: vhci bus config: vhci dip is busy owned\n")); 6634*7c478bd9Sstevel@tonic-gate goto default_bus_config; 6635*7c478bd9Sstevel@tonic-gate } 6636*7c478bd9Sstevel@tonic-gate 6637*7c478bd9Sstevel@tonic-gate switch (op) { 6638*7c478bd9Sstevel@tonic-gate case BUS_CONFIG_ONE: 6639*7c478bd9Sstevel@tonic-gate /* 6640*7c478bd9Sstevel@tonic-gate * First try to directly configure the requested child. 6641*7c478bd9Sstevel@tonic-gate * This will work only if the requested child has already 6642*7c478bd9Sstevel@tonic-gate * been enumerated under vhci, which is usually the most common 6643*7c478bd9Sstevel@tonic-gate * case. 6644*7c478bd9Sstevel@tonic-gate */ 6645*7c478bd9Sstevel@tonic-gate if (ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 6646*7c478bd9Sstevel@tonic-gate NDI_SUCCESS) { 6647*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6648*7c478bd9Sstevel@tonic-gate } 6649*7c478bd9Sstevel@tonic-gate 6650*7c478bd9Sstevel@tonic-gate MDI_DEBUG(2, (CE_NOTE, vdip, "!MDI: BUS_CONFIG_ONE on %s: " 6651*7c478bd9Sstevel@tonic-gate "will do BUS_CONFIG_ALL on all phcis\n", (char *)arg)); 6652*7c478bd9Sstevel@tonic-gate 6653*7c478bd9Sstevel@tonic-gate /* now do BUS_CONFIG_ALL on all phcis */ 6654*7c478bd9Sstevel@tonic-gate rv = i_mdi_bus_config_all_phcis(vdip, flags, 6655*7c478bd9Sstevel@tonic-gate BUS_CONFIG_ALL, -1, 1); 6656*7c478bd9Sstevel@tonic-gate break; 6657*7c478bd9Sstevel@tonic-gate 6658*7c478bd9Sstevel@tonic-gate case BUS_CONFIG_DRIVER: 6659*7c478bd9Sstevel@tonic-gate rv = i_mdi_bus_config_all_phcis(vdip, flags, op, 6660*7c478bd9Sstevel@tonic-gate (major_t)(uintptr_t)arg, 0); 6661*7c478bd9Sstevel@tonic-gate break; 6662*7c478bd9Sstevel@tonic-gate 6663*7c478bd9Sstevel@tonic-gate case BUS_CONFIG_ALL: 6664*7c478bd9Sstevel@tonic-gate rv = i_mdi_bus_config_all_phcis(vdip, flags, op, -1, 0); 6665*7c478bd9Sstevel@tonic-gate break; 6666*7c478bd9Sstevel@tonic-gate 6667*7c478bd9Sstevel@tonic-gate default: 6668*7c478bd9Sstevel@tonic-gate break; 6669*7c478bd9Sstevel@tonic-gate } 6670*7c478bd9Sstevel@tonic-gate 6671*7c478bd9Sstevel@tonic-gate default_bus_config: 6672*7c478bd9Sstevel@tonic-gate /* 6673*7c478bd9Sstevel@tonic-gate * i_mdi_bus_config_all_phcis() guarantees that child nodes are 6674*7c478bd9Sstevel@tonic-gate * enumerated under the vhci, but not necessarily attached. 6675*7c478bd9Sstevel@tonic-gate * Now configure the appropriate child nodes. 6676*7c478bd9Sstevel@tonic-gate */ 6677*7c478bd9Sstevel@tonic-gate if (rv == MDI_SUCCESS && 6678*7c478bd9Sstevel@tonic-gate ndi_busop_bus_config(vdip, flags, op, arg, child, 0) == 6679*7c478bd9Sstevel@tonic-gate NDI_SUCCESS) { 6680*7c478bd9Sstevel@tonic-gate return (MDI_SUCCESS); 6681*7c478bd9Sstevel@tonic-gate } 6682*7c478bd9Sstevel@tonic-gate 6683*7c478bd9Sstevel@tonic-gate return (MDI_FAILURE); 6684*7c478bd9Sstevel@tonic-gate } 6685*7c478bd9Sstevel@tonic-gate 6686*7c478bd9Sstevel@tonic-gate 6687*7c478bd9Sstevel@tonic-gate void * 6688*7c478bd9Sstevel@tonic-gate mdi_client_get_vhci_private(dev_info_t *dip) 6689*7c478bd9Sstevel@tonic-gate { 6690*7c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 6691*7c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 6692*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 6693*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 6694*7c478bd9Sstevel@tonic-gate return (ct->ct_vprivate); 6695*7c478bd9Sstevel@tonic-gate } 6696*7c478bd9Sstevel@tonic-gate return (NULL); 6697*7c478bd9Sstevel@tonic-gate } 6698*7c478bd9Sstevel@tonic-gate 6699*7c478bd9Sstevel@tonic-gate void 6700*7c478bd9Sstevel@tonic-gate mdi_client_set_vhci_private(dev_info_t *dip, void *data) 6701*7c478bd9Sstevel@tonic-gate { 6702*7c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_client(dip, NULL) == MDI_SUCCESS); 6703*7c478bd9Sstevel@tonic-gate if (mdi_component_is_client(dip, NULL) == MDI_SUCCESS) { 6704*7c478bd9Sstevel@tonic-gate mdi_client_t *ct; 6705*7c478bd9Sstevel@tonic-gate ct = i_devi_get_client(dip); 6706*7c478bd9Sstevel@tonic-gate ct->ct_vprivate = data; 6707*7c478bd9Sstevel@tonic-gate } 6708*7c478bd9Sstevel@tonic-gate } 6709*7c478bd9Sstevel@tonic-gate /* 6710*7c478bd9Sstevel@tonic-gate * mdi_pi_get_vhci_private(): 6711*7c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 6712*7c478bd9Sstevel@tonic-gate * mdi_pathinfo node 6713*7c478bd9Sstevel@tonic-gate */ 6714*7c478bd9Sstevel@tonic-gate void * 6715*7c478bd9Sstevel@tonic-gate mdi_pi_get_vhci_private(mdi_pathinfo_t *pip) 6716*7c478bd9Sstevel@tonic-gate { 6717*7c478bd9Sstevel@tonic-gate caddr_t vprivate = NULL; 6718*7c478bd9Sstevel@tonic-gate if (pip) { 6719*7c478bd9Sstevel@tonic-gate vprivate = MDI_PI(pip)->pi_vprivate; 6720*7c478bd9Sstevel@tonic-gate } 6721*7c478bd9Sstevel@tonic-gate return (vprivate); 6722*7c478bd9Sstevel@tonic-gate } 6723*7c478bd9Sstevel@tonic-gate 6724*7c478bd9Sstevel@tonic-gate /* 6725*7c478bd9Sstevel@tonic-gate * mdi_pi_set_vhci_private(): 6726*7c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_pathinfo node 6727*7c478bd9Sstevel@tonic-gate */ 6728*7c478bd9Sstevel@tonic-gate void 6729*7c478bd9Sstevel@tonic-gate mdi_pi_set_vhci_private(mdi_pathinfo_t *pip, void *priv) 6730*7c478bd9Sstevel@tonic-gate { 6731*7c478bd9Sstevel@tonic-gate if (pip) { 6732*7c478bd9Sstevel@tonic-gate MDI_PI(pip)->pi_vprivate = priv; 6733*7c478bd9Sstevel@tonic-gate } 6734*7c478bd9Sstevel@tonic-gate } 6735*7c478bd9Sstevel@tonic-gate 6736*7c478bd9Sstevel@tonic-gate /* 6737*7c478bd9Sstevel@tonic-gate * mdi_phci_get_vhci_private(): 6738*7c478bd9Sstevel@tonic-gate * Get the vhci private information associated with the 6739*7c478bd9Sstevel@tonic-gate * mdi_phci node 6740*7c478bd9Sstevel@tonic-gate */ 6741*7c478bd9Sstevel@tonic-gate void * 6742*7c478bd9Sstevel@tonic-gate mdi_phci_get_vhci_private(dev_info_t *dip) 6743*7c478bd9Sstevel@tonic-gate { 6744*7c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 6745*7c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 6746*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 6747*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 6748*7c478bd9Sstevel@tonic-gate return (ph->ph_vprivate); 6749*7c478bd9Sstevel@tonic-gate } 6750*7c478bd9Sstevel@tonic-gate return (NULL); 6751*7c478bd9Sstevel@tonic-gate } 6752*7c478bd9Sstevel@tonic-gate 6753*7c478bd9Sstevel@tonic-gate /* 6754*7c478bd9Sstevel@tonic-gate * mdi_phci_set_vhci_private(): 6755*7c478bd9Sstevel@tonic-gate * Set the vhci private information in the mdi_phci node 6756*7c478bd9Sstevel@tonic-gate */ 6757*7c478bd9Sstevel@tonic-gate void 6758*7c478bd9Sstevel@tonic-gate mdi_phci_set_vhci_private(dev_info_t *dip, void *priv) 6759*7c478bd9Sstevel@tonic-gate { 6760*7c478bd9Sstevel@tonic-gate ASSERT(mdi_component_is_phci(dip, NULL) == MDI_SUCCESS); 6761*7c478bd9Sstevel@tonic-gate if (mdi_component_is_phci(dip, NULL) == MDI_SUCCESS) { 6762*7c478bd9Sstevel@tonic-gate mdi_phci_t *ph; 6763*7c478bd9Sstevel@tonic-gate ph = i_devi_get_phci(dip); 6764*7c478bd9Sstevel@tonic-gate ph->ph_vprivate = priv; 6765*7c478bd9Sstevel@tonic-gate } 6766*7c478bd9Sstevel@tonic-gate } 6767