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