diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/ipmi/ipmi_devintf.c | 25 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 117 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 9 |
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 | ||
53 | static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); | 53 | static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); |
54 | static int ipmi_init_msghandler(void); | 54 | static int ipmi_init_msghandler(void); |
@@ -59,6 +59,9 @@ static int initialized = 0; | |||
59 | static struct proc_dir_entry *proc_ipmi_root = NULL; | 59 | static 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 | ||
997 | int 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 | } | ||
1008 | EXPORT_SYMBOL(ipmi_get_maintenance_mode); | ||
1009 | |||
1010 | static 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 | |||
1017 | int 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 | } | ||
1054 | EXPORT_SYMBOL(ipmi_set_maintenance_mode); | ||
1055 | |||
988 | int ipmi_set_gets_events(ipmi_user_t user, int val) | 1056 | int 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 | ||
952 | static 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 | |||
952 | static struct ipmi_smi_handlers handlers = | 960 | static 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 | }; |