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

Commit 42c2dc7e authored by Corey Minyard's avatar Corey Minyard
Browse files

ipmi: Break up i_ipmi_request



It was huge, and easily broken into pieces.

Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
parent 6dc1181f
Loading
Loading
Loading
Loading
+344 −310
Original line number Diff line number Diff line
@@ -1703,81 +1703,25 @@ static bool is_maintenance_mode_cmd(struct kernel_ipmi_msg *msg)
		|| (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST));
}

/*
 * Separate from ipmi_request so that the user does not have to be
 * supplied in certain circumstances (mainly at panic time).  If
 * messages are supplied, they will be freed, even if an error
 * occurs.
 */
static int i_ipmi_request(ipmi_user_t          user,
			  ipmi_smi_t           intf,
static int i_ipmi_req_sysintf(ipmi_smi_t             intf,
			      struct ipmi_addr       *addr,
			      long                   msgid,
			      struct kernel_ipmi_msg *msg,
			  void                 *user_msg_data,
			  void                 *supplied_smi,
			  struct ipmi_recv_msg *supplied_recv,
			  int                  priority,
			  unsigned char        source_address,
			  unsigned char        source_lun,
			      struct ipmi_smi_msg    *smi_msg,
			      struct ipmi_recv_msg   *recv_msg,
			      int                    retries,
			      unsigned int           retry_time_ms)
{
	int                      rv = 0;
	struct ipmi_smi_msg      *smi_msg;
	struct ipmi_recv_msg     *recv_msg;
	unsigned long            flags;


	if (supplied_recv)
		recv_msg = supplied_recv;
	else {
		recv_msg = ipmi_alloc_recv_msg();
		if (recv_msg == NULL)
			return -ENOMEM;
	}
	recv_msg->user_msg_data = user_msg_data;

	if (supplied_smi)
		smi_msg = (struct ipmi_smi_msg *) supplied_smi;
	else {
		smi_msg = ipmi_alloc_smi_msg();
		if (smi_msg == NULL) {
			ipmi_free_recv_msg(recv_msg);
			return -ENOMEM;
		}
	}

	rcu_read_lock();
	if (intf->in_shutdown) {
		rv = -ENODEV;
		goto out_err;
	}

	recv_msg->user = user;
	if (user)
		kref_get(&user->refcount);
	recv_msg->msgid = msgid;
	/*
	 * Store the message to send in the receive message so timeout
	 * responses can get the proper response data.
	 */
	recv_msg->msg = *msg;

	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
	struct ipmi_system_interface_addr *smi_addr;

		if (msg->netfn & 1) {
	if (msg->netfn & 1)
		/* Responses are not allowed to the SMI. */
			rv = -EINVAL;
			goto out_err;
		}
		return -EINVAL;

	smi_addr = (struct ipmi_system_interface_addr *) addr;
	if (smi_addr->lun > 3) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EINVAL;
			goto out_err;
		return -EINVAL;
	}

	memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
@@ -1791,11 +1735,12 @@ static int i_ipmi_request(ipmi_user_t user,
		 * the sequence numbers.
		 */
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EINVAL;
			goto out_err;
		return -EINVAL;
	}

	if (is_maintenance_mode_cmd(msg)) {
		unsigned long flags;

		spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
		intf->auto_maintenance_timeout
			= maintenance_mode_timeout_ms;
@@ -1808,10 +1753,9 @@ static int i_ipmi_request(ipmi_user_t user,
				       flags);
	}

		if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
	if (msg->data_len + 2 > IPMI_MAX_MSG_LENGTH) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EMSGSIZE;
			goto out_err;
		return -EMSGSIZE;
	}

	smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
@@ -1819,28 +1763,41 @@ static int i_ipmi_request(ipmi_user_t user,
	smi_msg->msgid = msgid;
	smi_msg->user_data = recv_msg;
	if (msg->data_len > 0)
			memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
		memcpy(&smi_msg->data[2], msg->data, msg->data_len);
	smi_msg->data_size = msg->data_len + 2;
	ipmi_inc_stat(intf, sent_local_commands);
	} else if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) {

	return 0;
}

