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 } 1689