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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <fcntl.h> 29 #include <libdevinfo.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <sys/stat.h> 34 #include <sys/sunddi.h> 35 #include <sys/types.h> 36 #include <ctype.h> 37 #include <libgen.h> 38 #include <unistd.h> 39 #include <devid.h> 40 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 /* The list of names of possible disk types used by libdevinfo. */ 65 static char *disktypes[] = { 66 DDI_NT_BLOCK, 67 DDI_NT_BLOCK_CHAN, 68 DDI_NT_BLOCK_WWN, 69 DDI_NT_BLOCK_FABRIC, 70 DDI_NT_CD_CHAN, 71 DDI_NT_CD, 72 DDI_NT_FD, 73 NULL 74 }; 75 76 /* 77 * Most of the removable media will be lumped under here; CD, DVD, MO, etc. 78 */ 79 static char *cdromtypes[] = { 80 DDI_NT_CD_CHAN, 81 DDI_NT_CD, 82 NULL 83 }; 84 85 static char *ctrltypes[] = { 86 DDI_NT_SCSI_NEXUS, 87 DDI_NT_SCSI_ATTACHMENT_POINT, 88 DDI_NT_FC_ATTACHMENT_POINT, 89 NULL 90 }; 91 92 static char *bustypes[] = { 93 "sbus", 94 "pci", 95 "usb", 96 NULL 97 }; 98 99 static bus_t *add_bus(struct search_args *args, di_node_t node, 100 di_minor_t minor, controller_t *cp); 101 static int add_cluster_devs(di_node_t node, di_minor_t minor, 102 void *arg); 103 static controller_t *add_controller(struct search_args *args, 104 di_node_t node, di_minor_t minor); 105 static int add_devpath(di_devlink_t devlink, void *arg); 106 static int add_devs(di_node_t node, di_minor_t minor, void *arg); 107 static int add_disk2controller(disk_t *diskp, 108 struct search_args *args); 109 static int add_disk2path(disk_t *dp, path_t *pp, 110 di_path_state_t st, char *wwn); 111 static int add_int2array(int p, int **parray); 112 static int add_ptr2array(void *p, void ***parray); 113 static char *bus_type(di_node_t node, di_minor_t minor, 114 di_prom_handle_t ph); 115 static int can_remove_controller(controller_t *cp, 116 controller_t *currp); 117 static void clean_paths(struct search_args *args); 118 static disk_t *create_disk(char *deviceid, char *kernel_name, 119 struct search_args *args); 120 static char *ctype(di_node_t node, di_minor_t minor); 121 static boolean_t disk_is_cdrom(char *type); 122 static alias_t *find_alias(disk_t *diskp, char *kernel_name); 123 static bus_t *find_bus(struct search_args *args, char *name); 124 static controller_t *find_controller(struct search_args *args, char *name); 125 static int fix_cluster_devpath(di_devlink_t devlink, void *arg); 126 static disk_t *get_disk_by_deviceid(disk_t *listp, char *devid); 127 static void get_disk_name_from_path(char *path, char *name, 128 int size); 129 static char *get_byte_prop(char *prop_name, di_node_t node); 130 static di_node_t get_parent_bus(di_node_t node, 131 struct search_args *args); 132 static int get_prom_int(char *prop_name, di_node_t node, 133 di_prom_handle_t ph); 134 static char *get_prom_str(char *prop_name, di_node_t node, 135 di_prom_handle_t ph); 136 static int get_prop(char *prop_name, di_node_t node); 137 static char *get_str_prop(char *prop_name, di_node_t node); 138 static int have_disk(struct search_args *args, char *devid, 139 char *kernel_name, disk_t **diskp); 140 static int is_cluster_disk(di_node_t node, di_minor_t minor); 141 static int is_ctds(char *name); 142 static int is_drive(di_minor_t minor); 143 static int is_HBA(di_node_t node, di_minor_t minor); 144 static int new_alias(disk_t *diskp, char *kernel_path, 145 char *devlink_path, struct search_args *args); 146 static int new_devpath(alias_t *ap, char *devpath); 147 static path_t *new_path(controller_t *cp, disk_t *diskp, 148 di_node_t node, di_path_state_t st, char *wwn); 149 static void remove_invalid_controller(char *name, 150 controller_t *currp, struct search_args *args); 151 static char *str_case_index(register char *s1, register char *s2); 152 153 /* 154 * The functions in this file do a dev tree walk to build up a model of the 155 * disks, controllers and paths on the system. This model is returned in the 156 * args->disk_listp and args->controller_listp members of the args param. 157 * There is no global data for this file so it is thread safe. It is up to 158 * the caller to merge the resulting model with any existing model that is 159 * cached. The caller must also free the memory for this model when it is 160 * no longer needed. 161 */ 162 void 163 findevs(struct search_args *args) 164 { 165 uint_t flags; 166 di_node_t di_root; 167 168 args->dev_walk_status = 0; 169 args->disk_listp = NULL; 170 args->controller_listp = NULL; 171 args->bus_listp = NULL; 172 173 args->handle = di_devlink_init(NULL, 0); 174 175 /* 176 * Have to make several passes at this with the new devfs caching. 177 * First, we find non-mpxio devices. Then we find mpxio/multipath 178 * devices. Finally, we get cluster devices. 179 */ 180 flags = DINFOCACHE; 181 di_root = di_init("/", flags); 182 args->ph = di_prom_init(); 183 (void) di_walk_minor(di_root, NULL, 0, args, add_devs); 184 di_fini(di_root); 185 186 flags = DINFOCPYALL | DINFOPATH; 187 di_root = di_init("/", flags); 188 (void) di_walk_minor(di_root, NULL, 0, args, add_devs); 189 di_fini(di_root); 190 191 /* do another pass to clean up cluster devpaths */ 192 flags = DINFOCACHE; 193 di_root = di_init("/", flags); 194 (void) di_walk_minor(di_root, DDI_PSEUDO, 0, args, add_cluster_devs); 195 if (args->ph != DI_PROM_HANDLE_NIL) { 196 (void) di_prom_fini(args->ph); 197 } 198 di_fini(di_root); 199 200 (void) di_devlink_fini(&(args->handle)); 201 202 clean_paths(args); 203 } 204 205 /* 206 * Definitions of private functions 207 */ 208 209 static bus_t * 210 add_bus(struct search_args *args, di_node_t node, di_minor_t minor, 211 controller_t *cp) 212 { 213 char *btype; 214 char *devpath; 215 bus_t *bp; 216 char kstat_name[MAXPATHLEN]; 217 di_node_t pnode; 218 219 if (node == DI_NODE_NIL) { 220 return (NULL); 221 } 222 223 if ((btype = bus_type(node, minor, args->ph)) == NULL) { 224 return (add_bus(args, di_parent_node(node), 225 di_minor_next(di_parent_node(node), NULL), cp)); 226 } 227 228 devpath = di_devfs_path(node); 229 230 if ((bp = find_bus(args, devpath)) != NULL) { 231 di_devfs_path_free((void *) devpath); 232 233 if (cp != NULL) { 234 if (add_ptr2array(cp, (void ***)&bp->controllers) != 0) { 235 args->dev_walk_status = ENOMEM; 236 return (NULL); 237 } 238 } 239 return (bp); 240 } 241 242 /* Special handling for root node. */ 243 if (strcmp(devpath, "/") == 0) { 244 di_devfs_path_free((void *) devpath); 245 return (NULL); 246 } 247 248 if (dm_debug) { 249 (void) fprintf(stderr, "INFO: add_bus %s\n", devpath); 250 } 251 252 bp = (bus_t *)calloc(1, sizeof (bus_t)); 253 if (bp == NULL) { 254 return (NULL); 255 } 256 257 bp->name = strdup(devpath); 258 di_devfs_path_free((void *) devpath); 259 if (bp->name == NULL) { 260 args->dev_walk_status = ENOMEM; 261 cache_free_bus(bp); 262 return (NULL); 263 } 264 265 bp->btype = strdup(btype); 266 if (bp->btype == NULL) { 267 args->dev_walk_status = ENOMEM; 268 cache_free_bus(bp); 269 return (NULL); 270 } 271 272 (void) snprintf(kstat_name, sizeof (kstat_name), "%s%d", 273 di_node_name(node), di_instance(node)); 274 275 if ((bp->kstat_name = strdup(kstat_name)) == NULL) { 276 args->dev_walk_status = ENOMEM; 277 cache_free_bus(bp); 278 return (NULL); 279 } 280 281 /* if parent node is a bus, get its name */ 282 if ((pnode = get_parent_bus(node, args)) != NULL) { 283 devpath = di_devfs_path(pnode); 284 bp->pname = strdup(devpath); 285 di_devfs_path_free((void *) devpath); 286 if (bp->pname == NULL) { 287 args->dev_walk_status = ENOMEM; 288 cache_free_bus(bp); 289 return (NULL); 290 } 291 292 } else { 293 bp->pname = NULL; 294 } 295 296 bp->freq = get_prom_int("clock-frequency", node, args->ph); 297 298 bp->controllers = (controller_t **)calloc(1, sizeof (controller_t *)); 299 if (bp->controllers == NULL) { 300 args->dev_walk_status = ENOMEM; 301 cache_free_bus(bp); 302 return (NULL); 303 } 304 bp->controllers[0] = NULL; 305 306 if (cp != NULL) { 307 if (add_ptr2array(cp, (void ***)&bp->controllers) != 0) { 308 args->dev_walk_status = ENOMEM; 309 return (NULL); 310 } 311 } 312 313 bp->next = args->bus_listp; 314 args->bus_listp = bp; 315 316 return (bp); 317 } 318 319 static int 320 add_cluster_devs(di_node_t node, di_minor_t minor, void *arg) 321 { 322 struct search_args *args; 323 char *devpath; 324 char slice_path[MAXPATHLEN]; 325 int result = DI_WALK_CONTINUE; 326 327 if (!is_cluster_disk(node, minor)) { 328 return (DI_WALK_CONTINUE); 329 } 330 331 args = (struct search_args *)arg; 332 333 if (dm_debug > 1) { 334 /* This is all just debugging code */ 335 char *devpath; 336 char dev_name[MAXPATHLEN]; 337 338 devpath = di_devfs_path(node); 339 (void) snprintf(dev_name, sizeof (dev_name), "%s:%s", devpath, 340 di_minor_name(minor)); 341 di_devfs_path_free((void *) devpath); 342 343 (void) fprintf(stderr, "INFO: cluster dev: %s\n", dev_name); 344 } 345 346 args->node = node; 347 args->minor = minor; 348 args->dev_walk_status = 0; 349 350 /* 351 * Fix the devpaths for the cluster drive. 352 * 353 * We will come through here once for each raw slice device name. 354 */ 355 devpath = di_devfs_path(node); 356 (void) snprintf(slice_path, sizeof (slice_path), "%s:%s", devpath, 357 di_minor_name(minor)); 358 di_devfs_path_free((void *) devpath); 359 360 /* Walk the /dev tree to get the cluster devlinks. */ 361 (void) di_devlink_walk(args->handle, DEVLINK_DID_REGEX, slice_path, 362 DI_PRIMARY_LINK, arg, fix_cluster_devpath); 363 364 if (args->dev_walk_status != 0) { 365 result = DI_WALK_TERMINATE; 366 } 367 368 return (result); 369 } 370 371 static controller_t * 372 add_controller(struct search_args *args, di_node_t node, di_minor_t minor) 373 { 374 char *devpath; 375 controller_t *cp; 376 char kstat_name[MAXPATHLEN]; 377 char *c_type = DM_CTYPE_UNKNOWN; 378 379 devpath = di_devfs_path(node); 380 381 if ((cp = find_controller(args, devpath)) != NULL) { 382 di_devfs_path_free((void *) devpath); 383 return (cp); 384 } 385 386 /* Special handling for fp attachment node. */ 387 if (strcmp(di_node_name(node), "fp") == 0) { 388 di_node_t pnode; 389 390 pnode = di_parent_node(node); 391 if (pnode != DI_NODE_NIL) { 392 di_devfs_path_free((void *) devpath); 393 devpath = di_devfs_path(pnode); 394 395 if ((cp = find_controller(args, devpath)) != NULL) { 396 di_devfs_path_free((void *) devpath); 397 return (cp); 398 } 399 400 /* not in the list, create it */ 401 node = pnode; 402 c_type = DM_CTYPE_FIBRE; 403 } 404 } 405 406 if (dm_debug) { 407 (void) fprintf(stderr, "INFO: add_controller %s\n", devpath); 408 } 409 410 cp = (controller_t *)calloc(1, sizeof (controller_t)); 411 if (cp == NULL) { 412 return (NULL); 413 } 414 415 cp->name = strdup(devpath); 416 di_devfs_path_free((void *) devpath); 417 if (cp->name == NULL) { 418 cache_free_controller(cp); 419 return (NULL); 420 } 421 422 if (strcmp(c_type, DM_CTYPE_UNKNOWN) == 0) { 423 c_type = ctype(node, minor); 424 } 425 cp->ctype = c_type; 426 427 (void) snprintf(kstat_name, sizeof (kstat_name), "%s%d", 428 di_node_name(node), di_instance(node)); 429 430 if ((cp->kstat_name = strdup(kstat_name)) == NULL) { 431 cache_free_controller(cp); 432 return (NULL); 433 } 434 435 if (libdiskmgt_str_eq(cp->ctype, "scsi")) { 436 cp->scsi_options = get_prop(SCSI_OPTIONS_PROP, node); 437 } 438 439 if (libdiskmgt_str_eq(di_node_name(node), "scsi_vhci")) { 440 cp->multiplex = 1; 441 } else { 442 cp->multiplex = 0; 443 } 444 445 cp->freq = get_prom_int("clock-frequency", node, args->ph); 446 447 cp->disks = (disk_t **)calloc(1, sizeof (disk_t *)); 448 if (cp->disks == NULL) { 449 cache_free_controller(cp); 450 return (NULL); 451 } 452 cp->disks[0] = NULL; 453 454 cp->next = args->controller_listp; 455 args->controller_listp = cp; 456 457 cp->bus = add_bus(args, di_parent_node(node), 458 di_minor_next(di_parent_node(node), NULL), cp); 459 460 return (cp); 461 } 462 463 static int 464 add_devpath(di_devlink_t devlink, void *arg) 465 { 466 struct search_args *args; 467 char *devidstr; 468 disk_t *diskp; 469 char kernel_name[MAXPATHLEN]; 470 471 args = (struct search_args *)arg; 472 473 /* 474 * Get the diskp value from calling have_disk. Can either be found 475 * by kernel name or devid. 476 */ 477 478 diskp = NULL; 479 devidstr = get_str_prop(DEVICE_ID_PROP, args->node); 480 (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", 481 di_node_name(args->node), di_instance(args->node)); 482 483 (void) have_disk(args, devidstr, kernel_name, &diskp); 484 485 /* 486 * The devlink_path is usually of the form /dev/rdsk/c0t0d0s0. 487 * For diskettes it is /dev/rdiskette*. 488 * On Intel we would also get each fdisk partition as well 489 * (e.g. /dev/rdsk/c0t0d0p0). 490 */ 491 if (diskp != NULL) { 492 alias_t *ap; 493 char *devlink_path; 494 495 if (diskp->drv_type != DM_DT_FLOPPY) { 496 /* 497 * Add other controllers for multipath disks. This will have 498 * no effect if the controller relationship is already set up. 499 */ 500 if (add_disk2controller(diskp, args) != 0) { 501 args->dev_walk_status = ENOMEM; 502 } 503 } 504 505 (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", 506 di_node_name(args->node), di_instance(args->node)); 507 devlink_path = (char *)di_devlink_path(devlink); 508 509 if (dm_debug > 1) { 510 (void) fprintf(stderr, "INFO: devpath %s\n", devlink_path); 511 } 512 513 if ((ap = find_alias(diskp, kernel_name)) == NULL) { 514 if (new_alias(diskp, kernel_name, devlink_path, args) != 0) { 515 args->dev_walk_status = ENOMEM; 516 } 517 } else { 518 /* 519 * It is possible that we have already added this devpath. 520 * Do not add it again. new_devpath will return a 0 if 521 * found, and not add the path. 522 */ 523 if (new_devpath(ap, devlink_path) != 0) { 524 args->dev_walk_status = ENOMEM; 525 } 526 } 527 } 528 529 return (DI_WALK_CONTINUE); 530 } 531 532 static int 533 add_devs(di_node_t node, di_minor_t minor, void *arg) 534 { 535 struct search_args *args; 536 int result = DI_WALK_CONTINUE; 537 538 args = (struct search_args *)arg; 539 540 if (dm_debug > 1) { 541 /* This is all just debugging code */ 542 char *devpath; 543 char dev_name[MAXPATHLEN]; 544 545 devpath = di_devfs_path(node); 546 (void) snprintf(dev_name, sizeof (dev_name), "%s:%s", devpath, 547 di_minor_name(minor)); 548 di_devfs_path_free((void *) devpath); 549 550 (void) fprintf(stderr, 551 "INFO: dev: %s, node: %s%d, minor: 0x%x, type: %s\n", 552 dev_name, 553 di_node_name(node), di_instance(node), 554 di_minor_spectype(minor), 555 (di_minor_nodetype(minor) != NULL ? 556 di_minor_nodetype(minor) : "NULL")); 557 } 558 559 if (bus_type(node, minor, args->ph) != NULL) { 560 if (add_bus(args, node, minor, NULL) == NULL) { 561 args->dev_walk_status = ENOMEM; 562 result = DI_WALK_TERMINATE; 563 } 564 565 } else if (is_HBA(node, minor)) { 566 if (add_controller(args, node, minor) == NULL) { 567 args->dev_walk_status = ENOMEM; 568 result = DI_WALK_TERMINATE; 569 } 570 571 } else if (di_minor_spectype(minor) == S_IFCHR && is_drive(minor)) { 572 char *devidstr; 573 char kernel_name[MAXPATHLEN]; 574 disk_t *diskp; 575 576 (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", 577 di_node_name(node), di_instance(node)); 578 devidstr = get_str_prop(DEVICE_ID_PROP, node); 579 580 args->node = node; 581 args->minor = minor; 582 583 /* Check if we already got this disk and this is another slice */ 584 if (!have_disk(args, devidstr, kernel_name, &diskp)) { 585 586 args->dev_walk_status = 0; 587 /* This is a newly found disk, create the disk structure. */ 588 diskp = create_disk(devidstr, kernel_name, args); 589 if (diskp == NULL) { 590 args->dev_walk_status = ENOMEM; 591 } 592 593 if (diskp->drv_type != DM_DT_FLOPPY) { 594 /* add the controller relationship */ 595 if (args->dev_walk_status == 0) { 596 if (add_disk2controller(diskp, args) != 0) { 597 args->dev_walk_status = ENOMEM; 598 } 599 } 600 } 601 } 602 603 /* Add the devpaths for the drive. */ 604 if (args->dev_walk_status == 0) { 605 char *devpath; 606 char slice_path[MAXPATHLEN]; 607 char *pattern; 608 609 /* 610 * We will come through here once for each of the raw slice 611 * device names. 612 */ 613 devpath = di_devfs_path(node); 614 (void) snprintf(slice_path, sizeof (slice_path), "%s:%s", 615 devpath, di_minor_name(minor)); 616 di_devfs_path_free((void *) devpath); 617 618 if (libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_NT_FD)) { 619 pattern = DEVLINK_FLOPPY_REGEX; 620 } else { 621 pattern = DEVLINK_REGEX; 622 } 623 624 /* Walk the /dev tree to get the devlinks. */ 625 (void) di_devlink_walk(args->handle, pattern, slice_path, 626 DI_PRIMARY_LINK, arg, add_devpath); 627 } 628 629 if (args->dev_walk_status != 0) { 630 result = DI_WALK_TERMINATE; 631 } 632 } 633 634 return (result); 635 } 636 637 static int 638 add_disk2controller(disk_t *diskp, struct search_args *args) 639 { 640 di_node_t pnode; 641 controller_t *cp; 642 di_minor_t minor; 643 di_node_t node; 644 int i; 645 646 node = args->node; 647 648 pnode = di_parent_node(node); 649 if (pnode == DI_NODE_NIL) { 650 return (0); 651 } 652 653 minor = di_minor_next(pnode, NULL); 654 if (minor == NULL) { 655 return (0); 656 } 657 658 if ((cp = add_controller(args, pnode, minor)) == NULL) { 659 return (ENOMEM); 660 } 661 662 /* check if the disk <-> ctrl assoc is already there */ 663 for (i = 0; diskp->controllers[i]; i++) { 664 if (cp == diskp->controllers[i]) { 665 return (0); 666 } 667 } 668 669 /* this is a new controller for this disk */ 670 671 /* add the disk to the controlller */ 672 if (add_ptr2array(diskp, (void ***)&cp->disks) != 0) { 673 return (ENOMEM); 674 } 675 676 /* add the controlller to the disk */ 677 if (add_ptr2array(cp, (void ***)&diskp->controllers) != 0) { 678 return (ENOMEM); 679 } 680 681 /* 682 * Set up paths for mpxio controlled drives. 683 */ 684 if (libdiskmgt_str_eq(di_node_name(pnode), "scsi_vhci")) { 685 /* note: mpxio di_path stuff is all consolidation private */ 686 di_path_t pi = DI_PATH_NIL; 687 688 while ((pi = di_path_next_phci(node, pi)) != DI_PATH_NIL) { 689 int cnt; 690 uchar_t *bytes; 691 char str[MAXPATHLEN]; 692 char *wwn; 693 694 di_node_t phci_node = di_path_phci_node(pi); 695 696 /* get the node wwn */ 697 cnt = di_path_prop_lookup_bytes(pi, WWN_PROP, &bytes); 698 wwn = NULL; 699 if (cnt > 0) { 700 int i; 701 702 str[0] = 0; 703 for (i = 0; i < cnt; i++) { 704 char bstr[8]; /* a byte is only 2 hex chars + null */ 705 706 (void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]); 707 (void) strlcat(str, bstr, sizeof (str)); 708 } 709 wwn = str; 710 } 711 712 if (new_path(cp, diskp, phci_node, di_path_state(pi), wwn) 713 == NULL) { 714 return (ENOMEM); 715 } 716 } 717 } 718 719 return (0); 720 } 721 722 static int 723 add_disk2path(disk_t *dp, path_t *pp, di_path_state_t st, char *wwn) 724 { 725 /* add the disk to the path */ 726 if (add_ptr2array(dp, (void ***)&pp->disks) != 0) { 727 cache_free_path(pp); 728 return (0); 729 } 730 731 /* add the path to the disk */ 732 if (add_ptr2array(pp, (void ***)&dp->paths) != 0) { 733 cache_free_path(pp); 734 return (0); 735 } 736 737 /* add the path state for this disk */ 738 if (add_int2array(st, &pp->states) != 0) { 739 cache_free_path(pp); 740 return (0); 741 } 742 743 /* add the path state for this disk */ 744 if (wwn != NULL) { 745 char *wp; 746 747 if ((wp = strdup(wwn)) != NULL) { 748 if (add_ptr2array(wp, (void ***)(&pp->wwns)) != 0) { 749 cache_free_path(pp); 750 return (0); 751 } 752 } 753 } 754 755 return (1); 756 } 757 758 static int 759 add_int2array(int p, int **parray) 760 { 761 int i; 762 int cnt; 763 int *pa; 764 int *new_array; 765 766 pa = *parray; 767 768 cnt = 0; 769 if (pa != NULL) { 770 for (; pa[cnt] != -1; cnt++); 771 } 772 773 new_array = (int *)calloc(cnt + 2, sizeof (int *)); 774 if (new_array == NULL) { 775 return (ENOMEM); 776 } 777 778 /* copy the existing array */ 779 for (i = 0; i < cnt; i++) { 780 new_array[i] = pa[i]; 781 } 782 783 new_array[i] = p; 784 new_array[i + 1] = -1; 785 786 free(pa); 787 *parray = new_array; 788 789 return (0); 790 } 791 792 static int 793 add_ptr2array(void *p, void ***parray) 794 { 795 int i; 796 int cnt; 797 void **pa; 798 void **new_array; 799 800 pa = *parray; 801 802 cnt = 0; 803 if (pa != NULL) { 804 for (; pa[cnt]; cnt++); 805 } 806 807 new_array = (void **)calloc(cnt + 2, sizeof (void *)); 808 if (new_array == NULL) { 809 return (ENOMEM); 810 } 811 812 /* copy the existing array */ 813 for (i = 0; i < cnt; i++) { 814 new_array[i] = pa[i]; 815 } 816 817 new_array[i] = p; 818 new_array[i + 1] = NULL; 819 820 free(pa); 821 *parray = new_array; 822 823 return (0); 824 } 825 826 /* 827 * This double checks that we aren't going to get into a bad situation. 828 * This function should never fail, but I just want to double check things. 829 */ 830 static int 831 can_remove_controller(controller_t *cp, controller_t *currp) 832 { 833 if (dm_debug) { 834 if (cp == currp) { 835 (void) fprintf(stderr, "ERROR: remove current controller\n"); 836 } 837 838 if (cp->disks != NULL && cp->disks[0] != NULL) { 839 (void) fprintf(stderr, 840 "ERROR: remove controller with disk ptrs\n"); 841 } 842 843 if (cp->paths != NULL && cp->paths[0] != NULL) { 844 (void) fprintf(stderr, 845 "ERROR: remove controller with path ptrs\n"); 846 } 847 } 848 849 return (1); 850 } 851 852 /* 853 * If we have a controller in the list that is really a path then we need to 854 * take that controller out of the list since nodes that are paths are not 855 * considered to be controllers. 856 */ 857 static void 858 clean_paths(struct search_args *args) 859 { 860 controller_t *cp; 861 862 cp = args->controller_listp; 863 while (cp != NULL) { 864 path_t **pp; 865 866 pp = cp->paths; 867 if (pp != NULL) { 868 int i; 869 870 for (i = 0; pp[i]; i++) { 871 remove_invalid_controller(pp[i]->name, cp, args); 872 } 873 } 874 cp = cp->next; 875 } 876 } 877 878 static disk_t * 879 create_disk(char *deviceid, char *kernel_name, struct search_args *args) 880 { 881 disk_t *diskp; 882 char *type; 883 char *prod_id; 884 char *vendor_id; 885 886 if (dm_debug) { 887 (void) fprintf(stderr, "INFO: create_disk %s\n", kernel_name); 888 } 889 890 diskp = calloc(1, sizeof (disk_t)); 891 if (diskp == NULL) { 892 return (NULL); 893 } 894 895 diskp->controllers = (controller_t **) 896 calloc(1, sizeof (controller_t *)); 897 if (diskp->controllers == NULL) { 898 cache_free_disk(diskp); 899 return (NULL); 900 } 901 diskp->controllers[0] = NULL; 902 903 diskp->devid = NULL; 904 if (deviceid != NULL) { 905 if ((diskp->device_id = strdup(deviceid)) == NULL) { 906 cache_free_disk(diskp); 907 return (NULL); 908 } 909 910 (void) devid_str_decode(deviceid, &(diskp->devid), NULL); 911 } 912 913 if (kernel_name != NULL) { 914 diskp->kernel_name = strdup(kernel_name); 915 if (diskp->kernel_name == NULL) { 916 cache_free_disk(diskp); 917 return (NULL); 918 } 919 } 920 921 diskp->paths = NULL; 922 diskp->aliases = NULL; 923 924 diskp->cd_rom = 0; 925 diskp->rpm = 0; 926 type = di_minor_nodetype(args->minor); 927 928 prod_id = get_str_prop(PROD_ID_PROP, args->node); 929 if (prod_id != NULL) { 930 if ((diskp->product_id = strdup(prod_id)) == NULL) { 931 cache_free_disk(diskp); 932 return (NULL); 933 } 934 } else { 935 prod_id = get_str_prop(PROD_ID_USB_PROP, args->node); 936 if (prod_id != NULL) { 937 if ((diskp->product_id = strdup(prod_id)) == NULL) { 938 cache_free_disk(diskp); 939 return (NULL); 940 } 941 } 942 } 943 944 vendor_id = get_str_prop(VENDOR_ID_PROP, args->node); 945 if (vendor_id != NULL) { 946 if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { 947 cache_free_disk(diskp); 948 return (NULL); 949 } 950 } else { 951 vendor_id = get_str_prop(VENDOR_ID_PROP, args->node); 952 if (vendor_id != NULL) { 953 if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { 954 cache_free_disk(diskp); 955 return (NULL); 956 } 957 } 958 } 959 960 /* 961 * DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS. 962 * We try to use uscsi later to determine the real type. 963 * The cd_rom flag tells us that the kernel categorized the drive 964 * as a CD-ROM. We leave the drv_type as UKNOWN for now. 965 * The combination of the cd_rom flag being set with the drv_type of 966 * unknown is what triggers the uscsi probe in drive.c. 967 */ 968 if (disk_is_cdrom(type)) { 969 diskp->drv_type = DM_DT_UNKNOWN; 970 diskp->cd_rom = 1; 971 diskp->removable = 1; 972 } else if (libdiskmgt_str_eq(type, DDI_NT_FD)) { 973 diskp->drv_type = DM_DT_FLOPPY; 974 diskp->removable = 1; 975 } else { 976 /* not a "CD-ROM" or Floppy */ 977 978 diskp->removable = get_prop(REMOVABLE_PROP, args->node); 979 980 if (diskp->removable == -1) { 981 diskp->removable = 0; 982 #if defined(i386) || defined(__amd64) 983 /* 984 * x86 does not have removable property. Check for common 985 * removable drives, zip & jaz, and mark those correctly. 986 */ 987 if (vendor_id != NULL && prod_id != NULL) { 988 if (str_case_index(vendor_id, "iomega") != NULL) { 989 if (str_case_index(prod_id, "jaz") != NULL) { 990 diskp->removable = 1; 991 } else if (str_case_index(prod_id, "zip") != NULL) { 992 diskp->removable = 1; 993 } 994 } 995 } 996 #endif 997 } 998 999 if (diskp->removable) { 1000 /* 1001 * For removable jaz or zip drives there is no way 1002 * to get the drive type unless media is inserted, so we 1003 * look at the product-id for a hint. 1004 */ 1005 1006 diskp->drv_type = DM_DT_UNKNOWN; 1007 1008 if (prod_id != NULL) { 1009 if (str_case_index(prod_id, "jaz") != NULL) { 1010 diskp->drv_type = DM_DT_JAZ; 1011 } else if (str_case_index(prod_id, "zip") != NULL) { 1012 diskp->drv_type = DM_DT_ZIP; 1013 } 1014 } 1015 } else { 1016 diskp->drv_type = DM_DT_FIXED; 1017 } 1018 } 1019 1020 diskp->next = args->disk_listp; 1021 args->disk_listp = diskp; 1022 1023 return (diskp); 1024 } 1025 1026 static char * 1027 ctype(di_node_t node, di_minor_t minor) 1028 { 1029 char *type; 1030 char *name; 1031 1032 type = di_minor_nodetype(minor); 1033 name = di_node_name(node); 1034 1035 /* IDE disks use SCSI nexus as the type, so handle this special case */ 1036 if (libdiskmgt_str_eq(name, "ide")) { 1037 return (DM_CTYPE_ATA); 1038 } 1039 1040 if (libdiskmgt_str_eq(di_minor_name(minor), "scsa2usb")) { 1041 return (DM_CTYPE_USB); 1042 } 1043 1044 if (libdiskmgt_str_eq(type, DDI_NT_SCSI_NEXUS) || 1045 libdiskmgt_str_eq(type, DDI_NT_SCSI_ATTACHMENT_POINT)) { 1046 return (DM_CTYPE_SCSI); 1047 } 1048 1049 if (libdiskmgt_str_eq(type, DDI_NT_FC_ATTACHMENT_POINT)) { 1050 return (DM_CTYPE_FIBRE); 1051 } 1052 1053 if (libdiskmgt_str_eq(type, DDI_NT_NEXUS) && 1054 libdiskmgt_str_eq(name, "fp")) { 1055 return (DM_CTYPE_FIBRE); 1056 } 1057 1058 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1059 libdiskmgt_str_eq(name, "ide")) { 1060 return (DM_CTYPE_ATA); 1061 } 1062 1063 return (DM_CTYPE_UNKNOWN); 1064 } 1065 1066 static boolean_t 1067 disk_is_cdrom(char *type) 1068 { 1069 1070 int type_index; 1071 1072 for (type_index = 0; cdromtypes[type_index] != NULL; type_index++) { 1073 if (libdiskmgt_str_eq(type, cdromtypes[type_index])) { 1074 return (B_TRUE); 1075 } 1076 } 1077 1078 return (B_FALSE); 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 char *type; 1560 int type_index; 1561 1562 type = di_minor_nodetype(minor); 1563 type_index = 0; 1564 1565 while (disktypes[type_index] != NULL) { 1566 if (libdiskmgt_str_eq(type, disktypes[type_index])) { 1567 return (1); 1568 } 1569 type_index++; 1570 } 1571 1572 return (0); 1573 } 1574 1575 static int 1576 is_HBA(di_node_t node, di_minor_t minor) 1577 { 1578 char *type; 1579 char *name; 1580 int type_index; 1581 1582 type = di_minor_nodetype(minor); 1583 type_index = 0; 1584 1585 while (ctrltypes[type_index] != NULL) { 1586 if (libdiskmgt_str_eq(type, ctrltypes[type_index])) { 1587 return (1); 1588 } 1589 type_index++; 1590 } 1591 1592 name = di_node_name(node); 1593 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1594 libdiskmgt_str_eq(name, "ide")) { 1595 return (1); 1596 } 1597 1598 return (0); 1599 } 1600 1601 static int 1602 new_alias(disk_t *diskp, char *kernel_name, char *devlink_path, 1603 struct search_args *args) 1604 { 1605 alias_t *aliasp; 1606 char alias[MAXPATHLEN]; 1607 di_node_t pnode; 1608 1609 aliasp = malloc(sizeof (alias_t)); 1610 if (aliasp == NULL) { 1611 return (ENOMEM); 1612 } 1613 1614 aliasp->alias = NULL; 1615 aliasp->kstat_name = NULL; 1616 aliasp->wwn = NULL; 1617 aliasp->devpaths = NULL; 1618 aliasp->orig_paths = NULL; 1619 1620 get_disk_name_from_path(devlink_path, alias, sizeof (alias)); 1621 1622 aliasp->alias = strdup(alias); 1623 if (aliasp->alias == NULL) { 1624 cache_free_alias(aliasp); 1625 return (ENOMEM); 1626 } 1627 1628 if (kernel_name != NULL) { 1629 aliasp->kstat_name = strdup(kernel_name); 1630 if (aliasp->kstat_name == NULL) { 1631 cache_free_alias(aliasp); 1632 return (ENOMEM); 1633 } 1634 } else { 1635 aliasp->kstat_name = NULL; 1636 } 1637 1638 aliasp->cluster = 0; 1639 aliasp->lun = get_prop(DM_LUN, args->node); 1640 aliasp->target = get_prop(DM_TARGET, args->node); 1641 aliasp->wwn = get_byte_prop(WWN_PROP, args->node); 1642 1643 pnode = di_parent_node(args->node); 1644 if (pnode != DI_NODE_NIL) { 1645 char prop_name[MAXPROPLEN]; 1646 1647 (void) snprintf(prop_name, sizeof (prop_name), 1648 "target%d-sync-speed", aliasp->target); 1649 diskp->sync_speed = get_prop(prop_name, pnode); 1650 (void) snprintf(prop_name, sizeof (prop_name), "target%d-wide", 1651 aliasp->target); 1652 diskp->wide = get_prop(prop_name, pnode); 1653 } 1654 1655 if (new_devpath(aliasp, devlink_path) != 0) { 1656 cache_free_alias(aliasp); 1657 return (ENOMEM); 1658 } 1659 1660 aliasp->next = diskp->aliases; 1661 diskp->aliases = aliasp; 1662 1663 return (0); 1664 } 1665 1666 /* 1667 * Append the new devpath to the end of the devpath list. This is important 1668 * since we may want to use the order of the devpaths to match up the vtoc 1669 * entries. 1670 */ 1671 static int 1672 new_devpath(alias_t *ap, char *devpath) 1673 { 1674 slice_t *newdp; 1675 slice_t *alistp; 1676 1677 /* 1678 * First, search the alias list to be sure that this devpath is 1679 * not already there. 1680 */ 1681 1682 for (alistp = ap->devpaths; alistp != NULL; alistp = alistp->next) { 1683 if (libdiskmgt_str_eq(alistp->devpath, devpath)) { 1684 return (0); 1685 } 1686 } 1687 1688 /* 1689 * Otherwise, not found so add this new devpath to the list. 1690 */ 1691 1692 newdp = malloc(sizeof (slice_t)); 1693 if (newdp == NULL) { 1694 return (ENOMEM); 1695 } 1696 1697 newdp->devpath = strdup(devpath); 1698 if (newdp->devpath == NULL) { 1699 free(newdp); 1700 return (ENOMEM); 1701 } 1702 newdp->slice_num = -1; 1703 newdp->next = NULL; 1704 1705 if (ap->devpaths == NULL) { 1706 ap->devpaths = newdp; 1707 } else { 1708 /* append the devpath to the end of the list */ 1709 slice_t *dp; 1710 1711 dp = ap->devpaths; 1712 while (dp->next != NULL) { 1713 dp = dp->next; 1714 } 1715 1716 dp->next = newdp; 1717 } 1718 1719 return (0); 1720 } 1721 1722 static path_t * 1723 new_path(controller_t *cp, disk_t *dp, di_node_t node, di_path_state_t st, 1724 char *wwn) 1725 { 1726 char *devpath; 1727 path_t *pp; 1728 di_minor_t minor; 1729 1730 /* Special handling for fp attachment node. */ 1731 if (strcmp(di_node_name(node), "fp") == 0) { 1732 di_node_t pnode; 1733 1734 pnode = di_parent_node(node); 1735 if (pnode != DI_NODE_NIL) { 1736 node = pnode; 1737 } 1738 } 1739 1740 devpath = di_devfs_path(node); 1741 1742 /* check if the path is already there */ 1743 pp = NULL; 1744 if (cp->paths != NULL) { 1745 int i; 1746 1747 for (i = 0; cp->paths[i]; i++) { 1748 if (libdiskmgt_str_eq(devpath, cp->paths[i]->name)) { 1749 pp = cp->paths[i]; 1750 break; 1751 } 1752 } 1753 } 1754 1755 if (pp != NULL) { 1756 /* the path exists, add this disk to it */ 1757 1758 di_devfs_path_free((void *) devpath); 1759 1760 if (!add_disk2path(dp, pp, st, wwn)) { 1761 return (NULL); 1762 } 1763 1764 return (pp); 1765 } 1766 1767 /* create a new path */ 1768 1769 pp = calloc(1, sizeof (path_t)); 1770 if (pp == NULL) { 1771 di_devfs_path_free((void *) devpath); 1772 return (NULL); 1773 } 1774 1775 pp->name = strdup(devpath); 1776 di_devfs_path_free((void *) devpath); 1777 if (pp->name == NULL) { 1778 cache_free_path(pp); 1779 return (NULL); 1780 } 1781 1782 /* add the disk to the path */ 1783 if (!add_disk2path(dp, pp, st, wwn)) { 1784 return (NULL); 1785 } 1786 1787 /* add the path to the controller */ 1788 if (add_ptr2array(pp, (void ***)&cp->paths) != 0) { 1789 cache_free_path(pp); 1790 return (NULL); 1791 } 1792 1793 /* add the controller to the path */ 1794 pp->controller = cp; 1795 1796 minor = di_minor_next(node, NULL); 1797 if (minor != NULL) { 1798 pp->ctype = ctype(node, minor); 1799 } else { 1800 pp->ctype = DM_CTYPE_UNKNOWN; 1801 } 1802 1803 return (pp); 1804 } 1805 1806 /* 1807 * We pass in the current controller pointer (currp) so we can double check 1808 * that we aren't corrupting the list by removing the element we are on. This 1809 * should never happen, but it doesn't hurt to double check. 1810 */ 1811 static void 1812 remove_invalid_controller(char *name, controller_t *currp, 1813 struct search_args *args) 1814 { 1815 controller_t *cp; 1816 bus_t *bp; 1817 controller_t *prevp; 1818 1819 bp = args->bus_listp; 1820 while (bp != NULL) { 1821 int i; 1822 1823 for (i = 0; bp->controllers[i]; i++) { 1824 if (libdiskmgt_str_eq(bp->controllers[i]->name, name)) { 1825 int j; 1826 1827 /* remove pointer to invalid controller (it is a path) */ 1828 for (j = i; bp->controllers[j]; j++) { 1829 bp->controllers[j] = bp->controllers[j + 1]; 1830 } 1831 } 1832 } 1833 bp = bp->next; 1834 } 1835 1836 if (args->controller_listp == NULL) { 1837 return; 1838 } 1839 1840 cp = args->controller_listp; 1841 if (libdiskmgt_str_eq(cp->name, name)) { 1842 if (can_remove_controller(cp, currp)) { 1843 args->controller_listp = cp->next; 1844 cache_free_controller(cp); 1845 } 1846 return; 1847 } 1848 1849 prevp = cp; 1850 cp = cp->next; 1851 while (cp != NULL) { 1852 if (libdiskmgt_str_eq(cp->name, name)) { 1853 if (can_remove_controller(cp, currp)) { 1854 prevp->next = cp->next; 1855 cache_free_controller(cp); 1856 } 1857 return; 1858 } 1859 prevp = cp; 1860 cp = cp->next; 1861 } 1862 } 1863 1864 /* 1865 * This is the standard strstr code modified for case independence. 1866 */ 1867 static char * 1868 str_case_index(register char *s1, register char *s2) 1869 { 1870 uint_t s2len = strlen(s2); /* length of the second string */ 1871 1872 /* If the length of the second string is 0, return the first arg. */ 1873 if (s2len == 0) { 1874 return (s1); 1875 } 1876 1877 while (strlen(s1) >= s2len) { 1878 if (strncasecmp(s1, s2, s2len) == 0) { 1879 return (s1); 1880 } 1881 s1++; 1882 } 1883 return (NULL); 1884 } 1885