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