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

Commit 4d2ee1e6 authored by Jitendra Bhivare's avatar Jitendra Bhivare Committed by Martin K. Petersen
Browse files

scsi: be2iscsi: Fix POST check and reset sequence



SLIPORT FUNCTION_RESET does not reset the chip.
So POST status needs to be checked before issuing FUNCTION_RESET.
The completion of FUNCTION_RESET is indicated in BMBX Rdy bit.

be_cmd_fw_initialize too needs to be done before issuing any cmd to FW.
be_cmd_fw_initialize is renamed as beiscsi_cmd_special_wrb.
Rearrange and rename few functions in init and cleanup path.

Signed-off-by: default avatarJitendra Bhivare <jitendra.bhivare@broadcom.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 480195c2
Loading
Loading
Loading
Loading
+121 −129
Original line number Diff line number Diff line
@@ -21,35 +21,6 @@
#include "be.h"
#include "be_mgmt.h"

int be_chk_reset_complete(struct beiscsi_hba *phba)
{
	unsigned int num_loop;
	u8 *mpu_sem = 0;
	u32 status;

	num_loop = 1000;
	mpu_sem = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
	msleep(5000);

	while (num_loop) {
		status = readl((void *)mpu_sem);

		if ((status & 0x80000000) || (status & 0x0000FFFF) == 0xC000)
			break;
		msleep(60);
		num_loop--;
	}

	if ((status & 0x80000000) || (!num_loop)) {
		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
			    "BC_%d : Failed in be_chk_reset_complete"
			    "status = 0x%x\n", status);
		return -EIO;
	}

	return 0;
}

struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
				 unsigned int *ref_tag)
{
@@ -769,87 +740,6 @@ int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
	return status;
}

/**
 * be_cmd_fw_initialize()- Initialize FW
 * @ctrl: Pointer to function control structure
 *
 * Send FW initialize pattern for the function.
 *
 * return
 * Success: 0
 * Failure: Non-Zero value
 **/
int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
{
	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
	struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
	int status;
	u8 *endian_check;

	mutex_lock(&ctrl->mbox_lock);
	memset(wrb, 0, sizeof(*wrb));

	endian_check = (u8 *) wrb;
	*endian_check++ = 0xFF;
	*endian_check++ = 0x12;
	*endian_check++ = 0x34;
	*endian_check++ = 0xFF;
	*endian_check++ = 0xFF;
	*endian_check++ = 0x56;
	*endian_check++ = 0x78;
	*endian_check++ = 0xFF;
	be_dws_cpu_to_le(wrb, sizeof(*wrb));

	status = be_mbox_notify(ctrl);
	if (status)
		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
			    "BC_%d : be_cmd_fw_initialize Failed\n");

	mutex_unlock(&ctrl->mbox_lock);
	return status;
}

/**
 * be_cmd_fw_uninit()- Uinitialize FW
 * @ctrl: Pointer to function control structure
 *
 * Send FW uninitialize pattern for the function
 *
 * return
 * Success: 0
 * Failure: Non-Zero value
 **/
int be_cmd_fw_uninit(struct be_ctrl_info *ctrl)
{
	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
	struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
	int status;
	u8 *endian_check;

	mutex_lock(&ctrl->mbox_lock);
	memset(wrb, 0, sizeof(*wrb));

	endian_check = (u8 *) wrb;
	*endian_check++ = 0xFF;
	*endian_check++ = 0xAA;
	*endian_check++ = 0xBB;
	*endian_check++ = 0xFF;
	*endian_check++ = 0xFF;
	*endian_check++ = 0xCC;
	*endian_check++ = 0xDD;
	*endian_check = 0xFF;

	be_dws_cpu_to_le(wrb, sizeof(*wrb));

	status = be_mbox_notify(ctrl);
	if (status)
		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
			    "BC_%d : be_cmd_fw_uninit Failed\n");

	mutex_unlock(&ctrl->mbox_lock);
	return status;
}

int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
			  struct be_queue_info *cq, struct be_queue_info *eq,
			  bool sol_evts, bool no_delay, int coalesce_wm)
@@ -1293,25 +1183,6 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
	return status;
}

int beiscsi_cmd_reset_function(struct beiscsi_hba  *phba)
{
	struct be_ctrl_info *ctrl = &phba->ctrl;
	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
	struct be_post_sgl_pages_req *req = embedded_payload(wrb);
	int status;

	mutex_lock(&ctrl->mbox_lock);

	req = embedded_payload(wrb);
	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
			   OPCODE_COMMON_FUNCTION_RESET, sizeof(*req));
	status = be_mbox_notify(ctrl);

	mutex_unlock(&ctrl->mbox_lock);
	return status;
}