static int i_ipmi_req_ipmb(ipmi_smi_t             intf,
			   struct ipmi_addr       *addr,
			   long                   msgid,
			   struct kernel_ipmi_msg *msg,
			   struct ipmi_smi_msg    *smi_msg,
			   struct ipmi_recv_msg   *recv_msg,
			   unsigned char          source_address,
			   unsigned char          source_lun,
			   int                    retries,
			   unsigned int           retry_time_ms)
{
	struct ipmi_ipmb_addr *ipmb_addr;
	unsigned char ipmb_seq;
	long seqid;
	int broadcast = 0;
	struct ipmi_channel *chans;
	int rv = 0;

	if (addr->channel >= IPMI_MAX_CHANNELS) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EINVAL;
			goto out_err;
		return -EINVAL;
	}

	chans = READ_ONCE(intf->channel_list)->c;

	if (chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_IPMB) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EINVAL;
			goto out_err;
		return -EINVAL;
	}

	if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
@@ -1860,15 +1817,13 @@ static int i_ipmi_request(ipmi_user_t user,
	 */
	if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EMSGSIZE;
			goto out_err;
		return -EMSGSIZE;
	}

	ipmb_addr = (struct ipmi_ipmb_addr *) addr;
	if (ipmb_addr->lun > 3) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EINVAL;
			goto out_err;
		return -EINVAL;
	}

	memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
@@ -1890,15 +1845,15 @@ static int i_ipmi_request(ipmi_user_t user,
		smi_msg->user_data = recv_msg;
	} else {
		/* It's a command, so get a sequence for it. */
		unsigned long flags;

			spin_lock_irqsave(&(intf->seq_lock), flags);
		spin_lock_irqsave(&intf->seq_lock, flags);

		if (is_maintenance_mode_cmd(msg))
			intf->ipmb_maintenance_mode_timeout =
				maintenance_mode_timeout_ms;

			if (intf->ipmb_maintenance_mode_timeout &&
			    retry_time_ms == 0)
		if (intf->ipmb_maintenance_mode_timeout && retry_time_ms == 0)
			/* Different default in maintenance mode */
			retry_time_ms = default_maintenance_retry_ms;

@@ -1913,15 +1868,12 @@ static int i_ipmi_request(ipmi_user_t user,
				   broadcast,
				   &ipmb_seq,
				   &seqid);
			if (rv) {
		if (rv)
			/*
			 * We have used up all the sequence numbers,
			 * probably, so abort.
			 */
				spin_unlock_irqrestore(&(intf->seq_lock),
						       flags);
			goto out_err;
			}

		ipmi_inc_stat(intf, sent_ipmb_commands);

@@ -1952,18 +1904,32 @@ static int i_ipmi_request(ipmi_user_t user,
		 * know that's pretty paranoid, but I prefer
		 * to be correct.
		 */
			spin_unlock_irqrestore(&(intf->seq_lock), flags);
out_err:
		spin_unlock_irqrestore(&intf->seq_lock, flags);
	}
	} else if (is_lan_addr(addr)) {

	return rv;
}

static int i_ipmi_req_lan(ipmi_smi_t             intf,
			  struct ipmi_addr       *addr,
			  long                   msgid,
			  struct kernel_ipmi_msg *msg,
			  struct ipmi_smi_msg    *smi_msg,
			  struct ipmi_recv_msg   *recv_msg,
			  unsigned char          source_lun,
			  int                    retries,
			  unsigned int           retry_time_ms)
{
	struct ipmi_lan_addr  *lan_addr;
	unsigned char ipmb_seq;
	long seqid;
	struct ipmi_channel *chans;
	int rv = 0;

	if (addr->channel >= IPMI_MAX_CHANNELS) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EINVAL;
			goto out_err;
		return -EINVAL;
	}

	chans = READ_ONCE(intf->channel_list)->c;
@@ -1973,22 +1939,19 @@ static int i_ipmi_request(ipmi_user_t user,
			&& (chans[addr->channel].medium
			    != IPMI_CHANNEL_MEDIUM_ASYNC)) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EINVAL;
			goto out_err;
		return -EINVAL;
	}

	/* 11 for the header and 1 for the checksum. */
	if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EMSGSIZE;
			goto out_err;
		return -EMSGSIZE;
	}

	lan_addr = (struct ipmi_lan_addr *) addr;
	if (lan_addr->lun > 3) {
		ipmi_inc_stat(intf, sent_invalid_commands);
			rv = -EINVAL;
			goto out_err;
		return -EINVAL;
	}

	memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
