diff options
-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 | ||||
-rw-r--r-- | include/linux/ipmi.h | 45 | ||||
-rw-r--r-- | include/linux/ipmi_msgdefs.h | 5 | ||||
-rw-r--r-- | include/linux/ipmi_smi.h | 7 |
6 files changed, 207 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 | }; |
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index 796ca009fd46..7a9db390c56a 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h | |||
@@ -208,6 +208,15 @@ struct kernel_ipmi_msg | |||
208 | code as the first byte of the incoming data, unlike a response. */ | 208 | code as the first byte of the incoming data, unlike a response. */ |
209 | 209 | ||
210 | 210 | ||
211 | /* | ||
212 | * Modes for ipmi_set_maint_mode() and the userland IOCTL. The AUTO | ||
213 | * setting is the default and means it will be set on certain | ||
214 | * commands. Hard setting it on and off will override automatic | ||
215 | * operation. | ||
216 | */ | ||
217 | #define IPMI_MAINTENANCE_MODE_AUTO 0 | ||
218 | #define IPMI_MAINTENANCE_MODE_OFF 1 | ||
219 | #define IPMI_MAINTENANCE_MODE_ON 2 | ||
211 | 220 | ||
212 | #ifdef __KERNEL__ | 221 | #ifdef __KERNEL__ |
213 | 222 | ||
@@ -374,6 +383,35 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, | |||
374 | unsigned int chans); | 383 | unsigned int chans); |
375 | 384 | ||
376 | /* | 385 | /* |
386 | * Go into a mode where the driver will not autonomously attempt to do | ||
387 | * things with the interface. It will still respond to attentions and | ||
388 | * interrupts, and it will expect that commands will complete. It | ||
389 | * will not automatcially check for flags, events, or things of that | ||
390 | * nature. | ||
391 | * | ||
392 | * This is primarily used for firmware upgrades. The idea is that | ||
393 | * when you go into firmware upgrade mode, you do this operation | ||
394 | * and the driver will not attempt to do anything but what you tell | ||
395 | * it or what the BMC asks for. | ||
396 | * | ||
397 | * Note that if you send a command that resets the BMC, the driver | ||
398 | * will still expect a response from that command. So the BMC should | ||
399 | * reset itself *after* the response is sent. Resetting before the | ||
400 | * response is just silly. | ||
401 | * | ||
402 | * If in auto maintenance mode, the driver will automatically go into | ||
403 | * maintenance mode for 30 seconds if it sees a cold reset, a warm | ||
404 | * reset, or a firmware NetFN. This means that code that uses only | ||
405 | * firmware NetFN commands to do upgrades will work automatically | ||
406 | * without change, assuming it sends a message every 30 seconds or | ||
407 | * less. | ||
408 | * | ||
409 | * See the IPMI_MAINTENANCE_MODE_xxx defines for what the mode means. | ||
410 | */ | ||
411 | int ipmi_get_maintenance_mode(ipmi_user_t user); | ||
412 | int ipmi_set_maintenance_mode(ipmi_user_t user, int mode); | ||
413 | |||
414 | /* | ||
377 | * Allow run-to-completion mode to be set for the interface of | 415 | * Allow run-to-completion mode to be set for the interface of |
378 | * a specific user. | 416 | * a specific user. |
379 | */ | 417 | */ |
@@ -656,4 +694,11 @@ struct ipmi_timing_parms | |||
656 | #define IPMICTL_GET_TIMING_PARMS_CMD _IOR(IPMI_IOC_MAGIC, 23, \ | 694 | #define IPMICTL_GET_TIMING_PARMS_CMD _IOR(IPMI_IOC_MAGIC, 23, \ |
657 | struct ipmi_timing_parms) | 695 | struct ipmi_timing_parms) |
658 | 696 | ||
697 | /* | ||
698 | * Set the maintenance mode. See ipmi_set_maintenance_mode() above | ||
699 | * for a description of what this does. | ||
700 | */ | ||
701 | #define IPMICTL_GET_MAINTENANCE_MODE_CMD _IOR(IPMI_IOC_MAGIC, 30, int) | ||
702 | #define IPMICTL_SET_MAINTENANCE_MODE_CMD _IOW(IPMI_IOC_MAGIC, 31, int) | ||
703 | |||
659 | #endif /* __LINUX_IPMI_H */ | 704 | #endif /* __LINUX_IPMI_H */ |
diff --git a/include/linux/ipmi_msgdefs.h b/include/linux/ipmi_msgdefs.h index 4d04d8b58a0a..8d6759cc1a71 100644 --- a/include/linux/ipmi_msgdefs.h +++ b/include/linux/ipmi_msgdefs.h | |||
@@ -46,6 +46,8 @@ | |||
46 | #define IPMI_NETFN_APP_REQUEST 0x06 | 46 | #define IPMI_NETFN_APP_REQUEST 0x06 |
47 | #define IPMI_NETFN_APP_RESPONSE 0x07 | 47 | #define IPMI_NETFN_APP_RESPONSE 0x07 |
48 | #define IPMI_GET_DEVICE_ID_CMD 0x01 | 48 | #define IPMI_GET_DEVICE_ID_CMD 0x01 |
49 | #define IPMI_COLD_RESET_CMD 0x02 | ||
50 | #define IPMI_WARM_RESET_CMD 0x03 | ||
49 | #define IPMI_CLEAR_MSG_FLAGS_CMD 0x30 | 51 | #define IPMI_CLEAR_MSG_FLAGS_CMD 0x30 |
50 | #define IPMI_GET_DEVICE_GUID_CMD 0x08 | 52 | #define IPMI_GET_DEVICE_GUID_CMD 0x08 |
51 | #define IPMI_GET_MSG_FLAGS_CMD 0x31 | 53 | #define IPMI_GET_MSG_FLAGS_CMD 0x31 |
@@ -60,6 +62,9 @@ | |||
60 | #define IPMI_NETFN_STORAGE_RESPONSE 0x0b | 62 | #define IPMI_NETFN_STORAGE_RESPONSE 0x0b |
61 | #define IPMI_ADD_SEL_ENTRY_CMD 0x44 | 63 | #define IPMI_ADD_SEL_ENTRY_CMD 0x44 |
62 | 64 | ||
65 | #define IPMI_NETFN_FIRMWARE_REQUEST 0x08 | ||
66 | #define IPMI_NETFN_FIRMWARE_RESPONSE 0x09 | ||
67 | |||
63 | /* The default slave address */ | 68 | /* The default slave address */ |
64 | #define IPMI_BMC_SLAVE_ADDR 0x20 | 69 | #define IPMI_BMC_SLAVE_ADDR 0x20 |
65 | 70 | ||
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index 2cc960da4176..c0633108d05d 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h | |||
@@ -115,6 +115,13 @@ struct ipmi_smi_handlers | |||
115 | poll for operations during things like crash dumps. */ | 115 | poll for operations during things like crash dumps. */ |
116 | void (*poll)(void *send_info); | 116 | void (*poll)(void *send_info); |
117 | 117 | ||
118 | /* Enable/disable firmware maintenance mode. Note that this | ||
119 | is *not* the modes defined, this is simply an on/off | ||
120 | setting. The message handler does the mode handling. Note | ||
121 | that this is called from interupt context, so it cannot | ||
122 | block. */ | ||
123 | void (*set_maintenance_mode)(void *send_info, int enable); | ||
124 | |||
118 | /* Tell the handler that we are using it/not using it. The | 125 | /* Tell the handler that we are using it/not using it. The |
119 | message handler get the modules that this handler belongs | 126 | message handler get the modules that this handler belongs |
120 | to; this function lets the SMI claim any modules that it | 127 | to; this function lets the SMI claim any modules that it |