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