diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2006-10-02 15:00:43 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-10-03 18:28:38 -0400 |
commit | d8b4521349274ab610d0b29384c704444e55cbca (patch) | |
tree | 5af421c4c6c262e966e2e3f37241b1cdb4fa199a /drivers/scsi/qla2xxx/qla_gs.c | |
parent | ee0ca6bab394fe41a2b4de58c4532b09a41c9165 (diff) |
[SCSI] qla2xxx: Add iIDMA support.
iIDMA (Intelligent Interleaved Direct Memory Access) allows for
the HBA hardware to send FC frames at the rate at which they can
be received by a target device. By taking advantage of the
higher link rate, the HBA can maximize bandwidth utilization in a
heterogeneous multi-speed SAN.
Within a fabric topology, port speed detection is done via a Name
Server command (GFPN_ID) followed by a Fabric Management command
(GPSC). In an FCAL/N2N topology, port speed is based on the HBA
link-rate.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_gs.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 187 |
1 files changed, 186 insertions, 1 deletions
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 2ebf259fccb2..029953c1a9c8 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c | |||
@@ -687,7 +687,6 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha) | |||
687 | return (rval); | 687 | return (rval); |
688 | } | 688 | } |
689 | 689 | ||
690 | |||
691 | /** | 690 | /** |
692 | * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query. | 691 | * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query. |
693 | * @ha: HA context | 692 | * @ha: HA context |
@@ -1647,3 +1646,189 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha) | |||
1647 | 1646 | ||
1648 | return rval; | 1647 | return rval; |
1649 | } | 1648 | } |
1649 | |||
1650 | /** | ||
1651 | * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query. | ||
1652 | * @ha: HA context | ||
1653 | * @list: switch info entries to populate | ||
1654 | * | ||
1655 | * Returns 0 on success. | ||
1656 | */ | ||
1657 | int | ||
1658 | qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list) | ||
1659 | { | ||
1660 | int rval; | ||
1661 | uint16_t i; | ||
1662 | |||
1663 | ms_iocb_entry_t *ms_pkt; | ||
1664 | struct ct_sns_req *ct_req; | ||
1665 | struct ct_sns_rsp *ct_rsp; | ||
1666 | |||
1667 | if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) | ||
1668 | return QLA_FUNCTION_FAILED; | ||
1669 | |||
1670 | for (i = 0; i < MAX_FIBRE_DEVICES; i++) { | ||
1671 | /* Issue GFPN_ID */ | ||
1672 | memset(list[i].fabric_port_name, 0, WWN_SIZE); | ||
1673 | |||
1674 | /* Prepare common MS IOCB */ | ||
1675 | ms_pkt = qla2x00_prep_ms_iocb(ha, GFPN_ID_REQ_SIZE, | ||
1676 | GFPN_ID_RSP_SIZE); | ||
1677 | |||
1678 | /* Prepare CT request */ | ||
1679 | ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD, | ||
1680 | GFPN_ID_RSP_SIZE); | ||
1681 | ct_rsp = &ha->ct_sns->p.rsp; | ||
1682 | |||
1683 | /* Prepare CT arguments -- port_id */ | ||
1684 | ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; | ||
1685 | ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; | ||
1686 | ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; | ||
1687 | |||
1688 | /* Execute MS IOCB */ | ||
1689 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
1690 | sizeof(ms_iocb_entry_t)); | ||
1691 | if (rval != QLA_SUCCESS) { | ||
1692 | /*EMPTY*/ | ||
1693 | DEBUG2_3(printk("scsi(%ld): GFPN_ID issue IOCB " | ||
1694 | "failed (%d).\n", ha->host_no, rval)); | ||
1695 | } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, | ||
1696 | "GFPN_ID") != QLA_SUCCESS) { | ||
1697 | rval = QLA_FUNCTION_FAILED; | ||
1698 | } else { | ||
1699 | /* Save fabric portname */ | ||
1700 | memcpy(list[i].fabric_port_name, | ||
1701 | ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE); | ||
1702 | } | ||
1703 | |||
1704 | /* Last device exit. */ | ||
1705 | if (list[i].d_id.b.rsvd_1 != 0) | ||
1706 | break; | ||
1707 | } | ||
1708 | |||
1709 | return (rval); | ||
1710 | } | ||
1711 | |||
1712 | static inline void * | ||
1713 | qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size, | ||
1714 | uint32_t rsp_size) | ||
1715 | { | ||
1716 | struct ct_entry_24xx *ct_pkt; | ||
1717 | |||
1718 | ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; | ||
1719 | memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); | ||
1720 | |||
1721 | ct_pkt->entry_type = CT_IOCB_TYPE; | ||
1722 | ct_pkt->entry_count = 1; | ||
1723 | ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); | ||
1724 | ct_pkt->timeout = __constant_cpu_to_le16(59); | ||
1725 | ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); | ||
1726 | ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); | ||
1727 | ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); | ||
1728 | ct_pkt->cmd_byte_count = cpu_to_le32(req_size); | ||
1729 | |||
1730 | ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); | ||
1731 | ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); | ||
1732 | ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; | ||
1733 | |||
1734 | ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); | ||
1735 | ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); | ||
1736 | ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; | ||
1737 | |||
1738 | return ct_pkt; | ||
1739 | } | ||
1740 | |||
1741 | |||
1742 | static inline struct ct_sns_req * | ||
1743 | qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd, | ||
1744 | uint16_t rsp_size) | ||
1745 | { | ||
1746 | memset(ct_req, 0, sizeof(struct ct_sns_pkt)); | ||
1747 | |||
1748 | ct_req->header.revision = 0x01; | ||
1749 | ct_req->header.gs_type = 0xFA; | ||
1750 | ct_req->header.gs_subtype = 0x01; | ||
1751 | ct_req->command = cpu_to_be16(cmd); | ||
1752 | ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); | ||
1753 | |||
1754 | return ct_req; | ||
1755 | } | ||
1756 | |||
1757 | /** | ||
1758 | * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query. | ||
1759 | * @ha: HA context | ||
1760 | * @list: switch info entries to populate | ||
1761 | * | ||
1762 | * Returns 0 on success. | ||
1763 | */ | ||
1764 | int | ||
1765 | qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list) | ||
1766 | { | ||
1767 | int rval; | ||
1768 | uint16_t i; | ||
1769 | |||
1770 | ms_iocb_entry_t *ms_pkt; | ||
1771 | struct ct_sns_req *ct_req; | ||
1772 | struct ct_sns_rsp *ct_rsp; | ||
1773 | |||
1774 | if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) | ||
1775 | return QLA_FUNCTION_FAILED; | ||
1776 | |||
1777 | rval = qla2x00_mgmt_svr_login(ha); | ||
1778 | if (rval) | ||
1779 | return rval; | ||
1780 | |||
1781 | for (i = 0; i < MAX_FIBRE_DEVICES; i++) { | ||
1782 | /* Issue GFPN_ID */ | ||
1783 | list[i].fp_speeds = list[i].fp_speed = 0; | ||
1784 | |||
1785 | /* Prepare common MS IOCB */ | ||
1786 | ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE, | ||
1787 | GPSC_RSP_SIZE); | ||
1788 | |||
1789 | /* Prepare CT request */ | ||
1790 | ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req, | ||
1791 | GPSC_CMD, GPSC_RSP_SIZE); | ||
1792 | ct_rsp = &ha->ct_sns->p.rsp; | ||
1793 | |||
1794 | /* Prepare CT arguments -- port_name */ | ||
1795 | memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name, | ||
1796 | WWN_SIZE); | ||
1797 | |||
1798 | /* Execute MS IOCB */ | ||
1799 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
1800 | sizeof(ms_iocb_entry_t)); | ||
1801 | if (rval != QLA_SUCCESS) { | ||
1802 | /*EMPTY*/ | ||
1803 | DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB " | ||
1804 | "failed (%d).\n", ha->host_no, rval)); | ||
1805 | } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, | ||
1806 | "GPSC") != QLA_SUCCESS) { | ||
1807 | rval = QLA_FUNCTION_FAILED; | ||
1808 | } else { | ||
1809 | /* Save portname */ | ||
1810 | list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds; | ||
1811 | list[i].fp_speed = ct_rsp->rsp.gpsc.speed; | ||
1812 | |||
1813 | DEBUG2_3(printk("scsi(%ld): GPSC ext entry - " | ||
1814 | "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x " | ||
1815 | "speed=%04x.\n", ha->host_no, | ||
1816 | list[i].fabric_port_name[0], | ||
1817 | list[i].fabric_port_name[1], | ||
1818 | list[i].fabric_port_name[2], | ||
1819 | list[i].fabric_port_name[3], | ||
1820 | list[i].fabric_port_name[4], | ||
1821 | list[i].fabric_port_name[5], | ||
1822 | list[i].fabric_port_name[6], | ||
1823 | list[i].fabric_port_name[7], | ||
1824 | be16_to_cpu(list[i].fp_speeds), | ||
1825 | be16_to_cpu(list[i].fp_speed))); | ||
1826 | } | ||
1827 | |||
1828 | /* Last device exit. */ | ||
1829 | if (list[i].d_id.b.rsvd_1 != 0) | ||
1830 | break; | ||
1831 | } | ||
1832 | |||
1833 | return (rval); | ||
1834 | } | ||