/**
 * be_cmd_set_vlan()- Configure VLAN paramters on the adapter
 * @phba: device priv structure instance
@@ -1653,3 +1524,124 @@ int beiscsi_set_uer_feature(struct beiscsi_hba *phba)
	mutex_unlock(&ctrl->mbox_lock);
	return ret;
}

static u32 beiscsi_get_post_stage(struct beiscsi_hba *phba)
{
	u32 sem;

	if (is_chip_be2_be3r(phba))
		sem = ioread32(phba->csr_va + SLIPORT_SEMAPHORE_OFFSET_BEx);
	else
		pci_read_config_dword(phba->pcidev,
				      SLIPORT_SEMAPHORE_OFFSET_SH, &sem);
	return sem;
}

int beiscsi_check_fw_rdy(struct beiscsi_hba *phba)
{
	u32 loop, post, rdy = 0;

	loop = 1000;
	while (loop--) {
		post = beiscsi_get_post_stage(phba);
		if (post & POST_ERROR_BIT)
			break;
		if ((post & POST_STAGE_MASK) == POST_STAGE_ARMFW_RDY) {
			rdy = 1;
			break;
		}
		msleep(60);
	}

	if (!rdy) {
		__beiscsi_log(phba, KERN_ERR,
			      "BC_%d : FW not ready 0x%x\n", post);
	}

	return rdy;
}

static int beiscsi_cmd_function_reset(struct beiscsi_hba  *phba)
{
	struct be_ctrl_info *ctrl = &phba->ctrl;
	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
	struct be_post_sgl_pages_req *req = embedded_payload(wrb);
	int status;

	mutex_lock(&ctrl->mbox_lock);

	req = embedded_payload(wrb);
	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
			   OPCODE_COMMON_FUNCTION_RESET, sizeof(*req));
	status = be_mbox_notify(ctrl);

	mutex_unlock(&ctrl->mbox_lock);
	return status;
}

int beiscsi_cmd_special_wrb(struct be_ctrl_info *ctrl, u32 load)
{
	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
	struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
	u8 *endian_check;
	int status;

	mutex_lock(&ctrl->mbox_lock);
	memset(wrb, 0, sizeof(*wrb));

	endian_check = (u8 *) wrb;
	if (load) {
		/* to start communicating */
		*endian_check++ = 0xFF;
		*endian_check++ = 0x12;
		*endian_check++ = 0x34;
		*endian_check++ = 0xFF;
		*endian_check++ = 0xFF;
		*endian_check++ = 0x56;
		*endian_check++ = 0x78;
		*endian_check++ = 0xFF;
	} else {
		/* to stop communicating */
		*endian_check++ = 0xFF;
		*endian_check++ = 0xAA;
		*endian_check++ = 0xBB;
		*endian_check++ = 0xFF;
		*endian_check++ = 0xFF;
		*endian_check++ = 0xCC;
		*endian_check++ = 0xDD;
		*endian_check = 0xFF;
	}
	be_dws_cpu_to_le(wrb, sizeof(*wrb));

	status = be_mbox_notify(ctrl);
	if (status)
		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
			    "BC_%d : special WRB message failed\n");
	mutex_unlock(&ctrl->mbox_lock);
	return status;
}

