diff options
Diffstat (limited to 'drivers/scsi/cxgb3i/cxgb3i_offload.c')
| -rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_offload.c | 125 |
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 | ||
| 121 | error_out: | 122 | error_out: |
| 122 | return -EADDRNOTAVAIL; | 123 | return -EADDRNOTAVAIL; |
| @@ -124,15 +125,19 @@ error_out: | |||
| 124 | 125 | ||
| 125 | static void c3cn_put_port(struct s3_conn *c3cn) | 126 | static 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 | ||
| 1477 | static struct rtable *find_route(__be32 saddr, __be32 daddr, | 1482 | static 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 | */ |
| 1571 | int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin) | 1577 | int 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: | |||
| 1771 | out_err: | 1780 | out_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 | ||
| 1777 | static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata) | 1788 | static 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 | ||
| 1853 | free_cdata: | 1886 | free_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); |
