aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/cxgb3i/cxgb3i_offload.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/cxgb3i/cxgb3i_offload.c')
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_offload.c125
1 files changed, 80 insertions, 45 deletions
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index de3b3b614cca..c1d5be4adf9c 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -94,29 +94,30 @@ static int c3cn_get_port(struct s3_conn *c3cn, struct cxgb3i_sdev_data *cdata)
94 if (!cdata) 94 if (!cdata)
95 goto error_out; 95 goto error_out;
96 96
97 if (c3cn->saddr.sin_port != 0) { 97 if (c3cn->saddr.sin_port) {
98 idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; 98 cxgb3i_log_error("connect, sin_port NON-ZERO %u.\n",
99 if (idx < 0 || idx >= cxgb3_max_connect) 99 c3cn->saddr.sin_port);
100 return 0; 100 return -EADDRINUSE;
101 if (!test_and_set_bit(idx, cdata->sport_map))
102 return -EADDRINUSE;
103 } 101 }
104 102
105 /* the sport_map_next may not be accurate but that is okay, sport_map 103 spin_lock_bh(&cdata->lock);
106 should be */ 104 start = idx = cdata->sport_next;
107 start = idx = cdata->sport_map_next;
108 do { 105 do {
109 if (++idx >= cxgb3_max_connect) 106 if (++idx >= cxgb3_max_connect)
110 idx = 0; 107 idx = 0;
111 if (!(test_and_set_bit(idx, cdata->sport_map))) { 108 if (!cdata->sport_conn[idx]) {
112 c3cn->saddr.sin_port = htons(cxgb3_sport_base + idx); 109 c3cn->saddr.sin_port = htons(cxgb3_sport_base + idx);
113 cdata->sport_map_next = idx; 110 cdata->sport_next = idx;
111 cdata->sport_conn[idx] = c3cn;
112 spin_unlock_bh(&cdata->lock);
113
114 c3cn_conn_debug("%s reserve port %u.\n", 114 c3cn_conn_debug("%s reserve port %u.\n",
115 cdata->cdev->name, 115 cdata->cdev->name,
116 cxgb3_sport_base + idx); 116 cxgb3_sport_base + idx);
117 return 0; 117 return 0;
118 } 118 }
119 } while (idx != start); 119 } while (idx != start);
120 spin_unlock_bh(&cdata->lock);
120 121
121error_out: 122error_out:
122 return -EADDRNOTAVAIL; 123 return -EADDRNOTAVAIL;
@@ -124,15 +125,19 @@ error_out:
124 125
125static void c3cn_put_port(struct s3_conn *c3cn) 126static void c3cn_put_port(struct s3_conn *c3cn)
126{ 127{
127 struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev); 128 if (!c3cn->cdev)
129 return;
128 130
129 if (c3cn->saddr.sin_port) { 131 if (c3cn->saddr.sin_port) {
132 struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev);
130 int idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; 133 int idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base;
131 134
132 c3cn->saddr.sin_port = 0; 135 c3cn->saddr.sin_port = 0;
133 if (idx < 0 || idx >= cxgb3_max_connect) 136 if (idx < 0 || idx >= cxgb3_max_connect)
134 return; 137 return;
135 clear_bit(idx, cdata->sport_map); 138 spin_lock_bh(&cdata->lock);
139 cdata->sport_conn[idx] = NULL;
140 spin_unlock_bh(&cdata->lock);
136 c3cn_conn_debug("%s, release port %u.\n", 141 c3cn_conn_debug("%s, release port %u.\n",
137 cdata->cdev->name, cxgb3_sport_base + idx); 142 cdata->cdev->name, cxgb3_sport_base + idx);
138 } 143 }
@@ -1305,11 +1310,7 @@ static void c3cn_release_offload_resources(struct s3_conn *c3cn)
1305 struct t3cdev *cdev = c3cn->cdev; 1310 struct t3cdev *cdev = c3cn->cdev;
1306 unsigned int tid = c3cn->tid; 1311 unsigned int tid = c3cn->tid;
1307 1312
1308 if (!cdev)
1309 return;
1310
1311 c3cn->qset = 0; 1313 c3cn->qset = 0;
1312
1313 c3cn_free_cpl_skbs(c3cn); 1314 c3cn_free_cpl_skbs(c3cn);
1314 1315
1315 if (c3cn->wr_avail != c3cn->wr_max) { 1316 if (c3cn->wr_avail != c3cn->wr_max) {
@@ -1317,18 +1318,22 @@ static void c3cn_release_offload_resources(struct s3_conn *c3cn)
1317 reset_wr_list(c3cn); 1318 reset_wr_list(c3cn);
1318 } 1319 }
1319 1320
1320 if (c3cn->l2t) { 1321 if (cdev) {
1321 l2t_release(L2DATA(cdev), c3cn->l2t); 1322 if (c3cn->l2t) {
1322 c3cn->l2t = NULL; 1323 l2t_release(L2DATA(cdev), c3cn->l2t);
1323 } 1324 c3cn->l2t = NULL;
1324 1325 }
1325 if (c3cn->state == C3CN_STATE_CONNECTING) /* we have ATID */ 1326 if (c3cn->state == C3CN_STATE_CONNECTING)
1326 s3_free_atid(cdev, tid); 1327 /* we have ATID */
1327 else { /* we have TID */ 1328 s3_free_atid(cdev, tid);
1328 cxgb3_remove_tid(cdev, (void *)c3cn, tid); 1329 else {
1329 c3cn_put(c3cn); 1330 /* we have TID */
1331 cxgb3_remove_tid(cdev, (void *)c3cn, tid);
1332 c3cn_put(c3cn);
1333 }
1330 } 1334 }
1331 1335
1336 c3cn->dst_cache = NULL;
1332 c3cn->cdev = NULL; 1337 c3cn->cdev = NULL;
1333} 1338}
1334 1339
@@ -1425,10 +1430,10 @@ void cxgb3i_c3cn_release(struct s3_conn *c3cn)
1425{ 1430{
1426 c3cn_conn_debug("c3cn 0x%p, s %u, f 0x%lx.\n", 1431 c3cn_conn_debug("c3cn 0x%p, s %u, f 0x%lx.\n",
1427 c3cn, c3cn->state, c3cn->flags); 1432 c3cn, c3cn->state, c3cn->flags);
1428 if (likely(c3cn->state != C3CN_STATE_CONNECTING)) 1433 if (unlikely(c3cn->state == C3CN_STATE_CONNECTING))
1429 c3cn_active_close(c3cn);
1430 else
1431 c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED); 1434 c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED);
1435 else if (likely(c3cn->state != C3CN_STATE_CLOSED))
1436 c3cn_active_close(c3cn);
1432 c3cn_put(c3cn); 1437 c3cn_put(c3cn);
1433} 1438}
1434 1439
@@ -1474,12 +1479,13 @@ static struct net_device *cxgb3_egress_dev(struct net_device *root_dev,
1474 return NULL; 1479 return NULL;
1475} 1480}
1476 1481
1477static struct rtable *find_route(__be32 saddr, __be32 daddr, 1482static struct rtable *find_route(struct net_device *dev,
1483 __be32 saddr, __be32 daddr,
1478 __be16 sport, __be16 dport) 1484 __be16 sport, __be16 dport)
1479{ 1485{
1480 struct rtable *rt; 1486 struct rtable *rt;
1481 struct flowi fl = { 1487 struct flowi fl = {
1482 .oif = 0, 1488 .oif = dev ? dev->ifindex : 0,
1483 .nl_u = { 1489 .nl_u = {
1484 .ip4_u = { 1490 .ip4_u = {
1485 .daddr = daddr, 1491 .daddr = daddr,
@@ -1568,36 +1574,40 @@ out_err:
1568 * 1574 *
1569 * return 0 if active open request is sent, < 0 otherwise. 1575 * return 0 if active open request is sent, < 0 otherwise.
1570 */ 1576 */
1571int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin) 1577int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn,
1578 struct sockaddr_in *usin)
1572{ 1579{
1573 struct rtable *rt; 1580 struct rtable *rt;
1574 struct net_device *dev;
1575 struct cxgb3i_sdev_data *cdata; 1581 struct cxgb3i_sdev_data *cdata;
1576 struct t3cdev *cdev; 1582 struct t3cdev *cdev;
1577 __be32 sipv4; 1583 __be32 sipv4;
1578 int err; 1584 int err;
1579 1585
1586 c3cn_conn_debug("c3cn 0x%p, dev 0x%p.\n", c3cn, dev);
1587
1580 if (usin->sin_family != AF_INET) 1588 if (usin->sin_family != AF_INET)
1581 return -EAFNOSUPPORT; 1589 return -EAFNOSUPPORT;
1582 1590
1583 c3cn->daddr.sin_port = usin->sin_port; 1591 c3cn->daddr.sin_port = usin->sin_port;
1584 c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr; 1592 c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr;
1585 1593
1586 rt = find_route(c3cn->saddr.sin_addr.s_addr, 1594 rt = find_route(dev, c3cn->saddr.sin_addr.s_addr,
1587 c3cn->daddr.sin_addr.s_addr, 1595 c3cn->daddr.sin_addr.s_addr,
1588 c3cn->saddr.sin_port, 1596 c3cn->saddr.sin_port,
1589 c3cn->daddr.sin_port); 1597 c3cn->daddr.sin_port);
1590 if (rt == NULL) { 1598 if (rt == NULL) {
1591 c3cn_conn_debug("NO route to 0x%x, port %u.\n", 1599 c3cn_conn_debug("NO route to 0x%x, port %u, dev %s.\n",
1592 c3cn->daddr.sin_addr.s_addr, 1600 c3cn->daddr.sin_addr.s_addr,
1593 ntohs(c3cn->daddr.sin_port)); 1601 ntohs(c3cn->daddr.sin_port),
1602 dev ? dev->name : "any");
1594 return -ENETUNREACH; 1603 return -ENETUNREACH;
1595 } 1604 }
1596 1605
1597 if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { 1606 if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
1598 c3cn_conn_debug("multi-cast route to 0x%x, port %u.\n", 1607 c3cn_conn_debug("multi-cast route to 0x%x, port %u, dev %s.\n",
1599 c3cn->daddr.sin_addr.s_addr, 1608 c3cn->daddr.sin_addr.s_addr,
1600 ntohs(c3cn->daddr.sin_port)); 1609 ntohs(c3cn->daddr.sin_port),
1610 dev ? dev->name : "any");
1601 ip_rt_put(rt); 1611 ip_rt_put(rt);
1602 return -ENETUNREACH; 1612 return -ENETUNREACH;
1603 } 1613 }
@@ -1657,7 +1667,6 @@ int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin)
1657 c3cn_set_state(c3cn, C3CN_STATE_CLOSED); 1667 c3cn_set_state(c3cn, C3CN_STATE_CLOSED);
1658 ip_rt_put(rt); 1668 ip_rt_put(rt);
1659 c3cn_put_port(c3cn); 1669 c3cn_put_port(c3cn);
1660 c3cn->daddr.sin_port = 0;
1661 return err; 1670 return err;
1662} 1671}
1663 1672
@@ -1733,7 +1742,7 @@ int cxgb3i_c3cn_send_pdus(struct s3_conn *c3cn, struct sk_buff *skb)
1733 c3cn_tx_debug("c3cn 0x%p, snd %u - %u > %u.\n", 1742 c3cn_tx_debug("c3cn 0x%p, snd %u - %u > %u.\n",
1734 c3cn, c3cn->write_seq, c3cn->snd_una, 1743 c3cn, c3cn->write_seq, c3cn->snd_una,
1735 cxgb3_snd_win); 1744 cxgb3_snd_win);
1736 err = -EAGAIN; 1745 err = -ENOBUFS;
1737 goto out_err; 1746 goto out_err;
1738 } 1747 }
1739 1748
@@ -1771,16 +1780,33 @@ done:
1771out_err: 1780out_err:
1772 if (copied == 0 && err == -EPIPE) 1781 if (copied == 0 && err == -EPIPE)
1773 copied = c3cn->err ? c3cn->err : -EPIPE; 1782 copied = c3cn->err ? c3cn->err : -EPIPE;
1783 else
1784 copied = err;
1774 goto done; 1785 goto done;
1775} 1786}
1776 1787
1777static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata) 1788static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata)
1778{ 1789{
1779 struct adap_ports *ports = &cdata->ports; 1790 struct adap_ports *ports = &cdata->ports;
1791 struct s3_conn *c3cn;
1780 int i; 1792 int i;
1781 1793
1794 for (i = 0; i < cxgb3_max_connect; i++) {
1795 if (cdata->sport_conn[i]) {
1796 c3cn = cdata->sport_conn[i];
1797 cdata->sport_conn[i] = NULL;
1798
1799 spin_lock_bh(&c3cn->lock);
1800 c3cn->cdev = NULL;
1801 c3cn_set_flag(c3cn, C3CN_OFFLOAD_DOWN);
1802 c3cn_closed(c3cn);
1803 spin_unlock_bh(&c3cn->lock);
1804 }
1805 }
1806
1782 for (i = 0; i < ports->nports; i++) 1807 for (i = 0; i < ports->nports; i++)
1783 NDEV2CDATA(ports->lldevs[i]) = NULL; 1808 NDEV2CDATA(ports->lldevs[i]) = NULL;
1809
1784 cxgb3i_free_big_mem(cdata); 1810 cxgb3i_free_big_mem(cdata);
1785} 1811}
1786 1812
@@ -1822,21 +1848,27 @@ void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client)
1822 struct cxgb3i_sdev_data *cdata; 1848 struct cxgb3i_sdev_data *cdata;
1823 struct ofld_page_info rx_page_info; 1849 struct ofld_page_info rx_page_info;
1824 unsigned int wr_len; 1850 unsigned int wr_len;
1825 int mapsize = DIV_ROUND_UP(cxgb3_max_connect, 1851 int mapsize = cxgb3_max_connect * sizeof(struct s3_conn *);
1826 8 * sizeof(unsigned long));
1827 int i; 1852 int i;
1828 1853
1829 cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL); 1854 cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL);
1830 if (!cdata) 1855 if (!cdata) {
1856 cxgb3i_log_warn("t3dev 0x%p, offload up, OOM %d.\n",
1857 cdev, mapsize);
1831 return; 1858 return;
1859 }
1832 1860
1833 if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 || 1861 if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 ||
1834 cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 0 || 1862 cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 0 ||
1835 cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) 1863 cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) {
1864 cxgb3i_log_warn("t3dev 0x%p, offload up, ioctl failed.\n",
1865 cdev);
1836 goto free_cdata; 1866 goto free_cdata;
1867 }
1837 1868
1838 s3_init_wr_tab(wr_len); 1869 s3_init_wr_tab(wr_len);
1839 1870
1871 spin_lock_init(&cdata->lock);
1840 INIT_LIST_HEAD(&cdata->list); 1872 INIT_LIST_HEAD(&cdata->list);
1841 cdata->cdev = cdev; 1873 cdata->cdev = cdev;
1842 cdata->client = client; 1874 cdata->client = client;
@@ -1848,6 +1880,7 @@ void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client)
1848 list_add_tail(&cdata->list, &cdata_list); 1880 list_add_tail(&cdata->list, &cdata_list);
1849 write_unlock(&cdata_rwlock); 1881 write_unlock(&cdata_rwlock);
1850 1882
1883 cxgb3i_log_info("t3dev 0x%p, offload up, added.\n", cdev);
1851 return; 1884 return;
1852 1885
1853free_cdata: 1886free_cdata:
@@ -1862,6 +1895,8 @@ void cxgb3i_sdev_remove(struct t3cdev *cdev)
1862{ 1895{
1863 struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); 1896 struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev);
1864 1897
1898 cxgb3i_log_info("t3dev 0x%p, offload down, remove.\n", cdev);
1899
1865 write_lock(&cdata_rwlock); 1900 write_lock(&cdata_rwlock);
1866 list_del(&cdata->list); 1901 list_del(&cdata->list);
1867 write_unlock(&cdata_rwlock); 1902 write_unlock(&cdata_rwlock);