Commit 6e4dc3d5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus-5.10-1' of git://github.com/cminyard/linux-ipmi

Pull IPMI updates from Corey Minyard:
 "Some minor bug fixes, return values, cleanups of prints, conversion of
  tasklets to the new API.

  The biggest change is retrying the initial information fetch from the
  management controller. If that fails, the iterface is not operational,
  and one group was having trouble with the management controller not
  being ready when the OS started up. So a retry was added"

* tag 'for-linus-5.10-1' of git://github.com/cminyard/linux-ipmi:
  ipmi_si: Fix wrong return value in try_smi_init()
  ipmi: msghandler: Fix a signedness bug
  ipmi: add retry in try_get_dev_id()
  ipmi: Clean up some printks
  ipmi:msghandler: retry to get device id on an error
  ipmi:sm: Print current state when the state is invalid
  ipmi: Reset response handler when failing to send the command
  ipmi: add a newline when printing parameter 'panic_op' by sysfs
  char: ipmi: convert tasklets to use new tasklet_setup() API
parents 2f6c6d08 8fe7990c
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -213,8 +213,10 @@ static int bt_start_transaction(struct si_sm_data *bt,
	if (bt->state == BT_STATE_LONG_BUSY)
		return IPMI_NODE_BUSY_ERR;

	if (bt->state != BT_STATE_IDLE)
	if (bt->state != BT_STATE_IDLE) {
		dev_warn(bt->io->dev, "BT in invalid state %d\n", bt->state);
		return IPMI_NOT_IN_MY_STATE_ERR;
	}

	if (bt_debug & BT_DEBUG_MSG) {
		dev_dbg(bt->io->dev, "+++++++++++++++++ New command\n");
+10 −5
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
 * that document.
 */

#define DEBUG /* So dev_dbg() is always available. */

#include <linux/kernel.h> /* For printk. */
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -187,7 +189,7 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason)
	(kcs->error_retries)++;
	if (kcs->error_retries > MAX_ERROR_RETRIES) {
		if (kcs_debug & KCS_DEBUG_ENABLE)
			printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n",
			dev_dbg(kcs->io->dev, "ipmi_kcs_sm: kcs hosed: %s\n",
				reason);
		kcs->state = KCS_HOSED;
	} else {
@@ -268,11 +270,13 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data,
	if (size > MAX_KCS_WRITE_SIZE)
		return IPMI_REQ_LEN_EXCEEDED_ERR;

	if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED))
	if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) {
		dev_warn(kcs->io->dev, "KCS in invalid state %d\n", kcs->state);
		return IPMI_NOT_IN_MY_STATE_ERR;
	}

	if (kcs_debug & KCS_DEBUG_MSG) {
		printk(KERN_DEBUG "start_kcs_transaction -");
		dev_dbg(kcs->io->dev, "%s -", __func__);
		for (i = 0; i < size; i++)
			pr_cont(" %02x", data[i]);
		pr_cont("\n");
@@ -331,7 +335,8 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
	status = read_status(kcs);

	if (kcs_debug & KCS_DEBUG_STATES)
		printk(KERN_DEBUG "KCS: State = %d, %x\n", kcs->state, status);
		dev_dbg(kcs->io->dev,
			"KCS: State = %d, %x\n", kcs->state, status);

	/* All states wait for ibf, so just do it here. */
	if (!check_ibf(kcs, status, time))
+36 −16
Original line number Diff line number Diff line
@@ -34,12 +34,13 @@
#include <linux/uuid.h>
#include <linux/nospec.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>

#define IPMI_DRIVER_VERSION "39.2"

static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
static void smi_recv_tasklet(unsigned long);
static void smi_recv_tasklet(struct tasklet_struct *t);
static void handle_new_recv_msgs(struct ipmi_smi *intf);
static void need_waiter(struct ipmi_smi *intf);
static int handle_one_recv_msg(struct ipmi_smi *intf,
@@ -60,6 +61,7 @@ enum ipmi_panic_event_op {
#else
#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_NONE
#endif

static enum ipmi_panic_event_op ipmi_send_panic_event = IPMI_PANIC_DEFAULT;

static int panic_op_write_handler(const char *val,
@@ -89,19 +91,19 @@ static int panic_op_read_handler(char *buffer, const struct kernel_param *kp)
{
	switch (ipmi_send_panic_event) {
	case IPMI_SEND_PANIC_EVENT_NONE:
		strcpy(buffer, "none");
		strcpy(buffer, "none\n");
		break;

	case IPMI_SEND_PANIC_EVENT:
		strcpy(buffer, "event");
		strcpy(buffer, "event\n");
		break;

	case IPMI_SEND_PANIC_EVENT_STRING:
		strcpy(buffer, "string");
		strcpy(buffer, "string\n");
		break;

	default:
		strcpy(buffer, "???");
		strcpy(buffer, "???\n");
		break;
	}

@@ -317,6 +319,7 @@ struct bmc_device {
	int                    dyn_guid_set;
	struct kref	       usecount;
	struct work_struct     remove_work;
	unsigned char	       cc; /* completion code */
};
#define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev)

@@ -2381,6 +2384,8 @@ static void bmc_device_id_handler(struct ipmi_smi *intf,
			msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id);
	if (rv) {
		dev_warn(intf->si_dev, "device id demangle failed: %d\n", rv);
		/* record completion code when error */
		intf->bmc->cc = msg->msg.data[0];
		intf->bmc->dyn_id_set = 0;
	} else {
		/*
@@ -2426,23 +2431,39 @@ send_get_device_id_cmd(struct ipmi_smi *intf)
static int __get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc)
{
	int rv;

	bmc->dyn_id_set = 2;
	unsigned int retry_count = 0;

	intf->null_user_handler = bmc_device_id_handler;

retry:
	bmc->cc = 0;
	bmc->dyn_id_set = 2;

	rv = send_get_device_id_cmd(intf);
	if (rv)
		return rv;
		goto out_reset_handler;

	wait_event(intf->waitq, bmc->dyn_id_set != 2);

	if (!bmc->dyn_id_set)
	if (!bmc->dyn_id_set) {
		if ((bmc->cc == IPMI_DEVICE_IN_FW_UPDATE_ERR
		     || bmc->cc ==  IPMI_DEVICE_IN_INIT_ERR
		     || bmc->cc ==  IPMI_NOT_IN_MY_STATE_ERR)
		     && ++retry_count <= GET_DEVICE_ID_MAX_RETRY) {
			msleep(500);
			dev_warn(intf->si_dev,
			    "BMC returned 0x%2.2x, retry get bmc device id\n",
			    bmc->cc);
			goto retry;
		}

		rv = -EIO; /* Something went wrong in the fetch. */
	}

	/* dyn_id_set makes the id data available. */
	smp_rmb();

out_reset_handler:
	intf->null_user_handler = NULL;

	return rv;
@@ -3245,7 +3266,6 @@ channel_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
		/* It's the one we want */
		if (msg->msg.data[0] != 0) {
			/* Got an error from the channel, just go on. */

			if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
				/*
				 * If the MC does not support this
@@ -3329,6 +3349,7 @@ static int __scan_channels(struct ipmi_smi *intf, struct ipmi_device_id *id)
			dev_warn(intf->si_dev,
				 "Error sending channel information for channel 0, %d\n",
				 rv);
			intf->null_user_handler = NULL;
			return -EIO;
		}

@@ -3430,9 +3451,8 @@ int ipmi_add_smi(struct module *owner,
	intf->curr_seq = 0;
	spin_lock_init(&intf->waiting_rcv_msgs_lock);
	INIT_LIST_HEAD(&intf->waiting_rcv_msgs);
	tasklet_init(&intf->recv_tasklet,
		     smi_recv_tasklet,
		     (unsigned long) intf);
	tasklet_setup(&intf->recv_tasklet,
		     smi_recv_tasklet);
	atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0);
	spin_lock_init(&intf->xmit_msgs_lock);
	INIT_LIST_HEAD(&intf->xmit_msgs);
@@ -4467,10 +4487,10 @@ static void handle_new_recv_msgs(struct ipmi_smi *intf)
	}
}

static void smi_recv_tasklet(unsigned long val)
static void smi_recv_tasklet(struct tasklet_struct *t)
{
	unsigned long flags = 0; /* keep us warning-free. */
	struct ipmi_smi *intf = (struct ipmi_smi *) val;
	struct ipmi_smi *intf = from_tasklet(intf, t, recv_tasklet);
	int run_to_completion = intf->run_to_completion;
	struct ipmi_smi_msg *newmsg = NULL;

@@ -4542,7 +4562,7 @@ void ipmi_smi_msg_received(struct ipmi_smi *intf,
		spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);

	if (run_to_completion)
		smi_recv_tasklet((unsigned long) intf);
		smi_recv_tasklet(&intf->recv_tasklet);
	else
		tasklet_schedule(&intf->recv_tasklet);
}
+18 −1
Original line number Diff line number Diff line
@@ -1316,6 +1316,7 @@ static int try_get_dev_id(struct smi_info *smi_info)
	unsigned char         *resp;
	unsigned long         resp_len;
	int                   rv = 0;
	unsigned int          retry_count = 0;

	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
	if (!resp)
@@ -1327,6 +1328,8 @@ static int try_get_dev_id(struct smi_info *smi_info)
	 */
	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
	msg[1] = IPMI_GET_DEVICE_ID_CMD;

retry:
	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);

	rv = wait_for_msg_done(smi_info);
@@ -1339,6 +1342,20 @@ static int try_get_dev_id(struct smi_info *smi_info)
	/* Check and record info from the get device id, in case we need it. */
	rv = ipmi_demangle_device_id(resp[0] >> 2, resp[1],
			resp + 2, resp_len - 2, &smi_info->device_id);
	if (rv) {
		/* record completion code */
		unsigned char cc = *(resp + 2);

		if ((cc == IPMI_DEVICE_IN_FW_UPDATE_ERR
		    || cc == IPMI_DEVICE_IN_INIT_ERR
		    || cc == IPMI_NOT_IN_MY_STATE_ERR)
		    && ++retry_count <= GET_DEVICE_ID_MAX_RETRY) {
			dev_warn(smi_info->io.dev,
			    "BMC returned 0x%2.2x, retry get bmc device id\n",
			    cc);
			goto retry;
		}
	}

out:
	kfree(resp);
@@ -1963,7 +1980,7 @@ static int try_smi_init(struct smi_info *new_smi)
	/* Do this early so it's available for logs. */
	if (!new_smi->io.dev) {
		pr_err("IPMI interface added with no device\n");
		rv = EIO;
		rv = -EIO;
		goto out_err;
	}

+22 −13
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@
 * 2001 Hewlett-Packard Company
 */

#define DEBUG /* So dev_dbg() is always available. */

#include <linux/kernel.h> /* For printk. */
#include <linux/string.h>
#include <linux/module.h>
@@ -126,11 +128,14 @@ static int start_smic_transaction(struct si_sm_data *smic,
	if (size > MAX_SMIC_WRITE_SIZE)
		return IPMI_REQ_LEN_EXCEEDED_ERR;

	if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED))
	if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) {
		dev_warn(smic->io->dev,
			 "SMIC in invalid state %d\n", smic->state);
		return IPMI_NOT_IN_MY_STATE_ERR;
	}

	if (smic_debug & SMIC_DEBUG_MSG) {
		printk(KERN_DEBUG "start_smic_transaction -");
		dev_dbg(smic->io->dev, "%s -", __func__);
		for (i = 0; i < size; i++)
			pr_cont(" %02x", data[i]);
		pr_cont("\n");
@@ -152,7 +157,7 @@ static int smic_get_result(struct si_sm_data *smic,
	int i;

	if (smic_debug & SMIC_DEBUG_MSG) {
		printk(KERN_DEBUG "smic_get result -");
		dev_dbg(smic->io->dev, "smic_get result -");
		for (i = 0; i < smic->read_pos; i++)
			pr_cont(" %02x", smic->read_data[i]);
		pr_cont("\n");
@@ -324,9 +329,9 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
	}
	if (smic->state != SMIC_IDLE) {
		if (smic_debug & SMIC_DEBUG_STATES)
			printk(KERN_DEBUG
			       "smic_event - smic->smic_timeout = %ld, time = %ld\n",
			       smic->smic_timeout, time);
			dev_dbg(smic->io->dev,
				"%s - smic->smic_timeout = %ld, time = %ld\n",
				__func__, smic->smic_timeout, time);
		/*
		 * FIXME: smic_event is sometimes called with time >
		 * SMIC_RETRY_TIMEOUT
@@ -345,8 +350,9 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)

	status = read_smic_status(smic);
	if (smic_debug & SMIC_DEBUG_STATES)
		printk(KERN_DEBUG "smic_event - state = %d, flags = 0x%02x, status = 0x%02x\n",
		       smic->state, flags, status);
		dev_dbg(smic->io->dev,
			"%s - state = %d, flags = 0x%02x, status = 0x%02x\n",
			__func__, smic->state, flags, status);

	switch (smic->state) {
	case SMIC_IDLE:
@@ -436,7 +442,8 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
		data = read_smic_data(smic);
		if (data != 0) {
			if (smic_debug & SMIC_DEBUG_ENABLE)
				printk(KERN_DEBUG "SMIC_WRITE_END: data = %02x\n",
				dev_dbg(smic->io->dev,
					"SMIC_WRITE_END: data = %02x\n",
					data);
			start_error_recovery(smic,
					     "state = SMIC_WRITE_END, "
@@ -516,7 +523,8 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
		/* data register holds an error code */
		if (data != 0) {
			if (smic_debug & SMIC_DEBUG_ENABLE)
				printk(KERN_DEBUG "SMIC_READ_END: data = %02x\n",
				dev_dbg(smic->io->dev,
					"SMIC_READ_END: data = %02x\n",
					data);
			start_error_recovery(smic,
					     "state = SMIC_READ_END, "
@@ -533,7 +541,8 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)

	default:
		if (smic_debug & SMIC_DEBUG_ENABLE) {
			printk(KERN_DEBUG "smic->state = %d\n", smic->state);
			dev_dbg(smic->io->dev,
				"smic->state = %d\n", smic->state);
			start_error_recovery(smic, "state = UNKNOWN");
			return SI_SM_CALL_WITH_DELAY;
		}
Loading