arcmsr: clear outbound doorbell buffer completely
authorChing Huang <ching2048@areca.com.tw>
Tue, 19 Aug 2014 07:07:35 +0000 (15:07 +0800)
committerChristoph Hellwig <hch@lst.de>
Tue, 16 Sep 2014 16:39:49 +0000 (09:39 -0700)
Clear outbound doorbell buffer completely for adapter type C.  This is to
prevent getting bad data input from IOP before ioctl command processing
starts.

Signed-off-by: Ching Huang <ching2048@areca.com.tw>
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/scsi/arcmsr/arcmsr_hba.c

index 0707677c11a167dba9f52b65ecbdb3b728877303..3363c31bb789cf768afae2f95fc7c0c04474f55e 100644 (file)
@@ -2870,11 +2870,23 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
                break;
        case ACB_ADAPTER_TYPE_C: {
                struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
-               uint32_t outbound_doorbell;
+               uint32_t outbound_doorbell, i;
                /* empty doorbell Qbuffer if door bell ringed */
                outbound_doorbell = readl(&reg->outbound_doorbell);
                writel(outbound_doorbell, &reg->outbound_doorbell_clear);
                writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+               for (i = 0; i < 200; i++) {
+                       msleep(20);
+                       outbound_doorbell = readl(&reg->outbound_doorbell);
+                       if (outbound_doorbell &
+                               ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) {
+                               writel(outbound_doorbell,
+                                       &reg->outbound_doorbell_clear);
+                               writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK,
+                                       &reg->inbound_doorbell);
+                       } else
+                               break;
+               }
                }
        }
 }
@@ -3102,9 +3114,7 @@ sleep:
                                arcmsr_get_firmware_spec(acb);
                                arcmsr_start_adapter_bgrb(acb);
                                /* clear Qbuffer if door bell ringed */
-                               outbound_doorbell = readl(&reg->outbound_doorbell);
-                               writel(outbound_doorbell, &reg->outbound_doorbell_clear); /*clear interrupt */
-                               writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+                               arcmsr_clear_doorbell_queue_buffer(acb);
                                /* enable outbound Post Queue,outbound doorbell Interrupt */
                                arcmsr_enable_outbound_ints(acb, intmask_org);
                                atomic_set(&acb->rq_map_token, 16);