diff options
author | Wayne Boyer <wayneb@linux.vnet.ibm.com> | 2009-10-20 14:09:00 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-11-06 12:09:27 -0500 |
commit | 3feeb89d40cc0ab3777f12571509b23da466105c (patch) | |
tree | 04f54e8c652b284614a7435715f0bb53847fe4b0 /drivers/scsi | |
parent | 61ec33eb7d8e1e94a93a8243238dc5f9a183001a (diff) |
[SCSI] ipr: add workaround for MSI interrupts on P7
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>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ipr.c | 42 | ||||
-rw-r--r-- | drivers/scsi/ipr.h | 1 |
2 files changed, 34 insertions, 9 deletions
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 5f045505a1f4..76d294fc7846 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c | |||
@@ -4189,6 +4189,25 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, | |||
4189 | } | 4189 | } |
4190 | 4190 | ||
4191 | /** | 4191 | /** |
4192 | * ipr_isr_eh - Interrupt service routine error handler | ||
4193 | * @ioa_cfg: ioa config struct | ||
4194 | * @msg: message to log | ||
4195 | * | ||
4196 | * Return value: | ||
4197 | * none | ||
4198 | **/ | ||
4199 | static void ipr_isr_eh(struct ipr_ioa_cfg *ioa_cfg, char *msg) | ||
4200 | { | ||
4201 | ioa_cfg->errors_logged++; | ||
4202 | dev_err(&ioa_cfg->pdev->dev, "%s\n", msg); | ||
4203 | |||
4204 | if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) | ||
4205 | ioa_cfg->sdt_state = GET_DUMP; | ||
4206 | |||
4207 | ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); | ||
4208 | } | ||
4209 | |||
4210 | /** | ||
4192 | * ipr_isr - Interrupt service routine | 4211 | * ipr_isr - Interrupt service routine |
4193 | * @irq: irq number | 4212 | * @irq: irq number |
4194 | * @devp: pointer to ioa config struct | 4213 | * @devp: pointer to ioa config struct |
@@ -4203,6 +4222,7 @@ static irqreturn_t ipr_isr(int irq, void *devp) | |||
4203 | volatile u32 int_reg, int_mask_reg; | 4222 | volatile u32 int_reg, int_mask_reg; |
4204 | u32 ioasc; | 4223 | u32 ioasc; |
4205 | u16 cmd_index; | 4224 | u16 cmd_index; |
4225 | int num_hrrq = 0; | ||
4206 | struct ipr_cmnd *ipr_cmd; | 4226 | struct ipr_cmnd *ipr_cmd; |
4207 | irqreturn_t rc = IRQ_NONE; | 4227 | irqreturn_t rc = IRQ_NONE; |
4208 | 4228 | ||
@@ -4233,13 +4253,7 @@ static irqreturn_t ipr_isr(int irq, void *devp) | |||
4233 | IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT; | 4253 | IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT; |
4234 | 4254 | ||
4235 | if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) { | 4255 | if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) { |
4236 | ioa_cfg->errors_logged++; | 4256 | ipr_isr_eh(ioa_cfg, "Invalid response handle from IOA"); |
4237 | dev_err(&ioa_cfg->pdev->dev, "Invalid response handle from IOA\n"); | ||
4238 | |||
4239 | if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) | ||
4240 | ioa_cfg->sdt_state = GET_DUMP; | ||
4241 | |||
4242 | ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); | ||
4243 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | 4257 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); |
4244 | return IRQ_HANDLED; | 4258 | return IRQ_HANDLED; |
4245 | } | 4259 | } |
@@ -4266,8 +4280,18 @@ static irqreturn_t ipr_isr(int irq, void *devp) | |||
4266 | 4280 | ||
4267 | if (ipr_cmd != NULL) { | 4281 | if (ipr_cmd != NULL) { |
4268 | /* Clear the PCI interrupt */ | 4282 | /* Clear the PCI interrupt */ |
4269 | writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg); | 4283 | do { |
4270 | int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; | 4284 | writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg); |
4285 | int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; | ||
4286 | } while (int_reg & IPR_PCII_HRRQ_UPDATED && | ||
4287 | num_hrrq++ < IPR_MAX_HRRQ_RETRIES); | ||
4288 | |||
4289 | if (int_reg & IPR_PCII_HRRQ_UPDATED) { | ||
4290 | ipr_isr_eh(ioa_cfg, "Error clearing HRRQ"); | ||
4291 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | ||
4292 | return IRQ_HANDLED; | ||
4293 | } | ||
4294 | |||
4271 | } else | 4295 | } else |
4272 | break; | 4296 | break; |
4273 | } | 4297 | } |
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 163245a1c3e5..19bbcf39f0c9 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h | |||
@@ -144,6 +144,7 @@ | |||
144 | #define IPR_IOA_MAX_SECTORS 32767 | 144 | #define IPR_IOA_MAX_SECTORS 32767 |
145 | #define IPR_VSET_MAX_SECTORS 512 | 145 | #define IPR_VSET_MAX_SECTORS 512 |
146 | #define IPR_MAX_CDB_LEN 16 | 146 | #define IPR_MAX_CDB_LEN 16 |
147 | #define IPR_MAX_HRRQ_RETRIES 3 | ||
147 | 148 | ||
148 | #define IPR_DEFAULT_BUS_WIDTH 16 | 149 | #define IPR_DEFAULT_BUS_WIDTH 16 |
149 | #define IPR_80MBs_SCSI_RATE ((80 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8)) | 150 | #define IPR_80MBs_SCSI_RATE ((80 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8)) |