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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <limits.h> 30 #include <strings.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <stdio.h> 34 #include <alloca.h> 35 #include <devid.h> 36 #include <sys/stat.h> 37 #include <libnvpair.h> 38 #include <fm/topo_mod.h> 39 #include <fm/fmd_fmri.h> 40 #include <sys/fm/protocol.h> 41 42 #include <topo_method.h> 43 #include <topo_subr.h> 44 #include <dev.h> 45 46 static int dev_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 47 topo_instance_t, void *, void *); 48 static void dev_release(topo_mod_t *, tnode_t *); 49 static int dev_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 50 nvlist_t *, nvlist_t **); 51 static int dev_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, 52 nvlist_t *, nvlist_t **); 53 static int dev_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, 54 nvlist_t *, nvlist_t **); 55 static int dev_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, 56 nvlist_t *, nvlist_t **); 57 static int dev_fmri_replaced(topo_mod_t *, tnode_t *, topo_version_t, 58 nvlist_t *, nvlist_t **); 59 static int dev_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, 60 nvlist_t *, nvlist_t **); 61 static int dev_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t, 62 nvlist_t *, nvlist_t **); 63 64 static const topo_method_t dev_methods[] = { 65 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 66 TOPO_STABILITY_INTERNAL, dev_fmri_nvl2str }, 67 { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 68 TOPO_STABILITY_INTERNAL, dev_fmri_str2nvl }, 69 { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, 70 TOPO_STABILITY_INTERNAL, dev_fmri_create_meth }, 71 { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, 72 TOPO_STABILITY_INTERNAL, dev_fmri_present }, 73 { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC, 74 TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL, 75 dev_fmri_replaced }, 76 { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, 77 TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, 78 dev_fmri_unusable }, 79 { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC, 80 TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL, 81 dev_fmri_service_state }, 82 { NULL } 83 }; 84 85 static const topo_modops_t dev_ops = 86 { dev_enum, dev_release }; 87 static const topo_modinfo_t dev_info = 88 { "dev", FM_FMRI_SCHEME_DEV, DEV_VERSION, &dev_ops }; 89 90 int 91 dev_init(topo_mod_t *mod, topo_version_t version) 92 { 93 if (getenv("TOPOHCDEBUG")) 94 topo_mod_setdebug(mod); 95 topo_mod_dprintf(mod, "initializing dev builtin\n"); 96 97 if (version != DEV_VERSION) 98 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 99 100 if (topo_mod_register(mod, &dev_info, TOPO_VERSION) != 0) { 101 topo_mod_dprintf(mod, "failed to register dev_info: " 102 "%s\n", topo_mod_errmsg(mod)); 103 return (-1); 104 } 105 106 return (0); 107 } 108 109 void 110 dev_fini(topo_mod_t *mod) 111 { 112 topo_mod_unregister(mod); 113 } 114 115 /*ARGSUSED*/ 116 static int 117 dev_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 118 topo_instance_t min, topo_instance_t max, void *notused1, void *notused2) 119 { 120 (void) topo_method_register(mod, pnode, dev_methods); 121 return (0); 122 } 123 124 static void 125 dev_release(topo_mod_t *mod, tnode_t *node) 126 { 127 topo_method_unregister_all(mod, node); 128 } 129 130 static ssize_t 131 fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 132 { 133 nvlist_t *anvl = NULL; 134 uint8_t version; 135 ssize_t size = 0; 136 char *devid = NULL; 137 char *devpath = NULL; 138 char *achas = NULL; 139 char *adom = NULL; 140 char *aprod = NULL; 141 char *asrvr = NULL; 142 char *ahost = NULL; 143 int more_auth = 0; 144 int err; 145 146 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 147 version > FM_DEV_SCHEME_VERSION) 148 return (-1); 149 150 /* Get authority, if present */ 151 err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); 152 if (err != 0 && err != ENOENT) 153 return (-1); 154 155 /* Get devid, if present */ 156 err = nvlist_lookup_string(nvl, FM_FMRI_DEV_ID, &devid); 157 if (err != 0 && err != ENOENT) 158 return (-1); 159 160 /* There must be a device path present */ 161 err = nvlist_lookup_string(nvl, FM_FMRI_DEV_PATH, &devpath); 162 if (err != 0 || devpath == NULL) 163 return (-1); 164 165 if (anvl != NULL) { 166 (void) nvlist_lookup_string(anvl, 167 FM_FMRI_AUTH_PRODUCT, &aprod); 168 (void) nvlist_lookup_string(anvl, 169 FM_FMRI_AUTH_CHASSIS, &achas); 170 (void) nvlist_lookup_string(anvl, 171 FM_FMRI_AUTH_DOMAIN, &adom); 172 (void) nvlist_lookup_string(anvl, 173 FM_FMRI_AUTH_SERVER, &asrvr); 174 (void) nvlist_lookup_string(anvl, 175 FM_FMRI_AUTH_HOST, &ahost); 176 if (aprod != NULL) 177 more_auth++; 178 if (achas != NULL) 179 more_auth++; 180 if (adom != NULL) 181 more_auth++; 182 if (asrvr != NULL) 183 more_auth++; 184 if (ahost != NULL) 185 more_auth++; 186 } 187 188 /* dev:// */ 189 topo_fmristr_build(&size, 190 buf, buflen, FM_FMRI_SCHEME_DEV, NULL, "://"); 191 192 /* authority, if any */ 193 if (aprod != NULL) 194 topo_fmristr_build(&size, 195 buf, buflen, aprod, FM_FMRI_AUTH_PRODUCT "=", 196 --more_auth > 0 ? "," : NULL); 197 if (achas != NULL) 198 topo_fmristr_build(&size, 199 buf, buflen, achas, FM_FMRI_AUTH_CHASSIS "=", 200 --more_auth > 0 ? "," : NULL); 201 if (adom != NULL) 202 topo_fmristr_build(&size, 203 buf, buflen, adom, FM_FMRI_AUTH_DOMAIN "=", 204 --more_auth > 0 ? "," : NULL); 205 if (asrvr != NULL) 206 topo_fmristr_build(&size, 207 buf, buflen, asrvr, FM_FMRI_AUTH_SERVER "=", 208 --more_auth > 0 ? "," : NULL); 209 if (ahost != NULL) 210 topo_fmristr_build(&size, 211 buf, buflen, ahost, FM_FMRI_AUTH_HOST "=", 212 NULL); 213 214 /* device-id part, topo_fmristr_build does nothing if devid is NULL */ 215 topo_fmristr_build(&size, 216 buf, buflen, devid, "/:" FM_FMRI_DEV_ID "=", NULL); 217 218 /* device-path part */ 219 topo_fmristr_build(&size, buf, buflen, devpath, "/", NULL); 220 221 return (size); 222 } 223 224 /*ARGSUSED*/ 225 static int 226 dev_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 227 nvlist_t *nvl, nvlist_t **out) 228 { 229 ssize_t len; 230 char *name = NULL; 231 nvlist_t *fmristr; 232 233 if (version > TOPO_METH_NVL2STR_VERSION) 234 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 235 236 if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 || 237 (name = topo_mod_alloc(mod, len + 1)) == NULL || 238 fmri_nvl2str(nvl, name, len + 1) == 0) { 239 if (name != NULL) 240 topo_mod_free(mod, name, len + 1); 241 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 242 } 243 244 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) 245 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 246 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 247 topo_mod_free(mod, name, len + 1); 248 nvlist_free(fmristr); 249 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 250 } 251 topo_mod_free(mod, name, len + 1); 252 *out = fmristr; 253 254 return (0); 255 } 256 257 /*ARGSUSED*/ 258 static int 259 dev_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 260 nvlist_t *in, nvlist_t **out) 261 { 262 nvlist_t *fmri; 263 char *devpath; 264 char *devid = NULL; 265 char *str; 266 int err; 267 268 if (version > TOPO_METH_STR2NVL_VERSION) 269 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 270 271 if (nvlist_lookup_string(in, "fmri-string", &str) != 0) 272 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 273 274 /* We're expecting a string version of a dev scheme FMRI */ 275 if (strncmp(str, "dev:///", 7) != 0) 276 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 277 278 devpath = str + 7; 279 if (strncmp(devpath, ":" FM_FMRI_DEV_ID "=", 7) == 0) { 280 char *n; 281 int len; 282 283 n = strchr(devpath + 7, '/'); 284 if (n == NULL) 285 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 286 len = n - (devpath + 7); 287 devid = alloca(len + 1); 288 (void) memcpy(devid, devpath + 7, len); 289 devid[len] = 0; 290 devpath = n + 1; 291 } 292 293 /* the device-path should start with a slash */ 294 if (*devpath != '/') 295 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 296 297 if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 298 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 299 300 err = nvlist_add_uint8(fmri, FM_VERSION, FM_DEV_SCHEME_VERSION); 301 err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV); 302 err |= nvlist_add_string(fmri, FM_FMRI_DEV_PATH, devpath); 303 if (devid != NULL) 304 err |= nvlist_add_string(fmri, FM_FMRI_DEV_ID, devid); 305 306 if (err != 0) { 307 nvlist_free(fmri); 308 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 309 } 310 *out = fmri; 311 312 return (0); 313 } 314 315 /*ARGSUSED*/ 316 static int 317 dev_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, 318 nvlist_t *in, nvlist_t **out) 319 { 320 uint8_t fmversion; 321 char *devpath = NULL; 322 uint32_t present; 323 char *devid = NULL, *path; 324 ddi_devid_t id; 325 ddi_devid_t matchid; 326 di_node_t dnode; 327 struct stat sb; 328 int len; 329 330 if (version > TOPO_METH_PRESENT_VERSION) 331 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 332 333 if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 || 334 fmversion > FM_DEV_SCHEME_VERSION || 335 nvlist_lookup_string(in, FM_FMRI_DEV_PATH, &devpath) != 0) 336 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 337 338 (void) nvlist_lookup_string(in, FM_FMRI_DEV_ID, &devid); 339 340 if (devpath == NULL || strlen(devpath) == 0) 341 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 342 343 /* 344 * stat() the device node in devfs. This will tell us if the device is 345 * present or not. Don't stat the minor, just the whole device. 346 * If the device is present and there is a devid, it must also match. 347 * so di_init that one node. No need for DINFOFORCE. 348 */ 349 len = strlen(devpath) + strlen("/devices") + 1; 350 path = topo_mod_alloc(mod, len); 351 (void) snprintf(path, len, "/devices%s", devpath); 352 if (devid == NULL) { 353 if (stat(path, &sb) != -1) 354 present = 1; 355 else if ((dnode = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 356 present = 0; 357 else { 358 if (di_lookup_node(dnode, devpath) == DI_NODE_NIL) 359 present = 0; 360 else 361 present = 1; 362 di_fini(dnode); 363 } 364 } else { 365 if (stat(path, &sb) == -1) 366 present = 0; 367 else if ((dnode = di_init(devpath, DINFOCPYONE)) == DI_NODE_NIL) 368 present = 0; 369 else { 370 if ((id = di_devid(dnode)) == NULL || 371 devid_str_decode(devid, &matchid, NULL) != 0) 372 present = 0; 373 else { 374 if (devid_compare(id, matchid) != 0) 375 present = 0; 376 else 377 present = 1; 378 devid_free(matchid); 379 } 380 di_fini(dnode); 381 } 382 } 383 topo_mod_free(mod, path, len); 384 385 if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 386 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 387 if (nvlist_add_uint32(*out, TOPO_METH_PRESENT_RET, present) != 0) { 388 nvlist_free(*out); 389 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 390 } 391 392 return (0); 393 } 394 395 /*ARGSUSED*/ 396 static int 397 dev_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version, 398 nvlist_t *in, nvlist_t **out) 399 { 400 uint8_t fmversion; 401 char *devpath = NULL; 402 uint32_t rval; 403 char *devid = NULL, *path; 404 ddi_devid_t id; 405 ddi_devid_t matchid; 406 di_node_t dnode; 407 struct stat sb; 408 int len; 409 410 if (version > TOPO_METH_REPLACED_VERSION) 411 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 412 413 if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 || 414 fmversion > FM_DEV_SCHEME_VERSION || 415 nvlist_lookup_string(in, FM_FMRI_DEV_PATH, &devpath) != 0) 416 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 417 418 (void) nvlist_lookup_string(in, FM_FMRI_DEV_ID, &devid); 419 420 if (devpath == NULL || strlen(devpath) == 0) 421 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 422 423 /* 424 * stat() the device node in devfs. This will tell us if the device is 425 * present or not. Don't stat the minor, just the whole device. 426 * If the device is present and there is a devid, it must also match. 427 * so di_init that one node. No need for DINFOFORCE. 428 */ 429 len = strlen(devpath) + strlen("/devices") + 1; 430 path = topo_mod_alloc(mod, len); 431 (void) snprintf(path, len, "/devices%s", devpath); 432 if (devid == NULL) { 433 if (stat(path, &sb) != -1) 434 rval = FMD_OBJ_STATE_UNKNOWN; 435 else if ((dnode = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 436 rval = FMD_OBJ_STATE_NOT_PRESENT; 437 else { 438 if (di_lookup_node(dnode, devpath) == DI_NODE_NIL) 439 rval = FMD_OBJ_STATE_NOT_PRESENT; 440 else 441 rval = FMD_OBJ_STATE_UNKNOWN; 442 di_fini(dnode); 443 } 444 } else { 445 if (stat(path, &sb) == -1) 446 rval = FMD_OBJ_STATE_NOT_PRESENT; 447 else if ((dnode = di_init(devpath, DINFOCPYONE)) == DI_NODE_NIL) 448 rval = FMD_OBJ_STATE_NOT_PRESENT; 449 else { 450 if ((id = di_devid(dnode)) == NULL || 451 devid_str_decode(devid, &matchid, NULL) != 0) 452 rval = FMD_OBJ_STATE_UNKNOWN; 453 else { 454 if (devid_compare(id, matchid) != 0) 455 rval = FMD_OBJ_STATE_REPLACED; 456 else 457 rval = FMD_OBJ_STATE_STILL_PRESENT; 458 devid_free(matchid); 459 } 460 di_fini(dnode); 461 } 462 } 463 topo_mod_free(mod, path, len); 464 465 if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 466 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 467 if (nvlist_add_uint32(*out, TOPO_METH_REPLACED_RET, rval) != 0) { 468 nvlist_free(*out); 469 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 470 } 471 472 return (0); 473 } 474 475 /*ARGSUSED*/ 476 static int 477 dev_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, 478 nvlist_t *in, nvlist_t **out) 479 { 480 di_node_t dnode; 481 uint8_t fmversion; 482 char *devpath = NULL; 483 uint32_t unusable; 484 uint_t state; 485 486 if (version > TOPO_METH_UNUSABLE_VERSION) 487 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 488 489 if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 || 490 fmversion > FM_DEV_SCHEME_VERSION || 491 nvlist_lookup_string(in, FM_FMRI_DEV_PATH, &devpath) != 0) 492 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 493 494 if (devpath == NULL) 495 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 496 497 if ((dnode = di_init(devpath, DINFOCPYONE)) == DI_NODE_NIL) { 498 if (errno != ENXIO) 499 return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); 500 unusable = 1; 501 } else { 502 uint_t retired = di_retired(dnode); 503 state = di_state(dnode); 504 if (retired || (state & (DI_DEVICE_OFFLINE | DI_DEVICE_DOWN | 505 DI_BUS_QUIESCED | DI_BUS_DOWN))) 506 unusable = 1; 507 else 508 unusable = 0; 509 di_fini(dnode); 510 } 511 512 if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 513 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 514 if (nvlist_add_uint32(*out, TOPO_METH_UNUSABLE_RET, unusable) != 0) { 515 nvlist_free(*out); 516 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 517 } 518 519 return (0); 520 } 521 522 /*ARGSUSED*/ 523 static int 524 dev_fmri_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version, 525 nvlist_t *in, nvlist_t **out) 526 { 527 di_node_t dnode; 528 uint8_t fmversion; 529 char *devpath = NULL; 530 uint32_t service_state; 531 uint_t state; 532 533 if (version > TOPO_METH_SERVICE_STATE_VERSION) 534 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 535 536 if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 || 537 fmversion > FM_DEV_SCHEME_VERSION || 538 nvlist_lookup_string(in, FM_FMRI_DEV_PATH, &devpath) != 0) 539 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 540 541 if (devpath == NULL) 542 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 543 544 if ((dnode = di_init(devpath, DINFOCPYONE)) == DI_NODE_NIL) { 545 if (errno != ENXIO) 546 return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); 547 service_state = FMD_SERVICE_STATE_UNUSABLE; 548 } else { 549 uint_t retired = di_retired(dnode); 550 state = di_state(dnode); 551 if (retired || (state & (DI_DEVICE_OFFLINE | DI_DEVICE_DOWN | 552 DI_BUS_QUIESCED | DI_BUS_DOWN))) 553 service_state = FMD_SERVICE_STATE_UNUSABLE; 554 else if (state & DI_DEVICE_DEGRADED) 555 service_state = FMD_SERVICE_STATE_DEGRADED; 556 else 557 service_state = FMD_SERVICE_STATE_OK; 558 di_fini(dnode); 559 } 560 561 if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 562 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 563 if (nvlist_add_uint32(*out, TOPO_METH_SERVICE_STATE_RET, 564 service_state) != 0) { 565 nvlist_free(*out); 566 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 567 } 568 569 return (0); 570 } 571 572 static nvlist_t * 573 dev_fmri_create(topo_mod_t *mp, const char *id, const char *path) 574 { 575 nvlist_t *out = NULL; 576 int e; 577 578 if (topo_mod_nvalloc(mp, &out, NV_UNIQUE_NAME) != 0) { 579 (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); 580 return (NULL); 581 } 582 e = nvlist_add_string(out, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV); 583 e |= nvlist_add_uint8(out, FM_VERSION, FM_DEV_SCHEME_VERSION); 584 e |= nvlist_add_string(out, FM_FMRI_DEV_PATH, path); 585 586 if (id != NULL) 587 e |= nvlist_add_string(out, FM_FMRI_DEV_ID, id); 588 589 if (e == 0) 590 return (out); 591 592 topo_mod_dprintf(mp, "construction of dev nvl failed"); 593 (void) topo_mod_seterrno(mp, EMOD_FMRI_NVL); 594 nvlist_free(out); 595 return (NULL); 596 } 597 598 /*ARGSUSED*/ 599 static int 600 dev_fmri_create_meth(topo_mod_t *mp, tnode_t *node, topo_version_t version, 601 nvlist_t *in, nvlist_t **out) 602 { 603 nvlist_t *args = NULL; 604 char *path, *id = NULL; 605 606 if (version > TOPO_METH_FMRI_VERSION) 607 return (topo_mod_seterrno(mp, EMOD_VER_NEW)); 608 609 if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args) != 0 || 610 nvlist_lookup_string(args, FM_FMRI_DEV_PATH, &path) != 0) { 611 topo_mod_dprintf(mp, "no path string in method argument\n"); 612 return (topo_mod_seterrno(mp, EMOD_METHOD_INVAL)); 613 } 614 615 (void) nvlist_lookup_string(args, FM_FMRI_DEV_ID, &id); 616 617 if ((*out = dev_fmri_create(mp, id, path)) == NULL) 618 return (-1); 619 return (0); 620 } 621