[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>
This commit is contained in:
parent
ed6f7744f9
commit
2a90030fcb
|
@ -94,29 +94,30 @@ static int c3cn_get_port(struct s3_conn *c3cn, struct cxgb3i_sdev_data *cdata)
|
||||||
if (!cdata)
|
if (!cdata)
|
||||||
goto error_out;
|
goto error_out;
|
||||||
|
|
||||||
if (c3cn->saddr.sin_port != 0) {
|
if (c3cn->saddr.sin_port) {
|
||||||
idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base;
|
cxgb3i_log_error("connect, sin_port NON-ZERO %u.\n",
|
||||||
if (idx < 0 || idx >= cxgb3_max_connect)
|
c3cn->saddr.sin_port);
|
||||||
return 0;
|
return -EADDRINUSE;
|
||||||
if (!test_and_set_bit(idx, cdata->sport_map))
|
|
||||||
return -EADDRINUSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the sport_map_next may not be accurate but that is okay, sport_map
|
spin_lock_bh(&cdata->lock);
|
||||||
should be */
|
start = idx = cdata->sport_next;
|
||||||
start = idx = cdata->sport_map_next;
|
|
||||||
do {
|
do {
|
||||||
if (++idx >= cxgb3_max_connect)
|
if (++idx >= cxgb3_max_connect)
|
||||||
idx = 0;
|
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);
|
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",
|
c3cn_conn_debug("%s reserve port %u.\n",
|
||||||
cdata->cdev->name,
|
cdata->cdev->name,
|
||||||
cxgb3_sport_base + idx);
|
cxgb3_sport_base + idx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} while (idx != start);
|
} while (idx != start);
|
||||||
|
spin_unlock_bh(&cdata->lock);
|
||||||
|
|
||||||
error_out:
|
error_out:
|
||||||
return -EADDRNOTAVAIL;
|
return -EADDRNOTAVAIL;
|
||||||
|
@ -124,15 +125,19 @@ error_out:
|
||||||
|
|
||||||
static void c3cn_put_port(struct s3_conn *c3cn)
|
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) {
|
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;
|
int idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base;
|
||||||
|
|
||||||
c3cn->saddr.sin_port = 0;
|
c3cn->saddr.sin_port = 0;
|
||||||
if (idx < 0 || idx >= cxgb3_max_connect)
|
if (idx < 0 || idx >= cxgb3_max_connect)
|
||||||
return;
|
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",
|
c3cn_conn_debug("%s, release port %u.\n",
|
||||||
cdata->cdev->name, cxgb3_sport_base + idx);
|
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;
|
struct t3cdev *cdev = c3cn->cdev;
|
||||||
unsigned int tid = c3cn->tid;
|
unsigned int tid = c3cn->tid;
|
||||||
|
|
||||||
if (!cdev)
|
|
||||||
return;
|
|
||||||
|
|
||||||
c3cn->qset = 0;
|
c3cn->qset = 0;
|
||||||
|
|
||||||
c3cn_free_cpl_skbs(c3cn);
|
c3cn_free_cpl_skbs(c3cn);
|
||||||
|
|
||||||
if (c3cn->wr_avail != c3cn->wr_max) {
|
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);
|
reset_wr_list(c3cn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c3cn->l2t) {
|
if (cdev) {
|
||||||
l2t_release(L2DATA(cdev), c3cn->l2t);
|
if (c3cn->l2t) {
|
||||||
c3cn->l2t = NULL;
|
l2t_release(L2DATA(cdev), c3cn->l2t);
|
||||||
}
|
c3cn->l2t = NULL;
|
||||||
|
}
|
||||||
if (c3cn->state == C3CN_STATE_CONNECTING) /* we have ATID */
|
if (c3cn->state == C3CN_STATE_CONNECTING)
|
||||||
s3_free_atid(cdev, tid);
|
/* we have ATID */
|
||||||
else { /* we have TID */
|
s3_free_atid(cdev, tid);
|
||||||
cxgb3_remove_tid(cdev, (void *)c3cn, tid);
|
else {
|
||||||
c3cn_put(c3cn);
|
/* we have TID */
|
||||||
|
cxgb3_remove_tid(cdev, (void *)c3cn, tid);
|
||||||
|
c3cn_put(c3cn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c3cn->dst_cache = NULL;
|
||||||
c3cn->cdev = 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
|
* @c3cn: the iscsi tcp connection
|
||||||
*/
|
*/
|
||||||
void cxgb3i_c3cn_release(struct s3_conn *c3cn)
|
void cxgb3i_c3cn_release(struct s3_conn *c3cn)
|
||||||
{
|
{
|
||||||
c3cn_conn_debug("c3cn 0x%p, s %u, f 0x%lx.\n",
|
c3cn_conn_debug("c3cn 0x%p, s %u, f 0x%lx.\n",
|
||||||
c3cn, c3cn->state, c3cn->flags);
|
c3cn, c3cn->state, c3cn->flags);
|
||||||
if (likely(c3cn->state != C3CN_STATE_CONNECTING))
|
if (unlikely(c3cn->state == C3CN_STATE_CONNECTING))
|
||||||
c3cn_active_close(c3cn);
|
|
||||||
else
|
|
||||||
c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED);
|
c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED);
|
||||||
|
else if (likely(c3cn->state != C3CN_STATE_CLOSED))
|
||||||
|
c3cn_active_close(c3cn);
|
||||||
c3cn_put(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);
|
c3cn_set_state(c3cn, C3CN_STATE_CLOSED);
|
||||||
ip_rt_put(rt);
|
ip_rt_put(rt);
|
||||||
c3cn_put_port(c3cn);
|
c3cn_put_port(c3cn);
|
||||||
c3cn->daddr.sin_port = 0;
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1776,10 +1781,25 @@ out_err:
|
||||||
static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata)
|
static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata)
|
||||||
{
|
{
|
||||||
struct adap_ports *ports = &cdata->ports;
|
struct adap_ports *ports = &cdata->ports;
|
||||||
|
struct s3_conn *c3cn;
|
||||||
int i;
|
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++)
|
for (i = 0; i < ports->nports; i++)
|
||||||
NDEV2CDATA(ports->lldevs[i]) = NULL;
|
NDEV2CDATA(ports->lldevs[i]) = NULL;
|
||||||
|
|
||||||
cxgb3i_free_big_mem(cdata);
|
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 cxgb3i_sdev_data *cdata;
|
||||||
struct ofld_page_info rx_page_info;
|
struct ofld_page_info rx_page_info;
|
||||||
unsigned int wr_len;
|
unsigned int wr_len;
|
||||||
int mapsize = DIV_ROUND_UP(cxgb3_max_connect,
|
int mapsize = cxgb3_max_connect * sizeof(struct s3_conn *);
|
||||||
8 * sizeof(unsigned long));
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL);
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 ||
|
if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 ||
|
||||||
cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 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;
|
goto free_cdata;
|
||||||
|
}
|
||||||
|
|
||||||
s3_init_wr_tab(wr_len);
|
s3_init_wr_tab(wr_len);
|
||||||
|
|
||||||
|
spin_lock_init(&cdata->lock);
|
||||||
INIT_LIST_HEAD(&cdata->list);
|
INIT_LIST_HEAD(&cdata->list);
|
||||||
cdata->cdev = cdev;
|
cdata->cdev = cdev;
|
||||||
cdata->client = client;
|
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);
|
list_add_tail(&cdata->list, &cdata_list);
|
||||||
write_unlock(&cdata_rwlock);
|
write_unlock(&cdata_rwlock);
|
||||||
|
|
||||||
|
cxgb3i_log_info("t3dev 0x%p, offload up, added.\n", cdev);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
free_cdata:
|
free_cdata:
|
||||||
|
@ -1861,6 +1888,8 @@ void cxgb3i_sdev_remove(struct t3cdev *cdev)
|
||||||
{
|
{
|
||||||
struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(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);
|
write_lock(&cdata_rwlock);
|
||||||
list_del(&cdata->list);
|
list_del(&cdata->list);
|
||||||
write_unlock(&cdata_rwlock);
|
write_unlock(&cdata_rwlock);
|
||||||
|
|
|
@ -135,11 +135,11 @@ enum c3cn_flags {
|
||||||
C3CN_ABORT_RPL_PENDING, /* expecting an abort reply */
|
C3CN_ABORT_RPL_PENDING, /* expecting an abort reply */
|
||||||
C3CN_TX_DATA_SENT, /* already sent a TX_DATA WR */
|
C3CN_TX_DATA_SENT, /* already sent a TX_DATA WR */
|
||||||
C3CN_ACTIVE_CLOSE_NEEDED, /* need to be closed */
|
C3CN_ACTIVE_CLOSE_NEEDED, /* need to be closed */
|
||||||
|
C3CN_OFFLOAD_DOWN /* offload function off */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cxgb3i_sdev_data - Per adapter data.
|
* cxgb3i_sdev_data - Per adapter data.
|
||||||
*
|
|
||||||
* Linked off of each Ethernet device port on the adapter.
|
* Linked off of each Ethernet device port on the adapter.
|
||||||
* Also available via the t3cdev structure since we have pointers to our port
|
* Also available via the t3cdev structure since we have pointers to our port
|
||||||
* net_device's there ...
|
* net_device's there ...
|
||||||
|
@ -148,16 +148,17 @@ enum c3cn_flags {
|
||||||
* @cdev: t3cdev adapter
|
* @cdev: t3cdev adapter
|
||||||
* @client: CPL client pointer
|
* @client: CPL client pointer
|
||||||
* @ports: array of adapter ports
|
* @ports: array of adapter ports
|
||||||
* @sport_map_next: next index into the port map
|
* @sport_next: next port
|
||||||
* @sport_map: source port map
|
* @sport_conn: source port connection
|
||||||
*/
|
*/
|
||||||
struct cxgb3i_sdev_data {
|
struct cxgb3i_sdev_data {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct t3cdev *cdev;
|
struct t3cdev *cdev;
|
||||||
struct cxgb3_client *client;
|
struct cxgb3_client *client;
|
||||||
struct adap_ports ports;
|
struct adap_ports ports;
|
||||||
unsigned int sport_map_next;
|
spinlock_t lock;
|
||||||
unsigned long sport_map[0];
|
unsigned int sport_next;
|
||||||
|
struct s3_conn *sport_conn[0];
|
||||||
};
|
};
|
||||||
#define NDEV2CDATA(ndev) (*(struct cxgb3i_sdev_data **)&(ndev)->ec_ptr)
|
#define NDEV2CDATA(ndev) (*(struct cxgb3i_sdev_data **)&(ndev)->ec_ptr)
|
||||||
#define CXGB3_SDEV_DATA(cdev) NDEV2CDATA((cdev)->lldev)
|
#define CXGB3_SDEV_DATA(cdev) NDEV2CDATA((cdev)->lldev)
|
||||||
|
|
Loading…
Reference in New Issue