1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <fcntl.h> 30 #include <libdevinfo.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <sys/stat.h> 35 #include <sys/sunddi.h> 36 #include <sys/types.h> 37 #include <ctype.h> 38 #include <libgen.h> 39 #include <unistd.h> 40 #include <devid.h> 41 42 #include "libdiskmgt.h" 43 #include "disks_private.h" 44 45 #define CLUSTER_DEV "did" 46 47 /* specify which disk links to use in the /dev directory */ 48 #define DEVLINK_REGEX "rdsk/.*" 49 #define DEVLINK_FLOPPY_REGEX "rdiskette[0-9]" 50 #define DEVLINK_DID_REGEX "did/rdsk/.*" 51 52 #define FLOPPY_NAME "rdiskette" 53 54 #define MAXPROPLEN 1024 55 #define DEVICE_ID_PROP "devid" 56 #define PROD_ID_PROP "inquiry-product-id" 57 #define PROD_ID_USB_PROP "usb-product-name" 58 #define REMOVABLE_PROP "removable-media" 59 #define 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 if (diskp->removable == -1) { 980 diskp->removable = 0; 981 #ifdef i386 982 /* 983 * x86 does not have removable property. Check for common 984 * removable drives, zip & jaz, and mark those correctly. 985 */ 986 if (vendor_id != NULL && prod_id != NULL) { 987 if (str_case_index(vendor_id, "iomega") != NULL) { 988 if (str_case_index(prod_id, "jaz") != NULL) { 989 diskp->removable = 1; 990 } else if (str_case_index(prod_id, "zip") != NULL) { 991 diskp->removable = 1; 992 } 993 } 994 } 995 #endif 996 } 997 998 if (diskp->removable) { 999 /* 1000 * For removable jaz or zip drives there is no way 1001 * to get the drive type unless media is inserted, so we 1002 * look at the product-id for a hint. 1003 */ 1004 1005 diskp->drv_type = DM_DT_UNKNOWN; 1006 1007 if (prod_id != NULL) { 1008 if (str_case_index(prod_id, "jaz") != NULL) { 1009 diskp->drv_type = DM_DT_JAZ; 1010 } else if (str_case_index(prod_id, "zip") != NULL) { 1011 diskp->drv_type = DM_DT_ZIP; 1012 } 1013 } 1014 } else { 1015 diskp->drv_type = DM_DT_FIXED; 1016 } 1017 } 1018 diskp->volm_path_set = 0; 1019 diskp->volm_path = NULL; 1020 1021 diskp->next = args->disk_listp; 1022 args->disk_listp = diskp; 1023 1024 return (diskp); 1025 } 1026 1027 static char * 1028 ctype(di_node_t node, di_minor_t minor) 1029 { 1030 char *type; 1031 char *name; 1032 1033 type = di_minor_nodetype(minor); 1034 name = di_node_name(node); 1035 1036 /* IDE disks use SCSI nexus as the type, so handle this special case */ 1037 if (libdiskmgt_str_eq(name, "ide")) { 1038 return (DM_CTYPE_ATA); 1039 } 1040 1041 if (libdiskmgt_str_eq(di_minor_name(minor), "scsa2usb")) { 1042 return (DM_CTYPE_USB); 1043 } 1044 1045 if (libdiskmgt_str_eq(type, DDI_NT_SCSI_NEXUS) || 1046 libdiskmgt_str_eq(type, DDI_NT_SCSI_ATTACHMENT_POINT)) { 1047 return (DM_CTYPE_SCSI); 1048 } 1049 1050 if (libdiskmgt_str_eq(type, DDI_NT_FC_ATTACHMENT_POINT)) { 1051 return (DM_CTYPE_FIBRE); 1052 } 1053 1054 if (libdiskmgt_str_eq(type, DDI_NT_NEXUS) && 1055 libdiskmgt_str_eq(name, "fp")) { 1056 return (DM_CTYPE_FIBRE); 1057 } 1058 1059 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1060 libdiskmgt_str_eq(name, "ide")) { 1061 return (DM_CTYPE_ATA); 1062 } 1063 1064 return (DM_CTYPE_UNKNOWN); 1065 } 1066 1067 static boolean_t 1068 disk_is_cdrom(char *type) 1069 { 1070 1071 int type_index; 1072 1073 for (type_index = 0; cdromtypes[type_index] != NULL; type_index++) { 1074 if (libdiskmgt_str_eq(type, cdromtypes[type_index])) { 1075 return (B_TRUE); 1076 } 1077 } 1078 1079 return (B_FALSE); 1080 } 1081 1082 static alias_t * 1083 find_alias(disk_t *diskp, char *kernel_name) 1084 { 1085 alias_t *ap; 1086 1087 ap = diskp->aliases; 1088 while (ap != NULL) { 1089 if (libdiskmgt_str_eq(ap->kstat_name, kernel_name)) { 1090 return (ap); 1091 } 1092 ap = ap->next; 1093 } 1094 1095 return (NULL); 1096 } 1097 1098 static bus_t * 1099 find_bus(struct search_args *args, char *name) 1100 { 1101 bus_t *listp; 1102 1103 listp = args->bus_listp; 1104 while (listp != NULL) { 1105 if (libdiskmgt_str_eq(listp->name, name)) { 1106 return (listp); 1107 } 1108 1109 listp = listp->next; 1110 } 1111 1112 return (NULL); 1113 } 1114 1115 static controller_t * 1116 find_controller(struct search_args *args, char *name) 1117 { 1118 controller_t *listp; 1119 1120 listp = args->controller_listp; 1121 while (listp != NULL) { 1122 if (libdiskmgt_str_eq(listp->name, name)) { 1123 return (listp); 1124 } 1125 1126 listp = listp->next; 1127 } 1128 1129 return (NULL); 1130 } 1131 1132 static int 1133 fix_cluster_devpath(di_devlink_t devlink, void *arg) 1134 { 1135 int fd; 1136 struct search_args *args; 1137 char *devlink_path; 1138 disk_t *diskp = NULL; 1139 alias_t *ap = NULL; 1140 1141 /* 1142 * The devlink_path is of the form /dev/did/rdsk/d1s0. 1143 */ 1144 1145 args = (struct search_args *)arg; 1146 1147 /* Find the disk by the deviceid we read from the cluster disk. */ 1148 devlink_path = (char *)di_devlink_path(devlink); 1149 if (devlink_path == NULL) { 1150 return (DI_WALK_CONTINUE); 1151 } 1152 1153 if ((fd = open(devlink_path, O_RDONLY|O_NDELAY)) >= 0) { 1154 ddi_devid_t devid; 1155 1156 if (dm_debug > 1) { 1157 (void) fprintf(stderr, "INFO: cluster devpath %s\n", 1158 devlink_path); 1159 } 1160 1161 if (devid_get(fd, &devid) == 0) { 1162 char *minor; 1163 char *devidstr; 1164 1165 minor = di_minor_name(args->minor); 1166 1167 if ((devidstr = devid_str_encode(devid, minor)) != NULL) { 1168 diskp = get_disk_by_deviceid(args->disk_listp, devidstr); 1169 1170 /* 1171 * This really shouldn't happen, since we should have 1172 * found all of the disks during our first pass through 1173 * the dev tree, but just in case... 1174 */ 1175 if (diskp == NULL) { 1176 if (dm_debug > 1) { 1177 (void) fprintf(stderr, 1178 "INFO: cluster create disk\n"); 1179 } 1180 1181 diskp = create_disk(devidstr, NULL, args); 1182 if (diskp == NULL) { 1183 args->dev_walk_status = ENOMEM; 1184 } 1185 1186 /* add the controller relationship */ 1187 if (args->dev_walk_status == 0) { 1188 if (add_disk2controller(diskp, args) != 0) { 1189 args->dev_walk_status = ENOMEM; 1190 } 1191 } 1192 1193 if (new_alias(diskp, NULL, devlink_path, args) 1194 != 0) { 1195 args->dev_walk_status = ENOMEM; 1196 } 1197 } 1198 1199 devid_str_free(devidstr); 1200 } 1201 1202 devid_free(devid); 1203 } 1204 (void) close(fd); 1205 } 1206 1207 1208 if (diskp != NULL) { 1209 if (dm_debug > 1) { 1210 (void) fprintf(stderr, "INFO: cluster found disk\n"); 1211 } 1212 1213 ap = diskp->aliases; 1214 } 1215 1216 if (ap != NULL) { 1217 /* NOTE: if ap->next != NULL have cluster disks w/ multiple paths */ 1218 1219 if (!ap->cluster) { 1220 char *basep; 1221 char *namep; 1222 int cnt = 0; 1223 int size; 1224 char alias[MAXPATHLEN]; 1225 1226 /* 1227 * First time; save the /dev/rdsk devpaths and update the 1228 * alias info with the new alias name. 1229 */ 1230 ap->orig_paths = ap->devpaths; 1231 ap->devpaths = NULL; 1232 1233 free(ap->alias); 1234 1235 /* get the new cluster alias name */ 1236 basep = strrchr(devlink_path, '/'); 1237 if (basep == NULL) { 1238 basep = devlink_path; 1239 } else { 1240 basep++; 1241 } 1242 1243 size = sizeof (alias) - 1; 1244 namep = alias; 1245 while (*basep != 0 && *basep != 's' && cnt < size) { 1246 *namep++ = *basep++; 1247 cnt++; 1248 } 1249 *namep = 0; 1250 1251 if ((ap->alias = strdup(alias)) == NULL) { 1252 args->dev_walk_status = ENOMEM; 1253 } 1254 1255 ap->cluster = 1; 1256 } 1257 1258 if (new_devpath(ap, devlink_path) != 0) { 1259 args->dev_walk_status = ENOMEM; 1260 } 1261 } 1262 1263 return (DI_WALK_CONTINUE); 1264 } 1265 1266 /* 1267 * Check if we have the drive in our list, based upon the device id. 1268 * We got the device id from the dev tree walk. This is encoded 1269 * using devid_str_encode(3DEVID). In order to check the device ids we need 1270 * to use the devid_compare(3DEVID) function, so we need to decode the 1271 * string representation of the device id. 1272 */ 1273 static disk_t * 1274 get_disk_by_deviceid(disk_t *listp, char *devidstr) 1275 { 1276 ddi_devid_t devid; 1277 1278 if (devidstr == NULL || devid_str_decode(devidstr, &devid, NULL) != 0) { 1279 return (NULL); 1280 } 1281 1282 while (listp != NULL) { 1283 if (listp->devid != NULL && 1284 devid_compare(listp->devid, devid) == 0) { 1285 break; 1286 } 1287 1288 listp = listp->next; 1289 } 1290 1291 devid_free(devid); 1292 1293 return (listp); 1294 } 1295 1296 /* 1297 * Get the base disk name with no path prefix and no slice (if there is one). 1298 * The name parameter should be big enough to hold the name. 1299 * This handles diskette names ok (/dev/rdiskette0) since there is no slice, 1300 * and converts the raw diskette name. 1301 * But, we don't know how to strip off the slice from third party drive 1302 * names. That just means that their drive name will include a slice on 1303 * it. 1304 */ 1305 static void 1306 get_disk_name_from_path(char *path, char *name, int size) 1307 { 1308 char *basep; 1309 int cnt = 0; 1310 1311 basep = strrchr(path, '/'); 1312 if (basep == NULL) { 1313 basep = path; 1314 } else { 1315 basep++; 1316 } 1317 1318 size = size - 1; /* leave room for terminating 0 */ 1319 1320 if (is_ctds(basep)) { 1321 while (*basep != 0 && *basep != 's' && cnt < size) { 1322 *name++ = *basep++; 1323 cnt++; 1324 } 1325 *name = 0; 1326 } else { 1327 if (strncmp(basep, FLOPPY_NAME, sizeof (FLOPPY_NAME) - 1) == 0) { 1328 /* 1329 * a floppy, convert rdiskette name to diskette name, 1330 * by skipping over the 'r' for raw diskette 1331 */ 1332 basep++; 1333 } 1334 1335 /* not a ctds name, just copy it */ 1336 (void) strlcpy(name, basep, size); 1337 } 1338 } 1339 1340 static char * 1341 get_byte_prop(char *prop_name, di_node_t node) 1342 { 1343 int cnt; 1344 uchar_t *bytes; 1345 int i; 1346 char str[MAXPATHLEN]; 1347 1348 cnt = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, prop_name, &bytes); 1349 if (cnt < 1) { 1350 return (NULL); 1351 } 1352 1353 str[0] = 0; 1354 for (i = 0; i < cnt; i++) { 1355 char bstr[8]; /* a byte is only 2 hex chars + null */ 1356 1357 (void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]); 1358 (void) strlcat(str, bstr, sizeof (str)); 1359 } 1360 return (strdup(str)); 1361 } 1362 1363 static di_node_t 1364 get_parent_bus(di_node_t node, struct search_args *args) 1365 { 1366 di_node_t pnode; 1367 1368 pnode = di_parent_node(node); 1369 if (pnode == DI_NODE_NIL) { 1370 return (NULL); 1371 } 1372 1373 if (bus_type(pnode, di_minor_next(pnode, NULL), args->ph) != NULL) { 1374 return (pnode); 1375 } 1376 1377 return (get_parent_bus(pnode, args)); 1378 } 1379 1380 static int 1381 get_prom_int(char *prop_name, di_node_t node, di_prom_handle_t ph) 1382 { 1383 int *n; 1384 1385 if (di_prom_prop_lookup_ints(ph, node, prop_name, &n) == 1) { 1386 return (*n); 1387 } 1388 1389 return (0); 1390 } 1391 1392 static char * 1393 get_prom_str(char *prop_name, di_node_t node, di_prom_handle_t ph) 1394 { 1395 char *str; 1396 1397 if (di_prom_prop_lookup_strings(ph, node, prop_name, &str) == 1) { 1398 return (str); 1399 } 1400 1401 return (NULL); 1402 } 1403 1404 /* 1405 * Get one of the positive int or boolean properties. 1406 */ 1407 static int 1408 get_prop(char *prop_name, di_node_t node) 1409 { 1410 int num; 1411 int *ip; 1412 1413 if ((num = di_prop_lookup_ints(DDI_DEV_T_ANY, node, prop_name, &ip)) 1414 >= 0) { 1415 if (num == 0) { 1416 /* boolean */ 1417 return (1); 1418 } else if (num == 1) { 1419 /* single int */ 1420 return (*ip); 1421 } 1422 } 1423 1424 return (-1); 1425 } 1426 1427 static char * 1428 get_str_prop(char *prop_name, di_node_t node) 1429 { 1430 char *str; 1431 1432 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, prop_name, &str) == 1) { 1433 return (str); 1434 } 1435 1436 return (NULL); 1437 } 1438 1439 /* 1440 * Check if we have the drive in our list, based upon the device id, if the 1441 * drive has a device id, or the kernel name, if it doesn't have a device id. 1442 */ 1443 static int 1444 have_disk(struct search_args *args, char *devidstr, char *kernel_name, 1445 disk_t **diskp) 1446 { 1447 disk_t *listp; 1448 1449 *diskp = NULL; 1450 listp = args->disk_listp; 1451 if (devidstr != NULL) { 1452 if ((*diskp = get_disk_by_deviceid(listp, devidstr)) != NULL) { 1453 return (1); 1454 } 1455 1456 } else { 1457 /* no devid, try matching the kernel names on the drives */ 1458 while (listp != NULL) { 1459 if (libdiskmgt_str_eq(kernel_name, listp->kernel_name)) { 1460 *diskp = listp; 1461 return (1); 1462 } 1463 listp = listp->next; 1464 } 1465 } 1466 1467 return (0); 1468 } 1469 1470 static char * 1471 bus_type(di_node_t node, di_minor_t minor, di_prom_handle_t ph) 1472 { 1473 char *type; 1474 int i; 1475 1476 type = get_prom_str("device_type", node, ph); 1477 if (type == NULL) { 1478 type = di_node_name(node); 1479 } 1480 1481 for (i = 0; bustypes[i]; i++) { 1482 if (libdiskmgt_str_eq(type, bustypes[i])) { 1483 return (type); 1484 } 1485 } 1486 1487 if (minor != NULL && strcmp(di_minor_nodetype(minor), 1488 DDI_NT_USB_ATTACHMENT_POINT) == 0) { 1489 return ("usb"); 1490 } 1491 1492 return (NULL); 1493 } 1494 1495 static int 1496 is_cluster_disk(di_node_t node, di_minor_t minor) 1497 { 1498 if (di_minor_spectype(minor) == S_IFCHR && 1499 libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_PSEUDO) && 1500 libdiskmgt_str_eq(di_node_name(node), CLUSTER_DEV)) { 1501 return (1); 1502 } 1503 1504 return (0); 1505 } 1506 1507 /* 1508 * If the input name is in c[t]ds format then return 1, otherwise return 0. 1509 */ 1510 static int 1511 is_ctds(char *name) 1512 { 1513 char *p; 1514 1515 p = name; 1516 1517 if (*p++ != 'c') { 1518 return (0); 1519 } 1520 /* skip controller digits */ 1521 while (isdigit(*p)) { 1522 p++; 1523 } 1524 1525 /* handle optional target */ 1526 if (*p == 't') { 1527 p++; 1528 /* skip over target */ 1529 while (isdigit(*p) || isupper(*p)) { 1530 p++; 1531 } 1532 } 1533 1534 if (*p++ != 'd') { 1535 return (0); 1536 } 1537 while (isdigit(*p)) { 1538 p++; 1539 } 1540 1541 if (*p++ != 's') { 1542 return (0); 1543 } 1544 1545 /* check the slice number */ 1546 while (isdigit(*p)) { 1547 p++; 1548 } 1549 1550 if (*p != 0) { 1551 return (0); 1552 } 1553 1554 return (1); 1555 } 1556 1557 static int 1558 is_drive(di_minor_t minor) 1559 { 1560 char *type; 1561 int type_index; 1562 1563 type = di_minor_nodetype(minor); 1564 type_index = 0; 1565 1566 while (disktypes[type_index] != NULL) { 1567 if (libdiskmgt_str_eq(type, disktypes[type_index])) { 1568 return (1); 1569 } 1570 type_index++; 1571 } 1572 1573 return (0); 1574 } 1575 1576 static int 1577 is_HBA(di_node_t node, di_minor_t minor) 1578 { 1579 char *type; 1580 char *name; 1581 int type_index; 1582 1583 type = di_minor_nodetype(minor); 1584 type_index = 0; 1585 1586 while (ctrltypes[type_index] != NULL) { 1587 if (libdiskmgt_str_eq(type, ctrltypes[type_index])) { 1588 return (1); 1589 } 1590 type_index++; 1591 } 1592 1593 name = di_node_name(node); 1594 if (libdiskmgt_str_eq(type, DDI_PSEUDO) && 1595 libdiskmgt_str_eq(name, "ide")) { 1596 return (1); 1597 } 1598 1599 return (0); 1600 } 1601 1602 static int 1603 new_alias(disk_t *diskp, char *kernel_name, char *devlink_path, 1604 struct search_args *args) 1605 { 1606 alias_t *aliasp; 1607 char alias[MAXPATHLEN]; 1608 di_node_t pnode; 1609 1610 aliasp = malloc(sizeof (alias_t)); 1611 if (aliasp == NULL) { 1612 return (ENOMEM); 1613 } 1614 1615 aliasp->alias = NULL; 1616 aliasp->kstat_name = NULL; 1617 aliasp->wwn = NULL; 1618 aliasp->devpaths = NULL; 1619 aliasp->orig_paths = NULL; 1620 1621 get_disk_name_from_path(devlink_path, alias, sizeof (alias)); 1622 1623 aliasp->alias = strdup(alias); 1624 if (aliasp->alias == NULL) { 1625 cache_free_alias(aliasp); 1626 return (ENOMEM); 1627 } 1628 1629 if (kernel_name != NULL) { 1630 aliasp->kstat_name = strdup(kernel_name); 1631 if (aliasp->kstat_name == NULL) { 1632 cache_free_alias(aliasp); 1633 return (ENOMEM); 1634 } 1635 } else { 1636 aliasp->kstat_name = NULL; 1637 } 1638 1639 aliasp->cluster = 0; 1640 aliasp->lun = get_prop(DM_LUN, args->node); 1641 aliasp->target = get_prop(DM_TARGET, args->node); 1642 aliasp->wwn = get_byte_prop(WWN_PROP, args->node); 1643 1644 pnode = di_parent_node(args->node); 1645 if (pnode != DI_NODE_NIL) { 1646 char prop_name[MAXPROPLEN]; 1647 1648 (void) snprintf(prop_name, sizeof (prop_name), 1649 "target%d-sync-speed", aliasp->target); 1650 diskp->sync_speed = get_prop(prop_name, pnode); 1651 (void) snprintf(prop_name, sizeof (prop_name), "target%d-wide", 1652 aliasp->target); 1653 diskp->wide = get_prop(prop_name, pnode); 1654 } 1655 1656 if (new_devpath(aliasp, devlink_path) != 0) { 1657 cache_free_alias(aliasp); 1658 return (ENOMEM); 1659 } 1660 1661 aliasp->next = diskp->aliases; 1662 diskp->aliases = aliasp; 1663 1664 return (0); 1665 } 1666 1667 /* 1668 * Append the new devpath to the end of the devpath list. This is important 1669 * since we may want to use the order of the devpaths to match up the vtoc 1670 * entries. 1671 */ 1672 static int 1673 new_devpath(alias_t *ap, char *devpath) 1674 { 1675 slice_t *newdp; 1676 slice_t *alistp; 1677 1678 /* 1679 * First, search the alias list to be sure that this devpath is 1680 * not already there. 1681 */ 1682 1683 for (alistp = ap->devpaths; alistp != NULL; alistp = alistp->next) { 1684 if (libdiskmgt_str_eq(alistp->devpath, devpath)) { 1685 return (0); 1686 } 1687 } 1688 1689 /* 1690 * Otherwise, not found so add this new devpath to the list. 1691 */ 1692 1693 newdp = malloc(sizeof (slice_t)); 1694 if (newdp == NULL) { 1695 return (ENOMEM); 1696 } 1697 1698 newdp->devpath = strdup(devpath); 1699 if (newdp->devpath == NULL) { 1700 free(newdp); 1701 return (ENOMEM); 1702 } 1703 newdp->slice_num = -1; 1704 newdp->next = NULL; 1705 1706 if (ap->devpaths == NULL) { 1707 ap->devpaths = newdp; 1708 } else { 1709 /* append the devpath to the end of the list */ 1710 slice_t *dp; 1711 1712 dp = ap->devpaths; 1713 while (dp->next != NULL) { 1714 dp = dp->next; 1715 } 1716 1717 dp->next = newdp; 1718 } 1719 1720 return (0); 1721 } 1722 1723 static path_t * 1724 new_path(controller_t *cp, disk_t *dp, di_node_t node, di_path_state_t st, 1725 char *wwn) 1726 { 1727 char *devpath; 1728 path_t *pp; 1729 di_minor_t minor; 1730 1731 /* Special handling for fp attachment node. */ 1732 if (strcmp(di_node_name(node), "fp") == 0) { 1733 di_node_t pnode; 1734 1735 pnode = di_parent_node(node); 1736 if (pnode != DI_NODE_NIL) { 1737 node = pnode; 1738 } 1739 } 1740 1741 devpath = di_devfs_path(node); 1742 1743 /* check if the path is already there */ 1744 pp = NULL; 1745 if (cp->paths != NULL) { 1746 int i; 1747 1748 for (i = 0; cp->paths[i]; i++) { 1749 if (libdiskmgt_str_eq(devpath, cp->paths[i]->name)) { 1750 pp = cp->paths[i]; 1751 break; 1752 } 1753 } 1754 } 1755 1756 if (pp != NULL) { 1757 /* the path exists, add this disk to it */ 1758 1759 di_devfs_path_free((void *) devpath); 1760 1761 if (!add_disk2path(dp, pp, st, wwn)) { 1762 return (NULL); 1763 } 1764 1765 return (pp); 1766 } 1767 1768 /* create a new path */ 1769 1770 pp = calloc(1, sizeof (path_t)); 1771 if (pp == NULL) { 1772 di_devfs_path_free((void *) devpath); 1773 return (NULL); 1774 } 1775 1776 pp->name = strdup(devpath); 1777 di_devfs_path_free((void *) devpath); 1778 if (pp->name == NULL) { 1779 cache_free_path(pp); 1780 return (NULL); 1781 } 1782 1783 /* add the disk to the path */ 1784 if (!add_disk2path(dp, pp, st, wwn)) { 1785 return (NULL); 1786 } 1787 1788 /* add the path to the controller */ 1789 if (add_ptr2array(pp, (void ***)&cp->paths) != 0) { 1790 cache_free_path(pp); 1791 return (NULL); 1792 } 1793 1794 /* add the controller to the path */ 1795 pp->controller = cp; 1796 1797 minor = di_minor_next(node, NULL); 1798 if (minor != NULL) { 1799 pp->ctype = ctype(node, minor); 1800 } else { 1801 pp->ctype = DM_CTYPE_UNKNOWN; 1802 } 1803 1804 return (pp); 1805 } 1806 1807 /* 1808 * We pass in the current controller pointer (currp) so we can double check 1809 * that we aren't corrupting the list by removing the element we are on. This 1810 * should never happen, but it doesn't hurt to double check. 1811 */ 1812 static void 1813 remove_invalid_controller(char *name, controller_t *currp, 1814 struct search_args *args) 1815 { 1816 controller_t *cp; 1817 bus_t *bp; 1818 controller_t *prevp; 1819 1820 bp = args->bus_listp; 1821 while (bp != NULL) { 1822 int i; 1823 1824 for (i = 0; bp->controllers[i]; i++) { 1825 if (libdiskmgt_str_eq(bp->controllers[i]->name, name)) { 1826 int j; 1827 1828 /* remove pointer to invalid controller (it is a path) */ 1829 for (j = i; bp->controllers[j]; j++) { 1830 bp->controllers[j] = bp->controllers[j + 1]; 1831 } 1832 } 1833 } 1834 bp = bp->next; 1835 } 1836 1837 if (args->controller_listp == NULL) { 1838 return; 1839 } 1840 1841 cp = args->controller_listp; 1842 if (libdiskmgt_str_eq(cp->name, name)) { 1843 if (can_remove_controller(cp, currp)) { 1844 args->controller_listp = cp->next; 1845 cache_free_controller(cp); 1846 } 1847 return; 1848 } 1849 1850 prevp = cp; 1851 cp = cp->next; 1852 while (cp != NULL) { 1853 if (libdiskmgt_str_eq(cp->name, name)) { 1854 if (can_remove_controller(cp, currp)) { 1855 prevp->next = cp->next; 1856 cache_free_controller(cp); 1857 } 1858 return; 1859 } 1860 prevp = cp; 1861 cp = cp->next; 1862 } 1863 } 1864 1865 /* 1866 * This is the standard strstr code modified for case independence. 1867 */ 1868 static char * 1869 str_case_index(register char *s1, register char *s2) 1870 { 1871 uint_t s2len = strlen(s2); /* length of the second string */ 1872 1873 /* If the length of the second string is 0, return the first arg. */ 1874 if (s2len == 0) { 1875 return (s1); 1876 } 1877 1878 while (strlen(s1) >= s2len) { 1879 if (strncasecmp(s1, s2, s2len) == 0) { 1880 return (s1); 1881 } 1882 s1++; 1883 } 1884 return (NULL); 1885 } 1886