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 int 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 if (strlcpy(drvlimit, optarg, MAXMODCONFNAME) >= 413 MAXMODCONFNAME) { 414 logmsg(MSG_ERROR, 415 gettext("invalid parent driver (%s) " 416 "specified"), optarg); 417 usage(); 418 } 419 /* update this if adding support for a new driver */ 420 if (strcmp(drvlimit, "fp") != 0 && 421 strcmp(drvlimit, "mpt") != 0 && 422 strcmp(drvlimit, "mpt_sas") != 0 && 423 strcmp(drvlimit, "pmcs") != 0) { 424 logmsg(MSG_ERROR, 425 gettext("invalid parent driver (%s) " 426 "specified"), drvlimit); 427 usage(); 428 } 429 break; 430 case 'h': 431 /* Just drop out and print the usage() output */ 432 globarg = MPX_USAGE; 433 break; 434 case 'i': 435 globarg = MPX_INIT; 436 break; 437 case 'l': 438 globarg |= MPX_LIST; 439 limctrl = (int)atol(optarg); 440 if (limctrl < 0) { 441 logmsg(MSG_INFO, 442 gettext("invalid controller number " 443 "(%d), checking all controllers\n"), 444 limctrl); 445 } 446 break; 447 case 'L': 448 globarg |= MPX_LIST; 449 break; 450 case 'g': 451 guid = 1; 452 break; 453 case 'm': 454 globarg = MPX_MAP; 455 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 456 logmsg(MSG_ERROR, 457 gettext("Unable to allocate space for a " 458 "device name\n")); 459 exit(errno); 460 } 461 devicep = strdup(optarg); 462 break; 463 case 'N': 464 cap_N_option = 1; 465 globarg = MPX_CAPABLE_CTRL; 466 break; 467 case 'n': 468 globarg = MPX_CAPABLE_CTRL; 469 break; 470 case 'o': 471 globarg = MPX_GETPATH; 472 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 473 logmsg(MSG_ERROR, 474 gettext("Unable to allocate space for a " 475 "device name\n")); 476 exit(errno); 477 } 478 devicep = strdup(optarg); 479 break; 480 case 'p': 481 globarg = MPX_PHYSICAL; 482 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 483 logmsg(MSG_ERROR, 484 gettext("Unable to allocate space for a " 485 "device name\n")); 486 exit(errno); 487 } 488 devicep = strdup(optarg); 489 break; 490 case 'q': 491 globarg = MPX_DEV_PATH; 492 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 493 logmsg(MSG_ERROR, 494 gettext("Unable to allocate space for a " 495 "device name\n")); 496 exit(errno); 497 } 498 devicep = strdup(optarg); 499 break; 500 case 'u': 501 globarg = MPX_UPDATEVFSTAB; 502 break; 503 default: 504 logmsg(MSG_ERROR, 505 gettext("Invalid command line option (%c)\n"), 506 opt); 507 usage(); 508 } 509 } 510 511 if ((globarg >= MPX_USAGE) || (guid && (globarg != MPX_LIST))) 512 usage(); 513 514 if ((drvlimit != NULL) && 515 ((globarg != MPX_LIST) && 516 (globarg != MPX_CAPABLE_CTRL))) 517 usage(); 518 } 519 520 static void 521 logmsg(int level, const char *msg, ...) 522 { 523 va_list ap; 524 525 if ((level >= MSG_ERROR) || 526 ((debugflag > 0) && (level >= MSG_INFO))) { 527 (void) fprintf(stdout, "stmsboot: "); 528 va_start(ap, msg); 529 (void) vfprintf(stdout, msg, ap); 530 va_end(ap); 531 } 532 } 533 534 /* 535 * It's up to the caller to do any sorting or pretty-printing of the device 536 * mappings we report. Since we're storing the device links as just the cXtYdZ 537 * part, we'll add /dev/rdsk/ back on when we print the listing so we maintain 538 * compatibility with previous versions of this tool. There's a little bit 539 * of footwork involved to make sure that we show all the paths to a device 540 * rather than just the first one we stashed away. 541 */ 542 static void 543 list_devs(int listguids, int ctrl) 544 { 545 nvlist_t *thisdevnvl; 546 nvpair_t *pair; 547 char *diskpath, *livepath, *key, *querydev; 548 char *matchctrl = NULL; 549 char checkctrl[MAXPATHLEN]; 550 int rv; 551 552 if (!mpxenabled) { 553 if (mpxprop) { 554 logmsg(MSG_ERROR, gettext("MPXIO disabled\n")); 555 } else { 556 logmsg(MSG_ERROR, gettext("No STMS devices have " 557 "been found\n")); 558 } 559 return; 560 } 561 562 if (listguids) { 563 (void) printf(gettext("non-STMS device name\t\t\tGUID\n" 564 "------------------------------------------" 565 "------------------------\n")); 566 } else { 567 (void) printf(gettext("non-STMS device name\t\t\t" 568 "STMS device name\n" 569 "------------------------------------------" 570 "------------------------\n")); 571 } 572 573 bzero(checkctrl, MAXPATHLEN); 574 pair = NULL; 575 while ((pair = nvlist_next_nvpair(mapnvl, pair)) 576 != NULL) { 577 boolean_t livescsivhcip = B_FALSE; 578 579 if ((((rv = nvpair_value_string(pair, &querydev)) < 0) || 580 ((key = nvpair_name(pair)) == NULL)) || 581 ((strstr(key, "/pci") != NULL) || 582 (strstr(key, "/sbus") != NULL) || 583 (strstr(key, "/scsi_vhci") != NULL) || 584 (strncmp(key, "id1", 3) == 0))) { 585 logmsg(MSG_INFO, 586 "list_devs: rv = %d; (%s) is not a devlink, " 587 "continuing.\n", rv, 588 (key != NULL) ? key : "null"); 589 querydev = NULL; 590 continue; 591 } 592 593 (void) nvlist_lookup_nvlist(mapnvl, querydev, &thisdevnvl); 594 (void) nvlist_lookup_boolean_value(thisdevnvl, NVL_MPXEN, 595 &livescsivhcip); 596 (void) nvlist_lookup_string(thisdevnvl, NVL_MPXPATH, 597 &livepath); 598 599 if ((!livescsivhcip) || 600 (livescsivhcip && 601 (strncmp(key, livepath, strlen(key)) == 0))) 602 continue; 603 604 (void) nvlist_lookup_string(thisdevnvl, NVL_PATH, 605 &diskpath); 606 607 logmsg(MSG_INFO, 608 "list_devs: %s :: %s ::%s :: MPXEN (%s)\n", 609 key, diskpath, livepath, 610 ((livescsivhcip) ? "TRUE" : "FALSE")); 611 612 if (ctrl > -1) { 613 (void) sprintf(checkctrl, "c%dt", ctrl); 614 matchctrl = strstr(key, checkctrl); 615 if (matchctrl == NULL) 616 continue; 617 } 618 if (listguids != 0) { 619 char *tempguid; 620 ddi_devid_t curdevid; 621 int rv; 622 623 rv = devid_str_decode(querydev, &curdevid, NULL); 624 if (rv == -1) { 625 logmsg(MSG_INFO, "Unable to decode devid %s\n", 626 key); 627 continue; 628 } 629 tempguid = devid_to_guid(curdevid); 630 if (tempguid != NULL) 631 (void) printf("/dev/rdsk/%s\t%s\n", 632 diskpath, tempguid); 633 634 devid_free_guid(tempguid); 635 devid_free(curdevid); 636 continue; 637 } 638 639 (void) printf("/dev/rdsk/%s\t/dev/rdsk/%s\n", 640 (strstr(key, diskpath) == NULL) ? key : diskpath, 641 livepath); 642 } 643 } 644 645 /* 646 * We get passed a device name which we search the mapnvl for. If we find 647 * it, we print the mapping as it is found. It is up to the caller of this 648 * utility to do any pretty-printing of the results. If a device listed on 649 * the command line does not exist in the mapnvl, then we print NOT_MAPPED. 650 * Otherwise we print the command-line device name as it maps to what is 651 * stashed in the mapnvl - even if that's a "no change" device mapping. 652 * 653 * Example output (-p maps to physpath=BOOT) 654 * # /lib/mpxio/stmsboot_util -p \ 655 * /pci@0,0/pci1022,7450@2/pci1000,3060@3/sd@1,0:a 656 * /scsi_vhci/disk@g500000e011e17720:a 657 * 658 * Or the reverse: 659 * # /lib/mpxio/stmsboot_util -p /scsi_vhci/disk@g500000e011e17720:a 660 * /pci@0,0/pci1022,7450@2/pci1000,3060@3/sd@1,0:a 661 * 662 * For the -m option, used when we're trying to find the root device mapping: 663 * 664 * # /lib/mpxio/stmsboot_util -m /dev/dsk/c2t0d0s2 665 * /dev/dsk/c3t500000E011637CF0d0s2 666 */ 667 static void 668 report_map(char *argdev, int physpath) 669 { 670 nvlist_t *thisdev; 671 int rv = 0; 672 char *thisdevid; 673 char *mpxpath = NULL; 674 char *prefixt = NULL; 675 char *prefixp = NULL; 676 char *stripdev = NULL; 677 char *slice = NULL; 678 boolean_t mpxenp; 679 uint_t slicelen = 0; 680 681 mpxenp = B_FALSE; 682 683 if ((prefixt = calloc(1, strlen(argdev) + 1)) == NULL) { 684 logmsg(MSG_INFO, "Unable to allocate memory\n"); 685 (void) printf("NOT_MAPPED\n"); 686 return; 687 } 688 689 (void) strlcpy(prefixt, argdev, strlen(argdev) + 1); 690 691 slice = strrchr(argdev, (physpath == NONBOOT) ? 's' : ':'); 692 if (slice != NULL) { 693 slicelen = strlen(slice); 694 if (slicelen > 3) 695 /* invalid size - max is 3 chars */ 696 slicelen = 0; 697 } 698 699 if ((stripdev = calloc(1, strlen(prefixt) + 1)) == NULL) { 700 logmsg(MSG_INFO, "Unable to allocate memory\n"); 701 (void) printf("NOT_MAPPED\n"); 702 free(prefixt); 703 return; 704 } 705 706 if ((strstr(prefixt, "/scsi_vhci") == NULL) && 707 (strstr(prefixt, "/pci") == NULL) && 708 (strstr(prefixt, "/sbus") == NULL)) { 709 prefixp = strrchr(prefixt, '/'); 710 (void) strlcpy(stripdev, 711 (prefixp == NULL) ? prefixt : prefixp + 1, 712 (prefixp == NULL) ? 713 strlen(prefixt) + 1: strlen(prefixp) + 1); 714 if (prefixp != NULL) 715 prefixt[strlen(argdev) - strlen(prefixp) + 1] = '\0'; 716 } else { 717 if ((physpath != BOOT) && 718 (physpath != BOOT_PATH)) { 719 logmsg(MSG_INFO, "Invalid device path provided\n"); 720 (void) printf("NOT_MAPPED\n"); 721 free(stripdev); 722 free(prefixt); 723 return; 724 } 725 (void) strlcpy(stripdev, argdev, strlen(argdev) + 1); 726 } 727 728 logmsg(MSG_INFO, 729 "stripdev (%s), prefixt(%s), prefixp(%s), slice(%s)\n", 730 (stripdev == NULL) ? "null" : stripdev, 731 (prefixt == NULL) ? "null" : prefixt, 732 (prefixp == NULL) ? "null" : prefixp, 733 (slice == NULL) ? "null" : slice); 734 735 if (slicelen > 0) 736 stripdev[strlen(stripdev) - slicelen] = '\0'; 737 738 /* search for the shortened version */ 739 rv = nvlist_lookup_string(mapnvl, stripdev, &thisdevid); 740 if (rv) { 741 if ((physpath != BOOT) && 742 (physpath != BOOT_PATH)) { 743 logmsg(MSG_INFO, 744 "searched mapnvl for '%s', got %s (%d)\n", 745 stripdev, strerror(rv), rv); 746 (void) printf("NOT_MAPPED\n"); 747 free(stripdev); 748 free(prefixt); 749 return; 750 } 751 } 752 753 logmsg(MSG_INFO, "device %s has devid %s\n", stripdev, thisdevid); 754 755 if (nvlist_lookup_nvlist(mapnvl, thisdevid, &thisdev) != 0) { 756 logmsg(MSG_INFO, "device (%s) in mapnvl but " 757 "not mapped!\n", thisdevid); 758 (void) printf("NOT_MAPPED\n"); 759 free(stripdev); 760 free(prefixt); 761 return; 762 } 763 764 /* quick exit */ 765 if (!mpxenabled && (strstr(argdev, "/pci") != NULL || 766 strstr(argdev, "/sbus") != NULL)) { 767 (void) printf("%s\n", argdev); 768 free(stripdev); 769 free(prefixt); 770 return; 771 } 772 773 (void) nvlist_lookup_boolean_value(thisdev, NVL_MPXEN, &mpxenp); 774 775 if (physpath == BOOT) { 776 (void) nvlist_lookup_string(thisdev, NVL_PHYSPATH, &mpxpath); 777 if ((strstr(argdev, "/scsi_vhci") != NULL) && 778 (strncmp(argdev, mpxpath, strlen(mpxpath)) == 0)) { 779 /* Need to translate vhci to phci */ 780 vhci_to_phci(stripdev, slice, DISPLAY_ONE_PATH); 781 } else { 782 (void) printf("%s%s\n", mpxpath, 783 ((slicelen > 0) && slice != NULL) ? slice : ""); 784 } 785 } else if (physpath == BOOT_PATH) { 786 (void) nvlist_lookup_string(thisdev, NVL_PHYSPATH, &mpxpath); 787 if ((strstr(argdev, "/scsi_vhci") != NULL) && 788 (strncmp(argdev, mpxpath, strlen(mpxpath)) == 0)) { 789 /* Need to translate vhci to phci */ 790 vhci_to_phci(stripdev, slice, DISPLAY_ALL_PATH); 791 } else { 792 (void) printf("%s%s\n", mpxpath, 793 ((slicelen > 0) && slice != NULL) ? slice : ""); 794 } 795 } else { 796 (void) nvlist_lookup_string(thisdev, 797 ((readonlyroot) ? NVL_PHYSPATH : 798 ((mpxenp == B_TRUE) ? NVL_MPXPATH : NVL_PATH)), 799 &mpxpath); 800 logmsg(MSG_INFO, "mpxpath = %s\n", 801 (mpxpath == NULL) ? "null" : mpxpath); 802 if (readonlyroot || 803 (strstr(mpxpath, "/scsi_vhci") != NULL) || 804 (strstr(mpxpath, "/pci") != NULL) || 805 (strstr(mpxpath, "/sbus") != NULL)) { 806 /* 807 * If we see a physical path here it means that 808 * devlinks aren't fully initialised yet, so we 809 * are still in maintenance/single-user mode. 810 */ 811 (void) printf("/devices%s:%c\n", mpxpath, 812 slice[1] + '1'); 813 } else { 814 (void) printf("%s%s%s\n", 815 (prefixt[0] == '/') ? prefixt : "", 816 mpxpath, 817 ((slicelen > 0) && slice != NULL) ? slice : ""); 818 } 819 } 820 free(prefixt); 821 free(stripdev); 822 } 823 824 /* 825 * Validate the in-kernel and on-disk forms of our devid cache, 826 * returns -1 for unfixable error and 0 for success. 827 */ 828 static int 829 validate_devnvl() 830 { 831 di_node_t curnode; 832 int rv1 = -1; 833 int rv2 = -1; 834 835 /* 836 * Method: we walk through the kernel's concept of the device tree 837 * looking for "ssd" then "sd" nodes. 838 * We check to see whether the device's devid is already in our nvlist 839 * (on disk) nvlist cache file. If it is, we check that it's components 840 * match what we've got already and fill any missing fields. 841 * If the devid isn't in our on-disk nvlist already then we add it 842 * and populate the property nvpairs. 843 * 844 * At the end of this function we should have this program's concept 845 * of the devid-keyed nvlist matching what is in the ondisk form which 846 * is ready to be written out. 847 * If we can't do this, then we return -1. 848 */ 849 curnode = di_drv_first_node("ssd", devinfo_root); 850 if (curnode != DI_NODE_NIL) 851 rv1 = mpxio_nvl_boilerplate(curnode); 852 853 curnode = di_drv_first_node("sd", devinfo_root); 854 if (curnode != DI_NODE_NIL) 855 rv2 = mpxio_nvl_boilerplate(curnode); 856 857 if (rv1 + rv2 == -2) 858 return (-1); 859 860 return (0); 861 } 862 863 /* 864 * According to devfs path name, it will print device node name. 865 */ 866 static void 867 print_node_name(char *drv_name, char *strdevfspath) 868 { 869 di_node_t curnode; 870 char *devfspath = NULL; 871 char *node_name = NULL; 872 873 curnode = di_drv_first_node(drv_name, devinfo_root); 874 for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { 875 devfspath = di_devfs_path(curnode); 876 logmsg(MSG_INFO, "find: devfspath %s\n", devfspath); 877 878 if (devfspath == NULL) 879 continue; 880 881 if ((strlen(strdevfspath) == strlen(devfspath)) && 882 (strncmp(strdevfspath, devfspath, 883 strlen(devfspath)) == 0)) { 884 node_name = find_link(curnode); 885 if (node_name == NULL) { 886 (void) printf("NOT MAPPED\n"); 887 } else { 888 (void) printf("%s\n", node_name); 889 } 890 return; 891 } 892 } 893 } 894 895 /* 896 * report device node name, search "ssd" and "sd" nodes, 897 * print the device node name which device path is same as 898 * parameter. 899 */ 900 static void 901 report_dev_node_name(char *strdevfspath) 902 { 903 logmsg(MSG_INFO, "strdevfspath: %s\n", strdevfspath); 904 print_node_name("ssd", strdevfspath); 905 print_node_name("sd", strdevfspath); 906 } 907 908 static int 909 mpxio_nvl_boilerplate(di_node_t curnode) 910 { 911 int rv; 912 char *strdevid; 913 ddi_devid_t curdevid; 914 nvlist_t *newnvl; 915 916 for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { 917 errno = 0; 918 919 curdevid = NULL; 920 get_devid(curnode, &curdevid); 921 if (curdevid == NULL) 922 /* 923 * There's no devid registered for this device 924 * so it's not cool enough to play with us 925 */ 926 continue; 927 928 strdevid = devid_str_encode(curdevid, NULL); 929 /* does this exist in the on-disk cache? */ 930 rv = nvlist_lookup_nvlist(mapnvl, strdevid, &newnvl); 931 if (rv == ENOENT) { 932 logmsg(MSG_INFO, "nvlist for %s not found\n", strdevid); 933 /* no, so alloc a new nvl to store it */ 934 if (nvlist_alloc(&newnvl, NV_UNIQUE_NAME, 0) != 0) { 935 logmsg(MSG_ERROR, 936 gettext("Unable to allocate space for " 937 "a devid property list: %s\n"), 938 strerror(errno)); 939 return (-1); 940 } 941 } else { 942 if ((rv != ENOTSUP) && (rv != EINVAL)) 943 logmsg(MSG_INFO, 944 "%s exists in ondisknvl, verifying\n", 945 strdevid); 946 } 947 948 if (popcheck_devnvl(curnode, newnvl, strdevid) != 0) { 949 logmsg(MSG_ERROR, 950 gettext("Unable to populate devid nvpair " 951 "for device with devid %s\n"), 952 strdevid); 953 devid_str_free(strdevid); 954 nvlist_free(newnvl); 955 return (-1); 956 } 957 958 /* Now add newnvl into our cache. */ 959 errno = 0; 960 rv = nvlist_add_nvlist(mapnvl, strdevid, newnvl); 961 if (rv) { 962 logmsg(MSG_ERROR, 963 gettext("Unable to add device (devid %s) " 964 "to in-kernel nvl: %s (%d)\n"), 965 strdevid, strerror(rv), rv); 966 devid_str_free(strdevid); 967 nvlist_free(newnvl); 968 return (-1); 969 } 970 logmsg(MSG_INFO, 971 gettext("added device (devid %s) to mapnvl\n\n"), 972 strdevid); 973 devid_str_free(strdevid); 974 } 975 return (0); 976 } 977 978 /* 979 * Operates on a single di_node_t, collecting all the device properties 980 * that we need. devnvl is allocated by the caller, and we add our nvpairs 981 * to it if they don't already exist. 982 * 983 * We are _only_ interested in devices which have a devid. We pull in 984 * devices even when they're excluded via stmsboot -D (driver), because 985 * we don't want to miss out on any devid data that might be handy later. 986 */ 987 static int 988 popcheck_devnvl(di_node_t thisnode, nvlist_t *devnvl, char *strdevid) 989 { 990 char *path = NULL; 991 char *curpath = NULL; 992 char *devfspath = NULL; 993 char *prop = NULL; 994 int scsivhciparent = 0; 995 int rv = 0; 996 boolean_t mpxenp = B_FALSE; 997 998 errno = 0; 999 devfspath = di_devfs_path(thisnode); 1000 if (devfspath == NULL) { 1001 logmsg(MSG_ERROR, 1002 gettext("Unable to determine devfs path for node: %s\n"), 1003 strerror(errno)); 1004 return (-1); 1005 } 1006 1007 /* Add a convenient devfspath to devid inverse map */ 1008 if (nvlist_add_string(mapnvl, devfspath, strdevid) != 0) { 1009 logmsg(MSG_ERROR, 1010 gettext("Unable to add device path %s with devid " 1011 "%s to mapnvl\n"), devfspath, strdevid); 1012 return (-1); 1013 } 1014 if (di_prop_lookup_strings(DDI_DEV_T_ANY, di_parent_node(thisnode), 1015 "mpxio-disable", &prop) >= 0) { 1016 if (strncmp(prop, "yes", 3) == 0) { 1017 if (!mpxprop) 1018 mpxprop++; 1019 } 1020 } 1021 1022 if (strncmp(di_driver_name(di_parent_node(thisnode)), 1023 "scsi_vhci", 9) == 0) { 1024 scsivhciparent = 1; 1025 if (!mpxenabled) 1026 mpxenabled++; 1027 1028 rv = nvlist_lookup_boolean_value(devnvl, NVL_MPXEN, &mpxenp); 1029 if (rv || (mpxenp == B_FALSE)) { 1030 rv = nvlist_add_boolean_value(devnvl, 1031 NVL_MPXEN, B_TRUE); 1032 if (rv) { 1033 logmsg(MSG_ERROR, 1034 gettext("Unable to add property %s " 1035 "(set to B_TRUE) for device %s: " 1036 "%s (%d)\n"), 1037 NVL_MPXEN, devfspath, 1038 strerror(rv), rv); 1039 return (-1); 1040 } 1041 logmsg(MSG_INFO, "NVL_MPXEN :: (B_FALSE->B_TRUE)\n"); 1042 } 1043 } else { 1044 /* turn _off_ the flag if it was enabled */ 1045 rv = nvlist_add_boolean_value(devnvl, NVL_MPXEN, B_FALSE); 1046 if (rv) { 1047 logmsg(MSG_ERROR, 1048 gettext("Unable to add property %s " 1049 "(set to B_FALSE) for device %s: %s (%d)\n"), 1050 NVL_MPXEN, devfspath, 1051 strerror(rv), rv); 1052 return (-1); 1053 } 1054 logmsg(MSG_INFO, "NVL_MPXEN :: (B_TRUE-> B_FALSE)\n"); 1055 } 1056 1057 rv = nvlist_add_string(devnvl, NVL_PHYSPATH, devfspath); 1058 if (rv) { 1059 logmsg(MSG_ERROR, 1060 gettext("Unable to add physical device path (%s) " 1061 "property to nvl\n")); 1062 return (-1); 1063 } 1064 1065 if ((curpath = calloc(1, MAXPATHLEN)) == NULL) { 1066 logmsg(MSG_ERROR, 1067 gettext("Unable to allocate space for current path\n")); 1068 return (-1); 1069 } 1070 curpath = find_link(thisnode); 1071 if (curpath == NULL) { 1072 if (readonlyroot) { 1073 return (0); 1074 } 1075 logmsg(MSG_ERROR, 1076 gettext("Unable to determine device path for node %s\n"), 1077 devfspath); 1078 return (-1); 1079 } 1080 1081 rv = nvlist_lookup_string(devnvl, NVL_MPXPATH, &path); 1082 1083 if (scsivhciparent) { 1084 (void) nvlist_add_string(devnvl, NVL_MPXPATH, curpath); 1085 } else { 1086 (void) nvlist_add_string(devnvl, NVL_PATH, curpath); 1087 path = curpath; 1088 } 1089 1090 /* 1091 * This next block provides the path to devid inverse mapping 1092 * that other functions require 1093 */ 1094 if (path != NULL) { 1095 if (nvlist_add_string(mapnvl, path, strdevid) != 0) { 1096 logmsg(MSG_ERROR, 1097 gettext("Unable to add device %s with devid " 1098 "%s to mapnvl\n"), path, strdevid); 1099 return (-1); 1100 } 1101 logmsg(MSG_INFO, "popcheck_devnvl: added path %s :: %s\n", 1102 path, strdevid); 1103 } 1104 1105 if (nvlist_add_string(mapnvl, curpath, strdevid) != 0) { 1106 logmsg(MSG_ERROR, 1107 gettext("Unable to add device %s with devid " 1108 "%s to mapnvl: %s\n"), 1109 curpath, strdevid, strerror(errno)); 1110 return (-1); 1111 } 1112 logmsg(MSG_INFO, "popcheck_devnvl: added curpath %s :: %s\n", 1113 curpath, strdevid); 1114 1115 return (0); 1116 } 1117 1118 static void 1119 print_mpx_capable(di_node_t curnode) 1120 { 1121 char *prop; 1122 char *path; 1123 char *aliases = NULL; 1124 1125 if (cap_N_option) { 1126 aliases = calloc(1, MAXPATHLEN + 1); 1127 if (aliases == NULL) { 1128 logmsg(MSG_ERROR, 1129 gettext("Unable to allocate memory for a device " 1130 "alias list\n")); 1131 return; 1132 } 1133 } 1134 1135 for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { 1136 if (di_prop_lookup_strings(DDI_DEV_T_ANY, curnode, 1137 "initiator-port", &prop) >= 0) { 1138 if ((path = di_devfs_path(curnode)) == NULL) { 1139 logmsg(MSG_INFO, 1140 "Unable to find devfs path for device " 1141 "%s: %s\n", &curnode, strerror(errno)); 1142 continue; 1143 } 1144 if (cap_N_option) { 1145 char *nodename = di_node_name(curnode); 1146 /* nodename is never going to be null */ 1147 if (strstr(aliases, nodename) == NULL) 1148 /* haven't seen this nodename before */ 1149 (void) snprintf(aliases, 1150 MAXPATHLEN + 1, "%s|%s", 1151 ((aliases != NULL) ? aliases : ""), 1152 nodename); 1153 } else 1154 (void) printf("%s\n", path); 1155 } 1156 } 1157 if (cap_N_option) 1158 (void) printf("%s\n", aliases); 1159 } 1160 1161 static int 1162 link_cb(di_devlink_t devlink, void *arg) 1163 { 1164 const char *result; 1165 1166 result = di_devlink_path(devlink); 1167 if (result == NULL) { 1168 arg = (void *)"(null)"; 1169 } else { 1170 (void) strlcpy(arg, result, strlen(result)); 1171 } 1172 logmsg(MSG_INFO, "\nlink_cb::linkdata->resultstr = %s\n", 1173 ((result != NULL) ? result : "(null)")); 1174 return (DI_WALK_CONTINUE); 1175 } 1176 1177 static char * 1178 find_link(di_node_t cnode) 1179 { 1180 di_minor_t devminor = DI_MINOR_NIL; 1181 di_devlink_handle_t hdl; 1182 char *devfspath = NULL; 1183 char *minorpath = NULL; 1184 char *linkname = NULL; 1185 char *cbresult = NULL; 1186 1187 devfspath = di_devfs_path(cnode); 1188 if (cnode == DI_NODE_NIL) { 1189 logmsg(MSG_ERROR, 1190 gettext("find_ctrl must be called with non-null " 1191 "di_node_t\n")); 1192 return (NULL); 1193 } 1194 logmsg(MSG_INFO, "find_link: devfspath %s\n", devfspath); 1195 1196 if (((cbresult = calloc(1, MAXPATHLEN)) == NULL) || 1197 ((minorpath = calloc(1, MAXPATHLEN)) == NULL) || 1198 ((linkname = calloc(1, MAXPATHLEN)) == NULL)) { 1199 logmsg(MSG_ERROR, "unable to allocate space for dev link\n"); 1200 return (NULL); 1201 } 1202 1203 devminor = di_minor_next(cnode, devminor); 1204 hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK); 1205 if (hdl == NULL) { 1206 logmsg((readonlyroot ? MSG_INFO : MSG_ERROR), 1207 gettext("unable to take devlink snapshot: %s\n"), 1208 strerror(errno)); 1209 return (NULL); 1210 } 1211 1212 linkname = "^dsk/"; 1213 (void) snprintf(minorpath, MAXPATHLEN, "%s:c", devfspath); 1214 1215 errno = 0; 1216 if (di_devlink_walk(hdl, linkname, minorpath, DI_PRIMARY_LINK, 1217 (void *)cbresult, link_cb) < 0) { 1218 logmsg(MSG_ERROR, 1219 gettext("Unable to walk devlink snapshot for %s: %s\n"), 1220 minorpath, strerror(errno)); 1221 return (NULL); 1222 } 1223 1224 if (di_devlink_fini(&hdl) < 0) { 1225 logmsg(MSG_ERROR, 1226 gettext("Unable to close devlink snapshot: %s\n"), 1227 strerror(errno)); 1228 } 1229 if (strstr(cbresult, "dsk/") == NULL) 1230 return (devfspath); 1231 1232 bzero(minorpath, MAXPATHLEN); 1233 /* strip off the trailing "s2" */ 1234 bcopy(cbresult, minorpath, strlen(cbresult) - 1); 1235 /* Now strip off the /dev/dsk/ prefix for output flexibility */ 1236 linkname = strrchr(minorpath, '/'); 1237 return (++linkname); 1238 } 1239 1240 /* 1241 * handle case where device has been probed but its target driver is not 1242 * attached so enumeration has not quite finished. Opening the /devices 1243 * pathname will force the kernel to finish the enumeration process and 1244 * let us get the data we need. 1245 */ 1246 static void 1247 get_devid(di_node_t node, ddi_devid_t *thisdevid) 1248 { 1249 int fd; 1250 char realpath[MAXPATHLEN]; 1251 char *openpath = di_devfs_path(node); 1252 1253 errno = 0; 1254 bzero(realpath, MAXPATHLEN); 1255 if (strstr(openpath, "/devices") == NULL) { 1256 (void) snprintf(realpath, MAXPATHLEN, 1257 "/devices%s:c,raw", openpath); 1258 fd = open(realpath, O_RDONLY|O_NDELAY); 1259 } else { 1260 fd = open(openpath, O_RDONLY|O_NDELAY); 1261 } 1262 1263 if (fd < 0) { 1264 logmsg(MSG_INFO, "Unable to open path %s: %s\n", 1265 openpath, strerror(errno)); 1266 return; 1267 } 1268 1269 if (devid_get(fd, thisdevid) != 0) { 1270 logmsg(MSG_INFO, 1271 "'%s' node (%s) without a devid registered\n", 1272 di_driver_name(node), di_devfs_path(node)); 1273 } 1274 (void) close(fd); 1275 } 1276 1277 static int 1278 print_bootpath() 1279 { 1280 char *bootprop = NULL; 1281 1282 if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root, 1283 "bootpath", &bootprop) >= 0) { 1284 (void) printf("%s\n", bootprop); 1285 return (0); 1286 } else if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root, 1287 "boot-path", &bootprop) >= 0) { 1288 (void) printf("%s\n", bootprop); 1289 return (0); 1290 } else { 1291 (void) printf("ERROR: no bootpath/boot-path property found\n"); 1292 return (ENOENT); 1293 } 1294 } 1295 1296 static void 1297 get_phci_driver_name(char *phci_path, char **driver_name) 1298 { 1299 di_node_t phci_node = DI_NODE_NIL; 1300 char *tmp = NULL; 1301 1302 phci_node = di_init(phci_path, DINFOCPYONE); 1303 if (phci_node == DI_NODE_NIL) { 1304 logmsg(MSG_ERROR, 1305 gettext("Unable to take phci snapshot " 1306 "(%s: %d)\n"), strerror(errno), errno); 1307 return; 1308 } 1309 tmp = di_driver_name(phci_node); 1310 if (tmp != NULL) { 1311 (void) strncpy(*driver_name, tmp, 10); 1312 } 1313 di_fini(phci_node); 1314 } 1315 1316 /* 1317 * We only call this routine if we have a scsi_vhci node and must 1318 * determine the actual physical path of its first online client 1319 * path. 1320 */ 1321 static void 1322 vhci_to_phci(char *devpath, char *slice, int d_flag) 1323 { 1324 sv_iocdata_t ioc; 1325 sv_path_info_t *pi; 1326 int vhci_fd; 1327 int rv; 1328 uint_t npaths = 0; 1329 char nodename[MAXPATHLEN]; 1330 char *phci_driver = NULL; 1331 1332 vhci_fd = open(VHCI_CTL_NODE, O_RDWR); 1333 if (vhci_fd < 0) 1334 goto failure; 1335 1336 bzero(&ioc, sizeof (sv_iocdata_t)); 1337 ioc.client = devpath; 1338 ioc.ret_elem = &npaths; 1339 rv = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc); 1340 if (rv || npaths == 0) { 1341 logmsg(MSG_INFO, 1342 "SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO ioctl() failed, " 1343 "%s (%d)\n", strerror(rv), rv); 1344 goto failure; 1345 } 1346 1347 bzero(&ioc, sizeof (sv_iocdata_t)); 1348 ioc.client = devpath; 1349 ioc.buf_elem = npaths; 1350 ioc.ret_elem = &npaths; 1351 if ((ioc.ret_buf = calloc(npaths, sizeof (sv_path_info_t))) 1352 == NULL) 1353 goto failure; 1354 rv = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc); 1355 if (rv || npaths == 0) { 1356 logmsg(MSG_INFO, 1357 "SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO ioctl() (#2) " 1358 "failed, %s (%d)\n", strerror(rv), rv); 1359 free(ioc.ret_buf); 1360 goto failure; 1361 } 1362 1363 if (ioc.buf_elem < npaths) 1364 npaths = ioc.buf_elem; 1365 1366 phci_driver = malloc(10); 1367 if (phci_driver == NULL) { 1368 logmsg(MSG_INFO, 1369 "vhci_to_phci: Memory allocation failed\n"); 1370 free(ioc.ret_buf); 1371 goto failure; 1372 } 1373 1374 pi = (sv_path_info_t *)ioc.ret_buf; 1375 while (npaths--) { 1376 bzero(nodename, MAXPATHLEN); 1377 bzero(phci_driver, 10); 1378 1379 get_phci_driver_name(pi->device.ret_phci, 1380 &phci_driver); 1381 logmsg(MSG_INFO, "phci driver name: %s\n", phci_driver); 1382 /* 1383 * A hack, but nicer than a platform-specific ifdef 1384 * fp on SPARC using "ssd" as nodename 1385 * mpt use "sd" when mpxio disabled, use "disk" when 1386 * mpxio is enabled 1387 * for alll other cases, "disk" should be used as the 1388 * nodename 1389 */ 1390 if (strstr(devpath, "ssd") != NULL) { 1391 (void) snprintf(nodename, 5, "ssd"); 1392 } else if (strncmp(phci_driver, "mpt", 10) == 0) { 1393 (void) snprintf(nodename, 5, "sd"); 1394 } else { 1395 (void) snprintf(nodename, 5, "disk"); 1396 } 1397 if ((d_flag == DISPLAY_ONE_PATH) && 1398 (pi->ret_state == MDI_PATHINFO_STATE_ONLINE)) { 1399 (void) printf("%s/%s@%s", pi->device.ret_phci, 1400 nodename, pi->ret_addr); 1401 if ((slice != NULL) && (strlen(slice) <= 3)) { 1402 (void) printf("%s\n", slice); 1403 } else { 1404 (void) printf("\n"); 1405 } 1406 break; 1407 } else if (d_flag == DISPLAY_ALL_PATH) { 1408 (void) printf("%s/%s@%s", pi->device.ret_phci, 1409 nodename, pi->ret_addr); 1410 if ((slice != NULL) && (strlen(slice) <= 3)) { 1411 (void) printf("%s\n", slice); 1412 } else { 1413 (void) printf("\n"); 1414 } 1415 } 1416 pi++; 1417 } 1418 free(ioc.ret_buf); 1419 free(phci_driver); 1420 return; 1421 1422 failure: 1423 (void) printf("NOT_MAPPED\n"); 1424 } 1425 1426 /* 1427 * Write /etc/vfstab to /etc/vfstab.new, with any remapped device 1428 * names substituted. 1429 * 1430 * Returns: 1431 * 0 successful operation 1432 * -1 failed 1433 */ 1434 static int 1435 update_vfstab() 1436 { 1437 FILE *fdin, *fdout; 1438 char *buf, *tmpbuf; 1439 char fname[MAXPATHLEN]; 1440 int rv = -1, rval = -1; 1441 char cdev[MAXPATHLEN]; 1442 char bdev[MAXPATHLEN]; 1443 char mntpt[MAXPATHLEN]; 1444 char fstype[512]; 1445 char fsckpass[512]; 1446 char mntboot[512]; 1447 char mntopt[MAXPATHLEN]; 1448 char fmt[80]; 1449 char *prefixt = NULL; 1450 char *curdev = NULL; 1451 char *thisdevid = NULL; 1452 char *slice = NULL; 1453 nvlist_t *thisdev; 1454 boolean_t devmpx = B_FALSE; 1455 1456 buf = calloc(1, MAXPATHLEN); 1457 tmpbuf = calloc(1, MAXPATHLEN); 1458 if (buf == NULL || tmpbuf == NULL) 1459 return (-1); 1460 1461 (void) snprintf(fname, MAXPATHLEN, "/etc/mpxio/vfstab.new"); 1462 1463 fdin = fopen("/etc/vfstab", "r"); 1464 fdout = fopen(fname, "w+"); 1465 if (fdin == NULL || fdout == NULL) { 1466 logmsg(MSG_INFO, "Unable to open vfstab or create a backup " 1467 "vfstab %s\n"); 1468 return (-1); 1469 } 1470 1471 (void) snprintf(fmt, sizeof (fmt), 1472 "%%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds", sizeof (bdev) - 1, 1473 sizeof (cdev) - 1, sizeof (mntpt) - 1, sizeof (fstype) - 1, 1474 sizeof (fsckpass) - 1, sizeof (mntboot) - 1, sizeof (mntopt) - 1); 1475 1476 while (fgets(buf, MAXPATHLEN, fdin) != NULL) { 1477 if (strlen(buf) == (MAXPATHLEN - 1) && 1478 buf[MAXPATHLEN-2] != '\n') { 1479 logmsg(MSG_ERROR, 1480 gettext("/etc/vfstab line length too long, " 1481 "exceeded %2$d: \"%3$s\"\n"), 1482 MAXPATHLEN - 2, buf); 1483 goto out; 1484 } 1485 1486 prefixt = NULL; 1487 curdev = NULL; 1488 slice = NULL; 1489 thisdevid = NULL; 1490 thisdev = NULL; 1491 1492 /* LINTED - variable format specifier */ 1493 rv = sscanf(buf, fmt, bdev, cdev, mntpt, fstype, fsckpass, 1494 mntboot, mntopt); 1495 1496 /* 1497 * Walk through the lines in the input file (/etc/vfstab), 1498 * skipping anything which is _not_ a COGD (common or garden 1499 * disk), ie all the /devices, /system, /dev/md, /dev/vx and 1500 * /dev/zvol and so forth. 1501 */ 1502 if ((rv == 7) && (bdev[0] == '/') && 1503 (strstr(bdev, "/dev/dsk"))) { 1504 slice = strrchr(bdev, 's'); 1505 /* take a copy, strip off /dev/dsk/ */ 1506 prefixt = strrchr(bdev, 'c'); 1507 prefixt[strlen(bdev) - 9 - strlen(slice)] = '\0'; 1508 slice++; /* advance past the s */ 1509 rval = nvlist_lookup_string(mapnvl, prefixt, 1510 &thisdevid); 1511 if (rval) { 1512 /* Whoa, where did this device go?! */ 1513 logmsg(MSG_INFO, 1514 "error looking up device %s\n", prefixt); 1515 /* Comment-out this line in the new version */ 1516 (void) snprintf(tmpbuf, MAXPATHLEN, 1517 "# DEVICE NOT FOUND %s", buf); 1518 (void) fprintf(fdout, "%s", tmpbuf); 1519 continue; 1520 } else { 1521 /* The device exists in our mapnvl */ 1522 (void) nvlist_lookup_nvlist(mapnvl, thisdevid, 1523 &thisdev); 1524 (void) nvlist_lookup_boolean_value(thisdev, 1525 NVL_MPXEN, &devmpx); 1526 (void) nvlist_lookup_string(thisdev, 1527 ((devmpx == B_TRUE) 1528 ? NVL_MPXPATH : NVL_PATH), 1529 &curdev); 1530 } 1531 } 1532 1533 if ((prefixt != NULL) && (curdev != NULL) && 1534 (rv = (strncmp(prefixt, curdev, strlen(prefixt)) != 0))) { 1535 /* Mapping change for this device */ 1536 if (strcmp(fstype, "swap") == 0) { 1537 (void) snprintf(tmpbuf, MAXPATHLEN, 1538 "/dev/dsk/%ss%s\t-\t-\tswap\t" 1539 "%s\t%s\t%s\n", 1540 curdev, slice, fsckpass, mntboot, mntopt); 1541 } else { 1542 (void) snprintf(tmpbuf, MAXPATHLEN, 1543 "/dev/dsk/%ss%s\t/dev/rdsk/%ss%s\t" 1544 "%s\t%s\t%s\t%s\t%s\n", 1545 curdev, slice, curdev, slice, 1546 mntpt, fstype, fsckpass, mntboot, mntopt); 1547 } 1548 errno = 0; 1549 (void) fprintf(fdout, "%s", tmpbuf); 1550 } else { 1551 (void) fprintf(fdout, "%s", buf); 1552 } 1553 1554 errno = 0; 1555 if (fflush(fdout) != 0) { 1556 logmsg(MSG_ERROR, 1557 gettext("fprintf failed to write to %s: %s (%d)\n"), 1558 fname, strerror(errno), errno); 1559 goto out; 1560 } 1561 } 1562 out: 1563 (void) fclose(fdin); 1564 (void) fclose(fdout); 1565 free(buf); 1566 free(tmpbuf); 1567 return (errno); 1568 } 1569