Skip to content

Commit

Permalink
[SCSI] ipr: add workaround for MSI interrupts on P7
Browse files Browse the repository at this point in the history
This patch adds some additional logic to the interrupt service routine to fix
a potential problem where an MSI interrupt does not get cleared the first time.

Signed-off-by: Wayne Boyer <wayneb@linux.vnet.ibm.com>
Acked-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
  • Loading branch information
Wayne Boyer authored and James Bottomley committed Nov 6, 2009
1 parent 61ec33e commit 3feeb89
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 9 deletions.
42 changes: 33 additions & 9 deletions drivers/scsi/ipr.c
Original file line number Diff line number Diff line change
Expand Up @@ -4188,6 +4188,25 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
return rc;
}

/**
* ipr_isr_eh - Interrupt service routine error handler
* @ioa_cfg: ioa config struct
* @msg: message to log
*
* Return value:
* none
**/
static void ipr_isr_eh(struct ipr_ioa_cfg *ioa_cfg, char *msg)
{
ioa_cfg->errors_logged++;
dev_err(&ioa_cfg->pdev->dev, "%s\n", msg);

if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
ioa_cfg->sdt_state = GET_DUMP;

ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
}

/**
* ipr_isr - Interrupt service routine
* @irq: irq number
Expand All @@ -4203,6 +4222,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
volatile u32 int_reg, int_mask_reg;
u32 ioasc;
u16 cmd_index;
int num_hrrq = 0;
struct ipr_cmnd *ipr_cmd;
irqreturn_t rc = IRQ_NONE;

Expand Down Expand Up @@ -4233,13 +4253,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT;

if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) {
ioa_cfg->errors_logged++;
dev_err(&ioa_cfg->pdev->dev, "Invalid response handle from IOA\n");

if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
ioa_cfg->sdt_state = GET_DUMP;

ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
ipr_isr_eh(ioa_cfg, "Invalid response handle from IOA");
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
return IRQ_HANDLED;
}
Expand All @@ -4266,8 +4280,18 @@ static irqreturn_t ipr_isr(int irq, void *devp)

if (ipr_cmd != NULL) {
/* Clear the PCI interrupt */
writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
do {
writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
} while (int_reg & IPR_PCII_HRRQ_UPDATED &&
num_hrrq++ < IPR_MAX_HRRQ_RETRIES);

if (int_reg & IPR_PCII_HRRQ_UPDATED) {
ipr_isr_eh(ioa_cfg, "Error clearing HRRQ");
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
return IRQ_HANDLED;
}

} else
break;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/ipr.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
#define IPR_IOA_MAX_SECTORS 32767
#define IPR_VSET_MAX_SECTORS 512
#define IPR_MAX_CDB_LEN 16
#define IPR_MAX_HRRQ_RETRIES 3

#define IPR_DEFAULT_BUS_WIDTH 16
#define IPR_80MBs_SCSI_RATE ((80 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8))
Expand Down

0 comments on commit 3feeb89

Please sign in to comment.