diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_isr.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 245 |
1 files changed, 229 insertions, 16 deletions
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 39fd17b05be5..d4885616cd39 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c | |||
@@ -86,12 +86,8 @@ qla2100_intr_handler(int irq, void *dev_id) | |||
86 | 86 | ||
87 | if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && | 87 | if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && |
88 | (status & MBX_INTERRUPT) && ha->flags.mbox_int) { | 88 | (status & MBX_INTERRUPT) && ha->flags.mbox_int) { |
89 | spin_lock_irqsave(&ha->mbx_reg_lock, flags); | ||
90 | |||
91 | set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); | 89 | set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); |
92 | up(&ha->mbx_intr_sem); | 90 | up(&ha->mbx_intr_sem); |
93 | |||
94 | spin_unlock_irqrestore(&ha->mbx_reg_lock, flags); | ||
95 | } | 91 | } |
96 | 92 | ||
97 | return (IRQ_HANDLED); | 93 | return (IRQ_HANDLED); |
@@ -199,12 +195,8 @@ qla2300_intr_handler(int irq, void *dev_id) | |||
199 | 195 | ||
200 | if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && | 196 | if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && |
201 | (status & MBX_INTERRUPT) && ha->flags.mbox_int) { | 197 | (status & MBX_INTERRUPT) && ha->flags.mbox_int) { |
202 | spin_lock_irqsave(&ha->mbx_reg_lock, flags); | ||
203 | |||
204 | set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); | 198 | set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); |
205 | up(&ha->mbx_intr_sem); | 199 | up(&ha->mbx_intr_sem); |
206 | |||
207 | spin_unlock_irqrestore(&ha->mbx_reg_lock, flags); | ||
208 | } | 200 | } |
209 | 201 | ||
210 | return (IRQ_HANDLED); | 202 | return (IRQ_HANDLED); |
@@ -654,10 +646,8 @@ qla2x00_ramp_up_queue_depth(scsi_qla_host_t *ha, srb_t *sp) | |||
654 | fcport->last_queue_full + ql2xqfullrampup * HZ)) | 646 | fcport->last_queue_full + ql2xqfullrampup * HZ)) |
655 | return; | 647 | return; |
656 | 648 | ||
657 | spin_unlock_irq(&ha->hardware_lock); | ||
658 | starget_for_each_device(sdev->sdev_target, fcport, | 649 | starget_for_each_device(sdev->sdev_target, fcport, |
659 | qla2x00_adjust_sdev_qdepth_up); | 650 | qla2x00_adjust_sdev_qdepth_up); |
660 | spin_lock_irq(&ha->hardware_lock); | ||
661 | } | 651 | } |
662 | 652 | ||
663 | /** | 653 | /** |
@@ -927,10 +917,8 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) | |||
927 | 917 | ||
928 | /* Adjust queue depth for all luns on the port. */ | 918 | /* Adjust queue depth for all luns on the port. */ |
929 | fcport->last_queue_full = jiffies; | 919 | fcport->last_queue_full = jiffies; |
930 | spin_unlock_irq(&ha->hardware_lock); | ||
931 | starget_for_each_device(cp->device->sdev_target, | 920 | starget_for_each_device(cp->device->sdev_target, |
932 | fcport, qla2x00_adjust_sdev_qdepth_down); | 921 | fcport, qla2x00_adjust_sdev_qdepth_down); |
933 | spin_lock_irq(&ha->hardware_lock); | ||
934 | break; | 922 | break; |
935 | } | 923 | } |
936 | if (lscsi_status != SS_CHECK_CONDITION) | 924 | if (lscsi_status != SS_CHECK_CONDITION) |
@@ -995,6 +983,22 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) | |||
995 | if (lscsi_status != 0) { | 983 | if (lscsi_status != 0) { |
996 | cp->result = DID_OK << 16 | lscsi_status; | 984 | cp->result = DID_OK << 16 | lscsi_status; |
997 | 985 | ||
986 | if (lscsi_status == SAM_STAT_TASK_SET_FULL) { | ||
987 | DEBUG2(printk(KERN_INFO | ||
988 | "scsi(%ld): QUEUE FULL status detected " | ||
989 | "0x%x-0x%x.\n", ha->host_no, comp_status, | ||
990 | scsi_status)); | ||
991 | |||
992 | /* | ||
993 | * Adjust queue depth for all luns on the | ||
994 | * port. | ||
995 | */ | ||
996 | fcport->last_queue_full = jiffies; | ||
997 | starget_for_each_device( | ||
998 | cp->device->sdev_target, fcport, | ||
999 | qla2x00_adjust_sdev_qdepth_down); | ||
1000 | break; | ||
1001 | } | ||
998 | if (lscsi_status != SS_CHECK_CONDITION) | 1002 | if (lscsi_status != SS_CHECK_CONDITION) |
999 | break; | 1003 | break; |
1000 | 1004 | ||
@@ -1482,12 +1486,8 @@ qla24xx_intr_handler(int irq, void *dev_id) | |||
1482 | 1486 | ||
1483 | if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && | 1487 | if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && |
1484 | (status & MBX_INTERRUPT) && ha->flags.mbox_int) { | 1488 | (status & MBX_INTERRUPT) && ha->flags.mbox_int) { |
1485 | spin_lock_irqsave(&ha->mbx_reg_lock, flags); | ||
1486 | |||
1487 | set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); | 1489 | set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); |
1488 | up(&ha->mbx_intr_sem); | 1490 | up(&ha->mbx_intr_sem); |
1489 | |||
1490 | spin_unlock_irqrestore(&ha->mbx_reg_lock, flags); | ||
1491 | } | 1491 | } |
1492 | 1492 | ||
1493 | return IRQ_HANDLED; | 1493 | return IRQ_HANDLED; |
@@ -1536,3 +1536,216 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt) | |||
1536 | qla2x00_sp_compl(ha, sp); | 1536 | qla2x00_sp_compl(ha, sp); |
1537 | } | 1537 | } |
1538 | 1538 | ||
1539 | static irqreturn_t | ||
1540 | qla24xx_msix_rsp_q(int irq, void *dev_id) | ||
1541 | { | ||
1542 | scsi_qla_host_t *ha; | ||
1543 | struct device_reg_24xx __iomem *reg; | ||
1544 | unsigned long flags; | ||
1545 | |||
1546 | ha = dev_id; | ||
1547 | reg = &ha->iobase->isp24; | ||
1548 | |||
1549 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1550 | |||
1551 | qla24xx_process_response_queue(ha); | ||
1552 | |||
1553 | WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); | ||
1554 | RD_REG_DWORD_RELAXED(®->hccr); | ||
1555 | |||
1556 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1557 | |||
1558 | return IRQ_HANDLED; | ||
1559 | } | ||
1560 | |||
1561 | static irqreturn_t | ||
1562 | qla24xx_msix_default(int irq, void *dev_id) | ||
1563 | { | ||
1564 | scsi_qla_host_t *ha; | ||
1565 | struct device_reg_24xx __iomem *reg; | ||
1566 | int status; | ||
1567 | unsigned long flags; | ||
1568 | unsigned long iter; | ||
1569 | uint32_t stat; | ||
1570 | uint32_t hccr; | ||
1571 | uint16_t mb[4]; | ||
1572 | |||
1573 | ha = dev_id; | ||
1574 | reg = &ha->iobase->isp24; | ||
1575 | status = 0; | ||
1576 | |||
1577 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1578 | for (iter = 50; iter--; ) { | ||
1579 | stat = RD_REG_DWORD(®->host_status); | ||
1580 | if (stat & HSRX_RISC_PAUSED) { | ||
1581 | hccr = RD_REG_DWORD(®->hccr); | ||
1582 | |||
1583 | qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " | ||
1584 | "Dumping firmware!\n", hccr); | ||
1585 | ha->isp_ops.fw_dump(ha, 1); | ||
1586 | set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); | ||
1587 | break; | ||
1588 | } else if ((stat & HSRX_RISC_INT) == 0) | ||
1589 | break; | ||
1590 | |||
1591 | switch (stat & 0xff) { | ||
1592 | case 0x1: | ||
1593 | case 0x2: | ||
1594 | case 0x10: | ||
1595 | case 0x11: | ||
1596 | qla24xx_mbx_completion(ha, MSW(stat)); | ||
1597 | status |= MBX_INTERRUPT; | ||
1598 | |||
1599 | break; | ||
1600 | case 0x12: | ||
1601 | mb[0] = MSW(stat); | ||
1602 | mb[1] = RD_REG_WORD(®->mailbox1); | ||
1603 | mb[2] = RD_REG_WORD(®->mailbox2); | ||
1604 | mb[3] = RD_REG_WORD(®->mailbox3); | ||
1605 | qla2x00_async_event(ha, mb); | ||
1606 | break; | ||
1607 | case 0x13: | ||
1608 | qla24xx_process_response_queue(ha); | ||
1609 | break; | ||
1610 | default: | ||
1611 | DEBUG2(printk("scsi(%ld): Unrecognized interrupt type " | ||
1612 | "(%d).\n", | ||
1613 | ha->host_no, stat & 0xff)); | ||
1614 | break; | ||
1615 | } | ||
1616 | WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); | ||
1617 | RD_REG_DWORD_RELAXED(®->hccr); | ||
1618 | } | ||
1619 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1620 | |||
1621 | if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && | ||
1622 | (status & MBX_INTERRUPT) && ha->flags.mbox_int) { | ||
1623 | set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); | ||
1624 | up(&ha->mbx_intr_sem); | ||
1625 | } | ||
1626 | |||
1627 | return IRQ_HANDLED; | ||
1628 | } | ||
1629 | |||
1630 | /* Interrupt handling helpers. */ | ||
1631 | |||
1632 | struct qla_init_msix_entry { | ||
1633 | uint16_t entry; | ||
1634 | uint16_t index; | ||
1635 | const char *name; | ||
1636 | irqreturn_t (*handler)(int, void *); | ||
1637 | }; | ||
1638 | |||
1639 | static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = { | ||
1640 | { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT, | ||
1641 | "qla2xxx (default)", qla24xx_msix_default }, | ||
1642 | |||
1643 | { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q, | ||
1644 | "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, | ||
1645 | }; | ||
1646 | |||
1647 | static void | ||
1648 | qla24xx_disable_msix(scsi_qla_host_t *ha) | ||
1649 | { | ||
1650 | int i; | ||
1651 | struct qla_msix_entry *qentry; | ||
1652 | |||
1653 | for (i = 0; i < QLA_MSIX_ENTRIES; i++) { | ||
1654 | qentry = &ha->msix_entries[imsix_entries[i].index]; | ||
1655 | if (qentry->have_irq) | ||
1656 | free_irq(qentry->msix_vector, ha); | ||
1657 | } | ||
1658 | pci_disable_msix(ha->pdev); | ||
1659 | } | ||
1660 | |||
1661 | static int | ||
1662 | qla24xx_enable_msix(scsi_qla_host_t *ha) | ||
1663 | { | ||
1664 | int i, ret; | ||
1665 | struct msix_entry entries[QLA_MSIX_ENTRIES]; | ||
1666 | struct qla_msix_entry *qentry; | ||
1667 | |||
1668 | for (i = 0; i < QLA_MSIX_ENTRIES; i++) | ||
1669 | entries[i].entry = imsix_entries[i].entry; | ||
1670 | |||
1671 | ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries)); | ||
1672 | if (ret) { | ||
1673 | qla_printk(KERN_WARNING, ha, | ||
1674 | "MSI-X: Failed to enable support -- %d/%d\n", | ||
1675 | QLA_MSIX_ENTRIES, ret); | ||
1676 | goto msix_out; | ||
1677 | } | ||
1678 | ha->flags.msix_enabled = 1; | ||
1679 | |||
1680 | for (i = 0; i < QLA_MSIX_ENTRIES; i++) { | ||
1681 | qentry = &ha->msix_entries[imsix_entries[i].index]; | ||
1682 | qentry->msix_vector = entries[i].vector; | ||
1683 | qentry->msix_entry = entries[i].entry; | ||
1684 | qentry->have_irq = 0; | ||
1685 | ret = request_irq(qentry->msix_vector, | ||
1686 | imsix_entries[i].handler, 0, imsix_entries[i].name, ha); | ||
1687 | if (ret) { | ||
1688 | qla_printk(KERN_WARNING, ha, | ||
1689 | "MSI-X: Unable to register handler -- %x/%d.\n", | ||
1690 | imsix_entries[i].index, ret); | ||
1691 | qla24xx_disable_msix(ha); | ||
1692 | goto msix_out; | ||
1693 | } | ||
1694 | qentry->have_irq = 1; | ||
1695 | } | ||
1696 | |||
1697 | msix_out: | ||
1698 | return ret; | ||
1699 | } | ||
1700 | |||
1701 | int | ||
1702 | qla2x00_request_irqs(scsi_qla_host_t *ha) | ||
1703 | { | ||
1704 | int ret; | ||
1705 | |||
1706 | /* If possible, enable MSI-X. */ | ||
1707 | if (!IS_QLA2432(ha)) | ||
1708 | goto skip_msix; | ||
1709 | |||
1710 | if (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX || | ||
1711 | !QLA_MSIX_FW_MODE_1(ha->fw_attributes)) { | ||
1712 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
1713 | "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n", | ||
1714 | ha->chip_revision, ha->fw_attributes)); | ||
1715 | |||
1716 | goto skip_msix; | ||
1717 | } | ||
1718 | |||
1719 | ret = qla24xx_enable_msix(ha); | ||
1720 | if (!ret) { | ||
1721 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
1722 | "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision, | ||
1723 | ha->fw_attributes)); | ||
1724 | return ret; | ||
1725 | } | ||
1726 | qla_printk(KERN_WARNING, ha, | ||
1727 | "MSI-X: Falling back-to INTa mode -- %d.\n", ret); | ||
1728 | skip_msix: | ||
1729 | ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler, | ||
1730 | IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); | ||
1731 | if (!ret) { | ||
1732 | ha->flags.inta_enabled = 1; | ||
1733 | ha->host->irq = ha->pdev->irq; | ||
1734 | } else { | ||
1735 | qla_printk(KERN_WARNING, ha, | ||
1736 | "Failed to reserve interrupt %d already in use.\n", | ||
1737 | ha->pdev->irq); | ||
1738 | } | ||
1739 | |||
1740 | return ret; | ||
1741 | } | ||
1742 | |||
1743 | void | ||
1744 | qla2x00_free_irqs(scsi_qla_host_t *ha) | ||
1745 | { | ||
1746 | |||
1747 | if (ha->flags.msix_enabled) | ||
1748 | qla24xx_disable_msix(ha); | ||
1749 | else if (ha->flags.inta_enabled) | ||
1750 | free_irq(ha->host->irq, ha); | ||
1751 | } | ||