int beiscsi_init_sliport(struct beiscsi_hba *phba)
{
	int status;

	/* check POST stage before talking to FW */
	status = beiscsi_check_fw_rdy(phba);
	if (!status)
		return -EIO;

	/*
	 * SLI COMMON_FUNCTION_RESET completion is indicated by BMBX RDY bit.
	 * It should clean up any stale info in FW for this fn.
	 */
	status = beiscsi_cmd_function_reset(phba);
	if (status) {
		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
			    "BC_%d : SLI Function Reset failed\n");
		return status;
	}

	/* indicate driver is loading */
	return beiscsi_cmd_special_wrb(&phba->ctrl, 1);
}
+23 −15
Original line number Diff line number Diff line
@@ -98,11 +98,23 @@ struct be_mcc_compl {
#define MPU_MAILBOX_DB_RDY_MASK	0x1	/* bit 0 */
#define MPU_MAILBOX_DB_HI_MASK	0x2	/* bit 1 */

/********** MPU semphore ******************/
#define MPU_EP_SEMAPHORE_OFFSET 0xac
#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF
#define EP_SEMAPHORE_POST_ERR_MASK 0x1
#define EP_SEMAPHORE_POST_ERR_SHIFT 31
/********** MPU semphore: used for SH & BE ******************/
#define SLIPORT_SOFTRESET_OFFSET		0x5c	/* CSR BAR offset */
#define SLIPORT_SEMAPHORE_OFFSET_BEx		0xac	/* CSR BAR offset */
#define SLIPORT_SEMAPHORE_OFFSET_SH		0x94	/* PCI-CFG offset */
#define POST_STAGE_MASK				0x0000FFFF
#define POST_ERROR_BIT				0x80000000
#define POST_ERR_RECOVERY_CODE_MASK		0xF000

/* Soft Reset register masks */
#define SLIPORT_SOFTRESET_SR_MASK		0x00000080	/* SR bit */

/* MPU semphore POST stage values */
#define POST_STAGE_AWAITING_HOST_RDY	0x1 /* FW awaiting goahead from host */
#define POST_STAGE_HOST_RDY		0x2 /* Host has given go-ahed to FW */
#define POST_STAGE_BE_RESET		0x3 /* Host wants to reset chip */
#define POST_STAGE_ARMFW_RDY		0xC000 /* FW is done with POST */
#define POST_STAGE_RECOVERABLE_ERR	0xE000 /* Recoverable err detected */

/********** MCC door bell ************/
#define DB_MCCQ_OFFSET 0x140
@@ -110,9 +122,6 @@ struct be_mcc_compl {
/* Number of entries posted */
#define DB_MCCQ_NUM_POSTED_SHIFT 16		/* bits 16 - 29 */

/* MPU semphore POST stage values */
#define POST_STAGE_ARMFW_RDY		0xc000	/* FW is done with POST */

/**
 * When the async bit of mcc_compl is set, the last 4 bytes of
 * mcc_compl is interpreted as follows:
@@ -753,6 +762,12 @@ struct be_cmd_set_features {
	} param;
} __packed;

int beiscsi_cmd_special_wrb(struct be_ctrl_info *ctrl, u32 load);

int beiscsi_check_fw_rdy(struct beiscsi_hba *phba);

int beiscsi_init_sliport(struct beiscsi_hba *phba);

int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
			  struct be_queue_info *eq, int eq_delay);

@@ -784,9 +799,6 @@ int __beiscsi_mcc_compl_status(struct beiscsi_hba *phba,
			       struct be_mcc_wrb **wrb,
			       struct be_dma_mem *mbx_cmd_mem);
/*ISCSI Functuions */
int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
int be_cmd_fw_uninit(struct be_ctrl_info *ctrl);

struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem);
int be_mcc_compl_poll(struct beiscsi_hba *phba, unsigned int tag);
void be_mcc_notify(struct beiscsi_hba *phba, unsigned int tag);
@@ -812,8 +824,6 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
				struct be_dma_mem *q_mem, u32 page_offset,
				u32 num_pages);

int beiscsi_cmd_reset_function(struct beiscsi_hba *phba);

int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
		       struct be_queue_info *wrbq,
		       struct hwi_wrb_context *pwrb_context,
@@ -1422,8 +1432,6 @@ struct be_cmd_get_port_name {
						 * the cxn
						 */

int be_chk_reset_complete(struct beiscsi_hba *phba);

void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
			bool embedded, u8 sge_cnt);

+20 −44
Original line number Diff line number Diff line
@@ -3544,7 +3544,7 @@ static void be_mcc_queues_destroy(struct beiscsi_hba *phba)
	}
}

static void hwi_cleanup(struct beiscsi_hba *phba)
static void hwi_cleanup_port(struct beiscsi_hba *phba)
{
	struct be_queue_info *q;
	struct be_ctrl_info *ctrl = &phba->ctrl;
@@ -3603,7 +3603,8 @@ static void hwi_cleanup(struct beiscsi_hba *phba)
			beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ);
		}
	}
	be_cmd_fw_uninit(ctrl);
	/* last communication, indicate driver is unloading */
	beiscsi_cmd_special_wrb(&phba->ctrl, 0);
}

static int be_mcc_queues_create(struct beiscsi_hba *phba,
@@ -3700,8 +3701,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
	phwi_context->max_eqd = 128;
	phwi_context->min_eqd = 0;
	phwi_context->cur_eqd = 0;
	be_cmd_fw_initialize(&phba->ctrl);
	/* set optic state to unknown */
	/* set port optic state to unknown */
	phba->optic_state = 0xff;

	status = beiscsi_create_eqs(phba, phwi_context);
@@ -3807,7 +3807,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
error:
	beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
		    "BM_%d : hwi_init_port failed");
	hwi_cleanup(phba);
	hwi_cleanup_port(phba);
	return status;
}

@@ -4196,7 +4196,7 @@ static int beiscsi_init_port(struct beiscsi_hba *phba)
	return ret;

do_cleanup_ctrlr:
	hwi_cleanup(phba);
	hwi_cleanup_port(phba);
	return ret;
}

@@ -4233,7 +4233,7 @@ static void hwi_purge_eq(struct beiscsi_hba *phba)
	}
}

