aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorAndrew Vasquez <andrew.vasquez@qlogic.com>2007-01-29 13:22:19 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-01-31 12:05:20 -0500
commita8488abefaa863a0c3a19888f03395adb3f1c6d2 (patch)
treed26c038c2a72231490db6c6e4ef9ea5d7f03862c /drivers/scsi
parent3c6061236801a376d86ca75fd56d61f964611dd5 (diff)
[SCSI] qla2xxx: Add MSI-X support.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h24
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h3
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c215
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c14
5 files changed, 247 insertions, 11 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index c4fc40f8e8ca..8d7e8cb1e703 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2046,6 +2046,27 @@ struct isp_operations {
2046 uint32_t); 2046 uint32_t);
2047}; 2047};
2048 2048
2049/* MSI-X Support *************************************************************/
2050
2051#define QLA_MSIX_CHIP_REV_24XX 3
2052#define QLA_MSIX_FW_MODE(m) (((m) & (BIT_7|BIT_8|BIT_9)) >> 7)
2053#define QLA_MSIX_FW_MODE_1(m) (QLA_MSIX_FW_MODE(m) == 1)
2054
2055#define QLA_MSIX_DEFAULT 0x00
2056#define QLA_MSIX_RSP_Q 0x01
2057
2058#define QLA_MSIX_ENTRIES 2
2059#define QLA_MIDX_DEFAULT 0
2060#define QLA_MIDX_RSP_Q 1
2061
2062struct scsi_qla_host;
2063
2064struct qla_msix_entry {
2065 int have_irq;
2066 uint16_t msix_vector;
2067 uint16_t msix_entry;
2068};
2069
2049/* 2070/*
2050 * Linux Host Adapter structure 2071 * Linux Host Adapter structure
2051 */ 2072 */
@@ -2356,6 +2377,7 @@ typedef struct scsi_qla_host {
2356 2377
2357 uint8_t host_str[16]; 2378 uint8_t host_str[16];
2358 uint32_t pci_attr; 2379 uint32_t pci_attr;
2380 uint16_t chip_revision;
2359 2381
2360 uint16_t product_id[4]; 2382 uint16_t product_id[4];
2361 2383
@@ -2389,6 +2411,8 @@ typedef struct scsi_qla_host {
2389 uint16_t zio_mode; 2411 uint16_t zio_mode;
2390 uint16_t zio_timer; 2412 uint16_t zio_timer;
2391 struct fc_host_statistics fc_host_stat; 2413 struct fc_host_statistics fc_host_stat;
2414
2415 struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES];
2392} scsi_qla_host_t; 2416} scsi_qla_host_t;
2393 2417
2394 2418
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 32ebeec45ff0..e6ca2bc9a28d 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -225,6 +225,9 @@ extern irqreturn_t qla24xx_intr_handler(int, void *);
225extern void qla2x00_process_response_queue(struct scsi_qla_host *); 225extern void qla2x00_process_response_queue(struct scsi_qla_host *);
226extern void qla24xx_process_response_queue(struct scsi_qla_host *); 226extern void qla24xx_process_response_queue(struct scsi_qla_host *);
227 227
228extern int qla2x00_request_irqs(scsi_qla_host_t *);
229extern void qla2x00_free_irqs(scsi_qla_host_t *);
230
228/* 231/*
229 * Global Function Prototypes in qla_sup.c source file. 232 * Global Function Prototypes in qla_sup.c source file.
230 */ 233 */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index a823f0bc519d..b6f0494e034c 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -293,6 +293,8 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
293 d &= ~PCI_ROM_ADDRESS_ENABLE; 293 d &= ~PCI_ROM_ADDRESS_ENABLE;
294 pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); 294 pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
295 295
296 pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision);
297
296 /* Get PCI bus information. */ 298 /* Get PCI bus information. */
297 spin_lock_irqsave(&ha->hardware_lock, flags); 299 spin_lock_irqsave(&ha->hardware_lock, flags);
298 ha->pci_attr = RD_REG_DWORD(&reg->ctrl_status); 300 ha->pci_attr = RD_REG_DWORD(&reg->ctrl_status);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index b95fcb2c065e..e883b5fc3b08 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1529,3 +1529,218 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt)
1529 qla2x00_sp_compl(ha, sp); 1529 qla2x00_sp_compl(ha, sp);
1530} 1530}
1531 1531
1532static irqreturn_t
1533qla24xx_msix_rsp_q(int irq, void *dev_id)
1534{
1535 scsi_qla_host_t *ha;
1536 struct device_reg_24xx __iomem *reg;
1537 unsigned long flags;
1538
1539 ha = dev_id;
1540 reg = &ha->iobase->isp24;
1541
1542 spin_lock_irqsave(&ha->hardware_lock, flags);
1543
1544 qla24xx_process_response_queue(ha);
1545
1546 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
1547 RD_REG_DWORD_RELAXED(&reg->hccr);
1548
1549 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1550
1551 return IRQ_HANDLED;
1552}
1553
1554static irqreturn_t
1555qla24xx_msix_default(int irq, void *dev_id)
1556{
1557 scsi_qla_host_t *ha;
1558 struct device_reg_24xx __iomem *reg;
1559 int status;
1560 unsigned long flags;
1561 unsigned long iter;
1562 uint32_t stat;
1563 uint32_t hccr;
1564 uint16_t mb[4];
1565
1566 ha = dev_id;
1567 reg = &ha->iobase->isp24;
1568 status = 0;
1569
1570 spin_lock_irqsave(&ha->hardware_lock, flags);
1571 for (iter = 50; iter--; ) {
1572 stat = RD_REG_DWORD(&reg->host_status);
1573 if (stat & HSRX_RISC_PAUSED) {
1574 hccr = RD_REG_DWORD(&reg->hccr);
1575
1576 qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
1577 "Dumping firmware!\n", hccr);
1578 ha->isp_ops.fw_dump(ha, 1);
1579 set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
1580 break;
1581 } else if ((stat & HSRX_RISC_INT) == 0)
1582 break;
1583
1584 switch (stat & 0xff) {
1585 case 0x1:
1586 case 0x2:
1587 case 0x10:
1588 case 0x11:
1589 qla24xx_mbx_completion(ha, MSW(stat));
1590 status |= MBX_INTERRUPT;
1591
1592 break;
1593 case 0x12:
1594 mb[0] = MSW(stat);
1595 mb[1] = RD_REG_WORD(&reg->mailbox1);
1596 mb[2] = RD_REG_WORD(&reg->mailbox2);
1597 mb[3] = RD_REG_WORD(&reg->mailbox3);
1598 qla2x00_async_event(ha, mb);
1599 break;
1600 case 0x13:
1601 qla24xx_process_response_queue(ha);
1602 break;
1603 default:
1604 DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
1605 "(%d).\n",
1606 ha->host_no, stat & 0xff));
1607 break;
1608 }
1609 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
1610 RD_REG_DWORD_RELAXED(&reg->hccr);
1611 }
1612 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1613
1614 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
1615 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
1616 spin_lock_irqsave(&ha->mbx_reg_lock, flags);
1617
1618 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
1619 up(&ha->mbx_intr_sem);
1620
1621 spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
1622 }
1623
1624 return IRQ_HANDLED;
1625}
1626
1627/* Interrupt handling helpers. */
1628
1629struct qla_init_msix_entry {
1630 uint16_t entry;
1631 uint16_t index;
1632 const char *name;
1633 irqreturn_t (*handler)(int, void *);
1634};
1635
1636static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = {
1637 { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT,
1638 "qla2xxx (default)", qla24xx_msix_default },
1639
1640 { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q,
1641 "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
1642};
1643
1644static void
1645qla24xx_disable_msix(scsi_qla_host_t *ha)
1646{
1647 int i;
1648 struct qla_msix_entry *qentry;
1649
1650 for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
1651 qentry = &ha->msix_entries[imsix_entries[i].index];
1652 if (qentry->have_irq)
1653 free_irq(qentry->msix_vector, ha);
1654 }
1655 pci_disable_msix(ha->pdev);
1656}
1657
1658static int
1659qla24xx_enable_msix(scsi_qla_host_t *ha)
1660{
1661 int i, ret;
1662 struct msix_entry entries[QLA_MSIX_ENTRIES];
1663 struct qla_msix_entry *qentry;
1664
1665 for (i = 0; i < QLA_MSIX_ENTRIES; i++)
1666 entries[i].entry = imsix_entries[i].entry;
1667
1668 ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries));
1669 if (ret) {
1670 qla_printk(KERN_WARNING, ha,
1671 "MSI-X: Failed to enable support -- %d/%d\n",
1672 QLA_MSIX_ENTRIES, ret);
1673 goto msix_out;
1674 }
1675 ha->flags.msix_enabled = 1;
1676
1677 for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
1678 qentry = &ha->msix_entries[imsix_entries[i].index];
1679 qentry->msix_vector = entries[i].vector;
1680 qentry->msix_entry = entries[i].entry;
1681 qentry->have_irq = 0;
1682 ret = request_irq(qentry->msix_vector,
1683 imsix_entries[i].handler, 0, imsix_entries[i].name, ha);
1684 if (ret) {
1685 qla_printk(KERN_WARNING, ha,
1686 "MSI-X: Unable to register handler -- %x/%d.\n",
1687 imsix_entries[i].index, ret);
1688 qla24xx_disable_msix(ha);
1689 goto msix_out;
1690 }
1691 qentry->have_irq = 1;
1692 }
1693
1694msix_out:
1695 return ret;
1696}
1697
1698int
1699qla2x00_request_irqs(scsi_qla_host_t *ha)
1700{
1701 int ret;
1702
1703 /* If possible, enable MSI-X. */
1704 if (!IS_QLA2432(ha))
1705 goto skip_msix;
1706
1707 if (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
1708 !QLA_MSIX_FW_MODE_1(ha->fw_attributes)) {
1709 DEBUG2(qla_printk(KERN_WARNING, ha,
1710 "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
1711 ha->chip_revision, ha->fw_attributes));
1712
1713 goto skip_msix;
1714 }
1715
1716 ret = qla24xx_enable_msix(ha);
1717 if (!ret) {
1718 DEBUG2(qla_printk(KERN_INFO, ha,
1719 "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
1720 ha->fw_attributes));
1721 return ret;
1722 }
1723 qla_printk(KERN_WARNING, ha,
1724 "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
1725skip_msix:
1726 ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler,
1727 IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
1728 if (ret) {
1729 qla_printk(KERN_WARNING, ha,
1730 "Failed to reserve interrupt %d already in use.\n",
1731 ha->pdev->irq);
1732 }
1733 ha->host->irq = ha->pdev->irq;
1734
1735 return ret;
1736}
1737
1738void
1739qla2x00_free_irqs(scsi_qla_host_t *ha)
1740{
1741
1742 if (ha->flags.msix_enabled)
1743 qla24xx_disable_msix(ha);
1744 else if (ha->host->irq)
1745 free_irq(ha->host->irq, ha);
1746}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index d03523d3bf38..2bd70bb82aab 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1612,15 +1612,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
1612 host->max_lun = MAX_LUNS; 1612 host->max_lun = MAX_LUNS;
1613 host->transportt = qla2xxx_transport_template; 1613 host->transportt = qla2xxx_transport_template;
1614 1614
1615 ret = request_irq(pdev->irq, ha->isp_ops.intr_handler, 1615 ret = qla2x00_request_irqs(ha);
1616 IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); 1616 if (ret)
1617 if (ret) {
1618 qla_printk(KERN_WARNING, ha,
1619 "Failed to reserve interrupt %d already in use.\n",
1620 pdev->irq);
1621 goto probe_failed; 1617 goto probe_failed;
1622 }
1623 host->irq = pdev->irq;
1624 1618
1625 /* Initialized the timer */ 1619 /* Initialized the timer */
1626 qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL); 1620 qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL);
@@ -1750,9 +1744,7 @@ qla2x00_free_device(scsi_qla_host_t *ha)
1750 1744
1751 qla2x00_mem_free(ha); 1745 qla2x00_mem_free(ha);
1752 1746
1753 /* Detach interrupts */ 1747 qla2x00_free_irqs(ha);
1754 if (ha->host->irq)
1755 free_irq(ha->host->irq, ha);
1756 1748
1757 /* release io space registers */ 1749 /* release io space registers */
1758 if (ha->iobase) 1750 if (ha->iobase)