diff options
author | Karen Xie <kxie@chelsio.com> | 2009-04-01 14:11:26 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-04-03 10:23:12 -0400 |
commit | 2a90030fcb827afa16914e57ac587e683280ae4a (patch) | |
tree | 269dafd0da1fc251c16341c6943095b637e148ec /drivers/scsi/cxgb3i | |
parent | ed6f7744f90a0efc6874f2ab93e4e593741079c9 (diff) |
[SCSI] cxgb3i: close all tcp connections upon chip reset
Keep track of offloaded tcp connections per adapter. Close all of the
connections upon reset.
Signed-off-by: Karen Xie <kxie@chelsio.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/cxgb3i')
-rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_offload.c | 101 | ||||
-rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_offload.h | 11 |
2 files changed, 71 insertions, 41 deletions
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c index c2e434e54e28..4d8654cdbdae 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 | ||
@@ -1417,17 +1422,18 @@ static void c3cn_active_close(struct s3_conn *c3cn) | |||
1417 | } | 1422 | } |
1418 | 1423 | ||
1419 | /** | 1424 | /** |
1420 | * cxgb3i_c3cn_release - close and release an iscsi tcp connection | 1425 | * cxgb3i_c3cn_release - close and release an iscsi tcp connection and any |
1426 | * resource held | ||
1421 | * @c3cn: the iscsi tcp connection | 1427 | * @c3cn: the iscsi tcp connection |
1422 | */ | 1428 | */ |
1423 | void cxgb3i_c3cn_release(struct s3_conn *c3cn) | 1429 | void cxgb3i_c3cn_release(struct s3_conn *c3cn) |
1424 | { | 1430 | { |
1425 | 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", |
1426 | c3cn, c3cn->state, c3cn->flags); | 1432 | c3cn, c3cn->state, c3cn->flags); |
1427 | if (likely(c3cn->state != C3CN_STATE_CONNECTING)) | 1433 | if (unlikely(c3cn->state == C3CN_STATE_CONNECTING)) |
1428 | c3cn_active_close(c3cn); | ||
1429 | else | ||
1430 | 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); | ||
1431 | c3cn_put(c3cn); | 1437 | c3cn_put(c3cn); |
1432 | } | 1438 | } |
1433 | 1439 | ||
@@ -1656,7 +1662,6 @@ int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin) | |||
1656 | c3cn_set_state(c3cn, C3CN_STATE_CLOSED); | 1662 | c3cn_set_state(c3cn, C3CN_STATE_CLOSED); |
1657 | ip_rt_put(rt); | 1663 | ip_rt_put(rt); |
1658 | c3cn_put_port(c3cn); | 1664 | c3cn_put_port(c3cn); |
1659 | c3cn->daddr.sin_port = 0; | ||
1660 | return err; | 1665 | return err; |
1661 | } | 1666 | } |
1662 | 1667 | ||
@@ -1776,10 +1781,25 @@ out_err: | |||
1776 | static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata) | 1781 | static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata) |
1777 | { | 1782 | { |
1778 | struct adap_ports *ports = &cdata->ports; | 1783 | struct adap_ports *ports = &cdata->ports; |
1784 | struct s3_conn *c3cn; | ||
1779 | int i; | 1785 | int i; |
1780 | 1786 | ||
1787 | for (i = 0; i < cxgb3_max_connect; i++) { | ||
1788 | if (cdata->sport_conn[i]) { | ||
1789 | c3cn = cdata->sport_conn[i]; | ||
1790 | cdata->sport_conn[i] = NULL; | ||
1791 | |||
1792 | spin_lock_bh(&c3cn->lock); | ||
1793 | c3cn->cdev = NULL; | ||
1794 | c3cn_set_flag(c3cn, C3CN_OFFLOAD_DOWN); | ||
1795 | c3cn_closed(c3cn); | ||
1796 | spin_unlock_bh(&c3cn->lock); | ||
1797 | } | ||
1798 | } | ||
1799 | |||
1781 | for (i = 0; i < ports->nports; i++) | 1800 | for (i = 0; i < ports->nports; i++) |
1782 | NDEV2CDATA(ports->lldevs[i]) = NULL; | 1801 | NDEV2CDATA(ports->lldevs[i]) = NULL; |
1802 | |||
1783 | cxgb3i_free_big_mem(cdata); | 1803 | cxgb3i_free_big_mem(cdata); |
1784 | } | 1804 | } |
1785 | 1805 | ||
@@ -1821,21 +1841,27 @@ void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client) | |||
1821 | struct cxgb3i_sdev_data *cdata; | 1841 | struct cxgb3i_sdev_data *cdata; |
1822 | struct ofld_page_info rx_page_info; | 1842 | struct ofld_page_info rx_page_info; |
1823 | unsigned int wr_len; | 1843 | unsigned int wr_len; |
1824 | int mapsize = DIV_ROUND_UP(cxgb3_max_connect, | 1844 | int mapsize = cxgb3_max_connect * sizeof(struct s3_conn *); |
1825 | 8 * sizeof(unsigned long)); | ||
1826 | int i; | 1845 | int i; |
1827 | 1846 | ||
1828 | cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL); | 1847 | cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL); |
1829 | if (!cdata) | 1848 | if (!cdata) { |
1849 | cxgb3i_log_warn("t3dev 0x%p, offload up, OOM %d.\n", | ||
1850 | cdev, mapsize); | ||
1830 | return; | 1851 | return; |
1852 | } | ||
1831 | 1853 | ||
1832 | if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 || | 1854 | if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 || |
1833 | cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 0 || | 1855 | cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 0 || |
1834 | cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) | 1856 | cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) { |
1857 | cxgb3i_log_warn("t3dev 0x%p, offload up, ioctl failed.\n", | ||
1858 | cdev); | ||
1835 | goto free_cdata; | 1859 | goto free_cdata; |
1860 | } | ||
1836 | 1861 | ||
1837 | s3_init_wr_tab(wr_len); | 1862 | s3_init_wr_tab(wr_len); |
1838 | 1863 | ||
1864 | spin_lock_init(&cdata->lock); | ||
1839 | INIT_LIST_HEAD(&cdata->list); | 1865 | INIT_LIST_HEAD(&cdata->list); |
1840 | cdata->cdev = cdev; | 1866 | cdata->cdev = cdev; |
1841 | cdata->client = client; | 1867 | cdata->client = client; |
@@ -1847,6 +1873,7 @@ void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client) | |||
1847 | list_add_tail(&cdata->list, &cdata_list); | 1873 | list_add_tail(&cdata->list, &cdata_list); |
1848 | write_unlock(&cdata_rwlock); | 1874 | write_unlock(&cdata_rwlock); |
1849 | 1875 | ||
1876 | cxgb3i_log_info("t3dev 0x%p, offload up, added.\n", cdev); | ||
1850 | return; | 1877 | return; |
1851 | 1878 | ||
1852 | free_cdata: | 1879 | free_cdata: |
@@ -1861,6 +1888,8 @@ void cxgb3i_sdev_remove(struct t3cdev *cdev) | |||
1861 | { | 1888 | { |
1862 | struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); | 1889 | struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); |
1863 | 1890 | ||
1891 | cxgb3i_log_info("t3dev 0x%p, offload down, remove.\n", cdev); | ||
1892 | |||
1864 | write_lock(&cdata_rwlock); | 1893 | write_lock(&cdata_rwlock); |
1865 | list_del(&cdata->list); | 1894 | list_del(&cdata->list); |
1866 | write_unlock(&cdata_rwlock); | 1895 | write_unlock(&cdata_rwlock); |
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.h b/drivers/scsi/cxgb3i/cxgb3i_offload.h index 275f23f16eb7..dab759d67bec 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_offload.h +++ b/drivers/scsi/cxgb3i/cxgb3i_offload.h | |||
@@ -135,11 +135,11 @@ enum c3cn_flags { | |||
135 | C3CN_ABORT_RPL_PENDING, /* expecting an abort reply */ | 135 | C3CN_ABORT_RPL_PENDING, /* expecting an abort reply */ |
136 | C3CN_TX_DATA_SENT, /* already sent a TX_DATA WR */ | 136 | C3CN_TX_DATA_SENT, /* already sent a TX_DATA WR */ |
137 | C3CN_ACTIVE_CLOSE_NEEDED, /* need to be closed */ | 137 | C3CN_ACTIVE_CLOSE_NEEDED, /* need to be closed */ |
138 | C3CN_OFFLOAD_DOWN /* offload function off */ | ||
138 | }; | 139 | }; |
139 | 140 | ||
140 | /** | 141 | /** |
141 | * cxgb3i_sdev_data - Per adapter data. | 142 | * cxgb3i_sdev_data - Per adapter data. |
142 | * | ||
143 | * Linked off of each Ethernet device port on the adapter. | 143 | * Linked off of each Ethernet device port on the adapter. |
144 | * Also available via the t3cdev structure since we have pointers to our port | 144 | * Also available via the t3cdev structure since we have pointers to our port |
145 | * net_device's there ... | 145 | * net_device's there ... |
@@ -148,16 +148,17 @@ enum c3cn_flags { | |||
148 | * @cdev: t3cdev adapter | 148 | * @cdev: t3cdev adapter |
149 | * @client: CPL client pointer | 149 | * @client: CPL client pointer |
150 | * @ports: array of adapter ports | 150 | * @ports: array of adapter ports |
151 | * @sport_map_next: next index into the port map | 151 | * @sport_next: next port |
152 | * @sport_map: source port map | 152 | * @sport_conn: source port connection |
153 | */ | 153 | */ |
154 | struct cxgb3i_sdev_data { | 154 | struct cxgb3i_sdev_data { |
155 | struct list_head list; | 155 | struct list_head list; |
156 | struct t3cdev *cdev; | 156 | struct t3cdev *cdev; |
157 | struct cxgb3_client *client; | 157 | struct cxgb3_client *client; |
158 | struct adap_ports ports; | 158 | struct adap_ports ports; |
159 | unsigned int sport_map_next; | 159 | spinlock_t lock; |
160 | unsigned long sport_map[0]; | 160 | unsigned int sport_next; |
161 | struct s3_conn *sport_conn[0]; | ||
161 | }; | 162 | }; |
162 | #define NDEV2CDATA(ndev) (*(struct cxgb3i_sdev_data **)&(ndev)->ec_ptr) | 163 | #define NDEV2CDATA(ndev) (*(struct cxgb3i_sdev_data **)&(ndev)->ec_ptr) |
163 | #define CXGB3_SDEV_DATA(cdev) NDEV2CDATA((cdev)->lldev) | 164 | #define CXGB3_SDEV_DATA(cdev) NDEV2CDATA((cdev)->lldev) |