Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+84 −10
Original line number Diff line number Diff line
@@ -411,6 +411,7 @@ static int ipmi_ioctl(struct inode *inode,
		break;
	}

	/* The next four are legacy, not per-channel. */
	case IPMICTL_SET_MY_ADDRESS_CMD:
	{
		unsigned int val;
@@ -420,22 +421,25 @@ static int ipmi_ioctl(struct inode *inode,
			break;
		}

		ipmi_set_my_address(priv->user, val);
		rv = 0;
		rv = ipmi_set_my_address(priv->user, 0, val);
		break;
	}

	case IPMICTL_GET_MY_ADDRESS_CMD:
	{
		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))) {
			rv = -EFAULT;
			break;
		}
		rv = 0;
		break;
	}

@@ -448,24 +452,94 @@ static int ipmi_ioctl(struct inode *inode,
			break;
		}

		ipmi_set_my_LUN(priv->user, val);
		rv = 0;
		rv = ipmi_set_my_LUN(priv->user, 0, val);
		break;
	}

	case IPMICTL_GET_MY_LUN_CMD:
	{
		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))) {
			rv = -EFAULT;
			break;
		}
		rv = 0;
		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:
	{
		struct ipmi_timing_parms parms;
+94 −43
Original line number Diff line number Diff line
@@ -124,6 +124,14 @@ struct ipmi_channel
{
	unsigned char medium;
	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
@@ -135,7 +143,7 @@ struct ipmi_proc_entry
#endif

#define IPMI_IPMB_NUM_SEQ	64
#define IPMI_MAX_CHANNELS       8
#define IPMI_MAX_CHANNELS       16
struct ipmi_smi
{
	/* What interface number are we? */
@@ -199,14 +207,6 @@ struct ipmi_smi
	   this is registered. */
	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
	   shutdown as a place to store this. */
	unsigned char event_receiver;
@@ -766,26 +766,44 @@ void ipmi_get_version(ipmi_user_t user,
	*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)
{
	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)
{
	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)
@@ -1213,7 +1231,7 @@ static inline int i_ipmi_request(ipmi_user_t user,
		unsigned char         ipmb_seq;
		long                  seqid;

		if (addr->channel > IPMI_NUM_CHANNELS) {
		if (addr->channel >= IPMI_NUM_CHANNELS) {
			spin_lock_irqsave(&intf->counter_lock, flags);
			intf->sent_invalid_commands++;
			spin_unlock_irqrestore(&intf->counter_lock, flags);
@@ -1346,6 +1364,18 @@ static inline int i_ipmi_request(ipmi_user_t user,
	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,
			 struct ipmi_addr *addr,
			 long             msgid,
@@ -1355,6 +1385,12 @@ int ipmi_request_settime(ipmi_user_t user,
			 int              retries,
			 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,
			      user->intf,
			      addr,
@@ -1363,8 +1399,8 @@ int ipmi_request_settime(ipmi_user_t user,
			      user_msg_data,
			      NULL, NULL,
			      priority,
			      user->intf->my_address,
			      user->intf->my_lun,
			      saddr,
			      lun,
			      retries,
			      retry_time_ms);
}
@@ -1378,6 +1414,12 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
			     struct ipmi_recv_msg *supplied_recv,
			     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,
			      user->intf,
			      addr,
@@ -1387,8 +1429,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
			      supplied_smi,
			      supplied_recv,
			      priority,
			      user->intf->my_address,
			      user->intf->my_lun,
			      saddr,
			      lun,
			      -1, 0);
}

@@ -1397,8 +1439,15 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off,
{
	char       *out = (char *) page;
	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,
@@ -1592,8 +1641,8 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
			      NULL,
			      NULL,
			      0,
			      intf->my_address,
			      intf->my_lun,
			      intf->channels[0].address,
			      intf->channels[0].lun,
			      -1, 0);
}

@@ -1696,11 +1745,13 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
			new_intf->intf_num = i;
			new_intf->version_major = version_major;
			new_intf->version_minor = version_minor;
			if (slave_addr == 0)
				new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
			else
				new_intf->my_address = slave_addr;
			new_intf->my_lun = 2;  /* the SMS LUN. */
			for (j=0; j<IPMI_MAX_CHANNELS; j++) {
				new_intf->channels[j].address
					= IPMI_BMC_SLAVE_ADDR;
				new_intf->channels[j].lun = 2;
			}
			if (slave_addr != 0)
				new_intf->channels[0].address = slave_addr;
			rwlock_init(&(new_intf->users_lock));
			INIT_LIST_HEAD(&(new_intf->users));
			new_intf->handlers = handlers;
@@ -1985,7 +2036,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
		msg->data[3] = msg->rsp[6];
                msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
		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 */
                msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
		msg->data[8] = msg->rsp[8]; /* cmd */
@@ -2919,8 +2970,8 @@ static void send_panic_events(char *str)
			       &smi_msg,
			       &recv_msg,
			       0,
			       intf->my_address,
			       intf->my_lun,
			       intf->channels[0].address,
			       intf->channels[0].lun,
			       0, 1); /* Don't retry, and don't wait. */
	}

@@ -2965,8 +3016,8 @@ static void send_panic_events(char *str)
			       &smi_msg,
			       &recv_msg,
			       0,
			       intf->my_address,
			       intf->my_lun,
			       intf->channels[0].address,
			       intf->channels[0].lun,
			       0, 1); /* Don't retry, and don't wait. */

		if (intf->local_event_generator) {
@@ -2985,8 +3036,8 @@ static void send_panic_events(char *str)
				       &smi_msg,
				       &recv_msg,
				       0,
				       intf->my_address,
				       intf->my_lun,
				       intf->channels[0].address,
				       intf->channels[0].lun,
				       0, 1); /* no retry, and no wait. */
		}
		intf->null_user_handler = NULL;
@@ -2996,7 +3047,7 @@ static void send_panic_events(char *str)
		   be zero, and it must not be my address. */
                if (((intf->event_receiver & 1) == 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
			   message. */
@@ -3031,7 +3082,7 @@ static void send_panic_events(char *str)
			data[0] = 0;
			data[1] = 0;
			data[2] = 0xf0; /* OEM event without timestamp. */
			data[3] = intf->my_address;
			data[3] = intf->channels[0].address;
			data[4] = j++; /* sequence # */
			/* Always give 11 bytes, so strncpy will fill
			   it with zeroes for me. */
@@ -3047,8 +3098,8 @@ static void send_panic_events(char *str)
				       &smi_msg,
				       &recv_msg,
				       0,
				       intf->my_address,
				       intf->my_lun,
				       intf->channels[0].address,
				       intf->channels[0].lun,
				       0, 1); /* no retry, and no wait. */
		}
	}	
+23 −7
Original line number Diff line number Diff line
@@ -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
   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
   it for everyone else. */
void ipmi_set_my_address(ipmi_user_t   user,
   it for everyone else.  Note that each channel can have its own address. */
int ipmi_set_my_address(ipmi_user_t   user,
			unsigned int  channel,
			unsigned char address);
unsigned char ipmi_get_my_address(ipmi_user_t user);
void ipmi_set_my_LUN(ipmi_user_t   user,
int ipmi_get_my_address(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 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
@@ -585,6 +591,16 @@ struct ipmi_cmdspec
 * things it takes to determine your address (if not the BMC) and set
 * 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_GET_MY_ADDRESS_CMD	_IOR(IPMI_IOC_MAGIC, 18, unsigned int)
#define IPMICTL_SET_MY_LUN_CMD		_IOR(IPMI_IOC_MAGIC, 19, unsigned int)