aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2006-12-06 23:41:02 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:39:47 -0500
commitb9675136e2ad95156fb93be6155f17590bb26fd7 (patch)
tree009bff8e0074774317b7f3921ed85122cf15bba9 /drivers/char/ipmi
parentb2c03941b50944a268ee4d5823872f220809a3ba (diff)
[PATCH] IPMI: Add maintenance mode
Some commands and operations on a BMC can cause the BMC to "go away" for a while. This can cause the automatic flag processing and other things of that nature to timeout and generate annoying logs, or possibly cause other bad things to happen when in firmware update mode. Add detection of those commands (cold reset, warm reset, and any firmware command) and turns off automatic processing for 30 seconds. It also add a manual override either way. Signed-off-by: Corey Minyard <minyard@acm.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/ipmi')
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c25
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c117
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c9
3 files changed, 150 insertions, 1 deletions
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 81fcf0ce21d1..375d3378eecd 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -596,6 +596,31 @@ static int ipmi_ioctl(struct inode *inode,
596 rv = 0; 596 rv = 0;
597 break; 597 break;
598 } 598 }
599
600 case IPMICTL_GET_MAINTENANCE_MODE_CMD:
601 {
602 int mode;
603
604 mode = ipmi_get_maintenance_mode(priv->user);
605 if (copy_to_user(arg, &mode, sizeof(mode))) {
606 rv = -EFAULT;
607 break;
608 }
609 rv = 0;
610 break;
611 }
612
613 case IPMICTL_SET_MAINTENANCE_MODE_CMD:
614 {
615 int mode;
616
617 if (copy_from_user(&mode, arg, sizeof(mode))) {
618 rv = -EFAULT;
619 break;
620 }
621 rv = ipmi_set_maintenance_mode(priv->user, mode);
622 break;
623 }
599 } 624 }
600 625
601 return rv; 626 return rv;
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 03f32611831d..ff0e68f0386b 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -48,7 +48,7 @@
48 48
49#define PFX "IPMI message handler: " 49#define PFX "IPMI message handler: "
50 50
51#define IPMI_DRIVER_VERSION "39.0" 51#define IPMI_DRIVER_VERSION "39.1"
52 52
53static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); 53static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
54static int ipmi_init_msghandler(void); 54static int ipmi_init_msghandler(void);
@@ -59,6 +59,9 @@ static int initialized = 0;
59static struct proc_dir_entry *proc_ipmi_root = NULL; 59static struct proc_dir_entry *proc_ipmi_root = NULL;
60#endif /* CONFIG_PROC_FS */ 60#endif /* CONFIG_PROC_FS */
61 61
62/* Remain in auto-maintenance mode for this amount of time (in ms). */
63#define IPMI_MAINTENANCE_MODE_TIMEOUT 30000
64
62#define MAX_EVENTS_IN_QUEUE 25 65#define MAX_EVENTS_IN_QUEUE 25
63 66
64/* Don't let a message sit in a queue forever, always time it with at lest 67/* Don't let a message sit in a queue forever, always time it with at lest
@@ -262,6 +265,12 @@ struct ipmi_smi
262 unsigned char local_sel_device; 265 unsigned char local_sel_device;
263 unsigned char local_event_generator; 266 unsigned char local_event_generator;
264 267
268 /* For handling of maintenance mode. */
269 int maintenance_mode;
270 int maintenance_mode_enable;
271 int auto_maintenance_timeout;
272 spinlock_t maintenance_mode_lock; /* Used in a timer... */
273
265 /* A cheap hack, if this is non-null and a message to an 274 /* A cheap hack, if this is non-null and a message to an
266 interface comes in with a NULL user, call this routine with 275 interface comes in with a NULL user, call this routine with
267 it. Note that the message will still be freed by the 276 it. Note that the message will still be freed by the
@@ -985,6 +994,65 @@ int ipmi_get_my_LUN(ipmi_user_t user,
985 return 0; 994 return 0;
986} 995}
987 996
997int ipmi_get_maintenance_mode(ipmi_user_t user)
998{
999 int mode;
1000 unsigned long flags;
1001
1002 spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
1003 mode = user->intf->maintenance_mode;
1004 spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
1005
1006 return mode;
1007}
1008EXPORT_SYMBOL(ipmi_get_maintenance_mode);
1009
1010static void maintenance_mode_update(ipmi_smi_t intf)
1011{
1012 if (intf->handlers->set_maintenance_mode)
1013 intf->handlers->set_maintenance_mode(
1014 intf->send_info, intf->maintenance_mode_enable);
1015}
1016
1017int ipmi_set_maintenance_mode(ipmi_user_t user, int mode)
1018{
1019 int rv = 0;
1020 unsigned long flags;
1021 ipmi_smi_t intf = user->intf;
1022
1023 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1024 if (intf->maintenance_mode != mode) {
1025 switch (mode) {
1026 case IPMI_MAINTENANCE_MODE_AUTO:
1027 intf->maintenance_mode = mode;
1028 intf->maintenance_mode_enable
1029 = (intf->auto_maintenance_timeout > 0);
1030 break;
1031
1032 case IPMI_MAINTENANCE_MODE_OFF:
1033 intf->maintenance_mode = mode;
1034 intf->maintenance_mode_enable = 0;
1035 break;
1036
1037 case IPMI_MAINTENANCE_MODE_ON:
1038 intf->maintenance_mode = mode;
1039 intf->maintenance_mode_enable = 1;
1040 break;
1041
1042 default:
1043 rv = -EINVAL;
1044 goto out_unlock;
1045 }
1046
1047 maintenance_mode_update(intf);
1048 }
1049 out_unlock:
1050 spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
1051
1052 return rv;
1053}
1054EXPORT_SYMBOL(ipmi_set_maintenance_mode);
1055
988int ipmi_set_gets_events(ipmi_user_t user, int val) 1056int ipmi_set_gets_events(ipmi_user_t user, int val)
989{ 1057{
990 unsigned long flags; 1058 unsigned long flags;
@@ -1322,6 +1390,24 @@ static int i_ipmi_request(ipmi_user_t user,
1322 goto out_err; 1390 goto out_err;
1323 } 1391 }
1324 1392
1393 if (((msg->netfn == IPMI_NETFN_APP_REQUEST)
1394 && ((msg->cmd == IPMI_COLD_RESET_CMD)
1395 || (msg->cmd == IPMI_WARM_RESET_CMD)))
1396 || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))
1397 {
1398 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
1399 intf->auto_maintenance_timeout
1400 = IPMI_MAINTENANCE_MODE_TIMEOUT;
1401 if (!intf->maintenance_mode
1402 && !intf->maintenance_mode_enable)
1403 {
1404 intf->maintenance_mode_enable = 1;
1405 maintenance_mode_update(intf);
1406 }
1407 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
1408 flags);
1409 }
1410
1325 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { 1411 if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
1326 spin_lock_irqsave(&intf->counter_lock, flags); 1412 spin_lock_irqsave(&intf->counter_lock, flags);
1327 intf->sent_invalid_commands++; 1413 intf->sent_invalid_commands++;
@@ -2605,6 +2691,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2605 INIT_LIST_HEAD(&intf->waiting_events); 2691 INIT_LIST_HEAD(&intf->waiting_events);
2606 intf->waiting_events_count = 0; 2692 intf->waiting_events_count = 0;
2607 mutex_init(&intf->cmd_rcvrs_mutex); 2693 mutex_init(&intf->cmd_rcvrs_mutex);
2694 spin_lock_init(&intf->maintenance_mode_lock);
2608 INIT_LIST_HEAD(&intf->cmd_rcvrs); 2695 INIT_LIST_HEAD(&intf->cmd_rcvrs);
2609 init_waitqueue_head(&intf->waitq); 2696 init_waitqueue_head(&intf->waitq);
2610 2697
@@ -3593,6 +3680,30 @@ static void ipmi_timeout_handler(long timeout_period)
3593 3680
3594 list_for_each_entry_safe(msg, msg2, &timeouts, link) 3681 list_for_each_entry_safe(msg, msg2, &timeouts, link)
3595 deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE); 3682 deliver_err_response(msg, IPMI_TIMEOUT_COMPLETION_CODE);
3683
3684 /*
3685 * Maintenance mode handling. Check the timeout
3686 * optimistically before we claim the lock. It may
3687 * mean a timeout gets missed occasionally, but that
3688 * only means the timeout gets extended by one period
3689 * in that case. No big deal, and it avoids the lock
3690 * most of the time.
3691 */
3692 if (intf->auto_maintenance_timeout > 0) {
3693 spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
3694 if (intf->auto_maintenance_timeout > 0) {
3695 intf->auto_maintenance_timeout
3696 -= timeout_period;
3697 if (!intf->maintenance_mode
3698 && (intf->auto_maintenance_timeout <= 0))
3699 {
3700 intf->maintenance_mode_enable = 0;
3701 maintenance_mode_update(intf);
3702 }
3703 }
3704 spin_unlock_irqrestore(&intf->maintenance_mode_lock,
3705 flags);
3706 }
3596 } 3707 }
3597 rcu_read_unlock(); 3708 rcu_read_unlock();
3598} 3709}
@@ -3606,6 +3717,10 @@ static void ipmi_request_event(void)
3606 /* Called from the timer, no need to check if handlers is 3717 /* Called from the timer, no need to check if handlers is
3607 * valid. */ 3718 * valid. */
3608 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { 3719 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
3720 /* No event requests when in maintenance mode. */
3721 if (intf->maintenance_mode_enable)
3722 continue;
3723
3609 handlers = intf->handlers; 3724 handlers = intf->handlers;
3610 if (handlers) 3725 if (handlers)
3611 handlers->request_events(intf->send_info); 3726 handlers->request_events(intf->send_info);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 89cdb928061c..f04bee76ba2b 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -949,12 +949,21 @@ static int smi_start_processing(void *send_info,
949 return 0; 949 return 0;
950} 950}
951 951
952static void set_maintenance_mode(void *send_info, int enable)
953{
954 struct smi_info *smi_info = send_info;
955
956 if (!enable)
957 atomic_set(&smi_info->req_events, 0);
958}
959
952static struct ipmi_smi_handlers handlers = 960static struct ipmi_smi_handlers handlers =
953{ 961{
954 .owner = THIS_MODULE, 962 .owner = THIS_MODULE,
955 .start_processing = smi_start_processing, 963 .start_processing = smi_start_processing,
956 .sender = sender, 964 .sender = sender,
957 .request_events = request_events, 965 .request_events = request_events,
966 .set_maintenance_mode = set_maintenance_mode,
958 .set_run_to_completion = set_run_to_completion, 967 .set_run_to_completion = set_run_to_completion,
959 .poll = poll, 968 .poll = poll,
960}; 969};