Commit c14979b9 authored by Corey Minyard's avatar Corey Minyard Committed by Linus Torvalds

[PATCH] ipmi: add per-channel IPMB addresses

IPMI allows multiple IPMB channels on a single interface, and each channel
might have a different IPMB address.  However, the driver has only one IPMB
address that it uses for everything.  This patch adds new IOCTLS and a new
internal interface for setting per-channel IPMB addresses and LUNs.  New
systems are coming out with support for multiple IPMB channels, and they are
broken without this patch.
Signed-off-by: default avatarCorey Minyard <minyard@acm.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b224cd3a
...@@ -411,6 +411,7 @@ static int ipmi_ioctl(struct inode *inode, ...@@ -411,6 +411,7 @@ static int ipmi_ioctl(struct inode *inode,
break; break;
} }
/* The next four are legacy, not per-channel. */
case IPMICTL_SET_MY_ADDRESS_CMD: case IPMICTL_SET_MY_ADDRESS_CMD:
{ {
unsigned int val; unsigned int val;
...@@ -420,22 +421,25 @@ static int ipmi_ioctl(struct inode *inode, ...@@ -420,22 +421,25 @@ static int ipmi_ioctl(struct inode *inode,
break; break;
} }
ipmi_set_my_address(priv->user, val); rv = ipmi_set_my_address(priv->user, 0, val);
rv = 0;
break; break;
} }
case IPMICTL_GET_MY_ADDRESS_CMD: case IPMICTL_GET_MY_ADDRESS_CMD:
{ {
unsigned int val; unsigned int val;
unsigned char rval;
val = ipmi_get_my_address(priv->user); rv = ipmi_get_my_address(priv->user, 0, &rval);
if (rv)
break;
val = rval;
if (copy_to_user(arg, &val, sizeof(val))) { if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT; rv = -EFAULT;
break; break;
} }
rv = 0;
break; break;
} }
...@@ -448,24 +452,94 @@ static int ipmi_ioctl(struct inode *inode, ...@@ -448,24 +452,94 @@ static int ipmi_ioctl(struct inode *inode,
break; break;
} }
ipmi_set_my_LUN(priv->user, val); rv = ipmi_set_my_LUN(priv->user, 0, val);
rv = 0;
break; break;
} }
case IPMICTL_GET_MY_LUN_CMD: case IPMICTL_GET_MY_LUN_CMD:
{ {
unsigned int val; unsigned int val;
unsigned char rval;
rv = ipmi_get_my_LUN(priv->user, 0, &rval);
if (rv)
break;
val = ipmi_get_my_LUN(priv->user); val = rval;
if (copy_to_user(arg, &val, sizeof(val))) { if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT; rv = -EFAULT;
break; break;
} }
rv = 0;
break; break;
} }
case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
{
struct ipmi_channel_lun_address_set val;
if (copy_from_user(&val, arg, sizeof(val))) {
rv = -EFAULT;
break;
}
return ipmi_set_my_address(priv->user, val.channel, val.value);
break;
}
case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
{
struct ipmi_channel_lun_address_set val;
if (copy_from_user(&val, arg, sizeof(val))) {
rv = -EFAULT;
break;
}
rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
if (rv)
break;
if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT;
break;
}
break;
}
case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
{
struct ipmi_channel_lun_address_set val;
if (copy_from_user(&val, arg, sizeof(val))) {
rv = -EFAULT;
break;
}
rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
break;
}
case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
{
struct ipmi_channel_lun_address_set val;
if (copy_from_user(&val, arg, sizeof(val))) {
rv = -EFAULT;
break;
}
rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
if (rv)
break;
if (copy_to_user(arg, &val, sizeof(val))) {
rv = -EFAULT;
break;
}
break;
}
case IPMICTL_SET_TIMING_PARMS_CMD: case IPMICTL_SET_TIMING_PARMS_CMD:
{ {
struct ipmi_timing_parms parms; struct ipmi_timing_parms parms;
......
...@@ -124,6 +124,14 @@ struct ipmi_channel ...@@ -124,6 +124,14 @@ struct ipmi_channel
{ {
unsigned char medium; unsigned char medium;
unsigned char protocol; unsigned char protocol;
/* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
but may be changed by the user. */
unsigned char address;
/* My LUN. This should generally stay the SMS LUN, but just in
case... */
unsigned char lun;
}; };
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -135,7 +143,7 @@ struct ipmi_proc_entry ...@@ -135,7 +143,7 @@ struct ipmi_proc_entry
#endif #endif
#define IPMI_IPMB_NUM_SEQ 64 #define IPMI_IPMB_NUM_SEQ 64
#define IPMI_MAX_CHANNELS 8 #define IPMI_MAX_CHANNELS 16
struct ipmi_smi struct ipmi_smi
{ {
/* What interface number are we? */ /* What interface number are we? */
...@@ -199,14 +207,6 @@ struct ipmi_smi ...@@ -199,14 +207,6 @@ struct ipmi_smi
this is registered. */ this is registered. */
ipmi_user_t all_cmd_rcvr; ipmi_user_t all_cmd_rcvr;
/* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
but may be changed by the user. */
unsigned char my_address;
/* My LUN. This should generally stay the SMS LUN, but just in
case... */
unsigned char my_lun;
/* The event receiver for my BMC, only really used at panic /* The event receiver for my BMC, only really used at panic
shutdown as a place to store this. */ shutdown as a place to store this. */
unsigned char event_receiver; unsigned char event_receiver;
...@@ -766,26 +766,44 @@ void ipmi_get_version(ipmi_user_t user, ...@@ -766,26 +766,44 @@ void ipmi_get_version(ipmi_user_t user,
*minor = user->intf->version_minor; *minor = user->intf->version_minor;
} }
void ipmi_set_my_address(ipmi_user_t user, int ipmi_set_my_address(ipmi_user_t user,
unsigned int channel,
unsigned char address) unsigned char address)
{ {
user->intf->my_address = address; if (channel >= IPMI_MAX_CHANNELS)
return -EINVAL;
user->intf->channels[channel].address = address;
return 0;
} }
unsigned char ipmi_get_my_address(ipmi_user_t user) int ipmi_get_my_address(ipmi_user_t user,
unsigned int channel,
unsigned char *address)
{ {
return user->intf->my_address; if (channel >= IPMI_MAX_CHANNELS)
return -EINVAL;
*address = user->intf->channels[channel].address;
return 0;
} }
void ipmi_set_my_LUN(ipmi_user_t user, int ipmi_set_my_LUN(ipmi_user_t user,
unsigned int channel,
unsigned char LUN) unsigned char LUN)
{ {
user->intf->my_lun = LUN & 0x3; if (channel >= IPMI_MAX_CHANNELS)
return -EINVAL;
user->intf->channels[channel].lun = LUN & 0x3;
return 0;
} }
unsigned char ipmi_get_my_LUN(ipmi_user_t user) int ipmi_get_my_LUN(ipmi_user_t user,
unsigned int channel,
unsigned char *address)
{ {
return user->intf->my_lun; if (channel >= IPMI_MAX_CHANNELS)
return -EINVAL;
*address = user->intf->channels[channel].lun;
return 0;
} }
int ipmi_set_gets_events(ipmi_user_t user, int val) int ipmi_set_gets_events(ipmi_user_t user, int val)
...@@ -1213,7 +1231,7 @@ static inline int i_ipmi_request(ipmi_user_t user, ...@@ -1213,7 +1231,7 @@ static inline int i_ipmi_request(ipmi_user_t user,
unsigned char ipmb_seq; unsigned char ipmb_seq;
long seqid; long seqid;
if (addr->channel > IPMI_NUM_CHANNELS) { if (addr->channel >= IPMI_NUM_CHANNELS) {
spin_lock_irqsave(&intf->counter_lock, flags); spin_lock_irqsave(&intf->counter_lock, flags);
intf->sent_invalid_commands++; intf->sent_invalid_commands++;
spin_unlock_irqrestore(&intf->counter_lock, flags); spin_unlock_irqrestore(&intf->counter_lock, flags);
...@@ -1346,6 +1364,18 @@ static inline int i_ipmi_request(ipmi_user_t user, ...@@ -1346,6 +1364,18 @@ static inline int i_ipmi_request(ipmi_user_t user,
return rv; return rv;
} }
static int check_addr(ipmi_smi_t intf,
struct ipmi_addr *addr,
unsigned char *saddr,
unsigned char *lun)
{
if (addr->channel >= IPMI_MAX_CHANNELS)
return -EINVAL;
*lun = intf->channels[addr->channel].lun;
*saddr = intf->channels[addr->channel].address;
return 0;
}
int ipmi_request_settime(ipmi_user_t user, int ipmi_request_settime(ipmi_user_t user,
struct ipmi_addr *addr, struct ipmi_addr *addr,
long msgid, long msgid,
...@@ -1355,6 +1385,12 @@ int ipmi_request_settime(ipmi_user_t user, ...@@ -1355,6 +1385,12 @@ int ipmi_request_settime(ipmi_user_t user,
int retries, int retries,
unsigned int retry_time_ms) unsigned int retry_time_ms)
{ {
unsigned char saddr, lun;
int rv;
rv = check_addr(user->intf, addr, &saddr, &lun);
if (rv)
return rv;
return i_ipmi_request(user, return i_ipmi_request(user,
user->intf, user->intf,
addr, addr,
...@@ -1363,8 +1399,8 @@ int ipmi_request_settime(ipmi_user_t user, ...@@ -1363,8 +1399,8 @@ int ipmi_request_settime(ipmi_user_t user,
user_msg_data, user_msg_data,
NULL, NULL, NULL, NULL,
priority, priority,
user->intf->my_address, saddr,
user->intf->my_lun, lun,
retries, retries,
retry_time_ms); retry_time_ms);
} }
...@@ -1378,6 +1414,12 @@ int ipmi_request_supply_msgs(ipmi_user_t user, ...@@ -1378,6 +1414,12 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
struct ipmi_recv_msg *supplied_recv, struct ipmi_recv_msg *supplied_recv,
int priority) int priority)
{ {
unsigned char saddr, lun;
int rv;
rv = check_addr(user->intf, addr, &saddr, &lun);
if (rv)
return rv;
return i_ipmi_request(user, return i_ipmi_request(user,
user->intf, user->intf,
addr, addr,
...@@ -1387,8 +1429,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user, ...@@ -1387,8 +1429,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
supplied_smi, supplied_smi,
supplied_recv, supplied_recv,
priority, priority,
user->intf->my_address, saddr,
user->intf->my_lun, lun,
-1, 0); -1, 0);
} }
...@@ -1397,8 +1439,15 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off, ...@@ -1397,8 +1439,15 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off,
{ {
char *out = (char *) page; char *out = (char *) page;
ipmi_smi_t intf = data; ipmi_smi_t intf = data;
int i;
int rv= 0;
return sprintf(out, "%x\n", intf->my_address); for (i=0; i<IPMI_MAX_CHANNELS; i++)
rv += sprintf(out+rv, "%x ", intf->channels[i].address);
out[rv-1] = '\n'; /* Replace the final space with a newline */
out[rv] = '\0';
rv++;
return rv;
} }
static int version_file_read_proc(char *page, char **start, off_t off, static int version_file_read_proc(char *page, char **start, off_t off,
...@@ -1592,8 +1641,8 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan) ...@@ -1592,8 +1641,8 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
NULL, NULL,
NULL, NULL,
0, 0,
intf->my_address, intf->channels[0].address,
intf->my_lun, intf->channels[0].lun,
-1, 0); -1, 0);
} }
...@@ -1696,11 +1745,13 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ...@@ -1696,11 +1745,13 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
new_intf->intf_num = i; new_intf->intf_num = i;
new_intf->version_major = version_major; new_intf->version_major = version_major;
new_intf->version_minor = version_minor; new_intf->version_minor = version_minor;
if (slave_addr == 0) for (j=0; j<IPMI_MAX_CHANNELS; j++) {
new_intf->my_address = IPMI_BMC_SLAVE_ADDR; new_intf->channels[j].address
else = IPMI_BMC_SLAVE_ADDR;
new_intf->my_address = slave_addr; new_intf->channels[j].lun = 2;
new_intf->my_lun = 2; /* the SMS LUN. */ }
if (slave_addr != 0)
new_intf->channels[0].address = slave_addr;
rwlock_init(&(new_intf->users_lock)); rwlock_init(&(new_intf->users_lock));
INIT_LIST_HEAD(&(new_intf->users)); INIT_LIST_HEAD(&(new_intf->users));
new_intf->handlers = handlers; new_intf->handlers = handlers;
...@@ -1985,7 +2036,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, ...@@ -1985,7 +2036,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
msg->data[3] = msg->rsp[6]; msg->data[3] = msg->rsp[6];
msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
msg->data[5] = ipmb_checksum(&(msg->data[3]), 2); msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
msg->data[6] = intf->my_address; msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
/* rqseq/lun */ /* rqseq/lun */
msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
msg->data[8] = msg->rsp[8]; /* cmd */ msg->data[8] = msg->rsp[8]; /* cmd */
...@@ -2919,8 +2970,8 @@ static void send_panic_events(char *str) ...@@ -2919,8 +2970,8 @@ static void send_panic_events(char *str)
&smi_msg, &smi_msg,
&recv_msg, &recv_msg,
0, 0,
intf->my_address, intf->channels[0].address,
intf->my_lun, intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */ 0, 1); /* Don't retry, and don't wait. */
} }
...@@ -2965,8 +3016,8 @@ static void send_panic_events(char *str) ...@@ -2965,8 +3016,8 @@ static void send_panic_events(char *str)
&smi_msg, &smi_msg,
&recv_msg, &recv_msg,
0, 0,
intf->my_address, intf->channels[0].address,
intf->my_lun, intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */ 0, 1); /* Don't retry, and don't wait. */
if (intf->local_event_generator) { if (intf->local_event_generator) {
...@@ -2985,8 +3036,8 @@ static void send_panic_events(char *str) ...@@ -2985,8 +3036,8 @@ static void send_panic_events(char *str)
&smi_msg, &smi_msg,
&recv_msg, &recv_msg,
0, 0,
intf->my_address, intf->channels[0].address,
intf->my_lun, intf->channels[0].lun,
0, 1); /* no retry, and no wait. */ 0, 1); /* no retry, and no wait. */
} }
intf->null_user_handler = NULL; intf->null_user_handler = NULL;
...@@ -2996,7 +3047,7 @@ static void send_panic_events(char *str) ...@@ -2996,7 +3047,7 @@ static void send_panic_events(char *str)
be zero, and it must not be my address. */ be zero, and it must not be my address. */
if (((intf->event_receiver & 1) == 0) if (((intf->event_receiver & 1) == 0)
&& (intf->event_receiver != 0) && (intf->event_receiver != 0)
&& (intf->event_receiver != intf->my_address)) && (intf->event_receiver != intf->channels[0].address))
{ {
/* The event receiver is valid, send an IPMB /* The event receiver is valid, send an IPMB
message. */ message. */
...@@ -3031,7 +3082,7 @@ static void send_panic_events(char *str) ...@@ -3031,7 +3082,7 @@ static void send_panic_events(char *str)
data[0] = 0; data[0] = 0;
data[1] = 0; data[1] = 0;
data[2] = 0xf0; /* OEM event without timestamp. */ data[2] = 0xf0; /* OEM event without timestamp. */
data[3] = intf->my_address; data[3] = intf->channels[0].address;
data[4] = j++; /* sequence # */ data[4] = j++; /* sequence # */
/* Always give 11 bytes, so strncpy will fill /* Always give 11 bytes, so strncpy will fill
it with zeroes for me. */ it with zeroes for me. */
...@@ -3047,8 +3098,8 @@ static void send_panic_events(char *str) ...@@ -3047,8 +3098,8 @@ static void send_panic_events(char *str)
&smi_msg, &smi_msg,
&recv_msg, &recv_msg,
0, 0,
intf->my_address, intf->channels[0].address,
intf->my_lun, intf->channels[0].lun,
0, 1); /* no retry, and no wait. */ 0, 1); /* no retry, and no wait. */
} }
} }
......
...@@ -298,13 +298,19 @@ void ipmi_get_version(ipmi_user_t user, ...@@ -298,13 +298,19 @@ void ipmi_get_version(ipmi_user_t user,
this user, so it will affect all users of this interface. This is this user, so it will affect all users of this interface. This is
so some initialization code can come in and do the OEM-specific so some initialization code can come in and do the OEM-specific
things it takes to determine your address (if not the BMC) and set things it takes to determine your address (if not the BMC) and set
it for everyone else. */ it for everyone else. Note that each channel can have its own address. */
void ipmi_set_my_address(ipmi_user_t user, int ipmi_set_my_address(ipmi_user_t user,
unsigned int channel,
unsigned char address); unsigned char address);
unsigned char ipmi_get_my_address(ipmi_user_t user); int ipmi_get_my_address(ipmi_user_t user,
void ipmi_set_my_LUN(ipmi_user_t user, unsigned int channel,
unsigned char *address);
int ipmi_set_my_LUN(ipmi_user_t user,
unsigned int channel,
unsigned char LUN); unsigned char LUN);
unsigned char ipmi_get_my_LUN(ipmi_user_t user); int ipmi_get_my_LUN(ipmi_user_t user,
unsigned int channel,
unsigned char *LUN);
/* /*
* Like ipmi_request, but lets you specify the number of retries and * Like ipmi_request, but lets you specify the number of retries and
...@@ -585,6 +591,16 @@ struct ipmi_cmdspec ...@@ -585,6 +591,16 @@ struct ipmi_cmdspec
* things it takes to determine your address (if not the BMC) and set * things it takes to determine your address (if not the BMC) and set
* it for everyone else. You should probably leave the LUN alone. * it for everyone else. You should probably leave the LUN alone.
*/ */
struct ipmi_channel_lun_address_set
{
unsigned short channel;
unsigned char value;
};
#define IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 24, struct ipmi_channel_lun_address_set)
#define IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 25, struct ipmi_channel_lun_address_set)
#define IPMICTL_SET_MY_CHANNEL_LUN_CMD _IOR(IPMI_IOC_MAGIC, 26, struct ipmi_channel_lun_address_set)
#define IPMICTL_GET_MY_CHANNEL_LUN_CMD _IOR(IPMI_IOC_MAGIC, 27, struct ipmi_channel_lun_address_set)
/* Legacy interfaces, these only set IPMB 0. */
#define IPMICTL_SET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 17, unsigned int) #define IPMICTL_SET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 17, unsigned int)
#define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int) #define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int)
#define IPMICTL_SET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 19, unsigned int) #define IPMICTL_SET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 19, unsigned int)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment