aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/cxgb3i
diff options
context:
space:
mode:
authorKaren Xie <kxie@chelsio.com>2009-04-01 14:11:26 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-04-03 10:23:12 -0400
commit2a90030fcb827afa16914e57ac587e683280ae4a (patch)
tree269dafd0da1fc251c16341c6943095b637e148ec /drivers/scsi/cxgb3i
parented6f7744f90a0efc6874f2ab93e4e593741079c9 (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.c101
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_offload.h11
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
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
@@ -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 */
1423void cxgb3i_c3cn_release(struct s3_conn *c3cn) 1429void 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:
1776static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata) 1781static 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
1852free_cdata: 1879free_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 */
154struct cxgb3i_sdev_data { 154struct 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)