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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Utility for cache configuration 29 */ 30 #include <unistd.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <strings.h> 34 #include <locale.h> 35 #include <langinfo.h> 36 #include <libintl.h> 37 #include <time.h> 38 #include <sys/nsctl/sd_bcache.h> 39 #include <sys/wait.h> 40 #include <errno.h> 41 #include <signal.h> 42 #include <sys/types.h> 43 #include <fcntl.h> 44 #include <stropts.h> 45 #include <ctype.h> 46 #include <libgen.h> 47 48 #include <sys/nsctl/sdbc_ioctl.h> 49 #include <sys/unistat/spcs_s.h> 50 #include <sys/unistat/spcs_s_u.h> 51 #include <sys/unistat/spcs_errors.h> 52 #include <nsctl.h> 53 54 #include <sys/nsctl/cfg.h> 55 #define STATS_PATH "/usr/bin/sd_stats" 56 57 #define _SD_FNAME /* bring in function names from sd_trace.h */ 58 #include <sys/nsctl/sd_trace.h> 59 #include <sys/syslog.h> 60 61 /* 62 * Since we no longer support nvram cards, the hints wrthru and nowrthru no 63 * longer serve any purpose, and the system will always be in wrthru mode. 64 * WRTHRU_HINTS, if defined still allows the setting and reporting of write 65 * hints. This is defined by default on DEBUG builds. 66 */ 67 #ifdef DEBUG 68 #define WRTHRU_HINTS 69 #endif 70 71 static int sdbc_max_devices = 0; 72 73 static char alert_file[200] = "/dev/console"; 74 75 /* Variables used to set up paramater block passed to kernel */ 76 static _sd_cache_param_t user_level_conf; 77 static int myid; 78 79 static int nodes_configured = 0; 80 static int minidsp = 0; /* Is it a sp10 */ 81 static int forced_wrthru = -1; /* 0 clear, 1 set,-1 as is */ 82 static int no_forced_wrthru = -1; 83 static short node_defined[MAX_SD_NODES]; 84 static short nodes_conf[MAX_SD_NODES]; 85 86 #define USAGELEN 1024 87 char stats_usage[USAGELEN+128]; 88 char scmadmUsage[USAGELEN]; 89 90 static caddr_t progname; 91 92 93 /* 94 * Functions exported for fwcadm. 95 */ 96 void enable_sdbc(void); 97 void disable_sdbc(void); 98 void sdbc_set_maxdev(); 99 100 static void buildusage(char *); 101 102 void print_all_options(void); 103 void get_cd_all(void); 104 int toggle_flush(void); 105 static void sd_gather_alert_dumps(); 106 static int get_cd(char *); 107 static int get_hint(char *, int *, int *); 108 static void check_and_set_mirrors(int, int); 109 static void print_hint(const uint_t, const int); 110 static char *get_device_name(char *arg); 111 static void get_version(); 112 113 extern struct tm *localtime_r(const time_t *, struct tm *); 114 115 #define PRINT_CACHE_SZ_ERR(sz) {\ 116 (void) fprintf(stderr, gettext("\n%s: desired cache size (%d) "\ 117 "set to system max (%d)\n"), \ 118 progname, (sz), MAX_CACHE_SIZE); \ 119 spcs_log("sdbc", NULL, \ 120 gettext("desired cache size (%d) "\ 121 "set to system max (%d)\n"), \ 122 (sz), MAX_CACHE_SIZE); \ 123 } 124 125 void 126 sdbc_report_error(spcs_s_info_t *ustatus) 127 { 128 if (*ustatus != NULL) { 129 spcs_s_report(*ustatus, stderr); 130 spcs_s_ufree(ustatus); 131 } else 132 (void) fprintf(stderr, "%s\n", strerror(errno)); 133 } 134 135 136 /* 137 * Return the per-cd hints for a cd. 138 * 139 * Since the global (no)wrthru and NSC_NOCACHE hints take precedence 140 * over the per-cd hints, get them as well and OR the whole lot 141 * together. 142 */ 143 static int 144 get_cd_hint(const int cd) 145 { 146 spcs_s_info_t ustats; 147 int nodehint, cdhint; 148 149 nodehint = SDBC_IOCTL(SDBC_GET_NODE_HINT, 0, 0, 0, 0, 0, &ustats); 150 if (nodehint == SPCS_S_ERROR) { 151 (void) fprintf(stderr, 152 gettext("%s: get system options failed\n"), progname); 153 sdbc_report_error(&ustats); 154 exit(1); 155 } 156 157 cdhint = SDBC_IOCTL(SDBC_GET_CD_HINT, cd, 0, 0, 0, 0, &ustats); 158 if (cdhint == SPCS_S_ERROR) { 159 (void) fprintf(stderr, 160 gettext("%s: get cd(%d) hint failed\n"), progname, cd); 161 sdbc_report_error(&ustats); 162 exit(1); 163 } 164 165 #ifdef WRTHRU_HINTS 166 nodehint &= (NSC_FORCED_WRTHRU | NSC_NO_FORCED_WRTHRU | NSC_NOCACHE); 167 #else 168 nodehint &= (NSC_NOCACHE); 169 #endif 170 if (nodehint) { 171 /* set the top bit to mark it as a system override */ 172 nodehint |= 0x80000000; 173 } 174 175 return (cdhint | nodehint); 176 } 177 178 179 180 /* 181 * Check for a config. 182 * 183 * If no suitable config can be found, install the default config. 184 * 185 * Calling state: 186 * libcfg locked (mode describes type of lock) 187 */ 188 static void 189 convert_config(CFGFILE *cfg, CFGLOCK mode) 190 { 191 char buf[CFG_MAX_BUF]; 192 char *default_cfg = "128 64"; 193 194 retry: 195 if (cfg_get_cstring(cfg, "scm.set1", buf, sizeof (buf)) >= 0) { 196 /* config exists, return */ 197 return; 198 } 199 200 cfg_rewind(cfg, CFG_SEC_CONF); 201 202 #ifdef DEBUG 203 (void) printf(gettext("%s: installing default config entry '%s'\n"), 204 progname, default_cfg); 205 #endif 206 if (mode != CFG_WRLOCK) { 207 cfg_unlock(cfg); 208 if (!cfg_lock(cfg, CFG_WRLOCK)) { 209 (void) fprintf(stderr, 210 gettext("%s: unable to lock configuration: %s\n"), 211 progname, cfg_error(NULL)); 212 exit(1); 213 } 214 mode = CFG_WRLOCK; 215 #ifdef DEBUG 216 (void) printf(gettext("%s: upgraded lock, retrying\n"), 217 progname); 218 #endif 219 goto retry; 220 } 221 222 if (cfg_put_cstring(cfg, "scm", default_cfg, strlen(default_cfg)) < 0) { 223 (void) fprintf(stderr, 224 gettext("%s: unable to write configuration: %s\n"), 225 progname, cfg_error(NULL)); 226 exit(1); 227 } 228 229 if (!cfg_commit(cfg)) { 230 (void) fprintf(stderr, 231 gettext("%s: unable to write to configuration: %s\n"), 232 progname, cfg_error(NULL)); 233 } 234 235 if (mode != CFG_WRLOCK) { 236 if (!cfg_lock(cfg, mode)) { 237 (void) fprintf(stderr, 238 gettext("%s: unable to relock configuration: %s\n"), 239 progname, cfg_error(NULL)); 240 exit(1); 241 } 242 } 243 244 cfg_rewind(cfg, CFG_SEC_CONF); 245 } 246 247 248 static int 249 iscluster(void) 250 { 251 int rc; 252 253 rc = cfg_iscluster(); 254 if (rc == 0) { 255 return (FALSE); 256 } else if (rc > 0) { 257 return (TRUE); 258 } else { 259 (void) fprintf(stderr, 260 gettext("%s: unable to ascertain environment\n"), progname); 261 exit(1); 262 } 263 264 /* NOTREACHED */ 265 } 266 267 268 static void 269 restore_hints() 270 { 271 CFGFILE *cfg; 272 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF]; 273 int setnumber; 274 spcs_s_info_t ustatus; 275 int cd; 276 277 if ((cfg = cfg_open(NULL)) == NULL) { 278 (void) fprintf(stderr, 279 gettext("%s: unable to access configuration: %s\n"), 280 progname, cfg_error(NULL)); 281 exit(1); 282 } 283 if (!cfg_lock(cfg, CFG_RDLOCK)) { 284 (void) fprintf(stderr, 285 gettext("%s: unable to lock configuration: %s\n"), 286 progname, cfg_error(NULL)); 287 exit(1); 288 } 289 290 for (setnumber = 1; /*CONSTCOND*/ TRUE; setnumber++) { 291 (void) snprintf(key, sizeof (key), "cache_hint.set%d.device", 292 setnumber); 293 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) { 294 /* error or not found */ 295 break; 296 } 297 298 if (strcmp(buf, "system") == 0) { 299 cd = -1; 300 } else { 301 cd = get_cd(buf); 302 if (cd < 0) 303 continue; 304 } 305 306 (void) snprintf(key, sizeof (key), "cache_hint.set%d.wrthru", 307 setnumber); 308 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) 309 continue; 310 311 if (atoi(buf) == 1) { 312 if (cd == -1) { 313 /* Node hint */ 314 if (SDBC_IOCTL(SDBC_SET_NODE_HINT, NSC_WRTHRU, 315 1, 0, 0, 0, &ustatus) == SPCS_S_ERROR) { 316 (void) fprintf(stderr, 317 gettext("%s: set system " 318 "option failed\n"), 319 progname); 320 sdbc_report_error(&ustatus); 321 exit(1); 322 } 323 } else if (SDBC_IOCTL(SDBC_SET_CD_HINT, cd, 324 NSC_WRTHRU, 1, 0, 0, &ustatus) == SPCS_S_ERROR) { 325 (void) fprintf(stderr, 326 gettext("%s: set option failed\n"), 327 progname); 328 sdbc_report_error(&ustatus); 329 exit(1); 330 } 331 } 332 333 (void) snprintf(key, sizeof (key), "cache_hint.set%d.nordcache", 334 setnumber); 335 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) 336 continue; 337 338 if (atoi(buf) == 1) { 339 if (cd == -1) { 340 /* Node hint */ 341 if (SDBC_IOCTL(SDBC_SET_NODE_HINT, NSC_NOCACHE, 342 1, 0, 0, 0, &ustatus) == SPCS_S_ERROR) { 343 (void) fprintf(stderr, 344 gettext("%s: set system " 345 "option failed\n"), 346 progname); 347 sdbc_report_error(&ustatus); 348 exit(1); 349 } 350 } else if (SDBC_IOCTL(SDBC_SET_CD_HINT, cd, NSC_NOCACHE, 351 1, 0, 0, &ustatus) == SPCS_S_ERROR) { 352 (void) fprintf(stderr, 353 gettext("%s: set option failed\n"), 354 progname); 355 sdbc_report_error(&ustatus); 356 exit(1); 357 } 358 } 359 } 360 361 cfg_close(cfg); 362 } 363 364 void 365 sdbc_set_maxdev() 366 { 367 spcs_s_info_t ustats; 368 369 if (SDBC_IOCTL(SDBC_MAXFILES, &sdbc_max_devices, 370 0, 0, 0, 0, &ustats) == SPCS_S_ERROR) { 371 (void) fprintf(stderr, gettext("%s: get maxfiles failed\n"), 372 progname); 373 sdbc_report_error(&ustats); 374 exit(1); 375 } 376 } 377 378 static void 379 bitmapfs_print(void) 380 { 381 CFGFILE *cfg; 382 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF]; 383 int setnumber; 384 385 cfg = cfg_open(NULL); 386 if (cfg == NULL) { 387 (void) fprintf(stderr, 388 gettext("%s: unable to access configuration: %s\n"), 389 progname, cfg_error(NULL)); 390 exit(1); 391 } 392 393 if (!cfg_lock(cfg, CFG_RDLOCK)) { 394 (void) fprintf(stderr, 395 gettext("%s: unable to lock configuration: %s\n"), 396 progname, cfg_error(NULL)); 397 exit(1); 398 } 399 400 for (setnumber = 1; /*CSTYLED*/; setnumber++) { 401 (void) snprintf(key, sizeof (key), 402 "bitmaps.set%d.bitmap", setnumber); 403 buf[0] = 0; 404 405 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) { 406 if (errno == ESRCH) { 407 /* end of list */ 408 break; 409 } 410 411 (void) fprintf(stderr, 412 gettext("%s: error reading configuration: %s\n"), 413 progname, cfg_error(NULL)); 414 exit(1); 415 } 416 417 (void) printf("%s\n", buf); 418 } 419 420 cfg_close(cfg); 421 } 422 423 424 static void 425 bitmapfs_delete(char *bitmapfs) 426 { 427 CFGFILE *cfg; 428 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF]; 429 int setnumber; 430 int commit = 0; 431 432 cfg = cfg_open(NULL); 433 if (cfg == NULL) { 434 (void) fprintf(stderr, 435 gettext("%s: unable to access configuration: %s\n"), 436 progname, cfg_error(NULL)); 437 exit(1); 438 } 439 440 if (!cfg_lock(cfg, CFG_WRLOCK)) { 441 (void) fprintf(stderr, 442 gettext("%s: unable to lock configuration: %s\n"), 443 progname, cfg_error(NULL)); 444 exit(1); 445 } 446 447 for (setnumber = 1; /*CSTYLED*/; setnumber++) { 448 (void) snprintf(key, sizeof (key), 449 "bitmaps.set%d.bitmap", setnumber); 450 buf[0] = 0; 451 452 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) { 453 if (errno == ESRCH) { 454 /* end of list */ 455 (void) fprintf(stderr, 456 gettext("%s: %s not found " 457 "in configuration\n"), 458 progname, bitmapfs); 459 break; 460 } 461 462 (void) fprintf(stderr, 463 gettext("%s: error reading configuration: %s\n"), 464 progname, cfg_error(NULL)); 465 exit(1); 466 } 467 468 if (strcmp(bitmapfs, buf) == 0) { 469 (void) snprintf(key, sizeof (key), 470 "bitmaps.set%d", setnumber); 471 472 if (cfg_put_cstring(cfg, key, (char *)NULL, 0) < 0) { 473 (void) fprintf(stderr, 474 gettext("%s: unable to delete %s " 475 "from configuration: %s\n"), 476 progname, bitmapfs, cfg_error(NULL)); 477 } else 478 commit++; 479 480 break; 481 } 482 } 483 484 if (commit) { 485 if (!cfg_commit(cfg)) { 486 (void) fprintf(stderr, 487 gettext("%s: unable to write " 488 "to configuration: %s\n"), 489 progname, cfg_error(NULL)); 490 } 491 commit = 0; 492 } 493 494 cfg_close(cfg); 495 } 496 497 498 /* 499 * User visible configuration. 500 */ 501 502 static const struct { 503 const char *tag; /* libcfg tag */ 504 const char *name; /* user presented name */ 505 const char *help; /* explanation string */ 506 } sdbc_cfg_options[] = { 507 { "thread", "nthreads", "number of threads" }, 508 { "size", "cache_size", "total cache size" }, 509 #ifdef DEBUG 510 { "write_cache", "write_cache_size", "write cache size" }, 511 { "fill_pattern", "fill_pattern", "debug fill pattern" }, 512 { "reserved1", "reserved1", "unavailable, do not use" }, 513 { "iobuf", "niobuf", "number of io buffers" }, 514 { "tdemons", "ntdeamons", "number of sd_test daemons" }, 515 { "forced_wrthru", "forced_wrthru", "override wrthru detection" }, 516 { "no_forced_wrthru", "no_forced_wrthru", "override wrthru"}, 517 #endif 518 { NULL } 519 }; 520 521 522 static int 523 configure_sdbc(int argc, char *argv[], int optind) 524 { 525 CFGFILE *cfg; 526 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF]; 527 char *cp, option[CFG_MAX_BUF], value[CFG_MAX_BUF]; 528 const int opt_width = 20; 529 int error, found, commit; 530 int i; 531 532 error = commit = 0; 533 534 cfg = cfg_open(NULL); 535 if (cfg == NULL) { 536 (void) fprintf(stderr, "%s: unable to open configuration: %s", 537 progname, cfg_error(NULL)); 538 return (1); 539 } 540 541 if (argc == optind) { 542 /* display current user visible config */ 543 544 if (!cfg_lock(cfg, CFG_RDLOCK)) { 545 (void) fprintf(stderr, 546 gettext("%s: unable to lock configuration: %s\n"), 547 progname, cfg_error(NULL)); 548 error = 1; 549 goto out; 550 } 551 552 convert_config(cfg, CFG_RDLOCK); 553 554 for (i = 0; sdbc_cfg_options[i].tag != NULL; i++) { 555 (void) snprintf(key, sizeof (key), 556 "scm.set1.%s", sdbc_cfg_options[i].tag); 557 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) { 558 if (errno == ESRCH) { 559 /* not found */ 560 (void) strcpy(buf, ""); 561 } else { 562 (void) fprintf(stderr, 563 gettext("%s: error reading " 564 "configuration: %s\n"), 565 progname, cfg_error(NULL)); 566 error = 1; 567 goto out; 568 } 569 } 570 571 (void) printf("%-*s: %-*s /* %s */\n", 572 opt_width, sdbc_cfg_options[i].name, 573 opt_width, buf, sdbc_cfg_options[i].help); 574 } 575 } else { 576 if (!cfg_lock(cfg, CFG_WRLOCK)) { 577 (void) fprintf(stderr, 578 gettext("%s: unable to lock configuration: %s\n"), 579 progname, cfg_error(NULL)); 580 error = 1; 581 goto out; 582 } 583 584 convert_config(cfg, CFG_WRLOCK); 585 586 for (/*CSTYLED*/; optind < argc; optind++) { 587 (void) strncpy(option, argv[optind], sizeof (option)); 588 option[sizeof (option) - 1] = '\0'; /* terminate */ 589 590 cp = strchr(option, '='); 591 if (cp != NULL) { 592 *cp = '\0'; /* terminate option */ 593 cp++; 594 (void) strncpy(value, cp, sizeof (value)); 595 value[sizeof (value) - 1] = '\0'; 596 597 if (*value == '\0') 598 (void) strncpy(value, "-", 599 sizeof (value)); 600 } 601 602 found = 0; 603 for (i = 0; sdbc_cfg_options[i].tag != NULL; i++) { 604 if (strcmp(option, 605 sdbc_cfg_options[i].name) == 0) { 606 found = 1; 607 break; 608 } 609 } 610 611 if (!found) { 612 (void) fprintf(stderr, 613 gettext("%s: unknown configuration " 614 "parameter: %s\n"), progname, option); 615 continue; 616 } 617 618 (void) snprintf(key, sizeof (key), 619 "scm.set1.%s", sdbc_cfg_options[i].tag); 620 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) { 621 (void) fprintf(stderr, 622 gettext("%s: error reading " 623 "configuration: %s\n"), 624 progname, cfg_error(NULL)); 625 error = 1; 626 goto out; 627 } 628 629 if (*buf == '\0') 630 (void) strncpy(buf, "<default>", sizeof (buf)); 631 632 if (cp != NULL) { 633 char *tmp; 634 long val; 635 /* set to new value */ 636 637 if (strcmp(value, "-")) { /* default ? */ 638 639 val = strtol(value, &tmp, 0); 640 if (strcmp(value, tmp) == 0) { 641 (void) fprintf(stderr, 642 gettext( 643 "%s: bad value (%s) " 644 "for option %s\n"), 645 progname, value, option); 646 error = 1; 647 goto out; 648 } 649 650 /* make sure cache size is valid */ 651 if (strcmp(key, "scm.set1.size") == 0) { 652 if (val > MAX_CACHE_SIZE) { 653 PRINT_CACHE_SZ_ERR(val); 654 655 /* 656 * Overwrite the 657 * cache size with 658 * the maximum cache 659 * size. 660 */ 661 (void) snprintf(value, 662 sizeof (value), 663 "%ld", 664 (long) 665 MAX_CACHE_SIZE); 666 } 667 } 668 } 669 670 if (cfg_put_cstring(cfg, key, value, 671 strlen(value)) < 0) { 672 (void) fprintf(stderr, 673 gettext("\n%s: error writing " 674 "configuration: %s\n"), 675 progname, cfg_error(NULL)); 676 error = 1; 677 goto out; 678 } 679 680 (void) snprintf(buf, sizeof (buf), 681 "%s = %s", buf, 682 (strcmp(value, "-") == 0) ? 683 "<default>" : value); 684 685 commit = 1; 686 } 687 688 (void) printf("%-*s: %-*s /* %s */\n", 689 opt_width, sdbc_cfg_options[i].name, 690 opt_width, buf, sdbc_cfg_options[i].help); 691 } /* end command line args */ 692 } 693 694 out: 695 if (commit) { 696 if (!cfg_commit(cfg)) { 697 (void) fprintf(stderr, 698 gettext("%s: unable to write " 699 "to configuration: %s\n"), 700 progname, cfg_error(NULL)); 701 } 702 commit = 0; 703 704 (void) printf("\n%s\n", 705 gettext("Changed configuration parameters " 706 "will take effect when the cache is restarted")); 707 } 708 709 cfg_close(cfg); 710 return (error); 711 } 712 713 714 static char * 715 cd_to_device(int cd) 716 { 717 static _sd_stats_t *cs_cur = NULL; 718 spcs_s_info_t ustatus; 719 720 if (cs_cur == NULL) { 721 cs_cur = malloc(sizeof (_sd_stats_t) + 722 (sdbc_max_devices - 1) * sizeof (_sd_shared_t)); 723 724 if (cs_cur == NULL) { 725 (void) fprintf(stderr, gettext("%s malloc: %s\n"), 726 progname, strerror(errno)); 727 exit(1); 728 } 729 } 730 731 if (SDBC_IOCTL(SDBC_STATS, cs_cur, 0, 0, 0, 0, 732 &ustatus) == SPCS_S_ERROR) { 733 (void) fprintf(stderr, 734 gettext("%s: stats ioctl failed\n"), progname); 735 sdbc_report_error(&ustatus); 736 exit(1); 737 } 738 if (cs_cur->st_cachesize == 0 || cd >= cs_cur->st_count) 739 return (""); 740 741 return (cs_cur->st_shared[cd].sh_filename); 742 } 743 744 /* 745 * takes either either a string containing the cd or the device name, and 746 * returns the device name. 747 */ 748 static char * 749 get_device_name(char *arg) 750 { 751 long cd = 0; 752 char *device; 753 754 /* if the arg has a leading '/', assume it's a valid device name */ 755 if (!arg || *arg == '/') { 756 return (arg); 757 } 758 759 /* treat the "all" keyword as a valid device name */ 760 if (strcmp(arg, "all") == 0) { 761 return (arg); 762 } 763 764 /* 765 * Next, assume it's a cd, and try to convert it to an integer, and 766 * subsequently convert that cd to its corresponding device name. 767 * 768 * Since strtol returns 0 on failure, we need to make a special case 769 * for a cd of "0", which is valid. 770 */ 771 if (((cd = strtol(arg, (char **)NULL, 10)) > 0) || 772 strcmp(arg, "0") == 0) { 773 device = cd_to_device((int)cd); 774 775 /* cd_to_device returns NULL or "" on failure--check both */ 776 if (device && (strcmp(device, ""))) { 777 /* it seems to be a valid device name */ 778 return (device); 779 } 780 } 781 782 return (NULL); 783 } 784 785 static void 786 remove_hint(char *device) 787 { 788 CFGFILE *cfg; 789 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF]; 790 int setnumber; 791 int rc; 792 793 if ((cfg = cfg_open(NULL)) == NULL) { 794 (void) fprintf(stderr, 795 gettext("%s: unable to access configuration: %s\n"), 796 progname, cfg_error(NULL)); 797 exit(1); 798 } 799 if (!cfg_lock(cfg, CFG_WRLOCK)) { 800 (void) fprintf(stderr, 801 gettext("%s: unable to lock configuration: %s\n"), 802 progname, cfg_error(NULL)); 803 exit(1); 804 } 805 806 for (setnumber = 1; /*CONSTCOND*/ TRUE; setnumber++) { 807 (void) snprintf(key, sizeof (key), "cache_hint.set%d.device", 808 setnumber); 809 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) { 810 /* error or not found */ 811 break; 812 } 813 814 if (strcmp(device, buf) != 0) 815 continue; 816 817 /* remove config file entry */ 818 (void) snprintf(key, sizeof (key), 819 "cache_hint.set%d", setnumber); 820 rc = cfg_put_cstring(cfg, key, NULL, 0); 821 if (rc < 0) 822 (void) fprintf(stderr, 823 gettext("%s: unable to update configuration " 824 "storage: %s"), 825 progname, cfg_error(NULL)); 826 else if (!cfg_commit(cfg)) 827 (void) fprintf(stderr, 828 gettext("%s: unable to update configuration " 829 "storage: %s"), 830 progname, cfg_error(NULL)); 831 else 832 (void) fprintf(stderr, 833 gettext("%s: persistent hint for %s" 834 " removed from configuration\n"), 835 progname, device); 836 break; 837 } 838 cfg_close(cfg); 839 } 840 841 842 static void 843 save_hint(int cd, int hint, int flag) 844 { 845 char device[NSC_MAXPATH]; 846 CFGFILE *cfg; 847 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF]; 848 int setnumber; 849 int found; 850 int rc; 851 852 if (hint != NSC_WRTHRU && hint != NSC_NOCACHE) 853 return; 854 855 if (flag != 0 && flag != 1) 856 return; 857 858 if ((cfg = cfg_open(NULL)) == NULL) { 859 (void) fprintf(stderr, 860 gettext("%s: unable to access configuration: %s\n"), 861 progname, cfg_error(NULL)); 862 exit(1); 863 } 864 if (!cfg_lock(cfg, CFG_WRLOCK)) { 865 (void) fprintf(stderr, 866 gettext("%s: unable to lock configuration: %s\n"), 867 progname, cfg_error(NULL)); 868 exit(1); 869 } 870 871 if (cd == -1) 872 (void) strcpy(device, "system"); 873 else 874 (void) strncpy(device, cd_to_device(cd), NSC_MAXPATH); 875 876 found = 0; 877 for (setnumber = 1; /*CONSTCOND*/ TRUE; setnumber++) { 878 (void) snprintf(key, sizeof (key), "cache_hint.set%d.device", 879 setnumber); 880 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) { 881 /* error or not found */ 882 break; 883 } 884 885 if (strcmp(device, buf) == 0) { 886 found = 1; 887 break; 888 } 889 } 890 891 if (found) { 892 if (hint == NSC_WRTHRU) 893 (void) snprintf(key, sizeof (key), 894 "cache_hint.set%d.wrthru", setnumber); 895 else /* NSC_NOCACHE */ 896 (void) snprintf(key, sizeof (key), 897 "cache_hint.set%d.nordcache", setnumber); 898 if (flag == 0) 899 rc = cfg_put_cstring(cfg, key, "0", 1); 900 else 901 rc = cfg_put_cstring(cfg, key, "1", 1); 902 } else { 903 (void) strncpy(buf, device, CFG_MAX_BUF); 904 if (flag == 0) 905 (void) strncat(buf, " 0 0", CFG_MAX_BUF); 906 else if (hint == NSC_WRTHRU) 907 (void) strncat(buf, " 1 0", CFG_MAX_BUF); 908 else /* NSC_NOCACHE */ 909 (void) strncat(buf, " 0 1", CFG_MAX_BUF); 910 rc = cfg_put_cstring(cfg, "cache_hint", buf, sizeof (buf)); 911 } 912 913 if (rc < 0) 914 (void) fprintf(stderr, 915 gettext("%s: unable to update configuration storage: %s"), 916 progname, cfg_error(NULL)); 917 else if (!cfg_commit(cfg)) 918 (void) fprintf(stderr, 919 gettext("%s: unable to update configuration storage: %s"), 920 progname, cfg_error(NULL)); 921 cfg_close(cfg); 922 } 923 924 #ifdef lint 925 int 926 scmadm_lintmain(int argc, char *argv[]) 927 #else 928 int 929 main(int argc, char *argv[]) 930 #endif 931 { 932 int o = 0; 933 int c; 934 int errflg = 0; 935 int hflag = 0; 936 int qflag = 1; 937 extern int optind; 938 extern char *optarg; 939 int cd; 940 int hint; 941 int flag; 942 int optflag = 0; 943 spcs_s_info_t ustats; 944 int Dopt, Lopt; 945 int Oopt = 0; 946 char *bitmapfs = NULL; 947 const char *exclusive = gettext( 948 "-d, -e, -m, -o, -C, -D, -L, and -v " 949 "are mutually exclusive\n"); 950 951 (void) setlocale(LC_ALL, ""); 952 (void) textdomain("scm"); 953 954 progname = strdup(basename(argv[0])); 955 956 sdbc_set_maxdev(); 957 958 buildusage(progname); 959 960 Dopt = Lopt = 0; 961 962 while ((c = getopt(argc, argv, 963 #ifdef DEBUG 964 "gi:t:S" 965 #endif 966 "CD:LOa:devqhm:o:")) != EOF) { 967 968 switch (c) { 969 970 case 'D': 971 if (optflag) { 972 (void) fprintf(stderr, exclusive); 973 goto usage; 974 } 975 976 Dopt++; 977 optflag++; 978 bitmapfs = optarg; 979 break; 980 981 case 'L': 982 if (optflag) { 983 (void) fprintf(stderr, exclusive); 984 goto usage; 985 } 986 987 Lopt++; 988 optflag++; 989 break; 990 991 #ifdef DEBUG 992 case 'S': 993 if (optflag) { 994 (void) fprintf(stderr, exclusive); 995 goto usage; 996 } 997 998 if (putenv(stats_usage) != 0) { 999 (void) fprintf(stderr, 1000 gettext("%s: unable to putenv()\n"), 1001 progname); 1002 exit(1); 1003 } 1004 1005 argv[1] = "scmadm"; 1006 if (execv(STATS_PATH, &argv[1]) == -1) { 1007 (void) fprintf(stderr, 1008 gettext("%s: failed to execute " STATS_PATH 1009 "\n"), progname); 1010 (void) fprintf(stderr, 1011 gettext("Please be sure to copy sd_stats" 1012 " from src/cmd/ns/sdbc in a development" 1013 " workspace\n")); 1014 } 1015 exit(0); 1016 break; 1017 #endif 1018 case 'a': 1019 (void) strcpy(alert_file, optarg); 1020 break; 1021 case 'q': 1022 qflag++; 1023 break; 1024 case 'O': /* restore hints */ 1025 Oopt++; 1026 break; 1027 case 'C': /* configure */ 1028 case 'e': /* enable */ 1029 case 'd': /* disable */ 1030 case 'v': /* get version */ 1031 case 'o': /* get/set options */ 1032 case 'm': /* get cd map */ 1033 #ifdef DEBUG 1034 case 't': /* trace */ 1035 case 'i': /* inject_ioerr */ 1036 case 'c': /* clear_ioerr */ 1037 case 'g': /* toggle_flush */ 1038 #endif 1039 if (optflag) { 1040 (void) fprintf(stderr, 1041 #ifdef DEBUG 1042 "%s%s", gettext("-t, -i, -c, -g, "), 1043 #endif 1044 exclusive); 1045 1046 errflg++; 1047 } 1048 optflag++; 1049 o = c; 1050 break; 1051 case 'h': 1052 hflag = 1; 1053 break; 1054 case '?': 1055 default: 1056 errflg++; 1057 break; 1058 } 1059 if (errflg || hflag) 1060 goto usage; 1061 } 1062 1063 if (Oopt) { 1064 /* Set hints saved in persistent configuration */ 1065 restore_hints(); 1066 exit(0); 1067 } 1068 if (Dopt || Lopt) { 1069 /* bitmapfs control */ 1070 1071 if (iscluster()) { 1072 (void) fprintf(stderr, 1073 gettext("%s: bitmap filesystems are not " 1074 "allowed in a cluster\n"), progname); 1075 goto usage; 1076 } 1077 1078 if ((Dopt + Lopt) > 1) { 1079 (void) fprintf(stderr, gettext("-D and -L are" 1080 "mutually exclusive\n")); 1081 goto usage; 1082 } 1083 1084 if (Lopt) 1085 bitmapfs_print(); 1086 else /* if (Dopt) */ 1087 bitmapfs_delete(bitmapfs); 1088 1089 exit(0); 1090 } 1091 1092 if (!o) { 1093 if (argc > 1) 1094 goto usage; 1095 (void) printf(gettext("%s: Printing all cd's and options:\n"), 1096 progname); 1097 print_all_options(); 1098 } 1099 1100 /* Configure */ 1101 if (o == 'C') { 1102 exit(configure_sdbc(argc, argv, optind)); 1103 } 1104 /* enable */ 1105 if (o == 'e') { 1106 enable_sdbc(); 1107 if (qflag == 0) 1108 sd_gather_alert_dumps(); 1109 exit(0); 1110 } 1111 /* disable */ 1112 if (o == 'd') { 1113 disable_sdbc(); 1114 exit(0); 1115 } 1116 /* get version */ 1117 if (o == 'v') { 1118 get_version(); 1119 exit(0); 1120 } 1121 /* node_hint or cd_hint */ 1122 if (o == 'o') { 1123 if (!(strcoll(optarg, "system"))) { /* node_hint */ 1124 if ((optind - 1) == (argc - 1)) { /* get */ 1125 if ((hint = SDBC_IOCTL(SDBC_GET_NODE_HINT, 0, 0, 1126 0, 0, 0, &ustats)) == SPCS_S_ERROR) { 1127 (void) fprintf(stderr, 1128 gettext("%s: get system " 1129 "options failed\n"), 1130 progname); 1131 sdbc_report_error(&ustats); 1132 exit(1); 1133 } 1134 #ifdef WRTHRU_HINTS 1135 (void) printf(gettext("System Status: ")); 1136 print_hint(hint, 1); 1137 #endif 1138 (void) printf(gettext("System Options: ")); 1139 print_hint(hint, 0); 1140 exit(0); 1141 } else { /* set, clear */ 1142 if (get_hint(argv[optind], &hint, &flag) == -1) 1143 goto usage; 1144 if (hint == -1) { 1145 /* remove hint from config */ 1146 remove_hint("system"); 1147 exit(0); 1148 } 1149 1150 if (SDBC_IOCTL(SDBC_SET_NODE_HINT, hint, flag, 1151 0, 0, 0, &ustats) == SPCS_S_ERROR) { 1152 (void) fprintf(stderr, 1153 gettext("%s: set system " 1154 "option failed\n"), 1155 progname); 1156 sdbc_report_error(&ustats); 1157 exit(1); 1158 } 1159 save_hint(-1, hint, flag); 1160 (void) printf(gettext("%s: System option %s" 1161 " now set.\n"), progname, argv[optind]); 1162 exit(0); 1163 } 1164 } else { /* cd_hint */ 1165 cd = get_cd(optarg); 1166 if ((optind - 1) == (argc - 1)) { /* get */ 1167 if (cd < 0) { 1168 (void) fprintf(stderr, 1169 gettext("%s: device %s not " 1170 "found\n"), 1171 progname, optarg); 1172 exit(1); 1173 } 1174 hint = get_cd_hint(cd); 1175 (void) printf(gettext("%s: cd(%d) Current " 1176 "options are: "), progname, cd); 1177 print_hint(hint, 0); 1178 exit(0); 1179 } else { /* set, clear */ 1180 if (get_hint(argv[optind], &hint, &flag) == -1) 1181 goto usage; 1182 if (hint == -1) { 1183 /* remove hint from config */ 1184 if (cd < 0) 1185 remove_hint(optarg); 1186 else 1187 remove_hint(cd_to_device(cd)); 1188 exit(0); 1189 } 1190 if (cd < 0) { 1191 (void) fprintf(stderr, 1192 gettext("%s: device %s not " 1193 "found\n"), 1194 progname, optarg); 1195 exit(1); 1196 } 1197 1198 if (SDBC_IOCTL(SDBC_SET_CD_HINT, cd, hint, 1199 flag, 0, 0, &ustats) == SPCS_S_ERROR) { 1200 (void) fprintf(stderr, 1201 gettext("%s: set option " 1202 "failed\n"), progname); 1203 sdbc_report_error(&ustats); 1204 exit(1); 1205 } 1206 save_hint(cd, hint, flag); 1207 (void) printf(gettext("%s: cd %d option %s now" 1208 " set.\n"), progname, cd, argv[optind]); 1209 exit(0); 1210 } 1211 } 1212 } 1213 1214 if (o == 'm') { /* "get_cd" = map */ 1215 char *dev_name; 1216 1217 if (!(strcoll(optarg, "all"))) /* all */ 1218 (void) get_cd_all(); 1219 else { 1220 cd = get_cd(optarg); 1221 if (cd < 0) { 1222 (void) fprintf(stderr, 1223 gettext("%s: device or cd %s not found\n"), 1224 progname, optarg); 1225 exit(1); 1226 } 1227 1228 if ((dev_name = get_device_name(optarg)) == NULL) { 1229 (void) fprintf(stderr, gettext( 1230 "%s: device for cd %d not found\n"), 1231 progname, cd); 1232 exit(1); 1233 } 1234 1235 (void) printf(gettext("%s: diskname %s; cd %d\n"), 1236 progname, dev_name, cd); 1237 exit(0); 1238 } 1239 } 1240 1241 #ifdef DEBUG 1242 if (o == 't') { /* "trace" */ 1243 int flag, value; 1244 _sdtr_table_t tt; 1245 if ((optind+1) != (argc-1)) 1246 goto usage; 1247 cd = get_cd(argv[optind]); 1248 if (cd < 0) { 1249 (void) fprintf(stderr, 1250 gettext("%s: device or cd %s not found\n"), 1251 progname, argv[optind]); 1252 exit(1); 1253 } 1254 1255 value = strtol(argv[optind+1], 0, 0); 1256 if (!(strcoll(optarg, gettext("size")))) { 1257 flag = SD_SET_SIZE; 1258 tt.tt_max = value; 1259 } else if (!(strcoll(optarg, gettext("mask")))) { 1260 flag = SD_SET_MASK; 1261 tt.tt_mask = value; 1262 } else if (!(strcoll(optarg, gettext("lbolt")))) { 1263 flag = SD_SET_LBOLT; 1264 tt.tt_lbolt = value; 1265 } else if (!(strcoll(optarg, gettext("good")))) { 1266 flag = SD_SET_GOOD; 1267 tt.tt_good = value; 1268 } else goto usage; 1269 1270 if (SDBC_IOCTL(SDBC_ADUMP, (long)cd, &tt, NULL, 0L, 1271 (long)flag, &ustats) == SPCS_S_ERROR) { 1272 (void) fprintf(stderr, 1273 gettext("%s: trace %s failed\n"), 1274 progname, optarg); 1275 sdbc_report_error(&ustats); 1276 exit(1); 1277 } 1278 (void) printf(gettext("%s: trace %s processed\n"), 1279 progname, optarg); 1280 if (cd != -1) 1281 (void) printf(gettext(" cd %d; size %d; mask 0x%04x; " 1282 "lbolt %d; good %d;\n"), 1283 cd, tt.tt_max, tt.tt_mask, 1284 tt.tt_lbolt, tt.tt_good); 1285 exit(0); 1286 } 1287 1288 if (o == 'i') { /* "inject_ioerr" */ 1289 int ioj_err = EIO; 1290 int cd; 1291 int ioj_cnt = 0; 1292 1293 /* a cd of "-1" represents all devices */ 1294 if (strcmp(optarg, "-1") == 0) { 1295 cd = -1; 1296 } else if ((cd = get_cd(optarg)) < 0) { 1297 (void) fprintf(stderr, 1298 gettext("%s: device or cd %s not found\n"), 1299 progname, optarg); 1300 exit(1); 1301 } 1302 if (argc == 4) 1303 ioj_err = strtol(argv[optind], 0, 0); 1304 if (argc == 5) 1305 ioj_cnt = strtol(argv[optind+1], 0, 0); 1306 1307 if (SDBC_IOCTL(SDBC_INJ_IOERR, cd, ioj_err, ioj_cnt, 0, 0, 1308 &ustats) == SPCS_S_ERROR) { 1309 (void) fprintf(stderr, 1310 gettext("%s: i/o error injection for cd %s " 1311 "failed\n"), progname, optarg); 1312 sdbc_report_error(&ustats); 1313 exit(1); 1314 } 1315 (void) printf(gettext("%s: i/o error injection cd %d errno %d " 1316 "processed\n"), progname, cd, ioj_err); 1317 exit(0); 1318 } 1319 1320 if (o == 'c') { /* "clear_ioerr" */ 1321 int cd; 1322 1323 /* a cd of "-1" represents all devices */ 1324 if (strcmp(optarg, "-1") == 0) { 1325 cd = -1; 1326 } else if ((cd = get_cd(optarg)) < 0) { 1327 (void) fprintf(stderr, 1328 gettext("%s: device or cd %s not found\n"), 1329 progname, optarg); 1330 exit(1); 1331 } 1332 1333 if (SDBC_IOCTL(SDBC_CLR_IOERR, cd, 0, 0, 0, 0, &ustats) 1334 == SPCS_S_ERROR) { 1335 (void) fprintf(stderr, 1336 gettext("%s: i/o error clear %s failed\n"), 1337 progname, optarg); 1338 sdbc_report_error(&ustats); 1339 exit(1); 1340 } 1341 (void) printf(gettext("%s: i/o error clear for cd %d " 1342 "processed\n"), progname, cd); 1343 exit(0); 1344 } 1345 1346 if (o == 'g') { /* "toggle_flush" */ 1347 flag = toggle_flush(); 1348 (void) printf(gettext("%s: sdbc cache flush now %s\n"), 1349 progname, flag ? "on" : "off"); 1350 exit(0); 1351 } 1352 #endif /* DEBUG */ 1353 1354 return (0); 1355 usage: 1356 (void) fprintf(stderr, "%s\n", scmadmUsage); 1357 if (hflag) { 1358 return (0); 1359 } 1360 return (1); 1361 } 1362 1363 1364 #define addusage(f__) \ 1365 (void) strncat(scmadmUsage, f__, sizeof (scmadmUsage)); 1366 1367 #define addusage1(f__, a__) \ 1368 (void) snprintf(fmt, sizeof (fmt), "%s%s", scmadmUsage, f__); \ 1369 (void) snprintf(scmadmUsage, sizeof (scmadmUsage), fmt, a__); 1370 1371 #define addusage2(f__, a__, b__) \ 1372 (void) snprintf(fmt, sizeof (fmt), "%s%s", scmadmUsage, f__); \ 1373 (void) snprintf(scmadmUsage, sizeof (scmadmUsage), fmt, a__, b__); 1374 1375 static void 1376 buildusage(char *p) 1377 { 1378 char fmt[USAGELEN]; 1379 #ifdef WRTHRU_HINTS 1380 char *hints_str = "[nordcache|rdcache|wrthru|nowrthru|forget]\n"; 1381 #else 1382 char *hints_str = "[nordcache|rdcache|forget]\n"; 1383 #endif 1384 1385 bzero(scmadmUsage, sizeof (scmadmUsage)); 1386 bzero(fmt, sizeof (fmt)); 1387 1388 addusage(gettext("Usage :\n")); 1389 addusage1(gettext("\t%s\n"), p); 1390 addusage1(gettext("\t%s -h\n"), p); 1391 addusage1(gettext("\t%s -e\n"), p); 1392 addusage1(gettext("\t%s -d\n"), p); 1393 addusage1(gettext("\t%s -v\n"), p); 1394 addusage1(gettext("\t%s {-L | -D bitmapfs}\n"), p); 1395 addusage1(gettext("\t%s -C [parameter[=[value]] ...]\n"), p); 1396 addusage2(gettext("\t%s -o system %s"), p, hints_str); 1397 addusage2(gettext("\t%s -o <cd> %s"), p, hints_str); 1398 addusage2(gettext("\t%s -o <diskname> %s"), p, hints_str); 1399 addusage1(gettext("\t%s -m {<cd>|<diskname>|all}\n"), p); 1400 #ifdef DEBUG 1401 addusage1(gettext( 1402 "\t%s -S [-Mz] [-d delay_time] [-l logfile] [-r range]\n"), p); 1403 addusage1(gettext( 1404 "\t%s -t {size|mask|lbolt|good} <cd|diskname> <value>\n"), p); 1405 addusage1(gettext("\t%s -g\n"), p); 1406 addusage1(gettext( 1407 "\t%s -i {cd|diskname|-1 for all} [errno [countdown]]\n"), p); 1408 addusage1(gettext("\t%s -c {cd|diskname|-1 for all}\n"), p); 1409 addusage(gettext("\nt = trace\tg = toggle_flush\ti = inject ioerr\n" 1410 "c = clear ioerr\tS = stats\n")); 1411 #endif /* DEBUG */ 1412 addusage(gettext( 1413 "e = enable\td = disable\tv=version\to = get/ set options\n")); 1414 addusage(gettext( 1415 "m = get cd map\n")); 1416 addusage1(gettext( 1417 "note: cd is a cache descriptor integer in the range [0-%d]\n"), 1418 sdbc_max_devices - 1); 1419 addusage(gettext( 1420 " bitmapfs is a block device or filesystem mount point\n")); 1421 1422 #ifdef DEBUG 1423 (void) snprintf(stats_usage, sizeof (stats_usage), 1424 "SD_STATS_USAGE=%s", scmadmUsage); 1425 #endif 1426 } 1427 1428 static int 1429 get_hint(char *str, int *hint, int *flag) 1430 { 1431 #ifdef WRTHRU_HINTS 1432 if (!(strcoll(str, gettext("wrthru")))) { 1433 *hint = NSC_WRTHRU; 1434 *flag = 1; 1435 return (0); 1436 } else if (!(strcoll(str, gettext("nowrthru")))) { 1437 *hint = NSC_WRTHRU; 1438 *flag = 0; 1439 return (0); 1440 } else 1441 #endif 1442 if (!(strcoll(str, gettext("nordcache")))) { 1443 *hint = NSC_NOCACHE; 1444 *flag = 1; 1445 return (0); 1446 } else if (!(strcoll(str, gettext("rdcache")))) { 1447 *hint = NSC_NOCACHE; 1448 *flag = 0; 1449 return (0); 1450 } else if (!(strcoll(str, gettext("forget")))) { 1451 *hint = -1; 1452 *flag = 0; 1453 return (0); 1454 } 1455 return (-1); 1456 } 1457 1458 /*ARGSUSED*/ 1459 void 1460 print_hint(const uint_t type, const int status) 1461 { 1462 #ifdef WRTHRU_HINTS 1463 if (status) { 1464 if (type & NSC_FORCED_WRTHRU) { 1465 (void) printf(gettext("Fast Writes Overridden\n")); 1466 } else { 1467 /* if (type & NSC_NO_FORCED_WRTHRU) */ 1468 (void) printf(gettext("default\n")); 1469 } 1470 } else { 1471 (void) printf("%swrthru, %srdcache", 1472 (type & (NSC_FORCED_WRTHRU|NSC_WRTHRU)) ? "" : "no", 1473 (type & NSC_NOCACHE) ? "no" : ""); 1474 #else 1475 { 1476 (void) printf("%srdcache", (type & NSC_NOCACHE) ? "no" : ""); 1477 #endif 1478 1479 if (type & 0x80000000) 1480 (void) printf(" (overridden by system)"); 1481 1482 (void) printf("\n"); 1483 } 1484 } 1485 1486 /* 1487 * Read the configuration via libcfg 1488 */ 1489 1490 int 1491 get_cache_config() 1492 { 1493 int i; 1494 int sysid; 1495 CFGFILE *cfg; 1496 char buf[CFG_MAX_BUF]; 1497 char key[CFG_MAX_KEY]; 1498 1499 1500 if ((cfg = cfg_open(NULL)) == NULL) { 1501 (void) fprintf(stderr, 1502 gettext("Cannot open configuration file\n")); 1503 exit(1); 1504 } 1505 1506 if (!cfg_lock(cfg, CFG_RDLOCK)) { 1507 (void) fprintf(stderr, 1508 gettext("Cannot lock configuration file\n")); 1509 exit(1); 1510 } 1511 1512 convert_config(cfg, CFG_RDLOCK); 1513 (void) memset((char *)&user_level_conf, 0, sizeof (_sd_cache_param_t)); 1514 1515 /* Get the system ID */ 1516 if (nsc_getsystemid(&sysid) < 0) { 1517 (void) fprintf(stderr, 1518 gettext("%s Unable to obtain subsystem ID: %s\n"), 1519 progname, strerror(errno)); 1520 exit(1); 1521 } 1522 myid = sysid; 1523 1524 user_level_conf.blk_size = 8192; /* DEFAULT */ 1525 user_level_conf.procs = 16; /* DEFAULT */ 1526 user_level_conf.reserved1 = RESERVED1_DEFAULTS; 1527 1528 bzero(buf, CFG_MAX_BUF); 1529 (void) snprintf(key, sizeof (key), "scm.set1.thread"); 1530 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) { 1531 user_level_conf.threads = atoi(buf); 1532 } else 1533 user_level_conf.threads = 128; /* DEFAULT */ 1534 1535 (void) snprintf(key, sizeof (key), "scm.set1.tdemons"); 1536 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) { 1537 user_level_conf.test_demons = atoi(buf); 1538 } 1539 1540 (void) snprintf(key, sizeof (key), "scm.set1.write_cache"); 1541 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) { 1542 user_level_conf.write_cache = atoi(buf); 1543 } 1544 1545 (void) snprintf(key, sizeof (key), "scm.set1.size"); 1546 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) { 1547 /* 1548 * We need to run strtol for backwards compatibility in 3.2. 1549 * A workaround for this bug was put in 3.2 which allowed 1550 * customers to set the cache size up to 1024 if it was 1551 * specified in hexadecimal. Decimal still had the limit 1552 * of 128. This change treats them both identically. 1553 */ 1554 user_level_conf.cache_mem[0] = (int)strtol(buf, NULL, 0); 1555 if (user_level_conf.cache_mem[0] > MAX_CACHE_SIZE) { 1556 (void) fprintf(stderr, gettext( 1557 "The cache size of %ld is larger than " 1558 "the system maximum of %ld.\nUse \"scmadm -C " 1559 "cache_size=<size>\" to set the size to a proper " 1560 "value.\n"), 1561 user_level_conf.cache_mem[0], MAX_CACHE_SIZE); 1562 user_level_conf.cache_mem[0] = MAX_CACHE_SIZE; 1563 } 1564 } 1565 1566 (void) snprintf(key, sizeof (key), "scm.set1.iobuf"); 1567 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) { 1568 user_level_conf.iobuf = atoi(buf); 1569 } 1570 1571 (void) snprintf(key, sizeof (key), "scm.set1.fill_pattern"); 1572 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) { 1573 user_level_conf.fill_pattern = atoi(buf); 1574 user_level_conf.gen_pattern = 1; 1575 } 1576 1577 (void) snprintf(key, sizeof (key), "scm.set1.no_forced_wrthru"); 1578 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) { 1579 no_forced_wrthru = atoi(buf); 1580 } 1581 1582 (void) snprintf(key, sizeof (key), "scm.set1.forced_wrthru"); 1583 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) { 1584 forced_wrthru = atoi(buf); 1585 } 1586 1587 (void) snprintf(key, sizeof (key), "scm.set1.reserved1"); 1588 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) { 1589 user_level_conf.reserved1 = atoi(buf); 1590 } 1591 1592 cfg_close(cfg); 1593 1594 /* 1595 * use the default minidsp configuration if no 1596 * node/mirror/remote-mirror/cluster line is in the sd.cf file 1597 */ 1598 if (nodes_configured == 0) 1599 check_and_set_mirrors(myid, _SD_NO_HOST); 1600 1601 1602 /* Check if our sysid was defined */ 1603 if (!node_defined[myid]) { 1604 (void) fprintf(stderr, 1605 gettext("This node(%d) is not defined in config.\n"), myid); 1606 exit(1); 1607 } 1608 1609 /* 1610 * Save off number of nodes so we can calculate the point-to-point 1611 * segements. Code in kernel currently supports MAX_SD_NODES 1612 */ 1613 if ((user_level_conf.num_nodes = nodes_configured) > 1614 MAX_SD_NODES) { 1615 (void) fprintf(stderr, 1616 gettext("Cache can support only %d nodes(%d).\n"), 1617 MAX_SD_NODES, nodes_configured); 1618 exit(1); 1619 } 1620 1621 if ((nodes_configured % 2) && !minidsp) { 1622 if (nodes_configured == 1) 1623 (void) fprintf(stderr, 1624 gettext("Only one node configured, " 1625 "mirror node must be %d\n"), _SD_NO_HOST); 1626 else 1627 (void) fprintf(stderr, 1628 gettext("Cannot configure odd number of nodes.\n")); 1629 exit(1); 1630 } 1631 1632 1633 /* Pass List of Nodes Configured to Cache */ 1634 for (i = 0; i < nodes_configured; i++) 1635 user_level_conf.nodes_conf[i] = nodes_conf[i]; 1636 1637 /* Place magic number in user_level_conf. Kernel will test for it */ 1638 user_level_conf.magic = _SD_MAGIC; 1639 (void) sleep(1); 1640 return (0); 1641 } 1642 1643 _sdtr_t hdr; 1644 1645 /* function name string */ 1646 char * 1647 _sd_fname(int f) 1648 { 1649 int fn = f & ST_FUNC; 1650 static char c[8]; 1651 char *s; 1652 1653 if (f & ST_BCACHE) 1654 s = _bcache_fname[fn]; 1655 else if (f & ST_BSUB) 1656 s = _bsub_fname[fn]; 1657 else if (f & ST_IO) 1658 s = _io_fname[fn]; 1659 else if (f & ST_STATS) 1660 s = _stats_fname[fn]; 1661 else if (f & ST_CCIO) 1662 s = _ccio_fname[fn]; 1663 else if (f & ST_FT) 1664 s = _ft_fname[fn]; 1665 else if (f & ST_INFO) 1666 s = _info_fname[fn]; 1667 if (!s) 1668 (void) sprintf(s = c, "0x%04x", f & 0xffff); 1669 return (s); 1670 } 1671 1672 int alerts = 0; 1673 1674 /* 1675 * Background daemon to wait for alert (on any device) 1676 * Writes the traces to "sd_alert.CD.NUM", 1677 * and writes an information message to the alert_file. 1678 */ 1679 1680 void 1681 sd_gather_alert_dumps() 1682 { 1683 _sdtr_table_t tt; 1684 _sdtr_t *buf; 1685 int cd, count, size, flag; 1686 char filename[64]; 1687 int fd; 1688 time_t tloc; 1689 struct tm tm_storage; 1690 struct tm *tm_ptr; 1691 char timebuf[80]; 1692 spcs_s_info_t ustats; 1693 1694 /* fork and detach daemon */ 1695 if (fork()) 1696 exit(0); 1697 (void) close(0); 1698 fd = open(alert_file, O_WRONLY|O_APPEND|O_CREAT, 0644); 1699 if (fd == -1) 1700 fd = open("/dev/console", O_WRONLY); 1701 if (fd != -1) { 1702 (void) dup2(fd, 1); 1703 (void) dup2(fd, 2); 1704 (void) close(fd); 1705 } 1706 (void) setsid(); 1707 1708 size = 10000; 1709 if (size < user_level_conf.trace_size) 1710 size = user_level_conf.trace_size; 1711 1712 buf = (_sdtr_t *)malloc(size * sizeof (_sdtr_t)); 1713 if (!buf) { 1714 (void) fprintf(stderr, gettext("%s malloc: %s\n"), 1715 progname, strerror(errno)); 1716 exit(1); 1717 } 1718 tloc = time(NULL); 1719 tm_ptr = (struct tm *)localtime_r(&tloc, &tm_storage); 1720 1721 loop: 1722 cd = SDT_ANY_CD; /* any device */ 1723 flag = SD_ALERT_WAIT; /* block for alert */ 1724 if ((count = SDBC_IOCTL(SDBC_ADUMP, cd, &tt, buf, size, 1725 flag, &ustats)) == SPCS_S_ERROR) { 1726 (void) fprintf(stderr, gettext("%s: sd_adump\n"), progname); 1727 sdbc_report_error(&ustats); 1728 if (errno == EIDRM) { 1729 (void) strftime(timebuf, 80, "%x %X", tm_ptr); 1730 (void) fprintf(stderr, 1731 gettext("%s: cache deconfigured at %s\n"), 1732 progname, timebuf); 1733 exit(0); 1734 } 1735 if (errno == ENOSYS) 1736 exit(0); 1737 exit(errno); 1738 } 1739 if (count == 0) 1740 goto loop; 1741 cd = tt.tt_cd; 1742 (void) sprintf(filename, "%s.%d.%d", "sd_alert", cd, alerts++); 1743 if ((fd = open(filename, O_CREAT | O_RDWR, 0444)) == -1) { 1744 (void) fprintf(stderr, gettext("%s: open: %s\n"), 1745 progname, strerror(errno)); 1746 exit(errno); 1747 } 1748 /* 1749 * write header to identify device, write entries 1750 */ 1751 hdr.t_func = SDF_CD; 1752 hdr.t_len = count; 1753 hdr.t_ret = tt.tt_cd; 1754 if (write(fd, &hdr, sizeof (_sdtr_t)) == -1) { 1755 (void) fprintf(stderr, gettext("%s: write: %s\n"), 1756 progname, strerror(errno)); 1757 exit(errno); 1758 } 1759 1760 if (write(fd, buf, sizeof (_sdtr_t)*count) == -1) { 1761 (void) fprintf(stderr, gettext("%s: write: %s\n"), 1762 progname, strerror(errno)); 1763 exit(errno); 1764 } 1765 (void) close(fd); 1766 1767 (void) strftime(timebuf, 80, "%x %X", tm_ptr); 1768 (void) printf("sd alert trace dump %s at %s\n", filename, timebuf); 1769 goto loop; 1770 } 1771 1772 1773 1774 /* 1775 * print list of configured cd's, diskname, options and global options 1776 */ 1777 void 1778 print_all_options() 1779 { 1780 static _sd_stats_t *cs_cur; 1781 spcs_s_info_t ustats; 1782 int cd; 1783 int hint; 1784 char *s1 = "device name"; 1785 char *s2 = "option"; 1786 char fn[19]; 1787 int len; 1788 1789 /* No corresponding free because this function exits */ 1790 cs_cur = malloc(sizeof (_sd_stats_t) + 1791 (sdbc_max_devices - 1) * sizeof (_sd_shared_t)); 1792 if (cs_cur == NULL) { 1793 (void) fprintf(stderr, gettext("%s malloc: %s\n"), 1794 progname, strerror(errno)); 1795 exit(1); 1796 } 1797 1798 /* node hints */ 1799 if ((hint = SDBC_IOCTL(SDBC_GET_NODE_HINT, 0, 0, 0, 0, 0, 1800 &ustats)) == SPCS_S_ERROR) { 1801 (void) fprintf(stderr, 1802 gettext("%s: get system option failed\n"), 1803 progname); 1804 sdbc_report_error(&ustats); 1805 exit(1); 1806 } 1807 #ifdef WRTHRU_HINTS 1808 (void) printf(gettext("System Status: ")); 1809 print_hint(hint, 1); 1810 #endif 1811 (void) printf(gettext("System Options: ")); 1812 print_hint(hint, 0); 1813 1814 /* get cds */ 1815 if (SDBC_IOCTL(SDBC_STATS, cs_cur, 0, 0, 0, 0, &ustats) 1816 == SPCS_S_ERROR) { 1817 (void) fprintf(stderr, 1818 gettext("%s: get_cd failed in print_all options\n"), 1819 progname); 1820 sdbc_report_error(&ustats); 1821 exit(1); 1822 } 1823 if (cs_cur->st_cachesize == 0) 1824 (void) printf(gettext("Cache is disabled\n")); 1825 else if (cs_cur->st_count == 0) 1826 (void) printf(gettext("No devices are configured\n")); 1827 else { 1828 (void) printf( 1829 gettext("\nConfigured cd's, disknames and options: \n")); 1830 (void) printf(gettext("cd\t%-28s\t%-20s\n"), s1, s2); 1831 for (cd = 0; cd < cs_cur->st_count; cd++) { 1832 if (cs_cur->st_shared[cd].sh_alloc) { 1833 hint = get_cd_hint(cd); 1834 if ((len = 1835 strlen(cs_cur->st_shared[cd].sh_filename)) 1836 > 23) { 1837 (void) strcpy(fn, "..."); 1838 (void) strcat(fn, 1839 cs_cur->st_shared[cd].sh_filename + 1840 len - 20); 1841 } else { 1842 (void) strcpy(fn, 1843 cs_cur->st_shared[cd].sh_filename); 1844 } 1845 1846 (void) printf(gettext("%d\t%-28.*s\t"), cd, 1847 NSC_MAXPATH, fn); 1848 1849 print_hint(hint, 0); 1850 } 1851 } 1852 } 1853 exit(0); 1854 } 1855 1856 1857 /* 1858 * cache device -- lookup names and cache descriptors of all configured devices 1859 */ 1860 void 1861 get_cd_all() 1862 { 1863 static _sd_stats_t *cs_cur; 1864 spcs_s_info_t ustats; 1865 int cd; 1866 char fn[19]; 1867 int len; 1868 1869 /* No corresponding free because this function exits */ 1870 cs_cur = malloc(sizeof (_sd_stats_t) + 1871 (sdbc_max_devices - 1) * sizeof (_sd_shared_t)); 1872 if (cs_cur == NULL) { 1873 (void) fprintf(stderr, gettext("%s malloc: %s\n"), 1874 progname, strerror(errno)); 1875 exit(1); 1876 } 1877 1878 if (SDBC_IOCTL(SDBC_STATS, cs_cur, 0, 0, 0, 0, &ustats) 1879 == SPCS_S_ERROR) { 1880 (void) fprintf(stderr, gettext("%s: get_cd_all"), 1881 progname); 1882 sdbc_report_error(&ustats); 1883 exit(1); 1884 } 1885 if (cs_cur->st_cachesize == 0) 1886 (void) printf(gettext("Cache is disabled\n")); 1887 else if (cs_cur->st_count == 0) 1888 (void) printf(gettext("No devices are configured\n")); 1889 else { 1890 (void) printf(gettext("\tcd\tdevice name\n")); 1891 for (cd = 0; cd < cs_cur->st_count; cd++) { 1892 if (cs_cur->st_shared[cd].sh_alloc) { 1893 if ((len = strlen( 1894 cs_cur->st_shared[cd].sh_filename)) > 15) { 1895 (void) strcpy(fn, "..."); 1896 (void) strcat(fn, 1897 cs_cur->st_shared[cd].sh_filename + 1898 len - 12); 1899 } else { 1900 (void) strcpy(fn, 1901 cs_cur->st_shared[cd].sh_filename); 1902 } 1903 (void) printf(gettext("\t%d\t%s\n"), 1904 cd, fn); 1905 } 1906 } 1907 } 1908 exit(0); 1909 } 1910 1911 /* 1912 * cache device -- specified by number or lookup name 1913 */ 1914 static int 1915 get_cd(char *s) 1916 { 1917 static _sd_stats_t *cs_cur = NULL; 1918 spcs_s_info_t ustats; 1919 int cd, arg_cd = -1; 1920 1921 if (cs_cur == NULL) { 1922 /* 1923 * No corresponding free because the memory is reused 1924 * every time the function is called. 1925 */ 1926 cs_cur = malloc(sizeof (_sd_stats_t) + 1927 (sdbc_max_devices - 1) * sizeof (_sd_shared_t)); 1928 if (cs_cur == NULL) { 1929 (void) fprintf(stderr, gettext("%s malloc: %s\n"), 1930 progname, strerror(errno)); 1931 exit(1); 1932 } 1933 } 1934 1935 if (SDBC_IOCTL(SDBC_STATS, cs_cur, 0, 0, 0, 0, &ustats) 1936 == SPCS_S_ERROR) { 1937 (void) fprintf(stderr, gettext("%s: get_cd\n"), progname); 1938 sdbc_report_error(&ustats); 1939 exit(1); 1940 } 1941 if (cs_cur->st_cachesize == 0) { 1942 (void) printf(gettext("Cache is disabled\n")); 1943 exit(0); 1944 } 1945 1946 if (*s != '/') { 1947 /* 1948 * Since strtol returns 0 on failure, we need to make a 1949 * special case for a cd of "0", which is valid. 1950 * 1951 * This case also deals with the difference between 1952 * scmadm -o system and scmadm -o 0 1953 */ 1954 if (((int)strtol(s, (char **)NULL, 10) == 0) && 1955 strcmp(s, "0")) 1956 return (-1); 1957 1958 /* 1959 * Only return failure at this point, in order to allow 1960 * checking arg_cd against st_count later on. 1961 */ 1962 if ((arg_cd = strtol(s, 0, 0)) < 0) { 1963 return (arg_cd); 1964 } 1965 } 1966 1967 /* make sure the cd passed as an argument is alloc'd and < st_count */ 1968 if (arg_cd >= 0) { 1969 return (((arg_cd < cs_cur->st_count) && 1970 (cs_cur->st_shared[arg_cd].sh_alloc)) ? arg_cd : -1); 1971 } 1972 1973 for (cd = 0; cd < cs_cur->st_count; cd++) { 1974 if (cs_cur->st_shared[cd].sh_alloc && 1975 strcmp(s, cs_cur->st_shared[cd].sh_filename) == 0) 1976 return (cd); 1977 } 1978 return (-1); 1979 } 1980 1981 void 1982 check_and_set_mirrors(int node, int mirror) 1983 { 1984 1985 if (minidsp) { 1986 (void) fprintf(stderr, 1987 gettext("%s: minidsp defined. " 1988 "Cannot define other nodes.\n"), 1989 progname); 1990 exit(1); 1991 } 1992 1993 if (mirror == _SD_NO_HOST) { 1994 minidsp++; 1995 } else if ((!(node % 2) && !(node == mirror - 1)) || 1996 (((node % 2) && !(node == mirror + 1)))) { 1997 (void) fprintf(stderr, 1998 gettext("%s: Node and Mirror identification values " 1999 "must be consecutive\n" 2000 "starting at an even number (Node = %d Mirror = %d)\n"), 2001 progname, node, mirror); 2002 exit(1); 2003 } 2004 2005 node_defined[node]++; 2006 2007 nodes_conf[nodes_configured] = node; 2008 nodes_configured++; 2009 2010 if (node == myid) { 2011 user_level_conf.mirror_host = mirror; 2012 } 2013 } 2014 2015 char *mem_string = 2016 "%-8s Structures use approx. %8d bytes (%5d pages) of memory\n"; 2017 2018 void 2019 enable_sdbc() 2020 { 2021 spcs_s_info_t ustats; 2022 2023 if (get_cache_config()) { 2024 (void) fprintf(stderr, 2025 gettext("%s: unable to read configuration file\n"), 2026 progname); 2027 exit(1); 2028 } 2029 2030 if (SDBC_IOCTL(SDBC_ENABLE, &user_level_conf, 0, 0, 0, 0, 2031 &ustats) == SPCS_S_ERROR) { 2032 (void) fprintf(stderr, gettext("%s: cache enable failed\n"), 2033 progname); 2034 spcs_log("scm", &ustats, gettext("%s cache enable failed"), 2035 progname); 2036 sdbc_report_error(&ustats); 2037 exit(1); 2038 } 2039 spcs_log("scm", NULL, gettext("%s cache enable succeeded"), 2040 progname); 2041 #ifdef DEBUG 2042 (void) printf(gettext("%s: cache has been configured\n"), progname); 2043 #endif 2044 #ifdef WRTHRU_HINTS 2045 if (iscluster()) { 2046 /* Must writethru on a cluster, even if nvram configured */ 2047 forced_wrthru = 1; 2048 } 2049 2050 if (minidsp && forced_wrthru != -1) { 2051 /* Have minidsp with forced_wrthru hint. Set / Clear hint */ 2052 if (SDBC_IOCTL(SDBC_SET_NODE_HINT, NSC_FORCED_WRTHRU, 2053 forced_wrthru, 0, 0, 0, &ustats) == SPCS_S_ERROR) { 2054 (void) fprintf(stderr, 2055 gettext("%s: set/clear forced_wrthru failed\n"), 2056 progname); 2057 sdbc_report_error(&ustats); 2058 } else if (forced_wrthru) { 2059 (void) printf(gettext("%s: Node option forced_wrthru " 2060 "now set.\n"), progname); 2061 } else { 2062 (void) printf(gettext("%s: Node option forced_wrthru " 2063 "now cleared.\n"), progname); 2064 } 2065 } 2066 if (no_forced_wrthru != -1) { 2067 if (SDBC_IOCTL(SDBC_SET_NODE_HINT, NSC_NO_FORCED_WRTHRU, 2068 no_forced_wrthru, 0, 0, 0, &ustats) == SPCS_S_ERROR) { 2069 (void) fprintf(stderr, 2070 gettext("%s: set/clear no_forced_wrthru " 2071 "failed\n"), progname); 2072 sdbc_report_error(&ustats); 2073 } else if (no_forced_wrthru) { 2074 (void) printf(gettext("%s: Node option no_forced_wrthru" 2075 " now set.\n"), progname); 2076 } else { 2077 (void) printf(gettext("%s: Node option no_forced_wrthru" 2078 " now cleared.\n"), progname); 2079 } 2080 } 2081 #endif 2082 2083 /* do scmadm -O to cater for manual cache disable then enable */ 2084 restore_hints(); 2085 } 2086 2087 void 2088 disable_sdbc() 2089 { 2090 spcs_s_info_t ustats; 2091 2092 if (SDBC_IOCTL(SDBC_DISABLE, 0, 0, 0, 0, 0, &ustats) != SPCS_S_OK) { 2093 /* 2094 * If it wasn't already enabled, don't appear to fail 2095 * or users of this program might think the cache is 2096 * configured, when it actually isn't. 2097 */ 2098 if (errno != SDBC_EDISABLE) { 2099 spcs_log("scm", &ustats, 2100 gettext("%s cache disable failed"), progname); 2101 sdbc_report_error(&ustats); 2102 exit(1); 2103 } 2104 } 2105 #ifdef DEBUG 2106 (void) printf(gettext("%s: cache has been deconfigured\n"), progname); 2107 #endif 2108 spcs_log("scm", NULL, gettext("%s cache disable succeeded"), 2109 progname); 2110 } 2111 2112 static void 2113 get_version() 2114 { 2115 cache_version_t version; 2116 spcs_s_info_t ustats; 2117 2118 if (SDBC_IOCTL(SDBC_VERSION, &version, 0, 0, 0, 0, &ustats) == 2119 SPCS_S_ERROR) { 2120 (void) fprintf(stderr, 2121 gettext("%s: get cache version failed\n"), progname); 2122 sdbc_report_error(&ustats); 2123 exit(1); 2124 } 2125 #ifdef DEBUG 2126 (void) printf(gettext("Cache version %d.%d.%d.%d\n"), 2127 version.major, version.minor, version.micro, version.baseline); 2128 #else 2129 if (version.micro) { 2130 (void) printf(gettext("Cache version %d.%d.%d\n"), 2131 version.major, version.minor, version.micro); 2132 } else { 2133 (void) printf(gettext("Cache version %d.%d\n"), 2134 version.major, version.minor); 2135 } 2136 #endif 2137 } 2138 2139 #ifdef DEBUG 2140 int 2141 toggle_flush(void) 2142 { 2143 int rc; 2144 spcs_s_info_t ustats; 2145 2146 if ((rc = SDBC_IOCTL(SDBC_TOGGLE_FLUSH, 0, 0, 0, 2147 0, 0, &ustats)) == SPCS_S_ERROR) { 2148 (void) fprintf(stderr, 2149 gettext("%s: toggle sdbc cache flush failed\n"), 2150 progname); 2151 sdbc_report_error(&ustats); 2152 exit(1); 2153 } 2154 return (rc); 2155 } 2156 #endif 2157