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