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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2011 by Delphix. All rights reserved. 29 * Copyright 2017 Nexenta Systems, Inc. 30 * Copyright 2021 Oxide Computer Company 31 * Copyright 2024 Sebastian Wiedenroth 32 */ 33 34 #include <fcntl.h> 35 #include <libdevinfo.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <sys/stat.h> 40 #include <sys/sunddi.h> 41 #include <sys/types.h> 42 #include <sys/mkdev.h> 43 #include <ctype.h> 44 #include <libgen.h> 45 #include <unistd.h> 46 #include <devid.h> 47 #include <sys/fs/zfs.h> 48 49 #include "libdiskmgt.h" 50 #include "disks_private.h" 51 52 /* specify which disk links to use in the /dev directory */ 53 #define DEVLINK_REGEX "rdsk/.*" 54 #define DEVLINK_FLOPPY_REGEX "rdiskette[0-9]" 55 56 #define FLOPPY_NAME "rdiskette" 57 58 #define MAXPROPLEN 1024 59 #define DEVICE_ID_PROP "devid" 60 #define INQUIRY_SERIAL_NO "inquiry-serial-no" 61 #define PROD_ID_PROP "inquiry-product-id" 62 #define PROD_ID_USB_PROP "usb-product-name" 63 #define REMOVABLE_PROP "removable-media" 64 #define HOTPLUGGABLE_PROP "hotpluggable" 65 #define SCSI_OPTIONS_PROP "scsi-options" 66 #define VENDOR_ID_PROP "inquiry-vendor-id" 67 #define VENDOR_ID_USB_PROP "usb-vendor-name" 68 #define WWN_PROP "node-wwn" 69 70 static char *ctrltypes[] = { 71 DDI_NT_FC_ATTACHMENT_POINT, 72 DDI_NT_NVME_ATTACHMENT_POINT, 73 DDI_NT_SATA_ATTACHMENT_POINT, 74 DDI_NT_SATA_NEXUS, 75 DDI_NT_SCSI_ATTACHMENT_POINT, 76 DDI_NT_SCSI_NEXUS, 77 NULL 78 }; 79 80 static char *bustypes[] = { 81 "sbus", 82 "pci", 83 "usb", 84 NULL 85 }; 86 87 static bus_t *add_bus(struct search_args *args, di_node_t node, 88 di_minor_t minor, controller_t *cp); 89 static controller_t *add_controller(struct search_args *args, 90 di_node_t node, di_minor_t minor); 91 static int add_devpath(di_devlink_t devlink, void *arg); 92 static int add_devs(di_node_t node, di_minor_t minor, void *arg); 93 static int add_disk2controller(disk_t *diskp, 94 struct search_args *args); 95 static int add_disk2path(disk_t *dp, path_t *pp, 96 di_path_state_t st, char *wwn); 97 static int add_int2array(int p, int **parray); 98 static int add_ptr2array(void *p, void ***parray); 99 static char *bus_type(di_node_t node, di_minor_t minor, 100 di_prom_handle_t ph); 101 static void remove_controller(controller_t *cp, 102 controller_t *currp); 103 static void clean_paths(struct search_args *args); 104 static disk_t *create_disk(char *deviceid, char *kernel_name, 105 struct search_args *args); 106 static char *ctype(di_node_t node, di_minor_t minor); 107 static boolean_t disk_is_cdrom(const char *type); 108 static alias_t *find_alias(disk_t *diskp, char *kernel_name); 109 static bus_t *find_bus(struct search_args *args, char *name); 110 static controller_t *find_controller(struct search_args *args, char *name); 111 static disk_t *get_disk_by_deviceid(disk_t *listp, char *devid); 112 static void get_disk_name_from_path(char *path, char *name, 113 int size); 114 static char *get_byte_prop(char *prop_name, di_node_t node); 115 static di_node_t get_parent_bus(di_node_t node, 116 struct search_args *args); 117 static int get_prom_int(char *prop_name, di_node_t node, 118 di_prom_handle_t ph); 119 static char *get_prom_str(char *prop_name, di_node_t node, 120 di_prom_handle_t ph); 121 static int get_prop(char *prop_name, di_node_t node); 122 static char *get_str_prop(char *prop_name, di_node_t node); 123 static int have_disk(struct search_args *args, char *devid, 124 char *kernel_name, disk_t **diskp); 125 static int is_ctds(char *name); 126 static int is_drive(di_minor_t minor); 127 static int is_zvol(di_node_t node, di_minor_t minor); 128 static int is_ctrl(di_node_t node, di_minor_t minor); 129 static int new_alias(disk_t *diskp, char *kernel_path, 130 char *devlink_path, struct search_args *args); 131 static int new_devpath(alias_t *ap, char *devpath); 132 static path_t *new_path(controller_t *cp, disk_t *diskp, 133 di_node_t node, di_path_state_t st, char *wwn); 134 static void remove_invalid_controller(char *name, 135 controller_t *currp, struct search_args *args); 136 137 /* 138 * The functions in this file do a dev tree walk to build up a model of the 139 * disks, controllers and paths on the system. This model is returned in the 140 * args->disk_listp and args->controller_listp members of the args param. 141 * There is no global data for this file so it is thread safe. It is up to 142 * the caller to merge the resulting model with any existing model that is 143 * cached. The caller must also free the memory for this model when it is 144 * no longer needed. 145 */ 146 void 147 findevs(struct search_args *args) 148 { 149 di_node_t di_root; 150 151 args->bus_listp = NULL; 152 args->controller_listp = NULL; 153 args->disk_listp = NULL; 154 155 args->ph = DI_PROM_HANDLE_NIL; 156 args->handle = DI_LINK_NIL; 157 args->dev_walk_status = 0; 158 159 /* 160 * Create device information library handles, which must be destroyed 161 * before we return. 162 */ 163 if ((args->ph = di_prom_init()) == DI_PROM_HANDLE_NIL || 164 (args->handle = di_devlink_init(NULL, 0)) == DI_LINK_NIL) { 165 /* 166 * We could not open all of the handles we need, so clean up 167 * and report failure to the caller. 168 */ 169 args->dev_walk_status = errno; 170 goto cleanup; 171 } 172 173 /* 174 * Have to make several passes at this with the new devfs caching. 175 * First, we find non-mpxio devices. Then we find mpxio/multipath 176 * devices. 177 */ 178 di_root = di_init("/", DINFOCACHE); 179 (void) di_walk_minor(di_root, NULL, 0, args, add_devs); 180 di_fini(di_root); 181 182 di_root = di_init("/", DINFOCPYALL|DINFOPATH); 183 (void) di_walk_minor(di_root, NULL, 0, args, add_devs); 184 di_fini(di_root); 185 186 clean_paths(args); 187 188 cleanup: 189 if (args->ph != DI_PROM_HANDLE_NIL) { 190 di_prom_fini(args->ph); 191 args->ph = DI_PROM_HANDLE_NIL; 192 } 193 if (args->handle != DI_LINK_NIL) { 194 (void) di_devlink_fini(&(args->handle)); 195 } 196 } 197 198 /* 199 * Definitions of private functions 200 */ 201 202 static bus_t * 203 add_bus(struct search_args *args, di_node_t node, di_minor_t minor, 204 controller_t *cp) 205 { 206 char *btype; 207 char *devpath; 208 bus_t *bp; 209 char kstat_name[MAXPATHLEN]; 210 di_node_t pnode; 211 212 if (node == DI_NODE_NIL) { 213 return (NULL); 214 } 215 216 if ((btype = bus_type(node, minor, args->ph)) == NULL) { 217 return (add_bus(args, di_parent_node(node), 218 di_minor_next(di_parent_node(node), NULL), cp)); 219 } 220 221 devpath = di_devfs_path(node); 222 223 if ((bp = find_bus(args, devpath)) != NULL) { 224 di_devfs_path_free((void *) devpath); 225 226 if (cp != NULL) { 227 if (add_ptr2array(cp, 228 (void ***)&bp->controllers) != 0) { 229 args->dev_walk_status = ENOMEM; 230 return (NULL); 231 } 232 } 233 return (bp); 234 } 235 236 /* Special handling for root node. */ 237 if (strcmp(devpath, "/") == 0) { 238 di_devfs_path_free((void *) devpath); 239 return (NULL); 240 } 241 242 if (dm_debug) { 243 (void) fprintf(stderr, "INFO: add_bus %s\n", devpath); 244 } 245 246 bp = (bus_t *)calloc(1, sizeof (bus_t)); 247 if (bp == NULL) { 248 return (NULL); 249 } 250 251 bp->name = strdup(devpath); 252 di_devfs_path_free((void *) devpath); 253 if (bp->name == NULL) { 254 args->dev_walk_status = ENOMEM; 255 cache_free_bus(bp); 256 return (NULL); 257 } 258 259 bp->btype = strdup(btype); 260 if (bp->btype == NULL) { 261 args->dev_walk_status = ENOMEM; 262 cache_free_bus(bp); 263 return (NULL); 264 } 265 266 (void) snprintf(kstat_name, sizeof (kstat_name), "%s%d", 267 di_node_name(node), di_instance(node)); 268 269 if ((bp->kstat_name = strdup(kstat_name)) == NULL) { 270 args->dev_walk_status = ENOMEM; 271 cache_free_bus(bp); 272 return (NULL); 273 } 274 275 /* if parent node is a bus, get its name */ 276 if ((pnode = get_parent_bus(node, args)) != NULL) { 277 devpath = di_devfs_path(pnode); 278 bp->pname = strdup(devpath); 279 di_devfs_path_free((void *) devpath); 280 if (bp->pname == NULL) { 281 args->dev_walk_status = ENOMEM; 282 cache_free_bus(bp); 283 return (NULL); 284 } 285 286 } else { 287 bp->pname = NULL; 288 } 289 290 bp->freq = get_prom_int("clock-frequency", node, args->ph); 291 292 bp->controllers = (controller_t **)calloc(1, sizeof (controller_t *)); 293 if (bp->controllers == NULL) { 294 args->dev_walk_status = ENOMEM; 295 cache_free_bus(bp); 296 return (NULL); 297 } 298 bp->controllers[0] = NULL; 299 300 if (cp != NULL) { 301 if (add_ptr2array(cp, (void ***)&bp->controllers) != 0) { 302 args->dev_walk_status = ENOMEM; 303 return (NULL); 304 } 305 } 306 307 bp->next = args->bus_listp; 308 args->bus_listp = bp; 309 310 return (bp); 311 } 312 313 static controller_t * 314 add_controller(struct search_args *args, di_node_t node, di_minor_t minor) 315 { 316 char *devpath; 317 controller_t *cp; 318 char kstat_name[MAXPATHLEN]; 319 char *c_type = DM_CTYPE_UNKNOWN; 320 321 devpath = di_devfs_path(node); 322 323 if ((cp = find_controller(args, devpath)) != NULL) { 324 di_devfs_path_free((void *) devpath); 325 return (cp); 326 } 327 328 /* Special handling for fp attachment node. */ 329 if (strcmp(di_node_name(node), "fp") == 0) { 330 di_node_t pnode; 331 332 pnode = di_parent_node(node); 333 if (pnode != DI_NODE_NIL) { 334 di_devfs_path_free((void *) devpath); 335 devpath = di_devfs_path(pnode); 336 337 if ((cp = find_controller(args, devpath)) != NULL) { 338 di_devfs_path_free((void *) devpath); 339 return (cp); 340 } 341 342 /* not in the list, create it */ 343 node = pnode; 344 c_type = DM_CTYPE_FIBRE; 345 } 346 } 347 348 if (dm_debug) { 349 (void) fprintf(stderr, "INFO: add_controller %s\n", devpath); 350 } 351 352 cp = (controller_t *)calloc(1, sizeof (controller_t)); 353 if (cp == NULL) { 354 return (NULL); 355 } 356 357 cp->name = strdup(devpath); 358 di_devfs_path_free((void *) devpath); 359 if (cp->name == NULL) { 360 cache_free_controller(cp); 361 return (NULL); 362 } 363 364 if (strcmp(c_type, DM_CTYPE_UNKNOWN) == 0) { 365 c_type = ctype(node, minor); 366 } 367 cp->ctype = c_type; 368 369 (void) snprintf(kstat_name, sizeof (kstat_name), "%s%d", 370 di_node_name(node), di_instance(node)); 371 372 if ((cp->kstat_name = strdup(kstat_name)) == NULL) { 373 cache_free_controller(cp); 374 return (NULL); 375 } 376 377 if (libdiskmgt_str_eq(cp->ctype, "scsi")) { 378 cp->scsi_options = get_prop(SCSI_OPTIONS_PROP, node); 379 } 380 381 if (libdiskmgt_str_eq(di_node_name(node), "scsi_vhci")) { 382 cp->multiplex = 1; 383 } else { 384 cp->multiplex = 0; 385 } 386 387 cp->freq = get_prom_int("clock-frequency", node, args->ph); 388 389 cp->disks = (disk_t **)calloc(1, sizeof (disk_t *)); 390 if (cp->disks == NULL) { 391 cache_free_controller(cp); 392 return (NULL); 393 } 394 cp->disks[0] = NULL; 395 396 cp->next = args->controller_listp; 397 args->controller_listp = cp; 398 399 cp->bus = add_bus(args, di_parent_node(node), 400 di_minor_next(di_parent_node(node), NULL), cp); 401 402 return (cp); 403 } 404 405 static int 406 add_devpath(di_devlink_t devlink, void *arg) 407 { 408 struct search_args *args; 409 char *devidstr; 410 disk_t *diskp; 411 char kernel_name[MAXPATHLEN]; 412 413 args = (struct search_args *)arg; 414 415 /* 416 * Get the diskp value from calling have_disk. Can either be found 417 * by kernel name or devid. 418 */ 419 420 diskp = NULL; 421 devidstr = get_str_prop(DEVICE_ID_PROP, args->node); 422 (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", 423 di_node_name(args->node), di_instance(args->node)); 424 425 (void) have_disk(args, devidstr, kernel_name, &diskp); 426 427 /* 428 * The devlink_path is usually of the form /dev/rdsk/c0t0d0s0. 429 * For diskettes it is /dev/rdiskette*. 430 * On Intel we would also get each fdisk partition as well 431 * (e.g. /dev/rdsk/c0t0d0p0). 432 */ 433 if (diskp != NULL) { 434 alias_t *ap; 435 char *devlink_path; 436 437 if (diskp->drv_type != DM_DT_FLOPPY) { 438 /* 439 * Add other controllers for multipath disks. 440 * This will have no effect if the controller 441 * relationship is already set up. 442 */ 443 if (add_disk2controller(diskp, args) != 0) { 444 args->dev_walk_status = ENOMEM; 445 } 446 } 447 448 (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", 449 di_node_name(args->node), di_instance(args->node)); 450 devlink_path = (char *)di_devlink_path(devlink); 451 452 if (dm_debug > 1) { 453 (void) fprintf(stderr, 454 "INFO: devpath %s\n", devlink_path); 455 } 456 457 if ((ap = find_alias(diskp, kernel_name)) == NULL) { 458 if (new_alias(diskp, kernel_name, devlink_path, 459 args) != 0) { 460 args->dev_walk_status = ENOMEM; 461 } 462 } else { 463 /* 464 * It is possible that we have already added this 465 * devpath. Do not add it again. new_devpath will 466 * return a 0 if found, and not add the path. 467 */ 468 if (new_devpath(ap, devlink_path) != 0) { 469 args->dev_walk_status = ENOMEM; 470 } 471 } 472 } 473 474 return (DI_WALK_CONTINUE); 475 } 476 477 static int 478 add_devs(di_node_t node, di_minor_t minor, void *arg) 479 { 480 struct search_args *args; 481 int result = DI_WALK_CONTINUE; 482 483 args = (struct search_args *)arg; 484 485 if (dm_debug > 1) { 486 /* This is all just debugging code */ 487 char *devpath; 488 char dev_name[MAXPATHLEN]; 489 490 devpath = di_devfs_path(node); 491 (void) snprintf(dev_name, sizeof (dev_name), "%s:%s", devpath, 492 di_minor_name(minor)); 493 di_devfs_path_free((void *) devpath); 494 495 (void) fprintf(stderr, 496 "INFO: dev: %s, node: %s%d, minor: 0x%x, type: %s\n", 497 dev_name, di_node_name(node), di_instance(node), 498 di_minor_spectype(minor), 499 (di_minor_nodetype(minor) != NULL ? 500 di_minor_nodetype(minor) : "NULL")); 501 } 502 503 if (bus_type(node, minor, args->ph) != NULL) { 504 if (add_bus(args, node, minor, NULL) == NULL) { 505 args->dev_walk_status = ENOMEM; 506 result = DI_WALK_TERMINATE; 507 } 508 509 } else if (is_ctrl(node, minor)) { 510 if (add_controller(args, node, minor) == NULL) { 511 args->dev_walk_status = ENOMEM; 512 result = DI_WALK_TERMINATE; 513 } 514 515 } else if (di_minor_spectype(minor) == S_IFCHR && 516 (is_drive(minor) || is_zvol(node, minor))) { 517 char *devidstr; 518 char kernel_name[MAXPATHLEN]; 519 disk_t *diskp; 520 521 (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", 522 di_node_name(node), di_instance(node)); 523 devidstr = get_str_prop(DEVICE_ID_PROP, node); 524 525 args->node = node; 526 args->minor = minor; 527 /* 528 * Check if we already got this disk and 529 * this is another slice. 530 */ 531 if (!have_disk(args, devidstr, kernel_name, &diskp)) { 532 args->dev_walk_status = 0; 533 /* 534 * This is a newly found disk, create the 535 * disk structure. 536 */ 537 diskp = create_disk(devidstr, kernel_name, args); 538 if (diskp == NULL) { 539 args->dev_walk_status = ENOMEM; 540 } 541 542 if (diskp->drv_type != DM_DT_FLOPPY) { 543 /* add the controller relationship */ 544 if (args->dev_walk_status == 0) { 545 if (add_disk2controller(diskp, 546 args) != 0) { 547 args->dev_walk_status = ENOMEM; 548 } 549 } 550 } 551 } 552 if (is_zvol(node, minor)) { 553 char zvdsk[MAXNAMELEN]; 554 char *str; 555 alias_t *ap; 556 557 if (di_prop_lookup_strings(di_minor_devt(minor), 558 node, "name", &str) == -1) 559 return (DI_WALK_CONTINUE); 560 (void) snprintf(zvdsk, MAXNAMELEN, "/dev/zvol/rdsk/%s", 561 str); 562 if ((ap = find_alias(diskp, kernel_name)) == NULL) { 563 if (new_alias(diskp, kernel_name, 564 zvdsk, args) != 0) { 565 args->dev_walk_status = ENOMEM; 566 } 567 } else { 568 /* 569 * It is possible that we have already added 570 * this devpath. 571 * Do not add it again. new_devpath will 572 * return a 0 if found, and not add the path. 573 */ 574 if (new_devpath(ap, zvdsk) != 0) { 575 args->dev_walk_status = ENOMEM; 576 } 577 } 578 } 579 580 /* Add the devpaths for the drive. */ 581 if (args->dev_walk_status == 0) { 582 char *devpath; 583 char slice_path[MAXPATHLEN]; 584 char *pattern; 585 586 /* 587 * We will come through here once for each of 588 * the raw slice device names. 589 */ 590 devpath = di_devfs_path(node); 591 (void) snprintf(slice_path, 592 sizeof (slice_path), "%s:%s", 593 devpath, di_minor_name(minor)); 594 di_devfs_path_free((void *) devpath); 595 596 if (libdiskmgt_str_eq(di_minor_nodetype(minor), 597 DDI_NT_FD)) { 598 pattern = DEVLINK_FLOPPY_REGEX; 599 } else { 600 pattern = DEVLINK_REGEX; 601 } 602 603 /* Walk the /dev tree to get the devlinks. */ 604 (void) di_devlink_walk(args->handle, pattern, 605 slice_path, DI_PRIMARY_LINK, arg, add_devpath); 606 } 607 608 if (args->dev_walk_status != 0) { 609 result = DI_WALK_TERMINATE; 610 } 611 } 612 613 return (result); 614 } 615 616 static int 617 add_disk2controller(disk_t *diskp, struct search_args *args) 618 { 619 di_node_t pnode; 620 controller_t *cp; 621 di_minor_t minor; 622 di_node_t node; 623 int i; 624 625 node = args->node; 626 627 pnode = di_parent_node(node); 628 if (pnode == DI_NODE_NIL) { 629 return (0); 630 } 631 632 /* 633 * Certain pseudo-device nodes do not all immediately have a valid 634 * parent-node. In particular, lofi (and zfs) would point to the generic 635 * /pseudo node. As a result, if we find a lofi disk, redirect it to the 636 * actual path. If we don't find it in this, then just fall back to the 637 * traditional path. 638 */ 639 if (libdiskmgt_str_eq(di_node_name(pnode), "pseudo") && 640 libdiskmgt_str_eq(di_node_name(node), "lofi")) { 641 di_node_t n; 642 643 n = di_drv_first_node("lofi", pnode); 644 while (n != DI_NODE_NIL) { 645 if (di_instance(n) == 0) { 646 pnode = n; 647 break; 648 } 649 650 n = di_drv_next_node(n); 651 } 652 } 653 654 minor = di_minor_next(pnode, NULL); 655 if (minor == NULL) { 656 return (0); 657 } 658 659 if ((cp = add_controller(args, pnode, minor)) == NULL) { 660 return (ENOMEM); 661 } 662 663 /* check if the disk <-> ctrl assoc is already there */ 664 for (i = 0; diskp->controllers[i]; i++) { 665 if (cp == diskp->controllers[i]) { 666 return (0); 667 } 668 } 669 670 /* this is a new controller for this disk */ 671 672 /* add the disk to the controller */ 673 if (add_ptr2array(diskp, (void ***)&cp->disks) != 0) { 674 return (ENOMEM); 675 } 676 677 /* add the controller to the disk */ 678 if (add_ptr2array(cp, (void ***)&diskp->controllers) != 0) { 679 return (ENOMEM); 680 } 681 682 /* 683 * Set up paths for mpxio controlled drives. 684 */ 685 if (libdiskmgt_str_eq(di_node_name(pnode), "scsi_vhci")) { 686 /* note: mpxio di_path stuff is all consolidation private */ 687 di_path_t pi = DI_PATH_NIL; 688 689 while ( 690 (pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) { 691 int cnt; 692 uchar_t *bytes; 693 char str[MAXPATHLEN]; 694 char *wwn; 695 696 di_node_t phci_node = di_path_phci_node(pi); 697 698 /* get the node wwn */ 699 cnt = di_path_prop_lookup_bytes(pi, WWN_PROP, &bytes); 700 wwn = NULL; 701 if (cnt > 0) { 702 int i; 703 str[0] = 0; 704 705 for (i = 0; i < cnt; i++) { 706 /* 707 * A byte is only 2 hex chars + null. 708 */ 709 char bstr[8]; 710 711 (void) snprintf(bstr, 712 sizeof (bstr), "%.2x", bytes[i]); 713 (void) strlcat(str, bstr, sizeof (str)); 714 } 715 wwn = str; 716 } 717 718 if (new_path(cp, diskp, phci_node, 719 di_path_state(pi), wwn) == NULL) { 720 return (ENOMEM); 721 } 722 } 723 } 724 725 return (0); 726 } 727 728 static int 729 add_disk2path(disk_t *dp, path_t *pp, di_path_state_t st, char *wwn) 730 { 731 /* add the disk to the path */ 732 if (add_ptr2array(dp, (void ***)&pp->disks) != 0) { 733 cache_free_path(pp); 734 return (0); 735 } 736 737 /* add the path to the disk */ 738 if (add_ptr2array(pp, (void ***)&dp->paths) != 0) { 739 cache_free_path(pp); 740 return (0); 741 } 742 743 /* add the path state for this disk */ 744 if (add_int2array(st, &pp->states) != 0) { 745 cache_free_path(pp); 746 return (0); 747 } 748 749 /* add the path state for this disk */ 750 if (wwn != NULL) { 751 char *wp; 752 753 if ((wp = strdup(wwn)) != NULL) { 754 if (add_ptr2array(wp, (void ***)(&pp->wwns)) != 0) { 755 cache_free_path(pp); 756 return (0); 757 } 758 } 759 } 760 761 return (1); 762 } 763 764 static int 765 add_int2array(int p, int **parray) 766 { 767 int i; 768 int cnt; 769 int *pa; 770 int *new_array; 771 772 pa = *parray; 773 774 cnt = 0; 775 if (pa != NULL) { 776 for (; pa[cnt] != -1; cnt++) 777 ; 778 } 779 780 new_array = (int *)calloc(cnt + 2, sizeof (int *)); 781 if (new_array == NULL) { 782 return (ENOMEM); 783 } 784 785 /* copy the existing array */ 786 for (i = 0; i < cnt; i++) { 787 new_array[i] = pa[i]; 788 } 789 790 new_array[i] = p; 791 new_array[i + 1] = -1; 792 793 free(pa); 794 *parray = new_array; 795 796 return (0); 797 } 798 799 static int 800 add_ptr2array(void *p, void ***parray) 801 { 802 int i; 803 int cnt; 804 void **pa; 805 void **new_array; 806 807 pa = *parray; 808 809 cnt = 0; 810 if (pa != NULL) { 811 for (; pa[cnt]; cnt++) 812 ; 813 } 814 815 new_array = (void **)calloc(cnt + 2, sizeof (void *)); 816 if (new_array == NULL) { 817 return (ENOMEM); 818 } 819 820 /* copy the existing array */ 821 for (i = 0; i < cnt; i++) { 822 new_array[i] = pa[i]; 823 } 824 825 new_array[i] = p; 826 new_array[i + 1] = NULL; 827 828 free(pa); 829 *parray = new_array; 830 831 return (0); 832 } 833 834 /* 835 * This function checks to see if a controller has other associations 836 * that may be valid. If we are calling this function, we have found that 837 * a controller for an mpxio device is showing up independently of the 838 * mpxio controller, noted as /scsi_vhci. This can happen with some FC 839 * cards that have inbound management devices that show up as well, with 840 * the real controller data associated. We do not want to display these 841 * 'devices' as real devices in libdiskmgt. 842 */ 843 static void 844 remove_controller(controller_t *cp, controller_t *currp) 845 { 846 int i; 847 848 if (cp == currp) { 849 if (dm_debug) { 850 (void) fprintf(stderr, "ERROR: removing current" 851 " controller\n"); 852 } 853 return; 854 } 855 856 if (cp->disks != NULL && cp->disks[0] != NULL) { 857 if (dm_debug) { 858 (void) fprintf(stderr, 859 "INFO: removing inbound management controller" 860 " with disk ptrs.\n"); 861 } 862 /* 863 * loop through the disks and remove the reference to the 864 * controller for this disk structure. The disk itself 865 * is still a valid device, the controller being removed 866 * is a 'path' so any disk that has a reference to it 867 * as a controller needs to have this reference removed. 868 */ 869 for (i = 0; cp->disks[i]; i++) { 870 disk_t *dp = cp->disks[i]; 871 int j; 872 873 for (j = 0; dp->controllers[j]; j++) { 874 int k; 875 876 if (libdiskmgt_str_eq(dp->controllers[j]->name, 877 cp->name)) { 878 879 if (dm_debug) { 880 (void) fprintf(stderr, 881 "INFO: REMOVING disk %s on " 882 "controller %s\n", 883 dp->kernel_name, cp->name); 884 } 885 for (k = j; dp->controllers[k]; k++) { 886 dp->controllers[k] = 887 dp->controllers[k + 1]; 888 } 889 } 890 } 891 } 892 } 893 /* 894 * Paths are removed with the call to cache_free_controller() 895 * below. 896 */ 897 898 if (cp->paths != NULL && cp->paths[0] != NULL) { 899 if (dm_debug) { 900 (void) fprintf(stderr, 901 "INFO: removing inbound management controller" 902 " with path ptrs. \n"); 903 } 904 } 905 cache_free_controller(cp); 906 } 907 908 /* 909 * If we have a controller in the list that is really a path then we need to 910 * take that controller out of the list since nodes that are paths are not 911 * considered to be controllers. 912 */ 913 static void 914 clean_paths(struct search_args *args) 915 { 916 controller_t *cp; 917 918 cp = args->controller_listp; 919 while (cp != NULL) { 920 path_t **pp; 921 922 pp = cp->paths; 923 if (pp != NULL) { 924 int i; 925 926 for (i = 0; pp[i]; i++) { 927 remove_invalid_controller(pp[i]->name, cp, 928 args); 929 } 930 } 931 cp = cp->next; 932 } 933 } 934 935 static disk_t * 936 create_disk(char *deviceid, char *kernel_name, struct search_args *args) 937 { 938 disk_t *diskp; 939 char *type; 940 char *prod_id; 941 char *vendor_id; 942 char *serial; 943 944 if (dm_debug) { 945 (void) fprintf(stderr, "INFO: create_disk %s\n", kernel_name); 946 } 947 948 diskp = calloc(1, sizeof (disk_t)); 949 if (diskp == NULL) { 950 return (NULL); 951 } 952 953 diskp->controllers = (controller_t **) 954 calloc(1, sizeof (controller_t *)); 955 if (diskp->controllers == NULL) { 956 cache_free_disk(diskp); 957 return (NULL); 958 } 959 diskp->controllers[0] = NULL; 960 961 diskp->devid = NULL; 962 if (deviceid != NULL) { 963 if ((diskp->device_id = strdup(deviceid)) == NULL) { 964 cache_free_disk(diskp); 965 return (NULL); 966 } 967 (void) devid_str_decode(deviceid, &(diskp->devid), NULL); 968 } 969 970 if (kernel_name != NULL) { 971 diskp->kernel_name = strdup(kernel_name); 972 if (diskp->kernel_name == NULL) { 973 cache_free_disk(diskp); 974 return (NULL); 975 } 976 } 977 978 diskp->paths = NULL; 979 diskp->aliases = NULL; 980 981 diskp->cd_rom = 0; 982 diskp->rpm = 0; 983 diskp->solid_state = -1; 984 type = di_minor_nodetype(args->minor); 985 986 prod_id = get_str_prop(PROD_ID_PROP, args->node); 987 if (prod_id != NULL) { 988 if ((diskp->product_id = strdup(prod_id)) == NULL) { 989 cache_free_disk(diskp); 990 return (NULL); 991 } 992 } else { 993 prod_id = get_str_prop(PROD_ID_USB_PROP, args->node); 994 if (prod_id != NULL) { 995 if ((diskp->product_id = strdup(prod_id)) == NULL) { 996 cache_free_disk(diskp); 997 return (NULL); 998 } 999 } 1000 } 1001 1002 vendor_id = get_str_prop(VENDOR_ID_PROP, args->node); 1003 if (vendor_id != NULL) { 1004 if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { 1005 cache_free_disk(diskp); 1006 return (NULL); 1007 } 1008 } else { 1009 vendor_id = get_str_prop(VENDOR_ID_USB_PROP, args->node); 1010 if (vendor_id != NULL) { 1011 if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { 1012 cache_free_disk(diskp); 1013 return (NULL); 1014 } 1015 } 1016 } 1017 1018 serial = get_str_prop(INQUIRY_SERIAL_NO, args->node); 1019 if (serial != NULL) { 1020 if ((diskp->serial = strdup(serial)) == NULL) { 1021 cache_free_disk(diskp); 1022 return (NULL); 1023 } 1024 } 1025 1026 /* 1027 * DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS. 1028 * We try to use uscsi later to determine the real type. 1029 * The cd_rom flag tells us that the kernel categorized the drive 1030 * as a CD-ROM. We leave the drv_type as UNKNOWN for now. 1031 * The combination of the cd_rom flag being set with the drv_type of 1032 * unknown is what triggers the uscsi probe in drive.c. 1033 */ 1034 if (disk_is_cdrom(type)) { 1035 diskp->drv_type = DM_DT_UNKNOWN; 1036 diskp->cd_rom = 1; 1037 diskp->removable = 1; 1038 } else if (libdiskmgt_str_eq(type, DDI_NT_FD)) { 1039 diskp->drv_type = DM_DT_FLOPPY; 1040 diskp->removable = 1; 1041 } else { 1042 /* not a CD-ROM or Floppy */ 1043 diskp->removable = get_prop(REMOVABLE_PROP, args->node); 1044 1045 if (diskp->removable == -1) { 1046 diskp->removable = 0; 1047 diskp->drv_type = DM_DT_FIXED; 1048 } 1049 } 1050 1051 diskp->next = args->disk_listp; 1052 args->disk_listp = diskp; 1053 1054 return (diskp); 1055 } 1056 1057 static char * 1058 ctype(di_node_t node, di_minor_t minor) 1059 { 1060 char *type; 1061 char *name; 1062 1063 type = di_minor_nodetype(minor); 1064 name = di_node_name(node); 1065 1066 /* IDE disks use SCSI nexus as the type, so handle this special case */ 1067 if ((libdiskmgt_str_eq(type, DDI_NT_SCSI_NEXUS) || 1068 libdiskmgt_str_eq(type, DDI_PSEUDO)) && 1069 libdiskmgt_str_eq(name, "ide")) 1070 return (DM_CTYPE_ATA); 1071 1072 if (libdiskmgt_str_eq(type, DDI_NT_FC_ATTACHMENT_POINT) || 1073 (libdiskmgt_str_eq(type, DDI_NT_NEXUS) && 1074 libdiskmgt_str_eq(name, "fp"))) 1075 return (DM_CTYPE_FIBRE); 1076 1077 if (libdiskmgt_str_eq(type, DDI_NT_NVME_ATTACHMENT_POINT)) 1078 return (DM_CTYPE_NVME); 1079 1080 if (libdiskmgt_str_eq(type, DDI_NT_SATA_NEXUS) || 1081 libdiskmgt_str_eq(type, DDI_NT_SATA_ATTACHMENT_POINT)) 1082 return (DM_CTYPE_SATA); 1083 1084 if (libdiskmgt_str_eq(type, DDI_NT_SCSI_NEXUS) || 1085 libdiskmgt_str_eq(type, DDI_NT_SCSI_ATTACHMENT_POINT)) 1086 return (DM_CTYPE_SCSI); 1087 1088 if (libdiskmgt_str_eq(di_minor_name(minor), "scsa2usb")) 1089 return (DM_CTYPE_USB); 1090 1091 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1092 libdiskmgt_str_eq(name, "xpvd")) 1093 return (DM_CTYPE_XEN); 1094 1095 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1096 libdiskmgt_str_eq(name, "lofi")) 1097 return (DM_CTYPE_LOFI); 1098 1099 if (dm_debug) { 1100 (void) fprintf(stderr, 1101 "INFO: unknown controller type=%s name=%s\n", type, name); 1102 } 1103 1104 return (DM_CTYPE_UNKNOWN); 1105 } 1106 1107 static boolean_t 1108 disk_is_cdrom(const char *type) 1109 { 1110 return (strncmp(type, DDI_NT_CD, strlen(DDI_NT_CD)) == 0); 1111 } 1112 1113 static alias_t * 1114 find_alias(disk_t *diskp, char *kernel_name) 1115 { 1116 alias_t *ap; 1117 1118 ap = diskp->aliases; 1119 while (ap != NULL) { 1120 if (libdiskmgt_str_eq(ap->kstat_name, kernel_name)) { 1121 return (ap); 1122 } 1123 ap = ap->next; 1124 } 1125 1126 return (NULL); 1127 } 1128 1129 static bus_t * 1130 find_bus(struct search_args *args, char *name) 1131 { 1132 bus_t *listp; 1133 1134 listp = args->bus_listp; 1135 while (listp != NULL) { 1136 if (libdiskmgt_str_eq(listp->name, name)) { 1137 return (listp); 1138 } 1139 listp = listp->next; 1140 } 1141 1142 return (NULL); 1143 } 1144 1145 static controller_t * 1146 find_controller(struct search_args *args, char *name) 1147 { 1148 controller_t *listp; 1149 1150 listp = args->controller_listp; 1151 while (listp != NULL) { 1152 if (libdiskmgt_str_eq(listp->name, name)) { 1153 return (listp); 1154 } 1155 listp = listp->next; 1156 } 1157 1158 return (NULL); 1159 } 1160 1161 /* 1162 * Check if we have the drive in our list, based upon the device id. 1163 * We got the device id from the dev tree walk. This is encoded 1164 * using devid_str_encode(3DEVID). In order to check the device ids we need 1165 * to use the devid_compare(3DEVID) function, so we need to decode the 1166 * string representation of the device id. 1167 */ 1168 static disk_t * 1169 get_disk_by_deviceid(disk_t *listp, char *devidstr) 1170 { 1171 ddi_devid_t devid; 1172 1173 if (devidstr == NULL || devid_str_decode(devidstr, &devid, NULL) != 0) { 1174 return (NULL); 1175 } 1176 1177 while (listp != NULL) { 1178 if (listp->devid != NULL && 1179 devid_compare(listp->devid, devid) == 0) { 1180 break; 1181 } 1182 listp = listp->next; 1183 } 1184 1185 devid_free(devid); 1186 return (listp); 1187 } 1188 1189 /* 1190 * Get the base disk name with no path prefix and no slice (if there is one). 1191 * The name parameter should be big enough to hold the name. 1192 * This handles diskette names ok (/dev/rdiskette0) since there is no slice, 1193 * and converts the raw diskette name. 1194 * But, we don't know how to strip off the slice from third party drive 1195 * names. That just means that their drive name will include a slice on 1196 * it. 1197 */ 1198 static void 1199 get_disk_name_from_path(char *path, char *name, int size) 1200 { 1201 char *basep; 1202 int cnt = 0; 1203 1204 basep = strrchr(path, '/'); 1205 if (basep == NULL) { 1206 basep = path; 1207 } else { 1208 basep++; 1209 } 1210 1211 size = size - 1; /* leave room for terminating 0 */ 1212 1213 if (is_ctds(basep)) { 1214 while (*basep != 0 && *basep != 's' && cnt < size) { 1215 *name++ = *basep++; 1216 cnt++; 1217 } 1218 *name = 0; 1219 } else { 1220 if (strncmp(basep, FLOPPY_NAME, 1221 sizeof (FLOPPY_NAME) - 1) == 0) { 1222 /* 1223 * a floppy, convert rdiskette name to diskette name, 1224 * by skipping over the 'r' for raw diskette 1225 */ 1226 basep++; 1227 } 1228 1229 /* not a ctds name, just copy it */ 1230 (void) strlcpy(name, basep, size); 1231 } 1232 } 1233 1234 static char * 1235 get_byte_prop(char *prop_name, di_node_t node) 1236 { 1237 int cnt; 1238 uchar_t *bytes; 1239 int i; 1240 char str[MAXPATHLEN]; 1241 1242 cnt = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, prop_name, &bytes); 1243 if (cnt < 1) { 1244 return (NULL); 1245 } 1246 1247 str[0] = 0; 1248 for (i = 0; i < cnt; i++) { 1249 char bstr[8]; /* a byte is only 2 hex chars + null */ 1250 1251 (void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]); 1252 (void) strlcat(str, bstr, sizeof (str)); 1253 } 1254 return (strdup(str)); 1255 } 1256 1257 static di_node_t 1258 get_parent_bus(di_node_t node, struct search_args *args) 1259 { 1260 di_node_t pnode; 1261 1262 pnode = di_parent_node(node); 1263 if (pnode == DI_NODE_NIL) { 1264 return (NULL); 1265 } 1266 1267 if (bus_type(pnode, di_minor_next(pnode, NULL), args->ph) != NULL) { 1268 return (pnode); 1269 } 1270 1271 return (get_parent_bus(pnode, args)); 1272 } 1273 1274 static int 1275 get_prom_int(char *prop_name, di_node_t node, di_prom_handle_t ph) 1276 { 1277 int *n; 1278 1279 if (di_prom_prop_lookup_ints(ph, node, prop_name, &n) == 1) { 1280 return (*n); 1281 } 1282 1283 return (0); 1284 } 1285 1286 static char * 1287 get_prom_str(char *prop_name, di_node_t node, di_prom_handle_t ph) 1288 { 1289 char *str; 1290 1291 if (di_prom_prop_lookup_strings(ph, node, prop_name, &str) == 1) { 1292 return (str); 1293 } 1294 1295 return (NULL); 1296 } 1297 1298 /* 1299 * Get one of the positive int or boolean properties. 1300 */ 1301 static int 1302 get_prop(char *prop_name, di_node_t node) 1303 { 1304 int num; 1305 int *ip; 1306 1307 if ((num = di_prop_lookup_ints(DDI_DEV_T_ANY, node, prop_name, &ip)) 1308 >= 0) { 1309 if (num == 0) { 1310 /* boolean */ 1311 return (1); 1312 } else if (num == 1) { 1313 /* single int */ 1314 return (*ip); 1315 } 1316 } 1317 return (-1); 1318 } 1319 1320 static char * 1321 get_str_prop(char *prop_name, di_node_t node) 1322 { 1323 char *str; 1324 1325 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, prop_name, &str) == 1) { 1326 return (str); 1327 } 1328 1329 return (NULL); 1330 } 1331 1332 /* 1333 * Check if we have the drive in our list, based upon the device id, if the 1334 * drive has a device id, or the kernel name, if it doesn't have a device id. 1335 */ 1336 static int 1337 have_disk(struct search_args *args, char *devidstr, char *kernel_name, 1338 disk_t **diskp) 1339 { 1340 disk_t *listp; 1341 1342 *diskp = NULL; 1343 listp = args->disk_listp; 1344 if (devidstr != NULL) { 1345 if ((*diskp = get_disk_by_deviceid(listp, devidstr)) != NULL) { 1346 return (1); 1347 } 1348 1349 } else { 1350 /* no devid, try matching the kernel names on the drives */ 1351 while (listp != NULL) { 1352 if (libdiskmgt_str_eq(kernel_name, 1353 listp->kernel_name)) { 1354 *diskp = listp; 1355 return (1); 1356 } 1357 listp = listp->next; 1358 } 1359 } 1360 return (0); 1361 } 1362 1363 static char * 1364 bus_type(di_node_t node, di_minor_t minor, di_prom_handle_t ph) 1365 { 1366 char *type; 1367 int i; 1368 1369 type = get_prom_str("device_type", node, ph); 1370 if (type == NULL) { 1371 type = di_node_name(node); 1372 } 1373 1374 for (i = 0; bustypes[i]; i++) { 1375 if (libdiskmgt_str_eq(type, bustypes[i])) { 1376 return (type); 1377 } 1378 } 1379 1380 if (minor != NULL && strcmp(di_minor_nodetype(minor), 1381 DDI_NT_USB_ATTACHMENT_POINT) == 0) { 1382 return ("usb"); 1383 } 1384 1385 return (NULL); 1386 } 1387 1388 /* 1389 * If the input name is in c[t]ds format then return 1, otherwise return 0. 1390 */ 1391 static int 1392 is_ctds(char *name) 1393 { 1394 char *p; 1395 1396 p = name; 1397 1398 if (*p++ != 'c') { 1399 return (0); 1400 } 1401 /* skip controller digits */ 1402 while (isdigit(*p)) { 1403 p++; 1404 } 1405 1406 /* handle optional target */ 1407 if (*p == 't') { 1408 p++; 1409 /* skip over target */ 1410 while (isdigit(*p) || isupper(*p)) { 1411 p++; 1412 } 1413 } 1414 1415 if (*p++ != 'd') { 1416 return (0); 1417 } 1418 while (isdigit(*p)) { 1419 p++; 1420 } 1421 1422 if (*p++ != 's') { 1423 return (0); 1424 } 1425 1426 /* check the slice number */ 1427 while (isdigit(*p)) { 1428 p++; 1429 } 1430 1431 if (*p != 0) { 1432 return (0); 1433 } 1434 1435 return (1); 1436 } 1437 1438 static int 1439 is_drive(di_minor_t minor) 1440 { 1441 return (strncmp(di_minor_nodetype(minor), DDI_NT_BLOCK, 1442 strlen(DDI_NT_BLOCK)) == 0); 1443 } 1444 1445 static int 1446 is_zvol(di_node_t node, di_minor_t minor) 1447 { 1448 if ((strncmp(di_node_name(node), ZFS_DRIVER, 3) == 0) && 1449 minor(di_minor_devt(minor))) 1450 return (1); 1451 return (0); 1452 } 1453 1454 static int 1455 is_ctrl(di_node_t node, di_minor_t minor) 1456 { 1457 char *type; 1458 char *name; 1459 int type_index; 1460 1461 type = di_minor_nodetype(minor); 1462 type_index = 0; 1463 1464 while (ctrltypes[type_index] != NULL) { 1465 if (libdiskmgt_str_eq(type, ctrltypes[type_index])) { 1466 return (1); 1467 } 1468 type_index++; 1469 } 1470 1471 name = di_node_name(node); 1472 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1473 (libdiskmgt_str_eq(name, "ide") || 1474 libdiskmgt_str_eq(name, "xpvd"))) 1475 return (1); 1476 1477 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1478 libdiskmgt_str_eq(name, "lofi") && 1479 libdiskmgt_str_eq(di_minor_name(minor), "ctl")) 1480 return (1); 1481 1482 return (0); 1483 } 1484 1485 static int 1486 new_alias(disk_t *diskp, char *kernel_name, char *devlink_path, 1487 struct search_args *args) 1488 { 1489 alias_t *aliasp; 1490 char alias[MAXPATHLEN]; 1491 di_node_t pnode; 1492 1493 aliasp = malloc(sizeof (alias_t)); 1494 if (aliasp == NULL) { 1495 return (ENOMEM); 1496 } 1497 1498 aliasp->alias = NULL; 1499 aliasp->kstat_name = NULL; 1500 aliasp->wwn = NULL; 1501 aliasp->devpaths = NULL; 1502 aliasp->orig_paths = NULL; 1503 1504 get_disk_name_from_path(devlink_path, alias, sizeof (alias)); 1505 1506 aliasp->alias = strdup(alias); 1507 if (aliasp->alias == NULL) { 1508 cache_free_alias(aliasp); 1509 return (ENOMEM); 1510 } 1511 1512 if (kernel_name != NULL) { 1513 aliasp->kstat_name = strdup(kernel_name); 1514 if (aliasp->kstat_name == NULL) { 1515 cache_free_alias(aliasp); 1516 return (ENOMEM); 1517 } 1518 } else { 1519 aliasp->kstat_name = NULL; 1520 } 1521 1522 aliasp->lun = get_prop(DM_LUN, args->node); 1523 aliasp->target = get_prop(DM_TARGET, args->node); 1524 aliasp->wwn = get_byte_prop(WWN_PROP, args->node); 1525 1526 pnode = di_parent_node(args->node); 1527 if (pnode != DI_NODE_NIL) { 1528 char prop_name[MAXPROPLEN]; 1529 1530 (void) snprintf(prop_name, sizeof (prop_name), 1531 "target%d-sync-speed", aliasp->target); 1532 diskp->sync_speed = get_prop(prop_name, pnode); 1533 (void) snprintf(prop_name, sizeof (prop_name), "target%d-wide", 1534 aliasp->target); 1535 diskp->wide = get_prop(prop_name, pnode); 1536 } 1537 1538 if (new_devpath(aliasp, devlink_path) != 0) { 1539 cache_free_alias(aliasp); 1540 return (ENOMEM); 1541 } 1542 1543 aliasp->next = diskp->aliases; 1544 diskp->aliases = aliasp; 1545 1546 return (0); 1547 } 1548 1549 /* 1550 * Append the new devpath to the end of the devpath list. This is important 1551 * since we may want to use the order of the devpaths to match up the vtoc 1552 * entries. 1553 */ 1554 static int 1555 new_devpath(alias_t *ap, char *devpath) 1556 { 1557 slice_t *newdp; 1558 slice_t *alistp; 1559 1560 /* 1561 * First, search the alias list to be sure that this devpath is 1562 * not already there. 1563 */ 1564 1565 for (alistp = ap->devpaths; alistp != NULL; alistp = alistp->next) { 1566 if (libdiskmgt_str_eq(alistp->devpath, devpath)) { 1567 return (0); 1568 } 1569 } 1570 1571 /* 1572 * Otherwise, not found so add this new devpath to the list. 1573 */ 1574 1575 newdp = malloc(sizeof (slice_t)); 1576 if (newdp == NULL) { 1577 return (ENOMEM); 1578 } 1579 1580 newdp->devpath = strdup(devpath); 1581 if (newdp->devpath == NULL) { 1582 free(newdp); 1583 return (ENOMEM); 1584 } 1585 newdp->slice_num = -1; 1586 newdp->next = NULL; 1587 1588 if (ap->devpaths == NULL) { 1589 ap->devpaths = newdp; 1590 } else { 1591 /* append the devpath to the end of the list */ 1592 slice_t *dp; 1593 1594 dp = ap->devpaths; 1595 while (dp->next != NULL) { 1596 dp = dp->next; 1597 } 1598 1599 dp->next = newdp; 1600 } 1601 1602 return (0); 1603 } 1604 1605 static path_t * 1606 new_path(controller_t *cp, disk_t *dp, di_node_t node, di_path_state_t st, 1607 char *wwn) 1608 { 1609 char *devpath; 1610 path_t *pp; 1611 di_minor_t minor; 1612 1613 /* Special handling for fp attachment node. */ 1614 if (strcmp(di_node_name(node), "fp") == 0) { 1615 di_node_t pnode; 1616 1617 pnode = di_parent_node(node); 1618 if (pnode != DI_NODE_NIL) { 1619 node = pnode; 1620 } 1621 } 1622 1623 devpath = di_devfs_path(node); 1624 1625 /* check if the path is already there */ 1626 pp = NULL; 1627 if (cp->paths != NULL) { 1628 int i; 1629 1630 for (i = 0; cp->paths[i]; i++) { 1631 if (libdiskmgt_str_eq(devpath, cp->paths[i]->name)) { 1632 pp = cp->paths[i]; 1633 break; 1634 } 1635 } 1636 } 1637 1638 if (pp != NULL) { 1639 /* the path exists, add this disk to it */ 1640 1641 di_devfs_path_free((void *) devpath); 1642 if (!add_disk2path(dp, pp, st, wwn)) { 1643 return (NULL); 1644 } 1645 return (pp); 1646 } 1647 1648 /* create a new path */ 1649 1650 pp = calloc(1, sizeof (path_t)); 1651 if (pp == NULL) { 1652 di_devfs_path_free((void *) devpath); 1653 return (NULL); 1654 } 1655 1656 pp->name = strdup(devpath); 1657 di_devfs_path_free((void *) devpath); 1658 if (pp->name == NULL) { 1659 cache_free_path(pp); 1660 return (NULL); 1661 } 1662 1663 /* add the disk to the path */ 1664 if (!add_disk2path(dp, pp, st, wwn)) { 1665 return (NULL); 1666 } 1667 1668 /* add the path to the controller */ 1669 if (add_ptr2array(pp, (void ***)&cp->paths) != 0) { 1670 cache_free_path(pp); 1671 return (NULL); 1672 } 1673 1674 /* add the controller to the path */ 1675 pp->controller = cp; 1676 1677 minor = di_minor_next(node, NULL); 1678 if (minor != NULL) { 1679 pp->ctype = ctype(node, minor); 1680 } else { 1681 pp->ctype = DM_CTYPE_UNKNOWN; 1682 } 1683 1684 return (pp); 1685 } 1686 1687 /* 1688 * We pass in the current controller pointer (currp) so we can double check 1689 * that we aren't corrupting the list by removing the element we are on. This 1690 * should never happen, but it doesn't hurt to double check. 1691 */ 1692 static void 1693 remove_invalid_controller(char *name, controller_t *currp, 1694 struct search_args *args) 1695 { 1696 controller_t *cp; 1697 bus_t *bp; 1698 controller_t *prevp; 1699 1700 bp = args->bus_listp; 1701 while (bp != NULL) { 1702 int i; 1703 1704 for (i = 0; bp->controllers[i]; i++) { 1705 if (libdiskmgt_str_eq(bp->controllers[i]->name, name)) { 1706 int j; 1707 /* 1708 * remove pointer to invalid controller. 1709 * (it is a path) 1710 */ 1711 for (j = i; bp->controllers[j]; j++) { 1712 bp->controllers[j] = 1713 bp->controllers[j + 1]; 1714 } 1715 } 1716 } 1717 bp = bp->next; 1718 } 1719 1720 if (args->controller_listp == NULL) { 1721 return; 1722 } 1723 1724 cp = args->controller_listp; 1725 if (libdiskmgt_str_eq(cp->name, name)) { 1726 args->controller_listp = cp->next; 1727 if (dm_debug) { 1728 (void) fprintf(stderr, 1729 "INFO: Removed controller %s from list\n", 1730 cp->name); 1731 } 1732 remove_controller(cp, currp); 1733 return; 1734 } 1735 1736 prevp = cp; 1737 cp = cp->next; 1738 while (cp != NULL) { 1739 if (libdiskmgt_str_eq(cp->name, name)) { 1740 if (dm_debug) { 1741 (void) fprintf(stderr, 1742 "INFO: Removed controller %s from list\n", 1743 cp->name); 1744 } 1745 prevp->next = cp->next; 1746 remove_controller(cp, currp); 1747 return; 1748 } 1749 prevp = cp; 1750 cp = cp->next; 1751 } 1752 } 1753