8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / avs / sdbc / scmadm.c
blobf0a28bbf81062008ed0eb10d05bad0b22d22c182
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Utility for cache configuration
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>
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>
54 #include <sys/nsctl/cfg.h>
55 #define STATS_PATH "/usr/bin/sd_stats"
57 #define _SD_FNAME /* bring in function names from sd_trace.h */
58 #include <sys/nsctl/sd_trace.h>
59 #include <sys/syslog.h>
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.
67 #ifdef DEBUG
68 #define WRTHRU_HINTS
69 #endif
71 static int sdbc_max_devices = 0;
73 static char alert_file[200] = "/dev/console";
75 /* Variables used to set up paramater block passed to kernel */
76 static _sd_cache_param_t user_level_conf;
77 static int myid;
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];
86 #define USAGELEN 1024
87 char stats_usage[USAGELEN+128];
88 char scmadmUsage[USAGELEN];
90 static caddr_t progname;
94 * Functions exported for fwcadm.
96 void enable_sdbc(void);
97 void disable_sdbc(void);
98 void sdbc_set_maxdev();
100 static void buildusage(char *);
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();
113 extern struct tm *localtime_r(const time_t *, struct tm *);
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); \
125 void
126 sdbc_report_error(spcs_s_info_t *ustatus)
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));
137 * Return the per-cd hints for a cd.
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.
143 static int
144 get_cd_hint(const int cd)
146 spcs_s_info_t ustats;
147 int nodehint, cdhint;
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);
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);
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;
175 return (cdhint | nodehint);
181 * Check for a config.
183 * If no suitable config can be found, install the default config.
185 * Calling state:
186 * libcfg locked (mode describes type of lock)
188 static void
189 convert_config(CFGFILE *cfg, CFGLOCK mode)
191 char buf[CFG_MAX_BUF];
192 char *default_cfg = "128 64";
194 retry:
195 if (cfg_get_cstring(cfg, "scm.set1", buf, sizeof (buf)) >= 0) {
196 /* config exists, return */
197 return;
200 cfg_rewind(cfg, CFG_SEC_CONF);
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);
214 mode = CFG_WRLOCK;
215 #ifdef DEBUG
216 (void) printf(gettext("%s: upgraded lock, retrying\n"),
217 progname);
218 #endif
219 goto retry;
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);
229 if (!cfg_commit(cfg)) {
230 (void) fprintf(stderr,
231 gettext("%s: unable to write to configuration: %s\n"),
232 progname, cfg_error(NULL));
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);
244 cfg_rewind(cfg, CFG_SEC_CONF);
248 static int
249 iscluster(void)
251 int rc;
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);
264 /* NOTREACHED */
268 static void
269 restore_hints()
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;
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);
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);
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;
298 if (strcmp(buf, "system") == 0) {
299 cd = -1;
300 } else {
301 cd = get_cd(buf);
302 if (cd < 0)
303 continue;
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;
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);
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);
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;
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);
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);
361 cfg_close(cfg);
364 void
365 sdbc_set_maxdev()
367 spcs_s_info_t ustats;
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);
378 static void
379 bitmapfs_print(void)
381 CFGFILE *cfg;
382 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF];
383 int setnumber;
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);
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);
400 for (setnumber = 1; /*CSTYLED*/; setnumber++) {
401 (void) snprintf(key, sizeof (key),
402 "bitmaps.set%d.bitmap", setnumber);
403 buf[0] = 0;
405 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) {
406 if (errno == ESRCH) {
407 /* end of list */
408 break;
411 (void) fprintf(stderr,
412 gettext("%s: error reading configuration: %s\n"),
413 progname, cfg_error(NULL));
414 exit(1);
417 (void) printf("%s\n", buf);
420 cfg_close(cfg);
424 static void
425 bitmapfs_delete(char *bitmapfs)
427 CFGFILE *cfg;
428 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF];
429 int setnumber;
430 int commit = 0;
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);
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);
447 for (setnumber = 1; /*CSTYLED*/; setnumber++) {
448 (void) snprintf(key, sizeof (key),
449 "bitmaps.set%d.bitmap", setnumber);
450 buf[0] = 0;
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;
462 (void) fprintf(stderr,
463 gettext("%s: error reading configuration: %s\n"),
464 progname, cfg_error(NULL));
465 exit(1);
468 if (strcmp(bitmapfs, buf) == 0) {
469 (void) snprintf(key, sizeof (key),
470 "bitmaps.set%d", setnumber);
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++;
480 break;
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));
491 commit = 0;
494 cfg_close(cfg);
499 * User visible configuration.
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 }
522 static int
523 configure_sdbc(int argc, char *argv[], int optind)
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;
532 error = commit = 0;
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);
541 if (argc == optind) {
542 /* display current user visible config */
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;
552 convert_config(cfg, CFG_RDLOCK);
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;
571 (void) printf("%-*s: %-*s /* %s */\n",
572 opt_width, sdbc_cfg_options[i].name,
573 opt_width, buf, sdbc_cfg_options[i].help);
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;
584 convert_config(cfg, CFG_WRLOCK);
586 for (/*CSTYLED*/; optind < argc; optind++) {
587 (void) strncpy(option, argv[optind], sizeof (option));
588 option[sizeof (option) - 1] = '\0'; /* terminate */
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';
597 if (*value == '\0')
598 (void) strncpy(value, "-",
599 sizeof (value));
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;
611 if (!found) {
612 (void) fprintf(stderr,
613 gettext("%s: unknown configuration "
614 "parameter: %s\n"), progname, option);
615 continue;
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;
629 if (*buf == '\0')
630 (void) strncpy(buf, "<default>", sizeof (buf));
632 if (cp != NULL) {
633 char *tmp;
634 long val;
635 /* set to new value */
637 if (strcmp(value, "-")) { /* default ? */
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;
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);
656 * Overwrite the
657 * cache size with
658 * the maximum cache
659 * size.
661 (void) snprintf(value,
662 sizeof (value),
663 "%ld",
664 (long)
665 MAX_CACHE_SIZE);
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;
680 (void) snprintf(buf, sizeof (buf),
681 "%s = %s", buf,
682 (strcmp(value, "-") == 0) ?
683 "<default>" : value);
685 commit = 1;
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 */
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));
702 commit = 0;
704 (void) printf("\n%s\n",
705 gettext("Changed configuration parameters "
706 "will take effect when the cache is restarted"));
709 cfg_close(cfg);
710 return (error);
714 static char *
715 cd_to_device(int cd)
717 static _sd_stats_t *cs_cur = NULL;
718 spcs_s_info_t ustatus;
720 if (cs_cur == NULL) {
721 cs_cur = malloc(sizeof (_sd_stats_t) +
722 (sdbc_max_devices - 1) * sizeof (_sd_shared_t));
724 if (cs_cur == NULL) {
725 (void) fprintf(stderr, gettext("%s malloc: %s\n"),
726 progname, strerror(errno));
727 exit(1);
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);
738 if (cs_cur->st_cachesize == 0 || cd >= cs_cur->st_count)
739 return ("");
741 return (cs_cur->st_shared[cd].sh_filename);
745 * takes either either a string containing the cd or the device name, and
746 * returns the device name.
748 static char *
749 get_device_name(char *arg)
751 long cd = 0;
752 char *device;
754 /* if the arg has a leading '/', assume it's a valid device name */
755 if (!arg || *arg == '/') {
756 return (arg);
759 /* treat the "all" keyword as a valid device name */
760 if (strcmp(arg, "all") == 0) {
761 return (arg);
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.
768 * Since strtol returns 0 on failure, we need to make a special case
769 * for a cd of "0", which is valid.
771 if (((cd = strtol(arg, (char **)NULL, 10)) > 0) ||
772 strcmp(arg, "0") == 0) {
773 device = cd_to_device((int)cd);
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);
782 return (NULL);
785 static void
786 remove_hint(char *device)
788 CFGFILE *cfg;
789 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF];
790 int setnumber;
791 int rc;
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);
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);
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;
814 if (strcmp(device, buf) != 0)
815 continue;
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;
838 cfg_close(cfg);
842 static void
843 save_hint(int cd, int hint, int flag)
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;
852 if (hint != NSC_WRTHRU && hint != NSC_NOCACHE)
853 return;
855 if (flag != 0 && flag != 1)
856 return;
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);
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);
871 if (cd == -1)
872 (void) strcpy(device, "system");
873 else
874 (void) strncpy(device, cd_to_device(cd), NSC_MAXPATH);
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;
885 if (strcmp(device, buf) == 0) {
886 found = 1;
887 break;
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));
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);
924 #ifdef lint
926 scmadm_lintmain(int argc, char *argv[])
927 #else
929 main(int argc, char *argv[])
930 #endif
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");
951 (void) setlocale(LC_ALL, "");
952 (void) textdomain("scm");
954 progname = strdup(basename(argv[0]));
956 sdbc_set_maxdev();
958 buildusage(progname);
960 Dopt = Lopt = 0;
962 while ((c = getopt(argc, argv,
963 #ifdef DEBUG
964 "gi:t:S"
965 #endif
966 "CD:LOa:devqhm:o:")) != EOF) {
968 switch (c) {
970 case 'D':
971 if (optflag) {
972 (void) fprintf(stderr, exclusive);
973 goto usage;
976 Dopt++;
977 optflag++;
978 bitmapfs = optarg;
979 break;
981 case 'L':
982 if (optflag) {
983 (void) fprintf(stderr, exclusive);
984 goto usage;
987 Lopt++;
988 optflag++;
989 break;
991 #ifdef DEBUG
992 case 'S':
993 if (optflag) {
994 (void) fprintf(stderr, exclusive);
995 goto usage;
998 if (putenv(stats_usage) != 0) {
999 (void) fprintf(stderr,
1000 gettext("%s: unable to putenv()\n"),
1001 progname);
1002 exit(1);
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"));
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);
1046 errflg++;
1048 optflag++;
1049 o = c;
1050 break;
1051 case 'h':
1052 hflag = 1;
1053 break;
1054 case '?':
1055 default:
1056 errflg++;
1057 break;
1059 if (errflg || hflag)
1060 goto usage;
1063 if (Oopt) {
1064 /* Set hints saved in persistent configuration */
1065 restore_hints();
1066 exit(0);
1068 if (Dopt || Lopt) {
1069 /* bitmapfs control */
1071 if (iscluster()) {
1072 (void) fprintf(stderr,
1073 gettext("%s: bitmap filesystems are not "
1074 "allowed in a cluster\n"), progname);
1075 goto usage;
1078 if ((Dopt + Lopt) > 1) {
1079 (void) fprintf(stderr, gettext("-D and -L are"
1080 "mutually exclusive\n"));
1081 goto usage;
1084 if (Lopt)
1085 bitmapfs_print();
1086 else /* if (Dopt) */
1087 bitmapfs_delete(bitmapfs);
1089 exit(0);
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();
1100 /* Configure */
1101 if (o == 'C') {
1102 exit(configure_sdbc(argc, argv, optind));
1104 /* enable */
1105 if (o == 'e') {
1106 enable_sdbc();
1107 if (qflag == 0)
1108 sd_gather_alert_dumps();
1109 exit(0);
1111 /* disable */
1112 if (o == 'd') {
1113 disable_sdbc();
1114 exit(0);
1116 /* get version */
1117 if (o == 'v') {
1118 get_version();
1119 exit(0);
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);
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);
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);
1159 save_hint(-1, hint, flag);
1160 (void) printf(gettext("%s: System option %s"
1161 " now set.\n"), progname, argv[optind]);
1162 exit(0);
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);
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);
1190 if (cd < 0) {
1191 (void) fprintf(stderr,
1192 gettext("%s: device %s not "
1193 "found\n"),
1194 progname, optarg);
1195 exit(1);
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);
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);
1214 if (o == 'm') { /* "get_cd" = map */
1215 char *dev_name;
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);
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);
1235 (void) printf(gettext("%s: diskname %s; cd %d\n"),
1236 progname, dev_name, cd);
1237 exit(0);
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);
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;
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);
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);
1288 if (o == 'i') { /* "inject_ioerr" */
1289 int ioj_err = EIO;
1290 int cd;
1291 int ioj_cnt = 0;
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);
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);
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);
1315 (void) printf(gettext("%s: i/o error injection cd %d errno %d "
1316 "processed\n"), progname, cd, ioj_err);
1317 exit(0);
1320 if (o == 'c') { /* "clear_ioerr" */
1321 int cd;
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);
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);
1341 (void) printf(gettext("%s: i/o error clear for cd %d "
1342 "processed\n"), progname, cd);
1343 exit(0);
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);
1352 #endif /* DEBUG */
1354 return (0);
1355 usage:
1356 (void) fprintf(stderr, "%s\n", scmadmUsage);
1357 if (hflag) {
1358 return (0);
1360 return (1);
1364 #define addusage(f__) \
1365 (void) strncat(scmadmUsage, f__, sizeof (scmadmUsage));
1367 #define addusage1(f__, a__) \
1368 (void) snprintf(fmt, sizeof (fmt), "%s%s", scmadmUsage, f__); \
1369 (void) snprintf(scmadmUsage, sizeof (scmadmUsage), fmt, a__);
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__);
1375 static void
1376 buildusage(char *p)
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
1385 bzero(scmadmUsage, sizeof (scmadmUsage));
1386 bzero(fmt, sizeof (fmt));
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"));
1422 #ifdef DEBUG
1423 (void) snprintf(stats_usage, sizeof (stats_usage),
1424 "SD_STATS_USAGE=%s", scmadmUsage);
1425 #endif
1428 static int
1429 get_hint(char *str, int *hint, int *flag)
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);
1455 return (-1);
1458 /*ARGSUSED*/
1459 void
1460 print_hint(const uint_t type, const int status)
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"));
1470 } else {
1471 (void) printf("%swrthru, %srdcache",
1472 (type & (NSC_FORCED_WRTHRU|NSC_WRTHRU)) ? "" : "no",
1473 (type & NSC_NOCACHE) ? "no" : "");
1474 #else
1476 (void) printf("%srdcache", (type & NSC_NOCACHE) ? "no" : "");
1477 #endif
1479 if (type & 0x80000000)
1480 (void) printf(" (overridden by system)");
1482 (void) printf("\n");
1487 * Read the configuration via libcfg
1491 get_cache_config()
1493 int i;
1494 int sysid;
1495 CFGFILE *cfg;
1496 char buf[CFG_MAX_BUF];
1497 char key[CFG_MAX_KEY];
1500 if ((cfg = cfg_open(NULL)) == NULL) {
1501 (void) fprintf(stderr,
1502 gettext("Cannot open configuration file\n"));
1503 exit(1);
1506 if (!cfg_lock(cfg, CFG_RDLOCK)) {
1507 (void) fprintf(stderr,
1508 gettext("Cannot lock configuration file\n"));
1509 exit(1);
1512 convert_config(cfg, CFG_RDLOCK);
1513 (void) memset((char *)&user_level_conf, 0, sizeof (_sd_cache_param_t));
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);
1522 myid = sysid;
1524 user_level_conf.blk_size = 8192; /* DEFAULT */
1525 user_level_conf.procs = 16; /* DEFAULT */
1526 user_level_conf.reserved1 = RESERVED1_DEFAULTS;
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 */
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);
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);
1545 (void) snprintf(key, sizeof (key), "scm.set1.size");
1546 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) > 0) {
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.
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;
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);
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;
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);
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);
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);
1592 cfg_close(cfg);
1595 * use the default minidsp configuration if no
1596 * node/mirror/remote-mirror/cluster line is in the sd.cf file
1598 if (nodes_configured == 0)
1599 check_and_set_mirrors(myid, _SD_NO_HOST);
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);
1610 * Save off number of nodes so we can calculate the point-to-point
1611 * segements. Code in kernel currently supports MAX_SD_NODES
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);
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);
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];
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);
1643 _sdtr_t hdr;
1645 /* function name string */
1646 char *
1647 _sd_fname(int f)
1649 int fn = f & ST_FUNC;
1650 static char c[8];
1651 char *s;
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);
1672 int alerts = 0;
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.
1680 void
1681 sd_gather_alert_dumps()
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;
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);
1706 (void) setsid();
1708 size = 10000;
1709 if (size < user_level_conf.trace_size)
1710 size = user_level_conf.trace_size;
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);
1718 tloc = time(NULL);
1719 tm_ptr = (struct tm *)localtime_r(&tloc, &tm_storage);
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);
1735 if (errno == ENOSYS)
1736 exit(0);
1737 exit(errno);
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);
1749 * write header to identify device, write entries
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);
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);
1765 (void) close(fd);
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;
1775 * print list of configured cd's, diskname, options and global options
1777 void
1778 print_all_options()
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;
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);
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);
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);
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);
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);
1846 (void) printf(gettext("%d\t%-28.*s\t"), cd,
1847 NSC_MAXPATH, fn);
1849 print_hint(hint, 0);
1853 exit(0);
1858 * cache device -- lookup names and cache descriptors of all configured devices
1860 void
1861 get_cd_all()
1863 static _sd_stats_t *cs_cur;
1864 spcs_s_info_t ustats;
1865 int cd;
1866 char fn[19];
1867 int len;
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);
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);
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);
1903 (void) printf(gettext("\t%d\t%s\n"),
1904 cd, fn);
1908 exit(0);
1912 * cache device -- specified by number or lookup name
1914 static int
1915 get_cd(char *s)
1917 static _sd_stats_t *cs_cur = NULL;
1918 spcs_s_info_t ustats;
1919 int cd, arg_cd = -1;
1921 if (cs_cur == NULL) {
1923 * No corresponding free because the memory is reused
1924 * every time the function is called.
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);
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);
1941 if (cs_cur->st_cachesize == 0) {
1942 (void) printf(gettext("Cache is disabled\n"));
1943 exit(0);
1946 if (*s != '/') {
1948 * Since strtol returns 0 on failure, we need to make a
1949 * special case for a cd of "0", which is valid.
1951 * This case also deals with the difference between
1952 * scmadm -o system and scmadm -o 0
1954 if (((int)strtol(s, (char **)NULL, 10) == 0) &&
1955 strcmp(s, "0"))
1956 return (-1);
1959 * Only return failure at this point, in order to allow
1960 * checking arg_cd against st_count later on.
1962 if ((arg_cd = strtol(s, 0, 0)) < 0) {
1963 return (arg_cd);
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);
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);
1978 return (-1);
1981 void
1982 check_and_set_mirrors(int node, int mirror)
1985 if (minidsp) {
1986 (void) fprintf(stderr,
1987 gettext("%s: minidsp defined. "
1988 "Cannot define other nodes.\n"),
1989 progname);
1990 exit(1);
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);
2005 node_defined[node]++;
2007 nodes_conf[nodes_configured] = node;
2008 nodes_configured++;
2010 if (node == myid) {
2011 user_level_conf.mirror_host = mirror;
2015 char *mem_string =
2016 "%-8s Structures use approx. %8d bytes (%5d pages) of memory\n";
2018 void
2019 enable_sdbc()
2021 spcs_s_info_t ustats;
2023 if (get_cache_config()) {
2024 (void) fprintf(stderr,
2025 gettext("%s: unable to read configuration file\n"),
2026 progname);
2027 exit(1);
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);
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;
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);
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);
2081 #endif
2083 /* do scmadm -O to cater for manual cache disable then enable */
2084 restore_hints();
2087 void
2088 disable_sdbc()
2090 spcs_s_info_t ustats;
2092 if (SDBC_IOCTL(SDBC_DISABLE, 0, 0, 0, 0, 0, &ustats) != SPCS_S_OK) {
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.
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);
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);
2112 static void
2113 get_version()
2115 cache_version_t version;
2116 spcs_s_info_t ustats;
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);
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);
2136 #endif
2139 #ifdef DEBUG
2141 toggle_flush(void)
2143 int rc;
2144 spcs_s_info_t ustats;
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);
2154 return (rc);
2156 #endif