Commit 6f7f6605 authored by Corey Minyard's avatar Corey Minyard
Browse files

ipmi:msghandler: Export and fix panic messaging capability



Don't have the other users that do things at panic time (the watchdog)
do all this themselves, provide a function to do it.

Also, with the new design where most stuff happens at thread context,
a few things needed to be fixed to avoid doing locking in a panic
context.

Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
parent be816bc4
Loading
Loading
Loading
Loading
+31 −19
Original line number Diff line number Diff line
@@ -2284,6 +2284,7 @@ static int i_ipmi_request(struct ipmi_user *user,
{
	struct ipmi_smi_msg *smi_msg;
	struct ipmi_recv_msg *recv_msg;
	int run_to_completion = READ_ONCE(intf->run_to_completion);
	int rv = 0;

	if (user) {
@@ -2317,6 +2318,7 @@ static int i_ipmi_request(struct ipmi_user *user,
		}
	}

	if (!run_to_completion)
		mutex_lock(&intf->users_mutex);
	if (intf->in_shutdown) {
		rv = -ENODEV;
@@ -2363,6 +2365,7 @@ static int i_ipmi_request(struct ipmi_user *user,

		smi_send(intf, intf->handlers, smi_msg, priority);
	}
	if (!run_to_completion)
		mutex_unlock(&intf->users_mutex);

out:
@@ -4559,7 +4562,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
	    && (msg->data[1] == IPMI_SEND_MSG_CMD)
	    && (msg->user_data == NULL)) {

		if (intf->in_shutdown)
		if (intf->in_shutdown || intf->run_to_completion)
			goto out;

		/*
@@ -4631,6 +4634,9 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
		 */
		struct ipmi_recv_msg *recv_msg;

		if (intf->run_to_completion)
			goto out;

		chan = msg->data[2] & 0x0f;
		if (chan >= IPMI_MAX_CHANNELS)
			/* Invalid channel number */
@@ -4653,6 +4659,9 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
		   && (msg->rsp[1] == IPMI_GET_MSG_CMD)) {
		struct ipmi_channel   *chans;

		if (intf->run_to_completion)
			goto out;

		/* It's from the receive queue. */
		chan = msg->rsp[3] & 0xf;
		if (chan >= IPMI_MAX_CHANNELS) {
@@ -4727,6 +4736,9 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
	} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
		   && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) {
		/* It's an asynchronous event. */
		if (intf->run_to_completion)
			goto out;

		requeue = handle_read_event_rsp(intf, msg);
	} else {
		/* It's a response from the local BMC. */
@@ -4855,15 +4867,6 @@ static void smi_work(struct work_struct *t)

		list_del(&msg->link);

		/*
		 * I would like for this check (and user->destroyed)
		 * to go away, but it's possible that an interface is
		 * processing a message that belongs to the user while
		 * the user is being deleted.  When that response
		 * comes back, it could be queued after the user is
		 * destroyed.  This is simpler than handling it in the
		 * interface.
		 */
		if (refcount_read(&user->destroyed) == 0) {
			ipmi_free_recv_msg(msg);
		} else {
@@ -5222,7 +5225,7 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
/*
 * Inside a panic, send a message and wait for a response.
 */
static void ipmi_panic_request_and_wait(struct ipmi_smi *intf,
static void _ipmi_panic_request_and_wait(struct ipmi_smi *intf,
					 struct ipmi_addr *addr,
					 struct kernel_ipmi_msg *msg)
{
@@ -5254,6 +5257,15 @@ static void ipmi_panic_request_and_wait(struct ipmi_smi *intf,
		ipmi_poll(intf);
}

void ipmi_panic_request_and_wait(struct ipmi_user *user,
				 struct ipmi_addr *addr,
				 struct kernel_ipmi_msg *msg)
{
	user->intf->run_to_completion = 1;
	_ipmi_panic_request_and_wait(user->intf, addr, msg);
}
EXPORT_SYMBOL(ipmi_panic_request_and_wait);

static void event_receiver_fetcher(struct ipmi_smi *intf,
				   struct ipmi_recv_msg *msg)
{
@@ -5322,7 +5334,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
	}

	/* Send the event announcing the panic. */
	ipmi_panic_request_and_wait(intf, &addr, &msg);
	_ipmi_panic_request_and_wait(intf, &addr, &msg);

	/*
	 * On every interface, dump a bunch of OEM event holding the
@@ -5358,7 +5370,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
	msg.data = NULL;
	msg.data_len = 0;
	intf->null_user_handler = device_id_fetcher;
	ipmi_panic_request_and_wait(intf, &addr, &msg);
	_ipmi_panic_request_and_wait(intf, &addr, &msg);

	if (intf->local_event_generator) {
		/* Request the event receiver from the local MC. */
@@ -5367,7 +5379,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
		msg.data = NULL;
		msg.data_len = 0;
		intf->null_user_handler = event_receiver_fetcher;
		ipmi_panic_request_and_wait(intf, &addr, &msg);
		_ipmi_panic_request_and_wait(intf, &addr, &msg);
	}
	intf->null_user_handler = NULL;

@@ -5419,7 +5431,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
		memcpy_and_pad(data+5, 11, p, size, '\0');
		p += size;

		ipmi_panic_request_and_wait(intf, &addr, &msg);
		_ipmi_panic_request_and_wait(intf, &addr, &msg);
	}
}

+10 −0
Original line number Diff line number Diff line
@@ -344,4 +344,14 @@ extern int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data);
/* Helper function for computing the IPMB checksum of some data. */
unsigned char ipmb_checksum(unsigned char *data, int size);

/*
 * For things that must send messages at panic time, like the IPMI watchdog
 * driver that extends the reset time on a panic, use this to send messages
 * from panic context.  Note that this puts the driver into a mode that
 * only works at panic time, so only use it then.
 */
void ipmi_panic_request_and_wait(struct ipmi_user *user,
				 struct ipmi_addr *addr,
				 struct kernel_ipmi_msg *msg);

#endif /* __LINUX_IPMI_H */