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