diff options
author | Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> | 2011-06-21 22:52:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-06-24 04:17:07 -0400 |
commit | 22c8c9343258feda9ea9ebb9e5f8cbb727b69454 (patch) | |
tree | fac14dcf287c032ff83c832a253178b90a2228b3 /drivers/net/qlcnic/qlcnic_init.c | |
parent | 9d6a6440fe30132e4d1f1aadd099345ced9178fb (diff) |
qlcnic: multi protocol internal loopback support added.
Driver will generate loopback traffic pattern and do the test. And
returns result of the test to application.
Updated driver version to 5.0.19.
Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlcnic/qlcnic_init.c')
-rw-r--r-- | drivers/net/qlcnic/qlcnic_init.c | 126 |
1 files changed, 124 insertions, 2 deletions
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 5b8bbcf904d5..9d5bee03a587 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c | |||
@@ -1281,6 +1281,7 @@ qlcnic_handle_linkevent(struct qlcnic_adapter *adapter, | |||
1281 | u16 cable_len; | 1281 | u16 cable_len; |
1282 | u16 link_speed; | 1282 | u16 link_speed; |
1283 | u8 link_status, module, duplex, autoneg; | 1283 | u8 link_status, module, duplex, autoneg; |
1284 | u8 lb_status = 0; | ||
1284 | struct net_device *netdev = adapter->netdev; | 1285 | struct net_device *netdev = adapter->netdev; |
1285 | 1286 | ||
1286 | adapter->has_link_events = 1; | 1287 | adapter->has_link_events = 1; |
@@ -1292,6 +1293,7 @@ qlcnic_handle_linkevent(struct qlcnic_adapter *adapter, | |||
1292 | link_status = msg->body[2] & 0xff; | 1293 | link_status = msg->body[2] & 0xff; |
1293 | duplex = (msg->body[2] >> 16) & 0xff; | 1294 | duplex = (msg->body[2] >> 16) & 0xff; |
1294 | autoneg = (msg->body[2] >> 24) & 0xff; | 1295 | autoneg = (msg->body[2] >> 24) & 0xff; |
1296 | lb_status = (msg->body[2] >> 32) & 0x3; | ||
1295 | 1297 | ||
1296 | module = (msg->body[2] >> 8) & 0xff; | 1298 | module = (msg->body[2] >> 8) & 0xff; |
1297 | if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE) | 1299 | if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE) |
@@ -1301,6 +1303,9 @@ qlcnic_handle_linkevent(struct qlcnic_adapter *adapter, | |||
1301 | dev_info(&netdev->dev, "unsupported cable length %d\n", | 1303 | dev_info(&netdev->dev, "unsupported cable length %d\n", |
1302 | cable_len); | 1304 | cable_len); |
1303 | 1305 | ||
1306 | if (!link_status && (lb_status == 1)) | ||
1307 | adapter->ahw->loopback_state |= QLCNIC_LINKEVENT; | ||
1308 | |||
1304 | qlcnic_advert_link_change(adapter, link_status); | 1309 | qlcnic_advert_link_change(adapter, link_status); |
1305 | 1310 | ||
1306 | if (duplex == LINKEVENT_FULL_DUPLEX) | 1311 | if (duplex == LINKEVENT_FULL_DUPLEX) |
@@ -1319,7 +1324,9 @@ qlcnic_handle_fw_message(int desc_cnt, int index, | |||
1319 | { | 1324 | { |
1320 | struct qlcnic_fw_msg msg; | 1325 | struct qlcnic_fw_msg msg; |
1321 | struct status_desc *desc; | 1326 | struct status_desc *desc; |
1322 | int i = 0, opcode; | 1327 | struct qlcnic_adapter *adapter; |
1328 | struct device *dev; | ||
1329 | int i = 0, opcode, ret; | ||
1323 | 1330 | ||
1324 | while (desc_cnt > 0 && i < 8) { | 1331 | while (desc_cnt > 0 && i < 8) { |
1325 | desc = &sds_ring->desc_head[index]; | 1332 | desc = &sds_ring->desc_head[index]; |
@@ -1330,10 +1337,28 @@ qlcnic_handle_fw_message(int desc_cnt, int index, | |||
1330 | desc_cnt--; | 1337 | desc_cnt--; |
1331 | } | 1338 | } |
1332 | 1339 | ||
1340 | adapter = sds_ring->adapter; | ||
1341 | dev = &adapter->pdev->dev; | ||
1333 | opcode = qlcnic_get_nic_msg_opcode(msg.body[0]); | 1342 | opcode = qlcnic_get_nic_msg_opcode(msg.body[0]); |
1343 | |||
1334 | switch (opcode) { | 1344 | switch (opcode) { |
1335 | case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE: | 1345 | case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE: |
1336 | qlcnic_handle_linkevent(sds_ring->adapter, &msg); | 1346 | qlcnic_handle_linkevent(adapter, &msg); |
1347 | break; | ||
1348 | case QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK: | ||
1349 | ret = (u32)(msg.body[1]); | ||
1350 | switch (ret) { | ||
1351 | case 0: | ||
1352 | adapter->ahw->loopback_state |= QLCNIC_LB_RESPONSE; | ||
1353 | break; | ||
1354 | case 1: | ||
1355 | dev_info(dev, "loopback already in progress\n"); | ||
1356 | break; | ||
1357 | default: | ||
1358 | dev_info(dev, "loopback configure request failed," | ||
1359 | " ret %x\n", ret); | ||
1360 | break; | ||
1361 | } | ||
1337 | break; | 1362 | break; |
1338 | default: | 1363 | default: |
1339 | break; | 1364 | break; |
@@ -1746,6 +1771,103 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, | |||
1746 | spin_unlock(&rds_ring->lock); | 1771 | spin_unlock(&rds_ring->lock); |
1747 | } | 1772 | } |
1748 | 1773 | ||
1774 | static void dump_skb(struct sk_buff *skb) | ||
1775 | { | ||
1776 | int i; | ||
1777 | unsigned char *data = skb->data; | ||
1778 | |||
1779 | printk(KERN_INFO "\n"); | ||
1780 | for (i = 0; i < skb->len; i++) { | ||
1781 | printk(KERN_INFO "%02x ", data[i]); | ||
1782 | if ((i & 0x0f) == 8) | ||
1783 | printk(KERN_INFO "\n"); | ||
1784 | } | ||
1785 | } | ||
1786 | |||
1787 | void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, | ||
1788 | struct qlcnic_host_sds_ring *sds_ring, | ||
1789 | int ring, u64 sts_data0) | ||
1790 | { | ||
1791 | struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; | ||
1792 | struct sk_buff *skb; | ||
1793 | struct qlcnic_host_rds_ring *rds_ring; | ||
1794 | int index, length, cksum, pkt_offset; | ||
1795 | |||
1796 | if (unlikely(ring >= adapter->max_rds_rings)) | ||
1797 | return; | ||
1798 | |||
1799 | rds_ring = &recv_ctx->rds_rings[ring]; | ||
1800 | |||
1801 | index = qlcnic_get_sts_refhandle(sts_data0); | ||
1802 | length = qlcnic_get_sts_totallength(sts_data0); | ||
1803 | if (unlikely(index >= rds_ring->num_desc)) | ||
1804 | return; | ||
1805 | |||
1806 | cksum = qlcnic_get_sts_status(sts_data0); | ||
1807 | pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0); | ||
1808 | |||
1809 | skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum); | ||
1810 | if (!skb) | ||
1811 | return; | ||
1812 | |||
1813 | if (length > rds_ring->skb_size) | ||
1814 | skb_put(skb, rds_ring->skb_size); | ||
1815 | else | ||
1816 | skb_put(skb, length); | ||
1817 | |||
1818 | if (pkt_offset) | ||
1819 | skb_pull(skb, pkt_offset); | ||
1820 | |||
1821 | if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr)) | ||
1822 | adapter->diag_cnt++; | ||
1823 | else | ||
1824 | dump_skb(skb); | ||
1825 | |||
1826 | dev_kfree_skb_any(skb); | ||
1827 | adapter->stats.rx_pkts++; | ||
1828 | adapter->stats.rxbytes += length; | ||
1829 | |||
1830 | return; | ||
1831 | } | ||
1832 | |||
1833 | void | ||
1834 | qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring) | ||
1835 | { | ||
1836 | struct qlcnic_adapter *adapter = sds_ring->adapter; | ||
1837 | struct status_desc *desc; | ||
1838 | u64 sts_data0; | ||
1839 | int ring, opcode, desc_cnt; | ||
1840 | |||
1841 | u32 consumer = sds_ring->consumer; | ||
1842 | |||
1843 | desc = &sds_ring->desc_head[consumer]; | ||
1844 | sts_data0 = le64_to_cpu(desc->status_desc_data[0]); | ||
1845 | |||
1846 | if (!(sts_data0 & STATUS_OWNER_HOST)) | ||
1847 | return; | ||
1848 | |||
1849 | desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0); | ||
1850 | opcode = qlcnic_get_sts_opcode(sts_data0); | ||
1851 | switch (opcode) { | ||
1852 | case QLCNIC_RESPONSE_DESC: | ||
1853 | qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring); | ||
1854 | break; | ||
1855 | default: | ||
1856 | ring = qlcnic_get_sts_type(sts_data0); | ||
1857 | qlcnic_process_rcv_diag(adapter, sds_ring, ring, sts_data0); | ||
1858 | break; | ||
1859 | } | ||
1860 | |||
1861 | for (; desc_cnt > 0; desc_cnt--) { | ||
1862 | desc = &sds_ring->desc_head[consumer]; | ||
1863 | desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM); | ||
1864 | consumer = get_next_index(consumer, sds_ring->num_desc); | ||
1865 | } | ||
1866 | |||
1867 | sds_ring->consumer = consumer; | ||
1868 | writel(consumer, sds_ring->crb_sts_consumer); | ||
1869 | } | ||
1870 | |||
1749 | void | 1871 | void |
1750 | qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2, | 1872 | qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2, |
1751 | u8 alt_mac, u8 *mac) | 1873 | u8 alt_mac, u8 *mac) |