diff options
author | Ching Huang <ching2048@areca.com.tw> | 2014-08-19 02:18:24 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-09-16 12:38:47 -0400 |
commit | 6b3937227479e50032112faf74bd913f36dba2c6 (patch) | |
tree | c5f8ec006a692018f7c6ff534776f97a40cda9a3 /drivers/scsi/arcmsr/arcmsr_hba.c | |
parent | 0d9d8b9ff4453e4816b22bf729256feb6b38e0ec (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.c | 198 |
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(®->outbound_doorbell); | 1443 | outbound_doorbell = readl(®->outbound_doorbell); |
1444 | writel(outbound_doorbell, ®->outbound_doorbell); | 1444 | do { |
1445 | if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { | 1445 | writel(outbound_doorbell, ®->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(®->outbound_doorbell); |
1451 | } | 1451 | } while (outbound_doorbell & (ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK |
1452 | | ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)); | ||
1452 | } | 1453 | } |
1453 | static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB) | 1454 | static 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(®->outbound_doorbell); | 1465 | outbound_doorbell = readl(®->outbound_doorbell); |
1465 | writel(outbound_doorbell, ®->outbound_doorbell_clear);/*clear interrupt*/ | 1466 | do { |
1466 | if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { | 1467 | writel(outbound_doorbell, ®->outbound_doorbell_clear); |
1467 | arcmsr_iop2drv_data_wrote_handle(pACB); | 1468 | readl(®->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(®->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 | } |
1477 | static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) | 1480 | static 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(®->outbound_intstatus) & | 1590 | outbound_intstatus = readl(®->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, ®->outbound_intstatus); | 1595 | writel(outbound_intstatus, ®->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(®->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 | ||
1604 | static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) | 1610 | static 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 | ||
1634 | static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB) | 1638 | static 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 | } |
1658 | static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) | 1663 | static 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 | ||
1683 | static void arcmsr_iop_parking(struct AdapterControlBlock *acb) | 1679 | static void arcmsr_iop_parking(struct AdapterControlBlock *acb) |