aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2006-10-01 02:27:56 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-01 03:39:23 -0400
commitc69c31270c35a6b8421a8e4ba81de1247ac6df95 (patch)
tree5f46902faa683f32a69adbe53c8ec3ca4ed19466
parent54f67f631dfc25ca7a8b19200e34013abc974337 (diff)
[PATCH] IPMI: per-channel command registration
This patch adds the ability to register for a command per-channel in the IPMI driver. If your BMC supports multiple channels, incoming messages can be useful to have the ability to register to receive commands on a specific channel instead the current behaviour of all channels. Signed-off-by: David Barksdale <amatus@ocgnet.org> 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--Documentation/IPMI.txt9
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c34
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c75
-rw-r--r--include/linux/ipmi.h48
4 files changed, 138 insertions, 28 deletions
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
index 0256805b548f..7756e09ea759 100644
--- a/Documentation/IPMI.txt
+++ b/Documentation/IPMI.txt
@@ -326,9 +326,12 @@ for events, they will all receive all events that come in.
326 326
327For receiving commands, you have to individually register commands you 327For receiving commands, you have to individually register commands you
328want to receive. Call ipmi_register_for_cmd() and supply the netfn 328want to receive. Call ipmi_register_for_cmd() and supply the netfn
329and command name for each command you want to receive. Only one user 329and command name for each command you want to receive. You also
330may be registered for each netfn/cmd, but different users may register 330specify a bitmask of the channels you want to receive the command from
331for different commands. 331(or use IPMI_CHAN_ALL for all channels if you don't care). Only one
332user may be registered for each netfn/cmd/channel, but different users
333may register for different commands, or the same command if the
334channel bitmasks do not overlap.
332 335
333From userland, equivalent IOCTLs are provided to do these functions. 336From userland, equivalent IOCTLs are provided to do these functions.
334 337
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 68d7c61a864e..81fcf0ce21d1 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -377,7 +377,8 @@ static int ipmi_ioctl(struct inode *inode,
377 break; 377 break;
378 } 378 }
379 379
380 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd); 380 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
381 IPMI_CHAN_ALL);
381 break; 382 break;
382 } 383 }
383 384
@@ -390,7 +391,36 @@ static int ipmi_ioctl(struct inode *inode,
390 break; 391 break;
391 } 392 }
392 393
393 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd); 394 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
395 IPMI_CHAN_ALL);
396 break;
397 }
398
399 case IPMICTL_REGISTER_FOR_CMD_CHANS:
400 {
401 struct ipmi_cmdspec_chans val;
402
403 if (copy_from_user(&val, arg, sizeof(val))) {
404 rv = -EFAULT;
405 break;
406 }
407
408 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
409 val.chans);
410 break;
411 }
412
413 case IPMICTL_UNREGISTER_FOR_CMD_CHANS:
414 {
415 struct ipmi_cmdspec_chans val;
416
417 if (copy_from_user(&val, arg, sizeof(val))) {
418 rv = -EFAULT;
419 break;
420 }
421
422 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
423 val.chans);
394 break; 424 break;
395 } 425 }
396 426
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 843d34c8627c..2455e8d478ac 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -96,6 +96,7 @@ struct cmd_rcvr
96 ipmi_user_t user; 96 ipmi_user_t user;
97 unsigned char netfn; 97 unsigned char netfn;
98 unsigned char cmd; 98 unsigned char cmd;
99 unsigned int chans;
99 100
100 /* 101 /*
101 * This is used to form a linked lised during mass deletion. 102 * This is used to form a linked lised during mass deletion.
@@ -953,24 +954,41 @@ int ipmi_set_gets_events(ipmi_user_t user, int val)
953 954
954static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, 955static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
955 unsigned char netfn, 956 unsigned char netfn,
956 unsigned char cmd) 957 unsigned char cmd,
958 unsigned char chan)
957{ 959{
958 struct cmd_rcvr *rcvr; 960 struct cmd_rcvr *rcvr;
959 961
960 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { 962 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
961 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) 963 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
964 && (rcvr->chans & (1 << chan)))
962 return rcvr; 965 return rcvr;
963 } 966 }
964 return NULL; 967 return NULL;
965} 968}
966 969
970static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
971 unsigned char netfn,
972 unsigned char cmd,
973 unsigned int chans)
974{
975 struct cmd_rcvr *rcvr;
976
977 list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
978 if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
979 && (rcvr->chans & chans))
980 return 0;
981 }
982 return 1;
983}
984
967int ipmi_register_for_cmd(ipmi_user_t user, 985int ipmi_register_for_cmd(ipmi_user_t user,
968 unsigned char netfn, 986 unsigned char netfn,
969 unsigned char cmd) 987 unsigned char cmd,
988 unsigned int chans)
970{ 989{
971 ipmi_smi_t intf = user->intf; 990 ipmi_smi_t intf = user->intf;
972 struct cmd_rcvr *rcvr; 991 struct cmd_rcvr *rcvr;
973 struct cmd_rcvr *entry;
974 int rv = 0; 992 int rv = 0;
975 993
976 994
@@ -979,12 +997,12 @@ int ipmi_register_for_cmd(ipmi_user_t user,
979 return -ENOMEM; 997 return -ENOMEM;
980 rcvr->cmd = cmd; 998 rcvr->cmd = cmd;
981 rcvr->netfn = netfn; 999 rcvr->netfn = netfn;
1000 rcvr->chans = chans;
982 rcvr->user = user; 1001 rcvr->user = user;
983 1002
984 mutex_lock(&intf->cmd_rcvrs_mutex); 1003 mutex_lock(&intf->cmd_rcvrs_mutex);
985 /* Make sure the command/netfn is not already registered. */ 1004 /* Make sure the command/netfn is not already registered. */
986 entry = find_cmd_rcvr(intf, netfn, cmd); 1005 if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
987 if (entry) {
988 rv = -EBUSY; 1006 rv = -EBUSY;
989 goto out_unlock; 1007 goto out_unlock;
990 } 1008 }
@@ -1001,24 +1019,39 @@ int ipmi_register_for_cmd(ipmi_user_t user,
1001 1019
1002int ipmi_unregister_for_cmd(ipmi_user_t user, 1020int ipmi_unregister_for_cmd(ipmi_user_t user,
1003 unsigned char netfn, 1021 unsigned char netfn,
1004 unsigned char cmd) 1022 unsigned char cmd,
1023 unsigned int chans)
1005{ 1024{
1006 ipmi_smi_t intf = user->intf; 1025 ipmi_smi_t intf = user->intf;
1007 struct cmd_rcvr *rcvr; 1026 struct cmd_rcvr *rcvr;
1027 struct cmd_rcvr *rcvrs = NULL;
1028 int i, rv = -ENOENT;
1008 1029
1009 mutex_lock(&intf->cmd_rcvrs_mutex); 1030 mutex_lock(&intf->cmd_rcvrs_mutex);
1010 /* Make sure the command/netfn is not already registered. */ 1031 for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
1011 rcvr = find_cmd_rcvr(intf, netfn, cmd); 1032 if (((1 << i) & chans) == 0)
1012 if ((rcvr) && (rcvr->user == user)) { 1033 continue;
1013 list_del_rcu(&rcvr->link); 1034 rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
1014 mutex_unlock(&intf->cmd_rcvrs_mutex); 1035 if (rcvr == NULL)
1015 synchronize_rcu(); 1036 continue;
1037 if (rcvr->user == user) {
1038 rv = 0;
1039 rcvr->chans &= ~chans;
1040 if (rcvr->chans == 0) {
1041 list_del_rcu(&rcvr->link);
1042 rcvr->next = rcvrs;
1043 rcvrs = rcvr;
1044 }
1045 }
1046 }
1047 mutex_unlock(&intf->cmd_rcvrs_mutex);
1048 synchronize_rcu();
1049 while (rcvrs) {
1050 rcvr = rcvrs;
1051 rcvrs = rcvr->next;
1016 kfree(rcvr); 1052 kfree(rcvr);
1017 return 0;
1018 } else {
1019 mutex_unlock(&intf->cmd_rcvrs_mutex);
1020 return -ENOENT;
1021 } 1053 }
1054 return rv;
1022} 1055}
1023 1056
1024void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) 1057void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
@@ -2548,6 +2581,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2548 int rv = 0; 2581 int rv = 0;
2549 unsigned char netfn; 2582 unsigned char netfn;
2550 unsigned char cmd; 2583 unsigned char cmd;
2584 unsigned char chan;
2551 ipmi_user_t user = NULL; 2585 ipmi_user_t user = NULL;
2552 struct ipmi_ipmb_addr *ipmb_addr; 2586 struct ipmi_ipmb_addr *ipmb_addr;
2553 struct ipmi_recv_msg *recv_msg; 2587 struct ipmi_recv_msg *recv_msg;
@@ -2568,9 +2602,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
2568 2602
2569 netfn = msg->rsp[4] >> 2; 2603 netfn = msg->rsp[4] >> 2;
2570 cmd = msg->rsp[8]; 2604 cmd = msg->rsp[8];
2605 chan = msg->rsp[3] & 0xf;
2571 2606
2572 rcu_read_lock(); 2607 rcu_read_lock();
2573 rcvr = find_cmd_rcvr(intf, netfn, cmd); 2608 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
2574 if (rcvr) { 2609 if (rcvr) {
2575 user = rcvr->user; 2610 user = rcvr->user;
2576 kref_get(&user->refcount); 2611 kref_get(&user->refcount);
@@ -2728,6 +2763,7 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2728 int rv = 0; 2763 int rv = 0;
2729 unsigned char netfn; 2764 unsigned char netfn;
2730 unsigned char cmd; 2765 unsigned char cmd;
2766 unsigned char chan;
2731 ipmi_user_t user = NULL; 2767 ipmi_user_t user = NULL;
2732 struct ipmi_lan_addr *lan_addr; 2768 struct ipmi_lan_addr *lan_addr;
2733 struct ipmi_recv_msg *recv_msg; 2769 struct ipmi_recv_msg *recv_msg;
@@ -2748,9 +2784,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
2748 2784
2749 netfn = msg->rsp[6] >> 2; 2785 netfn = msg->rsp[6] >> 2;
2750 cmd = msg->rsp[10]; 2786 cmd = msg->rsp[10];
2787 chan = msg->rsp[3] & 0xf;
2751 2788
2752 rcu_read_lock(); 2789 rcu_read_lock();
2753 rcvr = find_cmd_rcvr(intf, netfn, cmd); 2790 rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
2754 if (rcvr) { 2791 if (rcvr) {
2755 user = rcvr->user; 2792 user = rcvr->user;
2756 kref_get(&user->refcount); 2793 kref_get(&user->refcount);
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index d09fbeabf1dc..796ca009fd46 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -148,6 +148,13 @@ struct ipmi_lan_addr
148#define IPMI_BMC_CHANNEL 0xf 148#define IPMI_BMC_CHANNEL 0xf
149#define IPMI_NUM_CHANNELS 0x10 149#define IPMI_NUM_CHANNELS 0x10
150 150
151/*
152 * Used to signify an "all channel" bitmask. This is more than the
153 * actual number of channels because this is used in userland and
154 * will cover us if the number of channels is extended.
155 */
156#define IPMI_CHAN_ALL (~0)
157
151 158
152/* 159/*
153 * A raw IPMI message without any addressing. This covers both 160 * A raw IPMI message without any addressing. This covers both
@@ -350,18 +357,21 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
350 357
351/* 358/*
352 * When commands come in to the SMS, the user can register to receive 359 * When commands come in to the SMS, the user can register to receive
353 * them. Only one user can be listening on a specific netfn/cmd pair 360 * them. Only one user can be listening on a specific netfn/cmd/chan tuple
354 * at a time, you will get an EBUSY error if the command is already 361 * at a time, you will get an EBUSY error if the command is already
355 * registered. If a command is received that does not have a user 362 * registered. If a command is received that does not have a user
356 * registered, the driver will automatically return the proper 363 * registered, the driver will automatically return the proper
357 * error. 364 * error. Channels are specified as a bitfield, use IPMI_CHAN_ALL to
365 * mean all channels.
358 */ 366 */
359int ipmi_register_for_cmd(ipmi_user_t user, 367int ipmi_register_for_cmd(ipmi_user_t user,
360 unsigned char netfn, 368 unsigned char netfn,
361 unsigned char cmd); 369 unsigned char cmd,
370 unsigned int chans);
362int ipmi_unregister_for_cmd(ipmi_user_t user, 371int ipmi_unregister_for_cmd(ipmi_user_t user,
363 unsigned char netfn, 372 unsigned char netfn,
364 unsigned char cmd); 373 unsigned char cmd,
374 unsigned int chans);
365 375
366/* 376/*
367 * Allow run-to-completion mode to be set for the interface of 377 * Allow run-to-completion mode to be set for the interface of
@@ -571,6 +581,36 @@ struct ipmi_cmdspec
571#define IPMICTL_UNREGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 15, \ 581#define IPMICTL_UNREGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 15, \
572 struct ipmi_cmdspec) 582 struct ipmi_cmdspec)
573 583
584/*
585 * Register to get commands from other entities on specific channels.
586 * This way, you can only listen on specific channels, or have messages
587 * from some channels go to one place and other channels to someplace
588 * else. The chans field is a bitmask, (1 << channel) for each channel.
589 * It may be IPMI_CHAN_ALL for all channels.
590 */
591struct ipmi_cmdspec_chans
592{
593 unsigned int netfn;
594 unsigned int cmd;
595 unsigned int chans;
596};
597
598/*
599 * Register to receive a specific command on specific channels. error values:
600 * - EFAULT - an address supplied was invalid.
601 * - EBUSY - One of the netfn/cmd/chans supplied was already in use.
602 * - ENOMEM - could not allocate memory for the entry.
603 */
604#define IPMICTL_REGISTER_FOR_CMD_CHANS _IOR(IPMI_IOC_MAGIC, 28, \
605 struct ipmi_cmdspec_chans)
606/*
607 * Unregister some netfn/cmd/chans. error values:
608 * - EFAULT - an address supplied was invalid.
609 * - ENOENT - None of the netfn/cmd/chans were found registered for this user.
610 */
611#define IPMICTL_UNREGISTER_FOR_CMD_CHANS _IOR(IPMI_IOC_MAGIC, 29, \
612 struct ipmi_cmdspec_chans)
613
574/* 614/*
575 * Set whether this interface receives events. Note that the first 615 * Set whether this interface receives events. Note that the first
576 * user registered for events will get all pending events for the 616 * user registered for events will get all pending events for the