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