mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
[SCSI] iscsi: pass ep connect shost
When we create the tcp/ip connection by calling ep_connect, we currently just go by the routing table info. I think there are two problems with this. 1. Some drivers do not have access to a routing table. Some drivers like qla4xxx do not even know about other ports. 2. If you have two initiator ports on the same subnet, the user may have set things up so that session1 was supposed to be run through port1. and session2 was supposed to be run through port2. It looks like we could end with both sessions going through one of the ports. Fixes for cxgb3i from Karen Xie. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
5a2537959f
commit
10eb0f013c
8 changed files with 87 additions and 29 deletions
|
@ -517,7 +517,8 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct iscsi_endpoint *
|
static struct iscsi_endpoint *
|
||||||
iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking)
|
iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
|
||||||
|
int non_blocking)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct iser_conn *ib_conn;
|
struct iser_conn *ib_conn;
|
||||||
|
|
|
@ -144,7 +144,6 @@ struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *);
|
||||||
void cxgb3i_adapter_open(struct t3cdev *);
|
void cxgb3i_adapter_open(struct t3cdev *);
|
||||||
void cxgb3i_adapter_close(struct t3cdev *);
|
void cxgb3i_adapter_close(struct t3cdev *);
|
||||||
|
|
||||||
struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *);
|
|
||||||
struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *,
|
struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *,
|
||||||
struct net_device *);
|
struct net_device *);
|
||||||
void cxgb3i_hba_host_remove(struct cxgb3i_hba *);
|
void cxgb3i_hba_host_remove(struct cxgb3i_hba *);
|
||||||
|
|
|
@ -178,7 +178,7 @@ void cxgb3i_adapter_close(struct t3cdev *t3dev)
|
||||||
* cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device
|
* cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device
|
||||||
* @t3dev: t3cdev adapter
|
* @t3dev: t3cdev adapter
|
||||||
*/
|
*/
|
||||||
struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
|
static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
|
||||||
{
|
{
|
||||||
struct cxgb3i_adapter *snic;
|
struct cxgb3i_adapter *snic;
|
||||||
int i;
|
int i;
|
||||||
|
@ -261,20 +261,27 @@ void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cxgb3i_ep_connect - establish TCP connection to target portal
|
* cxgb3i_ep_connect - establish TCP connection to target portal
|
||||||
|
* @shost: scsi host to use
|
||||||
* @dst_addr: target IP address
|
* @dst_addr: target IP address
|
||||||
* @non_blocking: blocking or non-blocking call
|
* @non_blocking: blocking or non-blocking call
|
||||||
*
|
*
|
||||||
* Initiates a TCP/IP connection to the dst_addr
|
* Initiates a TCP/IP connection to the dst_addr
|
||||||
*/
|
*/
|
||||||
static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr,
|
static struct iscsi_endpoint *cxgb3i_ep_connect(struct Scsi_Host *shost,
|
||||||
|
struct sockaddr *dst_addr,
|
||||||
int non_blocking)
|
int non_blocking)
|
||||||
{
|
{
|
||||||
struct iscsi_endpoint *ep;
|
struct iscsi_endpoint *ep;
|
||||||
struct cxgb3i_endpoint *cep;
|
struct cxgb3i_endpoint *cep;
|
||||||
struct cxgb3i_hba *hba;
|
struct cxgb3i_hba *hba = NULL;
|
||||||
struct s3_conn *c3cn = NULL;
|
struct s3_conn *c3cn = NULL;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
if (shost)
|
||||||
|
hba = iscsi_host_priv(shost);
|
||||||
|
|
||||||
|
cxgb3i_api_debug("shost 0x%p, hba 0x%p.\n", shost, hba);
|
||||||
|
|
||||||
c3cn = cxgb3i_c3cn_create();
|
c3cn = cxgb3i_c3cn_create();
|
||||||
if (!c3cn) {
|
if (!c3cn) {
|
||||||
cxgb3i_log_info("ep connect OOM.\n");
|
cxgb3i_log_info("ep connect OOM.\n");
|
||||||
|
@ -282,17 +289,27 @@ static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr,
|
||||||
goto release_conn;
|
goto release_conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cxgb3i_c3cn_connect(c3cn, (struct sockaddr_in *)dst_addr);
|
err = cxgb3i_c3cn_connect(hba ? hba->ndev : NULL, c3cn,
|
||||||
|
(struct sockaddr_in *)dst_addr);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
cxgb3i_log_info("ep connect failed.\n");
|
cxgb3i_log_info("ep connect failed.\n");
|
||||||
goto release_conn;
|
goto release_conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev);
|
hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev);
|
||||||
if (!hba) {
|
if (!hba) {
|
||||||
err = -ENOSPC;
|
err = -ENOSPC;
|
||||||
cxgb3i_log_info("NOT going through cxgbi device.\n");
|
cxgb3i_log_info("NOT going through cxgbi device.\n");
|
||||||
goto release_conn;
|
goto release_conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shost && hba != iscsi_host_priv(shost)) {
|
||||||
|
err = -ENOSPC;
|
||||||
|
cxgb3i_log_info("Could not connect through request host%u\n",
|
||||||
|
shost->host_no);
|
||||||
|
goto release_conn;
|
||||||
|
}
|
||||||
|
|
||||||
if (c3cn_is_closing(c3cn)) {
|
if (c3cn_is_closing(c3cn)) {
|
||||||
err = -ENOSPC;
|
err = -ENOSPC;
|
||||||
cxgb3i_log_info("ep connect unable to connect.\n");
|
cxgb3i_log_info("ep connect unable to connect.\n");
|
||||||
|
|
|
@ -1479,12 +1479,13 @@ static struct net_device *cxgb3_egress_dev(struct net_device *root_dev,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rtable *find_route(__be32 saddr, __be32 daddr,
|
static struct rtable *find_route(struct net_device *dev,
|
||||||
|
__be32 saddr, __be32 daddr,
|
||||||
__be16 sport, __be16 dport)
|
__be16 sport, __be16 dport)
|
||||||
{
|
{
|
||||||
struct rtable *rt;
|
struct rtable *rt;
|
||||||
struct flowi fl = {
|
struct flowi fl = {
|
||||||
.oif = 0,
|
.oif = dev ? dev->ifindex : 0,
|
||||||
.nl_u = {
|
.nl_u = {
|
||||||
.ip4_u = {
|
.ip4_u = {
|
||||||
.daddr = daddr,
|
.daddr = daddr,
|
||||||
|
@ -1573,36 +1574,40 @@ static int initiate_act_open(struct s3_conn *c3cn, struct net_device *dev)
|
||||||
*
|
*
|
||||||
* return 0 if active open request is sent, < 0 otherwise.
|
* return 0 if active open request is sent, < 0 otherwise.
|
||||||
*/
|
*/
|
||||||
int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin)
|
int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn,
|
||||||
|
struct sockaddr_in *usin)
|
||||||
{
|
{
|
||||||
struct rtable *rt;
|
struct rtable *rt;
|
||||||
struct net_device *dev;
|
|
||||||
struct cxgb3i_sdev_data *cdata;
|
struct cxgb3i_sdev_data *cdata;
|
||||||
struct t3cdev *cdev;
|
struct t3cdev *cdev;
|
||||||
__be32 sipv4;
|
__be32 sipv4;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
c3cn_conn_debug("c3cn 0x%p, dev 0x%p.\n", c3cn, dev);
|
||||||
|
|
||||||
if (usin->sin_family != AF_INET)
|
if (usin->sin_family != AF_INET)
|
||||||
return -EAFNOSUPPORT;
|
return -EAFNOSUPPORT;
|
||||||
|
|
||||||
c3cn->daddr.sin_port = usin->sin_port;
|
c3cn->daddr.sin_port = usin->sin_port;
|
||||||
c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr;
|
c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr;
|
||||||
|
|
||||||
rt = find_route(c3cn->saddr.sin_addr.s_addr,
|
rt = find_route(dev, c3cn->saddr.sin_addr.s_addr,
|
||||||
c3cn->daddr.sin_addr.s_addr,
|
c3cn->daddr.sin_addr.s_addr,
|
||||||
c3cn->saddr.sin_port,
|
c3cn->saddr.sin_port,
|
||||||
c3cn->daddr.sin_port);
|
c3cn->daddr.sin_port);
|
||||||
if (rt == NULL) {
|
if (rt == NULL) {
|
||||||
c3cn_conn_debug("NO route to 0x%x, port %u.\n",
|
c3cn_conn_debug("NO route to 0x%x, port %u, dev %s.\n",
|
||||||
c3cn->daddr.sin_addr.s_addr,
|
c3cn->daddr.sin_addr.s_addr,
|
||||||
ntohs(c3cn->daddr.sin_port));
|
ntohs(c3cn->daddr.sin_port),
|
||||||
|
dev ? dev->name : "any");
|
||||||
return -ENETUNREACH;
|
return -ENETUNREACH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
|
if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
|
||||||
c3cn_conn_debug("multi-cast route to 0x%x, port %u.\n",
|
c3cn_conn_debug("multi-cast route to 0x%x, port %u, dev %s.\n",
|
||||||
c3cn->daddr.sin_addr.s_addr,
|
c3cn->daddr.sin_addr.s_addr,
|
||||||
ntohs(c3cn->daddr.sin_port));
|
ntohs(c3cn->daddr.sin_port),
|
||||||
|
dev ? dev->name : "any");
|
||||||
ip_rt_put(rt);
|
ip_rt_put(rt);
|
||||||
return -ENETUNREACH;
|
return -ENETUNREACH;
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,8 @@ void cxgb3i_sdev_add(struct t3cdev *, struct cxgb3_client *);
|
||||||
void cxgb3i_sdev_remove(struct t3cdev *);
|
void cxgb3i_sdev_remove(struct t3cdev *);
|
||||||
|
|
||||||
struct s3_conn *cxgb3i_c3cn_create(void);
|
struct s3_conn *cxgb3i_c3cn_create(void);
|
||||||
int cxgb3i_c3cn_connect(struct s3_conn *, struct sockaddr_in *);
|
int cxgb3i_c3cn_connect(struct net_device *, struct s3_conn *,
|
||||||
|
struct sockaddr_in *);
|
||||||
void cxgb3i_c3cn_rx_credits(struct s3_conn *, int);
|
void cxgb3i_c3cn_rx_credits(struct s3_conn *, int);
|
||||||
int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *);
|
int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *);
|
||||||
void cxgb3i_c3cn_release(struct s3_conn *);
|
void cxgb3i_c3cn_release(struct s3_conn *);
|
||||||
|
|
|
@ -1268,26 +1268,54 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int iscsi_if_ep_connect(struct iscsi_transport *transport,
|
||||||
|
struct iscsi_uevent *ev, int msg_type)
|
||||||
|
{
|
||||||
|
struct iscsi_endpoint *ep;
|
||||||
|
struct sockaddr *dst_addr;
|
||||||
|
struct Scsi_Host *shost = NULL;
|
||||||
|
int non_blocking, err = 0;
|
||||||
|
|
||||||
|
if (!transport->ep_connect)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) {
|
||||||
|
shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no);
|
||||||
|
if (!shost) {
|
||||||
|
printk(KERN_ERR "ep connect failed. Could not find "
|
||||||
|
"host no %u\n",
|
||||||
|
ev->u.ep_connect_through_host.host_no);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
non_blocking = ev->u.ep_connect_through_host.non_blocking;
|
||||||
|
} else
|
||||||
|
non_blocking = ev->u.ep_connect.non_blocking;
|
||||||
|
|
||||||
|
dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
|
||||||
|
ep = transport->ep_connect(shost, dst_addr, non_blocking);
|
||||||
|
if (IS_ERR(ep)) {
|
||||||
|
err = PTR_ERR(ep);
|
||||||
|
goto release_host;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev->r.ep_connect_ret.handle = ep->id;
|
||||||
|
release_host:
|
||||||
|
if (shost)
|
||||||
|
scsi_host_put(shost);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
iscsi_if_transport_ep(struct iscsi_transport *transport,
|
iscsi_if_transport_ep(struct iscsi_transport *transport,
|
||||||
struct iscsi_uevent *ev, int msg_type)
|
struct iscsi_uevent *ev, int msg_type)
|
||||||
{
|
{
|
||||||
struct iscsi_endpoint *ep;
|
struct iscsi_endpoint *ep;
|
||||||
struct sockaddr *dst_addr;
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
switch (msg_type) {
|
switch (msg_type) {
|
||||||
|
case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
|
||||||
case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
|
case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
|
||||||
if (!transport->ep_connect)
|
rc = iscsi_if_ep_connect(transport, ev, msg_type);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
|
|
||||||
ep = transport->ep_connect(dst_addr,
|
|
||||||
ev->u.ep_connect.non_blocking);
|
|
||||||
if (IS_ERR(ep))
|
|
||||||
return PTR_ERR(ep);
|
|
||||||
|
|
||||||
ev->r.ep_connect_ret.handle = ep->id;
|
|
||||||
break;
|
break;
|
||||||
case ISCSI_UEVENT_TRANSPORT_EP_POLL:
|
case ISCSI_UEVENT_TRANSPORT_EP_POLL:
|
||||||
if (!transport->ep_poll)
|
if (!transport->ep_poll)
|
||||||
|
@ -1469,6 +1497,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||||
case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
|
case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
|
||||||
case ISCSI_UEVENT_TRANSPORT_EP_POLL:
|
case ISCSI_UEVENT_TRANSPORT_EP_POLL:
|
||||||
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
|
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
|
||||||
|
case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
|
||||||
err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
|
err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
|
||||||
break;
|
break;
|
||||||
case ISCSI_UEVENT_TGT_DSCVR:
|
case ISCSI_UEVENT_TGT_DSCVR:
|
||||||
|
|
|
@ -51,6 +51,7 @@ enum iscsi_uevent_e {
|
||||||
ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
|
ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
|
||||||
ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17,
|
ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17,
|
||||||
ISCSI_UEVENT_CREATE_BOUND_SESSION = UEVENT_BASE + 18,
|
ISCSI_UEVENT_CREATE_BOUND_SESSION = UEVENT_BASE + 18,
|
||||||
|
ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST = UEVENT_BASE + 19,
|
||||||
|
|
||||||
/* up events */
|
/* up events */
|
||||||
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
|
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
|
||||||
|
@ -131,6 +132,10 @@ struct iscsi_uevent {
|
||||||
struct msg_transport_connect {
|
struct msg_transport_connect {
|
||||||
uint32_t non_blocking;
|
uint32_t non_blocking;
|
||||||
} ep_connect;
|
} ep_connect;
|
||||||
|
struct msg_transport_connect_through_host {
|
||||||
|
uint32_t host_no;
|
||||||
|
uint32_t non_blocking;
|
||||||
|
} ep_connect_through_host;
|
||||||
struct msg_transport_poll {
|
struct msg_transport_poll {
|
||||||
uint64_t ep_handle;
|
uint64_t ep_handle;
|
||||||
uint32_t timeout_ms;
|
uint32_t timeout_ms;
|
||||||
|
|
|
@ -126,7 +126,8 @@ struct iscsi_transport {
|
||||||
int *index, int *age);
|
int *index, int *age);
|
||||||
|
|
||||||
void (*session_recovery_timedout) (struct iscsi_cls_session *session);
|
void (*session_recovery_timedout) (struct iscsi_cls_session *session);
|
||||||
struct iscsi_endpoint *(*ep_connect) (struct sockaddr *dst_addr,
|
struct iscsi_endpoint *(*ep_connect) (struct Scsi_Host *shost,
|
||||||
|
struct sockaddr *dst_addr,
|
||||||
int non_blocking);
|
int non_blocking);
|
||||||
int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
|
int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
|
||||||
void (*ep_disconnect) (struct iscsi_endpoint *ep);
|
void (*ep_disconnect) (struct iscsi_endpoint *ep);
|
||||||
|
|
Loading…
Reference in a new issue