Commit 6b393722 authored by Ching Huang's avatar Ching Huang Committed by Christoph Hellwig

arcmsr: fix command timeout under heavy load

This patch rewrites the interrupt service routine relate function to fix
a command timeout under heavy controller load.
Signed-off-by: default avatarChing Huang <ching2048@areca.com.tw>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 0d9d8b9f
...@@ -51,7 +51,7 @@ struct device_attribute; ...@@ -51,7 +51,7 @@ struct device_attribute;
#else #else
#define ARCMSR_MAX_FREECCB_NUM 320 #define ARCMSR_MAX_FREECCB_NUM 320
#endif #endif
#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/08/05" #define ARCMSR_DRIVER_VERSION "v1.30.00.04-20140428"
#define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096 #define ARCMSR_MAX_XFER_SECTORS_B 4096
......
...@@ -1441,14 +1441,15 @@ static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb) ...@@ -1441,14 +1441,15 @@ static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
uint32_t outbound_doorbell; uint32_t outbound_doorbell;
struct MessageUnit_A __iomem *reg = acb->pmuA; struct MessageUnit_A __iomem *reg = acb->pmuA;
outbound_doorbell = readl(&reg->outbound_doorbell); outbound_doorbell = readl(&reg->outbound_doorbell);
do {
writel(outbound_doorbell, &reg->outbound_doorbell); writel(outbound_doorbell, &reg->outbound_doorbell);
if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK)
arcmsr_iop2drv_data_wrote_handle(acb); arcmsr_iop2drv_data_wrote_handle(acb);
} if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)
if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
arcmsr_iop2drv_data_read_handle(acb); arcmsr_iop2drv_data_read_handle(acb);
} outbound_doorbell = readl(&reg->outbound_doorbell);
} while (outbound_doorbell & (ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK
| ARCMSR_OUTBOUND_IOP331_DATA_READ_OK));
} }
static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB) static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
{ {
...@@ -1462,17 +1463,19 @@ static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB) ...@@ -1462,17 +1463,19 @@ static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
******************************************************************* *******************************************************************
*/ */
outbound_doorbell = readl(&reg->outbound_doorbell); outbound_doorbell = readl(&reg->outbound_doorbell);
writel(outbound_doorbell, &reg->outbound_doorbell_clear);/*clear interrupt*/ do {
if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { writel(outbound_doorbell, &reg->outbound_doorbell_clear);
readl(&reg->outbound_doorbell_clear);
if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK)
arcmsr_iop2drv_data_wrote_handle(pACB); arcmsr_iop2drv_data_wrote_handle(pACB);
} if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK)
if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) {
arcmsr_iop2drv_data_read_handle(pACB); arcmsr_iop2drv_data_read_handle(pACB);
} if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE)
if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { arcmsr_hbc_message_isr(pACB);
arcmsr_hbc_message_isr(pACB); /* messenger of "driver to iop commands" */ outbound_doorbell = readl(&reg->outbound_doorbell);
} } while (outbound_doorbell & (ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK
return; | ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK
| ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE));
} }
static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
{ {
...@@ -1521,21 +1524,23 @@ static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb) ...@@ -1521,21 +1524,23 @@ static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb)
/* areca cdb command done */ /* areca cdb command done */
/* Use correct offset and size for syncing */ /* Use correct offset and size for syncing */
while (readl(&phbcmu->host_int_status) & while ((flag_ccb = readl(&phbcmu->outbound_queueport_low)) !=
ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){ 0xFFFFFFFF) {
/* check if command done with no error*/ ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
flag_ccb = readl(&phbcmu->outbound_queueport_low); arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/ + ccb_cdb_phy);
arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); ccb = container_of(arcmsr_cdb, struct CommandControlBlock,
ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); arcmsr_cdb);
error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
? true : false;
/* check if command done with no error */ /* check if command done with no error */
arcmsr_drain_donequeue(acb, ccb, error); arcmsr_drain_donequeue(acb, ccb, error);
throttling++;
if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) { if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell); writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING,
break; &phbcmu->inbound_doorbell);
throttling = 0;
} }
throttling++;
} }
} }
/* /*
...@@ -1584,21 +1589,22 @@ static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb) ...@@ -1584,21 +1589,22 @@ static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
struct MessageUnit_A __iomem *reg = acb->pmuA; struct MessageUnit_A __iomem *reg = acb->pmuA;
outbound_intstatus = readl(&reg->outbound_intstatus) & outbound_intstatus = readl(&reg->outbound_intstatus) &
acb->outbound_int_enable; acb->outbound_int_enable;
if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) { if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
return 1; return IRQ_NONE;
} do {
writel(outbound_intstatus, &reg->outbound_intstatus); writel(outbound_intstatus, &reg->outbound_intstatus);
if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)
arcmsr_hba_doorbell_isr(acb); arcmsr_hba_doorbell_isr(acb);
} if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT)
if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
arcmsr_hba_postqueue_isr(acb); arcmsr_hba_postqueue_isr(acb);
} if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT)
if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
/* messenger of "driver to iop commands" */
arcmsr_hba_message_isr(acb); arcmsr_hba_message_isr(acb);
} outbound_intstatus = readl(&reg->outbound_intstatus) &
return 0; acb->outbound_int_enable;
} while (outbound_intstatus & (ARCMSR_MU_OUTBOUND_DOORBELL_INT
| ARCMSR_MU_OUTBOUND_POSTQUEUE_INT
| ARCMSR_MU_OUTBOUND_MESSAGE0_INT));
return IRQ_HANDLED;
} }
static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
...@@ -1608,27 +1614,25 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) ...@@ -1608,27 +1614,25 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
outbound_doorbell = readl(reg->iop2drv_doorbell) & outbound_doorbell = readl(reg->iop2drv_doorbell) &
acb->outbound_int_enable; acb->outbound_int_enable;
if (!outbound_doorbell) if (!outbound_doorbell)
return 1; return IRQ_NONE;
do {
writel(~outbound_doorbell, reg->iop2drv_doorbell); writel(~outbound_doorbell, reg->iop2drv_doorbell);
/*in case the last action of doorbell interrupt clearance is cached,
this action can push HW to write down the clear bit*/
readl(reg->iop2drv_doorbell);
writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK)
arcmsr_iop2drv_data_wrote_handle(acb); arcmsr_iop2drv_data_wrote_handle(acb);
} if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK)
if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
arcmsr_iop2drv_data_read_handle(acb); arcmsr_iop2drv_data_read_handle(acb);
} if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE)
if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
arcmsr_hbb_postqueue_isr(acb); arcmsr_hbb_postqueue_isr(acb);
} if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE)
if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
/* messenger of "driver to iop commands" */
arcmsr_hbb_message_isr(acb); arcmsr_hbb_message_isr(acb);
} outbound_doorbell = readl(reg->iop2drv_doorbell) &
return 0; acb->outbound_int_enable;
} while (outbound_doorbell & (ARCMSR_IOP2DRV_DATA_WRITE_OK
| ARCMSR_IOP2DRV_DATA_READ_OK
| ARCMSR_IOP2DRV_CDB_DONE
| ARCMSR_IOP2DRV_MESSAGE_CMD_DONE));
return IRQ_HANDLED;
} }
static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB) static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB)
...@@ -1640,44 +1644,36 @@ static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB) ...@@ -1640,44 +1644,36 @@ static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB)
** check outbound intstatus ** check outbound intstatus
********************************************* *********************************************
*/ */
host_interrupt_status = readl(&phbcmu->host_int_status); host_interrupt_status = readl(&phbcmu->host_int_status) &
if (!host_interrupt_status) { (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
/*it must be share irq*/ ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR);
return 1; if (!host_interrupt_status)
} return IRQ_NONE;
/* MU ioctl transfer doorbell interrupts*/ do {
if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) { if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR)
arcmsr_hbc_doorbell_isr(pACB); /* messenger of "ioctl message read write" */ arcmsr_hbc_doorbell_isr(pACB);
}
/* MU post queue interrupts*/ /* MU post queue interrupts*/
if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) { if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR)
arcmsr_hbc_postqueue_isr(pACB); /* messenger of "scsi commands" */ arcmsr_hbc_postqueue_isr(pACB);
} host_interrupt_status = readl(&phbcmu->host_int_status);
return 0; } while (host_interrupt_status & (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR));
return IRQ_HANDLED;
} }
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
{ {
switch (acb->adapter_type) { switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: { case ACB_ADAPTER_TYPE_A:
if (arcmsr_handle_hba_isr(acb)) { return arcmsr_handle_hba_isr(acb);
return IRQ_NONE;
}
}
break; break;
case ACB_ADAPTER_TYPE_B:
case ACB_ADAPTER_TYPE_B: { return arcmsr_handle_hbb_isr(acb);
if (arcmsr_handle_hbb_isr(acb)) {
return IRQ_NONE;
}
}
break; break;
case ACB_ADAPTER_TYPE_C: { case ACB_ADAPTER_TYPE_C:
if (arcmsr_handle_hbc_isr(acb)) { return arcmsr_handle_hbc_isr(acb);
default:
return IRQ_NONE; return IRQ_NONE;
} }
}
}
return IRQ_HANDLED;
} }
static void arcmsr_iop_parking(struct AdapterControlBlock *acb) static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment