1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * DACF (Device Autoconfiguration Framework) client code. 30 * 31 * DACF has two clients. the first is dacf modules which implement 32 * configuration operations; the second is the set of hooks in the kernel 33 * which do rule matching and invoke configuration operations. 34 * 35 * This file implements the second part, the kernel hooks. 36 * 37 * Currently implemented are post-attach and pre-detach handlers, and the hook 38 * for ddi_create_minor_common() which sets up post-attach and pre-detach 39 * reservations. 40 * 41 * This code depends on the core dacf code (in dacf.c) but the converse should 42 * never be true. 43 * 44 * This file also implements '__kernel', the kernel-supplied dacf module. 45 * For now, this is pretty much empty, except under DEBUG, in which case it 46 * contains some debugging code. 47 */ 48 49 #include <sys/param.h> 50 #include <sys/modctl.h> 51 #include <sys/sysmacros.h> 52 #include <sys/kmem.h> 53 #include <sys/cmn_err.h> 54 #include <sys/pathname.h> 55 #include <sys/ddi_impldefs.h> 56 #include <sys/sunddi.h> 57 #include <sys/autoconf.h> 58 #include <sys/modhash.h> 59 #include <sys/dacf_impl.h> 60 #include <sys/systm.h> 61 #include <sys/debug.h> 62 63 /* 64 * dacfc_match_create_minor() 65 * Check to see if this minor node creation sequence matches a dacf 66 * (device autoconfiguration framework) rule. If so make a reservation 67 * for the operation to be invoked at post-attach and/or pre-detach time. 68 */ 69 void 70 dacfc_match_create_minor(char *name, char *node_type, dev_info_t *dip, 71 struct ddi_minor_data *dmdp, int flag) 72 { 73 dacf_rule_t *r; 74 char *dev_path, *dev_pathp, *drv_mname = NULL; 75 dacf_rsrvlist_t *pa_rsrv, *pd_rsrv; 76 77 /* 78 * Check the dacf rule for non-clone devices or for network devices. 79 */ 80 if ((flag & CLONE_DEV) && (strcmp(node_type, DDI_NT_NET) != 0)) { 81 return; 82 } 83 84 /* 85 * Because dacf currently only implements post-attach and pre-detach 86 * processing, we only care about minor nodes created during attach. 87 * However, there is no restriction on drivers about when to create 88 * minor nodes. 89 */ 90 if (!DEVI_IS_ATTACHING(dmdp->dip)) { 91 return; 92 } 93 94 dev_path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 95 dev_pathp = ddi_pathname(dip, dev_path); 96 pa_rsrv = kmem_alloc(sizeof (dacf_rsrvlist_t), KM_SLEEP); 97 pd_rsrv = kmem_alloc(sizeof (dacf_rsrvlist_t), KM_SLEEP); 98 99 if (name) { 100 const char *drv_name = ddi_driver_name(dip); 101 if (drv_name == NULL) 102 drv_name = "???"; 103 drv_mname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 104 (void) snprintf(drv_mname, MAXPATHLEN, "%s:%s", drv_name, name); 105 } 106 107 mutex_enter(&dacf_lock); 108 109 /* 110 * Ensure that we don't wind up in a 'matching loop' against a devinfo 111 * node, which could cause deadlock. This could happen as follows: 112 * 113 * We match (just below) 114 * We invoke a task (later, at the end of devi_attach) 115 * this means we have taken the per-devinfo lock 116 * The task invoke winds up causing the same driver (that has 117 * just finished attaching) to create another minor node. 118 * We try to re-acquire the per-devinfo list lock again in the 119 * process of making another reservation 120 */ 121 mutex_enter(&(DEVI(dip)->devi_lock)); 122 if (DEVI_IS_INVOKING_DACF(dip)) { 123 mutex_exit(&(DEVI(dip)->devi_lock)); 124 cmn_err(CE_WARN, 125 "!dacf detected deadlock, aborting matching procedure\n"); 126 mutex_exit(&dacf_lock); 127 kmem_free(pa_rsrv, sizeof (dacf_rsrvlist_t)); 128 kmem_free(pd_rsrv, sizeof (dacf_rsrvlist_t)); 129 kmem_free(dev_path, MAXPATHLEN); 130 if (drv_mname) { 131 kmem_free(drv_mname, MAXPATHLEN); 132 } 133 return; 134 } 135 mutex_exit(&(DEVI(dip)->devi_lock)); 136 137 /* 138 * Do rule matching. It's possible to construct two rules that would 139 * match against the same minor node, so we match from most to least 140 * specific: 141 * device path 142 * minor node name (concatenation of drv_name:name 143 * node type 144 * 145 * Future additions to the set of device-specifiers should be 146 * sensitive to this ordering. 147 */ 148 149 /* 150 * post-attach matching 151 */ 152 r = NULL; 153 if (dev_pathp) { 154 r = dacf_match(DACF_OPID_POSTATTACH, DACF_DS_DEV_PATH, 155 dev_pathp); 156 } 157 if (!r && drv_mname) { 158 r = dacf_match(DACF_OPID_POSTATTACH, DACF_DS_DRV_MNAME, 159 drv_mname); 160 } 161 if (!r && node_type) { 162 r = dacf_match(DACF_OPID_POSTATTACH, DACF_DS_MIN_NT, node_type); 163 } 164 if (r) { 165 dacf_rsrv_make(pa_rsrv, r, dmdp, &(DEVI(dip)->devi_dacf_tasks)); 166 167 if (dacfdebug & DACF_DBG_MSGS) 168 printf("dacf: made 'post-attach' reservation for " 169 "%s, %s, %s\n", name, node_type, dev_pathp); 170 } else { 171 kmem_free(pa_rsrv, sizeof (dacf_rsrvlist_t)); 172 } 173 174 /* 175 * pre-detach matching 176 */ 177 r = NULL; 178 if (dev_pathp) { 179 r = dacf_match(DACF_OPID_PREDETACH, DACF_DS_DEV_PATH, 180 dev_pathp); 181 } 182 if (!r && drv_mname) { 183 r = dacf_match(DACF_OPID_PREDETACH, DACF_DS_DRV_MNAME, 184 drv_mname); 185 } 186 if (!r && node_type) { 187 r = dacf_match(DACF_OPID_PREDETACH, DACF_DS_MIN_NT, node_type); 188 } 189 if (r) { 190 dacf_rsrv_make(pd_rsrv, r, dmdp, &(DEVI(dip)->devi_dacf_tasks)); 191 192 if (dacfdebug & DACF_DBG_MSGS) { 193 printf("dacf: made 'pre-detach' reservation for " 194 "%s, %s, %s\n", name, node_type, dev_pathp); 195 } 196 } else { 197 kmem_free(pd_rsrv, sizeof (dacf_rsrvlist_t)); 198 } 199 200 mutex_exit(&dacf_lock); 201 kmem_free(dev_path, MAXPATHLEN); 202 if (drv_mname) { 203 kmem_free(drv_mname, MAXPATHLEN); 204 } 205 } 206 207 /* 208 * dacfc_postattach() 209 * autoconfiguration for post-attach events. 210 * 211 * strategy: try to configure. If some of the configuration operations 212 * fail, emit a warning. 213 */ 214 int 215 dacfc_postattach(dev_info_t *devi) 216 { 217 int err = DACF_SUCCESS; 218 char *path, *pathp; 219 dacf_rsrvlist_t **opsp, *op; 220 ASSERT(MUTEX_HELD(&dacf_lock)); 221 222 /* 223 * Instruct dacf_process_rsrvs() to invoke each POSTATTACH op. 224 */ 225 opsp = &DEVI(devi)->devi_dacf_tasks; 226 dacf_process_rsrvs(opsp, DACF_OPID_POSTATTACH, DACF_PROC_INVOKE); 227 228 /* 229 * Check to see that all POSTATTACH's succeeded. 230 */ 231 for (op = *opsp; op != NULL; op = op->rsrv_next) { 232 if (op->rsrv_rule->r_opid != DACF_OPID_POSTATTACH) 233 continue; 234 if (op->rsrv_result == DACF_SUCCESS) 235 continue; 236 if (dacfdebug & DACF_DBG_DEVI) { 237 cmn_err(CE_WARN, "op failed, err = %d\n", 238 op->rsrv_result); 239 } 240 err = DACF_FAILURE; 241 break; 242 } 243 244 /* 245 * If one or more postattach's failed, give up. 246 */ 247 if ((err == DACF_FAILURE) && (dacfdebug & DACF_DBG_DEVI)) { 248 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 249 if ((pathp = ddi_pathname(devi, path)) == NULL) 250 pathp = "<unknown>"; 251 cmn_err(CE_WARN, "%s attached, but failed to auto-configure", 252 pathp); 253 kmem_free(path, MAXPATHLEN); 254 } 255 256 return (err); 257 } 258 259 /* 260 * dacfc_predetach() 261 * auto-unconfiguration for pre-detach events. 262 * 263 * strategy: call the pre-detach operation for all matching reservations. 264 * If any of these fail, make (one) attempt to reconfigure things back 265 * into a sane state. if that fails, our state is uncertain. 266 */ 267 int 268 dacfc_predetach(dev_info_t *devi) 269 { 270 int err = DDI_SUCCESS; 271 char *path, *pathp; 272 dacf_rsrvlist_t **opsp, *op; 273 ASSERT(MUTEX_HELD(&dacf_lock)); 274 275 /* 276 * Instruct dacf_process_rsrvs() to invoke each PREDETACH op. 277 */ 278 opsp = &DEVI(devi)->devi_dacf_tasks; 279 dacf_process_rsrvs(opsp, DACF_OPID_PREDETACH, DACF_PROC_INVOKE); 280 281 /* 282 * Check to see that all PREDETACH's succeeded. 283 */ 284 for (op = *opsp; op != NULL; op = op->rsrv_next) { 285 if (op->rsrv_rule->r_opid != DACF_OPID_PREDETACH) 286 continue; 287 if (op->rsrv_result == 0) 288 continue; 289 err = DDI_FAILURE; 290 break; 291 } 292 293 /* 294 * If one or more predetach's failed, make one attempt to fix things 295 * by re-running all of the POST-ATTACH operations. If any of those 296 * fail, give up. 297 */ 298 if (err == DDI_FAILURE) { 299 int pa_err; 300 301 if (dacfdebug & DACF_DBG_DEVI) { 302 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 303 if ((pathp = ddi_pathname(devi, path)) == NULL) 304 pathp = "<unknown>"; 305 cmn_err(CE_WARN, "%s failed to auto-unconfigure, " 306 "attempting to reconfigure...", pathp); 307 kmem_free(path, MAXPATHLEN); 308 } 309 310 pa_err = dacfc_postattach(devi); 311 312 if (dacfdebug & DACF_DBG_DEVI) { 313 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 314 if ((pathp = ddi_pathname(devi, path)) == NULL) 315 pathp = "<unknown>"; 316 317 if (pa_err == DDI_FAILURE) { 318 cmn_err(CE_WARN, "%s failed to " 319 "auto-unconfigure, and could not be " 320 "re-autoconfigured.", pathp); 321 } else { 322 cmn_err(CE_WARN, "%s failed to " 323 "auto-unconfigure, but was successfully " 324 "re-autoconfigured.", pathp); 325 } 326 kmem_free(path, MAXPATHLEN); 327 } 328 } 329 330 return (err); 331 } 332 333 /* 334 * kmod_dacfsw: 335 * This is the declaration for the kernel-supplied '__kernel' dacf module. 336 * DACF supplies a framework based around loadable modules. However, it 337 * may be convenient (in the future) to have a module provided by the 338 * kernel. This is useful in cases when a module can't be loaded (early in 339 * boot), or for code that would never get unloaded anyway. 340 */ 341 #ifdef DEBUG 342 /*ARGSUSED*/ 343 static int 344 kmod_test_postattach(dacf_infohdl_t info_hdl, dacf_arghdl_t arg_hdl, int flags) 345 { 346 const char *verbose = dacf_get_arg(arg_hdl, "verbose"); 347 if (verbose && (strcmp(verbose, "true") == 0)) { 348 cmn_err(CE_WARN, "got kmod_test_postattach\n"); 349 } 350 return (0); 351 } 352 #endif 353 354 static dacf_op_t kmod_op_test[] = { 355 #ifdef DEBUG 356 { DACF_OPID_POSTATTACH, kmod_test_postattach }, 357 #endif 358 { DACF_OPID_END, NULL }, 359 }; 360 361 static dacf_opset_t kmod_opsets[] = { 362 #ifdef DEBUG 363 { "kmod_test", kmod_op_test }, 364 #endif 365 { NULL, NULL }, 366 }; 367 368 struct dacfsw kmod_dacfsw = { 369 DACF_MODREV_1, kmod_opsets 370 }; 371