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 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 topo_prop_get_string(parent, TOPO_BINDING_PGROUP, TOPO_BINDING_OCCUPANT, 253 &device, err); 254 255 dnode = topo_node_getspecific(dtn); 256 257 /* set the protocol group properties */ 258 disk_set_proto_props(mod, dtn, inst); 259 260 /* create/set the authority group */ 261 if (topo_pgroup_create(dtn, &disk_auth_pgroup, err) == 0) { 262 (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY, 263 FM_FMRI_AUTH_PRODUCT, err); 264 (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY, 265 FM_FMRI_AUTH_CHASSIS, err); 266 (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY, 267 FM_FMRI_AUTH_SERVER, err); 268 } 269 270 /* create/set the devfs-path in the io group */ 271 (void) topo_pgroup_create(dtn, &io_pgroup, err); 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 /* create the storage group */ 278 (void) topo_pgroup_create(dtn, &storage_pgroup, err); 279 280 /* set the storage group properties */ 281 ptr = strrchr(dnode->ddn_lpath, '/'); 282 ptr1 = strchr(ptr, 's'); 283 if (ptr1) 284 *ptr1 = '\0'; 285 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 286 TOPO_STORAGE_LOGICAL_DISK_NAME, TOPO_PROP_IMMUTABLE, 287 ptr+1, err); 288 if (ptr1) 289 *ptr1 = 's'; 290 291 292 /* populate the storage group properties */ 293 if (model) { 294 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 295 TOPO_STORAGE_MODEL, TOPO_PROP_IMMUTABLE, model, err); 296 } 297 if (manuf) { 298 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 299 TOPO_STORAGE_MANUFACTURER, TOPO_PROP_IMMUTABLE, manuf, 300 err); 301 } 302 if (serial) { 303 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 304 TOPO_STORAGE_SERIAL_NUM, TOPO_PROP_IMMUTABLE, serial, err); 305 } 306 if (firm) { 307 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 308 TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE, firm, err); 309 } 310 if (cap) { 311 (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, 312 TOPO_STORAGE_CAPACITY, TOPO_PROP_IMMUTABLE, cap, err); 313 } 314 } 315 316 /* create the disk topo node */ 317 /*ARGSUSED*/ 318 static tnode_t * 319 disk_tnode_create(topo_mod_t *mod, tnode_t *parent, 320 const char *name, topo_instance_t i, char *model, char *manuf, 321 char *serial, char *firm, char *cap, void *priv) 322 { 323 int err, len = 0; 324 nvlist_t *fmri; 325 tnode_t *dtn; 326 char *mm = NULL; 327 char *s; 328 nvlist_t *auth = topo_mod_auth(mod, parent); 329 330 if ((s = strchr(model, ' ')) != NULL) { 331 *s = '-'; 332 } 333 len = strlen(manuf) + strlen(model) + 2; 334 if ((mm = topo_mod_alloc(mod, len)) != NULL) 335 (void) snprintf(mm, len, "%s-%s", manuf, model); 336 else 337 mm = model; 338 339 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, 340 NULL, auth, mm, firm, serial); 341 342 nvlist_free(auth); 343 344 if (mm != model) 345 topo_mod_free(mod, mm, len); 346 else if (*s != NULL) 347 *s = ' '; 348 349 if (fmri == NULL) { 350 topo_mod_dprintf(mod, 351 "Unable to make nvlist for %s bind: %s.\n", 352 name, topo_mod_errmsg(mod)); 353 return (NULL); 354 } 355 356 if ((dtn = topo_node_bind(mod, parent, name, i, fmri)) == NULL) { 357 topo_mod_dprintf(mod, 358 "topo_node_bind (%s%d/%s%d) failed: %s\n", 359 topo_node_name(parent), topo_node_instance(parent), 360 name, i, 361 topo_strerror(topo_mod_errno(mod))); 362 nvlist_free(fmri); 363 return (NULL); 364 } 365 nvlist_free(fmri); 366 topo_node_setspecific(dtn, priv); 367 368 /* add the properties of the disk */ 369 disk_set_props(dtn, parent, model, manuf, serial, firm, cap, 370 &err, mod); 371 372 return (dtn); 373 } 374 375 /*ARGSUSED*/ 376 static tnode_t * 377 disk_declare(tnode_t *parent, const char *name, topo_instance_t i, 378 void *priv, topo_mod_t *mod) 379 { 380 tnode_t *dtn; 381 int err; 382 char *func = "disk_declare"; 383 char *model = NULL, *manuf = NULL, *serial = NULL; 384 char *cap = NULL, *firm = NULL; 385 disk_di_node_t *dnode = (disk_di_node_t *)priv; 386 nvlist_t *fmri; 387 388 disk_storage_info(mod, dnode, 389 &model, &manuf, &serial, &firm, &cap); 390 391 /* create the node */ 392 dtn = disk_tnode_create(mod, parent, 393 name, i, model, manuf, serial, firm, cap, priv); 394 395 topo_mod_strfree(mod, model); 396 topo_mod_strfree(mod, manuf); 397 topo_mod_strfree(mod, serial); 398 topo_mod_strfree(mod, firm); 399 topo_mod_strfree(mod, cap); 400 401 if (dtn == NULL) { 402 return (NULL); 403 } 404 405 /* set the parent fru */ 406 if (topo_node_resource(parent, &fmri, &err) != 0) { 407 topo_mod_dprintf(mod, 408 "%s: topo_node_resource error: %s\n", func, 409 topo_strerror(err)); 410 topo_node_unbind(dtn); 411 return (NULL); 412 } 413 if (topo_node_fru_set(parent, fmri, 0, &err) != 0) { 414 topo_mod_dprintf(mod, "%s topo_node_fru error: %s\n", 415 func, topo_strerror(err)); 416 nvlist_free(fmri); 417 topo_node_unbind(dtn); 418 return (NULL); 419 } 420 421 if (topo_method_register(mod, dtn, disk_methods) != 0) { 422 topo_mod_dprintf(mod, 423 "topo_method_register failed: %s\n", 424 topo_strerror(topo_mod_errno(mod))); 425 nvlist_free(fmri); 426 topo_node_unbind(dtn); 427 return (NULL); 428 } 429 430 nvlist_free(fmri); 431 432 return (dtn); 433 } 434 435 /*ARGSUSED*/ 436 static int 437 disk_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, 438 topo_instance_t min, topo_instance_t max, void *arg, void *notused) 439 { 440 tnode_t *diskn; 441 char *device; 442 int err; 443 disk_di_node_t *dnode; 444 445 if (strcmp(name, DISK) != 0) { 446 topo_mod_dprintf(mod, 447 "Currently only know how to enumerate %s components.\n", 448 DISK); 449 return (-1); 450 } 451 452 topo_prop_get_string(rnode, TOPO_BINDING_PGROUP, TOPO_BINDING_OCCUPANT, 453 &device, &err); 454 455 if ((dnode = disk_di_node_match_device(device)) == NULL) { 456 topo_mod_dprintf(mod, 457 "No occupant found for bay=%d.\n", 458 topo_node_instance(rnode)); 459 topo_mod_strfree(mod, device); 460 return (-1); 461 } 462 463 diskn = disk_declare(rnode, name, 0, dnode, mod); 464 if (diskn == NULL) { 465 topo_mod_dprintf(mod, "Enumeration of %s failed: %s\n", 466 DISK, topo_strerror(topo_mod_errno(mod))); 467 topo_mod_strfree(mod, device); 468 return (-1); /* mod_errno already set */ 469 } 470 topo_mod_strfree(mod, device); 471 return (0); 472 } 473 474 /* 475 * Query the current disk status. If successful, the disk status is returned as 476 * an nvlist consisting of at least the following members: 477 * 478 * protocol string Supported protocol (currently "scsi") 479 * 480 * status nvlist Arbitrary protocol-specific information 481 * about the current state of the disk. 482 * 483 * faults nvlist A list of supported faults. Each 484 * element of this list is a boolean value. 485 * An element's existence indicates that 486 * the drive supports detecting this fault, 487 * and the value indicates the current 488 * state of the fault. 489 * 490 * <fault-name> nvlist For each fault named in 'faults', a 491 * nvlist describing protocol-specific 492 * attributes of the fault. 493 * 494 * This method relies on the libdiskstatus library to query this information. 495 */ 496 static int 497 disk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers, 498 nvlist_t *in_nvl, nvlist_t **out_nvl) 499 { 500 disk_status_t *dsp; 501 char *devpath, *fullpath; 502 size_t pathlen; 503 int err; 504 nvlist_t *status; 505 *out_nvl = NULL; 506 507 if (vers != TOPO_METH_DISK_STATUS_VERSION) 508 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 509 510 /* 511 * If the caller specifies the "path" parameter, then this indicates 512 * that we should use this instead of deriving it from the topo node 513 * itself. 514 */ 515 if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) { 516 devpath = NULL; 517 } else { 518 /* 519 * Get the /devices path and attempt to open the disk status 520 * handle. 521 */ 522 if (topo_prop_get_string(nodep, TOPO_PGROUP_IO, 523 TOPO_IO_DEV_PATH, &devpath, &err) != 0) 524 return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP)); 525 526 /* 527 * Note that sizeof(string) includes the terminating NULL byte 528 */ 529 pathlen = strlen(devpath) + sizeof ("/devices") + 530 sizeof (PHYS_EXTN) - 1; 531 532 if ((fullpath = topo_mod_alloc(mod, pathlen)) == NULL) 533 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 534 535 (void) snprintf(fullpath, pathlen, "/devices%s%s", devpath, 536 PHYS_EXTN); 537 538 topo_mod_strfree(mod, devpath); 539 } 540 541 if ((dsp = disk_status_open(fullpath, &err)) == NULL) { 542 if (devpath) 543 topo_mod_free(mod, fullpath, pathlen); 544 return (topo_mod_seterrno(mod, err == EDS_NOMEM ? 545 EMOD_NOMEM : EMOD_METHOD_NOTSUP)); 546 } 547 548 if (devpath) 549 topo_mod_free(mod, fullpath, pathlen); 550 551 if ((status = disk_status_get(dsp)) == NULL) { 552 err = (disk_status_errno(dsp) == EDS_NOMEM ? 553 EMOD_NOMEM : EMOD_METHOD_NOTSUP); 554 disk_status_close(dsp); 555 return (topo_mod_seterrno(mod, err)); 556 } 557 558 *out_nvl = status; 559 disk_status_close(dsp); 560 return (0); 561 } 562 563 /* di_devlink callback for disk_drvinst2devpath */ 564 static int 565 disk_drvinst2devpath_devlink_callback(di_devlink_t dl, void *arg) 566 { 567 char **devpathp = (char **)arg; 568 char *devpath = (char *)di_devlink_path(dl); 569 570 *devpathp = strdup(devpath); 571 return (DI_WALK_TERMINATE); 572 } 573 574 static disk_di_node_t * 575 disk_di_node_add(int *instancep, char *devid, di_node_t node, topo_mod_t *mod) 576 { 577 int mlen; 578 char *devpath, *minorpath; 579 char *extn = ":a"; 580 disk_di_node_t *dnode; 581 582 (void) pthread_mutex_lock(&(disk_di_nodes.disk_di_nodes_lock)); 583 for (dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list)); 584 dnode != NULL; dnode = topo_list_next(dnode)) { 585 if (strcmp(dnode->ddn_devid, devid) == 0) { 586 topo_mod_dprintf(mod, 587 "disk_node_add - already there %s\n", devid); 588 (void) pthread_mutex_unlock( 589 &disk_di_nodes.disk_di_nodes_lock); 590 return (dnode); /* return existing node */ 591 } 592 } 593 594 if ((dnode = topo_mod_alloc(mod, sizeof (disk_di_node_t))) == NULL) { 595 topo_mod_dprintf(mod, 596 "disk_node_add - topo_mod_alloc failed\n"); 597 (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); 598 return (NULL); /* return existing node */ 599 } 600 601 dnode->ddn_devid = strdup(devid); 602 dnode->ddn_instance = *instancep; 603 dnode->ddn_node = node; 604 dnode->ddn_dpath = di_devfs_path(node); 605 606 mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1; 607 minorpath = topo_mod_alloc(mod, mlen); 608 (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, 609 extn); 610 /* walk devlink looking for node that maps to /device path */ 611 devpath = NULL; 612 (void) di_devlink_walk(devlink_hdl, "^dsk/", 613 minorpath, DI_PRIMARY_LINK, 614 (void *)&devpath, disk_drvinst2devpath_devlink_callback); 615 topo_mod_free(mod, minorpath, mlen); 616 dnode->ddn_lpath = devpath; 617 618 topo_list_append(&disk_di_nodes.disk_di_nodes_list, (void *)dnode); 619 (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); 620 621 topo_mod_dprintf(mod, 622 "disk_node_add - adding %s inst: %d\n", 623 dnode->ddn_devid, *instancep); 624 *instancep = (*instancep) + 1; 625 return (dnode); 626 } 627 628 /*ARGSUSED*/ 629 static int 630 disk_walk_di_nodes(di_node_t node, void *arg) 631 { 632 ddi_devid_t devid = NULL; 633 char *devidstr; 634 static int instance_devid = 0; 635 topo_mod_t *mod = (topo_mod_t *)arg; 636 637 /* only interested in nodes that have devids */ 638 devid = (ddi_devid_t)di_devid(node); 639 if (devid == NULL) 640 return (DI_WALK_CONTINUE); 641 642 /* ... with a string representation of the devid */ 643 devidstr = devid_str_encode(devid, NULL); 644 if (devidstr == NULL) 645 return (DI_WALK_CONTINUE); 646 647 /* create/find the devid scsi topology node */ 648 (void) disk_di_node_add(&instance_devid, devidstr, node, mod); 649 devid_str_free(devidstr); 650 return (DI_WALK_CONTINUE); 651 } 652 653 /*ARGSUSED*/ 654 int 655 _topo_init(topo_mod_t *mod, topo_version_t version) 656 { 657 di_node_t devtree; 658 659 /* 660 * Turn on module debugging output 661 */ 662 if (getenv("TOPODISKDEBUG") != NULL) 663 topo_mod_setdebug(mod); 664 topo_mod_dprintf(mod, "initializing %s enumerator\n", DISK); 665 666 if (topo_mod_register(mod, &disk_info, TOPO_VERSION) != 0) { 667 topo_mod_dprintf(mod, "%s registration failed: %s\n", 668 DISK, topo_mod_errmsg(mod)); 669 return (-1); /* mod errno already set */ 670 } 671 672 (void) pthread_mutex_init(&disk_di_nodes.disk_di_nodes_lock, NULL); 673 disk_di_nodes.disk_di_nodes_list.l_next = NULL; 674 disk_di_nodes.disk_di_nodes_list.l_prev = NULL; 675 676 devtree = di_init("/", DINFOCACHE); 677 /* we don't get all the nodes with topo_mod_devinfo */ 678 if (devtree == NULL) { 679 topo_mod_unregister(mod); 680 (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock); 681 topo_mod_dprintf(mod, "topo_mod_devinfo init failed."); 682 return (-1); 683 } 684 /* walk the tree to get the devids */ 685 devlink_hdl = di_devlink_init(NULL, 0); 686 if (devlink_hdl == DI_NODE_NIL) { 687 topo_mod_unregister(mod); 688 (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock); 689 topo_mod_dprintf(mod, "di_devlink init failed."); 690 return (-1); 691 } 692 (void) di_walk_node(devtree, DI_WALK_CLDFIRST, mod, 693 disk_walk_di_nodes); 694 695 if (devlink_hdl != NULL) 696 (void) di_devlink_fini(&devlink_hdl); 697 698 topo_mod_dprintf(mod, "%s enumerator initialized\n", DISK); 699 700 return (0); 701 } 702 703 void 704 _topo_fini(topo_mod_t *mod) 705 { 706 disk_di_node_t *dnode; 707 708 (void) pthread_mutex_lock(&disk_di_nodes.disk_di_nodes_lock); 709 while ((dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list))) 710 != NULL) { 711 free(dnode->ddn_lpath); 712 free(dnode->ddn_dpath); 713 free(dnode->ddn_devid); 714 topo_list_delete(&(disk_di_nodes.disk_di_nodes_list), 715 (void *)dnode); 716 topo_mod_free(mod, dnode, sizeof (disk_di_node_t)); 717 } 718 (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); 719 (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock); 720 topo_mod_unregister(mod); 721 } 722