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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <strings.h> 29 #include <devid.h> 30 #include <pthread.h> 31 #include <inttypes.h> 32 #include <sys/dkio.h> 33 #include <sys/scsi/scsi_types.h> 34 #include <fm/topo_mod.h> 35 #include <fm/topo_list.h> 36 #include <fm/libdiskstatus.h> 37 #include <sys/fm/protocol.h> 38 #include "disk.h" 39 40 static int disk_status(topo_mod_t *, tnode_t *, topo_version_t, 41 nvlist_t *, nvlist_t **); 42 43 /* 44 * Given a /devices path for a whole disk, appending this extension gives the 45 * path to a raw device that can be opened. 46 */ 47 #if defined(__i386) || defined(__amd64) 48 #define PHYS_EXTN ":q,raw" 49 #elif defined(__sparc) || defined(__sparcv9) 50 #define PHYS_EXTN ":c,raw" 51 #else 52 #error Unknown architecture 53 #endif 54 55 static int disk_enum(topo_mod_t *, tnode_t *, const char *, 56 topo_instance_t, topo_instance_t, void *, void *); 57 58 static const topo_modops_t disk_ops = 59 { disk_enum, NULL }; 60 61 const topo_modinfo_t disk_info = 62 {DISK, FM_FMRI_SCHEME_HC, DISK_VERSION, &disk_ops}; 63 64 static const topo_pgroup_info_t io_pgroup = 65 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 66 67 static const topo_pgroup_info_t disk_auth_pgroup = { 68 FM_FMRI_AUTHORITY, 69 TOPO_STABILITY_PRIVATE, 70 TOPO_STABILITY_PRIVATE, 71 }; 72 73 static const topo_pgroup_info_t storage_pgroup = { 74 TOPO_STORAGE_PGROUP, 75 TOPO_STABILITY_PRIVATE, 76 TOPO_STABILITY_PRIVATE, 77 1 78 }; 79 80 /* 81 * Methods for disks. This is used by the disk-transport module to 82 * generate ereports based off SCSI disk status. 83 */ 84 static const topo_method_t disk_methods[] = { 85 { TOPO_METH_DISK_STATUS, TOPO_METH_DISK_STATUS_DESC, 86 TOPO_METH_DISK_STATUS_VERSION, TOPO_STABILITY_INTERNAL, 87 disk_status }, 88 { NULL } 89 }; 90 static di_devlink_handle_t devlink_hdl = NULL; 91 92 /* disk node information */ 93 typedef struct disk_di_node { 94 topo_list_t ddn_list; 95 int ddn_instance; 96 char *ddn_devid; 97 di_node_t ddn_node; 98 char *ddn_lpath; /* logical path */ 99 char *ddn_dpath; /* device path */ 100 }disk_di_node_t; 101 102 typedef struct disk_di_nodes { 103 pthread_mutex_t disk_di_nodes_lock; 104 topo_list_t disk_di_nodes_list; 105 }disk_di_nodes_t; 106 107 /* list of devices */ 108 static disk_di_nodes_t disk_di_nodes; 109 110 /* given a device find it in the global device list */ 111 static disk_di_node_t * 112 disk_di_node_match_device(char *device) 113 { 114 disk_di_node_t *dnode; 115 116 (void) pthread_mutex_lock(&disk_di_nodes.disk_di_nodes_lock); 117 for (dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list)); 118 dnode != NULL; dnode = topo_list_next(dnode)) { 119 if (dnode->ddn_devid != NULL && 120 strcmp(device, 121 dnode->ddn_dpath) == 0) { 122 (void) pthread_mutex_unlock( 123 &disk_di_nodes.disk_di_nodes_lock); 124 return (dnode); 125 } 126 } 127 (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); 128 return (NULL); 129 } 130 131 /* get the disk storage group information */ 132 static void 133 disk_storage_info(topo_mod_t *mod, disk_di_node_t *dnode, 134 char **model, char **manuf, char **serial, char **firm, char **cap) 135 { 136 char *entry; 137 di_node_t node = dnode->ddn_node; 138 int64_t *nblocksp; 139 uint64_t nblocks; 140 int *dblksizep; 141 uint_t dblksize; 142 char lentry[MAXPATHLEN]; 143 144 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 145 INQUIRY_VENDOR_ID, &entry) > 0) { 146 *manuf = topo_mod_strdup(mod, entry); 147 } 148 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 149 INQUIRY_PRODUCT_ID, &entry) > 0) { 150 *model = topo_mod_strdup(mod, entry); 151 } 152 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 153 INQUIRY_REVISION_ID, &entry) > 0) { 154 *firm = topo_mod_strdup(mod, entry); 155 } 156 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 157 INQUIRY_SERIAL_NO, &entry) > 0) { 158 *serial = topo_mod_strdup(mod, entry); 159 } 160 if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, 161 "device-nblocks", &nblocksp) > 0) { 162 nblocks = (uint64_t)*nblocksp; 163 /* 164 * To save kernel memory, the driver may not 165 * define "device-dblksize" when its value is 166 * the default DEV_BSIZE value. 167 */ 168 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 169 "device-dblksize", &dblksizep) > 0) 170 dblksize = (uint_t)*dblksizep; 171 else 172 dblksize = DEV_BSIZE; /* default value */ 173 (void) snprintf(lentry, sizeof (lentry), 174 "%" PRIu64, nblocks * dblksize); 175 *cap = topo_mod_strdup(mod, lentry); 176 } 177 } 178 179 /* populate the protocol group properties */ 180 static void 181 disk_set_proto_props(topo_mod_t *mod, tnode_t *dtn, int pinst) 182 { 183 int err; 184 nvlist_t *asru = NULL; 185 char label[32]; 186 char *func = "disk_set_proto_props"; 187 nvlist_t *fmri; 188 disk_di_node_t *dnode; 189 190 /* set the asru */ 191 dnode = topo_node_getspecific(dtn); 192 asru = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION, 193 dnode->ddn_dpath, dnode->ddn_devid); 194 if (topo_node_asru_set(dtn, asru, 0, &err) != 0) { 195 topo_mod_dprintf(mod, 196 "%s: topo_node_asru_set error %d\n", 197 func, err); 198 nvlist_free(asru); 199 (void) topo_mod_seterrno(mod, err); 200 return; 201 } 202 nvlist_free(asru); 203 204 (void) snprintf(label, sizeof (label), "HD_ID_%d", pinst); 205 if (topo_node_label_set(dtn, label, &err) != 0) { 206 topo_mod_dprintf(mod, "%s: label error %s\n", func, 207 topo_strerror(err)); 208 (void) topo_mod_seterrno(mod, err); 209 return; 210 } 211 212 /* get the resource property */ 213 if (topo_node_resource(dtn, &fmri, &err) != 0) { 214 topo_mod_dprintf(mod, 215 "%s: topo_node_resource error: %s\n", func, 216 topo_strerror(err)); 217 (void) topo_mod_seterrno(mod, err); 218 return; 219 } 220 221 /* set the child fru to the same as the resource */ 222 if (topo_node_fru_set(dtn, fmri, 0, &err) != 0) { 223 topo_mod_dprintf(mod, 224 "%s: topo_node_fru_set error: %s\n", func, 225 topo_strerror(err)); 226 (void) topo_mod_seterrno(mod, err); 227 nvlist_free(fmri); 228 return; 229 } 230 nvlist_free(fmri); 231 } 232 233 234 /* 235 * Set the properties of the disk node which include: 236 * group: protocol properties: resource, asru, label, fru 237 * group: authority properties: product-id, chasis-id, server-id 238 * group: io properties: devfs-path 239 * group: storage properties: 240 * - logical-disk, disk-model, disk-manufacturer, serial-number 241 * - firmware-revision, capacity-in-bytes 242 */ 243 static void 244 disk_set_props(tnode_t *dtn, tnode_t *parent, char *model, char *manuf, 245 char *serial, char *firm, char *cap, int *err, topo_mod_t *mod) 246 { 247 char *device; 248 char *ptr, *ptr1; 249 int inst = topo_node_instance(parent); 250 disk_di_node_t *dnode; 251 252 dnode = topo_node_getspecific(dtn); 253 254 /* set the protocol group properties */ 255 disk_set_proto_props(mod, dtn, inst); 256 257 /* create/set the authority group */ 258 if (topo_pgroup_create(dtn, &disk_auth_pgroup, err) == 0) { 259 (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY, 260 FM_FMRI_AUTH_PRODUCT, err); 261 (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY, 262 FM_FMRI_AUTH_CHASSIS, err); 263 (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY, 264 FM_FMRI_AUTH_SERVER, err); 265 } 266 267 /* create/set the devfs-path in the io group */ 268 (void) topo_pgroup_create(dtn, &io_pgroup, err); 269 270 if (topo_prop_get_string(parent, TOPO_BINDING_PGROUP, 271 TOPO_BINDING_OCCUPANT, &device, err) == 0) { 272 (void) topo_prop_set_string(dtn, TOPO_PGROUP_IO, 273 TOPO_IO_DEV_PATH, TOPO_PROP_IMMUTABLE, device, err); 274 275 topo_mod_strfree(mod, device); 276 } 277 278 /* create the storage group */ 279 (void) topo_pgroup_create(dtn, &storage_pgroup, err); 280 281 /* set the storage group properties */ 282 ptr = strrchr(dnode->ddn_lpath, '/'); 283 ptr1 = strchr(ptr, 's'); 284 if (ptr1) 285 *ptr1 = '\0'; 286 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 287 TOPO_STORAGE_LOGICAL_DISK_NAME, TOPO_PROP_IMMUTABLE, 288 ptr+1, err); 289 if (ptr1) 290 *ptr1 = 's'; 291 292 293 /* populate the storage group properties */ 294 if (model) { 295 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 296 TOPO_STORAGE_MODEL, TOPO_PROP_IMMUTABLE, model, err); 297 } 298 if (manuf) { 299 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 300 TOPO_STORAGE_MANUFACTURER, TOPO_PROP_IMMUTABLE, manuf, 301 err); 302 } 303 if (serial) { 304 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 305 TOPO_STORAGE_SERIAL_NUM, TOPO_PROP_IMMUTABLE, serial, err); 306 } 307 if (firm) { 308 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 309 TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE, firm, err); 310 } 311 if (cap) { 312 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 313 TOPO_STORAGE_CAPACITY, TOPO_PROP_IMMUTABLE, cap, err); 314 } 315 } 316 317 /* create the disk topo node */ 318 /*ARGSUSED*/ 319 static tnode_t * 320 disk_tnode_create(topo_mod_t *mod, tnode_t *parent, 321 const char *name, topo_instance_t i, char *model, char *manuf, 322 char *serial, char *firm, char *cap, void *priv) 323 { 324 int err, len = 0; 325 nvlist_t *fmri; 326 tnode_t *dtn; 327 char *mm = NULL; 328 char *s; 329 nvlist_t *auth = topo_mod_auth(mod, parent); 330 331 if ((s = strchr(model, ' ')) != NULL) { 332 *s = '-'; 333 } 334 len = strlen(manuf) + strlen(model) + 2; 335 if ((mm = topo_mod_alloc(mod, len)) != NULL) 336 (void) snprintf(mm, len, "%s-%s", manuf, model); 337 else 338 mm = model; 339 340 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, 341 NULL, auth, mm, firm, serial); 342 343 nvlist_free(auth); 344 345 if (mm != model) 346 topo_mod_free(mod, mm, len); 347 else if (*s != NULL) 348 *s = ' '; 349 350 if (fmri == NULL) { 351 topo_mod_dprintf(mod, 352 "Unable to make nvlist for %s bind: %s.\n", 353 name, topo_mod_errmsg(mod)); 354 return (NULL); 355 } 356 357 if ((dtn = topo_node_bind(mod, parent, name, i, fmri)) == NULL) { 358 topo_mod_dprintf(mod, 359 "topo_node_bind (%s%d/%s%d) failed: %s\n", 360 topo_node_name(parent), topo_node_instance(parent), 361 name, i, 362 topo_strerror(topo_mod_errno(mod))); 363 nvlist_free(fmri); 364 return (NULL); 365 } 366 nvlist_free(fmri); 367 topo_node_setspecific(dtn, priv); 368 369 /* add the properties of the disk */ 370 disk_set_props(dtn, parent, model, manuf, serial, firm, cap, 371 &err, mod); 372 373 return (dtn); 374 } 375 376 /*ARGSUSED*/ 377 static tnode_t * 378 disk_declare(tnode_t *parent, const char *name, topo_instance_t i, 379 void *priv, topo_mod_t *mod) 380 { 381 tnode_t *dtn; 382 int err; 383 char *func = "disk_declare"; 384 char *model = NULL, *manuf = NULL, *serial = NULL; 385 char *cap = NULL, *firm = NULL; 386 disk_di_node_t *dnode = (disk_di_node_t *)priv; 387 nvlist_t *fmri; 388 389 disk_storage_info(mod, dnode, 390 &model, &manuf, &serial, &firm, &cap); 391 392 /* create the node */ 393 dtn = disk_tnode_create(mod, parent, 394 name, i, model, manuf, serial, firm, cap, priv); 395 396 topo_mod_strfree(mod, model); 397 topo_mod_strfree(mod, manuf); 398 topo_mod_strfree(mod, serial); 399 topo_mod_strfree(mod, firm); 400 topo_mod_strfree(mod, cap); 401 402 if (dtn == NULL) { 403 return (NULL); 404 } 405 406 /* set the parent fru */ 407 if (topo_node_resource(parent, &fmri, &err) != 0) { 408 topo_mod_dprintf(mod, 409 "%s: topo_node_resource error: %s\n", func, 410 topo_strerror(err)); 411 topo_node_unbind(dtn); 412 return (NULL); 413 } 414 if (topo_node_fru_set(parent, fmri, 0, &err) != 0) { 415 topo_mod_dprintf(mod, "%s topo_node_fru error: %s\n", 416 func, topo_strerror(err)); 417 nvlist_free(fmri); 418 topo_node_unbind(dtn); 419 return (NULL); 420 } 421 422 if (topo_method_register(mod, dtn, disk_methods) != 0) { 423 topo_mod_dprintf(mod, 424 "topo_method_register failed: %s\n", 425 topo_strerror(topo_mod_errno(mod))); 426 nvlist_free(fmri); 427 topo_node_unbind(dtn); 428 return (NULL); 429 } 430 431 nvlist_free(fmri); 432 433 return (dtn); 434 } 435 436 /*ARGSUSED*/ 437 static int 438 disk_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, 439 topo_instance_t min, topo_instance_t max, void *arg, void *notused) 440 { 441 tnode_t *diskn; 442 char *device; 443 int err; 444 disk_di_node_t *dnode; 445 446 if (strcmp(name, DISK) != 0) { 447 topo_mod_dprintf(mod, 448 "Currently only know how to enumerate %s components.\n", 449 DISK); 450 return (-1); 451 } 452 453 if (topo_prop_get_string(rnode, TOPO_BINDING_PGROUP, 454 TOPO_BINDING_OCCUPANT, &device, &err) != 0) 455 return (-1); 456 457 if ((dnode = disk_di_node_match_device(device)) == NULL) { 458 topo_mod_dprintf(mod, 459 "No occupant found for bay=%d.\n", 460 topo_node_instance(rnode)); 461 topo_mod_strfree(mod, device); 462 return (-1); 463 } 464 465 diskn = disk_declare(rnode, name, 0, dnode, mod); 466 if (diskn == NULL) { 467 topo_mod_dprintf(mod, "Enumeration of %s failed: %s\n", 468 DISK, topo_strerror(topo_mod_errno(mod))); 469 topo_mod_strfree(mod, device); 470 return (-1); /* mod_errno already set */ 471 } 472 topo_mod_strfree(mod, device); 473 return (0); 474 } 475 476 /* 477 * Query the current disk status. If successful, the disk status is returned as 478 * an nvlist consisting of at least the following members: 479 * 480 * protocol string Supported protocol (currently "scsi") 481 * 482 * status nvlist Arbitrary protocol-specific information 483 * about the current state of the disk. 484 * 485 * faults nvlist A list of supported faults. Each 486 * element of this list is a boolean value. 487 * An element's existence indicates that 488 * the drive supports detecting this fault, 489 * and the value indicates the current 490 * state of the fault. 491 * 492 * <fault-name> nvlist For each fault named in 'faults', a 493 * nvlist describing protocol-specific 494 * attributes of the fault. 495 * 496 * This method relies on the libdiskstatus library to query this information. 497 */ 498 static int 499 disk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers, 500 nvlist_t *in_nvl, nvlist_t **out_nvl) 501 { 502 disk_status_t *dsp; 503 char *devpath, *fullpath; 504 size_t pathlen; 505 int err; 506 nvlist_t *status; 507 *out_nvl = NULL; 508 509 if (vers != TOPO_METH_DISK_STATUS_VERSION) 510 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 511 512 /* 513 * If the caller specifies the "path" parameter, then this indicates 514 * that we should use this instead of deriving it from the topo node 515 * itself. 516 */ 517 if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) { 518 devpath = NULL; 519 } else { 520 /* 521 * Get the /devices path and attempt to open the disk status 522 * handle. 523 */ 524 if (topo_prop_get_string(nodep, TOPO_PGROUP_IO, 525 TOPO_IO_DEV_PATH, &devpath, &err) != 0) 526 return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP)); 527 528 /* 529 * Note that sizeof(string) includes the terminating NULL byte 530 */ 531 pathlen = strlen(devpath) + sizeof ("/devices") + 532 sizeof (PHYS_EXTN) - 1; 533 534 if ((fullpath = topo_mod_alloc(mod, pathlen)) == NULL) 535 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 536 537 (void) snprintf(fullpath, pathlen, "/devices%s%s", devpath, 538 PHYS_EXTN); 539 540 topo_mod_strfree(mod, devpath); 541 } 542 543 if ((dsp = disk_status_open(fullpath, &err)) == NULL) { 544 if (devpath) 545 topo_mod_free(mod, fullpath, pathlen); 546 return (topo_mod_seterrno(mod, err == EDS_NOMEM ? 547 EMOD_NOMEM : EMOD_METHOD_NOTSUP)); 548 } 549 550 if (devpath) 551 topo_mod_free(mod, fullpath, pathlen); 552 553 if ((status = disk_status_get(dsp)) == NULL) { 554 err = (disk_status_errno(dsp) == EDS_NOMEM ? 555 EMOD_NOMEM : EMOD_METHOD_NOTSUP); 556 disk_status_close(dsp); 557 return (topo_mod_seterrno(mod, err)); 558 } 559 560 *out_nvl = status; 561 disk_status_close(dsp); 562 return (0); 563 } 564 565 /* di_devlink callback for disk_drvinst2devpath */ 566 static int 567 disk_drvinst2devpath_devlink_callback(di_devlink_t dl, void *arg) 568 { 569 char **devpathp = (char **)arg; 570 char *devpath = (char *)di_devlink_path(dl); 571 572 *devpathp = strdup(devpath); 573 return (DI_WALK_TERMINATE); 574 } 575 576 static disk_di_node_t * 577 disk_di_node_add(int *instancep, char *devid, di_node_t node, topo_mod_t *mod) 578 { 579 int mlen; 580 char *devpath, *minorpath; 581 char *extn = ":a"; 582 disk_di_node_t *dnode; 583 584 (void) pthread_mutex_lock(&(disk_di_nodes.disk_di_nodes_lock)); 585 for (dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list)); 586 dnode != NULL; dnode = topo_list_next(dnode)) { 587 if (strcmp(dnode->ddn_devid, devid) == 0) { 588 topo_mod_dprintf(mod, 589 "disk_node_add - already there %s\n", devid); 590 (void) pthread_mutex_unlock( 591 &disk_di_nodes.disk_di_nodes_lock); 592 return (dnode); /* return existing node */ 593 } 594 } 595 596 if ((dnode = topo_mod_alloc(mod, sizeof (disk_di_node_t))) == NULL) { 597 topo_mod_dprintf(mod, 598 "disk_node_add - topo_mod_alloc failed\n"); 599 (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); 600 return (NULL); /* return existing node */ 601 } 602 603 dnode->ddn_devid = strdup(devid); 604 dnode->ddn_instance = *instancep; 605 dnode->ddn_node = node; 606 dnode->ddn_dpath = di_devfs_path(node); 607 608 mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1; 609 minorpath = topo_mod_alloc(mod, mlen); 610 (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, 611 extn); 612 /* walk devlink looking for node that maps to /device path */ 613 devpath = NULL; 614 (void) di_devlink_walk(devlink_hdl, "^dsk/", 615 minorpath, DI_PRIMARY_LINK, 616 (void *)&devpath, disk_drvinst2devpath_devlink_callback); 617 topo_mod_free(mod, minorpath, mlen); 618 dnode->ddn_lpath = devpath; 619 620 topo_list_append(&disk_di_nodes.disk_di_nodes_list, (void *)dnode); 621 (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); 622 623 topo_mod_dprintf(mod, 624 "disk_node_add - adding %s inst: %d\n", 625 dnode->ddn_devid, *instancep); 626 *instancep = (*instancep) + 1; 627 return (dnode); 628 } 629 630 /*ARGSUSED*/ 631 static int 632 disk_walk_di_nodes(di_node_t node, void *arg) 633 { 634 ddi_devid_t devid = NULL; 635 char *devidstr; 636 static int instance_devid = 0; 637 topo_mod_t *mod = (topo_mod_t *)arg; 638 639 /* only interested in nodes that have devids */ 640 devid = (ddi_devid_t)di_devid(node); 641 if (devid == NULL) 642 return (DI_WALK_CONTINUE); 643 644 /* ... with a string representation of the devid */ 645 devidstr = devid_str_encode(devid, NULL); 646 if (devidstr == NULL) 647 return (DI_WALK_CONTINUE); 648 649 /* create/find the devid scsi topology node */ 650 (void) disk_di_node_add(&instance_devid, devidstr, node, mod); 651 devid_str_free(devidstr); 652 return (DI_WALK_CONTINUE); 653 } 654 655 /*ARGSUSED*/ 656 int 657 _topo_init(topo_mod_t *mod, topo_version_t version) 658 { 659 di_node_t devtree; 660 661 /* 662 * Turn on module debugging output 663 */ 664 if (getenv("TOPODISKDEBUG") != NULL) 665 topo_mod_setdebug(mod); 666 topo_mod_dprintf(mod, "initializing %s enumerator\n", DISK); 667 668 if (topo_mod_register(mod, &disk_info, TOPO_VERSION) != 0) { 669 topo_mod_dprintf(mod, "%s registration failed: %s\n", 670 DISK, topo_mod_errmsg(mod)); 671 return (-1); /* mod errno already set */ 672 } 673 674 (void) pthread_mutex_init(&disk_di_nodes.disk_di_nodes_lock, NULL); 675 disk_di_nodes.disk_di_nodes_list.l_next = NULL; 676 disk_di_nodes.disk_di_nodes_list.l_prev = NULL; 677 678 devtree = di_init("/", DINFOCACHE); 679 /* we don't get all the nodes with topo_mod_devinfo */ 680 if (devtree == NULL) { 681 topo_mod_unregister(mod); 682 (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock); 683 topo_mod_dprintf(mod, "topo_mod_devinfo init failed."); 684 return (-1); 685 } 686 /* walk the tree to get the devids */ 687 devlink_hdl = di_devlink_init(NULL, 0); 688 if (devlink_hdl == DI_NODE_NIL) { 689 topo_mod_unregister(mod); 690 (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock); 691 topo_mod_dprintf(mod, "di_devlink init failed."); 692 return (-1); 693 } 694 (void) di_walk_node(devtree, DI_WALK_CLDFIRST, mod, 695 disk_walk_di_nodes); 696 697 if (devlink_hdl != NULL) 698 (void) di_devlink_fini(&devlink_hdl); 699 700 topo_mod_dprintf(mod, "%s enumerator initialized\n", DISK); 701 702 return (0); 703 } 704 705 void 706 _topo_fini(topo_mod_t *mod) 707 { 708 disk_di_node_t *dnode; 709 710 (void) pthread_mutex_lock(&disk_di_nodes.disk_di_nodes_lock); 711 while ((dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list))) 712 != NULL) { 713 free(dnode->ddn_lpath); 714 free(dnode->ddn_dpath); 715 free(dnode->ddn_devid); 716 topo_list_delete(&(disk_di_nodes.disk_di_nodes_list), 717 (void *)dnode); 718 topo_mod_free(mod, dnode, sizeof (disk_di_node_t)); 719 } 720 (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); 721 (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock); 722 topo_mod_unregister(mod); 723 } 724