16429Svs195195 /*
26429Svs195195 * CDDL HEADER START
36429Svs195195 *
46429Svs195195 * The contents of this file are subject to the terms of the
56429Svs195195 * Common Development and Distribution License (the "License").
66429Svs195195 * You may not use this file except in compliance with the License.
76429Svs195195 *
86429Svs195195 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96429Svs195195 * or http://www.opensolaris.org/os/licensing.
106429Svs195195 * See the License for the specific language governing permissions
116429Svs195195 * and limitations under the License.
126429Svs195195 *
136429Svs195195 * When distributing Covered Code, include this CDDL HEADER in each
146429Svs195195 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156429Svs195195 * If applicable, add the following below this CDDL HEADER, with the
166429Svs195195 * fields enclosed by brackets "[]" replaced with your own identifying
176429Svs195195 * information: Portions Copyright [yyyy] [name of copyright owner]
186429Svs195195 *
196429Svs195195 * CDDL HEADER END
206429Svs195195 */
216429Svs195195
226429Svs195195 /*
236429Svs195195 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
246429Svs195195 * Use is subject to license terms.
256429Svs195195 */
266429Svs195195
276429Svs195195 #include <stdio.h>
286429Svs195195 #include <string.h>
296429Svs195195 #include <sys/types.h>
306429Svs195195 #include <dirent.h>
316429Svs195195 #include <stdarg.h>
326429Svs195195 #include <stddef.h>
336429Svs195195 #include <stdlib.h>
346429Svs195195 #include <dlfcn.h>
356429Svs195195 #include <door.h>
366429Svs195195 #include <errno.h>
376429Svs195195 #include <fcntl.h>
386429Svs195195 #include <strings.h>
396429Svs195195 #include <unistd.h>
406429Svs195195 #include <synch.h>
416429Svs195195 #include <syslog.h>
426429Svs195195 #include <pthread.h>
436429Svs195195 #include <thread.h>
446429Svs195195 #include <signal.h>
456429Svs195195 #include <limits.h>
466429Svs195195 #include <locale.h>
476429Svs195195 #include <sys/stat.h>
486429Svs195195 #include <sys/systeminfo.h>
496429Svs195195 #include <sys/wait.h>
506429Svs195195 #include <sys/processor.h>
516429Svs195195 #include <ctype.h>
526429Svs195195 #include <poll.h>
536429Svs195195 #include <sys/wait.h>
546429Svs195195 #include <dirent.h>
556429Svs195195 #include <kstat.h>
566429Svs195195 #include <libscf.h>
576429Svs195195 #include <sys/pset.h>
586429Svs195195 #include <sys/param.h>
596429Svs195195 #include <sys/corectl.h>
606429Svs195195 #include <libgen.h>
616429Svs195195 #include <priv_utils.h>
626429Svs195195 #include <fpsapi.h>
636429Svs195195
646429Svs195195 #include "fpsd.h"
656429Svs195195 #include "messages.h"
666429Svs195195
677346SVaidehi.Rangan@Sun.COM #define SMF_SNAPSHOT_RUNNING "running"
687346SVaidehi.Rangan@Sun.COM
696429Svs195195 /* Only messages of priority 'debug_level' and lower will be logged */
706429Svs195195 int debug_level = DFLT_DBG_LVL;
716429Svs195195
726429Svs195195 fpsd_t fpsd;
736429Svs195195 mach_conf_t fpsd_conf;
746429Svs195195 char fps_tst_path[MAXPATHLEN + MAXNAMELEN];
756429Svs195195
766429Svs195195 void terminate_process();
776429Svs195195
786429Svs195195 /* Local Static Variables */
796429Svs195195
806429Svs195195 static int door_id = -1;
816429Svs195195 static char *str_fps_fmri = NULL;
826429Svs195195
836429Svs195195 /* Local static functions */
846429Svs195195
856429Svs195195 static int check_if_supported_CPU(char *cpu_brand, char *arch);
866429Svs195195 static int read_conf_props();
876429Svs195195 static void fpsd_fini();
886429Svs195195 static int reprobe_and_reread_config();
896429Svs195195 static int fpsd_probe_config();
906429Svs195195 static int fpsd_probe(mach_conf_t *m_stat);
916429Svs195195
926429Svs195195
936429Svs195195 /* ARGSUSED */
946429Svs195195 void
sig_hup_handler(int sig,siginfo_t * siginfo,void * sigctx)956429Svs195195 sig_hup_handler(int sig, siginfo_t *siginfo, void *sigctx)
966429Svs195195 {
976429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO,
986429Svs195195 SIGNAL_INFO, "HUP", SIGHUP);
997346SVaidehi.Rangan@Sun.COM fpsd.d_conf->m_reprobe = 1;
1006429Svs195195 }
1016429Svs195195
1026429Svs195195 void
fpsd_read_config()1036429Svs195195 fpsd_read_config()
1046429Svs195195 {
1056429Svs195195 int ret;
1066429Svs195195
1076429Svs195195 ret = reprobe_and_reread_config();
1086429Svs195195 if (NO_CPUS_2_TEST == ret) {
1096429Svs195195 while (NO_CPUS_2_TEST == ret) {
1107346SVaidehi.Rangan@Sun.COM if (!fpsd.d_conf->m_reprobe) {
1117346SVaidehi.Rangan@Sun.COM (void) sleep(600);
1127346SVaidehi.Rangan@Sun.COM }
1136429Svs195195 ret = reprobe_and_reread_config();
1146429Svs195195 }
1156429Svs195195 }
1166429Svs195195 }
1176429Svs195195
1186429Svs195195 static int
reprobe_and_reread_config()1196429Svs195195 reprobe_and_reread_config()
1206429Svs195195 {
1216429Svs195195 int ret;
1227346SVaidehi.Rangan@Sun.COM static int first_time = 1;
1236429Svs195195
1247346SVaidehi.Rangan@Sun.COM if (!first_time) {
1257346SVaidehi.Rangan@Sun.COM fpsd.d_conf->m_reprobe = 1;
1267346SVaidehi.Rangan@Sun.COM if (fpsd_probe(fpsd.d_conf) != 0) {
1277346SVaidehi.Rangan@Sun.COM (void) fpsd_message(FPSD_EXIT_ERROR,
128*7435SVaidehi.Rangan@Sun.COM FPS_WARNING, REPROBE_FAILURE);
1297346SVaidehi.Rangan@Sun.COM }
1307346SVaidehi.Rangan@Sun.COM } else {
1317346SVaidehi.Rangan@Sun.COM first_time = 0;
1326429Svs195195 }
1336429Svs195195 ret = fpsd_probe_config();
1346429Svs195195 if (ZERO_INTERVAL == ret) {
135*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_EXIT_ERROR, FPS_WARNING,
1366429Svs195195 FPSD_ZERO_INTVL, fpsd.d_interval);
1376429Svs195195 }
1386429Svs195195 return (ret);
1396429Svs195195
1406429Svs195195 }
1416429Svs195195
1426429Svs195195 static int
daemon_exists()1436429Svs195195 daemon_exists()
1446429Svs195195 {
1456429Svs195195 int door_fd;
1466429Svs195195 struct door_info dinfo;
1476429Svs195195
1486429Svs195195 door_fd = open(FPS_DOOR_FILE, O_RDONLY);
1496429Svs195195 if (door_fd < 0)
1506429Svs195195 return (NO_DAEMON);
1516429Svs195195 if (door_info(door_fd, &dinfo) < 0) {
1526429Svs195195 (void) close(door_fd);
1536429Svs195195 return (NO_DAEMON);
1546429Svs195195 }
1556429Svs195195 if ((dinfo.di_attributes & DOOR_REVOKED) ||
1566429Svs195195 (dinfo.di_data != (uintptr_t)FPS_DOOR_COOKIE)) {
1576429Svs195195 (void) close(door_fd);
1586429Svs195195 return (NO_DAEMON);
1596429Svs195195 }
1606429Svs195195 if (dinfo.di_target != getpid()) {
1616429Svs195195 /* Daemon exists; different process */
1626429Svs195195 (void) close(door_fd);
1636429Svs195195 return (DAEMON_EXISTS);
1646429Svs195195 } else {
1656429Svs195195 (void) close(door_fd);
1666429Svs195195 return (DAEMON_EXISTS_AND_SAME_PROC); /* Same process */
1676429Svs195195 }
1686429Svs195195
1696429Svs195195 }
1706429Svs195195
1716429Svs195195 static int
fps_setup_door(void)1726429Svs195195 fps_setup_door(void)
1736429Svs195195 {
1746429Svs195195
1756429Svs195195 struct stat stbuf;
1766429Svs195195 int newfd;
1776429Svs195195
1786429Svs195195 /* Create the door */
1796429Svs195195 door_id = door_create(fps_door_handler, FPS_DOOR_COOKIE, 0);
1806429Svs195195
1816429Svs195195 if (door_id < 0) {
182*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_WARNING, DAEMON_DOOR_FAIL,
1836429Svs195195 strerror(errno));
1846429Svs195195 return (-1);
1856429Svs195195 }
1866429Svs195195
1876429Svs195195 if (stat(FPS_DOOR_FILE, &stbuf) < 0) {
1886429Svs195195 if ((newfd = creat(FPS_DOOR_FILE, 0600)) < 0) {
1896429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR,
1906429Svs195195 DAEMON_DOOR_FILE_FAIL, strerror(errno));
1916429Svs195195 return (-1);
1926429Svs195195 }
1936429Svs195195 (void) close(newfd);
1946429Svs195195 }
1956429Svs195195
1966429Svs195195 if (fattach(door_id, FPS_DOOR_FILE) < 0) {
1976429Svs195195 if ((errno != EBUSY) || (fdetach(FPS_DOOR_FILE) < 0) ||
1986429Svs195195 (fattach(door_id, FPS_DOOR_FILE) < 0)) {
1996429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR,
2006429Svs195195 DAEMON_DOOR_FATTACH_FAIL,
2016429Svs195195 strerror(errno));
2026429Svs195195 return (-1);
2036429Svs195195 }
2046429Svs195195 }
2056429Svs195195
2066429Svs195195 return (0);
2076429Svs195195 }
2086429Svs195195
2096429Svs195195 void
terminate_process()2106429Svs195195 terminate_process()
2116429Svs195195 {
2126429Svs195195 fpsd_fini();
2136429Svs195195 if (door_id >= 0) {
2146429Svs195195 (void) door_revoke(door_id);
2156429Svs195195 (void) unlink(FPS_DOOR_FILE);
2166429Svs195195 }
2176429Svs195195 }
2186429Svs195195
2196429Svs195195 static int
become_daemon_init()2206429Svs195195 become_daemon_init()
2216429Svs195195 {
2226429Svs195195 int pfds[2];
2236429Svs195195 pid_t pid;
2246429Svs195195 int status;
2256429Svs195195 sigset_t set, oset;
2266429Svs195195
2276429Svs195195 /*
2286429Svs195195 * Block all signals prior to the fork and leave them blocked in
2296429Svs195195 * the parent so we don't get in a situation where the parent gets
2306429Svs195195 * SIGINT and returns non-zero exit status and the child is
2316429Svs195195 * actually running. In the child, restore the signal mask once
2326429Svs195195 * we've done our setsid().
2336429Svs195195 */
2346429Svs195195 (void) sigfillset(&set);
2356429Svs195195 (void) sigdelset(&set, SIGABRT);
2366429Svs195195 (void) sigdelset(&set, SIGHUP);
2376429Svs195195 (void) sigprocmask(SIG_BLOCK, &set, &oset);
2386429Svs195195
2396429Svs195195
2406429Svs195195 if (pipe(pfds) == -1)
2416429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, DAEMON_PIPE_FAIL,
2426429Svs195195 strerror(errno));
2436429Svs195195
2446429Svs195195 if ((pid = fork()) == -1)
2456429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, DAEMON_FORK_FAIL,
2466429Svs195195 strerror(errno));
2476429Svs195195
2486429Svs195195 /*
2496429Svs195195 * If we're the parent process, wait for either the child to send
2506429Svs195195 * us the appropriate exit status over the pipe or for the read to
2516429Svs195195 * fail (presumably with 0 for EOF if our child terminated
2526429Svs195195 * abnormally). If the read fails, exit with either the child's
2536429Svs195195 * exit status if it exited or with FPSD_EXIT_ERROR if it died
2546429Svs195195 * from a fatal signal.
2556429Svs195195 */
2566429Svs195195 if (pid != 0) { /* Parent */
2576429Svs195195 (void) close(pfds[1]);
2586429Svs195195
2596429Svs195195 if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
2606429Svs195195 _exit(status);
2616429Svs195195
2626429Svs195195 if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
2636429Svs195195 _exit(WEXITSTATUS(status));
2646429Svs195195
2656429Svs195195 _exit(FPSD_EXIT_ERROR);
2666429Svs195195 }
2676429Svs195195
2686429Svs195195 fpsd.d_pid = getpid();
2696429Svs195195 (void) sigprocmask(SIG_SETMASK, &oset, NULL); /* Restore signal mask */
2706429Svs195195 (void) setsid();
2716429Svs195195 (void) chdir("/");
2726429Svs195195 (void) umask(022);
2736429Svs195195 (void) close(pfds[0]);
2746429Svs195195 return (pfds[1]);
2756429Svs195195 }
2766429Svs195195
2776429Svs195195
2786429Svs195195 static void
become_daemon_fini(int fd)2796429Svs195195 become_daemon_fini(int fd)
2806429Svs195195 {
2816429Svs195195 (void) close(fd);
2826429Svs195195 if ((fd = open("/dev/null", O_RDWR)) >= 0) {
2836429Svs195195 (void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
2846429Svs195195 (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
2856429Svs195195 (void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
2866429Svs195195 (void) close(fd);
2876429Svs195195 }
2886429Svs195195
2896429Svs195195 }
2906429Svs195195
2916429Svs195195 /*
2926429Svs195195 * Calculates the number of iterations needed for each testable cpu
2936429Svs195195 * based on the frequency and using the following table. This table
2946429Svs195195 * tells how much time it takes for the matrix sizes on a processor
2956429Svs195195 * with frequencies upto 1000MHz/1500 MHz/ 2000 MHz. This data is
2966429Svs195195 * based on profiling done earlier.
2976429Svs195195 *
2986429Svs195195 * f\p\t| 100 200 300 400 500 600 700 800 900 ms
2996429Svs195195 * ======================================================================
3006429Svs195195 * 1000 1-28 29-50 51-62 63-72 73-81 82-90 91-98 99-105 106-112
3016429Svs195195 * 1500 1-36 37-64 65-80 81-93 94-106 107-115 116-126 127-134 135-144
3026429Svs195195 * 2000 1-39 40-70 71-87 88-102 103-113 114-126 127-137 138-148 149-157
3036429Svs195195 *
3046429Svs195195 * If asc is 0, these iterations will be executed in the descending of
3056429Svs195195 * of matrix size; else the iterations will be executed in the increasing
3066429Svs195195 * order of matrix sizes. This is done to average out the execution time
3076429Svs195195 * as large matrices mean more time to complete the test.
3086429Svs195195 */
3096429Svs195195
3106429Svs195195 static void
calculateTotalIterations(mach_conf_t * m_stat)3116429Svs195195 calculateTotalIterations(mach_conf_t *m_stat)
3126429Svs195195 {
3136429Svs195195 const int num_iterations_1K = 112;
3146429Svs195195 const int num_iterations_1500 = 144;
3156429Svs195195 const int num_iterations_2K = 157;
3166429Svs195195
3176429Svs195195 int total_iterations = 0;
3186429Svs195195 int asc = 1;
3196429Svs195195 int i;
3206429Svs195195 int freq;
3216429Svs195195
3226429Svs195195 if (m_stat->m_cpuids_size <= 0) {
323*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_EXIT_ERROR, FPS_WARNING,
324*7435SVaidehi.Rangan@Sun.COM ZERO_CPUS_2_TST);
3256429Svs195195 }
3266429Svs195195 m_stat->m_num_cpus_to_test = 0;
3276429Svs195195 for (i = 0; i < m_stat->m_cpuids_size; i++) {
3286429Svs195195 if (m_stat->m_cpus[i].disable_test)
3296429Svs195195 continue;
3306429Svs195195 freq = m_stat->m_cpus[i].frequency;
3316429Svs195195 m_stat->m_cpus[i].asc = asc;
3326429Svs195195 if (freq < 1500) {
3336429Svs195195 total_iterations += num_iterations_1K;
3346429Svs195195 m_stat->m_cpus[i].total_iterations = num_iterations_1K;
3356429Svs195195 } else if (freq < 2000) {
3366429Svs195195 total_iterations += num_iterations_1500;
3376429Svs195195 m_stat->m_cpus[i].total_iterations =
3386429Svs195195 num_iterations_1500;
3396429Svs195195 } else {
3406429Svs195195 total_iterations += num_iterations_2K;
3416429Svs195195 m_stat->m_cpus[i].total_iterations = num_iterations_2K;
3426429Svs195195 }
3436429Svs195195 if (asc) {
3446429Svs195195 m_stat->m_cpus[i].previous_iteration = 0;
3456429Svs195195 asc = 0;
3466429Svs195195 } else {
3476429Svs195195 m_stat->m_cpus[i].previous_iteration =
3486429Svs195195 m_stat->m_cpus[i].total_iterations + 1;
3496429Svs195195 asc = 1;
3506429Svs195195 }
3516429Svs195195 m_stat->m_num_cpus_to_test++;
3526429Svs195195 }
3536429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, TOT_ITERS,
3546429Svs195195 total_iterations, m_stat->m_num_cpus_to_test);
3556429Svs195195 fpsd.d_conf->total_iter = total_iterations;
3566429Svs195195 }
3576429Svs195195
3586429Svs195195 /*
3596429Svs195195 * Calculates the time interval between the tests invocation in seconds.
3606429Svs195195 * The goal is to complete once all iterations for all cpus in a 24hr
3616429Svs195195 * period.
3626429Svs195195 */
3636429Svs195195
3646429Svs195195 static int
calculateTimeInterval()3656429Svs195195 calculateTimeInterval()
3666429Svs195195 {
3676429Svs195195 int total_iterations = fpsd.d_conf->total_iter;
3686429Svs195195 int intvl;
3696429Svs195195
3706429Svs195195 if (total_iterations <= 0) {
371*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_EXIT_ERROR, FPS_WARNING,
372*7435SVaidehi.Rangan@Sun.COM FPSD_MIS_CALCULATIONS, total_iterations);
3736429Svs195195 }
3746429Svs195195 intvl = (24*60*60) / (total_iterations);
3756429Svs195195 fpsd.d_interval = intvl;
3766429Svs195195 return (1);
3776429Svs195195 }
3786429Svs195195
3796429Svs195195 /*
3806429Svs195195 * Checks if a platform is supported by looking for the corresponding
3816429Svs195195 * binary under /usr/lib/fps/ARCH/CPU_BRAND/fptest; (e.g) ARCH = sun4u,
3826429Svs195195 * CPU_BRAND = UltraSPARC-III;
3836429Svs195195 */
3846429Svs195195
3856429Svs195195 static int
check_if_supported_CPU(char * cpu_brand,char * arch)3866429Svs195195 check_if_supported_CPU(char *cpu_brand, char *arch)
3876429Svs195195 {
388*7435SVaidehi.Rangan@Sun.COM if ((NULL == cpu_brand) || (NULL == arch)) {
389*7435SVaidehi.Rangan@Sun.COM return (0);
390*7435SVaidehi.Rangan@Sun.COM }
3916429Svs195195 (void) snprintf(fps_tst_path, sizeof (fps_tst_path), "%s/%s/%s/%s",
3926429Svs195195 FPS_DIR, arch, cpu_brand, FPS_FPUTST_NAME);
3936429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, FPTST_BIN_PTH, fps_tst_path);
3946429Svs195195 if (access(fps_tst_path, X_OK) == 0)
3956429Svs195195 return (1);
3966429Svs195195 else
3976429Svs195195 return (0);
3986429Svs195195 }
3996429Svs195195
4006429Svs195195 /*
4016429Svs195195 * fpsd_probe(): probes system configuration and
4026429Svs195195 * sets up the fpsd_t structure.
4036429Svs195195 * Returns 0 on success, non-zero on failure.
4046429Svs195195 *
4056429Svs195195 */
4066429Svs195195 static int
fpsd_probe(mach_conf_t * m_stat)4076429Svs195195 fpsd_probe(mach_conf_t *m_stat)
4086429Svs195195 {
4096429Svs195195 kstat_ctl_t *kstat_ctl;
4106429Svs195195 kstat_t *fps_kstat;
4116429Svs195195 kstat_named_t *kstat_cpu_name;
4126429Svs195195 kstat_named_t *kstat_cpu_freq;
4136429Svs195195 char *cpu_brand = NULL;
4146429Svs195195 int cpu_freq;
4156429Svs195195 int supported;
4166429Svs195195 int i;
4176429Svs195195 int cpuid_index;
4186429Svs195195
4197346SVaidehi.Rangan@Sun.COM processorid_t *cpuid_list = NULL;
4206429Svs195195 kid_t ret;
4217101Svs195195 int total_onln = sysconf(_SC_NPROCESSORS_ONLN);
4226429Svs195195
4236429Svs195195 /* probe the system and fill in mach_conf_t elements */
4246429Svs195195
4256429Svs195195 (void) sysinfo(SI_MACHINE, m_stat->m_machine,
4266429Svs195195 sizeof (m_stat->m_machine) - 1);
4276429Svs195195
4286429Svs195195 if (1 == m_stat->m_reprobe) {
4296429Svs195195 /* Reprobe request */
4306429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, REPRBE_REQ);
4316429Svs195195 fpsd.d_iteration = 0;
4326429Svs195195 fpsd.d_interval = 0;
4336429Svs195195 fpsd.d_fpuid_index = 0;
4346429Svs195195 m_stat->m_num_on_fpuids = 0;
4356429Svs195195 m_stat->m_cpuids_size = 0;
4366429Svs195195 m_stat->total_iter = 0;
4376429Svs195195 m_stat->m_reprobe = 0;
4386429Svs195195 m_stat->m_num_cpus_to_test = 0;
4396429Svs195195
4406429Svs195195 if (NULL != fpsd.d_ignore_cpuid) {
4416429Svs195195 free(fpsd.d_ignore_cpuid);
4426429Svs195195 }
4436429Svs195195 }
4446429Svs195195
4456429Svs195195 /*
4466429Svs195195 * Find number of online FPUs, and initialize
4476429Svs195195 * m_stat->m_num_on_fpuids. Then collect kstat
4486429Svs195195 * cpu_info for each.
4496429Svs195195 */
4506429Svs195195
4517101Svs195195 cpuid_list = (processorid_t *)malloc(m_stat->m_num_fpus *
4526429Svs195195 sizeof (processorid_t));
4536429Svs195195 if (NULL == cpuid_list) {
4546429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO, LIBRARY_CALL_FAIL,
4556429Svs195195 "malloc", strerror(errno));
4566429Svs195195 return (-1);
4576429Svs195195 }
4587346SVaidehi.Rangan@Sun.COM /* Initialize cpuid_list */
4597346SVaidehi.Rangan@Sun.COM for (i = 0; i < m_stat->m_num_fpus; i++) {
4607346SVaidehi.Rangan@Sun.COM cpuid_list[i] = -1;
4617346SVaidehi.Rangan@Sun.COM }
4626429Svs195195
4636429Svs195195 cpuid_index = 0;
4647101Svs195195 for (i = 0; i < m_stat->m_max_cpuid; i++) {
4656429Svs195195 if (p_online(i, P_STATUS) == P_ONLINE) {
4666429Svs195195 cpuid_list[cpuid_index++] = i;
4676429Svs195195 }
4687101Svs195195 if (cpuid_index == total_onln) {
4696429Svs195195 /* Break after all onln cpuids found */
4706429Svs195195 break;
4716429Svs195195 }
4726429Svs195195 }
4737101Svs195195 m_stat->m_num_on_fpuids = (uint_t)cpuid_index;
4747101Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, NUM_ONLN_CPUS,
4757101Svs195195 m_stat->m_num_on_fpuids);
4766429Svs195195
4776429Svs195195 /*
4786429Svs195195 * Get cpu-brand info all valid cpuids using kstat.
4796429Svs195195 * This is needed to take care
4806429Svs195195 * of mixed cpu scenario
4816429Svs195195 */
4826429Svs195195
4836429Svs195195 kstat_ctl = kstat_open();
4846429Svs195195 if (NULL == kstat_ctl) {
485*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_WARNING, LIBRARY_CALL_FAIL,
4866429Svs195195 "kstat_open", strerror(errno));
4876429Svs195195 free(cpuid_list);
4886429Svs195195 return (-1);
4896429Svs195195 }
4906429Svs195195
4916429Svs195195
4926429Svs195195 for (i = 0; i < m_stat->m_num_on_fpuids; i++) {
4936429Svs195195
4946429Svs195195 supported = 0;
4956429Svs195195 fps_kstat = NULL;
4966429Svs195195
4977346SVaidehi.Rangan@Sun.COM if ((cpuid_list[i] < 0) ||
4987346SVaidehi.Rangan@Sun.COM (cpuid_list[i] >= m_stat->m_max_cpuid)) {
4997346SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_INFO,
5007346SVaidehi.Rangan@Sun.COM INVALID_CPUID, cpuid_list[i]);
5017346SVaidehi.Rangan@Sun.COM free(cpuid_list);
5027346SVaidehi.Rangan@Sun.COM return (-1);
5037346SVaidehi.Rangan@Sun.COM }
5046429Svs195195 fps_kstat = kstat_lookup(kstat_ctl, "cpu_info",
5056429Svs195195 cpuid_list[i], NULL);
5066429Svs195195 if (NULL == fps_kstat) {
5076429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO,
5086429Svs195195 LIBRARY_CALL_FAIL, "kstat_lookup",
5096429Svs195195 strerror(errno));
5107186Skk158166 (void) kstat_close(kstat_ctl);
5116429Svs195195 free(cpuid_list);
5126429Svs195195 return (-1);
5136429Svs195195 }
5146429Svs195195 ret = kstat_read(kstat_ctl, fps_kstat, NULL);
5156429Svs195195 if (ret != -1) {
5166429Svs195195 kstat_cpu_name = kstat_data_lookup(fps_kstat,
5176429Svs195195 "brand");
5186429Svs195195 if (NULL != kstat_cpu_name) {
5196429Svs195195 cpu_brand = KSTAT_NAMED_STR_PTR(
5206429Svs195195 kstat_cpu_name);
5216429Svs195195
5226429Svs195195 supported = check_if_supported_CPU(
5236429Svs195195 cpu_brand, m_stat->m_machine);
5246429Svs195195 }
5256429Svs195195 } else {
5266429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO,
5276429Svs195195 CPU_BRAND_PROBE_FAIL, cpuid_list[i]);
5286429Svs195195 (void) kstat_close(kstat_ctl);
5296429Svs195195 free(cpuid_list);
5306429Svs195195 return (-1);
5316429Svs195195 }
5326429Svs195195 if (!supported) {
5336429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO,
5346429Svs195195 CPU_NOT_SUPPORTED, cpu_brand,
5356429Svs195195 cpuid_list[i]);
5366429Svs195195 m_stat->m_cpus[i].disable_test = 1;
5376429Svs195195 (void) strcpy(m_stat->m_cpus[i].fptest_path, "");
5386429Svs195195 } else {
5396429Svs195195 m_stat->m_cpus[i].disable_test = 0;
5406429Svs195195 m_stat->m_num_cpus_to_test++;
5416429Svs195195 (void) strlcpy(m_stat->m_cpus[i].fptest_path,
5426429Svs195195 fps_tst_path,
5436429Svs195195 sizeof (m_stat->m_cpus[i].fptest_path));
5446429Svs195195 }
5456429Svs195195
5466429Svs195195 /* Get frequency */
5476429Svs195195
5486429Svs195195 kstat_cpu_freq = kstat_data_lookup(fps_kstat,
5496429Svs195195 "clock_MHz");
5506429Svs195195 if (NULL != kstat_cpu_freq) {
5516429Svs195195 cpu_freq = (int)kstat_cpu_freq->value.l;
5526429Svs195195 } else {
5536429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO,
5546429Svs195195 FREQ_PROBE_FAIL, cpuid_list[i]);
5557186Skk158166 (void) kstat_close(kstat_ctl);
5566429Svs195195 free(cpuid_list);
5576429Svs195195 return (-1);
5586429Svs195195 }
5596429Svs195195
5606429Svs195195 m_stat->m_cpus[i].cpuid = cpuid_list[i];
5616429Svs195195 m_stat->m_cpus[i].frequency = cpu_freq;
5626429Svs195195 (void) strncpy(m_stat->m_cpus[i].brand, cpu_brand,
5636429Svs195195 sizeof (m_stat->m_cpus[i].brand));
5646429Svs195195 m_stat->m_cpus[i].num_failures = 0;
5656429Svs195195
5666429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, CPU_INFO,
5676429Svs195195 cpuid_list[i], m_stat->m_cpus[i].brand,
5686429Svs195195 cpu_freq);
5696429Svs195195 }
5706429Svs195195 m_stat->m_cpuids_size = (int)m_stat->m_num_on_fpuids;
5716429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
5726429Svs195195 NUM_CPUS_2_TST, m_stat->m_cpuids_size);
5736429Svs195195 free(cpuid_list);
5747186Skk158166 (void) kstat_close(kstat_ctl);
5756429Svs195195 if (m_stat->m_num_cpus_to_test <= 0) {
576*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
5776429Svs195195 FPSD_NO_CPUS_TO_TEST);
5786429Svs195195 return (-1);
5796429Svs195195 }
5806429Svs195195 return (0);
5816429Svs195195 }
5826429Svs195195
5836429Svs195195 /*
5846429Svs195195 * returns 1 if cpuid is found in the list of cpus to be
5856429Svs195195 * excluded from testing.
5866429Svs195195 */
5876429Svs195195 static int
ignore_cpu(int cpuid)5886429Svs195195 ignore_cpu(int cpuid)
5896429Svs195195 {
5906429Svs195195 int found = 0;
5916429Svs195195 int i;
5926429Svs195195 processorid_t *ignore_cpus = fpsd.d_ignore_cpuid;
5936429Svs195195 for (i = 0; (i < fpsd.num_ignore_cpus) && (!found); i++) {
5946429Svs195195 if (ignore_cpus[i] == cpuid) {
5956429Svs195195 found = 1;
5966429Svs195195 }
5976429Svs195195 }
5986429Svs195195 return (found);
5996429Svs195195 }
6006429Svs195195
6016429Svs195195 /*
6027346SVaidehi.Rangan@Sun.COM * This function checks if the string has contiguous valid
6037346SVaidehi.Rangan@Sun.COM * digits. Leading and trailing blanks are O.K. Returns 0
6047346SVaidehi.Rangan@Sun.COM * if string is not a valid integer and 1 if valid.
6057346SVaidehi.Rangan@Sun.COM */
6067346SVaidehi.Rangan@Sun.COM
6077346SVaidehi.Rangan@Sun.COM static int
valid_integer(char * cpu_str)6087346SVaidehi.Rangan@Sun.COM valid_integer(char *cpu_str)
6097346SVaidehi.Rangan@Sun.COM {
6107346SVaidehi.Rangan@Sun.COM char *tmp_str = cpu_str;
6117346SVaidehi.Rangan@Sun.COM
6127346SVaidehi.Rangan@Sun.COM if ((NULL == cpu_str) || (strlen(cpu_str) == 0)) {
6137346SVaidehi.Rangan@Sun.COM return (0);
6147346SVaidehi.Rangan@Sun.COM }
6157346SVaidehi.Rangan@Sun.COM while (*tmp_str) {
6167346SVaidehi.Rangan@Sun.COM if (isblank(*tmp_str)) {
6177346SVaidehi.Rangan@Sun.COM tmp_str++;
6187346SVaidehi.Rangan@Sun.COM } else if (isdigit(*tmp_str)) {
6197346SVaidehi.Rangan@Sun.COM break;
6207346SVaidehi.Rangan@Sun.COM } else {
6217346SVaidehi.Rangan@Sun.COM return (0);
6227346SVaidehi.Rangan@Sun.COM }
6237346SVaidehi.Rangan@Sun.COM }
6247346SVaidehi.Rangan@Sun.COM if (!(*tmp_str)) {
6257346SVaidehi.Rangan@Sun.COM return (0);
6267346SVaidehi.Rangan@Sun.COM }
6277346SVaidehi.Rangan@Sun.COM while (*tmp_str) {
6287346SVaidehi.Rangan@Sun.COM if (isdigit(*tmp_str)) {
6297346SVaidehi.Rangan@Sun.COM tmp_str++;
6307346SVaidehi.Rangan@Sun.COM } else if (isblank(*tmp_str)) {
6317346SVaidehi.Rangan@Sun.COM break;
6327346SVaidehi.Rangan@Sun.COM } else
6337346SVaidehi.Rangan@Sun.COM return (0);
6347346SVaidehi.Rangan@Sun.COM }
6357346SVaidehi.Rangan@Sun.COM if (*tmp_str) {
6367346SVaidehi.Rangan@Sun.COM while (*tmp_str) {
6377346SVaidehi.Rangan@Sun.COM if (isblank(*tmp_str)) {
6387346SVaidehi.Rangan@Sun.COM tmp_str++;
6397346SVaidehi.Rangan@Sun.COM }
6407346SVaidehi.Rangan@Sun.COM else
6417346SVaidehi.Rangan@Sun.COM return (0);
6427346SVaidehi.Rangan@Sun.COM }
6437346SVaidehi.Rangan@Sun.COM }
6447346SVaidehi.Rangan@Sun.COM return (1);
6457346SVaidehi.Rangan@Sun.COM }
6467346SVaidehi.Rangan@Sun.COM
6477346SVaidehi.Rangan@Sun.COM /*
6486429Svs195195 * This function parses the string of cpu-ids separated by
6496429Svs195195 * "," , constructs the list and disables testing on those
6506429Svs195195 * cpus. This function assumes fpsd_probe has been called and all
6516429Svs195195 * the machine config info is available in structure fpsd.
6526429Svs195195 */
6536429Svs195195
6546429Svs195195 static int
parse_and_set_cpu_id_list(char * strCPUs)6556429Svs195195 parse_and_set_cpu_id_list(char *strCPUs)
6566429Svs195195 {
6576429Svs195195 char *last;
6586429Svs195195 int num_cpus = 0, invalid = 0;
6596429Svs195195 int *tmp_cpus;
6606429Svs195195 int num_cpus_to_test = 0;
6616429Svs195195 int i;
6626429Svs195195 int t_cpuid;
6636429Svs195195 char *cpu_id;
6646429Svs195195 static int first_time = 1;
6656429Svs195195
6666429Svs195195 tmp_cpus = (int *)malloc((int)fpsd.d_conf->m_num_fpus * sizeof (int));
6676429Svs195195 if (NULL == tmp_cpus)
6686429Svs195195 return (-1);
6696429Svs195195 cpu_id = strtok_r(strCPUs, ",", &last);
6706429Svs195195
6716429Svs195195 while ((NULL != cpu_id) && (!invalid)) {
6727346SVaidehi.Rangan@Sun.COM if (valid_integer(cpu_id)) {
6736429Svs195195 tmp_cpus[num_cpus++] =
6746429Svs195195 (int)strtol(cpu_id, (char **)NULL, 10);
6756429Svs195195 cpu_id = strtok_r(NULL, ",", &last);
6766429Svs195195 } else {
677*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_INFO,
6787346SVaidehi.Rangan@Sun.COM INVAL_PROP_VALUE, cpu_id);
6796429Svs195195 invalid = 1;
6806429Svs195195 }
6817346SVaidehi.Rangan@Sun.COM if (num_cpus > fpsd.d_conf->m_num_fpus) {
6827101Svs195195 /* More than max supported cpus */
683*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_INFO,
6846429Svs195195 INVAL_PROP_VALUE, strCPUs);
6856429Svs195195 invalid = 1;
6866429Svs195195 }
6876429Svs195195 }
6887346SVaidehi.Rangan@Sun.COM if ((!invalid) && (num_cpus > 0)) {
6896429Svs195195 fpsd.d_ignore_cpuid = (processorid_t *)malloc(
6906429Svs195195 sizeof (processorid_t) * (int) num_cpus);
6916429Svs195195 if (NULL != fpsd.d_ignore_cpuid) {
6926429Svs195195 for (i = 0; i < num_cpus; i++) {
6936429Svs195195 fpsd.d_ignore_cpuid[i] = tmp_cpus[i];
6946429Svs195195 }
6956429Svs195195 fpsd.num_ignore_cpus = num_cpus;
6966429Svs195195 } else {
6976429Svs195195 fpsd.num_ignore_cpus = 0;
6986429Svs195195 }
6997346SVaidehi.Rangan@Sun.COM } else {
7006429Svs195195 fpsd.d_ignore_cpuid = NULL;
7016429Svs195195 fpsd.num_ignore_cpus = 0;
7026429Svs195195 }
7036429Svs195195 free(tmp_cpus);
7046429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, NUM_IGN_CPUS,
7056429Svs195195 fpsd.num_ignore_cpus);
7066429Svs195195 if ((fpsd.num_ignore_cpus > 0) && (fpsd.d_conf->m_cpuids_size > 0)) {
7076429Svs195195 for (i = 0; i < fpsd.d_conf->m_cpuids_size; i++) {
7086429Svs195195 t_cpuid = fpsd.d_conf->m_cpus[i].cpuid;
7096429Svs195195 if (ignore_cpu(t_cpuid)) {
7106429Svs195195 fpsd.d_conf->m_cpus[i].disable_test = 1;
7116429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
7126429Svs195195 IGN_CPUS, t_cpuid);
7136429Svs195195 } else {
7146429Svs195195 num_cpus_to_test++;
7156429Svs195195 }
7166429Svs195195 }
7176429Svs195195 fpsd.d_conf->m_num_cpus_to_test = num_cpus_to_test;
7186429Svs195195 if (num_cpus_to_test <= 0) {
7196429Svs195195 if (1 == first_time) {
720*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_INFO,
7216429Svs195195 ALL_CPUS_EXCLDED);
7226429Svs195195 first_time = 0;
7236429Svs195195 } else {
724*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_INFO,
7256429Svs195195 ALL_CPUS_EXCLDED);
7266429Svs195195 }
7276429Svs195195 return (NO_CPUS_2_TEST);
7286429Svs195195 }
7296429Svs195195 }
7306429Svs195195 first_time = 1;
7316429Svs195195 return (0);
7326429Svs195195 }
7336429Svs195195
7346429Svs195195 #define CLEAN_UP_SCF_STUFF { \
7356429Svs195195 if (scf_handle_p) { \
7367186Skk158166 (void) scf_handle_unbind(scf_handle_p); \
7376429Svs195195 scf_handle_destroy(scf_handle_p); \
7386429Svs195195 } \
7396429Svs195195 if (inst) \
7406429Svs195195 scf_instance_destroy(inst); \
7416429Svs195195 if (pg) \
7426429Svs195195 scf_pg_destroy(pg); \
7436429Svs195195 if (scf_prop_p) \
7446429Svs195195 scf_property_destroy(scf_prop_p); \
7456429Svs195195 if (value) \
7466429Svs195195 scf_value_destroy(value); \
7477346SVaidehi.Rangan@Sun.COM if (scf_snapshot_p) \
7487346SVaidehi.Rangan@Sun.COM scf_snapshot_destroy(scf_snapshot_p); \
7496429Svs195195 }
7506429Svs195195
7516429Svs195195 /* Read properties from SMF configuration repository using libscf APIs */
7526429Svs195195
7536429Svs195195 static int
read_conf_props()7546429Svs195195 read_conf_props()
7556429Svs195195 {
7566429Svs195195 scf_handle_t *scf_handle_p;
7576429Svs195195 scf_property_t *scf_prop_p = NULL;
7586429Svs195195 scf_instance_t *inst = NULL;
7596429Svs195195 scf_propertygroup_t *pg = NULL;
7606429Svs195195 scf_value_t *value = NULL;
7616429Svs195195 int ret_val = -1;
7626429Svs195195 int val;
7636429Svs195195 int64_t intvl;
7646429Svs195195 int name_len;
7656429Svs195195 char *strCPUs;
7667346SVaidehi.Rangan@Sun.COM scf_snapshot_t *scf_snapshot_p = NULL;
7676429Svs195195
7686429Svs195195 scf_handle_p = scf_handle_create(SCF_VERSION);
7696429Svs195195 if ((NULL != scf_handle_p) && (NULL != str_fps_fmri)) {
7706429Svs195195 if (scf_handle_bind(scf_handle_p) != -1) {
7716429Svs195195 inst = scf_instance_create(scf_handle_p);
7726429Svs195195 pg = scf_pg_create(scf_handle_p);
7736429Svs195195 scf_prop_p = scf_property_create(scf_handle_p);
7746429Svs195195 if ((NULL == inst) || (NULL == pg) ||
7756429Svs195195 (NULL == scf_prop_p)) {
7766429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
7776429Svs195195 CREATE_FAIL,
7786429Svs195195 scf_strerror(scf_error()));
7796429Svs195195 CLEAN_UP_SCF_STUFF
7806429Svs195195 return (-1);
7816429Svs195195 }
7826429Svs195195 val = scf_handle_decode_fmri(scf_handle_p,
7836429Svs195195 str_fps_fmri,
7846429Svs195195 NULL, NULL, inst, pg, scf_prop_p, 0);
7856429Svs195195 if (val != 0) {
7866429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
7876429Svs195195 HANDLE_DECODE_FAIL,
7886429Svs195195 scf_strerror(scf_error()));
7896429Svs195195 CLEAN_UP_SCF_STUFF
7906429Svs195195 return (-1);
7916429Svs195195 }
7927346SVaidehi.Rangan@Sun.COM scf_snapshot_p = scf_snapshot_create(scf_handle_p);
7937346SVaidehi.Rangan@Sun.COM if (NULL == scf_snapshot_p) {
7947346SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
7957346SVaidehi.Rangan@Sun.COM SNAPSHOT_CREAT_FAIL,
7967346SVaidehi.Rangan@Sun.COM scf_strerror(scf_error()));
7977346SVaidehi.Rangan@Sun.COM CLEAN_UP_SCF_STUFF
7987346SVaidehi.Rangan@Sun.COM return (-1);
7997346SVaidehi.Rangan@Sun.COM }
8007346SVaidehi.Rangan@Sun.COM val = scf_instance_get_snapshot(inst,
8017346SVaidehi.Rangan@Sun.COM SMF_SNAPSHOT_RUNNING, scf_snapshot_p);
8027346SVaidehi.Rangan@Sun.COM if (val == -1) {
8037346SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
8047346SVaidehi.Rangan@Sun.COM INST_SNAPSHOT_GET_FAIL,
8057346SVaidehi.Rangan@Sun.COM scf_strerror(scf_error()));
8067346SVaidehi.Rangan@Sun.COM CLEAN_UP_SCF_STUFF
8077346SVaidehi.Rangan@Sun.COM return (-1);
8087346SVaidehi.Rangan@Sun.COM }
8097346SVaidehi.Rangan@Sun.COM val = scf_instance_get_pg_composed(inst, scf_snapshot_p,
8106429Svs195195 SMF_FPS_PROP_GRP_NAME, pg);
8116429Svs195195 if (val != 0) {
8126429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
8136429Svs195195 INSTANCE_PG_GET_FAIL,
8146429Svs195195 scf_strerror(scf_error()));
8156429Svs195195 CLEAN_UP_SCF_STUFF
8166429Svs195195 return (-1);
8176429Svs195195 }
8186429Svs195195 val = scf_pg_get_property(pg, SMF_PROP_INTVL,
8196429Svs195195 scf_prop_p);
8206429Svs195195 /* Read interval property if defined */
8216429Svs195195 if (val == 0) {
8226429Svs195195 value = scf_value_create(scf_handle_p);
8237346SVaidehi.Rangan@Sun.COM if (NULL != value) {
8247346SVaidehi.Rangan@Sun.COM val = scf_property_get_value(scf_prop_p,
8257346SVaidehi.Rangan@Sun.COM value);
8267346SVaidehi.Rangan@Sun.COM if (0 == val) {
8277346SVaidehi.Rangan@Sun.COM val =
8287346SVaidehi.Rangan@Sun.COM scf_value_get_integer(value,
8297346SVaidehi.Rangan@Sun.COM &intvl);
8307346SVaidehi.Rangan@Sun.COM if ((0 == val) && (intvl > 0)) {
8317346SVaidehi.Rangan@Sun.COM fpsd.d_interval =
8327346SVaidehi.Rangan@Sun.COM (int)intvl;
8337346SVaidehi.Rangan@Sun.COM fpsd_message(
8347346SVaidehi.Rangan@Sun.COM FPSD_NO_EXIT,
8357346SVaidehi.Rangan@Sun.COM FPS_DEBUG,
8367346SVaidehi.Rangan@Sun.COM INTVL_VAL, intvl);
8377346SVaidehi.Rangan@Sun.COM ret_val = 0;
8387346SVaidehi.Rangan@Sun.COM }
8397346SVaidehi.Rangan@Sun.COM }
8406429Svs195195 }
8416429Svs195195 } else {
8426429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO,
8436429Svs195195 PROP_UNDEFINED, SMF_PROP_INTVL,
8446429Svs195195 scf_strerror(scf_error()));
8456429Svs195195 }
8466429Svs195195 /*
8476429Svs195195 * Read property "exclude_cpus" if defined - this is
8486429Svs195195 * the array of cpu-ids to be excluded from testing.
8496429Svs195195 */
8506429Svs195195 val = scf_pg_get_property(pg, SMF_PROP_EXCLD_CPUS,
8516429Svs195195 scf_prop_p);
8526429Svs195195 if (val == 0) {
8536429Svs195195 val = scf_property_get_value(scf_prop_p, value);
8547346SVaidehi.Rangan@Sun.COM if (0 == val) {
8557346SVaidehi.Rangan@Sun.COM name_len =
8567346SVaidehi.Rangan@Sun.COM scf_limit(
8577346SVaidehi.Rangan@Sun.COM SCF_LIMIT_MAX_NAME_LENGTH);
8587346SVaidehi.Rangan@Sun.COM strCPUs = malloc(name_len +1);
8597346SVaidehi.Rangan@Sun.COM if (NULL == strCPUs) {
8607346SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT,
8617346SVaidehi.Rangan@Sun.COM FPS_DEBUG,
8627346SVaidehi.Rangan@Sun.COM LIBRARY_CALL_FAIL,
8637346SVaidehi.Rangan@Sun.COM "malloc");
8647346SVaidehi.Rangan@Sun.COM CLEAN_UP_SCF_STUFF
8657346SVaidehi.Rangan@Sun.COM return (-1);
8667346SVaidehi.Rangan@Sun.COM }
8677346SVaidehi.Rangan@Sun.COM val = scf_value_get_astring(value,
8687346SVaidehi.Rangan@Sun.COM strCPUs, name_len+1);
8697346SVaidehi.Rangan@Sun.COM if ((val != -1) &&
8707346SVaidehi.Rangan@Sun.COM (strlen(strCPUs) > 0)) {
8717346SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_NO_EXIT,
8727346SVaidehi.Rangan@Sun.COM FPS_DEBUG,
8737346SVaidehi.Rangan@Sun.COM EXCL_CPUS, strCPUs);
8747346SVaidehi.Rangan@Sun.COM ret_val =
8757346SVaidehi.Rangan@Sun.COM parse_and_set_cpu_id_list(
8767346SVaidehi.Rangan@Sun.COM strCPUs);
8777346SVaidehi.Rangan@Sun.COM }
8787346SVaidehi.Rangan@Sun.COM free(strCPUs);
8796429Svs195195 }
8806429Svs195195 } else {
8816429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
8826429Svs195195 PROP_UNDEFINED,
8836429Svs195195 SMF_PROP_EXCLD_CPUS,
8846429Svs195195 scf_strerror(scf_error()));
8856429Svs195195 }
8866429Svs195195 }
8876429Svs195195 }
8886429Svs195195
8896429Svs195195 /* Clean up */
8906429Svs195195
8916429Svs195195 CLEAN_UP_SCF_STUFF
8926429Svs195195 return (ret_val);
8936429Svs195195 }
8946429Svs195195
8957346SVaidehi.Rangan@Sun.COM static int
fpsd_init()8967346SVaidehi.Rangan@Sun.COM fpsd_init()
8977346SVaidehi.Rangan@Sun.COM {
8986429Svs195195 mach_conf_t *m_conf_p;
8996429Svs195195
9006429Svs195195 debug_level = DFLT_DBG_LVL;
9016429Svs195195 fpsd.d_fg = 0;
9026429Svs195195 fpsd.d_daemon = 0;
9036429Svs195195 fpsd.d_ignore_cpuid = NULL;
9046429Svs195195 fpsd.d_iteration = 0;
9056429Svs195195 fpsd.d_interval = 0;
9066429Svs195195 fpsd.d_fpuid_index = 0;
9076429Svs195195 fpsd.d_rootdir = "/";
9086429Svs195195 fpsd.d_pid = getpid();
9096429Svs195195 fpsd.d_conf = &fpsd_conf;
9106429Svs195195 fpsd.d_ts_hup = 0;
9116429Svs195195
9126429Svs195195 m_conf_p = fpsd.d_conf;
9136429Svs195195 m_conf_p->m_machine[0] = '\0';
9146429Svs195195 m_conf_p->m_num_on_fpuids = 0;
9156429Svs195195 m_conf_p->m_cpuids_size = 0;
9166429Svs195195 m_conf_p->total_iter = 0;
9176429Svs195195 m_conf_p->m_reprobe = 0;
9186429Svs195195 m_conf_p->m_num_cpus_to_test = 0;
9197101Svs195195 m_conf_p->m_num_fpus = (uint_t)sysconf(_SC_NPROCESSORS_MAX);
9206429Svs195195
9217346SVaidehi.Rangan@Sun.COM (void) pthread_mutex_init(&log_mutex, NULL);
9226429Svs195195
9237101Svs195195 m_conf_p->m_max_cpuid = (int)sysconf(_SC_CPUID_MAX) + 1;
9246429Svs195195
9256429Svs195195 /*
9266429Svs195195 * Allocate enough memory to accomodate maximum number of CPUs
9276429Svs195195 * supported by this platform.
9286429Svs195195 */
9296429Svs195195 m_conf_p->m_cpus = malloc(sizeof (fps_cpu_t) *
9307346SVaidehi.Rangan@Sun.COM m_conf_p->m_num_fpus);
9316429Svs195195 if (NULL == m_conf_p->m_cpus)
9326429Svs195195 return (1);
9336429Svs195195 else
9346429Svs195195 return (0);
9356429Svs195195
9366429Svs195195 }
9376429Svs195195
9386429Svs195195 static void
fpsd_fini()9397346SVaidehi.Rangan@Sun.COM fpsd_fini()
9407346SVaidehi.Rangan@Sun.COM {
9416429Svs195195 if (fpsd.d_ignore_cpuid)
9426429Svs195195 free(fpsd.d_ignore_cpuid);
9436429Svs195195 if (fpsd.d_conf->m_cpus)
9446429Svs195195 free(fpsd.d_conf->m_cpus);
9456429Svs195195 }
9466429Svs195195
9476429Svs195195 static int
fpsd_probe_config()9486429Svs195195 fpsd_probe_config()
9496429Svs195195 {
9506429Svs195195 int smf_invoked = 0;
9516429Svs195195 int ret = 0;
9526429Svs195195
9536429Svs195195 /*
9546429Svs195195 * Use smf_get_state to get the status of the service to see
9556429Svs195195 * if the status is "online" by now. If so, read the proper-
9566429Svs195195 * ties defined using SCF.
9576429Svs195195 */
9586429Svs195195
9596429Svs195195 if (NULL != str_fps_fmri) {
9607346SVaidehi.Rangan@Sun.COM smf_invoked = 1;
9616429Svs195195
9627346SVaidehi.Rangan@Sun.COM /* Read SMF properties if invoked thro' SMF */
9637346SVaidehi.Rangan@Sun.COM ret = read_conf_props();
9647346SVaidehi.Rangan@Sun.COM if (ret == NO_CPUS_2_TEST) {
9657346SVaidehi.Rangan@Sun.COM return (ret);
9666429Svs195195 }
9676429Svs195195 }
9686429Svs195195 calculateTotalIterations(fpsd.d_conf);
9696429Svs195195 if ((ret == -1) || (!smf_invoked) || (fpsd.d_interval <= 0)) {
9706429Svs195195 ret = calculateTimeInterval();
9716429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
9726429Svs195195 PRINT_INTVL, fpsd.d_interval);
9736429Svs195195 if ((ret != 1) || (fpsd.d_interval <= 0)) {
9746429Svs195195 return (ZERO_INTERVAL);
9756429Svs195195 }
9766429Svs195195 }
9776429Svs195195 return (0);
9786429Svs195195 }
9796429Svs195195
9806429Svs195195 int
main(int argc,char ** argv)9816429Svs195195 main(int argc, char **argv)
9826429Svs195195 {
9836429Svs195195
9846429Svs195195 int sig;
9856429Svs195195 sigset_t sigs;
9866429Svs195195 /* Pipe fd to write the status back to parent after becoming daemon */
9876429Svs195195 int pfd = -1;
9886429Svs195195 int status = FPSD_INIT_SUCCESS;
9896429Svs195195 char rcvsigstr[32];
9906429Svs195195 int c;
9916429Svs195195 int ret;
9926429Svs195195 struct rlimit rlim;
9936429Svs195195 char path[MAXPATHLEN];
9946429Svs195195 int probe_status = -1;
9956429Svs195195 const char *progname;
9966429Svs195195 struct sigaction act;
9976429Svs195195
9986429Svs195195 progname = strrchr(argv[0], '/');
9996429Svs195195 if (NULL != progname)
10006429Svs195195 progname++;
10016429Svs195195 else
10026429Svs195195 progname = argv[0];
10036429Svs195195
10046429Svs195195 #ifndef TEXT_DOMAIN /* Should be defined via Makefile */
10056429Svs195195 #define TEXT_DOMAIN "SUNW_FPS"
10066429Svs195195 #endif
10076429Svs195195
10086429Svs195195 (void) setlocale(LC_ALL, "");
10096429Svs195195 (void) textdomain(TEXT_DOMAIN);
10106429Svs195195
10116429Svs195195 openlog(FPS_DAEMON_NAME, LOG_PID, LOG_DAEMON);
10126429Svs195195
10136429Svs195195 if (fpsd_init()) {
10146429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, DAEMON_INIT_FAIL);
10156429Svs195195 }
10166429Svs195195
10176429Svs195195 /*
10186429Svs195195 * Set our per-process core file path to leave core files in
10196429Svs195195 * var/fps/core directory, named after the PID to aid in
10206429Svs195195 * debugging, and make sure that there is no restriction on core
10216429Svs195195 * file size.
10226429Svs195195 */
10236429Svs195195
10246429Svs195195 if ((ret = access(FPS_CORE_DIR, W_OK)) != 0) {
10256429Svs195195 if ((ret = mkdirp(FPS_CORE_DIR, 0755)) != 0) {
10266429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR,
10276429Svs195195 CORE_DIR_CREATION_FAILED,
10286429Svs195195 FPS_CORE_DIR, strerror(errno));
10296429Svs195195 }
10306429Svs195195 }
10316429Svs195195
10326429Svs195195 if (ret == 0) {
10336429Svs195195 (void) snprintf(path, sizeof (path), "%s/core.%s.%%p",
10346429Svs195195 FPS_CORE_DIR, progname);
10356429Svs195195 (void) core_set_process_path(path, strlen(path) + 1,
10366429Svs195195 fpsd.d_pid);
10376429Svs195195 rlim.rlim_cur = RLIM_INFINITY;
10386429Svs195195 rlim.rlim_max = RLIM_INFINITY;
10396429Svs195195
10406429Svs195195 (void) setrlimit(RLIMIT_CORE, &rlim);
10416429Svs195195 }
10426429Svs195195
10436429Svs195195
10446429Svs195195 /* parse arguments */
10456429Svs195195 while ((c = getopt(argc, argv, "dl:")) != EOF) {
10466429Svs195195 switch (c) {
10476429Svs195195 case 'd':
10486429Svs195195 fpsd.d_fg = 1;
10496429Svs195195 break;
10506429Svs195195
10516429Svs195195 case 'l':
10526429Svs195195 debug_level = atoi(optarg);
10536429Svs195195 if (debug_level < 0)
10546429Svs195195 debug_level = DFLT_DBG_LVL;
10556429Svs195195 break;
10566429Svs195195
10576429Svs195195 default:
10586429Svs195195 fpsd_message(FPSD_EXIT_USAGE, FPS_ERROR, USAGE_MSG,
10596429Svs195195 progname);
10606429Svs195195 break;
10616429Svs195195 }
10626429Svs195195 }
10636429Svs195195
10646429Svs195195
10656429Svs195195 /*
10666429Svs195195 * Reset all of our privilege sets to the minimum set of required
10676429Svs195195 * privileges. We continue to run as root so that files we create
10686429Svs195195 * such as logs and checkpoints are secured in the /var
10696429Svs195195 * filesystem.
10706429Svs195195 */
10716429Svs195195 if (__init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS,
10726429Svs195195 0, 0, /* run as uid 0 and gid 0 */
10736429Svs195195 PRIV_FILE_DAC_EXECUTE, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH,
10746429Svs195195 PRIV_FILE_DAC_WRITE, PRIV_FILE_OWNER, PRIV_PROC_OWNER,
10756429Svs195195 PRIV_PROC_PRIOCNTL, PRIV_SYS_ADMIN, PRIV_SYS_CONFIG,
10766429Svs195195 PRIV_SYS_DEVICES, PRIV_SYS_RES_CONFIG,
10776429Svs195195 PRIV_NET_PRIVADDR, NULL) != 0) {
10786429Svs195195
10796429Svs195195 (void) fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR,
10806429Svs195195 INSUFFICIENT_PRIVS, progname);
10816429Svs195195 }
10826429Svs195195
10836429Svs195195
10846429Svs195195 if (!fpsd.d_fg) { /* Now become daemon */
10856429Svs195195 pfd = become_daemon_init();
10866429Svs195195 } else {
10876429Svs195195 (void) chdir(FPS_DIR);
10886429Svs195195 }
10896429Svs195195
10906429Svs195195 if (daemon_exists()) {
10916429Svs195195 /*
10926429Svs195195 * If another instance of fpsd daemon is already running;
10936429Svs195195 * exit. Should not clean up door file
10946429Svs195195 */
10956429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR,
10966429Svs195195 DAEMON_ALREADY_RUNNING);
10976429Svs195195 }
10986429Svs195195
10996429Svs195195 /*
11006429Svs195195 * Setup door prevents any more instances of fpsd from running.
11016429Svs195195 */
11026429Svs195195 if (fps_setup_door() == -1) {
11036429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, DOOR_SETUP_FAIL);
11046429Svs195195 }
11056429Svs195195
11066429Svs195195 /*
11076429Svs195195 * Some desktop platforms satisfy E* guidelines. Here CPU power
11086429Svs195195 * management is enabled by default. The scheduling algorithms
11096429Svs195195 * change on these platforms to not to do testing on idle system
11106429Svs195195 * to save power.
11116429Svs195195 */
11126429Svs195195 init_estar_db(); /* Initialize Estar config data base */
11136429Svs195195 /* Print message on CPU E* enabled system */
11146429Svs195195 if (is_estar_system)
11156429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, ESTAR_INFO);
11166429Svs195195
11176429Svs195195 if ((probe_status = fpsd_probe(fpsd.d_conf)) != 0) {
1118*7435SVaidehi.Rangan@Sun.COM (void) fpsd_message(FPSD_NO_EXIT, FPS_DEBUG,
11196429Svs195195 UNSUPPORTED_SYSTEM);
11206429Svs195195 }
11216429Svs195195
11226429Svs195195 if (!fpsd.d_fg) { /* Complete daemonize proces */
11236429Svs195195
11246429Svs195195 fpsd.d_daemon = 1;
11256429Svs195195 /*
11266429Svs195195 * Now that we're running, if a pipe fd was specified, write an
11276429Svs195195 * exit status to it to indicate that our parent process can
11286429Svs195195 * safely detach.
11296429Svs195195 */
11306429Svs195195 if (pfd >= 0) {
11316429Svs195195 (void) write(pfd, &status, sizeof (status));
11326429Svs195195 }
11336429Svs195195 become_daemon_fini(pfd);
11346429Svs195195
11356429Svs195195 } else {
11366429Svs195195 /*
11376429Svs195195 * Mask all signals before creating sched thread. We will
11386429Svs195195 * unmask selective siganls from main thread. This ensures
11396429Svs195195 * that only main thread handles signals. This is done in
11406429Svs195195 * become_daemon() if we had to daemonize.
11416429Svs195195 */
11426429Svs195195
11436429Svs195195 (void) sigfillset(&sigs);
11446429Svs195195 (void) sigprocmask(SIG_BLOCK, &sigs, NULL);
11456429Svs195195 }
11466429Svs195195
11476429Svs195195 /*
11486429Svs195195 * Give some time for SMF to read the exit status
11496429Svs195195 * of parent and update fpsd fmri state
11506429Svs195195 */
11516429Svs195195 (void) poll(NULL, 0, 3*1000);
11526429Svs195195
11536429Svs195195 str_fps_fmri = getenv("SMF_FMRI");
11546429Svs195195 if (NULL != str_fps_fmri) {
11556429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, SMF_INVKD, str_fps_fmri);
11566429Svs195195 } else {
11576429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, CLI_INVKD);
11586429Svs195195 }
11596429Svs195195
11606429Svs195195 if (probe_status != 0) {
11616429Svs195195 /* Exit child proces too */
11626429Svs195195
11636429Svs195195 if (NULL != str_fps_fmri) {
11647346SVaidehi.Rangan@Sun.COM const char *smf_state;
11657346SVaidehi.Rangan@Sun.COM ret = smf_disable_instance(str_fps_fmri,
11667346SVaidehi.Rangan@Sun.COM SMF_TEMPORARY);
11677346SVaidehi.Rangan@Sun.COM if (0 == ret) {
11687346SVaidehi.Rangan@Sun.COM (void) fpsd_message(FPSD_NO_EXIT,
1169*7435SVaidehi.Rangan@Sun.COM FPS_DEBUG, FPSD_STATE);
11707346SVaidehi.Rangan@Sun.COM } else {
11717346SVaidehi.Rangan@Sun.COM /* Unable to disable the service. */
11727346SVaidehi.Rangan@Sun.COM smf_state = smf_get_state(str_fps_fmri);
11737346SVaidehi.Rangan@Sun.COM if (NULL == smf_state) {
11747346SVaidehi.Rangan@Sun.COM smf_state = " ";
11757346SVaidehi.Rangan@Sun.COM (void) fpsd_message(FPSD_NO_EXIT,
11767346SVaidehi.Rangan@Sun.COM FPS_ERROR, DISABLE_SVC_FAILED,
11777346SVaidehi.Rangan@Sun.COM smf_state);
11787346SVaidehi.Rangan@Sun.COM }
11796429Svs195195 (void) poll(NULL, 0, 3*1000);
11806429Svs195195 }
11816429Svs195195 }
11826429Svs195195 terminate_process();
11836429Svs195195 _exit(FPSD_EXIT_ERROR);
11846429Svs195195 }
11856429Svs195195
11866429Svs195195 act.sa_sigaction = sig_hup_handler;
11876429Svs195195 (void) sigemptyset(&act.sa_mask);
11886429Svs195195 act.sa_flags = SA_SIGINFO;
11896429Svs195195 (void) sigaction(SIGHUP, &act, NULL);
11906429Svs195195 fpsd_read_config();
11917346SVaidehi.Rangan@Sun.COM (void) sigfillset(&sigs);
11927346SVaidehi.Rangan@Sun.COM (void) sigprocmask(SIG_BLOCK, &sigs, NULL);
11936429Svs195195
11946429Svs195195 /*
11956429Svs195195 * On estar-systems, if interval < MIN_INTERVAL, scheduling tests will
11966429Svs195195 * reset the idle counter and prevent system from going to sleep.
11976429Svs195195 * To avoid this, setting interval to MIN_INTERVAL.
11986429Svs195195 */
11996429Svs195195
12006429Svs195195 if ((is_estar_system) && (fpsd.d_interval < MIN_INTERVAL)) {
12016429Svs195195 fpsd.d_interval = MIN_INTERVAL;
12026429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, MIN_INTERVAL_MSG,
12036429Svs195195 fpsd.d_interval, MIN_INTERVAL);
12046429Svs195195 }
12056429Svs195195
12066429Svs195195 /* Run scheduling thread */
12076429Svs195195 if ((ret == 0) && thr_create(NULL, 0,
12086429Svs195195 test_fpu_thr, (void *) NULL, THR_BOUND, NULL) != 0) {
1209*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_EXIT_ERROR, FPS_WARNING, THR_CREATION_FAIL);
12106429Svs195195 }
12116429Svs195195
12126429Svs195195 /*
12136429Svs195195 * We unmask selective signals here. Besides terminating on
12146429Svs195195 * SIGINT & SIGTERM, we handle SIGHUP that is used to cause
12156429Svs195195 * daemon to re-read the SMF properties.
12166429Svs195195 */
12176429Svs195195 (void) sigemptyset(&sigs);
12186429Svs195195 (void) sigaddset(&sigs, SIGINT);
12196429Svs195195 (void) sigaddset(&sigs, SIGTERM);
12206429Svs195195 (void) sigaddset(&sigs, SIGHUP);
12216429Svs195195 (void) sigprocmask(SIG_UNBLOCK, &sigs, NULL);
12226429Svs195195
12236429Svs195195 for (;;) {
12246429Svs195195 (void) sigwait(&sigs, &sig);
12256429Svs195195 (void) sig2str(sig, rcvsigstr);
12266429Svs195195
12276429Svs195195 if (sig != -1) {
12286429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO,
12296429Svs195195 SIGNAL_INFO, rcvsigstr, sig);
12306429Svs195195 switch (sig) {
12316429Svs195195 case SIGINT:
12326429Svs195195 case SIGTERM:
12336429Svs195195 terminate_process();
12346429Svs195195 _exit(FPSD_EXIT_ERROR);
12356429Svs195195 break;
12366429Svs195195 case SIGHUP:
12376429Svs195195 fpsd.d_ts_hup = gethrtime();
12386429Svs195195 break;
12396429Svs195195 default: break;
12406429Svs195195 }
12416429Svs195195 }
12426429Svs195195 }
12436429Svs195195 #pragma error_messages(off, E_STATEMENT_NOT_REACHED)
12446429Svs195195 /* NOTREACHED */
12456429Svs195195 return (0);
12466429Svs195195 }
1247