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

Commit 5c19b92a authored by Vikas Chaudhary's avatar Vikas Chaudhary Committed by James Bottomley
Browse files

[SCSI] qla4xxx: Fix MBOX intr switching from polling to intr mode for ISP83XX



Issue:
Mailbox command timed out after switching from polling mode to interrupt mode.

Events:-
 1. Mailbox interrupts are disabled
 2. FW generates AEN and at same time driver enables Mailbox Interrupt
 3. Driver issues new mailbox to Firmware

In above case driver will not get AEN interrupts generated by FW in step #2 as
FW generated this AEN when interrupts are disabled. During the same time
driver enabled the mailbox interrupt, so driver will not poll for interrupt.
Driver will never process AENs generated in step #2 and issues new mailbox to
FW, but now FW is not able to post mailbox completion as AENs generated before
are not processed by driver.

Fix:
Enable Mailbox / AEN interrupts before initializing FW in case of ISP83XX.
This will make sure we process all Mailbox and AENs in interrupt mode.

Signed-off-by: default avatarVikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 8108de97
Loading
Loading
Loading
Loading
+40 −13
Original line number Original line Diff line number Diff line
@@ -1351,31 +1351,58 @@ int qla4_83xx_start_firmware(struct scsi_qla_host *ha)


/*----------------------Interrupt Related functions ---------------------*/
/*----------------------Interrupt Related functions ---------------------*/


void qla4_83xx_disable_intrs(struct scsi_qla_host *ha)
static void qla4_83xx_disable_iocb_intrs(struct scsi_qla_host *ha)
{
{
	uint32_t mb_int, ret;
	if (test_and_clear_bit(AF_83XX_IOCB_INTR_ON, &ha->flags))
		qla4_8xxx_intr_disable(ha);
}


	if (test_and_clear_bit(AF_INTERRUPTS_ON, &ha->flags))
static void qla4_83xx_disable_mbox_intrs(struct scsi_qla_host *ha)
		qla4_8xxx_mbx_intr_disable(ha);
{
	uint32_t mb_int, ret;


	if (test_and_clear_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) {
		ret = readl(&ha->qla4_83xx_reg->mbox_int);
		ret = readl(&ha->qla4_83xx_reg->mbox_int);
		mb_int = ret & ~INT_ENABLE_FW_MB;
		mb_int = ret & ~INT_ENABLE_FW_MB;
		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
		writel(1, &ha->qla4_83xx_reg->leg_int_mask);
		writel(1, &ha->qla4_83xx_reg->leg_int_mask);
	}
	}
}


void qla4_83xx_enable_intrs(struct scsi_qla_host *ha)
void qla4_83xx_disable_intrs(struct scsi_qla_host *ha)
{
	qla4_83xx_disable_mbox_intrs(ha);
	qla4_83xx_disable_iocb_intrs(ha);
}

static void qla4_83xx_enable_iocb_intrs(struct scsi_qla_host *ha)
{
	if (!test_bit(AF_83XX_IOCB_INTR_ON, &ha->flags)) {
		qla4_8xxx_intr_enable(ha);
		set_bit(AF_83XX_IOCB_INTR_ON, &ha->flags);
	}
}

void qla4_83xx_enable_mbox_intrs(struct scsi_qla_host *ha)
{
{
	uint32_t mb_int;
	uint32_t mb_int;


	qla4_8xxx_mbx_intr_enable(ha);
	if (!test_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) {
		mb_int = INT_ENABLE_FW_MB;
		mb_int = INT_ENABLE_FW_MB;
		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
		writel(0, &ha->qla4_83xx_reg->leg_int_mask);
		writel(0, &ha->qla4_83xx_reg->leg_int_mask);
		set_bit(AF_83XX_MBOX_INTR_ON, &ha->flags);
	}
}



	set_bit(AF_INTERRUPTS_ON, &ha->flags);
void qla4_83xx_enable_intrs(struct scsi_qla_host *ha)
{
	qla4_83xx_enable_mbox_intrs(ha);
	qla4_83xx_enable_iocb_intrs(ha);
}
}



void qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
void qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
			      int incount)
			      int incount)
{
{
+2 −0
Original line number Original line Diff line number Diff line
@@ -516,6 +516,8 @@ struct scsi_qla_host {
#define AF_8XXX_RST_OWNER		25 /* 0x02000000 */
#define AF_8XXX_RST_OWNER		25 /* 0x02000000 */
#define AF_82XX_DUMP_READING		26 /* 0x04000000 */
#define AF_82XX_DUMP_READING		26 /* 0x04000000 */
#define AF_83XX_NO_FW_DUMP		27 /* 0x08000000 */
#define AF_83XX_NO_FW_DUMP		27 /* 0x08000000 */
#define AF_83XX_IOCB_INTR_ON		28 /* 0x10000000 */
#define AF_83XX_MBOX_INTR_ON		29 /* 0x20000000 */


	unsigned long dpc_flags;
	unsigned long dpc_flags;


+3 −2
Original line number Original line Diff line number Diff line
@@ -253,12 +253,13 @@ void qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha);
void qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha);
void qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha);
int qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha);
int qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha);
void qla4_8xxx_get_minidump(struct scsi_qla_host *ha);
void qla4_8xxx_get_minidump(struct scsi_qla_host *ha);
int qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha);
int qla4_8xxx_intr_disable(struct scsi_qla_host *ha);
int qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha);
int qla4_8xxx_intr_enable(struct scsi_qla_host *ha);
int qla4_8xxx_set_param(struct scsi_qla_host *ha, int param);
int qla4_8xxx_set_param(struct scsi_qla_host *ha, int param);
int qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha);
int qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha);
int qla4_83xx_post_idc_ack(struct scsi_qla_host *ha);
int qla4_83xx_post_idc_ack(struct scsi_qla_host *ha);
void qla4_83xx_disable_pause(struct scsi_qla_host *ha);
void qla4_83xx_disable_pause(struct scsi_qla_host *ha);
void qla4_83xx_enable_mbox_intrs(struct scsi_qla_host *ha);


extern int ql4xextended_error_logging;
extern int ql4xextended_error_logging;
extern int ql4xdontresethba;
extern int ql4xdontresethba;
+10 −0
Original line number Original line Diff line number Diff line
@@ -935,6 +935,16 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset)
	if (ha->isp_ops->start_firmware(ha) == QLA_ERROR)
	if (ha->isp_ops->start_firmware(ha) == QLA_ERROR)
		goto exit_init_hba;
		goto exit_init_hba;


	/*
	 * For ISP83XX, mailbox and IOCB interrupts are enabled separately.
	 * Mailbox interrupts must be enabled prior to issuing any mailbox
	 * command in order to prevent the possibility of losing interrupts
	 * while switching from polling to interrupt mode. IOCB interrupts are
	 * enabled via isp_ops->enable_intrs.
	 */
	if (is_qla8032(ha))
		qla4_83xx_enable_mbox_intrs(ha);

	if (qla4xxx_about_firmware(ha) == QLA_ERROR)
	if (qla4xxx_about_firmware(ha) == QLA_ERROR)
		goto exit_init_hba;
		goto exit_init_hba;


+10 −7
Original line number Original line Diff line number Diff line
@@ -1437,11 +1437,14 @@ int qla4xxx_request_irqs(struct scsi_qla_host *ha)


void qla4xxx_free_irqs(struct scsi_qla_host *ha)
void qla4xxx_free_irqs(struct scsi_qla_host *ha)
{
{
	if (test_bit(AF_MSIX_ENABLED, &ha->flags))
	if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags)) {
		if (test_bit(AF_MSIX_ENABLED, &ha->flags)) {
			qla4_8xxx_disable_msix(ha);
			qla4_8xxx_disable_msix(ha);
	else if (test_and_clear_bit(AF_MSI_ENABLED, &ha->flags)) {
		} else if (test_and_clear_bit(AF_MSI_ENABLED, &ha->flags)) {
			free_irq(ha->pdev->irq, ha);
			free_irq(ha->pdev->irq, ha);
			pci_disable_msi(ha->pdev);
			pci_disable_msi(ha->pdev);
	} else if (test_and_clear_bit(AF_INTx_ENABLED, &ha->flags))
		} else if (test_and_clear_bit(AF_INTx_ENABLED, &ha->flags)) {
			free_irq(ha->pdev->irq, ha);
			free_irq(ha->pdev->irq, ha);
		}
		}
	}
}
Loading