aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-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};