static void beiscsi_clean_port(struct beiscsi_hba *phba)
static void beiscsi_cleanup_port(struct beiscsi_hba *phba)
{
	int mgmt_status, ulp_num;
	struct ulp_cid_info *ptr_cid_info = NULL;
@@ -4250,7 +4250,7 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba)
	}

	hwi_purge_eq(phba);
	hwi_cleanup(phba);
	hwi_cleanup_port(phba);
	kfree(phba->io_sgl_hndl_base);
	kfree(phba->eh_sgl_hndl_base);
	kfree(phba->ep_array);
@@ -5011,12 +5011,12 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba)
	/* PCI_ERR is set then check if driver is not unloading */
	if (test_bit(BEISCSI_HBA_RUNNING, &phba->state) &&
	    test_bit(BEISCSI_HBA_PCI_ERR, &phba->state)) {
		hwi_cleanup(phba);
		hwi_cleanup_port(phba);
		return;
	}

	destroy_workqueue(phba->wq);
	beiscsi_clean_port(phba);
	beiscsi_cleanup_port(phba);
	beiscsi_free_mem(phba);

	beiscsi_unmap_pci_function(phba);
@@ -5461,9 +5461,8 @@ static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev)
	pci_set_power_state(pdev, PCI_D0);
	pci_restore_state(pdev);

	/* Wait for the CHIP Reset to complete */
	status = be_chk_reset_complete(phba);
	if (!status) {
	status = beiscsi_check_fw_rdy(phba);
	if (status) {
		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT,
			    "BM_%d : EEH Reset Completed\n");
	} else {
@@ -5478,7 +5477,7 @@ static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev)

static void beiscsi_eeh_resume(struct pci_dev *pdev)
{
	int ret = 0, i;
	int ret, i;
	struct be_eq_obj *pbe_eq;
	struct beiscsi_hba *phba = NULL;
	struct hwi_controller *phwi_ctrlr;
@@ -5498,19 +5497,9 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
			phba->num_cpus = 1;
	}

	ret = beiscsi_cmd_reset_function(phba);
	if (ret) {
		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
			    "BM_%d : Reset Failed\n");
		goto ret_err;
	}

	ret = be_chk_reset_complete(phba);
	if (ret) {
		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
			    "BM_%d : Failed to get out of reset.\n");
	ret = beiscsi_init_sliport(phba);
	if (ret)
		goto ret_err;
	}

	beiscsi_get_params(phba);
	phba->shost->max_id = phba->params.cxns_per_ctrl;
@@ -5627,28 +5616,15 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
	ret = be_ctrl_init(phba, pcidev);
	if (ret) {
		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
			    "BM_%d : beiscsi_dev_probe-"
			    "Failed in be_ctrl_init\n");
			    "BM_%d : be_ctrl_init failed\n");
		goto hba_free;
	}

	set_bit(BEISCSI_HBA_RUNNING, &phba->state);
	/*
	 * FUNCTION_RESET should clean up any stale info in FW for this fn
	 */
	ret = beiscsi_cmd_reset_function(phba);
	if (ret) {
		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
			    "BM_%d : Reset Failed\n");
		goto hba_free;
	}
	ret = be_chk_reset_complete(phba);
	if (ret) {
		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
			    "BM_%d : Failed to get out of reset.\n");
	ret = beiscsi_init_sliport(phba);
	if (ret)
		goto hba_free;
	}

	set_bit(BEISCSI_HBA_RUNNING, &phba->state);
	spin_lock_init(&phba->io_sgl_lock);
	spin_lock_init(&phba->mgmt_sgl_lock);
	spin_lock_init(&phba->async_pdu_lock);
@@ -5772,7 +5748,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
		irq_poll_disable(&pbe_eq->iopoll);
	}
free_twq:
	beiscsi_clean_port(phba);
	beiscsi_cleanup_port(phba);
	beiscsi_free_mem(phba);
free_port:
	pci_free_consistent(phba->pcidev,
+0 −8
Original line number Diff line number Diff line
@@ -82,14 +82,6 @@
#define BEISCSI_MAX_FRAGS_INIT	192
#define BE_NUM_MSIX_ENTRIES	1

#define MPU_EP_CONTROL          0
#define MPU_EP_SEMAPHORE        0xac
#define BE2_SOFT_RESET          0x5c
#define BE2_PCI_ONLINE0         0xb0
#define BE2_PCI_ONLINE1         0xb4
#define BE2_SET_RESET           0x80
#define BE2_MPU_IRAM_ONLINE     0x00000080

#define BE_SENSE_INFO_SIZE		258
#define BE_ISCSI_PDU_HEADER_SIZE	64
#define BE_MIN_MEM_SIZE			16384