diff options
author | Robert Elliott <elliott@hp.com> | 2015-01-23 22:45:01 (GMT) |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2015-02-02 17:57:44 (GMT) |
commit | c706a7954a160ddc1a29e1dfe4dc1f58e2b95023 (patch) | |
tree | 2a99497688d8427753f6fcf76a4e5a946adeb9b6 /drivers/scsi/hpsa.c | |
parent | 007e7aa9b37d570fc5917522a6f6bcca14264632 (diff) | |
download | linux-c706a7954a160ddc1a29e1dfe4dc1f58e2b95023.tar.xz |
hpsa: detect and report failures changing controller transport modes
Detect failues when attempting to change controller to use simple
or performant transport modes (mode change ack) rather than just
proceeding ahead after timeouts.
Return values are added to:
hpsa_put_ctlr_into_performant_mode
hpsa_wait_for_mode_change_ack
and all their callers check/propagate the result.
More consistency in printing errors and whether
dev_err is used.
Reviewed-by: Scott Teel <scott.teel@pmcs.com>
Signed-off-by: Robert Elliott <elliott@hp.com>
Signed-off-by: Don Brace <don.brace@pmcs.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi/hpsa.c')
-rw-r--r-- | drivers/scsi/hpsa.c | 40 |
1 files changed, 29 insertions, 11 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 89744a1..c1f4a95 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -243,7 +243,7 @@ static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id); static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr, int wait_for_ready); static inline void finish_cmd(struct CommandList *c); -static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h); +static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h); #define BOARD_NOT_READY 0 #define BOARD_READY 1 static void hpsa_drain_accel_commands(struct ctlr_info *h); @@ -6191,7 +6191,7 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h) writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG); } -static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) +static int hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) { int i; u32 doorbell_value; @@ -6202,13 +6202,16 @@ static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & DOORBELL_CLEAR_EVENTS)) - break; + goto done; /* delay and try again */ msleep(CLEAR_EVENT_WAIT_INTERVAL); } + return -ENODEV; +done: + return 0; } -static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h) +static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h) { int i; u32 doorbell_value; @@ -6223,12 +6226,16 @@ static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h) doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & CFGTBL_ChangeReq)) - break; + goto done; /* delay and try again */ msleep(MODE_CHANGE_WAIT_INTERVAL); } + return -ENODEV; +done: + return 0; } +/* return -ENODEV or other reason on error, 0 on success */ static int hpsa_enter_simple_mode(struct ctlr_info *h) { u32 trans_support; @@ -6243,7 +6250,8 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h) writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) + goto error; print_cfg_table(&h->pdev->dev, h->cfgtable); if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) goto error; @@ -7144,7 +7152,8 @@ static void calc_bucket_map(int bucket[], int num_buckets, } } -static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) +/* return -ENODEV or other reason on error, 0 on success */ +static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) { int i; unsigned long register_value; @@ -7236,12 +7245,16 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) } } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) { + dev_err(&h->pdev->dev, + "performant mode problem - doorbell timeout\n"); + return -ENODEV; + } register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) { dev_err(&h->pdev->dev, "performant mode problem - transport not active\n"); - return; + return -ENODEV; } /* Change the access methods to the performant access methods */ h->access = access; @@ -7249,7 +7262,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) if (!((trans_support & CFGTBL_Trans_io_accel1) || (trans_support & CFGTBL_Trans_io_accel2))) - return; + return 0; if (trans_support & CFGTBL_Trans_io_accel1) { /* Set up I/O accelerator mode */ @@ -7313,7 +7326,12 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) writel(bft2[i], &h->ioaccel2_bft2_regs[i]); } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) { + dev_err(&h->pdev->dev, + "performant mode problem - enabling ioaccel mode\n"); + return -ENODEV; + } + return 0; } static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) |