|
@@ -94,29 +94,30 @@ static int c3cn_get_port(struct s3_conn *c3cn, struct cxgb3i_sdev_data *cdata)
|
|
|
if (!cdata)
|
|
|
goto error_out;
|
|
|
|
|
|
- if (c3cn->saddr.sin_port != 0) {
|
|
|
- idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base;
|
|
|
- if (idx < 0 || idx >= cxgb3_max_connect)
|
|
|
- return 0;
|
|
|
- if (!test_and_set_bit(idx, cdata->sport_map))
|
|
|
- return -EADDRINUSE;
|
|
|
+ if (c3cn->saddr.sin_port) {
|
|
|
+ cxgb3i_log_error("connect, sin_port NON-ZERO %u.\n",
|
|
|
+ c3cn->saddr.sin_port);
|
|
|
+ return -EADDRINUSE;
|
|
|
}
|
|
|
|
|
|
- /* the sport_map_next may not be accurate but that is okay, sport_map
|
|
|
- should be */
|
|
|
- start = idx = cdata->sport_map_next;
|
|
|
+ spin_lock_bh(&cdata->lock);
|
|
|
+ start = idx = cdata->sport_next;
|
|
|
do {
|
|
|
if (++idx >= cxgb3_max_connect)
|
|
|
idx = 0;
|
|
|
- if (!(test_and_set_bit(idx, cdata->sport_map))) {
|
|
|
+ if (!cdata->sport_conn[idx]) {
|
|
|
c3cn->saddr.sin_port = htons(cxgb3_sport_base + idx);
|
|
|
- cdata->sport_map_next = idx;
|
|
|
+ cdata->sport_next = idx;
|
|
|
+ cdata->sport_conn[idx] = c3cn;
|
|
|
+ spin_unlock_bh(&cdata->lock);
|
|
|
+
|
|
|
c3cn_conn_debug("%s reserve port %u.\n",
|
|
|
cdata->cdev->name,
|
|
|
cxgb3_sport_base + idx);
|
|
|
return 0;
|
|
|
}
|
|
|
} while (idx != start);
|
|
|
+ spin_unlock_bh(&cdata->lock);
|
|
|
|
|
|
error_out:
|
|
|
return -EADDRNOTAVAIL;
|
|
@@ -124,15 +125,19 @@ error_out:
|
|
|
|
|
|
static void c3cn_put_port(struct s3_conn *c3cn)
|
|
|
{
|
|
|
- struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev);
|
|
|
+ if (!c3cn->cdev)
|
|
|
+ return;
|
|
|
|
|
|
if (c3cn->saddr.sin_port) {
|
|
|
+ struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev);
|
|
|
int idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base;
|
|
|
|
|
|
c3cn->saddr.sin_port = 0;
|
|
|
if (idx < 0 || idx >= cxgb3_max_connect)
|
|
|
return;
|
|
|
- clear_bit(idx, cdata->sport_map);
|
|
|
+ spin_lock_bh(&cdata->lock);
|
|
|
+ cdata->sport_conn[idx] = NULL;
|
|
|
+ spin_unlock_bh(&cdata->lock);
|
|
|
c3cn_conn_debug("%s, release port %u.\n",
|
|
|
cdata->cdev->name, cxgb3_sport_base + idx);
|
|
|
}
|
|
@@ -1305,11 +1310,7 @@ static void c3cn_release_offload_resources(struct s3_conn *c3cn)
|
|
|
struct t3cdev *cdev = c3cn->cdev;
|
|
|
unsigned int tid = c3cn->tid;
|
|
|
|
|
|
- if (!cdev)
|
|
|
- return;
|
|
|
-
|
|
|
c3cn->qset = 0;
|
|
|
-
|
|
|
c3cn_free_cpl_skbs(c3cn);
|
|
|
|
|
|
if (c3cn->wr_avail != c3cn->wr_max) {
|
|
@@ -1317,18 +1318,22 @@ static void c3cn_release_offload_resources(struct s3_conn *c3cn)
|
|
|
reset_wr_list(c3cn);
|
|
|
}
|
|
|
|
|
|
- if (c3cn->l2t) {
|
|
|
- l2t_release(L2DATA(cdev), c3cn->l2t);
|
|
|
- c3cn->l2t = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (c3cn->state == C3CN_STATE_CONNECTING) /* we have ATID */
|
|
|
- s3_free_atid(cdev, tid);
|
|
|
- else { /* we have TID */
|
|
|
- cxgb3_remove_tid(cdev, (void *)c3cn, tid);
|
|
|
- c3cn_put(c3cn);
|
|
|
+ if (cdev) {
|
|
|
+ if (c3cn->l2t) {
|
|
|
+ l2t_release(L2DATA(cdev), c3cn->l2t);
|
|
|
+ c3cn->l2t = NULL;
|
|
|
+ }
|
|
|
+ if (c3cn->state == C3CN_STATE_CONNECTING)
|
|
|
+ /* we have ATID */
|
|
|
+ s3_free_atid(cdev, tid);
|
|
|
+ else {
|
|
|
+ /* we have TID */
|
|
|
+ cxgb3_remove_tid(cdev, (void *)c3cn, tid);
|
|
|
+ c3cn_put(c3cn);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ c3cn->dst_cache = NULL;
|
|
|
c3cn->cdev = NULL;
|
|
|
}
|
|
|
|
|
@@ -1417,17 +1422,18 @@ static void c3cn_active_close(struct s3_conn *c3cn)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * cxgb3i_c3cn_release - close and release an iscsi tcp connection
|
|
|
+ * cxgb3i_c3cn_release - close and release an iscsi tcp connection and any
|
|
|
+ * resource held
|
|
|
* @c3cn: the iscsi tcp connection
|
|
|
*/
|
|
|
void cxgb3i_c3cn_release(struct s3_conn *c3cn)
|
|
|
{
|
|
|
c3cn_conn_debug("c3cn 0x%p, s %u, f 0x%lx.\n",
|
|
|
c3cn, c3cn->state, c3cn->flags);
|
|
|
- if (likely(c3cn->state != C3CN_STATE_CONNECTING))
|
|
|
- c3cn_active_close(c3cn);
|
|
|
- else
|
|
|
+ if (unlikely(c3cn->state == C3CN_STATE_CONNECTING))
|
|
|
c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED);
|
|
|
+ else if (likely(c3cn->state != C3CN_STATE_CLOSED))
|
|
|
+ c3cn_active_close(c3cn);
|
|
|
c3cn_put(c3cn);
|
|
|
}
|
|
|
|
|
@@ -1656,7 +1662,6 @@ int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin)
|
|
|
c3cn_set_state(c3cn, C3CN_STATE_CLOSED);
|
|
|
ip_rt_put(rt);
|
|
|
c3cn_put_port(c3cn);
|
|
|
- c3cn->daddr.sin_port = 0;
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -1776,10 +1781,25 @@ out_err:
|
|
|
static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata)
|
|
|
{
|
|
|
struct adap_ports *ports = &cdata->ports;
|
|
|
+ struct s3_conn *c3cn;
|
|
|
int i;
|
|
|
|
|
|
+ for (i = 0; i < cxgb3_max_connect; i++) {
|
|
|
+ if (cdata->sport_conn[i]) {
|
|
|
+ c3cn = cdata->sport_conn[i];
|
|
|
+ cdata->sport_conn[i] = NULL;
|
|
|
+
|
|
|
+ spin_lock_bh(&c3cn->lock);
|
|
|
+ c3cn->cdev = NULL;
|
|
|
+ c3cn_set_flag(c3cn, C3CN_OFFLOAD_DOWN);
|
|
|
+ c3cn_closed(c3cn);
|
|
|
+ spin_unlock_bh(&c3cn->lock);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
for (i = 0; i < ports->nports; i++)
|
|
|
NDEV2CDATA(ports->lldevs[i]) = NULL;
|
|
|
+
|
|
|
cxgb3i_free_big_mem(cdata);
|
|
|
}
|
|
|
|
|
@@ -1821,21 +1841,27 @@ void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client)
|
|
|
struct cxgb3i_sdev_data *cdata;
|
|
|
struct ofld_page_info rx_page_info;
|
|
|
unsigned int wr_len;
|
|
|
- int mapsize = DIV_ROUND_UP(cxgb3_max_connect,
|
|
|
- 8 * sizeof(unsigned long));
|
|
|
+ int mapsize = cxgb3_max_connect * sizeof(struct s3_conn *);
|
|
|
int i;
|
|
|
|
|
|
cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL);
|
|
|
- if (!cdata)
|
|
|
+ if (!cdata) {
|
|
|
+ cxgb3i_log_warn("t3dev 0x%p, offload up, OOM %d.\n",
|
|
|
+ cdev, mapsize);
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 ||
|
|
|
cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 0 ||
|
|
|
- cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0)
|
|
|
+ cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) {
|
|
|
+ cxgb3i_log_warn("t3dev 0x%p, offload up, ioctl failed.\n",
|
|
|
+ cdev);
|
|
|
goto free_cdata;
|
|
|
+ }
|
|
|
|
|
|
s3_init_wr_tab(wr_len);
|
|
|
|
|
|
+ spin_lock_init(&cdata->lock);
|
|
|
INIT_LIST_HEAD(&cdata->list);
|
|
|
cdata->cdev = cdev;
|
|
|
cdata->client = client;
|
|
@@ -1847,6 +1873,7 @@ void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client)
|
|
|
list_add_tail(&cdata->list, &cdata_list);
|
|
|
write_unlock(&cdata_rwlock);
|
|
|
|
|
|
+ cxgb3i_log_info("t3dev 0x%p, offload up, added.\n", cdev);
|
|
|
return;
|
|
|
|
|
|
free_cdata:
|
|
@@ -1861,6 +1888,8 @@ void cxgb3i_sdev_remove(struct t3cdev *cdev)
|
|
|
{
|
|
|
struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev);
|
|
|
|
|
|
+ cxgb3i_log_info("t3dev 0x%p, offload down, remove.\n", cdev);
|
|
|
+
|
|
|
write_lock(&cdata_rwlock);
|
|
|
list_del(&cdata->list);
|
|
|
write_unlock(&cdata_rwlock);
|