diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 29 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_poweroff.c | 112 |
2 files changed, 130 insertions, 11 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index ed75e96d0035..1813d0d198f1 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -54,7 +54,9 @@ static int ipmi_init_msghandler(void); | |||
54 | 54 | ||
55 | static int initialized = 0; | 55 | static int initialized = 0; |
56 | 56 | ||
57 | static struct proc_dir_entry *proc_ipmi_root = NULL; | 57 | #ifdef CONFIG_PROC_FS |
58 | struct proc_dir_entry *proc_ipmi_root = NULL; | ||
59 | #endif /* CONFIG_PROC_FS */ | ||
58 | 60 | ||
59 | #define MAX_EVENTS_IN_QUEUE 25 | 61 | #define MAX_EVENTS_IN_QUEUE 25 |
60 | 62 | ||
@@ -124,11 +126,13 @@ struct ipmi_channel | |||
124 | unsigned char protocol; | 126 | unsigned char protocol; |
125 | }; | 127 | }; |
126 | 128 | ||
129 | #ifdef CONFIG_PROC_FS | ||
127 | struct ipmi_proc_entry | 130 | struct ipmi_proc_entry |
128 | { | 131 | { |
129 | char *name; | 132 | char *name; |
130 | struct ipmi_proc_entry *next; | 133 | struct ipmi_proc_entry *next; |
131 | }; | 134 | }; |
135 | #endif | ||
132 | 136 | ||
133 | #define IPMI_IPMB_NUM_SEQ 64 | 137 | #define IPMI_IPMB_NUM_SEQ 64 |
134 | #define IPMI_MAX_CHANNELS 8 | 138 | #define IPMI_MAX_CHANNELS 8 |
@@ -156,10 +160,13 @@ struct ipmi_smi | |||
156 | struct ipmi_smi_handlers *handlers; | 160 | struct ipmi_smi_handlers *handlers; |
157 | void *send_info; | 161 | void *send_info; |
158 | 162 | ||
163 | #ifdef CONFIG_PROC_FS | ||
159 | /* A list of proc entries for this interface. This does not | 164 | /* A list of proc entries for this interface. This does not |
160 | need a lock, only one thread creates it and only one thread | 165 | need a lock, only one thread creates it and only one thread |
161 | destroys it. */ | 166 | destroys it. */ |
167 | spinlock_t proc_entry_lock; | ||
162 | struct ipmi_proc_entry *proc_entries; | 168 | struct ipmi_proc_entry *proc_entries; |
169 | #endif | ||
163 | 170 | ||
164 | /* A table of sequence numbers for this interface. We use the | 171 | /* A table of sequence numbers for this interface. We use the |
165 | sequence numbers for IPMB messages that go out of the | 172 | sequence numbers for IPMB messages that go out of the |
@@ -1470,8 +1477,9 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, | |||
1470 | read_proc_t *read_proc, write_proc_t *write_proc, | 1477 | read_proc_t *read_proc, write_proc_t *write_proc, |
1471 | void *data, struct module *owner) | 1478 | void *data, struct module *owner) |
1472 | { | 1479 | { |
1473 | struct proc_dir_entry *file; | ||
1474 | int rv = 0; | 1480 | int rv = 0; |
1481 | #ifdef CONFIG_PROC_FS | ||
1482 | struct proc_dir_entry *file; | ||
1475 | struct ipmi_proc_entry *entry; | 1483 | struct ipmi_proc_entry *entry; |
1476 | 1484 | ||
1477 | /* Create a list element. */ | 1485 | /* Create a list element. */ |
@@ -1497,10 +1505,13 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, | |||
1497 | file->write_proc = write_proc; | 1505 | file->write_proc = write_proc; |
1498 | file->owner = owner; | 1506 | file->owner = owner; |
1499 | 1507 | ||
1508 | spin_lock(&smi->proc_entry_lock); | ||
1500 | /* Stick it on the list. */ | 1509 | /* Stick it on the list. */ |
1501 | entry->next = smi->proc_entries; | 1510 | entry->next = smi->proc_entries; |
1502 | smi->proc_entries = entry; | 1511 | smi->proc_entries = entry; |
1512 | spin_unlock(&smi->proc_entry_lock); | ||
1503 | } | 1513 | } |
1514 | #endif /* CONFIG_PROC_FS */ | ||
1504 | 1515 | ||
1505 | return rv; | 1516 | return rv; |
1506 | } | 1517 | } |
@@ -1509,6 +1520,7 @@ static int add_proc_entries(ipmi_smi_t smi, int num) | |||
1509 | { | 1520 | { |
1510 | int rv = 0; | 1521 | int rv = 0; |
1511 | 1522 | ||
1523 | #ifdef CONFIG_PROC_FS | ||
1512 | sprintf(smi->proc_dir_name, "%d", num); | 1524 | sprintf(smi->proc_dir_name, "%d", num); |
1513 | smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); | 1525 | smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); |
1514 | if (!smi->proc_dir) | 1526 | if (!smi->proc_dir) |
@@ -1531,14 +1543,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num) | |||
1531 | rv = ipmi_smi_add_proc_entry(smi, "version", | 1543 | rv = ipmi_smi_add_proc_entry(smi, "version", |
1532 | version_file_read_proc, NULL, | 1544 | version_file_read_proc, NULL, |
1533 | smi, THIS_MODULE); | 1545 | smi, THIS_MODULE); |
1546 | #endif /* CONFIG_PROC_FS */ | ||
1534 | 1547 | ||
1535 | return rv; | 1548 | return rv; |
1536 | } | 1549 | } |
1537 | 1550 | ||
1538 | static void remove_proc_entries(ipmi_smi_t smi) | 1551 | static void remove_proc_entries(ipmi_smi_t smi) |
1539 | { | 1552 | { |
1553 | #ifdef CONFIG_PROC_FS | ||
1540 | struct ipmi_proc_entry *entry; | 1554 | struct ipmi_proc_entry *entry; |
1541 | 1555 | ||
1556 | spin_lock(&smi->proc_entry_lock); | ||
1542 | while (smi->proc_entries) { | 1557 | while (smi->proc_entries) { |
1543 | entry = smi->proc_entries; | 1558 | entry = smi->proc_entries; |
1544 | smi->proc_entries = entry->next; | 1559 | smi->proc_entries = entry->next; |
@@ -1547,7 +1562,9 @@ static void remove_proc_entries(ipmi_smi_t smi) | |||
1547 | kfree(entry->name); | 1562 | kfree(entry->name); |
1548 | kfree(entry); | 1563 | kfree(entry); |
1549 | } | 1564 | } |
1565 | spin_unlock(&smi->proc_entry_lock); | ||
1550 | remove_proc_entry(smi->proc_dir_name, proc_ipmi_root); | 1566 | remove_proc_entry(smi->proc_dir_name, proc_ipmi_root); |
1567 | #endif /* CONFIG_PROC_FS */ | ||
1551 | } | 1568 | } |
1552 | 1569 | ||
1553 | static int | 1570 | static int |
@@ -1694,6 +1711,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
1694 | new_intf->seq_table[j].seqid = 0; | 1711 | new_intf->seq_table[j].seqid = 0; |
1695 | } | 1712 | } |
1696 | new_intf->curr_seq = 0; | 1713 | new_intf->curr_seq = 0; |
1714 | #ifdef CONFIG_PROC_FS | ||
1715 | spin_lock_init(&(new_intf->proc_entry_lock)); | ||
1716 | #endif | ||
1697 | spin_lock_init(&(new_intf->waiting_msgs_lock)); | 1717 | spin_lock_init(&(new_intf->waiting_msgs_lock)); |
1698 | INIT_LIST_HEAD(&(new_intf->waiting_msgs)); | 1718 | INIT_LIST_HEAD(&(new_intf->waiting_msgs)); |
1699 | spin_lock_init(&(new_intf->events_lock)); | 1719 | spin_lock_init(&(new_intf->events_lock)); |
@@ -3085,6 +3105,7 @@ static int ipmi_init_msghandler(void) | |||
3085 | ipmi_interfaces[i] = NULL; | 3105 | ipmi_interfaces[i] = NULL; |
3086 | } | 3106 | } |
3087 | 3107 | ||
3108 | #ifdef CONFIG_PROC_FS | ||
3088 | proc_ipmi_root = proc_mkdir("ipmi", NULL); | 3109 | proc_ipmi_root = proc_mkdir("ipmi", NULL); |
3089 | if (!proc_ipmi_root) { | 3110 | if (!proc_ipmi_root) { |
3090 | printk(KERN_ERR PFX "Unable to create IPMI proc dir"); | 3111 | printk(KERN_ERR PFX "Unable to create IPMI proc dir"); |
@@ -3092,6 +3113,7 @@ static int ipmi_init_msghandler(void) | |||
3092 | } | 3113 | } |
3093 | 3114 | ||
3094 | proc_ipmi_root->owner = THIS_MODULE; | 3115 | proc_ipmi_root->owner = THIS_MODULE; |
3116 | #endif /* CONFIG_PROC_FS */ | ||
3095 | 3117 | ||
3096 | init_timer(&ipmi_timer); | 3118 | init_timer(&ipmi_timer); |
3097 | ipmi_timer.data = 0; | 3119 | ipmi_timer.data = 0; |
@@ -3129,7 +3151,9 @@ static __exit void cleanup_ipmi(void) | |||
3129 | atomic_inc(&stop_operation); | 3151 | atomic_inc(&stop_operation); |
3130 | del_timer_sync(&ipmi_timer); | 3152 | del_timer_sync(&ipmi_timer); |
3131 | 3153 | ||
3154 | #ifdef CONFIG_PROC_FS | ||
3132 | remove_proc_entry(proc_ipmi_root->name, &proc_root); | 3155 | remove_proc_entry(proc_ipmi_root->name, &proc_root); |
3156 | #endif /* CONFIG_PROC_FS */ | ||
3133 | 3157 | ||
3134 | initialized = 0; | 3158 | initialized = 0; |
3135 | 3159 | ||
@@ -3170,4 +3194,5 @@ EXPORT_SYMBOL(ipmi_get_my_address); | |||
3170 | EXPORT_SYMBOL(ipmi_set_my_LUN); | 3194 | EXPORT_SYMBOL(ipmi_set_my_LUN); |
3171 | EXPORT_SYMBOL(ipmi_get_my_LUN); | 3195 | EXPORT_SYMBOL(ipmi_get_my_LUN); |
3172 | EXPORT_SYMBOL(ipmi_smi_add_proc_entry); | 3196 | EXPORT_SYMBOL(ipmi_smi_add_proc_entry); |
3197 | EXPORT_SYMBOL(proc_ipmi_root); | ||
3173 | EXPORT_SYMBOL(ipmi_user_set_run_to_completion); | 3198 | EXPORT_SYMBOL(ipmi_user_set_run_to_completion); |
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index cb5cdc6f14bf..61329b55c4a9 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <asm/semaphore.h> | 34 | #include <asm/semaphore.h> |
35 | #include <linux/kdev_t.h> | 35 | #include <linux/kdev_t.h> |
36 | #include <linux/module.h> | 36 | #include <linux/module.h> |
37 | #include <linux/moduleparam.h> | ||
38 | #include <linux/proc_fs.h> | ||
37 | #include <linux/string.h> | 39 | #include <linux/string.h> |
38 | #include <linux/ipmi.h> | 40 | #include <linux/ipmi.h> |
39 | #include <linux/ipmi_smi.h> | 41 | #include <linux/ipmi_smi.h> |
@@ -44,6 +46,18 @@ | |||
44 | /* Where to we insert our poweroff function? */ | 46 | /* Where to we insert our poweroff function? */ |
45 | extern void (*pm_power_off)(void); | 47 | extern void (*pm_power_off)(void); |
46 | 48 | ||
49 | /* Definitions for controlling power off (if the system supports it). It | ||
50 | * conveniently matches the IPMI chassis control values. */ | ||
51 | #define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */ | ||
52 | #define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ | ||
53 | |||
54 | /* the IPMI data command */ | ||
55 | static int poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
56 | |||
57 | /* parameter definition to allow user to flag power cycle */ | ||
58 | module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN); | ||
59 | MODULE_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."); | ||
60 | |||
47 | /* Stuff from the get device id command. */ | 61 | /* Stuff from the get device id command. */ |
48 | static unsigned int mfg_id; | 62 | static unsigned int mfg_id; |
49 | static unsigned int prod_id; | 63 | static unsigned int prod_id; |
@@ -349,26 +363,38 @@ static void ipmi_poweroff_chassis (ipmi_user_t user) | |||
349 | smi_addr.channel = IPMI_BMC_CHANNEL; | 363 | smi_addr.channel = IPMI_BMC_CHANNEL; |
350 | smi_addr.lun = 0; | 364 | smi_addr.lun = 0; |
351 | 365 | ||
352 | printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n"); | 366 | powercyclefailed: |
367 | printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", | ||
368 | ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle")); | ||
353 | 369 | ||
354 | /* | 370 | /* |
355 | * Power down | 371 | * Power down |
356 | */ | 372 | */ |
357 | send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; | 373 | send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; |
358 | send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; | 374 | send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; |
359 | data[0] = 0; /* Power down */ | 375 | data[0] = poweroff_control; |
360 | send_msg.data = data; | 376 | send_msg.data = data; |
361 | send_msg.data_len = sizeof(data); | 377 | send_msg.data_len = sizeof(data); |
362 | rv = ipmi_request_in_rc_mode(user, | 378 | rv = ipmi_request_in_rc_mode(user, |
363 | (struct ipmi_addr *) &smi_addr, | 379 | (struct ipmi_addr *) &smi_addr, |
364 | &send_msg); | 380 | &send_msg); |
365 | if (rv) { | 381 | if (rv) { |
366 | printk(KERN_ERR PFX "Unable to send chassis powerdown message," | 382 | switch (poweroff_control) { |
367 | " IPMI error 0x%x\n", rv); | 383 | case IPMI_CHASSIS_POWER_CYCLE: |
368 | goto out; | 384 | /* power cycle failed, default to power down */ |
385 | printk(KERN_ERR PFX "Unable to send chassis power " \ | ||
386 | "cycle message, IPMI error 0x%x\n", rv); | ||
387 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
388 | goto powercyclefailed; | ||
389 | |||
390 | case IPMI_CHASSIS_POWER_DOWN: | ||
391 | default: | ||
392 | printk(KERN_ERR PFX "Unable to send chassis power " \ | ||
393 | "down message, IPMI error 0x%x\n", rv); | ||
394 | break; | ||
395 | } | ||
369 | } | 396 | } |
370 | 397 | ||
371 | out: | ||
372 | return; | 398 | return; |
373 | } | 399 | } |
374 | 400 | ||
@@ -430,7 +456,8 @@ static void ipmi_po_new_smi(int if_num) | |||
430 | if (ready) | 456 | if (ready) |
431 | return; | 457 | return; |
432 | 458 | ||
433 | rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user); | 459 | rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, |
460 | &ipmi_user); | ||
434 | if (rv) { | 461 | if (rv) { |
435 | printk(KERN_ERR PFX "could not create IPMI user, error %d\n", | 462 | printk(KERN_ERR PFX "could not create IPMI user, error %d\n", |
436 | rv); | 463 | rv); |
@@ -509,21 +536,84 @@ static struct ipmi_smi_watcher smi_watcher = | |||
509 | }; | 536 | }; |
510 | 537 | ||
511 | 538 | ||
539 | #ifdef CONFIG_PROC_FS | ||
540 | /* displays properties to proc */ | ||
541 | static int proc_read_chassctrl(char *page, char **start, off_t off, int count, | ||
542 | int *eof, void *data) | ||
543 | { | ||
544 | return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n", | ||
545 | poweroff_control); | ||
546 | } | ||
547 | |||
548 | /* process property writes from proc */ | ||
549 | static int proc_write_chassctrl(struct file *file, const char *buffer, | ||
550 | unsigned long count, void *data) | ||
551 | { | ||
552 | int rv = count; | ||
553 | unsigned int newval = 0; | ||
554 | |||
555 | sscanf(buffer, "%d", &newval); | ||
556 | switch (newval) { | ||
557 | case IPMI_CHASSIS_POWER_CYCLE: | ||
558 | printk(KERN_INFO PFX "power cycle is now enabled\n"); | ||
559 | poweroff_control = newval; | ||
560 | break; | ||
561 | |||
562 | case IPMI_CHASSIS_POWER_DOWN: | ||
563 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
564 | break; | ||
565 | |||
566 | default: | ||
567 | rv = -EINVAL; | ||
568 | break; | ||
569 | } | ||
570 | |||
571 | return rv; | ||
572 | } | ||
573 | #endif /* CONFIG_PROC_FS */ | ||
574 | |||
512 | /* | 575 | /* |
513 | * Startup and shutdown functions. | 576 | * Startup and shutdown functions. |
514 | */ | 577 | */ |
515 | static int ipmi_poweroff_init (void) | 578 | static int ipmi_poweroff_init (void) |
516 | { | 579 | { |
517 | int rv; | 580 | int rv; |
581 | struct proc_dir_entry *file; | ||
518 | 582 | ||
519 | printk ("Copyright (C) 2004 MontaVista Software -" | 583 | printk ("Copyright (C) 2004 MontaVista Software -" |
520 | " IPMI Powerdown via sys_reboot version " | 584 | " IPMI Powerdown via sys_reboot version " |
521 | IPMI_POWEROFF_VERSION ".\n"); | 585 | IPMI_POWEROFF_VERSION ".\n"); |
522 | 586 | ||
587 | switch (poweroff_control) { | ||
588 | case IPMI_CHASSIS_POWER_CYCLE: | ||
589 | printk(KERN_INFO PFX "Power cycle is enabled.\n"); | ||
590 | break; | ||
591 | |||
592 | case IPMI_CHASSIS_POWER_DOWN: | ||
593 | default: | ||
594 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
595 | break; | ||
596 | } | ||
597 | |||
523 | rv = ipmi_smi_watcher_register(&smi_watcher); | 598 | rv = ipmi_smi_watcher_register(&smi_watcher); |
524 | if (rv) | 599 | if (rv) { |
525 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); | 600 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); |
601 | goto out_err; | ||
602 | } | ||
603 | |||
604 | #ifdef CONFIG_PROC_FS | ||
605 | file = create_proc_entry("poweroff_control", 0, proc_ipmi_root); | ||
606 | if (!file) { | ||
607 | printk(KERN_ERR PFX "Unable to create proc power control\n"); | ||
608 | } else { | ||
609 | file->nlink = 1; | ||
610 | file->read_proc = proc_read_chassctrl; | ||
611 | file->write_proc = proc_write_chassctrl; | ||
612 | file->owner = THIS_MODULE; | ||
613 | } | ||
614 | #endif | ||
526 | 615 | ||
616 | out_err: | ||
527 | return rv; | 617 | return rv; |
528 | } | 618 | } |
529 | 619 | ||
@@ -532,6 +622,10 @@ static __exit void ipmi_poweroff_cleanup(void) | |||
532 | { | 622 | { |
533 | int rv; | 623 | int rv; |
534 | 624 | ||
625 | #ifdef CONFIG_PROC_FS | ||
626 | remove_proc_entry("poweroff_control", proc_ipmi_root); | ||
627 | #endif | ||
628 | |||
535 | ipmi_smi_watcher_unregister(&smi_watcher); | 629 | ipmi_smi_watcher_unregister(&smi_watcher); |
536 | 630 | ||
537 | if (ready) { | 631 | if (ready) { |