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