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