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