Commit 6ac999ef authored by Jitendra Bhivare's avatar Jitendra Bhivare Committed by Martin K. Petersen
Browse files

be2iscsi: Fix soft lockup in mgmt_get_all_if_id path using bmbx



We are taking mbox_lock spinlock which disables pre-emption before we
poll for mbox completion. Waiting there with spinlock held in excess of
20s will cause soft lockup.

Actual fix is to change mbox_lock to mutex. The changes are done in
phases. This is the first part.

1. Changed mgmt_get_all_if_id to use MCC where after posting lock is
released.

2. Changed be_mbox_db_ready_wait to busy wait for 12s max and removed
wait_event_timeout. Added error handling code for IO reads.
OPCODE_COMMON_QUERY_FIRMWARE_CONFIG mbox command takes 8s time when
unreachable boot targets configured.

Signed-off-by: default avatarJitendra Bhivare <jitendra.bhivare@avagotech.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 420eb6d7
Loading
Loading
Loading
Loading
+29 −31
Original line number Diff line number Diff line
@@ -587,47 +587,42 @@ int be_mcc_notify_wait(struct beiscsi_hba *phba)
 **/
static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
{
#define BEISCSI_MBX_RDY_BIT_TIMEOUT	4000	/* 4sec */
#define BEISCSI_MBX_RDY_BIT_TIMEOUT	12000	/* 12sec */
	void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
	struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
	unsigned long timeout;
	bool read_flag = false;
	int ret = 0, i;
	u32 ready;
	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(rdybit_check_q);

	/*
	 * This BMBX busy wait path is used during init only.
	 * For the commands executed during init, 5s should suffice.
	 */
	timeout = jiffies + msecs_to_jiffies(BEISCSI_MBX_RDY_BIT_TIMEOUT);
	do {
		if (beiscsi_error(phba))
			return -EIO;

	timeout = jiffies + (HZ * 110);
		ready = ioread32(db);
		if (ready == 0xffffffff)
			return -EIO;

		ready &= MPU_MAILBOX_DB_RDY_MASK;
		if (ready)
			return 0;

	do {
		for (i = 0; i < BEISCSI_MBX_RDY_BIT_TIMEOUT; i++) {
			ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
			if (ready) {
				read_flag = true;
		if (time_after(jiffies, timeout))
			break;
			}
		mdelay(1);
		}

		if (!read_flag) {
			wait_event_timeout(rdybit_check_q,
					  (read_flag != true),
					   HZ * 5);
		}
	} while ((time_before(jiffies, timeout)) && !read_flag);
	} while (!ready);

	if (!read_flag) {
	beiscsi_log(phba, KERN_ERR,
			BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
			"BC_%d : FW Timed Out\n");

	phba->fw_timeout = true;
	beiscsi_ue_detect(phba);
			ret = -EBUSY;
	}

	return ret;
	return -EBUSY;
}

/*
@@ -674,6 +669,9 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
	if (status)
		return status;

	/* RDY is set; small delay before CQE read. */
	udelay(1);

	if (be_mcc_compl_is_new(compl)) {
		status = be_mcc_compl_process(ctrl, &mbox->compl);
		be_mcc_compl_use(compl);
+22 −10
Original line number Diff line number Diff line
@@ -809,27 +809,39 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba)
{
	struct be_ctrl_info *ctrl = &phba->ctrl;
	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
	struct be_cmd_get_all_if_id_req *req = embedded_payload(wrb);
	struct be_cmd_get_all_if_id_req *pbe_allid = req;
	struct be_mcc_wrb *wrb;
	struct be_cmd_get_all_if_id_req *req;
	struct be_cmd_get_all_if_id_req *pbe_allid;
	unsigned int tag;
	int status = 0;

	memset(wrb, 0, sizeof(*wrb));

	spin_lock(&ctrl->mbox_lock);
	tag = alloc_mcc_tag(phba);
	if (!tag) {
		spin_unlock(&ctrl->mbox_lock);
		return -ENOMEM;
	}

	wrb = wrb_from_mccq(phba);
	req = embedded_payload(wrb);
	wrb->tag0 |= tag;

	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
			   OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID,
			   sizeof(*req));
	status = be_mbox_notify(ctrl);
	if (!status)
		phba->interface_handle = pbe_allid->if_hndl_list[0];
	else {
	be_mcc_notify(phba);
	spin_unlock(&ctrl->mbox_lock);

	status = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
	if (status) {
		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
			    "BG_%d : Failed in mgmt_get_all_if_id\n");
		return -EBUSY;
	}
	spin_unlock(&ctrl->mbox_lock);

	pbe_allid = embedded_payload(wrb);
	phba->interface_handle = pbe_allid->if_hndl_list[0];

	return status;
}