aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2005-09-06 18:18:42 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:48 -0400
commit56a55ec64806fb56e0cd43b0f726020b74c6689b (patch)
treeccb6709a781bdfaf774aa7774f0c22b6bbc923e8
parent1fdd75bd6cfa60a54b6db91d9256a711ab52fef3 (diff)
[PATCH] ipmi: fix panic ipmb response
The "null message handler" in the IPMI driver is used in startup and panic situations to handle messages. It was only designed to work with messages from the local management controller, but in some cases it was used to get messages from remote managmenet controllers, and the system would then panic. This patch makes the "null message handler" in the IPMI driver more general so it works with any kind of message. 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_msghandler.c107
-rw-r--r--include/linux/ipmi.h3
2 files changed, 69 insertions, 41 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 05293d0e6692..d0ed25278cbb 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -219,7 +219,7 @@ struct ipmi_smi
219 interface comes in with a NULL user, call this routine with 219 interface comes in with a NULL user, call this routine with
220 it. Note that the message will still be freed by the 220 it. Note that the message will still be freed by the
221 caller. This only works on the system interface. */ 221 caller. This only works on the system interface. */
222 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg); 222 void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
223 223
224 /* When we are scanning the channels for an SMI, this will 224 /* When we are scanning the channels for an SMI, this will
225 tell which channel we are scanning. */ 225 tell which channel we are scanning. */
@@ -459,7 +459,27 @@ unsigned int ipmi_addr_length(int addr_type)
459 459
460static void deliver_response(struct ipmi_recv_msg *msg) 460static void deliver_response(struct ipmi_recv_msg *msg)
461{ 461{
462 msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data); 462 if (! msg->user) {
463 ipmi_smi_t intf = msg->user_msg_data;
464 unsigned long flags;
465
466 /* Special handling for NULL users. */
467 if (intf->null_user_handler) {
468 intf->null_user_handler(intf, msg);
469 spin_lock_irqsave(&intf->counter_lock, flags);
470 intf->handled_local_responses++;
471 spin_unlock_irqrestore(&intf->counter_lock, flags);
472 } else {
473 /* No handler, so give up. */
474 spin_lock_irqsave(&intf->counter_lock, flags);
475 intf->unhandled_local_responses++;
476 spin_unlock_irqrestore(&intf->counter_lock, flags);
477 }
478 ipmi_free_recv_msg(msg);
479 } else {
480 msg->user->handler->ipmi_recv_hndl(msg,
481 msg->user->handler_data);
482 }
463} 483}
464 484
465/* Find the next sequence number not being used and add the given 485/* Find the next sequence number not being used and add the given
@@ -1389,6 +1409,8 @@ int ipmi_request_settime(ipmi_user_t user,
1389 unsigned char saddr, lun; 1409 unsigned char saddr, lun;
1390 int rv; 1410 int rv;
1391 1411
1412 if (! user)
1413 return -EINVAL;
1392 rv = check_addr(user->intf, addr, &saddr, &lun); 1414 rv = check_addr(user->intf, addr, &saddr, &lun);
1393 if (rv) 1415 if (rv)
1394 return rv; 1416 return rv;
@@ -1418,6 +1440,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
1418 unsigned char saddr, lun; 1440 unsigned char saddr, lun;
1419 int rv; 1441 int rv;
1420 1442
1443 if (! user)
1444 return -EINVAL;
1421 rv = check_addr(user->intf, addr, &saddr, &lun); 1445 rv = check_addr(user->intf, addr, &saddr, &lun);
1422 if (rv) 1446 if (rv)
1423 return rv; 1447 return rv;
@@ -1638,7 +1662,7 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
1638 (struct ipmi_addr *) &si, 1662 (struct ipmi_addr *) &si,
1639 0, 1663 0,
1640 &msg, 1664 &msg,
1641 NULL, 1665 intf,
1642 NULL, 1666 NULL,
1643 NULL, 1667 NULL,
1644 0, 1668 0,
@@ -1648,19 +1672,20 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
1648} 1672}
1649 1673
1650static void 1674static void
1651channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg) 1675channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
1652{ 1676{
1653 int rv = 0; 1677 int rv = 0;
1654 int chan; 1678 int chan;
1655 1679
1656 if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2)) 1680 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
1657 && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD)) 1681 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
1682 && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
1658 { 1683 {
1659 /* It's the one we want */ 1684 /* It's the one we want */
1660 if (msg->rsp[2] != 0) { 1685 if (msg->msg.data[0] != 0) {
1661 /* Got an error from the channel, just go on. */ 1686 /* Got an error from the channel, just go on. */
1662 1687
1663 if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) { 1688 if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
1664 /* If the MC does not support this 1689 /* If the MC does not support this
1665 command, that is legal. We just 1690 command, that is legal. We just
1666 assume it has one IPMB at channel 1691 assume it has one IPMB at channel
@@ -1677,13 +1702,13 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
1677 } 1702 }
1678 goto next_channel; 1703 goto next_channel;
1679 } 1704 }
1680 if (msg->rsp_size < 6) { 1705 if (msg->msg.data_len < 4) {
1681 /* Message not big enough, just go on. */ 1706 /* Message not big enough, just go on. */
1682 goto next_channel; 1707 goto next_channel;
1683 } 1708 }
1684 chan = intf->curr_channel; 1709 chan = intf->curr_channel;
1685 intf->channels[chan].medium = msg->rsp[4] & 0x7f; 1710 intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
1686 intf->channels[chan].protocol = msg->rsp[5] & 0x1f; 1711 intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
1687 1712
1688 next_channel: 1713 next_channel:
1689 intf->curr_channel++; 1714 intf->curr_channel++;
@@ -2382,6 +2407,14 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
2382 unsigned long flags; 2407 unsigned long flags;
2383 2408
2384 recv_msg = (struct ipmi_recv_msg *) msg->user_data; 2409 recv_msg = (struct ipmi_recv_msg *) msg->user_data;
2410 if (recv_msg == NULL)
2411 {
2412 printk(KERN_WARNING"IPMI message received with no owner. This\n"
2413 "could be because of a malformed message, or\n"
2414 "because of a hardware error. Contact your\n"
2415 "hardware vender for assistance\n");
2416 return 0;
2417 }
2385 2418
2386 /* Make sure the user still exists. */ 2419 /* Make sure the user still exists. */
2387 list_for_each_entry(user, &(intf->users), link) { 2420 list_for_each_entry(user, &(intf->users), link) {
@@ -2392,19 +2425,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
2392 } 2425 }
2393 } 2426 }
2394 2427
2395 if (!found) { 2428 if ((! found) && recv_msg->user) {
2396 /* Special handling for NULL users. */ 2429 /* The user for the message went away, so give up. */
2397 if (!recv_msg->user && intf->null_user_handler){ 2430 spin_lock_irqsave(&intf->counter_lock, flags);
2398 intf->null_user_handler(intf, msg); 2431 intf->unhandled_local_responses++;
2399 spin_lock_irqsave(&intf->counter_lock, flags); 2432 spin_unlock_irqrestore(&intf->counter_lock, flags);
2400 intf->handled_local_responses++;
2401 spin_unlock_irqrestore(&intf->counter_lock, flags);
2402 }else{
2403 /* The user for the message went away, so give up. */
2404 spin_lock_irqsave(&intf->counter_lock, flags);
2405 intf->unhandled_local_responses++;
2406 spin_unlock_irqrestore(&intf->counter_lock, flags);
2407 }
2408 ipmi_free_recv_msg(recv_msg); 2433 ipmi_free_recv_msg(recv_msg);
2409 } else { 2434 } else {
2410 struct ipmi_system_interface_addr *smi_addr; 2435 struct ipmi_system_interface_addr *smi_addr;
@@ -2890,28 +2915,30 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
2890} 2915}
2891 2916
2892#ifdef CONFIG_IPMI_PANIC_STRING 2917#ifdef CONFIG_IPMI_PANIC_STRING
2893static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg) 2918static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2894{ 2919{
2895 if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2)) 2920 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2896 && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD) 2921 && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
2897 && (msg->rsp[2] == IPMI_CC_NO_ERROR)) 2922 && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
2923 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
2898 { 2924 {
2899 /* A get event receiver command, save it. */ 2925 /* A get event receiver command, save it. */
2900 intf->event_receiver = msg->rsp[3]; 2926 intf->event_receiver = msg->msg.data[1];
2901 intf->event_receiver_lun = msg->rsp[4] & 0x3; 2927 intf->event_receiver_lun = msg->msg.data[2] & 0x3;
2902 } 2928 }
2903} 2929}
2904 2930
2905static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg) 2931static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2906{ 2932{
2907 if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2)) 2933 if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2908 && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD) 2934 && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
2909 && (msg->rsp[2] == IPMI_CC_NO_ERROR)) 2935 && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
2936 && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
2910 { 2937 {
2911 /* A get device id command, save if we are an event 2938 /* A get device id command, save if we are an event
2912 receiver or generator. */ 2939 receiver or generator. */
2913 intf->local_sel_device = (msg->rsp[8] >> 2) & 1; 2940 intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
2914 intf->local_event_generator = (msg->rsp[8] >> 5) & 1; 2941 intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
2915 } 2942 }
2916} 2943}
2917#endif 2944#endif
@@ -2967,7 +2994,7 @@ static void send_panic_events(char *str)
2967 &addr, 2994 &addr,
2968 0, 2995 0,
2969 &msg, 2996 &msg,
2970 NULL, 2997 intf,
2971 &smi_msg, 2998 &smi_msg,
2972 &recv_msg, 2999 &recv_msg,
2973 0, 3000 0,
@@ -3013,7 +3040,7 @@ static void send_panic_events(char *str)
3013 &addr, 3040 &addr,
3014 0, 3041 0,
3015 &msg, 3042 &msg,
3016 NULL, 3043 intf,
3017 &smi_msg, 3044 &smi_msg,
3018 &recv_msg, 3045 &recv_msg,
3019 0, 3046 0,
@@ -3033,7 +3060,7 @@ static void send_panic_events(char *str)
3033 &addr, 3060 &addr,
3034 0, 3061 0,
3035 &msg, 3062 &msg,
3036 NULL, 3063 intf,
3037 &smi_msg, 3064 &smi_msg,
3038 &recv_msg, 3065 &recv_msg,
3039 0, 3066 0,
@@ -3095,7 +3122,7 @@ static void send_panic_events(char *str)
3095 &addr, 3122 &addr,
3096 0, 3123 0,
3097 &msg, 3124 &msg,
3098 NULL, 3125 intf,
3099 &smi_msg, 3126 &smi_msg,
3100 &recv_msg, 3127 &recv_msg,
3101 0, 3128 0,
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index dd30adedd07d..938d55b813a5 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -242,7 +242,8 @@ struct ipmi_recv_msg
242 /* The user_msg_data is the data supplied when a message was 242 /* The user_msg_data is the data supplied when a message was
243 sent, if this is a response to a sent message. If this is 243 sent, if this is a response to a sent message. If this is
244 not a response to a sent message, then user_msg_data will 244 not a response to a sent message, then user_msg_data will
245 be NULL. */ 245 be NULL. If the user above is NULL, then this will be the
246 intf. */
246 void *user_msg_data; 247 void *user_msg_data;
247 248
248 /* Call this when done with the message. It will presumably free 249 /* Call this when done with the message. It will presumably free