aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2009-05-13 18:57:38 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-05-23 16:44:09 -0400
commit10eb0f013c63c71c82ede77945a5f390c10cfda6 (patch)
tree6f4b738aa1dfc422087a0b05ebde4388cf84a3f0
parent5a2537959fa8781012e8c286fc1614e0f6991327 (diff)
[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>
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c3
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i.h1
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_iscsi.c25
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_offload.c23
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_offload.h3
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c51
-rw-r--r--include/scsi/iscsi_if.h7
-rw-r--r--include/scsi/scsi_transport_iscsi.h3
8 files changed, 87 insertions, 29 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 75223f50de58..ffbe0c76bc11 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -517,7 +517,8 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s
517} 517}
518 518
519static struct iscsi_endpoint * 519static struct iscsi_endpoint *
520iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking) 520iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
521 int non_blocking)
521{ 522{
522 int err; 523 int err;
523 struct iser_conn *ib_conn; 524 struct iser_conn *ib_conn;
diff --git a/drivers/scsi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgb3i/cxgb3i.h
index 59b0958d2d11..e3133b58e594 100644
--- a/drivers/scsi/cxgb3i/cxgb3i.h
+++ b/drivers/scsi/cxgb3i/cxgb3i.h
@@ -144,7 +144,6 @@ struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *);
144void cxgb3i_adapter_open(struct t3cdev *); 144void cxgb3i_adapter_open(struct t3cdev *);
145void cxgb3i_adapter_close(struct t3cdev *); 145void cxgb3i_adapter_close(struct t3cdev *);
146 146
147struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *);
148struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *, 147struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *,
149 struct net_device *); 148 struct net_device *);
150void cxgb3i_hba_host_remove(struct cxgb3i_hba *); 149void cxgb3i_hba_host_remove(struct cxgb3i_hba *);
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index 9212400b9b13..04a43744aedf 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
@@ -178,7 +178,7 @@ void cxgb3i_adapter_close(struct t3cdev *t3dev)
178 * cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device 178 * cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device
179 * @t3dev: t3cdev adapter 179 * @t3dev: t3cdev adapter
180 */ 180 */
181struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev) 181static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
182{ 182{
183 struct cxgb3i_adapter *snic; 183 struct cxgb3i_adapter *snic;
184 int i; 184 int i;
@@ -261,20 +261,27 @@ void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba)
261 261
262/** 262/**
263 * cxgb3i_ep_connect - establish TCP connection to target portal 263 * cxgb3i_ep_connect - establish TCP connection to target portal
264 * @shost: scsi host to use
264 * @dst_addr: target IP address 265 * @dst_addr: target IP address
265 * @non_blocking: blocking or non-blocking call 266 * @non_blocking: blocking or non-blocking call
266 * 267 *
267 * Initiates a TCP/IP connection to the dst_addr 268 * Initiates a TCP/IP connection to the dst_addr
268 */ 269 */
269static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr, 270static struct iscsi_endpoint *cxgb3i_ep_connect(struct Scsi_Host *shost,
271 struct sockaddr *dst_addr,
270 int non_blocking) 272 int non_blocking)
271{ 273{
272 struct iscsi_endpoint *ep; 274 struct iscsi_endpoint *ep;
273 struct cxgb3i_endpoint *cep; 275 struct cxgb3i_endpoint *cep;
274 struct cxgb3i_hba *hba; 276 struct cxgb3i_hba *hba = NULL;
275 struct s3_conn *c3cn = NULL; 277 struct s3_conn *c3cn = NULL;
276 int err = 0; 278 int err = 0;
277 279
280 if (shost)
281 hba = iscsi_host_priv(shost);
282
283 cxgb3i_api_debug("shost 0x%p, hba 0x%p.\n", shost, hba);
284
278 c3cn = cxgb3i_c3cn_create(); 285 c3cn = cxgb3i_c3cn_create();
279 if (!c3cn) { 286 if (!c3cn) {
280 cxgb3i_log_info("ep connect OOM.\n"); 287 cxgb3i_log_info("ep connect OOM.\n");
@@ -282,17 +289,27 @@ static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr,
282 goto release_conn; 289 goto release_conn;
283 } 290 }
284 291
285 err = cxgb3i_c3cn_connect(c3cn, (struct sockaddr_in *)dst_addr); 292 err = cxgb3i_c3cn_connect(hba ? hba->ndev : NULL, c3cn,
293 (struct sockaddr_in *)dst_addr);
286 if (err < 0) { 294 if (err < 0) {
287 cxgb3i_log_info("ep connect failed.\n"); 295 cxgb3i_log_info("ep connect failed.\n");
288 goto release_conn; 296 goto release_conn;
289 } 297 }
298
290 hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev); 299 hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev);
291 if (!hba) { 300 if (!hba) {
292 err = -ENOSPC; 301 err = -ENOSPC;
293 cxgb3i_log_info("NOT going through cxgbi device.\n"); 302 cxgb3i_log_info("NOT going through cxgbi device.\n");
294 goto release_conn; 303 goto release_conn;
295 } 304 }
305
306 if (shost && hba != iscsi_host_priv(shost)) {
307 err = -ENOSPC;
308 cxgb3i_log_info("Could not connect through request host%u\n",
309 shost->host_no);
310 goto release_conn;
311 }
312
296 if (c3cn_is_closing(c3cn)) { 313 if (c3cn_is_closing(c3cn)) {
297 err = -ENOSPC; 314 err = -ENOSPC;
298 cxgb3i_log_info("ep connect unable to connect.\n"); 315 cxgb3i_log_info("ep connect unable to connect.\n");
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index e11c9c180f39..c1d5be4adf9c 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -1479,12 +1479,13 @@ static struct net_device *cxgb3_egress_dev(struct net_device *root_dev,
1479 return NULL; 1479 return NULL;
1480} 1480}
1481 1481
1482static struct rtable *find_route(__be32 saddr, __be32 daddr, 1482static struct rtable *find_route(struct net_device *dev,
1483 __be32 saddr, __be32 daddr,
1483 __be16 sport, __be16 dport) 1484 __be16 sport, __be16 dport)
1484{ 1485{
1485 struct rtable *rt; 1486 struct rtable *rt;
1486 struct flowi fl = { 1487 struct flowi fl = {
1487 .oif = 0, 1488 .oif = dev ? dev->ifindex : 0,
1488 .nl_u = { 1489 .nl_u = {
1489 .ip4_u = { 1490 .ip4_u = {
1490 .daddr = daddr, 1491 .daddr = daddr,
@@ -1573,36 +1574,40 @@ out_err:
1573 * 1574 *
1574 * return 0 if active open request is sent, < 0 otherwise. 1575 * return 0 if active open request is sent, < 0 otherwise.
1575 */ 1576 */
1576int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin) 1577int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn,
1578 struct sockaddr_in *usin)
1577{ 1579{
1578 struct rtable *rt; 1580 struct rtable *rt;
1579 struct net_device *dev;
1580 struct cxgb3i_sdev_data *cdata; 1581 struct cxgb3i_sdev_data *cdata;
1581 struct t3cdev *cdev; 1582 struct t3cdev *cdev;
1582 __be32 sipv4; 1583 __be32 sipv4;
1583 int err; 1584 int err;
1584 1585
1586 c3cn_conn_debug("c3cn 0x%p, dev 0x%p.\n", c3cn, dev);
1587
1585 if (usin->sin_family != AF_INET) 1588 if (usin->sin_family != AF_INET)
1586 return -EAFNOSUPPORT; 1589 return -EAFNOSUPPORT;
1587 1590
1588 c3cn->daddr.sin_port = usin->sin_port; 1591 c3cn->daddr.sin_port = usin->sin_port;
1589 c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr; 1592 c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr;
1590 1593
1591 rt = find_route(c3cn->saddr.sin_addr.s_addr, 1594 rt = find_route(dev, c3cn->saddr.sin_addr.s_addr,
1592 c3cn->daddr.sin_addr.s_addr, 1595 c3cn->daddr.sin_addr.s_addr,
1593 c3cn->saddr.sin_port, 1596 c3cn->saddr.sin_port,
1594 c3cn->daddr.sin_port); 1597 c3cn->daddr.sin_port);
1595 if (rt == NULL) { 1598 if (rt == NULL) {
1596 c3cn_conn_debug("NO route to 0x%x, port %u.\n", 1599 c3cn_conn_debug("NO route to 0x%x, port %u, dev %s.\n",
1597 c3cn->daddr.sin_addr.s_addr, 1600 c3cn->daddr.sin_addr.s_addr,
1598 ntohs(c3cn->daddr.sin_port)); 1601 ntohs(c3cn->daddr.sin_port),
1602 dev ? dev->name : "any");
1599 return -ENETUNREACH; 1603 return -ENETUNREACH;
1600 } 1604 }
1601 1605
1602 if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { 1606 if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
1603 c3cn_conn_debug("multi-cast route to 0x%x, port %u.\n", 1607 c3cn_conn_debug("multi-cast route to 0x%x, port %u, dev %s.\n",
1604 c3cn->daddr.sin_addr.s_addr, 1608 c3cn->daddr.sin_addr.s_addr,
1605 ntohs(c3cn->daddr.sin_port)); 1609 ntohs(c3cn->daddr.sin_port),
1610 dev ? dev->name : "any");
1606 ip_rt_put(rt); 1611 ip_rt_put(rt);
1607 return -ENETUNREACH; 1612 return -ENETUNREACH;
1608 } 1613 }
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.h b/drivers/scsi/cxgb3i/cxgb3i_offload.h
index ebfca960c0a9..6a1d86b1fafe 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.h
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.h
@@ -169,7 +169,8 @@ void cxgb3i_sdev_add(struct t3cdev *, struct cxgb3_client *);
169void cxgb3i_sdev_remove(struct t3cdev *); 169void cxgb3i_sdev_remove(struct t3cdev *);
170 170
171struct s3_conn *cxgb3i_c3cn_create(void); 171struct s3_conn *cxgb3i_c3cn_create(void);
172int cxgb3i_c3cn_connect(struct s3_conn *, struct sockaddr_in *); 172int cxgb3i_c3cn_connect(struct net_device *, struct s3_conn *,
173 struct sockaddr_in *);
173void cxgb3i_c3cn_rx_credits(struct s3_conn *, int); 174void cxgb3i_c3cn_rx_credits(struct s3_conn *, int);
174int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *); 175int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *);
175void cxgb3i_c3cn_release(struct s3_conn *); 176void cxgb3i_c3cn_release(struct s3_conn *);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 0a2ce7b6325c..d69a53aa406f 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1268,26 +1268,54 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
1268 return err; 1268 return err;
1269} 1269}
1270 1270
1271static int iscsi_if_ep_connect(struct iscsi_transport *transport,
1272 struct iscsi_uevent *ev, int msg_type)
1273{
1274 struct iscsi_endpoint *ep;
1275 struct sockaddr *dst_addr;
1276 struct Scsi_Host *shost = NULL;
1277 int non_blocking, err = 0;
1278
1279 if (!transport->ep_connect)
1280 return -EINVAL;
1281
1282 if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) {
1283 shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no);
1284 if (!shost) {
1285 printk(KERN_ERR "ep connect failed. Could not find "
1286 "host no %u\n",
1287 ev->u.ep_connect_through_host.host_no);
1288 return -ENODEV;
1289 }
1290 non_blocking = ev->u.ep_connect_through_host.non_blocking;
1291 } else
1292 non_blocking = ev->u.ep_connect.non_blocking;
1293
1294 dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
1295 ep = transport->ep_connect(shost, dst_addr, non_blocking);
1296 if (IS_ERR(ep)) {
1297 err = PTR_ERR(ep);
1298 goto release_host;
1299 }
1300
1301 ev->r.ep_connect_ret.handle = ep->id;
1302release_host:
1303 if (shost)
1304 scsi_host_put(shost);
1305 return err;
1306}
1307
1271static int 1308static int
1272iscsi_if_transport_ep(struct iscsi_transport *transport, 1309iscsi_if_transport_ep(struct iscsi_transport *transport,
1273 struct iscsi_uevent *ev, int msg_type) 1310 struct iscsi_uevent *ev, int msg_type)
1274{ 1311{
1275 struct iscsi_endpoint *ep; 1312 struct iscsi_endpoint *ep;
1276 struct sockaddr *dst_addr;
1277 int rc = 0; 1313 int rc = 0;
1278 1314
1279 switch (msg_type) { 1315 switch (msg_type) {
1316 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
1280 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: 1317 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
1281 if (!transport->ep_connect) 1318 rc = iscsi_if_ep_connect(transport, ev, msg_type);
1282 return -EINVAL;
1283
1284 dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
1285 ep = transport->ep_connect(dst_addr,
1286 ev->u.ep_connect.non_blocking);
1287 if (IS_ERR(ep))
1288 return PTR_ERR(ep);
1289
1290 ev->r.ep_connect_ret.handle = ep->id;
1291 break; 1319 break;
1292 case ISCSI_UEVENT_TRANSPORT_EP_POLL: 1320 case ISCSI_UEVENT_TRANSPORT_EP_POLL:
1293 if (!transport->ep_poll) 1321 if (!transport->ep_poll)
@@ -1469,6 +1497,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1469 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: 1497 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
1470 case ISCSI_UEVENT_TRANSPORT_EP_POLL: 1498 case ISCSI_UEVENT_TRANSPORT_EP_POLL:
1471 case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: 1499 case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
1500 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
1472 err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); 1501 err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
1473 break; 1502 break;
1474 case ISCSI_UEVENT_TGT_DSCVR: 1503 case ISCSI_UEVENT_TGT_DSCVR:
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index d0ed5226f8c4..2c1a4af9eafb 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -50,7 +50,8 @@ enum iscsi_uevent_e {
50 ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15, 50 ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
51 ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16, 51 ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
52 ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17, 52 ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17,
53 ISCSI_UEVENT_CREATE_BOUND_SESSION = UEVENT_BASE + 18, 53 ISCSI_UEVENT_CREATE_BOUND_SESSION = UEVENT_BASE + 18,
54 ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST = UEVENT_BASE + 19,
54 55
55 /* up events */ 56 /* up events */
56 ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, 57 ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
@@ -131,6 +132,10 @@ struct iscsi_uevent {
131 struct msg_transport_connect { 132 struct msg_transport_connect {
132 uint32_t non_blocking; 133 uint32_t non_blocking;
133 } ep_connect; 134 } ep_connect;
135 struct msg_transport_connect_through_host {
136 uint32_t host_no;
137 uint32_t non_blocking;
138 } ep_connect_through_host;
134 struct msg_transport_poll { 139 struct msg_transport_poll {
135 uint64_t ep_handle; 140 uint64_t ep_handle;
136 uint32_t timeout_ms; 141 uint32_t timeout_ms;
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 457588e1119b..8cb7a31d9961 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -126,7 +126,8 @@ struct iscsi_transport {
126 int *index, int *age); 126 int *index, int *age);
127 127
128 void (*session_recovery_timedout) (struct iscsi_cls_session *session); 128 void (*session_recovery_timedout) (struct iscsi_cls_session *session);
129 struct iscsi_endpoint *(*ep_connect) (struct sockaddr *dst_addr, 129 struct iscsi_endpoint *(*ep_connect) (struct Scsi_Host *shost,
130 struct sockaddr *dst_addr,
130 int non_blocking); 131 int non_blocking);
131 int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms); 132 int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
132 void (*ep_disconnect) (struct iscsi_endpoint *ep); 133 void (*ep_disconnect) (struct iscsi_endpoint *ep);