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 /* 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <stdarg.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <fcntl.h> 32 #include <errno.h> 33 #include <unistd.h> 34 #include <stropts.h> 35 #include <strings.h> 36 #include <sys/param.h> 37 #include <libdevinfo.h> 38 #include <locale.h> 39 #include <libintl.h> 40 #include <devid.h> 41 #include <sys/libdevid.h> 42 #include <sys/modctl.h> /* for MAXMODCONFNAME */ 43 #include <sys/scsi/adapters/scsi_vhci.h> 44 45 /* 46 * SAVE_DIR is the directory in which system files are saved. 47 * SAVE_DIR must be under the root filesystem, as this program is 48 * typically run before any other filesystems are mounted. 49 */ 50 #define SAVE_DIR "/etc/mpxio" 51 #define VHCI_CTL_NODE "/devices/scsi_vhci:devctl" 52 53 /* nvlist property names, these are ALL string types */ 54 #define NVL_DEVID "nvl-devid" 55 #define NVL_PATH "nvl-path" 56 #define NVL_PHYSPATH "nvl-physpath" 57 #define NVL_MPXPATH "nvl-mpxiopath" 58 #define NVL_MPXEN "nvl-mpxioenabled" 59 60 #define MPX_LIST 0x01 61 #define MPX_MAP 0x02 62 #define MPX_CAPABLE_CTRL 0x04 63 #define MPX_DEV_PATH 0x06 64 #define MPX_INIT 0x08 65 #define MPX_PHYSICAL 0x10 66 #define MPX_BOOTPATH 0x20 67 #define MPX_UPDATEVFSTAB 0x40 68 #define MPX_GETPATH 0x60 69 #define MPX_USAGE 0x80 70 #define MSG_INFO 0x01 71 #define MSG_ERROR 0x02 72 #define MSG_PANIC 0x04 73 74 #define BOOT_PATH 0x02 75 #define BOOT 0x01 76 #define NONBOOT 0x00 77 78 #define DISPLAY_ONE_PATH 0x00 79 #define DISPLAY_ALL_PATH 0x01 80 81 static di_node_t devinfo_root = DI_NODE_NIL; 82 static char *ondiskname = "/etc/mpxio/devid_path.cache"; 83 84 /* 85 * We use devid-keyed nvlists to keep track of the guid, traditional and 86 * MPxIO-enabled /dev/rdsk paths. Each of these nvlists is eventually 87 * added to our global nvlist and our on-disk nvlist. 88 */ 89 static nvlist_t *mapnvl; 90 static int mpxenabled = 0; 91 static int limctrl = -1; 92 static int mpxprop = 0; 93 static int guid = 0; 94 static char *drvlimit; 95 static int globarg = 0; 96 static int debugflag = 0; 97 static char *devicep; 98 static int readonlyroot = 0; 99 static int cap_N_option = 0; 100 101 static void print_mpx_capable(di_node_t curnode); 102 static int popcheck_devnvl(di_node_t thisnode, nvlist_t *devnvl, 103 char *strdevid); 104 static int mpxio_nvl_boilerplate(di_node_t curnode); 105 static int validate_devnvl(); 106 static void report_map(char *argdev, int physpath); 107 static void list_devs(int listguids, int ctrl); 108 static void logmsg(int level, const char *msg, ...); 109 static char *find_link(di_node_t cnode); 110 static void usage(); 111 static void parse_args(int argc, char *argv[]); 112 static void get_devid(di_node_t node, ddi_devid_t *thisdevid); 113 static int print_bootpath(); 114 static void vhci_to_phci(char *devpath, char *slice, int d_flag); 115 static int update_vfstab(); 116 static void report_dev_node_name(char *strdevfspath); 117 static void print_node_name(char *drv_name, char *strdevfspath); 118 int 119 main(int argc, char **argv) 120 { 121 struct stat cachestat; 122 int mapfd = 0; 123 int rv = 0; 124 char *ondiskbuf; 125 size_t newsz = 0; 126 127 parse_args(argc, argv); 128 errno = 0; 129 devinfo_root = di_init("/", DINFOCPYALL|DINFOFORCE); 130 logmsg(MSG_INFO, "errno = %d after " 131 "di_init(/,DINFOCPYALL|DINFOFORCE)\n", errno); 132 if (devinfo_root == NULL) { 133 logmsg(MSG_ERROR, 134 gettext("Unable to take device tree snapshot " 135 "(%s: %d)\n"), strerror(errno), errno); 136 return (-1); 137 } 138 logmsg(MSG_INFO, "opened root di_node\n"); 139 140 if (globarg == MPX_CAPABLE_CTRL) { 141 /* we just want to find MPxIO-capable controllers and exit */ 142 if (drvlimit != NULL) { 143 print_mpx_capable(di_drv_first_node(drvlimit, 144 devinfo_root)); 145 } else { 146 print_mpx_capable(di_drv_first_node("fp", 147 devinfo_root)); 148 print_mpx_capable(di_drv_first_node("mpt", 149 devinfo_root)); 150 print_mpx_capable(di_drv_first_node("mpt_sas", 151 devinfo_root)); 152 print_mpx_capable(di_drv_first_node("pmcs", 153 devinfo_root)); 154 } 155 di_fini(devinfo_root); 156 return (0); 157 } 158 159 mapfd = open(ondiskname, O_RDWR|O_CREAT|O_SYNC, S_IRUSR | S_IWUSR); 160 if (mapfd < 0) { 161 /* we could be in single-user, so try for RO */ 162 if ((mapfd = open(ondiskname, O_RDONLY)) < 0) { 163 logmsg(MSG_ERROR, 164 gettext("Unable to open or create %s:%s\n"), 165 ondiskname, strerror(errno)); 166 return (errno); 167 } 168 readonlyroot = 1; 169 } 170 171 if (stat(ondiskname, &cachestat) != 0) { 172 logmsg(MSG_ERROR, 173 gettext("Unable to stat() %s: %s\n"), 174 ondiskname, strerror(errno)); 175 return (errno); 176 } 177 ondiskbuf = calloc(1, cachestat.st_size); 178 if (ondiskbuf == NULL) { 179 logmsg(MSG_ERROR, 180 gettext("Unable to allocate memory for the devid " 181 "cache file: %s\n"), strerror(errno)); 182 return (errno); 183 } 184 rv = read(mapfd, ondiskbuf, cachestat.st_size); 185 if (rv != cachestat.st_size) { 186 logmsg(MSG_ERROR, 187 gettext("Unable to read all of devid cache file (got %d " 188 "from expected %d bytes): %s\n"), 189 rv, cachestat.st_size, strerror(errno)); 190 return (errno); 191 } 192 errno = 0; 193 rv = nvlist_unpack(ondiskbuf, cachestat.st_size, &mapnvl, 0); 194 if (rv) { 195 logmsg(MSG_INFO, 196 "Unable to unpack devid cache file %s: %s (%d)\n", 197 ondiskname, strerror(rv), rv); 198 if (nvlist_alloc(&mapnvl, NV_UNIQUE_NAME, 0) != 0) { 199 logmsg(MSG_ERROR, 200 gettext("Unable to allocate root property" 201 "list\n")); 202 return (errno); 203 } 204 } 205 free(ondiskbuf); 206 207 if (validate_devnvl() < 0) { 208 logmsg(MSG_ERROR, 209 gettext("unable to validate kernel with on-disk devid " 210 "cache file\n")); 211 return (errno); 212 } 213 214 /* 215 * If we're in single-user mode or maintenance mode, we won't 216 * necessarily have a writable root device (ZFSroot; ufs root is 217 * different in that we _do_ have a writable root device. 218 * This causes problems for the devlink calls (see 219 * $SRC/lib/libdevinfo/devinfo_devlink.c) and we do not try to 220 * write out the devnvl if root is readonly. 221 */ 222 if (!readonlyroot) { 223 rv = nvlist_size(mapnvl, &newsz, NV_ENCODE_NATIVE); 224 if (rv) { 225 logmsg(MSG_ERROR, 226 gettext("Unable to determine size of packed " 227 "on-disk devid cache file %s: %s (%d).\n"), 228 ondiskname, strerror(rv), rv); 229 logmsg(MSG_ERROR, gettext("Terminating\n")); 230 nvlist_free(mapnvl); 231 (void) close(mapfd); 232 return (rv); 233 } 234 235 if ((ondiskbuf = calloc(1, newsz)) == NULL) { 236 logmsg(MSG_ERROR, 237 "Unable to allocate space for writing out new " 238 "on-disk devid cache file: %s\n", strerror(errno)); 239 (void) close(mapfd); 240 nvlist_free(mapnvl); 241 return (errno); 242 } 243 244 rv = nvlist_pack(mapnvl, &ondiskbuf, &newsz, 245 NV_ENCODE_NATIVE, 0); 246 if (rv) { 247 logmsg(MSG_ERROR, 248 gettext("Unable to pack on-disk devid cache " 249 "file: %s (%d)\n"), strerror(rv), rv); 250 (void) close(mapfd); 251 free(ondiskbuf); 252 nvlist_free(mapnvl); 253 return (rv); 254 } 255 256 rv = lseek(mapfd, 0, 0); 257 if (rv == -1) { 258 logmsg(MSG_ERROR, 259 gettext("Unable to seek to start of devid cache " 260 "file: %s (%d)\n"), strerror(errno), errno); 261 (void) close(mapfd); 262 free(ondiskbuf); 263 nvlist_free(mapnvl); 264 return (-1); 265 } 266 267 if (write(mapfd, ondiskbuf, newsz) != newsz) { 268 logmsg(MSG_ERROR, 269 gettext("Unable to completely write out " 270 "on-disk devid cache file: %s\n"), strerror(errno)); 271 (void) close(mapfd); 272 nvlist_free(mapnvl); 273 free(ondiskbuf); 274 return (errno); 275 } 276 } /* !readonlyroot */ 277 278 /* Now we can process the command line args */ 279 if (globarg == MPX_PHYSICAL) { 280 report_map(devicep, BOOT); 281 } else if (globarg == MPX_BOOTPATH) { 282 rv = print_bootpath(); 283 di_fini(devinfo_root); 284 return (rv); 285 } else if (globarg == MPX_UPDATEVFSTAB) { 286 rv = update_vfstab(); 287 di_fini(devinfo_root); 288 return (rv); 289 } else if (globarg == MPX_GETPATH) { 290 report_dev_node_name(devicep); 291 } else if (globarg == MPX_DEV_PATH) { 292 report_map(devicep, BOOT_PATH); 293 } else if (globarg != MPX_INIT) { 294 if (globarg & MPX_LIST) 295 list_devs(guid, limctrl); 296 297 if (globarg == MPX_MAP) 298 report_map(devicep, NONBOOT); 299 } else { 300 logmsg(MSG_INFO, "\nprivate devid cache file initialised\n"); 301 } 302 303 nvlist_free(mapnvl); 304 di_fini(devinfo_root); 305 return (0); 306 } 307 308 static void 309 usage() 310 { 311 (void) fprintf(stderr, 312 gettext("usage: stmsboot_util -b | -m devname | " 313 "-l <ctrl> | -L | [-g] | -n | -N | -i | -p devname\n")); 314 (void) fprintf(stderr, "\n\n"); 315 (void) fprintf(stderr, gettext("\t-h\tprint this usage message\n")); 316 (void) fprintf(stderr, gettext("\t-b\tretrieve the system's bootpath " 317 "setting\n")); 318 (void) fprintf(stderr, gettext("\t-m devname\n")); 319 (void) fprintf(stderr, gettext("\t\tReports the current mapping for " 320 "devname\n")); 321 (void) fprintf(stderr, gettext("\t-g\tprint the GUID for MPxIO-capable " 322 "devices. This\n")); 323 (void) fprintf(stderr, gettext("\t\toption is only valid with the -L " 324 "or -l options\n")); 325 (void) fprintf(stderr, gettext("\t-L | -l <ctrl>\n")); 326 (void) fprintf(stderr, gettext("\t\tList the 'native' to 'MPxIO' " 327 "device mappings. If <ctrl>\n")); 328 (void) fprintf(stderr, gettext("\t\tis specified, only print mappings " 329 "for those devices\n")); 330 (void) fprintf(stderr, gettext("\t\tattached via the specified " 331 "controller.\n")); 332 (void) fprintf(stderr, gettext("\t-i\tinitialise the private devid " 333 "cache file and exit\n")); 334 (void) fprintf(stderr, gettext("\t\tThis option excludes all " 335 "others.\n")); 336 (void) fprintf(stderr, gettext("\t-n\tprint the devfs paths for " 337 "multipath-capable\n")); 338 (void) fprintf(stderr, gettext("\t\tcontroller ports.\n")); 339 (void) fprintf(stderr, gettext("\t-N\tprint the device aliases of " 340 "multipath-capable\n")); 341 (void) fprintf(stderr, gettext("\t\tcontroller ports.\n")); 342 (void) fprintf(stderr, gettext("\t-p\tdevname\n")); 343 (void) fprintf(stderr, gettext("\t\tThis option provides the physical " 344 "devfs path for\n")); 345 (void) fprintf(stderr, gettext("\t\ta specific device (devname). Used " 346 "to set the bootpath\n")); 347 (void) fprintf(stderr, gettext("\t\tvariable on x86/x64 systems\n")); 348 (void) fprintf(stderr, gettext("\t-u\ttranslates device mappings in " 349 "/etc/vfstab as \n")); 350 (void) fprintf(stderr, gettext("\t\trequired. The output is written " 351 "to /etc/mpxio/vfstab.new\n\n")); 352 exit(2); 353 } 354 355 static void 356 parse_args(int argc, char *argv[]) 357 { 358 char opt; 359 360 if (argc == 1) 361 usage(); 362 363 /* 364 * -b prints the bootpath property 365 * -d turns on debug mode for this utility (copious output!) 366 * -D drvname 367 * if supplied, indicates that we're going to operate on 368 * devices attached to this driver. 369 * -g if (-l or -L), prints guids for devices rather than paths 370 * -h prints the usage() help text. 371 * -i initialises the cache file and exits. 372 * -l controller 373 * list non-STMS to STMS device name mappings for the specific 374 * controller, when MPxIO is enabled only. 375 * -L list non-STMS to STMS device name mappings for all controllers 376 * when MPxIO is enabled only. 377 * -m devname 378 * prints the device path (/dev/rdsk) that devname maps to 379 * in the currently-running system. 380 * -n 381 * if supplied, returns name of STMS-capable controller nodes. 382 * If the -D drvname option is specified as well, we only report 383 * nodes attached with drvname. 384 * -N 385 * same as the -n option, except that we only print the 386 * node-name (dev_info :: devi_node_name). Multiple instances 387 * through the libdevinfo snapshot are uniqified and separated 388 * by the "|" character for direct use by egrep(1). 389 * -p devname 390 * prints the physical devfs path for devname. Only used to 391 * determine the bootpath. 392 * -u 393 * remaps devices in /etc/vfstab, saving the newly generated 394 * file to /etc/mpxio/vfstab.new. If we have any remapped 395 * devices, exit with status 0, otherwise -1 for error. 396 */ 397 while ((opt = getopt(argc, argv, "bdD:ghil:Lm:nNo:p:q:u")) != EOF) { 398 switch (opt) { 399 case 'b': 400 globarg = MPX_BOOTPATH; 401 break; 402 case 'd': 403 debugflag = 1; 404 break; 405 case 'D': 406 if ((drvlimit = calloc(1, MAXMODCONFNAME)) == NULL) { 407 logmsg(MSG_ERROR, 408 gettext("Unable to allocate memory for a " 409 "driver name: %s\n"), strerror(errno)); 410 exit(errno); 411 } 412 bcopy(optarg, drvlimit, strlen(optarg)); 413 /* update this if adding support for a new driver */ 414 if ((strncmp(drvlimit, "fp", 2) == NULL) && 415 (strncmp(drvlimit, "mpt", 3) == NULL) && 416 (strncmp(drvlimit, "mpt_sas", 7) == NULL) && 417 (strncmp(drvlimit, "pmcs", 4) == NULL)) { 418 logmsg(MSG_ERROR, 419 gettext("invalid parent driver (%s) " 420 "specified"), drvlimit); 421 usage(); 422 } 423 break; 424 case 'h': 425 /* Just drop out and print the usage() output */ 426 globarg = MPX_USAGE; 427 break; 428 case 'i': 429 globarg = MPX_INIT; 430 break; 431 case 'l': 432 globarg |= MPX_LIST; 433 limctrl = (int)atol(optarg); 434 if (limctrl < 0) { 435 logmsg(MSG_INFO, 436 gettext("invalid controller number " 437 "(%d), checking all controllers\n"), 438 limctrl); 439 } 440 break; 441 case 'L': 442 globarg |= MPX_LIST; 443 break; 444 case 'g': 445 guid = 1; 446 break; 447 case 'm': 448 globarg = MPX_MAP; 449 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 450 logmsg(MSG_ERROR, 451 gettext("Unable to allocate space for a " 452 "device name\n")); 453 exit(errno); 454 } 455 devicep = strdup(optarg); 456 break; 457 case 'N': 458 cap_N_option = 1; 459 globarg = MPX_CAPABLE_CTRL; 460 break; 461 case 'n': 462 globarg = MPX_CAPABLE_CTRL; 463 break; 464 case 'o': 465 globarg = MPX_GETPATH; 466 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 467 logmsg(MSG_ERROR, 468 gettext("Unable to allocate space for a " 469 "device name\n")); 470 exit(errno); 471 } 472 devicep = strdup(optarg); 473 break; 474 case 'p': 475 globarg = MPX_PHYSICAL; 476 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 477 logmsg(MSG_ERROR, 478 gettext("Unable to allocate space for a " 479 "device name\n")); 480 exit(errno); 481 } 482 devicep = strdup(optarg); 483 break; 484 case 'q': 485 globarg = MPX_DEV_PATH; 486 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 487 logmsg(MSG_ERROR, 488 gettext("Unable to allocate space for a " 489 "device name\n")); 490 exit(errno); 491 } 492 devicep = strdup(optarg); 493 break; 494 case 'u': 495 globarg = MPX_UPDATEVFSTAB; 496 break; 497 default: 498 logmsg(MSG_ERROR, 499 gettext("Invalid command line option (%c)\n"), 500 opt); 501 usage(); 502 } 503 } 504 505 if ((globarg >= MPX_USAGE) || (guid && (globarg != MPX_LIST))) 506 usage(); 507 508 if ((drvlimit != NULL) && 509 ((globarg != MPX_LIST) && 510 (globarg != MPX_CAPABLE_CTRL))) 511 usage(); 512 } 513 514 static void 515 logmsg(int level, const char *msg, ...) 516 { 517 va_list ap; 518 519 if ((level >= MSG_ERROR) || 520 ((debugflag > 0) && (level >= MSG_INFO))) { 521 (void) fprintf(stdout, "stmsboot: "); 522 va_start(ap, msg); 523 (void) vfprintf(stdout, msg, ap); 524 va_end(ap); 525 } 526 } 527 528 /* 529 * It's up to the caller to do any sorting or pretty-printing of the device 530 * mappings we report. Since we're storing the device links as just the cXtYdZ 531 * part, we'll add /dev/rdsk/ back on when we print the listing so we maintain 532 * compatibility with previous versions of this tool. There's a little bit 533 * of footwork involved to make sure that we show all the paths to a device 534 * rather than just the first one we stashed away. 535 */ 536 static void 537 list_devs(int listguids, int ctrl) 538 { 539 nvlist_t *thisdevnvl; 540 nvpair_t *pair; 541 char *diskpath, *livepath, *key, *querydev; 542 char *matchctrl = NULL; 543 char checkctrl[MAXPATHLEN]; 544 int rv; 545 546 if (!mpxenabled) { 547 if (mpxprop) { 548 logmsg(MSG_ERROR, gettext("MPXIO disabled\n")); 549 } else { 550 logmsg(MSG_ERROR, gettext("No STMS devices have " 551 "been found\n")); 552 } 553 return; 554 } 555 556 if (listguids) { 557 (void) printf(gettext("non-STMS device name\t\t\tGUID\n" 558 "------------------------------------------" 559 "------------------------\n")); 560 } else { 561 (void) printf(gettext("non-STMS device name\t\t\t" 562 "STMS device name\n" 563 "------------------------------------------" 564 "------------------------\n")); 565 } 566 567 bzero(checkctrl, MAXPATHLEN); 568 pair = NULL; 569 while ((pair = nvlist_next_nvpair(mapnvl, pair)) 570 != NULL) { 571 boolean_t livescsivhcip = B_FALSE; 572 573 if ((((rv = nvpair_value_string(pair, &querydev)) < 0) || 574 ((key = nvpair_name(pair)) == NULL)) || 575 ((strstr(key, "/pci") != NULL) || 576 (strstr(key, "/sbus") != NULL) || 577 (strstr(key, "/scsi_vhci") != NULL) || 578 (strncmp(key, "id1", 3) == 0))) { 579 logmsg(MSG_INFO, 580 "list_devs: rv = %d; (%s) is not a devlink, " 581 "continuing.\n", rv, 582 (key != NULL) ? key : "null"); 583 querydev = NULL; 584 continue; 585 } 586 587 (void) nvlist_lookup_nvlist(mapnvl, querydev, &thisdevnvl); 588 (void) nvlist_lookup_boolean_value(thisdevnvl, NVL_MPXEN, 589 &livescsivhcip); 590 (void) nvlist_lookup_string(thisdevnvl, NVL_MPXPATH, 591 &livepath); 592 593 if ((!livescsivhcip) || 594 (livescsivhcip && 595 (strncmp(key, livepath, strlen(key)) == 0))) 596 continue; 597 598 (void) nvlist_lookup_string(thisdevnvl, NVL_PATH, 599 &diskpath); 600 601 logmsg(MSG_INFO, 602 "list_devs: %s :: %s ::%s :: MPXEN (%s)\n", 603 key, diskpath, livepath, 604 ((livescsivhcip) ? "TRUE" : "FALSE")); 605 606 if (ctrl > -1) { 607 (void) sprintf(checkctrl, "c%dt", ctrl); 608 matchctrl = strstr(key, checkctrl); 609 if (matchctrl == NULL) 610 continue; 611 } 612 if (listguids != 0) { 613 char *tempguid; 614 ddi_devid_t curdevid; 615 int rv; 616 617 rv = devid_str_decode(querydev, &curdevid, NULL); 618 if (rv == -1) { 619 logmsg(MSG_INFO, "Unable to decode devid %s\n", 620 key); 621 continue; 622 } 623 tempguid = devid_to_guid(curdevid); 624 if (tempguid != NULL) 625 (void) printf("/dev/rdsk/%s\t%s\n", 626 diskpath, tempguid); 627 628 devid_free_guid(tempguid); 629 devid_free(curdevid); 630 continue; 631 } 632 633 (void) printf("/dev/rdsk/%s\t/dev/rdsk/%s\n", 634 (strstr(key, diskpath) == NULL) ? key : diskpath, 635 livepath); 636 } 637 } 638 639 /* 640 * We get passed a device name which we search the mapnvl for. If we find 641 * it, we print the mapping as it is found. It is up to the caller of this 642 * utility to do any pretty-printing of the results. If a device listed on 643 * the command line does not exist in the mapnvl, then we print NOT_MAPPED. 644 * Otherwise we print the command-line device name as it maps to what is 645 * stashed in the mapnvl - even if that's a "no change" device mapping. 646 * 647 * Example output (-p maps to physpath=BOOT) 648 * # /lib/mpxio/stmsboot_util -p \ 649 * /pci@0,0/pci1022,7450@2/pci1000,3060@3/sd@1,0:a 650 * /scsi_vhci/disk@g500000e011e17720:a 651 * 652 * Or the reverse: 653 * # /lib/mpxio/stmsboot_util -p /scsi_vhci/disk@g500000e011e17720:a 654 * /pci@0,0/pci1022,7450@2/pci1000,3060@3/sd@1,0:a 655 * 656 * For the -m option, used when we're trying to find the root device mapping: 657 * 658 * # /lib/mpxio/stmsboot_util -m /dev/dsk/c2t0d0s2 659 * /dev/dsk/c3t500000E011637CF0d0s2 660 */ 661 static void 662 report_map(char *argdev, int physpath) 663 { 664 nvlist_t *thisdev; 665 int rv = 0; 666 char *thisdevid; 667 char *mpxpath = NULL; 668 char *prefixt = NULL; 669 char *prefixp = NULL; 670 char *stripdev = NULL; 671 char *slice = NULL; 672 boolean_t mpxenp; 673 uint_t slicelen = 0; 674 675 mpxenp = B_FALSE; 676 677 if ((prefixt = calloc(1, strlen(argdev) + 1)) == NULL) { 678 logmsg(MSG_INFO, "Unable to allocate memory\n"); 679 (void) printf("NOT_MAPPED\n"); 680 return; 681 } 682 683 (void) strlcpy(prefixt, argdev, strlen(argdev) + 1); 684 685 slice = strrchr(argdev, (physpath == NONBOOT) ? 's' : ':'); 686 if (slice != NULL) { 687 slicelen = strlen(slice); 688 if (slicelen > 3) 689 /* invalid size - max is 3 chars */ 690 slicelen = 0; 691 } 692 693 if ((stripdev = calloc(1, strlen(prefixt) + 1)) == NULL) { 694 logmsg(MSG_INFO, "Unable to allocate memory\n"); 695 (void) printf("NOT_MAPPED\n"); 696 free(prefixt); 697 return; 698 } 699 700 if ((strstr(prefixt, "/scsi_vhci") == NULL) && 701 (strstr(prefixt, "/pci") == NULL) && 702 (strstr(prefixt, "/sbus") == NULL)) { 703 prefixp = strrchr(prefixt, '/'); 704 (void) strlcpy(stripdev, 705 (prefixp == NULL) ? prefixt : prefixp + 1, 706 (prefixp == NULL) ? 707 strlen(prefixt) + 1: strlen(prefixp) + 1); 708 if (prefixp != NULL) 709 prefixt[strlen(argdev) - strlen(prefixp) + 1] = '\0'; 710 } else { 711 if ((physpath != BOOT) && 712 (physpath != BOOT_PATH)) { 713 logmsg(MSG_INFO, "Invalid device path provided\n"); 714 (void) printf("NOT_MAPPED\n"); 715 free(stripdev); 716 free(prefixt); 717 return; 718 } 719 (void) strlcpy(stripdev, argdev, strlen(argdev) + 1); 720 } 721 722 logmsg(MSG_INFO, 723 "stripdev (%s), prefixt(%s), prefixp(%s), slice(%s)\n", 724 (stripdev == NULL) ? "null" : stripdev, 725 (prefixt == NULL) ? "null" : prefixt, 726 (prefixp == NULL) ? "null" : prefixp, 727 (slice == NULL) ? "null" : slice); 728 729 if (slicelen > 0) 730 stripdev[strlen(stripdev) - slicelen] = '\0'; 731 732 /* search for the shortened version */ 733 rv = nvlist_lookup_string(mapnvl, stripdev, &thisdevid); 734 if (rv) { 735 if ((physpath != BOOT) && 736 (physpath != BOOT_PATH)) { 737 logmsg(MSG_INFO, 738 "searched mapnvl for '%s', got %s (%d)\n", 739 stripdev, strerror(rv), rv); 740 (void) printf("NOT_MAPPED\n"); 741 free(stripdev); 742 free(prefixt); 743 return; 744 } 745 } 746 747 logmsg(MSG_INFO, "device %s has devid %s\n", stripdev, thisdevid); 748 749 if (nvlist_lookup_nvlist(mapnvl, thisdevid, &thisdev) != 0) { 750 logmsg(MSG_INFO, "device (%s) in mapnvl but " 751 "not mapped!\n", thisdevid); 752 (void) printf("NOT_MAPPED\n"); 753 free(stripdev); 754 free(prefixt); 755 return; 756 } 757 758 /* quick exit */ 759 if (!mpxenabled && (strstr(argdev, "/pci") != NULL || 760 strstr(argdev, "/sbus") != NULL)) { 761 (void) printf("%s\n", argdev); 762 free(stripdev); 763 free(prefixt); 764 return; 765 } 766 767 (void) nvlist_lookup_boolean_value(thisdev, NVL_MPXEN, &mpxenp); 768 769 if (physpath == BOOT) { 770 (void) nvlist_lookup_string(thisdev, NVL_PHYSPATH, &mpxpath); 771 if ((strstr(argdev, "/scsi_vhci") != NULL) && 772 (strncmp(argdev, mpxpath, strlen(mpxpath)) == 0)) { 773 /* Need to translate vhci to phci */ 774 vhci_to_phci(stripdev, slice, DISPLAY_ONE_PATH); 775 } else { 776 (void) printf("%s%s\n", mpxpath, 777 ((slicelen > 0) && slice != NULL) ? slice : ""); 778 } 779 } else if (physpath == BOOT_PATH) { 780 (void) nvlist_lookup_string(thisdev, NVL_PHYSPATH, &mpxpath); 781 if ((strstr(argdev, "/scsi_vhci") != NULL) && 782 (strncmp(argdev, mpxpath, strlen(mpxpath)) == 0)) { 783 /* Need to translate vhci to phci */ 784 vhci_to_phci(stripdev, slice, DISPLAY_ALL_PATH); 785 } else { 786 (void) printf("%s%s\n", mpxpath, 787 ((slicelen > 0) && slice != NULL) ? slice : ""); 788 } 789 } else { 790 (void) nvlist_lookup_string(thisdev, 791 ((readonlyroot) ? NVL_PHYSPATH : 792 ((mpxenp == B_TRUE) ? NVL_MPXPATH : NVL_PATH)), 793 &mpxpath); 794 logmsg(MSG_INFO, "mpxpath = %s\n", 795 (mpxpath == NULL) ? "null" : mpxpath); 796 if (readonlyroot || 797 (strstr(mpxpath, "/scsi_vhci") != NULL) || 798 (strstr(mpxpath, "/pci") != NULL) || 799 (strstr(mpxpath, "/sbus") != NULL)) { 800 /* 801 * If we see a physical path here it means that 802 * devlinks aren't fully initialised yet, so we 803 * are still in maintenance/single-user mode. 804 */ 805 (void) printf("/devices%s:%c\n", mpxpath, 806 slice[1] + '1'); 807 } else { 808 (void) printf("%s%s%s\n", 809 (prefixt[0] == '/') ? prefixt : "", 810 mpxpath, 811 ((slicelen > 0) && slice != NULL) ? slice : ""); 812 } 813 } 814 free(prefixt); 815 free(stripdev); 816 } 817 818 /* 819 * Validate the in-kernel and on-disk forms of our devid cache, 820 * returns -1 for unfixable error and 0 for success. 821 */ 822 static int 823 validate_devnvl() 824 { 825 di_node_t curnode; 826 int rv1 = -1; 827 int rv2 = -1; 828 829 /* 830 * Method: we walk through the kernel's concept of the device tree 831 * looking for "ssd" then "sd" nodes. 832 * We check to see whether the device's devid is already in our nvlist 833 * (on disk) nvlist cache file. If it is, we check that it's components 834 * match what we've got already and fill any missing fields. 835 * If the devid isn't in our on-disk nvlist already then we add it 836 * and populate the property nvpairs. 837 * 838 * At the end of this function we should have this program's concept 839 * of the devid-keyed nvlist matching what is in the ondisk form which 840 * is ready to be written out. 841 * If we can't do this, then we return -1. 842 */ 843 curnode = di_drv_first_node("ssd", devinfo_root); 844 if (curnode != DI_NODE_NIL) 845 rv1 = mpxio_nvl_boilerplate(curnode); 846 847 curnode = di_drv_first_node("sd", devinfo_root); 848 if (curnode != DI_NODE_NIL) 849 rv2 = mpxio_nvl_boilerplate(curnode); 850 851 if (rv1 + rv2 == -2) 852 return (-1); 853 854 return (0); 855 } 856 857 /* 858 * According to devfs path name, it will print device node name. 859 */ 860 static void 861 print_node_name(char *drv_name, char *strdevfspath) 862 { 863 di_node_t curnode; 864 char *devfspath = NULL; 865 char *node_name = NULL; 866 867 curnode = di_drv_first_node(drv_name, devinfo_root); 868 for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { 869 devfspath = di_devfs_path(curnode); 870 logmsg(MSG_INFO, "find: devfspath %s\n", devfspath); 871 872 if (devfspath == NULL) 873 continue; 874 875 if (strncmp(strdevfspath, devfspath, 876 strlen(strdevfspath)) == 0) { 877 node_name = find_link(curnode); 878 if (node_name == NULL) { 879 (void) printf("NOT MAPPED\n"); 880 } else { 881 (void) printf("%s\n", node_name); 882 } 883 return; 884 } 885 } 886 } 887 888 /* 889 * report device node name, search "ssd" and "sd" nodes, 890 * print the device node name which device path is same as 891 * parameter. 892 */ 893 static void 894 report_dev_node_name(char *strdevfspath) 895 { 896 logmsg(MSG_INFO, "strdevfspath: %s\n", strdevfspath); 897 print_node_name("ssd", strdevfspath); 898 print_node_name("sd", strdevfspath); 899 } 900 901 static int 902 mpxio_nvl_boilerplate(di_node_t curnode) 903 { 904 int rv; 905 char *strdevid; 906 ddi_devid_t curdevid; 907 nvlist_t *newnvl; 908 909 for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { 910 errno = 0; 911 912 curdevid = NULL; 913 get_devid(curnode, &curdevid); 914 if (curdevid == NULL) 915 /* 916 * There's no devid registered for this device 917 * so it's not cool enough to play with us 918 */ 919 continue; 920 921 strdevid = devid_str_encode(curdevid, NULL); 922 /* does this exist in the on-disk cache? */ 923 rv = nvlist_lookup_nvlist(mapnvl, strdevid, &newnvl); 924 if (rv == ENOENT) { 925 logmsg(MSG_INFO, "nvlist for %s not found\n", strdevid); 926 /* no, so alloc a new nvl to store it */ 927 if (nvlist_alloc(&newnvl, NV_UNIQUE_NAME, 0) != 0) { 928 logmsg(MSG_ERROR, 929 gettext("Unable to allocate space for " 930 "a devid property list: %s\n"), 931 strerror(errno)); 932 return (-1); 933 } 934 } else { 935 if ((rv != ENOTSUP) && (rv != EINVAL)) 936 logmsg(MSG_INFO, 937 "%s exists in ondisknvl, verifying\n", 938 strdevid); 939 } 940 941 if (popcheck_devnvl(curnode, newnvl, strdevid) != 0) { 942 logmsg(MSG_ERROR, 943 gettext("Unable to populate devid nvpair " 944 "for device with devid %s\n"), 945 strdevid); 946 devid_str_free(strdevid); 947 nvlist_free(newnvl); 948 return (-1); 949 } 950 951 /* Now add newnvl into our cache. */ 952 errno = 0; 953 rv = nvlist_add_nvlist(mapnvl, strdevid, newnvl); 954 if (rv) { 955 logmsg(MSG_ERROR, 956 gettext("Unable to add device (devid %s) " 957 "to in-kernel nvl: %s (%d)\n"), 958 strdevid, strerror(rv), rv); 959 devid_str_free(strdevid); 960 nvlist_free(newnvl); 961 return (-1); 962 } 963 logmsg(MSG_INFO, 964 gettext("added device (devid %s) to mapnvl\n\n"), 965 strdevid); 966 devid_str_free(strdevid); 967 } 968 return (0); 969 } 970 971 /* 972 * Operates on a single di_node_t, collecting all the device properties 973 * that we need. devnvl is allocated by the caller, and we add our nvpairs 974 * to it if they don't already exist. 975 * 976 * We are _only_ interested in devices which have a devid. We pull in 977 * devices even when they're excluded via stmsboot -D (driver), because 978 * we don't want to miss out on any devid data that might be handy later. 979 */ 980 static int 981 popcheck_devnvl(di_node_t thisnode, nvlist_t *devnvl, char *strdevid) 982 { 983 char *path = NULL; 984 char *curpath = NULL; 985 char *devfspath = NULL; 986 char *prop = NULL; 987 int scsivhciparent = 0; 988 int rv = 0; 989 boolean_t mpxenp = B_FALSE; 990 991 errno = 0; 992 devfspath = di_devfs_path(thisnode); 993 if (devfspath == NULL) { 994 logmsg(MSG_ERROR, 995 gettext("Unable to determine devfs path for node: %s\n"), 996 strerror(errno)); 997 return (-1); 998 } 999 1000 /* Add a convenient devfspath to devid inverse map */ 1001 if (nvlist_add_string(mapnvl, devfspath, strdevid) != 0) { 1002 logmsg(MSG_ERROR, 1003 gettext("Unable to add device path %s with devid " 1004 "%s to mapnvl\n"), devfspath, strdevid); 1005 return (-1); 1006 } 1007 if (di_prop_lookup_strings(DDI_DEV_T_ANY, di_parent_node(thisnode), 1008 "mpxio-disable", &prop) >= 0) { 1009 if (strncmp(prop, "yes", 3) == 0) { 1010 if (!mpxprop) 1011 mpxprop++; 1012 } 1013 } 1014 1015 if (strncmp(di_driver_name(di_parent_node(thisnode)), 1016 "scsi_vhci", 9) == 0) { 1017 scsivhciparent = 1; 1018 if (!mpxenabled) 1019 mpxenabled++; 1020 1021 rv = nvlist_lookup_boolean_value(devnvl, NVL_MPXEN, &mpxenp); 1022 if (rv || (mpxenp == B_FALSE)) { 1023 rv = nvlist_add_boolean_value(devnvl, 1024 NVL_MPXEN, B_TRUE); 1025 if (rv) { 1026 logmsg(MSG_ERROR, 1027 gettext("Unable to add property %s " 1028 "(set to B_TRUE) for device %s: " 1029 "%s (%d)\n"), 1030 NVL_MPXEN, devfspath, 1031 strerror(rv), rv); 1032 return (-1); 1033 } 1034 logmsg(MSG_INFO, "NVL_MPXEN :: (B_FALSE->B_TRUE)\n"); 1035 } 1036 } else { 1037 /* turn _off_ the flag if it was enabled */ 1038 rv = nvlist_add_boolean_value(devnvl, NVL_MPXEN, B_FALSE); 1039 if (rv) { 1040 logmsg(MSG_ERROR, 1041 gettext("Unable to add property %s " 1042 "(set to B_FALSE) for device %s: %s (%d)\n"), 1043 NVL_MPXEN, devfspath, 1044 strerror(rv), rv); 1045 return (-1); 1046 } 1047 logmsg(MSG_INFO, "NVL_MPXEN :: (B_TRUE-> B_FALSE)\n"); 1048 } 1049 1050 rv = nvlist_add_string(devnvl, NVL_PHYSPATH, devfspath); 1051 if (rv) { 1052 logmsg(MSG_ERROR, 1053 gettext("Unable to add physical device path (%s) " 1054 "property to nvl\n")); 1055 return (-1); 1056 } 1057 1058 if ((curpath = calloc(1, MAXPATHLEN)) == NULL) { 1059 logmsg(MSG_ERROR, 1060 gettext("Unable to allocate space for current path\n")); 1061 return (-1); 1062 } 1063 curpath = find_link(thisnode); 1064 if (curpath == NULL) { 1065 if (readonlyroot) { 1066 return (0); 1067 } 1068 logmsg(MSG_ERROR, 1069 gettext("Unable to determine device path for node %s\n"), 1070 devfspath); 1071 return (-1); 1072 } 1073 1074 rv = nvlist_lookup_string(devnvl, NVL_MPXPATH, &path); 1075 1076 if (scsivhciparent) { 1077 (void) nvlist_add_string(devnvl, NVL_MPXPATH, curpath); 1078 } else { 1079 (void) nvlist_add_string(devnvl, NVL_PATH, curpath); 1080 path = curpath; 1081 } 1082 1083 /* 1084 * This next block provides the path to devid inverse mapping 1085 * that other functions require 1086 */ 1087 if (path != NULL) { 1088 if (nvlist_add_string(mapnvl, path, strdevid) != 0) { 1089 logmsg(MSG_ERROR, 1090 gettext("Unable to add device %s with devid " 1091 "%s to mapnvl\n"), path, strdevid); 1092 return (-1); 1093 } 1094 logmsg(MSG_INFO, "popcheck_devnvl: added path %s :: %s\n", 1095 path, strdevid); 1096 } 1097 1098 if (nvlist_add_string(mapnvl, curpath, strdevid) != 0) { 1099 logmsg(MSG_ERROR, 1100 gettext("Unable to add device %s with devid " 1101 "%s to mapnvl: %s\n"), 1102 curpath, strdevid, strerror(errno)); 1103 return (-1); 1104 } 1105 logmsg(MSG_INFO, "popcheck_devnvl: added curpath %s :: %s\n", 1106 curpath, strdevid); 1107 1108 return (0); 1109 } 1110 1111 static void 1112 print_mpx_capable(di_node_t curnode) 1113 { 1114 char *prop; 1115 char *path; 1116 char *aliases = NULL; 1117 1118 if (cap_N_option) { 1119 aliases = calloc(1, MAXPATHLEN + 1); 1120 if (aliases == NULL) { 1121 logmsg(MSG_ERROR, 1122 gettext("Unable to allocate memory for a device " 1123 "alias list\n")); 1124 return; 1125 } 1126 } 1127 1128 for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { 1129 if (di_prop_lookup_strings(DDI_DEV_T_ANY, curnode, 1130 "initiator-port", &prop) >= 0) { 1131 if ((path = di_devfs_path(curnode)) == NULL) { 1132 logmsg(MSG_INFO, 1133 "Unable to find devfs path for device " 1134 "%s: %s\n", &curnode, strerror(errno)); 1135 continue; 1136 } 1137 if (cap_N_option) { 1138 char *nodename = di_node_name(curnode); 1139 /* nodename is never going to be null */ 1140 if (strstr(aliases, nodename) == NULL) 1141 /* haven't seen this nodename before */ 1142 (void) snprintf(aliases, 1143 MAXPATHLEN + 1, "%s|%s", 1144 ((aliases != NULL) ? aliases : ""), 1145 nodename); 1146 } else 1147 (void) printf("%s\n", path); 1148 } 1149 } 1150 if (cap_N_option) 1151 (void) printf("%s\n", aliases); 1152 } 1153 1154 static int 1155 link_cb(di_devlink_t devlink, void *arg) 1156 { 1157 const char *result; 1158 1159 result = di_devlink_path(devlink); 1160 if (result == NULL) { 1161 arg = (void *)"(null)"; 1162 } else { 1163 (void) strlcpy(arg, result, strlen(result)); 1164 } 1165 logmsg(MSG_INFO, "\nlink_cb::linkdata->resultstr = %s\n", 1166 ((result != NULL) ? result : "(null)")); 1167 return (DI_WALK_CONTINUE); 1168 } 1169 1170 static char * 1171 find_link(di_node_t cnode) 1172 { 1173 di_minor_t devminor = DI_MINOR_NIL; 1174 di_devlink_handle_t hdl; 1175 char *devfspath = NULL; 1176 char *minorpath = NULL; 1177 char *linkname = NULL; 1178 char *cbresult = NULL; 1179 1180 devfspath = di_devfs_path(cnode); 1181 if (cnode == DI_NODE_NIL) { 1182 logmsg(MSG_ERROR, 1183 gettext("find_ctrl must be called with non-null " 1184 "di_node_t\n")); 1185 return (NULL); 1186 } 1187 logmsg(MSG_INFO, "find_link: devfspath %s\n", devfspath); 1188 1189 if (((cbresult = calloc(1, MAXPATHLEN)) == NULL) || 1190 ((minorpath = calloc(1, MAXPATHLEN)) == NULL) || 1191 ((linkname = calloc(1, MAXPATHLEN)) == NULL)) { 1192 logmsg(MSG_ERROR, "unable to allocate space for dev link\n"); 1193 return (NULL); 1194 } 1195 1196 devminor = di_minor_next(cnode, devminor); 1197 hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK); 1198 if (hdl == NULL) { 1199 logmsg((readonlyroot ? MSG_INFO : MSG_ERROR), 1200 gettext("unable to take devlink snapshot: %s\n"), 1201 strerror(errno)); 1202 return (NULL); 1203 } 1204 1205 linkname = "^dsk/"; 1206 (void) snprintf(minorpath, MAXPATHLEN, "%s:c", devfspath); 1207 1208 errno = 0; 1209 if (di_devlink_walk(hdl, linkname, minorpath, DI_PRIMARY_LINK, 1210 (void *)cbresult, link_cb) < 0) { 1211 logmsg(MSG_ERROR, 1212 gettext("Unable to walk devlink snapshot for %s: %s\n"), 1213 minorpath, strerror(errno)); 1214 return (NULL); 1215 } 1216 1217 if (di_devlink_fini(&hdl) < 0) { 1218 logmsg(MSG_ERROR, 1219 gettext("Unable to close devlink snapshot: %s\n"), 1220 strerror(errno)); 1221 } 1222 if (strstr(cbresult, "dsk/") == NULL) 1223 return (devfspath); 1224 1225 bzero(minorpath, MAXPATHLEN); 1226 /* strip off the trailing "s2" */ 1227 bcopy(cbresult, minorpath, strlen(cbresult) - 1); 1228 /* Now strip off the /dev/dsk/ prefix for output flexibility */ 1229 linkname = strrchr(minorpath, '/'); 1230 return (++linkname); 1231 } 1232 1233 /* 1234 * handle case where device has been probed but its target driver is not 1235 * attached so enumeration has not quite finished. Opening the /devices 1236 * pathname will force the kernel to finish the enumeration process and 1237 * let us get the data we need. 1238 */ 1239 static void 1240 get_devid(di_node_t node, ddi_devid_t *thisdevid) 1241 { 1242 int fd; 1243 char realpath[MAXPATHLEN]; 1244 char *openpath = di_devfs_path(node); 1245 1246 errno = 0; 1247 bzero(realpath, MAXPATHLEN); 1248 if (strstr(openpath, "/devices") == NULL) { 1249 (void) snprintf(realpath, MAXPATHLEN, 1250 "/devices%s:c,raw", openpath); 1251 fd = open(realpath, O_RDONLY|O_NDELAY); 1252 } else { 1253 fd = open(openpath, O_RDONLY|O_NDELAY); 1254 } 1255 1256 if (fd < 0) { 1257 logmsg(MSG_INFO, "Unable to open path %s: %s\n", 1258 openpath, strerror(errno)); 1259 return; 1260 } 1261 1262 if (devid_get(fd, thisdevid) != 0) { 1263 logmsg(MSG_INFO, 1264 "'%s' node (%s) without a devid registered\n", 1265 di_driver_name(node), di_devfs_path(node)); 1266 } 1267 (void) close(fd); 1268 } 1269 1270 static int 1271 print_bootpath() 1272 { 1273 char *bootprop = NULL; 1274 1275 if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root, 1276 "bootpath", &bootprop) >= 0) { 1277 (void) printf("%s\n", bootprop); 1278 return (0); 1279 } else if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root, 1280 "boot-path", &bootprop) >= 0) { 1281 (void) printf("%s\n", bootprop); 1282 return (0); 1283 } else { 1284 (void) printf("ERROR: no bootpath/boot-path property found\n"); 1285 return (ENOENT); 1286 } 1287 } 1288 1289 static void 1290 get_phci_driver_name(char *phci_path, char **driver_name) 1291 { 1292 di_node_t phci_node = DI_NODE_NIL; 1293 char *tmp = NULL; 1294 1295 phci_node = di_init(phci_path, DINFOCPYONE); 1296 if (phci_node == DI_NODE_NIL) { 1297 logmsg(MSG_ERROR, 1298 gettext("Unable to take phci snapshot " 1299 "(%s: %d)\n"), strerror(errno), errno); 1300 return; 1301 } 1302 tmp = di_driver_name(phci_node); 1303 if (tmp != NULL) { 1304 (void) strncpy(*driver_name, tmp, 10); 1305 } 1306 di_fini(phci_node); 1307 } 1308 1309 /* 1310 * We only call this routine if we have a scsi_vhci node and must 1311 * determine the actual physical path of its first online client 1312 * path. 1313 */ 1314 static void 1315 vhci_to_phci(char *devpath, char *slice, int d_flag) 1316 { 1317 sv_iocdata_t ioc; 1318 sv_path_info_t *pi; 1319 int vhci_fd; 1320 int rv; 1321 uint_t npaths = 0; 1322 char nodename[MAXPATHLEN]; 1323 char *phci_driver = NULL; 1324 1325 vhci_fd = open(VHCI_CTL_NODE, O_RDWR); 1326 if (vhci_fd < 0) 1327 goto failure; 1328 1329 bzero(&ioc, sizeof (sv_iocdata_t)); 1330 ioc.client = devpath; 1331 ioc.ret_elem = &npaths; 1332 rv = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc); 1333 if (rv || npaths == 0) { 1334 logmsg(MSG_INFO, 1335 "SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO ioctl() failed, " 1336 "%s (%d)\n", strerror(rv), rv); 1337 goto failure; 1338 } 1339 1340 bzero(&ioc, sizeof (sv_iocdata_t)); 1341 ioc.client = devpath; 1342 ioc.buf_elem = npaths; 1343 ioc.ret_elem = &npaths; 1344 if ((ioc.ret_buf = calloc(npaths, sizeof (sv_path_info_t))) 1345 == NULL) 1346 goto failure; 1347 rv = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc); 1348 if (rv || npaths == 0) { 1349 logmsg(MSG_INFO, 1350 "SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO ioctl() (#2) " 1351 "failed, %s (%d)\n", strerror(rv), rv); 1352 free(ioc.ret_buf); 1353 goto failure; 1354 } 1355 1356 if (ioc.buf_elem < npaths) 1357 npaths = ioc.buf_elem; 1358 1359 phci_driver = malloc(10); 1360 if (phci_driver == NULL) { 1361 logmsg(MSG_INFO, 1362 "vhci_to_phci: Memory allocation failed\n"); 1363 free(ioc.ret_buf); 1364 goto failure; 1365 } 1366 1367 pi = (sv_path_info_t *)ioc.ret_buf; 1368 while (npaths--) { 1369 if (pi->ret_state == MDI_PATHINFO_STATE_ONLINE) { 1370 1371 bzero(nodename, MAXPATHLEN); 1372 bzero(phci_driver, 10); 1373 1374 get_phci_driver_name(pi->device.ret_phci, 1375 &phci_driver); 1376 logmsg(MSG_INFO, "phci driver name: %s\n", phci_driver); 1377 /* 1378 * A hack, but nicer than a platform-specific ifdef 1379 * fp on SPARC using "ssd" as nodename 1380 * mpt use "sd" when mpxio disabled, use "disk" when 1381 * mpxio is enabled 1382 * for alll other cases, "disk" should be used as the 1383 * nodename 1384 */ 1385 if (strstr(devpath, "ssd") != NULL) { 1386 (void) snprintf(nodename, 5, "ssd"); 1387 } else if (strncmp(phci_driver, "mpt", 10) == 0) { 1388 (void) snprintf(nodename, 5, "sd"); 1389 } else { 1390 (void) snprintf(nodename, 5, "disk"); 1391 } 1392 if (d_flag == DISPLAY_ONE_PATH) { 1393 (void) printf("%s/%s@%s", pi->device.ret_phci, 1394 nodename, pi->ret_addr); 1395 if ((slice != NULL) && (strlen(slice) <= 3)) { 1396 (void) printf("%s\n", slice); 1397 } else { 1398 (void) printf("\n"); 1399 } 1400 break; 1401 } else if (d_flag == DISPLAY_ALL_PATH) { 1402 (void) printf("%s/%s@%s", pi->device.ret_phci, 1403 nodename, pi->ret_addr); 1404 if ((slice != NULL) && (strlen(slice) <= 3)) { 1405 (void) printf("%s\n", slice); 1406 } else { 1407 (void) printf("\n"); 1408 } 1409 } 1410 } 1411 pi++; 1412 } 1413 free(ioc.ret_buf); 1414 free(phci_driver); 1415 return; 1416 1417 failure: 1418 (void) printf("NOT_MAPPED\n"); 1419 } 1420 1421 /* 1422 * Write /etc/vfstab to /etc/vfstab.new, with any remapped device 1423 * names substituted. 1424 * 1425 * Returns: 1426 * 0 successful operation 1427 * -1 failed 1428 */ 1429 static int 1430 update_vfstab() 1431 { 1432 FILE *fdin, *fdout; 1433 char *buf, *tmpbuf; 1434 char fname[MAXPATHLEN]; 1435 int rv = -1, rval = -1; 1436 char cdev[MAXPATHLEN]; 1437 char bdev[MAXPATHLEN]; 1438 char mntpt[MAXPATHLEN]; 1439 char fstype[512]; 1440 char fsckpass[512]; 1441 char mntboot[512]; 1442 char mntopt[MAXPATHLEN]; 1443 char fmt[80]; 1444 char *prefixt = NULL; 1445 char *curdev = NULL; 1446 char *thisdevid = NULL; 1447 char *slice = NULL; 1448 nvlist_t *thisdev; 1449 boolean_t devmpx = B_FALSE; 1450 1451 buf = calloc(1, MAXPATHLEN); 1452 tmpbuf = calloc(1, MAXPATHLEN); 1453 if (buf == NULL || tmpbuf == NULL) 1454 return (-1); 1455 1456 (void) snprintf(fname, MAXPATHLEN, "/etc/mpxio/vfstab.new"); 1457 1458 fdin = fopen("/etc/vfstab", "r"); 1459 fdout = fopen(fname, "w+"); 1460 if (fdin == NULL || fdout == NULL) { 1461 logmsg(MSG_INFO, "Unable to open vfstab or create a backup " 1462 "vfstab %s\n"); 1463 return (-1); 1464 } 1465 1466 (void) snprintf(fmt, sizeof (fmt), 1467 "%%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds", sizeof (bdev) - 1, 1468 sizeof (cdev) - 1, sizeof (mntpt) - 1, sizeof (fstype) - 1, 1469 sizeof (fsckpass) - 1, sizeof (mntboot) - 1, sizeof (mntopt) - 1); 1470 1471 while (fgets(buf, MAXPATHLEN, fdin) != NULL) { 1472 if (strlen(buf) == (MAXPATHLEN - 1) && 1473 buf[MAXPATHLEN-2] != '\n') { 1474 logmsg(MSG_ERROR, 1475 gettext("/etc/vfstab line length too long, " 1476 "exceeded %2$d: \"%3$s\"\n"), 1477 MAXPATHLEN - 2, buf); 1478 goto out; 1479 } 1480 1481 prefixt = NULL; 1482 curdev = NULL; 1483 slice = NULL; 1484 thisdevid = NULL; 1485 thisdev = NULL; 1486 1487 /* LINTED - variable format specifier */ 1488 rv = sscanf(buf, fmt, bdev, cdev, mntpt, fstype, fsckpass, 1489 mntboot, mntopt); 1490 1491 /* 1492 * Walk through the lines in the input file (/etc/vfstab), 1493 * skipping anything which is _not_ a COGD (common or garden 1494 * disk), ie all the /devices, /system, /dev/md, /dev/vx and 1495 * /dev/zvol and so forth. 1496 */ 1497 if ((rv == 7) && (bdev[0] == '/') && 1498 (strstr(bdev, "/dev/dsk"))) { 1499 slice = strrchr(bdev, 's'); 1500 /* take a copy, strip off /dev/dsk/ */ 1501 prefixt = strrchr(bdev, 'c'); 1502 prefixt[strlen(bdev) - 9 - strlen(slice)] = '\0'; 1503 slice++; /* advance past the s */ 1504 rval = nvlist_lookup_string(mapnvl, prefixt, 1505 &thisdevid); 1506 if (rval) { 1507 /* Whoa, where did this device go?! */ 1508 logmsg(MSG_INFO, 1509 "error looking up device %s\n", prefixt); 1510 /* Comment-out this line in the new version */ 1511 (void) snprintf(tmpbuf, MAXPATHLEN, 1512 "# DEVICE NOT FOUND %s", buf); 1513 (void) fprintf(fdout, "%s", tmpbuf); 1514 continue; 1515 } else { 1516 /* The device exists in our mapnvl */ 1517 (void) nvlist_lookup_nvlist(mapnvl, thisdevid, 1518 &thisdev); 1519 (void) nvlist_lookup_boolean_value(thisdev, 1520 NVL_MPXEN, &devmpx); 1521 (void) nvlist_lookup_string(thisdev, 1522 ((devmpx == B_TRUE) 1523 ? NVL_MPXPATH : NVL_PATH), 1524 &curdev); 1525 } 1526 } 1527 1528 if ((prefixt != NULL) && (curdev != NULL) && 1529 (rv = (strncmp(prefixt, curdev, strlen(prefixt)) != 0))) { 1530 /* Mapping change for this device */ 1531 if (strcmp(fstype, "swap") == 0) { 1532 (void) snprintf(tmpbuf, MAXPATHLEN, 1533 "/dev/dsk/%ss%s\t-\t-\tswap\t" 1534 "%s\t%s\t%s\n", 1535 curdev, slice, fsckpass, mntboot, mntopt); 1536 } else { 1537 (void) snprintf(tmpbuf, MAXPATHLEN, 1538 "/dev/dsk/%ss%s\t/dev/rdsk/%ss%s\t" 1539 "%s\t%s\t%s\t%s\t%s\n", 1540 curdev, slice, curdev, slice, 1541 mntpt, fstype, fsckpass, mntboot, mntopt); 1542 } 1543 errno = 0; 1544 (void) fprintf(fdout, "%s", tmpbuf); 1545 } else { 1546 (void) fprintf(fdout, "%s", buf); 1547 } 1548 1549 errno = 0; 1550 if (fflush(fdout) != 0) { 1551 logmsg(MSG_ERROR, 1552 gettext("fprintf failed to write to %s: %s (%d)\n"), 1553 fname, strerror(errno), errno); 1554 goto out; 1555 } 1556 } 1557 out: 1558 (void) fclose(fdin); 1559 (void) fclose(fdout); 1560 free(buf); 1561 free(tmpbuf); 1562 return (errno); 1563 } 1564