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 diskp->solid_state = -1; 1001 type = di_minor_nodetype(args->minor); 1002 1003 prod_id = get_str_prop(PROD_ID_PROP, args->node); 1004 if (prod_id != NULL) { 1005 if ((diskp->product_id = strdup(prod_id)) == NULL) { 1006 cache_free_disk(diskp); 1007 return (NULL); 1008 } 1009 } else { 1010 prod_id = get_str_prop(PROD_ID_USB_PROP, args->node); 1011 if (prod_id != NULL) { 1012 if ((diskp->product_id = strdup(prod_id)) == NULL) { 1013 cache_free_disk(diskp); 1014 return (NULL); 1015 } 1016 } 1017 } 1018 1019 vendor_id = get_str_prop(VENDOR_ID_PROP, args->node); 1020 if (vendor_id != NULL) { 1021 if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { 1022 cache_free_disk(diskp); 1023 return (NULL); 1024 } 1025 } else { 1026 vendor_id = get_str_prop(VENDOR_ID_PROP, args->node); 1027 if (vendor_id != NULL) { 1028 if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { 1029 cache_free_disk(diskp); 1030 return (NULL); 1031 } 1032 } 1033 } 1034 1035 /* 1036 * DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS. 1037 * We try to use uscsi later to determine the real type. 1038 * The cd_rom flag tells us that the kernel categorized the drive 1039 * as a CD-ROM. We leave the drv_type as UKNOWN for now. 1040 * The combination of the cd_rom flag being set with the drv_type of 1041 * unknown is what triggers the uscsi probe in drive.c. 1042 */ 1043 if (disk_is_cdrom(type)) { 1044 diskp->drv_type = DM_DT_UNKNOWN; 1045 diskp->cd_rom = 1; 1046 diskp->removable = 1; 1047 } else if (libdiskmgt_str_eq(type, DDI_NT_FD)) { 1048 diskp->drv_type = DM_DT_FLOPPY; 1049 diskp->removable = 1; 1050 } else { 1051 /* not a "CD-ROM" or Floppy */ 1052 diskp->removable = get_prop(REMOVABLE_PROP, args->node); 1053 1054 if (diskp->removable == -1) { 1055 diskp->removable = 0; 1056 #if defined(i386) || defined(__amd64) 1057 /* 1058 * x86 does not have removable property. 1059 * Check for common removable drives, zip & jaz, 1060 * and mark those correctly. 1061 */ 1062 if (vendor_id != NULL && prod_id != NULL) { 1063 if (str_case_index(vendor_id, 1064 "iomega") != NULL) { 1065 if (str_case_index(prod_id, 1066 "jaz") != NULL) { 1067 diskp->removable = 1; 1068 } else if (str_case_index(prod_id, 1069 "zip") != NULL) { 1070 diskp->removable = 1; 1071 } 1072 } 1073 } 1074 #endif 1075 } 1076 1077 if (diskp->removable) { 1078 /* 1079 * For removable jaz or zip drives there is no way 1080 * to get the drive type unless media is inserted,so 1081 * we look at the product-id for a hint. 1082 */ 1083 diskp->drv_type = DM_DT_UNKNOWN; 1084 1085 if (prod_id != NULL) { 1086 if (str_case_index(prod_id, "jaz") != NULL) { 1087 diskp->drv_type = DM_DT_JAZ; 1088 } else if (str_case_index(prod_id, 1089 "zip") != NULL) { 1090 diskp->drv_type = DM_DT_ZIP; 1091 } 1092 } 1093 } else { 1094 diskp->drv_type = DM_DT_FIXED; 1095 } 1096 } 1097 1098 diskp->next = args->disk_listp; 1099 args->disk_listp = diskp; 1100 1101 return (diskp); 1102 } 1103 1104 static char * 1105 ctype(di_node_t node, di_minor_t minor) 1106 { 1107 char *type; 1108 char *name; 1109 1110 type = di_minor_nodetype(minor); 1111 name = di_node_name(node); 1112 1113 /* IDE disks use SCSI nexus as the type, so handle this special case */ 1114 if (libdiskmgt_str_eq(name, "ide")) { 1115 return (DM_CTYPE_ATA); 1116 } 1117 1118 if (libdiskmgt_str_eq(di_minor_name(minor), "scsa2usb")) { 1119 return (DM_CTYPE_USB); 1120 } 1121 1122 if (libdiskmgt_str_eq(type, DDI_NT_SCSI_NEXUS) || 1123 libdiskmgt_str_eq(type, DDI_NT_SCSI_ATTACHMENT_POINT)) { 1124 return (DM_CTYPE_SCSI); 1125 } 1126 1127 if (libdiskmgt_str_eq(type, DDI_NT_FC_ATTACHMENT_POINT)) { 1128 return (DM_CTYPE_FIBRE); 1129 } 1130 1131 if (libdiskmgt_str_eq(type, DDI_NT_NEXUS) && 1132 libdiskmgt_str_eq(name, "fp")) { 1133 return (DM_CTYPE_FIBRE); 1134 } 1135 1136 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1137 libdiskmgt_str_eq(name, "ide")) { 1138 return (DM_CTYPE_ATA); 1139 } 1140 1141 return (DM_CTYPE_UNKNOWN); 1142 } 1143 1144 static boolean_t 1145 disk_is_cdrom(const char *type) 1146 { 1147 return (strncmp(type, DDI_NT_CD, strlen(DDI_NT_CD)) == 0); 1148 } 1149 1150 static alias_t * 1151 find_alias(disk_t *diskp, char *kernel_name) 1152 { 1153 alias_t *ap; 1154 1155 ap = diskp->aliases; 1156 while (ap != NULL) { 1157 if (libdiskmgt_str_eq(ap->kstat_name, kernel_name)) { 1158 return (ap); 1159 } 1160 ap = ap->next; 1161 } 1162 1163 return (NULL); 1164 } 1165 1166 static bus_t * 1167 find_bus(struct search_args *args, char *name) 1168 { 1169 bus_t *listp; 1170 1171 listp = args->bus_listp; 1172 while (listp != NULL) { 1173 if (libdiskmgt_str_eq(listp->name, name)) { 1174 return (listp); 1175 } 1176 listp = listp->next; 1177 } 1178 1179 return (NULL); 1180 } 1181 1182 static controller_t * 1183 find_controller(struct search_args *args, char *name) 1184 { 1185 controller_t *listp; 1186 1187 listp = args->controller_listp; 1188 while (listp != NULL) { 1189 if (libdiskmgt_str_eq(listp->name, name)) { 1190 return (listp); 1191 } 1192 listp = listp->next; 1193 } 1194 1195 return (NULL); 1196 } 1197 1198 static int 1199 fix_cluster_devpath(di_devlink_t devlink, void *arg) 1200 { 1201 int fd; 1202 struct search_args *args; 1203 char *devlink_path; 1204 disk_t *diskp = NULL; 1205 alias_t *ap = NULL; 1206 1207 /* 1208 * The devlink_path is of the form /dev/did/rdsk/d1s0. 1209 */ 1210 1211 args = (struct search_args *)arg; 1212 1213 /* Find the disk by the deviceid we read from the cluster disk. */ 1214 devlink_path = (char *)di_devlink_path(devlink); 1215 if (devlink_path == NULL) { 1216 return (DI_WALK_CONTINUE); 1217 } 1218 1219 if ((fd = open(devlink_path, O_RDONLY|O_NDELAY)) >= 0) { 1220 ddi_devid_t devid; 1221 1222 if (dm_debug > 1) { 1223 (void) fprintf(stderr, "INFO: cluster devpath %s\n", 1224 devlink_path); 1225 } 1226 1227 if (devid_get(fd, &devid) == 0) { 1228 char *minor; 1229 char *devidstr; 1230 1231 minor = di_minor_name(args->minor); 1232 1233 if ((devidstr = 1234 devid_str_encode(devid, minor)) != NULL) { 1235 diskp = get_disk_by_deviceid(args->disk_listp, 1236 devidstr); 1237 /* 1238 * This really shouldn't happen, since 1239 * we should have found all of the disks 1240 * during our first pass through 1241 * the dev tree, but just in case... 1242 */ 1243 if (diskp == NULL) { 1244 if (dm_debug > 1) { 1245 (void) fprintf(stderr, 1246 "INFO: cluster create" 1247 " disk\n"); 1248 } 1249 1250 diskp = create_disk(devidstr, 1251 NULL, args); 1252 if (diskp == NULL) { 1253 args->dev_walk_status = ENOMEM; 1254 } 1255 1256 /* add the controller relationship */ 1257 if (args->dev_walk_status == 0) { 1258 if (add_disk2controller(diskp, 1259 args) != 0) { 1260 args->dev_walk_status 1261 = ENOMEM; 1262 } 1263 } 1264 1265 if (new_alias(diskp, NULL, 1266 devlink_path, args) != 0) { 1267 args->dev_walk_status = ENOMEM; 1268 } 1269 } 1270 devid_str_free(devidstr); 1271 } 1272 devid_free(devid); 1273 } 1274 (void) close(fd); 1275 } 1276 1277 1278 if (diskp != NULL) { 1279 if (dm_debug > 1) { 1280 (void) fprintf(stderr, "INFO: cluster found" 1281 " disk\n"); 1282 } 1283 ap = diskp->aliases; 1284 } 1285 1286 if (ap != NULL) { 1287 /* 1288 * NOTE: if ap->next != NULL have cluster 1289 * disks w/ multiple paths. 1290 */ 1291 1292 if (!ap->cluster) { 1293 char *basep; 1294 char *namep; 1295 int cnt = 0; 1296 int size; 1297 char alias[MAXPATHLEN]; 1298 1299 /* 1300 * First time; save the /dev/rdsk devpaths and 1301 * update the alias info with the new alias name. 1302 */ 1303 ap->orig_paths = ap->devpaths; 1304 ap->devpaths = NULL; 1305 1306 free(ap->alias); 1307 1308 /* get the new cluster alias name */ 1309 basep = strrchr(devlink_path, '/'); 1310 if (basep == NULL) { 1311 basep = devlink_path; 1312 } else { 1313 basep++; 1314 } 1315 size = sizeof (alias) - 1; 1316 namep = alias; 1317 1318 while (*basep != 0 && *basep != 's' && cnt < size) { 1319 *namep++ = *basep++; 1320 cnt++; 1321 } 1322 *namep = 0; 1323 1324 if ((ap->alias = strdup(alias)) == NULL) { 1325 args->dev_walk_status = ENOMEM; 1326 } 1327 1328 ap->cluster = 1; 1329 } 1330 1331 if (new_devpath(ap, devlink_path) != 0) { 1332 args->dev_walk_status = ENOMEM; 1333 } 1334 } 1335 1336 return (DI_WALK_CONTINUE); 1337 } 1338 1339 /* 1340 * Check if we have the drive in our list, based upon the device id. 1341 * We got the device id from the dev tree walk. This is encoded 1342 * using devid_str_encode(3DEVID). In order to check the device ids we need 1343 * to use the devid_compare(3DEVID) function, so we need to decode the 1344 * string representation of the device id. 1345 */ 1346 static disk_t * 1347 get_disk_by_deviceid(disk_t *listp, char *devidstr) 1348 { 1349 ddi_devid_t devid; 1350 1351 if (devidstr == NULL || devid_str_decode(devidstr, &devid, NULL) != 0) { 1352 return (NULL); 1353 } 1354 1355 while (listp != NULL) { 1356 if (listp->devid != NULL && 1357 devid_compare(listp->devid, devid) == 0) { 1358 break; 1359 } 1360 listp = listp->next; 1361 } 1362 1363 devid_free(devid); 1364 return (listp); 1365 } 1366 1367 /* 1368 * Get the base disk name with no path prefix and no slice (if there is one). 1369 * The name parameter should be big enough to hold the name. 1370 * This handles diskette names ok (/dev/rdiskette0) since there is no slice, 1371 * and converts the raw diskette name. 1372 * But, we don't know how to strip off the slice from third party drive 1373 * names. That just means that their drive name will include a slice on 1374 * it. 1375 */ 1376 static void 1377 get_disk_name_from_path(char *path, char *name, int size) 1378 { 1379 char *basep; 1380 int cnt = 0; 1381 1382 basep = strrchr(path, '/'); 1383 if (basep == NULL) { 1384 basep = path; 1385 } else { 1386 basep++; 1387 } 1388 1389 size = size - 1; /* leave room for terminating 0 */ 1390 1391 if (is_ctds(basep)) { 1392 while (*basep != 0 && *basep != 's' && cnt < size) { 1393 *name++ = *basep++; 1394 cnt++; 1395 } 1396 *name = 0; 1397 } else { 1398 if (strncmp(basep, FLOPPY_NAME, 1399 sizeof (FLOPPY_NAME) - 1) == 0) { 1400 /* 1401 * a floppy, convert rdiskette name to diskette name, 1402 * by skipping over the 'r' for raw diskette 1403 */ 1404 basep++; 1405 } 1406 1407 /* not a ctds name, just copy it */ 1408 (void) strlcpy(name, basep, size); 1409 } 1410 } 1411 1412 static char * 1413 get_byte_prop(char *prop_name, di_node_t node) 1414 { 1415 int cnt; 1416 uchar_t *bytes; 1417 int i; 1418 char str[MAXPATHLEN]; 1419 1420 cnt = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, prop_name, &bytes); 1421 if (cnt < 1) { 1422 return (NULL); 1423 } 1424 1425 str[0] = 0; 1426 for (i = 0; i < cnt; i++) { 1427 char bstr[8]; /* a byte is only 2 hex chars + null */ 1428 1429 (void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]); 1430 (void) strlcat(str, bstr, sizeof (str)); 1431 } 1432 return (strdup(str)); 1433 } 1434 1435 static di_node_t 1436 get_parent_bus(di_node_t node, struct search_args *args) 1437 { 1438 di_node_t pnode; 1439 1440 pnode = di_parent_node(node); 1441 if (pnode == DI_NODE_NIL) { 1442 return (NULL); 1443 } 1444 1445 if (bus_type(pnode, di_minor_next(pnode, NULL), args->ph) != NULL) { 1446 return (pnode); 1447 } 1448 1449 return (get_parent_bus(pnode, args)); 1450 } 1451 1452 static int 1453 get_prom_int(char *prop_name, di_node_t node, di_prom_handle_t ph) 1454 { 1455 int *n; 1456 1457 if (di_prom_prop_lookup_ints(ph, node, prop_name, &n) == 1) { 1458 return (*n); 1459 } 1460 1461 return (0); 1462 } 1463 1464 static char * 1465 get_prom_str(char *prop_name, di_node_t node, di_prom_handle_t ph) 1466 { 1467 char *str; 1468 1469 if (di_prom_prop_lookup_strings(ph, node, prop_name, &str) == 1) { 1470 return (str); 1471 } 1472 1473 return (NULL); 1474 } 1475 1476 /* 1477 * Get one of the positive int or boolean properties. 1478 */ 1479 static int 1480 get_prop(char *prop_name, di_node_t node) 1481 { 1482 int num; 1483 int *ip; 1484 1485 if ((num = di_prop_lookup_ints(DDI_DEV_T_ANY, node, prop_name, &ip)) 1486 >= 0) { 1487 if (num == 0) { 1488 /* boolean */ 1489 return (1); 1490 } else if (num == 1) { 1491 /* single int */ 1492 return (*ip); 1493 } 1494 } 1495 return (-1); 1496 } 1497 1498 static char * 1499 get_str_prop(char *prop_name, di_node_t node) 1500 { 1501 char *str; 1502 1503 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, prop_name, &str) == 1) { 1504 return (str); 1505 } 1506 1507 return (NULL); 1508 } 1509 1510 /* 1511 * Check if we have the drive in our list, based upon the device id, if the 1512 * drive has a device id, or the kernel name, if it doesn't have a device id. 1513 */ 1514 static int 1515 have_disk(struct search_args *args, char *devidstr, char *kernel_name, 1516 disk_t **diskp) 1517 { 1518 disk_t *listp; 1519 1520 *diskp = NULL; 1521 listp = args->disk_listp; 1522 if (devidstr != NULL) { 1523 if ((*diskp = get_disk_by_deviceid(listp, devidstr)) != NULL) { 1524 return (1); 1525 } 1526 1527 } else { 1528 /* no devid, try matching the kernel names on the drives */ 1529 while (listp != NULL) { 1530 if (libdiskmgt_str_eq(kernel_name, 1531 listp->kernel_name)) { 1532 *diskp = listp; 1533 return (1); 1534 } 1535 listp = listp->next; 1536 } 1537 } 1538 return (0); 1539 } 1540 1541 static char * 1542 bus_type(di_node_t node, di_minor_t minor, di_prom_handle_t ph) 1543 { 1544 char *type; 1545 int i; 1546 1547 type = get_prom_str("device_type", node, ph); 1548 if (type == NULL) { 1549 type = di_node_name(node); 1550 } 1551 1552 for (i = 0; bustypes[i]; i++) { 1553 if (libdiskmgt_str_eq(type, bustypes[i])) { 1554 return (type); 1555 } 1556 } 1557 1558 if (minor != NULL && strcmp(di_minor_nodetype(minor), 1559 DDI_NT_USB_ATTACHMENT_POINT) == 0) { 1560 return ("usb"); 1561 } 1562 1563 return (NULL); 1564 } 1565 1566 static int 1567 is_cluster_disk(di_node_t node, di_minor_t minor) 1568 { 1569 if (di_minor_spectype(minor) == S_IFCHR && 1570 libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_PSEUDO) && 1571 libdiskmgt_str_eq(di_node_name(node), CLUSTER_DEV)) { 1572 return (1); 1573 } 1574 1575 return (0); 1576 } 1577 1578 /* 1579 * If the input name is in c[t]ds format then return 1, otherwise return 0. 1580 */ 1581 static int 1582 is_ctds(char *name) 1583 { 1584 char *p; 1585 1586 p = name; 1587 1588 if (*p++ != 'c') { 1589 return (0); 1590 } 1591 /* skip controller digits */ 1592 while (isdigit(*p)) { 1593 p++; 1594 } 1595 1596 /* handle optional target */ 1597 if (*p == 't') { 1598 p++; 1599 /* skip over target */ 1600 while (isdigit(*p) || isupper(*p)) { 1601 p++; 1602 } 1603 } 1604 1605 if (*p++ != 'd') { 1606 return (0); 1607 } 1608 while (isdigit(*p)) { 1609 p++; 1610 } 1611 1612 if (*p++ != 's') { 1613 return (0); 1614 } 1615 1616 /* check the slice number */ 1617 while (isdigit(*p)) { 1618 p++; 1619 } 1620 1621 if (*p != 0) { 1622 return (0); 1623 } 1624 1625 return (1); 1626 } 1627 1628 static int 1629 is_drive(di_minor_t minor) 1630 { 1631 return (strncmp(di_minor_nodetype(minor), DDI_NT_BLOCK, 1632 strlen(DDI_NT_BLOCK)) == 0); 1633 } 1634 1635 static int 1636 is_zvol(di_node_t node, di_minor_t minor) 1637 { 1638 if ((strncmp(di_node_name(node), ZFS_DRIVER, 3) == 0) && 1639 minor(di_minor_devt(minor))) 1640 return (1); 1641 return (0); 1642 } 1643 1644 static int 1645 is_HBA(di_node_t node, di_minor_t minor) 1646 { 1647 char *type; 1648 char *name; 1649 int type_index; 1650 1651 type = di_minor_nodetype(minor); 1652 type_index = 0; 1653 1654 while (ctrltypes[type_index] != NULL) { 1655 if (libdiskmgt_str_eq(type, ctrltypes[type_index])) { 1656 return (1); 1657 } 1658 type_index++; 1659 } 1660 1661 name = di_node_name(node); 1662 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1663 libdiskmgt_str_eq(name, "ide")) { 1664 return (1); 1665 } 1666 1667 return (0); 1668 } 1669 1670 static int 1671 new_alias(disk_t *diskp, char *kernel_name, char *devlink_path, 1672 struct search_args *args) 1673 { 1674 alias_t *aliasp; 1675 char alias[MAXPATHLEN]; 1676 di_node_t pnode; 1677 1678 aliasp = malloc(sizeof (alias_t)); 1679 if (aliasp == NULL) { 1680 return (ENOMEM); 1681 } 1682 1683 aliasp->alias = NULL; 1684 aliasp->kstat_name = NULL; 1685 aliasp->wwn = NULL; 1686 aliasp->devpaths = NULL; 1687 aliasp->orig_paths = NULL; 1688 1689 get_disk_name_from_path(devlink_path, alias, sizeof (alias)); 1690 1691 aliasp->alias = strdup(alias); 1692 if (aliasp->alias == NULL) { 1693 cache_free_alias(aliasp); 1694 return (ENOMEM); 1695 } 1696 1697 if (kernel_name != NULL) { 1698 aliasp->kstat_name = strdup(kernel_name); 1699 if (aliasp->kstat_name == NULL) { 1700 cache_free_alias(aliasp); 1701 return (ENOMEM); 1702 } 1703 } else { 1704 aliasp->kstat_name = NULL; 1705 } 1706 1707 aliasp->cluster = 0; 1708 aliasp->lun = get_prop(DM_LUN, args->node); 1709 aliasp->target = get_prop(DM_TARGET, args->node); 1710 aliasp->wwn = get_byte_prop(WWN_PROP, args->node); 1711 1712 pnode = di_parent_node(args->node); 1713 if (pnode != DI_NODE_NIL) { 1714 char prop_name[MAXPROPLEN]; 1715 1716 (void) snprintf(prop_name, sizeof (prop_name), 1717 "target%d-sync-speed", aliasp->target); 1718 diskp->sync_speed = get_prop(prop_name, pnode); 1719 (void) snprintf(prop_name, sizeof (prop_name), "target%d-wide", 1720 aliasp->target); 1721 diskp->wide = get_prop(prop_name, pnode); 1722 } 1723 1724 if (new_devpath(aliasp, devlink_path) != 0) { 1725 cache_free_alias(aliasp); 1726 return (ENOMEM); 1727 } 1728 1729 aliasp->next = diskp->aliases; 1730 diskp->aliases = aliasp; 1731 1732 return (0); 1733 } 1734 1735 /* 1736 * Append the new devpath to the end of the devpath list. This is important 1737 * since we may want to use the order of the devpaths to match up the vtoc 1738 * entries. 1739 */ 1740 static int 1741 new_devpath(alias_t *ap, char *devpath) 1742 { 1743 slice_t *newdp; 1744 slice_t *alistp; 1745 1746 /* 1747 * First, search the alias list to be sure that this devpath is 1748 * not already there. 1749 */ 1750 1751 for (alistp = ap->devpaths; alistp != NULL; alistp = alistp->next) { 1752 if (libdiskmgt_str_eq(alistp->devpath, devpath)) { 1753 return (0); 1754 } 1755 } 1756 1757 /* 1758 * Otherwise, not found so add this new devpath to the list. 1759 */ 1760 1761 newdp = malloc(sizeof (slice_t)); 1762 if (newdp == NULL) { 1763 return (ENOMEM); 1764 } 1765 1766 newdp->devpath = strdup(devpath); 1767 if (newdp->devpath == NULL) { 1768 free(newdp); 1769 return (ENOMEM); 1770 } 1771 newdp->slice_num = -1; 1772 newdp->next = NULL; 1773 1774 if (ap->devpaths == NULL) { 1775 ap->devpaths = newdp; 1776 } else { 1777 /* append the devpath to the end of the list */ 1778 slice_t *dp; 1779 1780 dp = ap->devpaths; 1781 while (dp->next != NULL) { 1782 dp = dp->next; 1783 } 1784 1785 dp->next = newdp; 1786 } 1787 1788 return (0); 1789 } 1790 1791 static path_t * 1792 new_path(controller_t *cp, disk_t *dp, di_node_t node, di_path_state_t st, 1793 char *wwn) 1794 { 1795 char *devpath; 1796 path_t *pp; 1797 di_minor_t minor; 1798 1799 /* Special handling for fp attachment node. */ 1800 if (strcmp(di_node_name(node), "fp") == 0) { 1801 di_node_t pnode; 1802 1803 pnode = di_parent_node(node); 1804 if (pnode != DI_NODE_NIL) { 1805 node = pnode; 1806 } 1807 } 1808 1809 devpath = di_devfs_path(node); 1810 1811 /* check if the path is already there */ 1812 pp = NULL; 1813 if (cp->paths != NULL) { 1814 int i; 1815 1816 for (i = 0; cp->paths[i]; i++) { 1817 if (libdiskmgt_str_eq(devpath, cp->paths[i]->name)) { 1818 pp = cp->paths[i]; 1819 break; 1820 } 1821 } 1822 } 1823 1824 if (pp != NULL) { 1825 /* the path exists, add this disk to it */ 1826 1827 di_devfs_path_free((void *) devpath); 1828 if (!add_disk2path(dp, pp, st, wwn)) { 1829 return (NULL); 1830 } 1831 return (pp); 1832 } 1833 1834 /* create a new path */ 1835 1836 pp = calloc(1, sizeof (path_t)); 1837 if (pp == NULL) { 1838 di_devfs_path_free((void *) devpath); 1839 return (NULL); 1840 } 1841 1842 pp->name = strdup(devpath); 1843 di_devfs_path_free((void *) devpath); 1844 if (pp->name == NULL) { 1845 cache_free_path(pp); 1846 return (NULL); 1847 } 1848 1849 /* add the disk to the path */ 1850 if (!add_disk2path(dp, pp, st, wwn)) { 1851 return (NULL); 1852 } 1853 1854 /* add the path to the controller */ 1855 if (add_ptr2array(pp, (void ***)&cp->paths) != 0) { 1856 cache_free_path(pp); 1857 return (NULL); 1858 } 1859 1860 /* add the controller to the path */ 1861 pp->controller = cp; 1862 1863 minor = di_minor_next(node, NULL); 1864 if (minor != NULL) { 1865 pp->ctype = ctype(node, minor); 1866 } else { 1867 pp->ctype = DM_CTYPE_UNKNOWN; 1868 } 1869 1870 return (pp); 1871 } 1872 1873 /* 1874 * We pass in the current controller pointer (currp) so we can double check 1875 * that we aren't corrupting the list by removing the element we are on. This 1876 * should never happen, but it doesn't hurt to double check. 1877 */ 1878 static void 1879 remove_invalid_controller(char *name, controller_t *currp, 1880 struct search_args *args) 1881 { 1882 controller_t *cp; 1883 bus_t *bp; 1884 controller_t *prevp; 1885 1886 bp = args->bus_listp; 1887 while (bp != NULL) { 1888 int i; 1889 1890 for (i = 0; bp->controllers[i]; i++) { 1891 if (libdiskmgt_str_eq(bp->controllers[i]->name, name)) { 1892 int j; 1893 /* 1894 * remove pointer to invalid controller. 1895 * (it is a path) 1896 */ 1897 for (j = i; bp->controllers[j]; j++) { 1898 bp->controllers[j] = 1899 bp->controllers[j + 1]; 1900 } 1901 } 1902 } 1903 bp = bp->next; 1904 } 1905 1906 if (args->controller_listp == NULL) { 1907 return; 1908 } 1909 1910 cp = args->controller_listp; 1911 if (libdiskmgt_str_eq(cp->name, name)) { 1912 args->controller_listp = cp->next; 1913 if (dm_debug) { 1914 (void) fprintf(stderr, 1915 "INFO: Removed controller %s from list\n", 1916 cp->name); 1917 } 1918 remove_controller(cp, currp); 1919 return; 1920 } 1921 1922 prevp = cp; 1923 cp = cp->next; 1924 while (cp != NULL) { 1925 if (libdiskmgt_str_eq(cp->name, name)) { 1926 if (dm_debug) { 1927 (void) fprintf(stderr, 1928 "INFO: Removed controller %s from list\n", 1929 cp->name); 1930 } 1931 prevp->next = cp->next; 1932 remove_controller(cp, currp); 1933 return; 1934 } 1935 prevp = cp; 1936 cp = cp->next; 1937 } 1938 } 1939 1940 /* 1941 * This is the standard strstr code modified for case independence. 1942 */ 1943 static char * 1944 str_case_index(register char *s1, register char *s2) 1945 { 1946 uint_t s2len = strlen(s2); /* length of the second string */ 1947 1948 /* If the length of the second string is 0, return the first arg. */ 1949 if (s2len == 0) { 1950 return (s1); 1951 } 1952 1953 while (strlen(s1) >= s2len) { 1954 if (strncasecmp(s1, s2, s2len) == 0) { 1955 return (s1); 1956 } 1957 s1++; 1958 } 1959 return (NULL); 1960 } 1961