aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/arcmsr/arcmsr_hba.c
diff options
context:
space:
mode:
authorChing Huang <ching2048@areca.com.tw>2014-08-19 02:18:24 -0400
committerChristoph Hellwig <hch@lst.de>2014-09-16 12:38:47 -0400
commit6b3937227479e50032112faf74bd913f36dba2c6 (patch)
treec5f8ec006a692018f7c6ff534776f97a40cda9a3 /drivers/scsi/arcmsr/arcmsr_hba.c
parent0d9d8b9ff4453e4816b22bf729256feb6b38e0ec (diff)
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: Ching Huang <ching2048@areca.com.tw> Reviewed-by: Tomas Henzl <thenzl@redhat.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi/arcmsr/arcmsr_hba.c')
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c198
1 files changed, 97 insertions, 101 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index b13764ca23fd..506fe7b851bc 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -1441,14 +1441,15 @@ static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
1441 uint32_t outbound_doorbell; 1441 uint32_t outbound_doorbell;
1442 struct MessageUnit_A __iomem *reg = acb->pmuA; 1442 struct MessageUnit_A __iomem *reg = acb->pmuA;
1443 outbound_doorbell = readl(&reg->outbound_doorbell); 1443 outbound_doorbell = readl(&reg->outbound_doorbell);
1444 writel(outbound_doorbell, &reg->outbound_doorbell); 1444 do {
1445 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { 1445 writel(outbound_doorbell, &reg->outbound_doorbell);
1446 arcmsr_iop2drv_data_wrote_handle(acb); 1446 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK)
1447 } 1447 arcmsr_iop2drv_data_wrote_handle(acb);
1448 1448 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)
1449 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { 1449 arcmsr_iop2drv_data_read_handle(acb);
1450 arcmsr_iop2drv_data_read_handle(acb); 1450 outbound_doorbell = readl(&reg->outbound_doorbell);
1451 } 1451 } while (outbound_doorbell & (ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK
1452 | ARCMSR_OUTBOUND_IOP331_DATA_READ_OK));
1452} 1453}
1453static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB) 1454static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
1454{ 1455{
@@ -1462,17 +1463,19 @@ static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
1462 ******************************************************************* 1463 *******************************************************************
1463 */ 1464 */
1464 outbound_doorbell = readl(&reg->outbound_doorbell); 1465 outbound_doorbell = readl(&reg->outbound_doorbell);
1465 writel(outbound_doorbell, &reg->outbound_doorbell_clear);/*clear interrupt*/ 1466 do {
1466 if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { 1467 writel(outbound_doorbell, &reg->outbound_doorbell_clear);
1467 arcmsr_iop2drv_data_wrote_handle(pACB); 1468 readl(&reg->outbound_doorbell_clear);
1468 } 1469 if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK)
1469 if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) { 1470 arcmsr_iop2drv_data_wrote_handle(pACB);
1470 arcmsr_iop2drv_data_read_handle(pACB); 1471 if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK)
1471 } 1472 arcmsr_iop2drv_data_read_handle(pACB);
1472 if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { 1473 if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE)
1473 arcmsr_hbc_message_isr(pACB); /* messenger of "driver to iop commands" */ 1474 arcmsr_hbc_message_isr(pACB);
1474 } 1475 outbound_doorbell = readl(&reg->outbound_doorbell);
1475 return; 1476 } while (outbound_doorbell & (ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK
1477 | ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK
1478 | ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE));
1476} 1479}
1477static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) 1480static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
1478{ 1481{
@@ -1521,21 +1524,23 @@ static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb)
1521 /* areca cdb command done */ 1524 /* areca cdb command done */
1522 /* Use correct offset and size for syncing */ 1525 /* Use correct offset and size for syncing */
1523 1526
1524 while (readl(&phbcmu->host_int_status) & 1527 while ((flag_ccb = readl(&phbcmu->outbound_queueport_low)) !=
1525 ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){ 1528 0xFFFFFFFF) {
1526 /* check if command done with no error*/ 1529 ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
1527 flag_ccb = readl(&phbcmu->outbound_queueport_low); 1530 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
1528 ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/ 1531 + ccb_cdb_phy);
1529 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); 1532 ccb = container_of(arcmsr_cdb, struct CommandControlBlock,
1530 ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); 1533 arcmsr_cdb);
1531 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; 1534 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
1532 /* check if command done with no error */ 1535 ? true : false;
1533 arcmsr_drain_donequeue(acb, ccb, error); 1536 /* check if command done with no error */
1534 if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) { 1537 arcmsr_drain_donequeue(acb, ccb, error);
1535 writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell); 1538 throttling++;
1536 break; 1539 if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
1537 } 1540 writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING,
1538 throttling++; 1541 &phbcmu->inbound_doorbell);
1542 throttling = 0;
1543 }
1539 } 1544 }
1540} 1545}
1541/* 1546/*
@@ -1584,21 +1589,22 @@ static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
1584 struct MessageUnit_A __iomem *reg = acb->pmuA; 1589 struct MessageUnit_A __iomem *reg = acb->pmuA;
1585 outbound_intstatus = readl(&reg->outbound_intstatus) & 1590 outbound_intstatus = readl(&reg->outbound_intstatus) &
1586 acb->outbound_int_enable; 1591 acb->outbound_int_enable;
1587 if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) { 1592 if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
1588 return 1; 1593 return IRQ_NONE;
1589 } 1594 do {
1590 writel(outbound_intstatus, &reg->outbound_intstatus); 1595 writel(outbound_intstatus, &reg->outbound_intstatus);
1591 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { 1596 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)
1592 arcmsr_hba_doorbell_isr(acb); 1597 arcmsr_hba_doorbell_isr(acb);
1593 } 1598 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT)
1594 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { 1599 arcmsr_hba_postqueue_isr(acb);
1595 arcmsr_hba_postqueue_isr(acb); 1600 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT)
1596 } 1601 arcmsr_hba_message_isr(acb);
1597 if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { 1602 outbound_intstatus = readl(&reg->outbound_intstatus) &
1598 /* messenger of "driver to iop commands" */ 1603 acb->outbound_int_enable;
1599 arcmsr_hba_message_isr(acb); 1604 } while (outbound_intstatus & (ARCMSR_MU_OUTBOUND_DOORBELL_INT
1600 } 1605 | ARCMSR_MU_OUTBOUND_POSTQUEUE_INT
1601 return 0; 1606 | ARCMSR_MU_OUTBOUND_MESSAGE0_INT));
1607 return IRQ_HANDLED;
1602} 1608}
1603 1609
1604static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) 1610static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
@@ -1608,27 +1614,25 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
1608 outbound_doorbell = readl(reg->iop2drv_doorbell) & 1614 outbound_doorbell = readl(reg->iop2drv_doorbell) &
1609 acb->outbound_int_enable; 1615 acb->outbound_int_enable;
1610 if (!outbound_doorbell) 1616 if (!outbound_doorbell)
1611 return 1; 1617 return IRQ_NONE;
1612 1618 do {
1613 writel(~outbound_doorbell, reg->iop2drv_doorbell); 1619 writel(~outbound_doorbell, reg->iop2drv_doorbell);
1614 /*in case the last action of doorbell interrupt clearance is cached, 1620 writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
1615 this action can push HW to write down the clear bit*/ 1621 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK)
1616 readl(reg->iop2drv_doorbell); 1622 arcmsr_iop2drv_data_wrote_handle(acb);
1617 writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); 1623 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK)
1618 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { 1624 arcmsr_iop2drv_data_read_handle(acb);
1619 arcmsr_iop2drv_data_wrote_handle(acb); 1625 if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE)
1620 } 1626 arcmsr_hbb_postqueue_isr(acb);
1621 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { 1627 if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE)
1622 arcmsr_iop2drv_data_read_handle(acb); 1628 arcmsr_hbb_message_isr(acb);
1623 } 1629 outbound_doorbell = readl(reg->iop2drv_doorbell) &
1624 if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { 1630 acb->outbound_int_enable;
1625 arcmsr_hbb_postqueue_isr(acb); 1631 } while (outbound_doorbell & (ARCMSR_IOP2DRV_DATA_WRITE_OK
1626 } 1632 | ARCMSR_IOP2DRV_DATA_READ_OK
1627 if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { 1633 | ARCMSR_IOP2DRV_CDB_DONE
1628 /* messenger of "driver to iop commands" */ 1634 | ARCMSR_IOP2DRV_MESSAGE_CMD_DONE));
1629 arcmsr_hbb_message_isr(acb); 1635 return IRQ_HANDLED;
1630 }
1631 return 0;
1632} 1636}
1633 1637
1634static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB) 1638static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB)
@@ -1640,44 +1644,36 @@ static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB)
1640 ** check outbound intstatus 1644 ** check outbound intstatus
1641 ********************************************* 1645 *********************************************
1642 */ 1646 */
1643 host_interrupt_status = readl(&phbcmu->host_int_status); 1647 host_interrupt_status = readl(&phbcmu->host_int_status) &
1644 if (!host_interrupt_status) { 1648 (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
1645 /*it must be share irq*/ 1649 ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR);
1646 return 1; 1650 if (!host_interrupt_status)
1647 } 1651 return IRQ_NONE;
1648 /* MU ioctl transfer doorbell interrupts*/ 1652 do {
1649 if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) { 1653 if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR)
1650 arcmsr_hbc_doorbell_isr(pACB); /* messenger of "ioctl message read write" */ 1654 arcmsr_hbc_doorbell_isr(pACB);
1651 } 1655 /* MU post queue interrupts*/
1652 /* MU post queue interrupts*/ 1656 if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR)
1653 if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) { 1657 arcmsr_hbc_postqueue_isr(pACB);
1654 arcmsr_hbc_postqueue_isr(pACB); /* messenger of "scsi commands" */ 1658 host_interrupt_status = readl(&phbcmu->host_int_status);
1655 } 1659 } while (host_interrupt_status & (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
1656 return 0; 1660 ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR));
1661 return IRQ_HANDLED;
1657} 1662}
1658static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) 1663static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
1659{ 1664{
1660 switch (acb->adapter_type) { 1665 switch (acb->adapter_type) {
1661 case ACB_ADAPTER_TYPE_A: { 1666 case ACB_ADAPTER_TYPE_A:
1662 if (arcmsr_handle_hba_isr(acb)) { 1667 return arcmsr_handle_hba_isr(acb);
1663 return IRQ_NONE;
1664 }
1665 }
1666 break; 1668 break;
1667 1669 case ACB_ADAPTER_TYPE_B:
1668 case ACB_ADAPTER_TYPE_B: { 1670 return arcmsr_handle_hbb_isr(acb);
1669 if (arcmsr_handle_hbb_isr(acb)) {
1670 return IRQ_NONE;
1671 }
1672 }
1673 break; 1671 break;
1674 case ACB_ADAPTER_TYPE_C: { 1672 case ACB_ADAPTER_TYPE_C:
1675 if (arcmsr_handle_hbc_isr(acb)) { 1673 return arcmsr_handle_hbc_isr(acb);
1676 return IRQ_NONE; 1674 default:
1677 } 1675 return IRQ_NONE;
1678 }
1679 } 1676 }
1680 return IRQ_HANDLED;
1681} 1677}
1682 1678
1683static void arcmsr_iop_parking(struct AdapterControlBlock *acb) 1679static void arcmsr_iop_parking(struct AdapterControlBlock *acb)