1*25e8c5aaSvikram /* 2*25e8c5aaSvikram * CDDL HEADER START 3*25e8c5aaSvikram * 4*25e8c5aaSvikram * The contents of this file are subject to the terms of the 5*25e8c5aaSvikram * Common Development and Distribution License (the "License"). 6*25e8c5aaSvikram * You may not use this file except in compliance with the License. 7*25e8c5aaSvikram * 8*25e8c5aaSvikram * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*25e8c5aaSvikram * or http://www.opensolaris.org/os/licensing. 10*25e8c5aaSvikram * See the License for the specific language governing permissions 11*25e8c5aaSvikram * and limitations under the License. 12*25e8c5aaSvikram * 13*25e8c5aaSvikram * When distributing Covered Code, include this CDDL HEADER in each 14*25e8c5aaSvikram * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*25e8c5aaSvikram * If applicable, add the following below this CDDL HEADER, with the 16*25e8c5aaSvikram * fields enclosed by brackets "[]" replaced with your own identifying 17*25e8c5aaSvikram * information: Portions Copyright [yyyy] [name of copyright owner] 18*25e8c5aaSvikram * 19*25e8c5aaSvikram * CDDL HEADER END 20*25e8c5aaSvikram */ 21*25e8c5aaSvikram /* 22*25e8c5aaSvikram * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*25e8c5aaSvikram * Use is subject to license terms. 24*25e8c5aaSvikram */ 25*25e8c5aaSvikram 26*25e8c5aaSvikram #include <sys/ddi.h> 27*25e8c5aaSvikram #include <sys/sunddi.h> 28*25e8c5aaSvikram #include <sys/sunndi.h> 29*25e8c5aaSvikram #include <sys/ddi_impldefs.h> 30*25e8c5aaSvikram #include <sys/ddi_implfuncs.h> 31*25e8c5aaSvikram #include <sys/list.h> 32*25e8c5aaSvikram #include <sys/reboot.h> 33*25e8c5aaSvikram #include <sys/sysmacros.h> 34*25e8c5aaSvikram #include <sys/console.h> 35*25e8c5aaSvikram #include <sys/devcache.h> 36*25e8c5aaSvikram 37*25e8c5aaSvikram /* 38*25e8c5aaSvikram * The nvpair name in the I/O retire specific sub-nvlist 39*25e8c5aaSvikram */ 40*25e8c5aaSvikram #define RIO_STORE_VERSION_STR "rio-store-version" 41*25e8c5aaSvikram #define RIO_STORE_MAGIC_STR "rio-store-magic" 42*25e8c5aaSvikram #define RIO_STORE_FLAGS_STR "rio-store-flags" 43*25e8c5aaSvikram 44*25e8c5aaSvikram #define RIO_STORE_VERSION_1 1 45*25e8c5aaSvikram #define RIO_STORE_VERSION RIO_STORE_VERSION_1 46*25e8c5aaSvikram 47*25e8c5aaSvikram /* 48*25e8c5aaSvikram * decoded retire list element 49*25e8c5aaSvikram */ 50*25e8c5aaSvikram 51*25e8c5aaSvikram typedef enum rio_store_flags { 52*25e8c5aaSvikram RIO_STORE_F_INVAL = 0, 53*25e8c5aaSvikram RIO_STORE_F_RETIRED = 1, 54*25e8c5aaSvikram RIO_STORE_F_BYPASS = 2 55*25e8c5aaSvikram } rio_store_flags_t; 56*25e8c5aaSvikram 57*25e8c5aaSvikram typedef struct rio_store { 58*25e8c5aaSvikram char *rst_devpath; 59*25e8c5aaSvikram rio_store_flags_t rst_flags; 60*25e8c5aaSvikram list_node_t rst_next; 61*25e8c5aaSvikram } rio_store_t; 62*25e8c5aaSvikram 63*25e8c5aaSvikram #define RIO_STORE_MAGIC 0x601fcace /* retire */ 64*25e8c5aaSvikram 65*25e8c5aaSvikram static int rio_store_decode(nvf_handle_t nvfh, nvlist_t *line_nvl, char *name); 66*25e8c5aaSvikram static int rio_store_encode(nvf_handle_t nvfh, nvlist_t **ret_nvl); 67*25e8c5aaSvikram static void retire_list_free(nvf_handle_t nvfh); 68*25e8c5aaSvikram 69*25e8c5aaSvikram 70*25e8c5aaSvikram /* 71*25e8c5aaSvikram * Retire I/O persistent store registration info 72*25e8c5aaSvikram */ 73*25e8c5aaSvikram static nvf_ops_t rio_store_ops = { 74*25e8c5aaSvikram "/etc/devices/retire_store", /* path to store */ 75*25e8c5aaSvikram rio_store_decode, /* decode nvlist into retire_list */ 76*25e8c5aaSvikram rio_store_encode, /* encode retire_list into nvlist */ 77*25e8c5aaSvikram retire_list_free, /* free retire_list */ 78*25e8c5aaSvikram NULL /* write complete callback */ 79*25e8c5aaSvikram }; 80*25e8c5aaSvikram 81*25e8c5aaSvikram static nvf_handle_t rio_store_handle; 82*25e8c5aaSvikram static char store_path[MAXPATHLEN]; 83*25e8c5aaSvikram static int store_debug = 0; 84*25e8c5aaSvikram static int bypass_msg = 0; 85*25e8c5aaSvikram static int retire_msg = 0; 86*25e8c5aaSvikram 87*25e8c5aaSvikram #define STORE_DEBUG 0x0001 88*25e8c5aaSvikram #define STORE_TRACE 0x0002 89*25e8c5aaSvikram 90*25e8c5aaSvikram #define STORE_DBG(args) if (store_debug & STORE_DEBUG) cmn_err args 91*25e8c5aaSvikram #define STORE_TRC(args) if (store_debug & STORE_TRACE) cmn_err args 92*25e8c5aaSvikram 93*25e8c5aaSvikram /* 94*25e8c5aaSvikram * We don't use the simple read disable offered by the 95*25e8c5aaSvikram * caching framework (see devcache.c) as it will not 96*25e8c5aaSvikram * have the desired effect of bypassing the persistent 97*25e8c5aaSvikram * store. A simple read disable will 98*25e8c5aaSvikram * 99*25e8c5aaSvikram * 1. cause any additions to the cache to destroy the 100*25e8c5aaSvikram * existing on-disk cache 101*25e8c5aaSvikram * 102*25e8c5aaSvikram * 2. prevent deletions from the existing on-disk 103*25e8c5aaSvikram * cache which is needed for recovery from bad 104*25e8c5aaSvikram * retire decisions. 105*25e8c5aaSvikram * 106*25e8c5aaSvikram * Use the following tunable instead 107*25e8c5aaSvikram * 108*25e8c5aaSvikram */ 109*25e8c5aaSvikram int ddi_retire_store_bypass = 0; 110*25e8c5aaSvikram 111*25e8c5aaSvikram 112*25e8c5aaSvikram 113*25e8c5aaSvikram /* 114*25e8c5aaSvikram * Initialize retire store data structures 115*25e8c5aaSvikram */ 116*25e8c5aaSvikram void 117*25e8c5aaSvikram retire_store_init(void) 118*25e8c5aaSvikram { 119*25e8c5aaSvikram if (boothowto & RB_ASKNAME) { 120*25e8c5aaSvikram 121*25e8c5aaSvikram printf("Retire store [%s] (/dev/null to bypass): ", 122*25e8c5aaSvikram rio_store_ops.nvfr_cache_path); 123*25e8c5aaSvikram console_gets(store_path, sizeof (store_path) - 1); 124*25e8c5aaSvikram store_path[sizeof (store_path) - 1] = '\0'; 125*25e8c5aaSvikram 126*25e8c5aaSvikram if (strcmp(store_path, "/dev/null") == 0) { 127*25e8c5aaSvikram ddi_retire_store_bypass = 1; 128*25e8c5aaSvikram } else if (store_path[0] != '\0') { 129*25e8c5aaSvikram if (store_path[0] != '/') { 130*25e8c5aaSvikram printf("Invalid store path: %s. Using default" 131*25e8c5aaSvikram "\n", store_path); 132*25e8c5aaSvikram } else { 133*25e8c5aaSvikram rio_store_ops.nvfr_cache_path = store_path; 134*25e8c5aaSvikram } 135*25e8c5aaSvikram } 136*25e8c5aaSvikram } 137*25e8c5aaSvikram 138*25e8c5aaSvikram rio_store_handle = nvf_register_file(&rio_store_ops); 139*25e8c5aaSvikram 140*25e8c5aaSvikram list_create(nvf_list(rio_store_handle), sizeof (rio_store_t), 141*25e8c5aaSvikram offsetof(rio_store_t, rst_next)); 142*25e8c5aaSvikram } 143*25e8c5aaSvikram 144*25e8c5aaSvikram /* 145*25e8c5aaSvikram * Read and populate the in-core retire store 146*25e8c5aaSvikram */ 147*25e8c5aaSvikram void 148*25e8c5aaSvikram retire_store_read(void) 149*25e8c5aaSvikram { 150*25e8c5aaSvikram rw_enter(nvf_lock(rio_store_handle), RW_WRITER); 151*25e8c5aaSvikram ASSERT(list_head(nvf_list(rio_store_handle)) == NULL); 152*25e8c5aaSvikram (void) nvf_read_file(rio_store_handle); 153*25e8c5aaSvikram rw_exit(nvf_lock(rio_store_handle)); 154*25e8c5aaSvikram STORE_DBG((CE_NOTE, "Read on-disk retire store")); 155*25e8c5aaSvikram } 156*25e8c5aaSvikram 157*25e8c5aaSvikram static void 158*25e8c5aaSvikram rio_store_free(rio_store_t *rsp) 159*25e8c5aaSvikram { 160*25e8c5aaSvikram int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS; 161*25e8c5aaSvikram 162*25e8c5aaSvikram ASSERT(rsp); 163*25e8c5aaSvikram ASSERT(rsp->rst_devpath); 164*25e8c5aaSvikram ASSERT(rsp->rst_flags & RIO_STORE_F_RETIRED); 165*25e8c5aaSvikram ASSERT(!(rsp->rst_flags & ~flag_mask)); 166*25e8c5aaSvikram 167*25e8c5aaSvikram STORE_TRC((CE_NOTE, "store: freed path: %s", rsp->rst_devpath)); 168*25e8c5aaSvikram 169*25e8c5aaSvikram kmem_free(rsp->rst_devpath, strlen(rsp->rst_devpath) + 1); 170*25e8c5aaSvikram kmem_free(rsp, sizeof (*rsp)); 171*25e8c5aaSvikram } 172*25e8c5aaSvikram 173*25e8c5aaSvikram static void 174*25e8c5aaSvikram retire_list_free(nvf_handle_t nvfh) 175*25e8c5aaSvikram { 176*25e8c5aaSvikram list_t *listp; 177*25e8c5aaSvikram rio_store_t *rsp; 178*25e8c5aaSvikram 179*25e8c5aaSvikram ASSERT(nvfh == rio_store_handle); 180*25e8c5aaSvikram ASSERT(RW_WRITE_HELD(nvf_lock(nvfh))); 181*25e8c5aaSvikram 182*25e8c5aaSvikram listp = nvf_list(nvfh); 183*25e8c5aaSvikram while (rsp = list_head(listp)) { 184*25e8c5aaSvikram list_remove(listp, rsp); 185*25e8c5aaSvikram rio_store_free(rsp); 186*25e8c5aaSvikram } 187*25e8c5aaSvikram 188*25e8c5aaSvikram STORE_DBG((CE_NOTE, "store: freed retire list")); 189*25e8c5aaSvikram } 190*25e8c5aaSvikram 191*25e8c5aaSvikram static int 192*25e8c5aaSvikram rio_store_decode(nvf_handle_t nvfh, nvlist_t *line_nvl, char *name) 193*25e8c5aaSvikram { 194*25e8c5aaSvikram rio_store_t *rsp; 195*25e8c5aaSvikram int32_t version; 196*25e8c5aaSvikram int32_t magic; 197*25e8c5aaSvikram int32_t flags; 198*25e8c5aaSvikram int rval; 199*25e8c5aaSvikram 200*25e8c5aaSvikram ASSERT(nvfh == rio_store_handle); 201*25e8c5aaSvikram ASSERT(RW_WRITE_HELD(nvf_lock(nvfh))); 202*25e8c5aaSvikram ASSERT(name); 203*25e8c5aaSvikram 204*25e8c5aaSvikram version = 0; 205*25e8c5aaSvikram rval = nvlist_lookup_int32(line_nvl, RIO_STORE_VERSION_STR, &version); 206*25e8c5aaSvikram if (rval != 0 || version != RIO_STORE_VERSION) { 207*25e8c5aaSvikram return (EINVAL); 208*25e8c5aaSvikram } 209*25e8c5aaSvikram 210*25e8c5aaSvikram magic = 0; 211*25e8c5aaSvikram rval = nvlist_lookup_int32(line_nvl, RIO_STORE_MAGIC_STR, &magic); 212*25e8c5aaSvikram if (rval != 0 || magic != RIO_STORE_MAGIC) { 213*25e8c5aaSvikram return (EINVAL); 214*25e8c5aaSvikram } 215*25e8c5aaSvikram 216*25e8c5aaSvikram flags = 0; 217*25e8c5aaSvikram rval = nvlist_lookup_int32(line_nvl, RIO_STORE_FLAGS_STR, &flags); 218*25e8c5aaSvikram if (rval != 0 || flags != RIO_STORE_F_RETIRED) { 219*25e8c5aaSvikram return (EINVAL); 220*25e8c5aaSvikram } 221*25e8c5aaSvikram 222*25e8c5aaSvikram if (ddi_retire_store_bypass) { 223*25e8c5aaSvikram flags |= RIO_STORE_F_BYPASS; 224*25e8c5aaSvikram if (!bypass_msg) { 225*25e8c5aaSvikram bypass_msg = 1; 226*25e8c5aaSvikram cmn_err(CE_WARN, 227*25e8c5aaSvikram "Bypassing retire store /etc/devices/retire_store"); 228*25e8c5aaSvikram } 229*25e8c5aaSvikram } 230*25e8c5aaSvikram 231*25e8c5aaSvikram rsp = kmem_zalloc(sizeof (rio_store_t), KM_SLEEP); 232*25e8c5aaSvikram rsp->rst_devpath = i_ddi_strdup(name, KM_SLEEP); 233*25e8c5aaSvikram rsp->rst_flags = flags; 234*25e8c5aaSvikram list_insert_tail(nvf_list(nvfh), rsp); 235*25e8c5aaSvikram 236*25e8c5aaSvikram STORE_TRC((CE_NOTE, "store: added to retire list: %s", name)); 237*25e8c5aaSvikram if (!retire_msg) { 238*25e8c5aaSvikram retire_msg = 1; 239*25e8c5aaSvikram cmn_err(CE_NOTE, "One or more I/O devices have been retired"); 240*25e8c5aaSvikram } 241*25e8c5aaSvikram 242*25e8c5aaSvikram return (0); 243*25e8c5aaSvikram } 244*25e8c5aaSvikram 245*25e8c5aaSvikram static int 246*25e8c5aaSvikram rio_store_encode(nvf_handle_t nvfh, nvlist_t **ret_nvl) 247*25e8c5aaSvikram { 248*25e8c5aaSvikram nvlist_t *nvl; 249*25e8c5aaSvikram nvlist_t *line_nvl; 250*25e8c5aaSvikram list_t *listp; 251*25e8c5aaSvikram rio_store_t *rsp; 252*25e8c5aaSvikram int rval; 253*25e8c5aaSvikram 254*25e8c5aaSvikram ASSERT(nvfh == rio_store_handle); 255*25e8c5aaSvikram ASSERT(RW_WRITE_HELD(nvf_lock(nvfh))); 256*25e8c5aaSvikram 257*25e8c5aaSvikram *ret_nvl = NULL; 258*25e8c5aaSvikram 259*25e8c5aaSvikram nvl = NULL; 260*25e8c5aaSvikram rval = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 261*25e8c5aaSvikram if (rval != 0) { 262*25e8c5aaSvikram return (DDI_FAILURE); 263*25e8c5aaSvikram } 264*25e8c5aaSvikram 265*25e8c5aaSvikram listp = nvf_list(nvfh); 266*25e8c5aaSvikram for (rsp = list_head(listp); rsp; rsp = list_next(listp, rsp)) { 267*25e8c5aaSvikram int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS; 268*25e8c5aaSvikram int flags; 269*25e8c5aaSvikram ASSERT(rsp->rst_devpath); 270*25e8c5aaSvikram ASSERT(!(rsp->rst_flags & ~flag_mask)); 271*25e8c5aaSvikram 272*25e8c5aaSvikram line_nvl = NULL; 273*25e8c5aaSvikram rval = nvlist_alloc(&line_nvl, NV_UNIQUE_NAME, KM_SLEEP); 274*25e8c5aaSvikram if (rval != 0) { 275*25e8c5aaSvikram line_nvl = NULL; 276*25e8c5aaSvikram goto error; 277*25e8c5aaSvikram } 278*25e8c5aaSvikram 279*25e8c5aaSvikram rval = nvlist_add_int32(line_nvl, RIO_STORE_VERSION_STR, 280*25e8c5aaSvikram RIO_STORE_VERSION); 281*25e8c5aaSvikram if (rval != 0) { 282*25e8c5aaSvikram goto error; 283*25e8c5aaSvikram } 284*25e8c5aaSvikram rval = nvlist_add_int32(line_nvl, RIO_STORE_MAGIC_STR, 285*25e8c5aaSvikram RIO_STORE_MAGIC); 286*25e8c5aaSvikram if (rval != 0) { 287*25e8c5aaSvikram goto error; 288*25e8c5aaSvikram } 289*25e8c5aaSvikram 290*25e8c5aaSvikram /* don't save the bypass flag */ 291*25e8c5aaSvikram flags = RIO_STORE_F_RETIRED; 292*25e8c5aaSvikram rval = nvlist_add_int32(line_nvl, RIO_STORE_FLAGS_STR, 293*25e8c5aaSvikram flags); 294*25e8c5aaSvikram if (rval != 0) { 295*25e8c5aaSvikram goto error; 296*25e8c5aaSvikram } 297*25e8c5aaSvikram 298*25e8c5aaSvikram rval = nvlist_add_nvlist(nvl, rsp->rst_devpath, line_nvl); 299*25e8c5aaSvikram if (rval != 0) { 300*25e8c5aaSvikram goto error; 301*25e8c5aaSvikram } 302*25e8c5aaSvikram nvlist_free(line_nvl); 303*25e8c5aaSvikram line_nvl = NULL; 304*25e8c5aaSvikram } 305*25e8c5aaSvikram 306*25e8c5aaSvikram *ret_nvl = nvl; 307*25e8c5aaSvikram STORE_DBG((CE_NOTE, "packed retire list into nvlist")); 308*25e8c5aaSvikram return (DDI_SUCCESS); 309*25e8c5aaSvikram 310*25e8c5aaSvikram error: 311*25e8c5aaSvikram nvlist_free(line_nvl); 312*25e8c5aaSvikram ASSERT(nvl); 313*25e8c5aaSvikram nvlist_free(nvl); 314*25e8c5aaSvikram return (DDI_FAILURE); 315*25e8c5aaSvikram } 316*25e8c5aaSvikram 317*25e8c5aaSvikram int 318*25e8c5aaSvikram e_ddi_retire_persist(char *devpath) 319*25e8c5aaSvikram { 320*25e8c5aaSvikram rio_store_t *rsp; 321*25e8c5aaSvikram rio_store_t *new_rsp; 322*25e8c5aaSvikram list_t *listp; 323*25e8c5aaSvikram char *new_path; 324*25e8c5aaSvikram 325*25e8c5aaSvikram STORE_DBG((CE_NOTE, "e_ddi_retire_persist: entered: %s", devpath)); 326*25e8c5aaSvikram 327*25e8c5aaSvikram new_rsp = kmem_zalloc(sizeof (*new_rsp), KM_SLEEP); 328*25e8c5aaSvikram new_rsp->rst_devpath = new_path = i_ddi_strdup(devpath, KM_SLEEP); 329*25e8c5aaSvikram new_rsp->rst_flags = RIO_STORE_F_RETIRED; 330*25e8c5aaSvikram 331*25e8c5aaSvikram rw_enter(nvf_lock(rio_store_handle), RW_WRITER); 332*25e8c5aaSvikram 333*25e8c5aaSvikram listp = nvf_list(rio_store_handle); 334*25e8c5aaSvikram for (rsp = list_head(listp); rsp; rsp = list_next(listp, rsp)) { 335*25e8c5aaSvikram int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS; 336*25e8c5aaSvikram ASSERT(!(rsp->rst_flags & ~flag_mask)); 337*25e8c5aaSvikram 338*25e8c5aaSvikram /* already there */ 339*25e8c5aaSvikram if (strcmp(devpath, rsp->rst_devpath) == 0) { 340*25e8c5aaSvikram /* explicit retire, clear bypass flag (if any) */ 341*25e8c5aaSvikram rsp->rst_flags &= ~RIO_STORE_F_BYPASS; 342*25e8c5aaSvikram ASSERT(rsp->rst_flags == RIO_STORE_F_RETIRED); 343*25e8c5aaSvikram rw_exit(nvf_lock(rio_store_handle)); 344*25e8c5aaSvikram kmem_free(new_path, strlen(new_path) + 1); 345*25e8c5aaSvikram kmem_free(new_rsp, sizeof (*new_rsp)); 346*25e8c5aaSvikram STORE_DBG((CE_NOTE, "store: already in. Clear bypass " 347*25e8c5aaSvikram ": %s", devpath)); 348*25e8c5aaSvikram return (0); 349*25e8c5aaSvikram } 350*25e8c5aaSvikram 351*25e8c5aaSvikram } 352*25e8c5aaSvikram 353*25e8c5aaSvikram ASSERT(rsp == NULL); 354*25e8c5aaSvikram list_insert_tail(listp, new_rsp); 355*25e8c5aaSvikram 356*25e8c5aaSvikram nvf_mark_dirty(rio_store_handle); 357*25e8c5aaSvikram 358*25e8c5aaSvikram rw_exit(nvf_lock(rio_store_handle)); 359*25e8c5aaSvikram 360*25e8c5aaSvikram nvf_wake_daemon(); 361*25e8c5aaSvikram 362*25e8c5aaSvikram STORE_DBG((CE_NOTE, "store: New, added to list, dirty: %s", devpath)); 363*25e8c5aaSvikram 364*25e8c5aaSvikram return (0); 365*25e8c5aaSvikram } 366*25e8c5aaSvikram 367*25e8c5aaSvikram int 368*25e8c5aaSvikram e_ddi_retire_unpersist(char *devpath) 369*25e8c5aaSvikram { 370*25e8c5aaSvikram rio_store_t *rsp; 371*25e8c5aaSvikram rio_store_t *next; 372*25e8c5aaSvikram list_t *listp; 373*25e8c5aaSvikram int is_dirty = 0; 374*25e8c5aaSvikram 375*25e8c5aaSvikram STORE_DBG((CE_NOTE, "e_ddi_retire_unpersist: entered: %s", devpath)); 376*25e8c5aaSvikram 377*25e8c5aaSvikram rw_enter(nvf_lock(rio_store_handle), RW_WRITER); 378*25e8c5aaSvikram 379*25e8c5aaSvikram listp = nvf_list(rio_store_handle); 380*25e8c5aaSvikram for (rsp = list_head(listp); rsp; rsp = next) { 381*25e8c5aaSvikram next = list_next(listp, rsp); 382*25e8c5aaSvikram if (strcmp(devpath, rsp->rst_devpath) != 0) 383*25e8c5aaSvikram continue; 384*25e8c5aaSvikram 385*25e8c5aaSvikram list_remove(listp, rsp); 386*25e8c5aaSvikram rio_store_free(rsp); 387*25e8c5aaSvikram 388*25e8c5aaSvikram STORE_DBG((CE_NOTE, "store: found in list. Freed: %s", 389*25e8c5aaSvikram devpath)); 390*25e8c5aaSvikram 391*25e8c5aaSvikram nvf_mark_dirty(rio_store_handle); 392*25e8c5aaSvikram is_dirty = 1; 393*25e8c5aaSvikram } 394*25e8c5aaSvikram 395*25e8c5aaSvikram rw_exit(nvf_lock(rio_store_handle)); 396*25e8c5aaSvikram 397*25e8c5aaSvikram if (is_dirty) 398*25e8c5aaSvikram nvf_wake_daemon(); 399*25e8c5aaSvikram 400*25e8c5aaSvikram return (is_dirty); 401*25e8c5aaSvikram } 402*25e8c5aaSvikram 403*25e8c5aaSvikram int 404*25e8c5aaSvikram e_ddi_device_retired(char *devpath) 405*25e8c5aaSvikram { 406*25e8c5aaSvikram list_t *listp; 407*25e8c5aaSvikram rio_store_t *rsp; 408*25e8c5aaSvikram size_t len; 409*25e8c5aaSvikram int retired; 410*25e8c5aaSvikram 411*25e8c5aaSvikram retired = 0; 412*25e8c5aaSvikram 413*25e8c5aaSvikram rw_enter(nvf_lock(rio_store_handle), RW_READER); 414*25e8c5aaSvikram 415*25e8c5aaSvikram listp = nvf_list(rio_store_handle); 416*25e8c5aaSvikram for (rsp = list_head(listp); rsp; rsp = list_next(listp, rsp)) { 417*25e8c5aaSvikram int flag_mask = RIO_STORE_F_RETIRED|RIO_STORE_F_BYPASS; 418*25e8c5aaSvikram ASSERT(!(rsp->rst_flags & ~flag_mask)); 419*25e8c5aaSvikram 420*25e8c5aaSvikram /* 421*25e8c5aaSvikram * If the "bypass" flag is set, then the device 422*25e8c5aaSvikram * is *not* retired for the current boot of the 423*25e8c5aaSvikram * system. It indicates that the retire store 424*25e8c5aaSvikram * was read but the devices in the retire store 425*25e8c5aaSvikram * were not retired i.e. effectively the store 426*25e8c5aaSvikram * was bypassed. For why we bother to even read 427*25e8c5aaSvikram * the store when we bypass it, see the comments 428*25e8c5aaSvikram * for the tunable ddi_retire_store_bypass. 429*25e8c5aaSvikram */ 430*25e8c5aaSvikram if (rsp->rst_flags & RIO_STORE_F_BYPASS) { 431*25e8c5aaSvikram STORE_TRC((CE_NOTE, "store: found & bypassed: %s", 432*25e8c5aaSvikram rsp->rst_devpath)); 433*25e8c5aaSvikram continue; 434*25e8c5aaSvikram } 435*25e8c5aaSvikram 436*25e8c5aaSvikram /* 437*25e8c5aaSvikram * device is retired, if it or a parent exists 438*25e8c5aaSvikram * in the in-core list 439*25e8c5aaSvikram */ 440*25e8c5aaSvikram len = strlen(rsp->rst_devpath); 441*25e8c5aaSvikram if (strncmp(devpath, rsp->rst_devpath, len) != 0) 442*25e8c5aaSvikram continue; 443*25e8c5aaSvikram if (devpath[len] == '\0' || devpath[len] == '/') { 444*25e8c5aaSvikram /* exact match or a child */ 445*25e8c5aaSvikram retired = 1; 446*25e8c5aaSvikram STORE_TRC((CE_NOTE, "store: found & !bypassed: %s", 447*25e8c5aaSvikram devpath)); 448*25e8c5aaSvikram break; 449*25e8c5aaSvikram } 450*25e8c5aaSvikram } 451*25e8c5aaSvikram rw_exit(nvf_lock(rio_store_handle)); 452*25e8c5aaSvikram 453*25e8c5aaSvikram return (retired); 454*25e8c5aaSvikram } 455