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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <fcntl.h> 30 #include <libdevinfo.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <sys/stat.h> 35 #include <sys/sunddi.h> 36 #include <sys/types.h> 37 #include <ctype.h> 38 #include <libgen.h> 39 #include <unistd.h> 40 #include <devid.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_HBA(di_node_t node, di_minor_t minor); 145 static int new_alias(disk_t *diskp, char *kernel_path, 146 char *devlink_path, struct search_args *args); 147 static int new_devpath(alias_t *ap, char *devpath); 148 static path_t *new_path(controller_t *cp, disk_t *diskp, 149 di_node_t node, di_path_state_t st, char *wwn); 150 static void remove_invalid_controller(char *name, 151 controller_t *currp, struct search_args *args); 152 static char *str_case_index(register char *s1, register char *s2); 153 154 /* 155 * The functions in this file do a dev tree walk to build up a model of the 156 * disks, controllers and paths on the system. This model is returned in the 157 * args->disk_listp and args->controller_listp members of the args param. 158 * There is no global data for this file so it is thread safe. It is up to 159 * the caller to merge the resulting model with any existing model that is 160 * cached. The caller must also free the memory for this model when it is 161 * no longer needed. 162 */ 163 void 164 findevs(struct search_args *args) 165 { 166 uint_t flags; 167 di_node_t di_root; 168 169 args->dev_walk_status = 0; 170 args->disk_listp = NULL; 171 args->controller_listp = NULL; 172 args->bus_listp = NULL; 173 174 args->handle = di_devlink_init(NULL, 0); 175 176 /* 177 * Have to make several passes at this with the new devfs caching. 178 * First, we find non-mpxio devices. Then we find mpxio/multipath 179 * devices. Finally, we get cluster devices. 180 */ 181 flags = DINFOCACHE; 182 di_root = di_init("/", flags); 183 args->ph = di_prom_init(); 184 (void) di_walk_minor(di_root, NULL, 0, args, add_devs); 185 di_fini(di_root); 186 187 flags = DINFOCPYALL | DINFOPATH; 188 di_root = di_init("/", flags); 189 (void) di_walk_minor(di_root, NULL, 0, args, add_devs); 190 di_fini(di_root); 191 192 /* do another pass to clean up cluster devpaths */ 193 flags = DINFOCACHE; 194 di_root = di_init("/", flags); 195 (void) di_walk_minor(di_root, DDI_PSEUDO, 0, args, add_cluster_devs); 196 if (args->ph != DI_PROM_HANDLE_NIL) { 197 (void) di_prom_fini(args->ph); 198 } 199 di_fini(di_root); 200 201 (void) di_devlink_fini(&(args->handle)); 202 203 clean_paths(args); 204 } 205 206 /* 207 * Definitions of private functions 208 */ 209 210 static bus_t * 211 add_bus(struct search_args *args, di_node_t node, di_minor_t minor, 212 controller_t *cp) 213 { 214 char *btype; 215 char *devpath; 216 bus_t *bp; 217 char kstat_name[MAXPATHLEN]; 218 di_node_t pnode; 219 220 if (node == DI_NODE_NIL) { 221 return (NULL); 222 } 223 224 if ((btype = bus_type(node, minor, args->ph)) == NULL) { 225 return (add_bus(args, di_parent_node(node), 226 di_minor_next(di_parent_node(node), NULL), cp)); 227 } 228 229 devpath = di_devfs_path(node); 230 231 if ((bp = find_bus(args, devpath)) != NULL) { 232 di_devfs_path_free((void *) devpath); 233 234 if (cp != NULL) { 235 if (add_ptr2array(cp, (void ***)&bp->controllers) != 0) { 236 args->dev_walk_status = ENOMEM; 237 return (NULL); 238 } 239 } 240 return (bp); 241 } 242 243 /* Special handling for root node. */ 244 if (strcmp(devpath, "/") == 0) { 245 di_devfs_path_free((void *) devpath); 246 return (NULL); 247 } 248 249 if (dm_debug) { 250 (void) fprintf(stderr, "INFO: add_bus %s\n", devpath); 251 } 252 253 bp = (bus_t *)calloc(1, sizeof (bus_t)); 254 if (bp == NULL) { 255 return (NULL); 256 } 257 258 bp->name = strdup(devpath); 259 di_devfs_path_free((void *) devpath); 260 if (bp->name == NULL) { 261 args->dev_walk_status = ENOMEM; 262 cache_free_bus(bp); 263 return (NULL); 264 } 265 266 bp->btype = strdup(btype); 267 if (bp->btype == NULL) { 268 args->dev_walk_status = ENOMEM; 269 cache_free_bus(bp); 270 return (NULL); 271 } 272 273 (void) snprintf(kstat_name, sizeof (kstat_name), "%s%d", 274 di_node_name(node), di_instance(node)); 275 276 if ((bp->kstat_name = strdup(kstat_name)) == NULL) { 277 args->dev_walk_status = ENOMEM; 278 cache_free_bus(bp); 279 return (NULL); 280 } 281 282 /* if parent node is a bus, get its name */ 283 if ((pnode = get_parent_bus(node, args)) != NULL) { 284 devpath = di_devfs_path(pnode); 285 bp->pname = strdup(devpath); 286 di_devfs_path_free((void *) devpath); 287 if (bp->pname == NULL) { 288 args->dev_walk_status = ENOMEM; 289 cache_free_bus(bp); 290 return (NULL); 291 } 292 293 } else { 294 bp->pname = NULL; 295 } 296 297 bp->freq = get_prom_int("clock-frequency", node, args->ph); 298 299 bp->controllers = (controller_t **)calloc(1, sizeof (controller_t *)); 300 if (bp->controllers == NULL) { 301 args->dev_walk_status = ENOMEM; 302 cache_free_bus(bp); 303 return (NULL); 304 } 305 bp->controllers[0] = NULL; 306 307 if (cp != NULL) { 308 if (add_ptr2array(cp, (void ***)&bp->controllers) != 0) { 309 args->dev_walk_status = ENOMEM; 310 return (NULL); 311 } 312 } 313 314 bp->next = args->bus_listp; 315 args->bus_listp = bp; 316 317 return (bp); 318 } 319 320 static int 321 add_cluster_devs(di_node_t node, di_minor_t minor, void *arg) 322 { 323 struct search_args *args; 324 char *devpath; 325 char slice_path[MAXPATHLEN]; 326 int result = DI_WALK_CONTINUE; 327 328 if (!is_cluster_disk(node, minor)) { 329 return (DI_WALK_CONTINUE); 330 } 331 332 args = (struct search_args *)arg; 333 334 if (dm_debug > 1) { 335 /* This is all just debugging code */ 336 char *devpath; 337 char dev_name[MAXPATHLEN]; 338 339 devpath = di_devfs_path(node); 340 (void) snprintf(dev_name, sizeof (dev_name), "%s:%s", devpath, 341 di_minor_name(minor)); 342 di_devfs_path_free((void *) devpath); 343 344 (void) fprintf(stderr, "INFO: cluster dev: %s\n", dev_name); 345 } 346 347 args->node = node; 348 args->minor = minor; 349 args->dev_walk_status = 0; 350 351 /* 352 * Fix the devpaths for the cluster drive. 353 * 354 * We will come through here once for each raw slice device name. 355 */ 356 devpath = di_devfs_path(node); 357 (void) snprintf(slice_path, sizeof (slice_path), "%s:%s", devpath, 358 di_minor_name(minor)); 359 di_devfs_path_free((void *) devpath); 360 361 /* Walk the /dev tree to get the cluster devlinks. */ 362 (void) di_devlink_walk(args->handle, DEVLINK_DID_REGEX, slice_path, 363 DI_PRIMARY_LINK, arg, fix_cluster_devpath); 364 365 if (args->dev_walk_status != 0) { 366 result = DI_WALK_TERMINATE; 367 } 368 369 return (result); 370 } 371 372 static controller_t * 373 add_controller(struct search_args *args, di_node_t node, di_minor_t minor) 374 { 375 char *devpath; 376 controller_t *cp; 377 char kstat_name[MAXPATHLEN]; 378 char *c_type = DM_CTYPE_UNKNOWN; 379 380 devpath = di_devfs_path(node); 381 382 if ((cp = find_controller(args, devpath)) != NULL) { 383 di_devfs_path_free((void *) devpath); 384 return (cp); 385 } 386 387 /* Special handling for fp attachment node. */ 388 if (strcmp(di_node_name(node), "fp") == 0) { 389 di_node_t pnode; 390 391 pnode = di_parent_node(node); 392 if (pnode != DI_NODE_NIL) { 393 di_devfs_path_free((void *) devpath); 394 devpath = di_devfs_path(pnode); 395 396 if ((cp = find_controller(args, devpath)) != NULL) { 397 di_devfs_path_free((void *) devpath); 398 return (cp); 399 } 400 401 /* not in the list, create it */ 402 node = pnode; 403 c_type = DM_CTYPE_FIBRE; 404 } 405 } 406 407 if (dm_debug) { 408 (void) fprintf(stderr, "INFO: add_controller %s\n", devpath); 409 } 410 411 cp = (controller_t *)calloc(1, sizeof (controller_t)); 412 if (cp == NULL) { 413 return (NULL); 414 } 415 416 cp->name = strdup(devpath); 417 di_devfs_path_free((void *) devpath); 418 if (cp->name == NULL) { 419 cache_free_controller(cp); 420 return (NULL); 421 } 422 423 if (strcmp(c_type, DM_CTYPE_UNKNOWN) == 0) { 424 c_type = ctype(node, minor); 425 } 426 cp->ctype = c_type; 427 428 (void) snprintf(kstat_name, sizeof (kstat_name), "%s%d", 429 di_node_name(node), di_instance(node)); 430 431 if ((cp->kstat_name = strdup(kstat_name)) == NULL) { 432 cache_free_controller(cp); 433 return (NULL); 434 } 435 436 if (libdiskmgt_str_eq(cp->ctype, "scsi")) { 437 cp->scsi_options = get_prop(SCSI_OPTIONS_PROP, node); 438 } 439 440 if (libdiskmgt_str_eq(di_node_name(node), "scsi_vhci")) { 441 cp->multiplex = 1; 442 } else { 443 cp->multiplex = 0; 444 } 445 446 cp->freq = get_prom_int("clock-frequency", node, args->ph); 447 448 cp->disks = (disk_t **)calloc(1, sizeof (disk_t *)); 449 if (cp->disks == NULL) { 450 cache_free_controller(cp); 451 return (NULL); 452 } 453 cp->disks[0] = NULL; 454 455 cp->next = args->controller_listp; 456 args->controller_listp = cp; 457 458 cp->bus = add_bus(args, di_parent_node(node), 459 di_minor_next(di_parent_node(node), NULL), cp); 460 461 return (cp); 462 } 463 464 static int 465 add_devpath(di_devlink_t devlink, void *arg) 466 { 467 struct search_args *args; 468 char *devidstr; 469 disk_t *diskp; 470 char kernel_name[MAXPATHLEN]; 471 472 args = (struct search_args *)arg; 473 474 /* 475 * Get the diskp value from calling have_disk. Can either be found 476 * by kernel name or devid. 477 */ 478 479 diskp = NULL; 480 devidstr = get_str_prop(DEVICE_ID_PROP, args->node); 481 (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", 482 di_node_name(args->node), di_instance(args->node)); 483 484 (void) have_disk(args, devidstr, kernel_name, &diskp); 485 486 /* 487 * The devlink_path is usually of the form /dev/rdsk/c0t0d0s0. 488 * For diskettes it is /dev/rdiskette*. 489 * On Intel we would also get each fdisk partition as well 490 * (e.g. /dev/rdsk/c0t0d0p0). 491 */ 492 if (diskp != NULL) { 493 alias_t *ap; 494 char *devlink_path; 495 496 if (diskp->drv_type != DM_DT_FLOPPY) { 497 /* 498 * Add other controllers for multipath disks. This will have 499 * no effect if the controller relationship is already set up. 500 */ 501 if (add_disk2controller(diskp, args) != 0) { 502 args->dev_walk_status = ENOMEM; 503 } 504 } 505 506 (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", 507 di_node_name(args->node), di_instance(args->node)); 508 devlink_path = (char *)di_devlink_path(devlink); 509 510 if (dm_debug > 1) { 511 (void) fprintf(stderr, "INFO: devpath %s\n", devlink_path); 512 } 513 514 if ((ap = find_alias(diskp, kernel_name)) == NULL) { 515 if (new_alias(diskp, kernel_name, devlink_path, args) != 0) { 516 args->dev_walk_status = ENOMEM; 517 } 518 } else { 519 /* 520 * It is possible that we have already added this devpath. 521 * Do not add it again. new_devpath will return a 0 if 522 * found, and not add the path. 523 */ 524 if (new_devpath(ap, devlink_path) != 0) { 525 args->dev_walk_status = ENOMEM; 526 } 527 } 528 } 529 530 return (DI_WALK_CONTINUE); 531 } 532 533 static int 534 add_devs(di_node_t node, di_minor_t minor, void *arg) 535 { 536 struct search_args *args; 537 int result = DI_WALK_CONTINUE; 538 539 args = (struct search_args *)arg; 540 541 if (dm_debug > 1) { 542 /* This is all just debugging code */ 543 char *devpath; 544 char dev_name[MAXPATHLEN]; 545 546 devpath = di_devfs_path(node); 547 (void) snprintf(dev_name, sizeof (dev_name), "%s:%s", devpath, 548 di_minor_name(minor)); 549 di_devfs_path_free((void *) devpath); 550 551 (void) fprintf(stderr, 552 "INFO: dev: %s, node: %s%d, minor: 0x%x, type: %s\n", 553 dev_name, 554 di_node_name(node), di_instance(node), 555 di_minor_spectype(minor), 556 (di_minor_nodetype(minor) != NULL ? 557 di_minor_nodetype(minor) : "NULL")); 558 } 559 560 if (bus_type(node, minor, args->ph) != NULL) { 561 if (add_bus(args, node, minor, NULL) == NULL) { 562 args->dev_walk_status = ENOMEM; 563 result = DI_WALK_TERMINATE; 564 } 565 566 } else if (is_HBA(node, minor)) { 567 if (add_controller(args, node, minor) == NULL) { 568 args->dev_walk_status = ENOMEM; 569 result = DI_WALK_TERMINATE; 570 } 571 572 } else if (di_minor_spectype(minor) == S_IFCHR && is_drive(minor)) { 573 char *devidstr; 574 char kernel_name[MAXPATHLEN]; 575 disk_t *diskp; 576 577 (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", 578 di_node_name(node), di_instance(node)); 579 devidstr = get_str_prop(DEVICE_ID_PROP, node); 580 581 args->node = node; 582 args->minor = minor; 583 584 /* Check if we already got this disk and this is another slice */ 585 if (!have_disk(args, devidstr, kernel_name, &diskp)) { 586 587 args->dev_walk_status = 0; 588 /* This is a newly found disk, create the disk structure. */ 589 diskp = create_disk(devidstr, kernel_name, args); 590 if (diskp == NULL) { 591 args->dev_walk_status = ENOMEM; 592 } 593 594 if (diskp->drv_type != DM_DT_FLOPPY) { 595 /* add the controller relationship */ 596 if (args->dev_walk_status == 0) { 597 if (add_disk2controller(diskp, args) != 0) { 598 args->dev_walk_status = ENOMEM; 599 } 600 } 601 } 602 } 603 604 /* Add the devpaths for the drive. */ 605 if (args->dev_walk_status == 0) { 606 char *devpath; 607 char slice_path[MAXPATHLEN]; 608 char *pattern; 609 610 /* 611 * We will come through here once for each of the raw slice 612 * device names. 613 */ 614 devpath = di_devfs_path(node); 615 (void) snprintf(slice_path, sizeof (slice_path), "%s:%s", 616 devpath, di_minor_name(minor)); 617 di_devfs_path_free((void *) devpath); 618 619 if (libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_NT_FD)) { 620 pattern = DEVLINK_FLOPPY_REGEX; 621 } else { 622 pattern = DEVLINK_REGEX; 623 } 624 625 /* Walk the /dev tree to get the devlinks. */ 626 (void) di_devlink_walk(args->handle, pattern, slice_path, 627 DI_PRIMARY_LINK, arg, add_devpath); 628 } 629 630 if (args->dev_walk_status != 0) { 631 result = DI_WALK_TERMINATE; 632 } 633 } 634 635 return (result); 636 } 637 638 static int 639 add_disk2controller(disk_t *diskp, struct search_args *args) 640 { 641 di_node_t pnode; 642 controller_t *cp; 643 di_minor_t minor; 644 di_node_t node; 645 int i; 646 647 node = args->node; 648 649 pnode = di_parent_node(node); 650 if (pnode == DI_NODE_NIL) { 651 return (0); 652 } 653 654 minor = di_minor_next(pnode, NULL); 655 if (minor == NULL) { 656 return (0); 657 } 658 659 if ((cp = add_controller(args, pnode, minor)) == NULL) { 660 return (ENOMEM); 661 } 662 663 /* check if the disk <-> ctrl assoc is already there */ 664 for (i = 0; diskp->controllers[i]; i++) { 665 if (cp == diskp->controllers[i]) { 666 return (0); 667 } 668 } 669 670 /* this is a new controller for this disk */ 671 672 /* add the disk to the controlller */ 673 if (add_ptr2array(diskp, (void ***)&cp->disks) != 0) { 674 return (ENOMEM); 675 } 676 677 /* add the controlller to the disk */ 678 if (add_ptr2array(cp, (void ***)&diskp->controllers) != 0) { 679 return (ENOMEM); 680 } 681 682 /* 683 * Set up paths for mpxio controlled drives. 684 */ 685 if (libdiskmgt_str_eq(di_node_name(pnode), "scsi_vhci")) { 686 /* note: mpxio di_path stuff is all consolidation private */ 687 di_path_t pi = DI_PATH_NIL; 688 689 while ((pi = di_path_next_phci(node, pi)) != DI_PATH_NIL) { 690 int cnt; 691 uchar_t *bytes; 692 char str[MAXPATHLEN]; 693 char *wwn; 694 695 di_node_t phci_node = di_path_phci_node(pi); 696 697 /* get the node wwn */ 698 cnt = di_path_prop_lookup_bytes(pi, WWN_PROP, &bytes); 699 wwn = NULL; 700 if (cnt > 0) { 701 int i; 702 703 str[0] = 0; 704 for (i = 0; i < cnt; i++) { 705 char bstr[8]; /* a byte is only 2 hex chars + null */ 706 707 (void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]); 708 (void) strlcat(str, bstr, sizeof (str)); 709 } 710 wwn = str; 711 } 712 713 if (new_path(cp, diskp, phci_node, di_path_state(pi), wwn) 714 == NULL) { 715 return (ENOMEM); 716 } 717 } 718 } 719 720 return (0); 721 } 722 723 static int 724 add_disk2path(disk_t *dp, path_t *pp, di_path_state_t st, char *wwn) 725 { 726 /* add the disk to the path */ 727 if (add_ptr2array(dp, (void ***)&pp->disks) != 0) { 728 cache_free_path(pp); 729 return (0); 730 } 731 732 /* add the path to the disk */ 733 if (add_ptr2array(pp, (void ***)&dp->paths) != 0) { 734 cache_free_path(pp); 735 return (0); 736 } 737 738 /* add the path state for this disk */ 739 if (add_int2array(st, &pp->states) != 0) { 740 cache_free_path(pp); 741 return (0); 742 } 743 744 /* add the path state for this disk */ 745 if (wwn != NULL) { 746 char *wp; 747 748 if ((wp = strdup(wwn)) != NULL) { 749 if (add_ptr2array(wp, (void ***)(&pp->wwns)) != 0) { 750 cache_free_path(pp); 751 return (0); 752 } 753 } 754 } 755 756 return (1); 757 } 758 759 static int 760 add_int2array(int p, int **parray) 761 { 762 int i; 763 int cnt; 764 int *pa; 765 int *new_array; 766 767 pa = *parray; 768 769 cnt = 0; 770 if (pa != NULL) { 771 for (; pa[cnt] != -1; cnt++); 772 } 773 774 new_array = (int *)calloc(cnt + 2, sizeof (int *)); 775 if (new_array == NULL) { 776 return (ENOMEM); 777 } 778 779 /* copy the existing array */ 780 for (i = 0; i < cnt; i++) { 781 new_array[i] = pa[i]; 782 } 783 784 new_array[i] = p; 785 new_array[i + 1] = -1; 786 787 free(pa); 788 *parray = new_array; 789 790 return (0); 791 } 792 793 static int 794 add_ptr2array(void *p, void ***parray) 795 { 796 int i; 797 int cnt; 798 void **pa; 799 void **new_array; 800 801 pa = *parray; 802 803 cnt = 0; 804 if (pa != NULL) { 805 for (; pa[cnt]; cnt++); 806 } 807 808 new_array = (void **)calloc(cnt + 2, sizeof (void *)); 809 if (new_array == NULL) { 810 return (ENOMEM); 811 } 812 813 /* copy the existing array */ 814 for (i = 0; i < cnt; i++) { 815 new_array[i] = pa[i]; 816 } 817 818 new_array[i] = p; 819 new_array[i + 1] = NULL; 820 821 free(pa); 822 *parray = new_array; 823 824 return (0); 825 } 826 827 /* 828 * This double checks that we aren't going to get into a bad situation. 829 * This function should never fail, but I just want to double check things. 830 */ 831 static int 832 can_remove_controller(controller_t *cp, controller_t *currp) 833 { 834 if (dm_debug) { 835 if (cp == currp) { 836 (void) fprintf(stderr, "ERROR: remove current controller\n"); 837 } 838 839 if (cp->disks != NULL && cp->disks[0] != NULL) { 840 (void) fprintf(stderr, 841 "ERROR: remove controller with disk ptrs\n"); 842 } 843 844 if (cp->paths != NULL && cp->paths[0] != NULL) { 845 (void) fprintf(stderr, 846 "ERROR: remove controller with path ptrs\n"); 847 } 848 } 849 850 return (1); 851 } 852 853 /* 854 * If we have a controller in the list that is really a path then we need to 855 * take that controller out of the list since nodes that are paths are not 856 * considered to be controllers. 857 */ 858 static void 859 clean_paths(struct search_args *args) 860 { 861 controller_t *cp; 862 863 cp = args->controller_listp; 864 while (cp != NULL) { 865 path_t **pp; 866 867 pp = cp->paths; 868 if (pp != NULL) { 869 int i; 870 871 for (i = 0; pp[i]; i++) { 872 remove_invalid_controller(pp[i]->name, cp, args); 873 } 874 } 875 cp = cp->next; 876 } 877 } 878 879 static disk_t * 880 create_disk(char *deviceid, char *kernel_name, struct search_args *args) 881 { 882 disk_t *diskp; 883 char *type; 884 char *prod_id; 885 char *vendor_id; 886 887 if (dm_debug) { 888 (void) fprintf(stderr, "INFO: create_disk %s\n", kernel_name); 889 } 890 891 diskp = calloc(1, sizeof (disk_t)); 892 if (diskp == NULL) { 893 return (NULL); 894 } 895 896 diskp->controllers = (controller_t **) 897 calloc(1, sizeof (controller_t *)); 898 if (diskp->controllers == NULL) { 899 cache_free_disk(diskp); 900 return (NULL); 901 } 902 diskp->controllers[0] = NULL; 903 904 diskp->devid = NULL; 905 if (deviceid != NULL) { 906 if ((diskp->device_id = strdup(deviceid)) == NULL) { 907 cache_free_disk(diskp); 908 return (NULL); 909 } 910 911 (void) devid_str_decode(deviceid, &(diskp->devid), NULL); 912 } 913 914 if (kernel_name != NULL) { 915 diskp->kernel_name = strdup(kernel_name); 916 if (diskp->kernel_name == NULL) { 917 cache_free_disk(diskp); 918 return (NULL); 919 } 920 } 921 922 diskp->paths = NULL; 923 diskp->aliases = NULL; 924 925 diskp->cd_rom = 0; 926 diskp->rpm = 0; 927 type = di_minor_nodetype(args->minor); 928 929 prod_id = get_str_prop(PROD_ID_PROP, args->node); 930 if (prod_id != NULL) { 931 if ((diskp->product_id = strdup(prod_id)) == NULL) { 932 cache_free_disk(diskp); 933 return (NULL); 934 } 935 } else { 936 prod_id = get_str_prop(PROD_ID_USB_PROP, args->node); 937 if (prod_id != NULL) { 938 if ((diskp->product_id = strdup(prod_id)) == NULL) { 939 cache_free_disk(diskp); 940 return (NULL); 941 } 942 } 943 } 944 945 vendor_id = get_str_prop(VENDOR_ID_PROP, args->node); 946 if (vendor_id != NULL) { 947 if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { 948 cache_free_disk(diskp); 949 return (NULL); 950 } 951 } else { 952 vendor_id = get_str_prop(VENDOR_ID_PROP, args->node); 953 if (vendor_id != NULL) { 954 if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { 955 cache_free_disk(diskp); 956 return (NULL); 957 } 958 } 959 } 960 961 /* 962 * DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS. 963 * We try to use uscsi later to determine the real type. 964 * The cd_rom flag tells us that the kernel categorized the drive 965 * as a CD-ROM. We leave the drv_type as UKNOWN for now. 966 * The combination of the cd_rom flag being set with the drv_type of 967 * unknown is what triggers the uscsi probe in drive.c. 968 */ 969 if (disk_is_cdrom(type)) { 970 diskp->drv_type = DM_DT_UNKNOWN; 971 diskp->cd_rom = 1; 972 diskp->removable = 1; 973 } else if (libdiskmgt_str_eq(type, DDI_NT_FD)) { 974 diskp->drv_type = DM_DT_FLOPPY; 975 diskp->removable = 1; 976 } else { 977 /* not a "CD-ROM" or Floppy */ 978 979 diskp->removable = get_prop(REMOVABLE_PROP, args->node); 980 if (diskp->removable == -1) { 981 /* 982 * This is a workaround. Hotpluggable devices don't export 983 * a "removable-media" property, but they are treated as 984 * removable media devices by vold to implement automount. 985 * Once vold is EOL'ed, it should be removed. 986 */ 987 diskp->removable = get_prop(HOTPLUGGABLE_PROP, args->node); 988 } 989 990 if (diskp->removable == -1) { 991 diskp->removable = 0; 992 #if defined(i386) || defined(__amd64) 993 /* 994 * x86 does not have removable property. Check for common 995 * removable drives, zip & jaz, and mark those correctly. 996 */ 997 if (vendor_id != NULL && prod_id != NULL) { 998 if (str_case_index(vendor_id, "iomega") != NULL) { 999 if (str_case_index(prod_id, "jaz") != NULL) { 1000 diskp->removable = 1; 1001 } else if (str_case_index(prod_id, "zip") != NULL) { 1002 diskp->removable = 1; 1003 } 1004 } 1005 } 1006 #endif 1007 } 1008 1009 if (diskp->removable) { 1010 /* 1011 * For removable jaz or zip drives there is no way 1012 * to get the drive type unless media is inserted, so we 1013 * look at the product-id for a hint. 1014 */ 1015 1016 diskp->drv_type = DM_DT_UNKNOWN; 1017 1018 if (prod_id != NULL) { 1019 if (str_case_index(prod_id, "jaz") != NULL) { 1020 diskp->drv_type = DM_DT_JAZ; 1021 } else if (str_case_index(prod_id, "zip") != NULL) { 1022 diskp->drv_type = DM_DT_ZIP; 1023 } 1024 } 1025 } else { 1026 diskp->drv_type = DM_DT_FIXED; 1027 } 1028 } 1029 diskp->volm_path_set = 0; 1030 diskp->volm_path = NULL; 1031 1032 diskp->next = args->disk_listp; 1033 args->disk_listp = diskp; 1034 1035 return (diskp); 1036 } 1037 1038 static char * 1039 ctype(di_node_t node, di_minor_t minor) 1040 { 1041 char *type; 1042 char *name; 1043 1044 type = di_minor_nodetype(minor); 1045 name = di_node_name(node); 1046 1047 /* IDE disks use SCSI nexus as the type, so handle this special case */ 1048 if (libdiskmgt_str_eq(name, "ide")) { 1049 return (DM_CTYPE_ATA); 1050 } 1051 1052 if (libdiskmgt_str_eq(di_minor_name(minor), "scsa2usb")) { 1053 return (DM_CTYPE_USB); 1054 } 1055 1056 if (libdiskmgt_str_eq(type, DDI_NT_SCSI_NEXUS) || 1057 libdiskmgt_str_eq(type, DDI_NT_SCSI_ATTACHMENT_POINT)) { 1058 return (DM_CTYPE_SCSI); 1059 } 1060 1061 if (libdiskmgt_str_eq(type, DDI_NT_FC_ATTACHMENT_POINT)) { 1062 return (DM_CTYPE_FIBRE); 1063 } 1064 1065 if (libdiskmgt_str_eq(type, DDI_NT_NEXUS) && 1066 libdiskmgt_str_eq(name, "fp")) { 1067 return (DM_CTYPE_FIBRE); 1068 } 1069 1070 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1071 libdiskmgt_str_eq(name, "ide")) { 1072 return (DM_CTYPE_ATA); 1073 } 1074 1075 return (DM_CTYPE_UNKNOWN); 1076 } 1077 1078 static boolean_t 1079 disk_is_cdrom(char *type) 1080 { 1081 1082 int type_index; 1083 1084 for (type_index = 0; cdromtypes[type_index] != NULL; type_index++) { 1085 if (libdiskmgt_str_eq(type, cdromtypes[type_index])) { 1086 return (B_TRUE); 1087 } 1088 } 1089 1090 return (B_FALSE); 1091 } 1092 1093 static alias_t * 1094 find_alias(disk_t *diskp, char *kernel_name) 1095 { 1096 alias_t *ap; 1097 1098 ap = diskp->aliases; 1099 while (ap != NULL) { 1100 if (libdiskmgt_str_eq(ap->kstat_name, kernel_name)) { 1101 return (ap); 1102 } 1103 ap = ap->next; 1104 } 1105 1106 return (NULL); 1107 } 1108 1109 static bus_t * 1110 find_bus(struct search_args *args, char *name) 1111 { 1112 bus_t *listp; 1113 1114 listp = args->bus_listp; 1115 while (listp != NULL) { 1116 if (libdiskmgt_str_eq(listp->name, name)) { 1117 return (listp); 1118 } 1119 1120 listp = listp->next; 1121 } 1122 1123 return (NULL); 1124 } 1125 1126 static controller_t * 1127 find_controller(struct search_args *args, char *name) 1128 { 1129 controller_t *listp; 1130 1131 listp = args->controller_listp; 1132 while (listp != NULL) { 1133 if (libdiskmgt_str_eq(listp->name, name)) { 1134 return (listp); 1135 } 1136 1137 listp = listp->next; 1138 } 1139 1140 return (NULL); 1141 } 1142 1143 static int 1144 fix_cluster_devpath(di_devlink_t devlink, void *arg) 1145 { 1146 int fd; 1147 struct search_args *args; 1148 char *devlink_path; 1149 disk_t *diskp = NULL; 1150 alias_t *ap = NULL; 1151 1152 /* 1153 * The devlink_path is of the form /dev/did/rdsk/d1s0. 1154 */ 1155 1156 args = (struct search_args *)arg; 1157 1158 /* Find the disk by the deviceid we read from the cluster disk. */ 1159 devlink_path = (char *)di_devlink_path(devlink); 1160 if (devlink_path == NULL) { 1161 return (DI_WALK_CONTINUE); 1162 } 1163 1164 if ((fd = open(devlink_path, O_RDONLY|O_NDELAY)) >= 0) { 1165 ddi_devid_t devid; 1166 1167 if (dm_debug > 1) { 1168 (void) fprintf(stderr, "INFO: cluster devpath %s\n", 1169 devlink_path); 1170 } 1171 1172 if (devid_get(fd, &devid) == 0) { 1173 char *minor; 1174 char *devidstr; 1175 1176 minor = di_minor_name(args->minor); 1177 1178 if ((devidstr = devid_str_encode(devid, minor)) != NULL) { 1179 diskp = get_disk_by_deviceid(args->disk_listp, devidstr); 1180 1181 /* 1182 * This really shouldn't happen, since we should have 1183 * found all of the disks during our first pass through 1184 * the dev tree, but just in case... 1185 */ 1186 if (diskp == NULL) { 1187 if (dm_debug > 1) { 1188 (void) fprintf(stderr, 1189 "INFO: cluster create disk\n"); 1190 } 1191 1192 diskp = create_disk(devidstr, NULL, args); 1193 if (diskp == NULL) { 1194 args->dev_walk_status = ENOMEM; 1195 } 1196 1197 /* add the controller relationship */ 1198 if (args->dev_walk_status == 0) { 1199 if (add_disk2controller(diskp, args) != 0) { 1200 args->dev_walk_status = ENOMEM; 1201 } 1202 } 1203 1204 if (new_alias(diskp, NULL, devlink_path, args) 1205 != 0) { 1206 args->dev_walk_status = ENOMEM; 1207 } 1208 } 1209 1210 devid_str_free(devidstr); 1211 } 1212 1213 devid_free(devid); 1214 } 1215 (void) close(fd); 1216 } 1217 1218 1219 if (diskp != NULL) { 1220 if (dm_debug > 1) { 1221 (void) fprintf(stderr, "INFO: cluster found disk\n"); 1222 } 1223 1224 ap = diskp->aliases; 1225 } 1226 1227 if (ap != NULL) { 1228 /* NOTE: if ap->next != NULL have cluster disks w/ multiple paths */ 1229 1230 if (!ap->cluster) { 1231 char *basep; 1232 char *namep; 1233 int cnt = 0; 1234 int size; 1235 char alias[MAXPATHLEN]; 1236 1237 /* 1238 * First time; save the /dev/rdsk devpaths and update the 1239 * alias info with the new alias name. 1240 */ 1241 ap->orig_paths = ap->devpaths; 1242 ap->devpaths = NULL; 1243 1244 free(ap->alias); 1245 1246 /* get the new cluster alias name */ 1247 basep = strrchr(devlink_path, '/'); 1248 if (basep == NULL) { 1249 basep = devlink_path; 1250 } else { 1251 basep++; 1252 } 1253 1254 size = sizeof (alias) - 1; 1255 namep = alias; 1256 while (*basep != 0 && *basep != 's' && cnt < size) { 1257 *namep++ = *basep++; 1258 cnt++; 1259 } 1260 *namep = 0; 1261 1262 if ((ap->alias = strdup(alias)) == NULL) { 1263 args->dev_walk_status = ENOMEM; 1264 } 1265 1266 ap->cluster = 1; 1267 } 1268 1269 if (new_devpath(ap, devlink_path) != 0) { 1270 args->dev_walk_status = ENOMEM; 1271 } 1272 } 1273 1274 return (DI_WALK_CONTINUE); 1275 } 1276 1277 /* 1278 * Check if we have the drive in our list, based upon the device id. 1279 * We got the device id from the dev tree walk. This is encoded 1280 * using devid_str_encode(3DEVID). In order to check the device ids we need 1281 * to use the devid_compare(3DEVID) function, so we need to decode the 1282 * string representation of the device id. 1283 */ 1284 static disk_t * 1285 get_disk_by_deviceid(disk_t *listp, char *devidstr) 1286 { 1287 ddi_devid_t devid; 1288 1289 if (devidstr == NULL || devid_str_decode(devidstr, &devid, NULL) != 0) { 1290 return (NULL); 1291 } 1292 1293 while (listp != NULL) { 1294 if (listp->devid != NULL && 1295 devid_compare(listp->devid, devid) == 0) { 1296 break; 1297 } 1298 1299 listp = listp->next; 1300 } 1301 1302 devid_free(devid); 1303 1304 return (listp); 1305 } 1306 1307 /* 1308 * Get the base disk name with no path prefix and no slice (if there is one). 1309 * The name parameter should be big enough to hold the name. 1310 * This handles diskette names ok (/dev/rdiskette0) since there is no slice, 1311 * and converts the raw diskette name. 1312 * But, we don't know how to strip off the slice from third party drive 1313 * names. That just means that their drive name will include a slice on 1314 * it. 1315 */ 1316 static void 1317 get_disk_name_from_path(char *path, char *name, int size) 1318 { 1319 char *basep; 1320 int cnt = 0; 1321 1322 basep = strrchr(path, '/'); 1323 if (basep == NULL) { 1324 basep = path; 1325 } else { 1326 basep++; 1327 } 1328 1329 size = size - 1; /* leave room for terminating 0 */ 1330 1331 if (is_ctds(basep)) { 1332 while (*basep != 0 && *basep != 's' && cnt < size) { 1333 *name++ = *basep++; 1334 cnt++; 1335 } 1336 *name = 0; 1337 } else { 1338 if (strncmp(basep, FLOPPY_NAME, sizeof (FLOPPY_NAME) - 1) == 0) { 1339 /* 1340 * a floppy, convert rdiskette name to diskette name, 1341 * by skipping over the 'r' for raw diskette 1342 */ 1343 basep++; 1344 } 1345 1346 /* not a ctds name, just copy it */ 1347 (void) strlcpy(name, basep, size); 1348 } 1349 } 1350 1351 static char * 1352 get_byte_prop(char *prop_name, di_node_t node) 1353 { 1354 int cnt; 1355 uchar_t *bytes; 1356 int i; 1357 char str[MAXPATHLEN]; 1358 1359 cnt = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, prop_name, &bytes); 1360 if (cnt < 1) { 1361 return (NULL); 1362 } 1363 1364 str[0] = 0; 1365 for (i = 0; i < cnt; i++) { 1366 char bstr[8]; /* a byte is only 2 hex chars + null */ 1367 1368 (void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]); 1369 (void) strlcat(str, bstr, sizeof (str)); 1370 } 1371 return (strdup(str)); 1372 } 1373 1374 static di_node_t 1375 get_parent_bus(di_node_t node, struct search_args *args) 1376 { 1377 di_node_t pnode; 1378 1379 pnode = di_parent_node(node); 1380 if (pnode == DI_NODE_NIL) { 1381 return (NULL); 1382 } 1383 1384 if (bus_type(pnode, di_minor_next(pnode, NULL), args->ph) != NULL) { 1385 return (pnode); 1386 } 1387 1388 return (get_parent_bus(pnode, args)); 1389 } 1390 1391 static int 1392 get_prom_int(char *prop_name, di_node_t node, di_prom_handle_t ph) 1393 { 1394 int *n; 1395 1396 if (di_prom_prop_lookup_ints(ph, node, prop_name, &n) == 1) { 1397 return (*n); 1398 } 1399 1400 return (0); 1401 } 1402 1403 static char * 1404 get_prom_str(char *prop_name, di_node_t node, di_prom_handle_t ph) 1405 { 1406 char *str; 1407 1408 if (di_prom_prop_lookup_strings(ph, node, prop_name, &str) == 1) { 1409 return (str); 1410 } 1411 1412 return (NULL); 1413 } 1414 1415 /* 1416 * Get one of the positive int or boolean properties. 1417 */ 1418 static int 1419 get_prop(char *prop_name, di_node_t node) 1420 { 1421 int num; 1422 int *ip; 1423 1424 if ((num = di_prop_lookup_ints(DDI_DEV_T_ANY, node, prop_name, &ip)) 1425 >= 0) { 1426 if (num == 0) { 1427 /* boolean */ 1428 return (1); 1429 } else if (num == 1) { 1430 /* single int */ 1431 return (*ip); 1432 } 1433 } 1434 1435 return (-1); 1436 } 1437 1438 static char * 1439 get_str_prop(char *prop_name, di_node_t node) 1440 { 1441 char *str; 1442 1443 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, prop_name, &str) == 1) { 1444 return (str); 1445 } 1446 1447 return (NULL); 1448 } 1449 1450 /* 1451 * Check if we have the drive in our list, based upon the device id, if the 1452 * drive has a device id, or the kernel name, if it doesn't have a device id. 1453 */ 1454 static int 1455 have_disk(struct search_args *args, char *devidstr, char *kernel_name, 1456 disk_t **diskp) 1457 { 1458 disk_t *listp; 1459 1460 *diskp = NULL; 1461 listp = args->disk_listp; 1462 if (devidstr != NULL) { 1463 if ((*diskp = get_disk_by_deviceid(listp, devidstr)) != NULL) { 1464 return (1); 1465 } 1466 1467 } else { 1468 /* no devid, try matching the kernel names on the drives */ 1469 while (listp != NULL) { 1470 if (libdiskmgt_str_eq(kernel_name, listp->kernel_name)) { 1471 *diskp = listp; 1472 return (1); 1473 } 1474 listp = listp->next; 1475 } 1476 } 1477 1478 return (0); 1479 } 1480 1481 static char * 1482 bus_type(di_node_t node, di_minor_t minor, di_prom_handle_t ph) 1483 { 1484 char *type; 1485 int i; 1486 1487 type = get_prom_str("device_type", node, ph); 1488 if (type == NULL) { 1489 type = di_node_name(node); 1490 } 1491 1492 for (i = 0; bustypes[i]; i++) { 1493 if (libdiskmgt_str_eq(type, bustypes[i])) { 1494 return (type); 1495 } 1496 } 1497 1498 if (minor != NULL && strcmp(di_minor_nodetype(minor), 1499 DDI_NT_USB_ATTACHMENT_POINT) == 0) { 1500 return ("usb"); 1501 } 1502 1503 return (NULL); 1504 } 1505 1506 static int 1507 is_cluster_disk(di_node_t node, di_minor_t minor) 1508 { 1509 if (di_minor_spectype(minor) == S_IFCHR && 1510 libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_PSEUDO) && 1511 libdiskmgt_str_eq(di_node_name(node), CLUSTER_DEV)) { 1512 return (1); 1513 } 1514 1515 return (0); 1516 } 1517 1518 /* 1519 * If the input name is in c[t]ds format then return 1, otherwise return 0. 1520 */ 1521 static int 1522 is_ctds(char *name) 1523 { 1524 char *p; 1525 1526 p = name; 1527 1528 if (*p++ != 'c') { 1529 return (0); 1530 } 1531 /* skip controller digits */ 1532 while (isdigit(*p)) { 1533 p++; 1534 } 1535 1536 /* handle optional target */ 1537 if (*p == 't') { 1538 p++; 1539 /* skip over target */ 1540 while (isdigit(*p) || isupper(*p)) { 1541 p++; 1542 } 1543 } 1544 1545 if (*p++ != 'd') { 1546 return (0); 1547 } 1548 while (isdigit(*p)) { 1549 p++; 1550 } 1551 1552 if (*p++ != 's') { 1553 return (0); 1554 } 1555 1556 /* check the slice number */ 1557 while (isdigit(*p)) { 1558 p++; 1559 } 1560 1561 if (*p != 0) { 1562 return (0); 1563 } 1564 1565 return (1); 1566 } 1567 1568 static int 1569 is_drive(di_minor_t minor) 1570 { 1571 char *type; 1572 int type_index; 1573 1574 type = di_minor_nodetype(minor); 1575 type_index = 0; 1576 1577 while (disktypes[type_index] != NULL) { 1578 if (libdiskmgt_str_eq(type, disktypes[type_index])) { 1579 return (1); 1580 } 1581 type_index++; 1582 } 1583 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