aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi/ipmi_poweroff.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/ipmi/ipmi_poweroff.c')
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c168
1 files changed, 88 insertions, 80 deletions
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index f951c30236c9..e82a96ba396b 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -42,7 +42,6 @@
42#include <linux/ipmi_smi.h> 42#include <linux/ipmi_smi.h>
43 43
44#define PFX "IPMI poweroff: " 44#define PFX "IPMI poweroff: "
45#define IPMI_POWEROFF_VERSION "v33"
46 45
47/* Where to we insert our poweroff function? */ 46/* Where to we insert our poweroff function? */
48extern void (*pm_power_off)(void); 47extern void (*pm_power_off)(void);
@@ -53,16 +52,17 @@ extern void (*pm_power_off)(void);
53#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ 52#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */
54 53
55/* the IPMI data command */ 54/* the IPMI data command */
56static int poweroff_control = IPMI_CHASSIS_POWER_DOWN; 55static int poweroff_powercycle;
57 56
58/* parameter definition to allow user to flag power cycle */ 57/* parameter definition to allow user to flag power cycle */
59module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN); 58module_param(poweroff_powercycle, int, 0);
60MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); 59MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
61 60
62/* Stuff from the get device id command. */ 61/* Stuff from the get device id command. */
63static unsigned int mfg_id; 62static unsigned int mfg_id;
64static unsigned int prod_id; 63static unsigned int prod_id;
65static unsigned char capabilities; 64static unsigned char capabilities;
65static unsigned char ipmi_version;
66 66
67/* We use our own messages for this operation, we don't let the system 67/* We use our own messages for this operation, we don't let the system
68 allocate them, since we may be in a panic situation. The whole 68 allocate them, since we may be in a panic situation. The whole
@@ -338,6 +338,25 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user)
338} 338}
339 339
340/* 340/*
341 * ipmi_dell_chassis_detect()
342 * Dell systems with IPMI < 1.5 don't set the chassis capability bit
343 * but they can handle a chassis poweroff or powercycle command.
344 */
345
346#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
347static int ipmi_dell_chassis_detect (ipmi_user_t user)
348{
349 const char ipmi_version_major = ipmi_version & 0xF;
350 const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
351 const char mfr[3]=DELL_IANA_MFR_ID;
352 if (!memcmp(mfr, &mfg_id, sizeof(mfr)) &&
353 ipmi_version_major <= 1 &&
354 ipmi_version_minor < 5)
355 return 1;
356 return 0;
357}
358
359/*
341 * Standard chassis support 360 * Standard chassis support
342 */ 361 */
343 362
@@ -366,37 +385,34 @@ static void ipmi_poweroff_chassis (ipmi_user_t user)
366 385
367 powercyclefailed: 386 powercyclefailed:
368 printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", 387 printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
369 ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle")); 388 (poweroff_powercycle ? "cycle" : "down"));
370 389
371 /* 390 /*
372 * Power down 391 * Power down
373 */ 392 */
374 send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; 393 send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
375 send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; 394 send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
376 data[0] = poweroff_control; 395 if (poweroff_powercycle)
396 data[0] = IPMI_CHASSIS_POWER_CYCLE;
397 else
398 data[0] = IPMI_CHASSIS_POWER_DOWN;
377 send_msg.data = data; 399 send_msg.data = data;
378 send_msg.data_len = sizeof(data); 400 send_msg.data_len = sizeof(data);
379 rv = ipmi_request_in_rc_mode(user, 401 rv = ipmi_request_in_rc_mode(user,
380 (struct ipmi_addr *) &smi_addr, 402 (struct ipmi_addr *) &smi_addr,
381 &send_msg); 403 &send_msg);
382 if (rv) { 404 if (rv) {
383 switch (poweroff_control) { 405 if (poweroff_powercycle) {
384 case IPMI_CHASSIS_POWER_CYCLE: 406 /* power cycle failed, default to power down */
385 /* power cycle failed, default to power down */ 407 printk(KERN_ERR PFX "Unable to send chassis power " \
386 printk(KERN_ERR PFX "Unable to send chassis power " \ 408 "cycle message, IPMI error 0x%x\n", rv);
387 "cycle message, IPMI error 0x%x\n", rv); 409 poweroff_powercycle = 0;
388 poweroff_control = IPMI_CHASSIS_POWER_DOWN; 410 goto powercyclefailed;
389 goto powercyclefailed;
390
391 case IPMI_CHASSIS_POWER_DOWN:
392 default:
393 printk(KERN_ERR PFX "Unable to send chassis power " \
394 "down message, IPMI error 0x%x\n", rv);
395 break;
396 } 411 }
397 }
398 412
399 return; 413 printk(KERN_ERR PFX "Unable to send chassis power " \
414 "down message, IPMI error 0x%x\n", rv);
415 }
400} 416}
401 417
402 418
@@ -414,6 +430,9 @@ static struct poweroff_function poweroff_functions[] = {
414 { .platform_type = "CPI1", 430 { .platform_type = "CPI1",
415 .detect = ipmi_cpi1_detect, 431 .detect = ipmi_cpi1_detect,
416 .poweroff_func = ipmi_poweroff_cpi1 }, 432 .poweroff_func = ipmi_poweroff_cpi1 },
433 { .platform_type = "chassis",
434 .detect = ipmi_dell_chassis_detect,
435 .poweroff_func = ipmi_poweroff_chassis },
417 /* Chassis should generally be last, other things should override 436 /* Chassis should generally be last, other things should override
418 it. */ 437 it. */
419 { .platform_type = "chassis", 438 { .platform_type = "chassis",
@@ -499,10 +518,11 @@ static void ipmi_po_new_smi(int if_num)
499 prod_id = (halt_recv_msg.msg.data[10] 518 prod_id = (halt_recv_msg.msg.data[10]
500 | (halt_recv_msg.msg.data[11] << 8)); 519 | (halt_recv_msg.msg.data[11] << 8));
501 capabilities = halt_recv_msg.msg.data[6]; 520 capabilities = halt_recv_msg.msg.data[6];
521 ipmi_version = halt_recv_msg.msg.data[5];
502 522
503 523
504 /* Scan for a poweroff method */ 524 /* Scan for a poweroff method */
505 for (i=0; i<NUM_PO_FUNCS; i++) { 525 for (i = 0; i < NUM_PO_FUNCS; i++) {
506 if (poweroff_functions[i].detect(ipmi_user)) 526 if (poweroff_functions[i].detect(ipmi_user))
507 goto found; 527 goto found;
508 } 528 }
@@ -538,39 +558,35 @@ static struct ipmi_smi_watcher smi_watcher =
538 558
539 559
540#ifdef CONFIG_PROC_FS 560#ifdef CONFIG_PROC_FS
541/* displays properties to proc */ 561#include <linux/sysctl.h>
542static int proc_read_chassctrl(char *page, char **start, off_t off, int count, 562
543 int *eof, void *data) 563static ctl_table ipmi_table[] = {
544{ 564 { .ctl_name = DEV_IPMI_POWEROFF_POWERCYCLE,
545 return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n", 565 .procname = "poweroff_powercycle",
546 poweroff_control); 566 .data = &poweroff_powercycle,
547} 567 .maxlen = sizeof(poweroff_powercycle),
568 .mode = 0644,
569 .proc_handler = &proc_dointvec },
570 { }
571};
548 572
549/* process property writes from proc */ 573static ctl_table ipmi_dir_table[] = {
550static int proc_write_chassctrl(struct file *file, const char *buffer, 574 { .ctl_name = DEV_IPMI,
551 unsigned long count, void *data) 575 .procname = "ipmi",
552{ 576 .mode = 0555,
553 int rv = count; 577 .child = ipmi_table },
554 unsigned int newval = 0; 578 { }
555 579};
556 sscanf(buffer, "%d", &newval);
557 switch (newval) {
558 case IPMI_CHASSIS_POWER_CYCLE:
559 printk(KERN_INFO PFX "power cycle is now enabled\n");
560 poweroff_control = newval;
561 break;
562
563 case IPMI_CHASSIS_POWER_DOWN:
564 poweroff_control = IPMI_CHASSIS_POWER_DOWN;
565 break;
566
567 default:
568 rv = -EINVAL;
569 break;
570 }
571 580
572 return rv; 581static ctl_table ipmi_root_table[] = {
573} 582 { .ctl_name = CTL_DEV,
583 .procname = "dev",
584 .mode = 0555,
585 .child = ipmi_dir_table },
586 { }
587};
588
589static struct ctl_table_header *ipmi_table_header;
574#endif /* CONFIG_PROC_FS */ 590#endif /* CONFIG_PROC_FS */
575 591
576/* 592/*
@@ -578,42 +594,32 @@ static int proc_write_chassctrl(struct file *file, const char *buffer,
578 */ 594 */
579static int ipmi_poweroff_init (void) 595static int ipmi_poweroff_init (void)
580{ 596{
581 int rv; 597 int rv;
582 struct proc_dir_entry *file;
583 598
584 printk ("Copyright (C) 2004 MontaVista Software -" 599 printk ("Copyright (C) 2004 MontaVista Software -"
585 " IPMI Powerdown via sys_reboot version " 600 " IPMI Powerdown via sys_reboot.\n");
586 IPMI_POWEROFF_VERSION ".\n"); 601
587 602 if (poweroff_powercycle)
588 switch (poweroff_control) { 603 printk(KERN_INFO PFX "Power cycle is enabled.\n");
589 case IPMI_CHASSIS_POWER_CYCLE: 604
590 printk(KERN_INFO PFX "Power cycle is enabled.\n"); 605#ifdef CONFIG_PROC_FS
591 break; 606 ipmi_table_header = register_sysctl_table(ipmi_root_table, 1);
592 607 if (!ipmi_table_header) {
593 case IPMI_CHASSIS_POWER_DOWN: 608 printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
594 default: 609 rv = -ENOMEM;
595 poweroff_control = IPMI_CHASSIS_POWER_DOWN; 610 goto out_err;
596 break;
597 } 611 }
612#endif
598 613
614#ifdef CONFIG_PROC_FS
599 rv = ipmi_smi_watcher_register(&smi_watcher); 615 rv = ipmi_smi_watcher_register(&smi_watcher);
616#endif
600 if (rv) { 617 if (rv) {
618 unregister_sysctl_table(ipmi_table_header);
601 printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); 619 printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
602 goto out_err; 620 goto out_err;
603 } 621 }
604 622
605#ifdef CONFIG_PROC_FS
606 file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
607 if (!file) {
608 printk(KERN_ERR PFX "Unable to create proc power control\n");
609 } else {
610 file->nlink = 1;
611 file->read_proc = proc_read_chassctrl;
612 file->write_proc = proc_write_chassctrl;
613 file->owner = THIS_MODULE;
614 }
615#endif
616
617 out_err: 623 out_err:
618 return rv; 624 return rv;
619} 625}
@@ -624,7 +630,7 @@ static __exit void ipmi_poweroff_cleanup(void)
624 int rv; 630 int rv;
625 631
626#ifdef CONFIG_PROC_FS 632#ifdef CONFIG_PROC_FS
627 remove_proc_entry("poweroff_control", proc_ipmi_root); 633 unregister_sysctl_table(ipmi_table_header);
628#endif 634#endif
629 635
630 ipmi_smi_watcher_unregister(&smi_watcher); 636 ipmi_smi_watcher_unregister(&smi_watcher);
@@ -642,3 +648,5 @@ module_exit(ipmi_poweroff_cleanup);
642 648
643module_init(ipmi_poweroff_init); 649module_init(ipmi_poweroff_init);
644MODULE_LICENSE("GPL"); 650MODULE_LICENSE("GPL");
651MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
652MODULE_DESCRIPTION("IPMI Poweroff extension to sys_reboot");