linux/arch/parisc/kernel/pdc_chassis.c
<<
>>
Prefs
   1/* 
   2 *    interfaces to Chassis Codes via PDC (firmware)
   3 *
   4 *    Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
   5 *    Copyright (C) 2002-2006 Thibaut VARENE <varenet@parisc-linux.org>
   6 *
   7 *    This program is free software; you can redistribute it and/or modify
   8 *    it under the terms of the GNU General Public License, version 2, as
   9 *    published by the Free Software Foundation.
  10 *
  11 *    This program is distributed in the hope that it will be useful,
  12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *    GNU General Public License for more details.
  15 *
  16 *    You should have received a copy of the GNU General Public License
  17 *    along with this program; if not, write to the Free Software
  18 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 *
  20 *    TODO: poll chassis warns, trigger (configurable) machine shutdown when
  21 *              needed.
  22 *          Find out how to get Chassis warnings out of PAT boxes?
  23 */
  24
  25#undef PDC_CHASSIS_DEBUG
  26#ifdef PDC_CHASSIS_DEBUG
  27#define DPRINTK(fmt, args...)   printk(fmt, ## args)
  28#else
  29#define DPRINTK(fmt, args...)
  30#endif
  31
  32#include <linux/init.h>
  33#include <linux/module.h>
  34#include <linux/kernel.h>
  35#include <linux/reboot.h>
  36#include <linux/notifier.h>
  37#include <linux/cache.h>
  38#include <linux/proc_fs.h>
  39#include <linux/seq_file.h>
  40
  41#include <asm/pdc_chassis.h>
  42#include <asm/processor.h>
  43#include <asm/pdc.h>
  44#include <asm/pdcpat.h>
  45
  46#define PDC_CHASSIS_VER "0.05"
  47
  48#ifdef CONFIG_PDC_CHASSIS
  49static unsigned int pdc_chassis_enabled __read_mostly = 1;
  50
  51
  52/**
  53 * pdc_chassis_setup() - Enable/disable pdc_chassis code at boot time.
  54 * @str configuration param: 0 to disable chassis log
  55 * @return 1
  56 */
  57 
  58static int __init pdc_chassis_setup(char *str)
  59{
  60        /*panic_timeout = simple_strtoul(str, NULL, 0);*/
  61        get_option(&str, &pdc_chassis_enabled);
  62        return 1;
  63}
  64__setup("pdcchassis=", pdc_chassis_setup);
  65
  66
  67/** 
  68 * pdc_chassis_checkold() - Checks for old PDC_CHASSIS compatibility
  69 * @pdc_chassis_old: 1 if old pdc chassis style
  70 * 
  71 * Currently, only E class and A180 are known to work with this.
  72 * Inspired by Christoph Plattner
  73 */
  74#if 0
  75static void __init pdc_chassis_checkold(void)
  76{
  77        switch(CPU_HVERSION) {
  78                case 0x480:             /* E25 */
  79                case 0x481:             /* E35 */
  80                case 0x482:             /* E45 */
  81                case 0x483:             /* E55 */
  82                case 0x516:             /* A180 */
  83                        break;
  84
  85                default:
  86                        break;
  87        }
  88        DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old);
  89}
  90#endif
  91
  92/**
  93 * pdc_chassis_panic_event() - Called by the panic handler.
  94 *
  95 * As soon as a panic occurs, we should inform the PDC.
  96 */
  97
  98static int pdc_chassis_panic_event(struct notifier_block *this,
  99                        unsigned long event, void *ptr)
 100{
 101        pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
 102                return NOTIFY_DONE;
 103}   
 104
 105
 106static struct notifier_block pdc_chassis_panic_block = {
 107        .notifier_call = pdc_chassis_panic_event,
 108        .priority = INT_MAX,
 109};
 110
 111
 112/**
 113 * parisc_reboot_event() - Called by the reboot handler.
 114 *
 115 * As soon as a reboot occurs, we should inform the PDC.
 116 */
 117
 118static int pdc_chassis_reboot_event(struct notifier_block *this,
 119                        unsigned long event, void *ptr)
 120{
 121        pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
 122                return NOTIFY_DONE;
 123}   
 124
 125
 126static struct notifier_block pdc_chassis_reboot_block = {
 127        .notifier_call = pdc_chassis_reboot_event,
 128        .priority = INT_MAX,
 129};
 130#endif /* CONFIG_PDC_CHASSIS */
 131
 132
 133/**
 134 * parisc_pdc_chassis_init() - Called at boot time.
 135 */
 136
 137void __init parisc_pdc_chassis_init(void)
 138{
 139#ifdef CONFIG_PDC_CHASSIS
 140        if (likely(pdc_chassis_enabled)) {
 141                DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__);
 142
 143                /* Let see if we have something to handle... */
 144                printk(KERN_INFO "Enabling %s chassis codes support v%s\n",
 145                                is_pdc_pat() ? "PDC_PAT" : "regular",
 146                                PDC_CHASSIS_VER);
 147
 148                /* initialize panic notifier chain */
 149                atomic_notifier_chain_register(&panic_notifier_list,
 150                                &pdc_chassis_panic_block);
 151
 152                /* initialize reboot notifier chain */
 153                register_reboot_notifier(&pdc_chassis_reboot_block);
 154        }
 155#endif /* CONFIG_PDC_CHASSIS */
 156}
 157
 158
 159/** 
 160 * pdc_chassis_send_status() - Sends a predefined message to the chassis,
 161 * and changes the front panel LEDs according to the new system state
 162 * @retval: PDC call return value.
 163 *
 164 * Only machines with 64 bits PDC PAT and those reported in
 165 * pdc_chassis_checkold() are supported atm.
 166 * 
 167 * returns 0 if no error, -1 if no supported PDC is present or invalid message,
 168 * else returns the appropriate PDC error code.
 169 * 
 170 * For a list of predefined messages, see asm-parisc/pdc_chassis.h
 171 */
 172
 173int pdc_chassis_send_status(int message)
 174{
 175        /* Maybe we should do that in an other way ? */
 176        int retval = 0;
 177#ifdef CONFIG_PDC_CHASSIS
 178        if (likely(pdc_chassis_enabled)) {
 179
 180                DPRINTK(KERN_DEBUG "%s: pdc_chassis_send_status(%d)\n", __FILE__, message);
 181
 182#ifdef CONFIG_64BIT
 183                if (is_pdc_pat()) {
 184                        switch(message) {
 185                                case PDC_CHASSIS_DIRECT_BSTART:
 186                                        retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BSTART, PDC_CHASSIS_LSTATE_RUN_NORMAL);
 187                                        break;
 188
 189                                case PDC_CHASSIS_DIRECT_BCOMPLETE:
 190                                        retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BCOMPLETE, PDC_CHASSIS_LSTATE_RUN_NORMAL);
 191                                        break;
 192
 193                                case PDC_CHASSIS_DIRECT_SHUTDOWN:
 194                                        retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_SHUTDOWN, PDC_CHASSIS_LSTATE_NONOS);
 195                                        break;
 196
 197                                case PDC_CHASSIS_DIRECT_PANIC:
 198                                        retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_PANIC, PDC_CHASSIS_LSTATE_RUN_CRASHREC);
 199                                        break;
 200
 201                                case PDC_CHASSIS_DIRECT_LPMC:
 202                                        retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_LPMC, PDC_CHASSIS_LSTATE_RUN_SYSINT);
 203                                        break;
 204
 205                                case PDC_CHASSIS_DIRECT_HPMC:
 206                                        retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_HPMC, PDC_CHASSIS_LSTATE_RUN_NCRIT);
 207                                        break;
 208
 209                                default:
 210                                        retval = -1;
 211                        }
 212                } else retval = -1;
 213#else
 214                if (1) {
 215                        switch (message) {
 216                                case PDC_CHASSIS_DIRECT_BSTART:
 217                                        retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_INIT));
 218                                        break;
 219
 220                                case PDC_CHASSIS_DIRECT_BCOMPLETE:
 221                                        retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN));
 222                                        break;
 223
 224                                case PDC_CHASSIS_DIRECT_SHUTDOWN:
 225                                        retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_SHUT));
 226                                        break;
 227
 228                                case PDC_CHASSIS_DIRECT_HPMC:
 229                                case PDC_CHASSIS_DIRECT_PANIC:
 230                                        retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_FLT));
 231                                        break;
 232
 233                                case PDC_CHASSIS_DIRECT_LPMC:
 234                                        retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_WARN));
 235                                        break;
 236
 237                                default:
 238                                        retval = -1;
 239                        }
 240                } else retval = -1;
 241#endif /* CONFIG_64BIT */
 242        }       /* if (pdc_chassis_enabled) */
 243#endif /* CONFIG_PDC_CHASSIS */
 244        return retval;
 245}
 246
 247#ifdef CONFIG_PDC_CHASSIS_WARN
 248#ifdef CONFIG_PROC_FS
 249static int pdc_chassis_warn_show(struct seq_file *m, void *v)
 250{
 251        unsigned long warn;
 252        u32 warnreg;
 253
 254        if (pdc_chassis_warn(&warn) != PDC_OK)
 255                return -EIO;
 256
 257        warnreg = (warn & 0xFFFFFFFF);
 258
 259        if ((warnreg >> 24) & 0xFF)
 260                seq_printf(m, "Chassis component failure! (eg fan or PSU): 0x%.2x\n",
 261                           (warnreg >> 24) & 0xFF);
 262
 263        seq_printf(m, "Battery: %s\n", (warnreg & 0x04) ? "Low!" : "OK");
 264        seq_printf(m, "Temp low: %s\n", (warnreg & 0x02) ? "Exceeded!" : "OK");
 265        seq_printf(m, "Temp mid: %s\n", (warnreg & 0x01) ? "Exceeded!" : "OK");
 266        return 0;
 267}
 268
 269static int pdc_chassis_warn_open(struct inode *inode, struct file *file)
 270{
 271        return single_open(file, pdc_chassis_warn_show, NULL);
 272}
 273
 274static const struct file_operations pdc_chassis_warn_fops = {
 275        .open           = pdc_chassis_warn_open,
 276        .read           = seq_read,
 277        .llseek         = seq_lseek,
 278        .release        = single_release,
 279};
 280
 281static int __init pdc_chassis_create_procfs(void)
 282{
 283        unsigned long test;
 284        int ret;
 285
 286        ret = pdc_chassis_warn(&test);
 287        if ((ret == PDC_BAD_PROC) || (ret == PDC_BAD_OPTION)) {
 288                /* seems that some boxes (eg L1000) do not implement this */
 289                printk(KERN_INFO "Chassis warnings not supported.\n");
 290                return 0;
 291        }
 292
 293        printk(KERN_INFO "Enabling PDC chassis warnings support v%s\n",
 294                        PDC_CHASSIS_VER);
 295        proc_create("chassis", 0400, NULL, &pdc_chassis_warn_fops);
 296        return 0;
 297}
 298
 299__initcall(pdc_chassis_create_procfs);
 300
 301#endif /* CONFIG_PROC_FS */
 302#endif /* CONFIG_PDC_CHASSIS_WARN */
 303