2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <ctype.h>
2N/A#include <string.h>
2N/A#include <sys/param.h>
2N/A#include <sys/types.h>
2N/A#include <sys/utsname.h>
2N/A#include <stdarg.h>
2N/A#include <syslog.h>
2N/A#include <sys/openpromio.h>
2N/A#include <libintl.h>
2N/A#include "pdevinfo.h"
2N/A#include "display.h"
2N/A
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/A/*
2N/A * external data
2N/A */
2N/Aextern int print_flag;
2N/Aextern int logging;
2N/A
2N/A/*
2N/A * The following macros for dealing with raw output from the Mostek 48T02
2N/A * were borrowed from the kernel. Openboot passes the raw Mostek data
2N/A * thru the device tree, and there are no library routines to deal with
2N/A * this data.
2N/A */
2N/A
2N/A/*
2N/A * Tables to convert a single byte from binary-coded decimal (BCD).
2N/A */
2N/Astatic uchar_t bcd_to_byte[256] = { /* CSTYLED */
2N/A 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
2N/A 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0,
2N/A 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0,
2N/A 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0,
2N/A 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0, 0, 0, 0, 0, 0,
2N/A 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, 0,
2N/A 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, 0, 0, 0, 0, 0,
2N/A 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 0, 0,
2N/A 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0,
2N/A 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
2N/A};
2N/A
2N/A#define BCD_TO_BYTE(x) bcd_to_byte[(x) & 0xff]
2N/A#define YRBASE 68
2N/A
2N/Astatic int days_thru_month[64] = {
2N/A 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 0, 0,
2N/A 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0,
2N/A 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0,
2N/A 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0,
2N/A};
2N/A
2N/A/*
2N/A * This function takes the raw Mostek data from the device tree translates
2N/A * it into UNIXC time (secs since Jan 1, 1970) and returns a string from
2N/A * ctime(3c).
2N/A */
2N/Achar *
2N/Aget_time(uchar_t *mostek)
2N/A{
2N/A time_t utc;
2N/A int sec, min, hour, day, month, year;
2N/A
2N/A year = BCD_TO_BYTE(mostek[6]) + YRBASE;
2N/A month = BCD_TO_BYTE(mostek[5] & 0x1f) + ((year & 3) << 4);
2N/A day = BCD_TO_BYTE(mostek[4] & 0x3f);
2N/A hour = BCD_TO_BYTE(mostek[2] & 0x3f);
2N/A min = BCD_TO_BYTE(mostek[1] & 0x7f);
2N/A sec = BCD_TO_BYTE(mostek[0] & 0x7f);
2N/A
2N/A utc = (year - 70); /* next 3 lines: utc = 365y + y/4 */
2N/A utc += (utc << 3) + (utc << 6);
2N/A utc += (utc << 2) + ((year - 69) >> 2);
2N/A utc += days_thru_month[month] + day - 1;
2N/A utc = (utc << 3) + (utc << 4) + hour; /* 24 * day + hour */
2N/A utc = (utc << 6) - (utc << 2) + min; /* 60 * hour + min */
2N/A utc = (utc << 6) - (utc << 2) + sec; /* 60 * min + sec */
2N/A
2N/A return (ctime((time_t *)&utc));
2N/A}
2N/A
2N/Avoid
2N/Adisp_powerfail(Prom_node *root)
2N/A{
2N/A Prom_node *pnode;
2N/A const char *option_str = "options";
2N/A const char *pf_str = "powerfail-time";
2N/A char *value_str;
2N/A time_t value;
2N/A
2N/A pnode = dev_find_node(root, option_str);
2N/A if (pnode == NULL) {
2N/A return;
2N/A }
2N/A
2N/A value_str = get_prop_val(find_prop(pnode, pf_str));
2N/A if (value_str == NULL) {
2N/A return;
2N/A }
2N/A
2N/A value = (time_t)atoi(value_str);
2N/A if (value == 0)
2N/A return;
2N/A
2N/A (void) log_printf(
2N/A dgettext(TEXT_DOMAIN,
2N/A "Most recent AC Power Failure:\n"));
2N/A (void) log_printf("=============================\n");
2N/A (void) log_printf("%s", ctime(&value));
2N/A (void) log_printf("\n");
2N/A}
2N/A
2N/A
2N/A/*VARARGS1*/
2N/Avoid
2N/Alog_printf(const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A int len;
2N/A static char bigbuf[4096];
2N/A char buffer[1024];
2N/A
2N/A if (print_flag == 0) {
2N/A return;
2N/A }
2N/A
2N/A va_start(ap, fmt);
2N/A if (logging != 0) {
2N/A len = vsprintf(buffer, fmt, ap);
2N/A (void) strcat(bigbuf, buffer);
2N/A
2N/A /* we only call to syslog when we get the entire line. */
2N/A if (buffer[len-1] == '\n') {
2N/A syslog(LOG_DAEMON|LOG_NOTICE, bigbuf);
2N/A bigbuf[0] = 0;
2N/A }
2N/A
2N/A } else {
2N/A (void) vprintf(fmt, ap);
2N/A }
2N/A va_end(ap);
2N/A}
2N/A
2N/Avoid
2N/Aprint_header(int board)
2N/A{
2N/A log_printf("\n");
2N/A log_printf(dgettext(TEXT_DOMAIN,
2N/A "Analysis for Board %d\n"), board, 0);
2N/A log_printf("--------------------\n", 0);
2N/A}