Skip to content

Commit 272652f

Browse files
shivasharan-smartinkpetersen
authored andcommitted
scsi: megaraid_sas: add retry logic in megasas_readl
Due to hardware errata in Aero controllers, reads to certain fusion registers could intermittently return zero. This behavior is transient in nature and subsequent reads will return valid value. For Aero controllers, any calls to readl to read from certain registers will be retried for maximum three times, if read returns zero. Signed-off-by: Shivasharan S <shivasharan.srikanteshwara@broadcom.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent de51637 commit 272652f

File tree

2 files changed

+49
-18
lines changed

2 files changed

+49
-18
lines changed

drivers/scsi/megaraid/megaraid_sas_base.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,28 @@ megasas_free_ctrl_dma_buffers(struct megasas_instance *instance);
220220
static inline void
221221
megasas_init_ctrl_params(struct megasas_instance *instance);
222222

223+
u32 megasas_readl(struct megasas_instance *instance,
224+
const volatile void __iomem *addr)
225+
{
226+
u32 i = 0, ret_val;
227+
/*
228+
* Due to a HW errata in Aero controllers, reads to certain
229+
* Fusion registers could intermittently return all zeroes.
230+
* This behavior is transient in nature and subsequent reads will
231+
* return valid value. As a workaround in driver, retry readl for
232+
* upto three times until a non-zero value is read.
233+
*/
234+
if (instance->adapter_type == AERO_SERIES) {
235+
do {
236+
ret_val = readl(addr);
237+
i++;
238+
} while (ret_val == 0 && i < 3);
239+
return ret_val;
240+
} else {
241+
return readl(addr);
242+
}
243+
}
244+
223245
/**
224246
* megasas_set_dma_settings - Populate DMA address, length and flags for DCMDs
225247
* @instance: Adapter soft state
@@ -3842,7 +3864,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
38423864

38433865
if (instance->adapter_type != MFI_SERIES) {
38443866
for (i = 0; i < (10 * 1000); i += 20) {
3845-
if (readl(
3867+
if (megasas_readl(
3868+
instance,
38463869
&instance->
38473870
reg_set->
38483871
doorbell) & 1)
@@ -5401,7 +5424,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
54015424

54025425
if (instance->adapter_type >= VENTURA_SERIES) {
54035426
scratch_pad_2 =
5404-
readl(&instance->reg_set->outbound_scratch_pad_2);
5427+
megasas_readl(instance,
5428+
&instance->reg_set->outbound_scratch_pad_2);
54055429
instance->max_raid_mapsize = ((scratch_pad_2 >>
54065430
MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT) &
54075431
MR_MAX_RAID_MAP_SIZE_MASK);
@@ -5413,8 +5437,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
54135437
if (msix_enable && !msix_disable) {
54145438
int irq_flags = PCI_IRQ_MSIX;
54155439

5416-
scratch_pad_1 = readl
5417-
(&instance->reg_set->outbound_scratch_pad_1);
5440+
scratch_pad_1 = megasas_readl
5441+
(instance, &instance->reg_set->outbound_scratch_pad_1);
54185442
/* Check max MSI-X vectors */
54195443
if (fusion) {
54205444
if (instance->adapter_type == THUNDERBOLT_SERIES) {
@@ -5525,7 +5549,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
55255549

55265550
if (instance->adapter_type >= VENTURA_SERIES) {
55275551
scratch_pad_3 =
5528-
readl(&instance->reg_set->outbound_scratch_pad_3);
5552+
megasas_readl(instance,
5553+
&instance->reg_set->outbound_scratch_pad_3);
55295554
if ((scratch_pad_3 & MR_NVME_PAGE_SIZE_MASK) >=
55305555
MR_DEFAULT_NVME_PAGE_SHIFT)
55315556
instance->nvme_page_size =
@@ -6193,8 +6218,8 @@ megasas_set_dma_mask(struct megasas_instance *instance)
61936218
* If 32 bit DMA mask fails, then try for 64 bit mask
61946219
* for FW capable of handling 64 bit DMA.
61956220
*/
6196-
scratch_pad_1 = readl
6197-
(&instance->reg_set->outbound_scratch_pad_1);
6221+
scratch_pad_1 = megasas_readl
6222+
(instance, &instance->reg_set->outbound_scratch_pad_1);
61986223

61996224
if (!(scratch_pad_1 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET))
62006225
goto fail_set_dma_mask;

drivers/scsi/megaraid/megaraid_sas_fusion.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ static void megasas_free_reply_fusion(struct megasas_instance *instance);
9595
static inline
9696
void megasas_configure_queue_sizes(struct megasas_instance *instance);
9797
static void megasas_fusion_crash_dump(struct megasas_instance *instance);
98+
extern u32 megasas_readl(struct megasas_instance *instance,
99+
const volatile void __iomem *addr);
98100

99101
/**
100102
* megasas_check_same_4gb_region - check if allocation
@@ -267,7 +269,8 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c
267269
/* ventura FW does not fill outbound_scratch_pad_2 with queue depth */
268270
if (instance->adapter_type < VENTURA_SERIES)
269271
cur_max_fw_cmds =
270-
readl(&instance->reg_set->outbound_scratch_pad_2) & 0x00FFFF;
272+
megasas_readl(instance,
273+
&instance->reg_set->outbound_scratch_pad_2) & 0x00FFFF;
271274

272275
if (dual_qdepth_disable || !cur_max_fw_cmds)
273276
cur_max_fw_cmds = instance->instancet->read_fw_status_reg(instance) & 0x00FFFF;
@@ -984,8 +987,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
984987

985988
cmd = fusion->ioc_init_cmd;
986989

987-
scratch_pad_1 = readl
988-
(&instance->reg_set->outbound_scratch_pad_1);
990+
scratch_pad_1 = megasas_readl
991+
(instance, &instance->reg_set->outbound_scratch_pad_1);
989992

990993
cur_rdpq_mode = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
991994

@@ -1104,7 +1107,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
11041107
instance->instancet->disable_intr(instance);
11051108

11061109
for (i = 0; i < (10 * 1000); i += 20) {
1107-
if (readl(&instance->reg_set->doorbell) & 1)
1110+
if (megasas_readl(instance, &instance->reg_set->doorbell) & 1)
11081111
msleep(20);
11091112
else
11101113
break;
@@ -1653,7 +1656,8 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
16531656

16541657
megasas_configure_queue_sizes(instance);
16551658

1656-
scratch_pad_1 = readl(&instance->reg_set->outbound_scratch_pad_1);
1659+
scratch_pad_1 = megasas_readl(instance,
1660+
&instance->reg_set->outbound_scratch_pad_1);
16571661
/* If scratch_pad_1 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set,
16581662
* Firmware support extended IO chain frame which is 4 times more than
16591663
* legacy Firmware.
@@ -3731,7 +3735,7 @@ megasas_release_fusion(struct megasas_instance *instance)
37313735
static u32
37323736
megasas_read_fw_status_reg_fusion(struct megasas_instance *instance)
37333737
{
3734-
return readl(&instance->reg_set->outbound_scratch_pad_0);
3738+
return megasas_readl(instance, &instance->reg_set->outbound_scratch_pad_0);
37353739
}
37363740

37373741
/**
@@ -3793,11 +3797,12 @@ megasas_adp_reset_fusion(struct megasas_instance *instance,
37933797
writel(MPI2_WRSEQ_6TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
37943798

37953799
/* Check that the diag write enable (DRWE) bit is on */
3796-
host_diag = readl(&instance->reg_set->fusion_host_diag);
3800+
host_diag = megasas_readl(instance, &instance->reg_set->fusion_host_diag);
37973801
retry = 0;
37983802
while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
37993803
msleep(100);
3800-
host_diag = readl(&instance->reg_set->fusion_host_diag);
3804+
host_diag = megasas_readl(instance,
3805+
&instance->reg_set->fusion_host_diag);
38013806
if (retry++ == 100) {
38023807
dev_warn(&instance->pdev->dev,
38033808
"Host diag unlock failed from %s %d\n",
@@ -3814,11 +3819,12 @@ megasas_adp_reset_fusion(struct megasas_instance *instance,
38143819
msleep(3000);
38153820

38163821
/* Make sure reset adapter bit is cleared */
3817-
host_diag = readl(&instance->reg_set->fusion_host_diag);
3822+
host_diag = megasas_readl(instance, &instance->reg_set->fusion_host_diag);
38183823
retry = 0;
38193824
while (host_diag & HOST_DIAG_RESET_ADAPTER) {
38203825
msleep(100);
3821-
host_diag = readl(&instance->reg_set->fusion_host_diag);
3826+
host_diag = megasas_readl(instance,
3827+
&instance->reg_set->fusion_host_diag);
38223828
if (retry++ == 1000) {
38233829
dev_warn(&instance->pdev->dev,
38243830
"Diag reset adapter never cleared %s %d\n",
@@ -4607,7 +4613,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
46074613
dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
46084614
"forcibly FAULT Firmware\n");
46094615
atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
4610-
status_reg = readl(&instance->reg_set->doorbell);
4616+
status_reg = megasas_readl(instance, &instance->reg_set->doorbell);
46114617
writel(status_reg | MFI_STATE_FORCE_OCR,
46124618
&instance->reg_set->doorbell);
46134619
readl(&instance->reg_set->doorbell);

0 commit comments

Comments
 (0)