@@ -2009,8 +1972,9 @@ static int i_ipmi_request(ipmi_user_t user,
		smi_msg->user_data = recv_msg;
	} else {
		/* It's a command, so get a sequence for it. */
		unsigned long flags;

			spin_lock_irqsave(&(intf->seq_lock), flags);
		spin_lock_irqsave(&intf->seq_lock, flags);

		/*
		 * Create a sequence number with a 1 second
@@ -2023,15 +1987,12 @@ static int i_ipmi_request(ipmi_user_t user,
				   0,
				   &ipmb_seq,
				   &seqid);
			if (rv) {
		if (rv)
			/*
			 * We have used up all the sequence numbers,
			 * probably, so abort.
			 */
				spin_unlock_irqrestore(&(intf->seq_lock),
						       flags);
			goto out_err;
			}

		ipmi_inc_stat(intf, sent_lan_commands);

@@ -2061,26 +2022,99 @@ static int i_ipmi_request(ipmi_user_t user,
		 * know that's pretty paranoid, but I prefer
		 * to be correct.
		 */
			spin_unlock_irqrestore(&(intf->seq_lock), flags);
out_err:
		spin_unlock_irqrestore(&intf->seq_lock, flags);
	}

	return rv;
}

/*
 * Separate from ipmi_request so that the user does not have to be
 * supplied in certain circumstances (mainly at panic time).  If
 * messages are supplied, they will be freed, even if an error
 * occurs.
 */
static int i_ipmi_request(ipmi_user_t          user,
			  ipmi_smi_t           intf,
			  struct ipmi_addr     *addr,
			  long                 msgid,
			  struct kernel_ipmi_msg *msg,
			  void                 *user_msg_data,
			  void                 *supplied_smi,
			  struct ipmi_recv_msg *supplied_recv,
			  int                  priority,
			  unsigned char        source_address,
			  unsigned char        source_lun,
			  int                  retries,
			  unsigned int         retry_time_ms)
{
	struct ipmi_smi_msg *smi_msg;
	struct ipmi_recv_msg *recv_msg;
	int rv = 0;

	if (supplied_recv)
		recv_msg = supplied_recv;
	else {
		recv_msg = ipmi_alloc_recv_msg();
		if (recv_msg == NULL)
			return -ENOMEM;
	}
	recv_msg->user_msg_data = user_msg_data;

	if (supplied_smi)
		smi_msg = (struct ipmi_smi_msg *) supplied_smi;
	else {
		smi_msg = ipmi_alloc_smi_msg();
		if (smi_msg == NULL) {
			ipmi_free_recv_msg(recv_msg);
			return -ENOMEM;
		}
	}

	rcu_read_lock();
	if (intf->in_shutdown) {
		rv = -ENODEV;
		goto out_err;
	}

	recv_msg->user = user;
	if (user)
		kref_get(&user->refcount);
	recv_msg->msgid = msgid;
	/*
	 * Store the message to send in the receive message so timeout
	 * responses can get the proper response data.
	 */
	recv_msg->msg = *msg;

	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
		rv = i_ipmi_req_sysintf(intf, addr, msgid, msg, smi_msg,
					recv_msg, retries, retry_time_ms);
	} else if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) {
		rv = i_ipmi_req_ipmb(intf, addr, msgid, msg, smi_msg, recv_msg,
				     source_address, source_lun,
				     retries, retry_time_ms);
	} else if (is_lan_addr(addr)) {
		rv = i_ipmi_req_lan(intf, addr, msgid, msg, smi_msg, recv_msg,
				    source_lun, retries, retry_time_ms);
	} else {
	    /* Unknown address type. */
		ipmi_inc_stat(intf, sent_invalid_commands);
		rv = -EINVAL;
		goto out_err;
	}

	if (rv) {
out_err:
		ipmi_free_smi_msg(smi_msg);
		ipmi_free_recv_msg(recv_msg);
	} else {
		ipmi_debug_msg("Send", smi_msg->data, smi_msg->data_size);

		smi_send(intf, intf->handlers, smi_msg, priority);
	}
	rcu_read_unlock();

	return 0;

 out_err:
	rcu_read_unlock();
	ipmi_free_smi_msg(smi_msg);
	ipmi_free_recv_msg(recv_msg);
	return rv;
}