aboutsummaryrefslogtreecommitdiffstats
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
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>
-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
-rw-r--r--include/linux/ipmi.h45
-rw-r--r--include/linux/ipmi_msgdefs.h5
-rw-r--r--include/linux/ipmi_smi.h7
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
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};
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 */
411int ipmi_get_maintenance_mode(ipmi_user_t user);
412int 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