aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_gs.c
diff options
context:
space:
mode:
authorAndrew Vasquez <andrew.vasquez@qlogic.com>2006-10-02 15:00:43 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-10-03 18:28:38 -0400
commitd8b4521349274ab610d0b29384c704444e55cbca (patch)
tree5af421c4c6c262e966e2e3f37241b1cdb4fa199a /drivers/scsi/qla2xxx/qla_gs.c
parentee0ca6bab394fe41a2b4de58c4532b09a41c9165 (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.c187
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 */
1657int
1658qla2x00_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
1712static inline void *
1713qla24xx_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
1742static inline struct ct_sns_req *
1743qla24xx_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 */
1764int
1765qla2x00_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}