* iscsi update for 2.6.31
@ 2009-05-13 22:57 michaelc
2009-05-13 22:57 ` [PATCH 01/13] iscsi: pass ep connect shost michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi
The following patches were made over scsi-rc-fixes. There
are fixes (no regressions) and features mixed in so the
patchset is for 2.6.31
The patches fix several bugs for the nop used as a iscsi ping
handling, add session binding for offload cards, and
add some of the last bits to prepare libiscsi for bnx2i
which looks like it has been ACKd by Dave Miller and just needs
a couple more clean ups on the iscsi side
(the only remaining core iscsi pieces for bnx2i is the netlink code
which is still being finalized).
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 01/13] iscsi: pass ep connect shost
2009-05-13 22:57 iscsi update for 2.6.31 michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 02/13] libiscsi: check of LLD has a alloc pdu callout michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
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>
---
drivers/infiniband/ulp/iser/iscsi_iser.c | 3 +-
drivers/scsi/cxgb3i/cxgb3i.h | 1 -
drivers/scsi/cxgb3i/cxgb3i_iscsi.c | 25 ++++++++++++--
drivers/scsi/cxgb3i/cxgb3i_offload.c | 23 ++++++++-----
drivers/scsi/cxgb3i/cxgb3i_offload.h | 3 +-
drivers/scsi/scsi_transport_iscsi.c | 51 +++++++++++++++++++++++------
include/scsi/iscsi_if.h | 7 +++-
include/scsi/scsi_transport_iscsi.h | 3 +-
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 75223f5..ffbe0c7 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
}
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;
struct iser_conn *ib_conn;
diff --git a/drivers/scsi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgb3i/cxgb3i.h
index 59b0958..e3133b5 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 *);
void cxgb3i_adapter_open(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 net_device *);
void cxgb3i_hba_host_remove(struct cxgb3i_hba *);
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index 9212400..04a4374 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)
* cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device
* @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;
int i;
@@ -261,20 +261,27 @@ void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba)
/**
* cxgb3i_ep_connect - establish TCP connection to target portal
+ * @shost: scsi host to use
* @dst_addr: target IP address
* @non_blocking: blocking or non-blocking call
*
* 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)
{
struct iscsi_endpoint *ep;
struct cxgb3i_endpoint *cep;
- struct cxgb3i_hba *hba;
+ struct cxgb3i_hba *hba = NULL;
struct s3_conn *c3cn = NULL;
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();
if (!c3cn) {
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;
}
- 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) {
cxgb3i_log_info("ep connect failed.\n");
goto release_conn;
}
+
hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev);
if (!hba) {
err = -ENOSPC;
cxgb3i_log_info("NOT going through cxgbi device.\n");
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)) {
err = -ENOSPC;
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 e11c9c1..c1d5be4 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,
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)
{
struct rtable *rt;
struct flowi fl = {
- .oif = 0,
+ .oif = dev ? dev->ifindex : 0,
.nl_u = {
.ip4_u = {
.daddr = daddr,
@@ -1573,36 +1574,40 @@ out_err:
*
* 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 net_device *dev;
struct cxgb3i_sdev_data *cdata;
struct t3cdev *cdev;
__be32 sipv4;
int err;
+ c3cn_conn_debug("c3cn 0x%p, dev 0x%p.\n", c3cn, dev);
+
if (usin->sin_family != AF_INET)
return -EAFNOSUPPORT;
c3cn->daddr.sin_port = usin->sin_port;
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->saddr.sin_port,
c3cn->daddr.sin_port);
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,
- ntohs(c3cn->daddr.sin_port));
+ ntohs(c3cn->daddr.sin_port),
+ dev ? dev->name : "any");
return -ENETUNREACH;
}
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,
- ntohs(c3cn->daddr.sin_port));
+ ntohs(c3cn->daddr.sin_port),
+ dev ? dev->name : "any");
ip_rt_put(rt);
return -ENETUNREACH;
}
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.h b/drivers/scsi/cxgb3i/cxgb3i_offload.h
index ebfca96..6a1d86b 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 *);
void cxgb3i_sdev_remove(struct t3cdev *);
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);
int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *);
void cxgb3i_c3cn_release(struct s3_conn *);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 0947954..858baff 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)
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
iscsi_if_transport_ep(struct iscsi_transport *transport,
struct iscsi_uevent *ev, int msg_type)
{
struct iscsi_endpoint *ep;
- struct sockaddr *dst_addr;
int rc = 0;
switch (msg_type) {
+ case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
- if (!transport->ep_connect)
- 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;
+ rc = iscsi_if_ep_connect(transport, ev, msg_type);
break;
case ISCSI_UEVENT_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_POLL:
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
+ case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
break;
case ISCSI_UEVENT_TGT_DSCVR:
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index d0ed522..2c1a4af 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -50,7 +50,8 @@ enum iscsi_uevent_e {
ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
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 */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
@@ -131,6 +132,10 @@ struct iscsi_uevent {
struct msg_transport_connect {
uint32_t non_blocking;
} ep_connect;
+ struct msg_transport_connect_through_host {
+ uint32_t host_no;
+ uint32_t non_blocking;
+ } ep_connect_through_host;
struct msg_transport_poll {
uint64_t ep_handle;
uint32_t timeout_ms;
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 457588e..8cb7a31 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -126,7 +126,8 @@ struct iscsi_transport {
int *index, int *age);
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 (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
void (*ep_disconnect) (struct iscsi_endpoint *ep);
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 02/13] libiscsi: check of LLD has a alloc pdu callout.
2009-05-13 22:57 ` [PATCH 01/13] iscsi: pass ep connect shost michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 03/13] libiscsi: handle param allocation failures michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
bnx2i does not have one. It currently preallocates the bdt
when the session is setup.
We probably want to change that to a dma pool, then allocate from
the pool in the alloc pdu. Until then check if there is a alloc
pdu callout.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 19 ++++++++++++-------
1 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index e72b4ad..11bc3e1 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -257,9 +257,11 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
itt_t itt;
int rc;
- rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
- if (rc)
- return rc;
+ if (conn->session->tt->alloc_pdu) {
+ rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
+ if (rc)
+ return rc;
+ }
hdr = (struct iscsi_cmd *) task->hdr;
itt = hdr->itt;
memset(hdr, 0, sizeof(*hdr));
@@ -566,11 +568,14 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
} else
task->data_count = 0;
- if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
- "pdu for mgmt task.\n");
- goto requeue_task;
+ if (conn->session->tt->alloc_pdu) {
+ if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
+ iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
+ "pdu for mgmt task.\n");
+ goto requeue_task;
+ }
}
+
itt = task->hdr->itt;
task->hdr_len = sizeof(struct iscsi_hdr);
memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr));
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 03/13] libiscsi: handle param allocation failures
2009-05-13 22:57 ` [PATCH 02/13] libiscsi: check of LLD has a alloc pdu callout michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 04/13] libiscsi: export iscsi_itt_to_task for bnx2i michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
If we could not allocate the initiator name or some other id like
the hwaddress or netdev, then userspace could deal with the failure
by just running in a dregraded mode.
Now we want to be able to switch values for the params and we
want some feedback, so this patch will check if a string like
the initiatorname could not be allocated and return an error.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 108 ++++++++++++++--------------------------------
1 files changed, 33 insertions(+), 75 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 11bc3e1..b4aaf2e 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2656,6 +2656,23 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
}
EXPORT_SYMBOL_GPL(iscsi_conn_bind);
+static int iscsi_switch_str_param(char **param, char *new_val_buf)
+{
+ char *new_val;
+
+ if (*param) {
+ if (!strcmp(*param, new_val_buf))
+ return 0;
+ }
+
+ new_val = kstrdup(new_val_buf, GFP_NOIO);
+ if (!new_val)
+ return -ENOMEM;
+
+ kfree(*param);
+ *param = new_val;
+ return 0;
+}
int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf, int buflen)
@@ -2728,38 +2745,15 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
sscanf(buf, "%u", &conn->exp_statsn);
break;
case ISCSI_PARAM_USERNAME:
- kfree(session->username);
- session->username = kstrdup(buf, GFP_KERNEL);
- if (!session->username)
- return -ENOMEM;
- break;
+ return iscsi_switch_str_param(&session->username, buf);
case ISCSI_PARAM_USERNAME_IN:
- kfree(session->username_in);
- session->username_in = kstrdup(buf, GFP_KERNEL);
- if (!session->username_in)
- return -ENOMEM;
- break;
+ return iscsi_switch_str_param(&session->username_in, buf);
case ISCSI_PARAM_PASSWORD:
- kfree(session->password);
- session->password = kstrdup(buf, GFP_KERNEL);
- if (!session->password)
- return -ENOMEM;
- break;
+ return iscsi_switch_str_param(&session->password, buf);
case ISCSI_PARAM_PASSWORD_IN:
- kfree(session->password_in);
- session->password_in = kstrdup(buf, GFP_KERNEL);
- if (!session->password_in)
- return -ENOMEM;
- break;
+ return iscsi_switch_str_param(&session->password_in, buf);
case ISCSI_PARAM_TARGET_NAME:
- /* this should not change between logins */
- if (session->targetname)
- break;
-
- session->targetname = kstrdup(buf, GFP_KERNEL);
- if (!session->targetname)
- return -ENOMEM;
- break;
+ return iscsi_switch_str_param(&session->targetname, buf);
case ISCSI_PARAM_TPGT:
sscanf(buf, "%d", &session->tpgt);
break;
@@ -2767,25 +2761,11 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
sscanf(buf, "%d", &conn->persistent_port);
break;
case ISCSI_PARAM_PERSISTENT_ADDRESS:
- /*
- * this is the address returned in discovery so it should
- * not change between logins.
- */
- if (conn->persistent_address)
- break;
-
- conn->persistent_address = kstrdup(buf, GFP_KERNEL);
- if (!conn->persistent_address)
- return -ENOMEM;
- break;
+ return iscsi_switch_str_param(&conn->persistent_address, buf);
case ISCSI_PARAM_IFACE_NAME:
- if (!session->ifacename)
- session->ifacename = kstrdup(buf, GFP_KERNEL);
- break;
+ return iscsi_switch_str_param(&session->ifacename, buf);
case ISCSI_PARAM_INITIATOR_NAME:
- if (!session->initiatorname)
- session->initiatorname = kstrdup(buf, GFP_KERNEL);
- break;
+ return iscsi_switch_str_param(&session->initiatorname, buf);
default:
return -ENOSYS;
}
@@ -2856,10 +2836,7 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
len = sprintf(buf, "%s\n", session->ifacename);
break;
case ISCSI_PARAM_INITIATOR_NAME:
- if (!session->initiatorname)
- len = sprintf(buf, "%s\n", "unknown");
- else
- len = sprintf(buf, "%s\n", session->initiatorname);
+ len = sprintf(buf, "%s\n", session->initiatorname);
break;
default:
return -ENOSYS;
@@ -2925,29 +2902,16 @@ int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
switch (param) {
case ISCSI_HOST_PARAM_NETDEV_NAME:
- if (!ihost->netdev)
- len = sprintf(buf, "%s\n", "default");
- else
- len = sprintf(buf, "%s\n", ihost->netdev);
+ len = sprintf(buf, "%s\n", ihost->netdev);
break;
case ISCSI_HOST_PARAM_HWADDRESS:
- if (!ihost->hwaddress)
- len = sprintf(buf, "%s\n", "default");
- else
- len = sprintf(buf, "%s\n", ihost->hwaddress);
+ len = sprintf(buf, "%s\n", ihost->hwaddress);
break;
case ISCSI_HOST_PARAM_INITIATOR_NAME:
- if (!ihost->initiatorname)
- len = sprintf(buf, "%s\n", "unknown");
- else
- len = sprintf(buf, "%s\n", ihost->initiatorname);
+ len = sprintf(buf, "%s\n", ihost->initiatorname);
break;
case ISCSI_HOST_PARAM_IPADDRESS:
- if (!strlen(ihost->local_address))
- len = sprintf(buf, "%s\n", "unknown");
- else
- len = sprintf(buf, "%s\n",
- ihost->local_address);
+ len = sprintf(buf, "%s\n", ihost->local_address);
break;
default:
return -ENOSYS;
@@ -2964,17 +2928,11 @@ int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
switch (param) {
case ISCSI_HOST_PARAM_NETDEV_NAME:
- if (!ihost->netdev)
- ihost->netdev = kstrdup(buf, GFP_KERNEL);
- break;
+ return iscsi_switch_str_param(&ihost->netdev, buf);
case ISCSI_HOST_PARAM_HWADDRESS:
- if (!ihost->hwaddress)
- ihost->hwaddress = kstrdup(buf, GFP_KERNEL);
- break;
+ return iscsi_switch_str_param(&ihost->hwaddress, buf);
case ISCSI_HOST_PARAM_INITIATOR_NAME:
- if (!ihost->initiatorname)
- ihost->initiatorname = kstrdup(buf, GFP_KERNEL);
- break;
+ return iscsi_switch_str_param(&ihost->initiatorname, buf);
default:
return -ENOSYS;
}
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 04/13] libiscsi: export iscsi_itt_to_task for bnx2i
2009-05-13 22:57 ` [PATCH 03/13] libiscsi: handle param allocation failures michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 05/13] libiscsi: have iscsi_data_in_rsp call iscsi_update_cmdsn michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
bnx2i needs to be able to look up mgmt task like login and nop, because
it does some processing of them on the completion path. This exports
iscsi_itt_to_task so it can look up the task.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 3 ++-
include/scsi/libiscsi.h | 1 +
2 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index b4aaf2e..a6e6eef 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -828,7 +828,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
*
* The session lock must be held.
*/
-static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
+struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
{
struct iscsi_session *session = conn->session;
int i;
@@ -845,6 +845,7 @@ static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
return session->cmds[i];
}
+EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
/**
* __iscsi_complete_pdu - complete pdu
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 0289f57..88d33a4 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -406,6 +406,7 @@ extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
char *, int);
extern int iscsi_verify_itt(struct iscsi_conn *, itt_t);
extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t);
+extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t);
extern void iscsi_requeue_task(struct iscsi_task *task);
extern void iscsi_put_task(struct iscsi_task *task);
extern void __iscsi_get_task(struct iscsi_task *task);
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 05/13] libiscsi: have iscsi_data_in_rsp call iscsi_update_cmdsn
2009-05-13 22:57 ` [PATCH 04/13] libiscsi: export iscsi_itt_to_task for bnx2i michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 06/13] libiscsi: fix nop response/reply and session cleanup race michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
This has iscsi_data_in_rsp call iscsi_update_cmdsn when a pdu is
completed like is done for other pdu's that are don.
For libiscsi_tcp, this means that it calls iscsi_update_cmdsn when
it is handling the pdu internally to only transfer data, but if there is
status then it does not need to call it since the completion handling
will do it.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 1 +
drivers/scsi/libiscsi_tcp.c | 8 +++++++-
2 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index a6e6eef..047543c 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -729,6 +729,7 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
return;
+ iscsi_update_cmdsn(conn->session, (struct iscsi_nopin *)hdr);
sc->result = (DID_OK << 16) | rhdr->cmd_status;
conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index b579ca9..db93cd0 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -473,7 +473,13 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
int datasn = be32_to_cpu(rhdr->datasn);
unsigned total_in_length = scsi_in(task->sc)->length;
- iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
+ /*
+ * lib iscsi will update this in the completion handling if there
+ * is status.
+ */
+ if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
+ iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
+
if (tcp_conn->in.datalen == 0)
return 0;
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 06/13] libiscsi: fix nop response/reply and session cleanup race
2009-05-13 22:57 ` [PATCH 05/13] libiscsi: have iscsi_data_in_rsp call iscsi_update_cmdsn michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 07/13] libiscsi_tcp: update recv tracking for each skb instead of iscsi pdu michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
If we are responding to a nop from the target by sending our nop,
and the session is getting torn down, then iscsi_start_session_recovery
could set the conn stop bits while the recv path is sending the nop
response and we will hit the bug ons in __iscsi_conn_send_pdu.
This has us check the state in __iscsi_conn_send_pdu and fail all
incoming mgmt IO if we are not logged in and if the pdu is not login
related. It also changes the ordering of the setting of conn stop state
bits so they are set after the session state is set (both are set under
the session lock).
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 047543c..212fe20 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -546,6 +546,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
*/
task = conn->login_task;
else {
+ if (session->state != ISCSI_STATE_LOGGED_IN)
+ return NULL;
+
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
@@ -2566,8 +2569,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
{
int old_stop_stage;
- del_timer_sync(&conn->transport_timer);
-
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
if (conn->stop_stage == STOP_CONN_TERM) {
@@ -2585,13 +2586,17 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
session->state = ISCSI_STATE_TERMINATE;
else if (conn->stop_stage != STOP_CONN_RECOVER)
session->state = ISCSI_STATE_IN_RECOVERY;
+ spin_unlock_bh(&session->lock);
+ del_timer_sync(&conn->transport_timer);
+ iscsi_suspend_tx(conn);
+
+ spin_lock_bh(&session->lock);
old_stop_stage = conn->stop_stage;
conn->stop_stage = flag;
conn->c_stage = ISCSI_CONN_STOPPED;
spin_unlock_bh(&session->lock);
- iscsi_suspend_tx(conn);
/*
* for connection level recovery we should not calculate
* header digest. conn->hdr_size used for optimization
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 07/13] libiscsi_tcp: update recv tracking for each skb instead of iscsi pdu
2009-05-13 22:57 ` [PATCH 06/13] libiscsi: fix nop response/reply and session cleanup race michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 08/13] libiscsi: fix iscsi transport checks to account for slower links michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
Everytime we read in a pdu libiscsi will update a tracking field.
It uses this to decide when to check if the transport might be bad.
If we have not got data in recv_timeout seconds then we will
send a iscsi ping/nop.
If we are on a slow link then it could take a while to read in all
the data for a data_in. In that case we might send a ping/nop when
we do not need to or we might drop a session thinking it is bad
when the lower layer is making forward progress on it.
This patch has libiscsi_tcp update the recv tracking for each skb
(basically network packet from our point of view) instead of the
entire iscsi pdu+data, so we account for these cases where data is
coming in slowly.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi_tcp.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index db93cd0..b84a1d8 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -863,6 +863,12 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
int rc = 0;
ISCSI_DBG_TCP(conn, "in %d bytes\n", skb->len - offset);
+ /*
+ * Update for each skb instead of pdu, because over slow networks a
+ * data_in's data could take a while to read in. We also want to
+ * account for r2ts.
+ */
+ conn->last_recv = jiffies;
if (unlikely(conn->suspend_rx)) {
ISCSI_DBG_TCP(conn, "Rx suspended!\n");
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 08/13] libiscsi: fix iscsi transport checks to account for slower links
2009-05-13 22:57 ` [PATCH 07/13] libiscsi_tcp: update recv tracking for each skb instead of iscsi pdu michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 09/13] libiscsi: handle cleanup task races michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
If we have not got any pdus for recv_timeout seconds, then we will
send a iscsi ping/nop to make sure the target is still around. The
problem is if this is a slow link, and the ping got queued after
the data for a data_out (read), then the transport code could think
the ping has failed when it is just slowly making its way through
the network. This patch has us check if we are making progress while
the nop is outstanding. If we are still reading in data, then we
do not fail the session at that time.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 38 +++++++++++++++++++++++++++++---------
1 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 212fe20..c648bd3 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1677,6 +1677,22 @@ static void iscsi_start_tx(struct iscsi_conn *conn)
iscsi_conn_queue_work(conn);
}
+/*
+ * We want to make sure a ping is in flight. It has timed out.
+ * And we are not busy processing a pdu that is making
+ * progress but got started before the ping and is taking a while
+ * to complete so the ping is just stuck behind it in a queue.
+ */
+static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
+{
+ if (conn->ping_task &&
+ time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
+ (conn->ping_timeout * HZ), jiffies))
+ return 1;
+ else
+ return 0;
+}
+
static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
{
struct iscsi_cls_session *cls_session;
@@ -1712,16 +1728,20 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
* if the ping timedout then we are in the middle of cleaning up
* and can let the iscsi eh handle it
*/
- if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
- (conn->ping_timeout * HZ), jiffies))
+ if (iscsi_has_ping_timed_out(conn)) {
rc = BLK_EH_RESET_TIMER;
+ goto done;
+ }
/*
* if we are about to check the transport then give the command
* more time
*/
if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
- jiffies))
+ jiffies)) {
rc = BLK_EH_RESET_TIMER;
+ goto done;
+ }
+
/* if in the middle of checking the transport then give us more time */
if (conn->ping_task)
rc = BLK_EH_RESET_TIMER;
@@ -1748,13 +1768,13 @@ static void iscsi_check_transport_timeouts(unsigned long data)
recv_timeout *= HZ;
last_recv = conn->last_recv;
- if (conn->ping_task &&
- time_before_eq(conn->last_ping + (conn->ping_timeout * HZ),
- jiffies)) {
+
+ if (iscsi_has_ping_timed_out(conn)) {
iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
- "expired, last rx %lu, last ping %lu, "
- "now %lu\n", conn->ping_timeout, last_recv,
- conn->last_ping, jiffies);
+ "expired, recv timeout %d, last rx %lu, "
+ "last ping %lu, now %lu\n",
+ conn->ping_timeout, conn->recv_timeout,
+ last_recv, conn->last_ping, jiffies);
spin_unlock(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return;
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 09/13] libiscsi: handle cleanup task races
2009-05-13 22:57 ` [PATCH 08/13] libiscsi: fix iscsi transport checks to account for slower links michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 10/13] libiscsi: don't let io sit in queue when session has failed michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
bnx2i needs to send a hardware specific cleanup command if
a command has not completed normally (iscsi/scsi response from
target), and the session is still ok (this is the case when we
send a TMF to stop the command).
At this time it will need to drop the session lock. The problem
with the current code is that fail_all_commands assumes we
will hold the lock the entire time, so it uses list_for_each_entry_safe.
If while bnx2i drops the session lock multiple cmds complete then
list_for_each_entry_safe will not handle this correctly.
This patch removes the running lists and just has us loop over
the cmds array (in later patches we will then replace that
array with a block tag map at the session level). It also fixes
up the completion path so that if the TMF code and the normal recv
path were completing the same command then they both do not try
to do release the refcount taken when the task is queued.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 225 ++++++++++++++++++++++++-----------------------
include/scsi/libiscsi.h | 5 +-
2 files changed, 118 insertions(+), 112 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index c648bd3..a9d7e52 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -109,7 +109,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
* if the window closed with IO queued, then kick the
* xmit thread
*/
- if (!list_empty(&session->leadconn->xmitqueue) ||
+ if (!list_empty(&session->leadconn->cmdqueue) ||
!list_empty(&session->leadconn->mgmtqueue)) {
if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
iscsi_conn_queue_work(session->leadconn);
@@ -366,7 +366,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
return -EIO;
task->state = ISCSI_TASK_RUNNING;
- list_move_tail(&task->running, &conn->run_list);
conn->scsicmd_pdus_cnt++;
ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x "
@@ -382,26 +381,23 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
}
/**
- * iscsi_complete_command - finish a task
+ * iscsi_free_task - free a task
* @task: iscsi cmd task
*
* Must be called with session lock.
* This function returns the scsi command to scsi-ml or cleans
* up mgmt tasks then returns the task to the pool.
*/
-static void iscsi_complete_command(struct iscsi_task *task)
+static void iscsi_free_task(struct iscsi_task *task)
{
struct iscsi_conn *conn = task->conn;
struct iscsi_session *session = conn->session;
struct scsi_cmnd *sc = task->sc;
session->tt->cleanup_task(task);
- list_del_init(&task->running);
- task->state = ISCSI_TASK_COMPLETED;
+ task->state = ISCSI_TASK_FREE;
task->sc = NULL;
- if (conn->task == task)
- conn->task = NULL;
/*
* login task is preallocated so do not free
*/
@@ -410,9 +406,6 @@ static void iscsi_complete_command(struct iscsi_task *task)
__kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
- if (conn->ping_task == task)
- conn->ping_task = NULL;
-
if (sc) {
task->sc = NULL;
/* SCSI eh reuses commands to verify us */
@@ -435,7 +428,7 @@ EXPORT_SYMBOL_GPL(__iscsi_get_task);
static void __iscsi_put_task(struct iscsi_task *task)
{
if (atomic_dec_and_test(&task->refcount))
- iscsi_complete_command(task);
+ iscsi_free_task(task);
}
void iscsi_put_task(struct iscsi_task *task)
@@ -448,14 +441,50 @@ void iscsi_put_task(struct iscsi_task *task)
}
EXPORT_SYMBOL_GPL(iscsi_put_task);
+/**
+ * iscsi_complete_task - finish a task
+ * @task: iscsi cmd task
+ *
+ * Must be called with session lock.
+ */
+static void iscsi_complete_task(struct iscsi_task *task)
+{
+ struct iscsi_conn *conn = task->conn;
+
+ if (task->state == ISCSI_TASK_COMPLETED)
+ return;
+ WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
+
+ task->state = ISCSI_TASK_COMPLETED;
+
+ if (!list_empty(&task->running))
+ list_del_init(&task->running);
+
+ if (conn->task == task)
+ conn->task = NULL;
+
+ if (conn->ping_task == task)
+ conn->ping_task = NULL;
+
+ /* release get from queueing */
+ __iscsi_put_task(task);
+}
+
/*
- * session lock must be held
+ * session lock must be held and if not called for a task that is
+ * still pending or from the xmit thread, then xmit thread must
+ * be suspended.
*/
-static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
- int err)
+static void fail_scsi_task(struct iscsi_task *task, int err)
{
+ struct iscsi_conn *conn = task->conn;
struct scsi_cmnd *sc;
+ /*
+ * if a command completes and we get a successful tmf response
+ * we will hit this because the scsi eh abort code does not take
+ * a ref to the task.
+ */
sc = task->sc;
if (!sc)
return;
@@ -475,10 +504,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
scsi_in(sc)->resid = scsi_in(sc)->length;
}
- if (conn->task == task)
- conn->task = NULL;
- /* release ref from queuecommand */
- __iscsi_put_task(task);
+ iscsi_complete_task(task);
}
static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
@@ -518,7 +544,6 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
session->state = ISCSI_STATE_LOGGING_OUT;
task->state = ISCSI_TASK_RUNNING;
- list_move_tail(&task->running, &conn->mgmt_run_list);
ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x "
"datalen %d]\n", hdr->opcode & ISCSI_OPCODE_MASK,
hdr->itt, task->data_count);
@@ -564,6 +589,8 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
atomic_set(&task->refcount, 1);
task->conn = conn;
task->sc = NULL;
+ INIT_LIST_HEAD(&task->running);
+ task->state = ISCSI_TASK_PENDING;
if (data_size) {
memcpy(task->data, data, data_size);
@@ -575,7 +602,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
"pdu for mgmt task.\n");
- goto requeue_task;
+ goto free_task;
}
}
@@ -591,30 +618,22 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
task->conn->session->age);
}
- INIT_LIST_HEAD(&task->running);
- list_add_tail(&task->running, &conn->mgmtqueue);
-
if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
if (iscsi_prep_mgmt_task(conn, task))
goto free_task;
if (session->tt->xmit_task(task))
goto free_task;
-
- } else
+ } else {
+ list_add_tail(&task->running, &conn->mgmtqueue);
iscsi_conn_queue_work(conn);
+ }
return task;
free_task:
__iscsi_put_task(task);
return NULL;
-
-requeue_task:
- if (task != conn->login_task)
- __kfifo_put(session->cmdpool.queue, (void*)&task,
- sizeof(void*));
- return NULL;
}
int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
@@ -709,11 +728,10 @@ invalid_datalen:
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
}
out:
- ISCSI_DBG_SESSION(session, "done [sc %p res %d itt 0x%x]\n",
+ ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n",
sc, sc->result, task->itt);
conn->scsirsp_pdus_cnt++;
-
- __iscsi_put_task(task);
+ iscsi_complete_task(task);
}
/**
@@ -747,8 +765,11 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
}
+ ISCSI_DBG_SESSION(conn->session, "data in with status done "
+ "[sc %p res %d itt 0x%x]\n",
+ sc, sc->result, task->itt);
conn->scsirsp_pdus_cnt++;
- __iscsi_put_task(task);
+ iscsi_complete_task(task);
}
static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
@@ -969,7 +990,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
}
iscsi_tmf_rsp(conn, hdr);
- __iscsi_put_task(task);
+ iscsi_complete_task(task);
break;
case ISCSI_OP_NOOP_IN:
iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
@@ -987,7 +1008,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
goto recv_pdu;
mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
- __iscsi_put_task(task);
+ iscsi_complete_task(task);
break;
default:
rc = ISCSI_ERR_BAD_OPCODE;
@@ -999,7 +1020,7 @@ out:
recv_pdu:
if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
rc = ISCSI_ERR_CONN_FAILED;
- __iscsi_put_task(task);
+ iscsi_complete_task(task);
return rc;
}
EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
@@ -1176,7 +1197,12 @@ void iscsi_requeue_task(struct iscsi_task *task)
{
struct iscsi_conn *conn = task->conn;
- list_move_tail(&task->running, &conn->requeue);
+ /*
+ * this may be on the requeue list already if the xmit_task callout
+ * is handling the r2ts while we are adding new ones
+ */
+ if (list_empty(&task->running))
+ list_add_tail(&task->running, &conn->requeue);
iscsi_conn_queue_work(conn);
}
EXPORT_SYMBOL_GPL(iscsi_requeue_task);
@@ -1216,6 +1242,7 @@ check_mgmt:
while (!list_empty(&conn->mgmtqueue)) {
conn->task = list_entry(conn->mgmtqueue.next,
struct iscsi_task, running);
+ list_del_init(&conn->task->running);
if (iscsi_prep_mgmt_task(conn, conn->task)) {
__iscsi_put_task(conn->task);
conn->task = NULL;
@@ -1227,23 +1254,26 @@ check_mgmt:
}
/* process pending command queue */
- while (!list_empty(&conn->xmitqueue)) {
+ while (!list_empty(&conn->cmdqueue)) {
if (conn->tmf_state == TMF_QUEUED)
break;
- conn->task = list_entry(conn->xmitqueue.next,
+ conn->task = list_entry(conn->cmdqueue.next,
struct iscsi_task, running);
+ list_del_init(&conn->task->running);
if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
- fail_command(conn, conn->task, DID_IMM_RETRY << 16);
+ fail_scsi_task(conn->task, DID_IMM_RETRY << 16);
continue;
}
rc = iscsi_prep_scsi_cmd_pdu(conn->task);
if (rc) {
if (rc == -ENOMEM) {
+ list_add_tail(&conn->task->running,
+ &conn->cmdqueue);
conn->task = NULL;
goto again;
} else
- fail_command(conn, conn->task, DID_ABORT << 16);
+ fail_scsi_task(conn->task, DID_ABORT << 16);
continue;
}
rc = iscsi_xmit_task(conn);
@@ -1270,8 +1300,8 @@ check_mgmt:
conn->task = list_entry(conn->requeue.next,
struct iscsi_task, running);
+ list_del_init(&conn->task->running);
conn->task->state = ISCSI_TASK_RUNNING;
- list_move_tail(conn->requeue.next, &conn->run_list);
rc = iscsi_xmit_task(conn);
if (rc)
goto again;
@@ -1412,7 +1442,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
reason = FAILURE_OOM;
goto reject;
}
- list_add_tail(&task->running, &conn->xmitqueue);
if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
reason = iscsi_prep_scsi_cmd_pdu(task);
@@ -1429,8 +1458,10 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
reason = FAILURE_SESSION_NOT_READY;
goto prepd_reject;
}
- } else
+ } else {
+ list_add_tail(&task->running, &conn->cmdqueue);
iscsi_conn_queue_work(conn);
+ }
session->queued_cmdsn++;
spin_unlock(&session->lock);
@@ -1439,7 +1470,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
prepd_reject:
sc->scsi_done = NULL;
- iscsi_complete_command(task);
+ iscsi_complete_task(task);
reject:
spin_unlock(&session->lock);
ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
@@ -1449,7 +1480,7 @@ reject:
prepd_fault:
sc->scsi_done = NULL;
- iscsi_complete_command(task);
+ iscsi_complete_task(task);
fault:
spin_unlock(&session->lock);
ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
@@ -1618,44 +1649,24 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
* Fail commands. session lock held and recv side suspended and xmit
* thread flushed
*/
-static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
- int error)
+static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
+ int error)
{
- struct iscsi_task *task, *tmp;
-
- if (conn->task) {
- if (lun == -1 ||
- (conn->task->sc && conn->task->sc->device->lun == lun))
- conn->task = NULL;
- }
+ struct iscsi_task *task;
+ int i;
- /* flush pending */
- list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) {
- if (lun == task->sc->device->lun || lun == -1) {
- ISCSI_DBG_SESSION(conn->session,
- "failing pending sc %p itt 0x%x\n",
- task->sc, task->itt);
- fail_command(conn, task, error << 16);
- }
- }
+ for (i = 0; i < conn->session->cmds_max; i++) {
+ task = conn->session->cmds[i];
+ if (!task->sc || task->state == ISCSI_TASK_FREE)
+ continue;
- list_for_each_entry_safe(task, tmp, &conn->requeue, running) {
- if (lun == task->sc->device->lun || lun == -1) {
- ISCSI_DBG_SESSION(conn->session,
- "failing requeued sc %p itt 0x%x\n",
- task->sc, task->itt);
- fail_command(conn, task, error << 16);
- }
- }
+ if (lun != -1 && lun != task->sc->device->lun)
+ continue;
- /* fail all other running */
- list_for_each_entry_safe(task, tmp, &conn->run_list, running) {
- if (lun == task->sc->device->lun || lun == -1) {
- ISCSI_DBG_SESSION(conn->session,
- "failing in progress sc %p itt 0x%x\n",
- task->sc, task->itt);
- fail_command(conn, task, error << 16);
- }
+ ISCSI_DBG_SESSION(conn->session,
+ "failing sc %p itt 0x%x state %d\n",
+ task->sc, task->itt, task->state);
+ fail_scsi_task(task, error << 16);
}
}
@@ -1859,7 +1870,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
}
if (task->state == ISCSI_TASK_PENDING) {
- fail_command(conn, task, DID_ABORT << 16);
+ fail_scsi_task(task, DID_ABORT << 16);
goto success;
}
@@ -1890,7 +1901,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
* then sent more data for the cmd.
*/
spin_lock(&session->lock);
- fail_command(conn, task, DID_ABORT << 16);
+ fail_scsi_task(task, DID_ABORT << 16);
conn->tmf_state = TMF_INITIAL;
spin_unlock(&session->lock);
iscsi_start_tx(conn);
@@ -1997,7 +2008,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
iscsi_suspend_tx(conn);
spin_lock_bh(&session->lock);
- fail_all_commands(conn, sc->device->lun, DID_ERROR);
+ fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
conn->tmf_state = TMF_INITIAL;
spin_unlock_bh(&session->lock);
@@ -2304,6 +2315,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
if (cmd_task_size)
task->dd_data = &task[1];
task->itt = cmd_i;
+ task->state = ISCSI_TASK_FREE;
INIT_LIST_HEAD(&task->running);
}
@@ -2390,10 +2402,8 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
conn->transport_timer.data = (unsigned long)conn;
conn->transport_timer.function = iscsi_check_transport_timeouts;
- INIT_LIST_HEAD(&conn->run_list);
- INIT_LIST_HEAD(&conn->mgmt_run_list);
INIT_LIST_HEAD(&conn->mgmtqueue);
- INIT_LIST_HEAD(&conn->xmitqueue);
+ INIT_LIST_HEAD(&conn->cmdqueue);
INIT_LIST_HEAD(&conn->requeue);
INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
@@ -2561,27 +2571,24 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
EXPORT_SYMBOL_GPL(iscsi_conn_start);
static void
-flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
+fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
{
- struct iscsi_task *task, *tmp;
+ struct iscsi_task *task;
+ int i;
- /* handle pending */
- list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) {
- ISCSI_DBG_SESSION(session, "flushing pending mgmt task "
- "itt 0x%x\n", task->itt);
- /* release ref from prep task */
- __iscsi_put_task(task);
- }
+ for (i = 0; i < conn->session->cmds_max; i++) {
+ task = conn->session->cmds[i];
+ if (task->sc)
+ continue;
- /* handle running */
- list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) {
- ISCSI_DBG_SESSION(session, "flushing running mgmt task "
- "itt 0x%x\n", task->itt);
- /* release ref from prep task */
- __iscsi_put_task(task);
- }
+ if (task->state == ISCSI_TASK_FREE)
+ continue;
- conn->task = NULL;
+ ISCSI_DBG_SESSION(conn->session,
+ "failing mgmt itt 0x%x state %d\n",
+ task->itt, task->state);
+ iscsi_complete_task(task);
+ }
}
static void iscsi_start_session_recovery(struct iscsi_session *session,
@@ -2638,10 +2645,10 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
*/
spin_lock_bh(&session->lock);
if (flag == STOP_CONN_RECOVER)
- fail_all_commands(conn, -1, DID_TRANSPORT_DISRUPTED);
+ fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
else
- fail_all_commands(conn, -1, DID_ERROR);
- flush_control_queues(session, conn);
+ fail_scsi_tasks(conn, -1, DID_ERROR);
+ fail_mgmt_tasks(session, conn);
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
}
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 88d33a4..facae71 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -82,6 +82,7 @@ enum {
enum {
+ ISCSI_TASK_FREE,
ISCSI_TASK_COMPLETED,
ISCSI_TASK_PENDING,
ISCSI_TASK_RUNNING,
@@ -181,9 +182,7 @@ struct iscsi_conn {
/* xmit */
struct list_head mgmtqueue; /* mgmt (control) xmit queue */
- struct list_head mgmt_run_list; /* list of control tasks */
- struct list_head xmitqueue; /* data-path cmd queue */
- struct list_head run_list; /* list of cmds in progress */
+ struct list_head cmdqueue; /* data-path cmd queue */
struct list_head requeue; /* tasks needing another run */
struct work_struct xmitwork; /* per-conn. xmit workqueue */
unsigned long suspend_tx; /* suspend Tx */
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 10/13] libiscsi: don't let io sit in queue when session has failed
2009-05-13 22:57 ` [PATCH 09/13] libiscsi: handle cleanup task races michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 11/13] libiscsi: check if iscsi host has work queue before queueing work michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
If the session is failed, but we have not yet fully transitioned
to the recovery stage we were still queueuing IO. The idea is
that for some failures we can recvover at the command level
and still continue to execute other IO. Well, we never have
added the recovery within a command code, so queueing up IO here
just creates the possibility that it might time time out so
this just has us requeue the IO the scsi layer for now.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 15 ++++++---------
1 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index a9d7e52..57eb3af 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1390,13 +1390,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
goto fault;
}
- /*
- * ISCSI_STATE_FAILED is a temp. state. The recovery
- * code will decide what is best to do with command queued
- * during this time
- */
- if (session->state != ISCSI_STATE_LOGGED_IN &&
- session->state != ISCSI_STATE_FAILED) {
+ if (session->state != ISCSI_STATE_LOGGED_IN) {
/*
* to handle the race between when we set the recovery state
* and block the session we requeue here (commands could
@@ -1404,12 +1398,15 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
* up because the block code is not locked)
*/
switch (session->state) {
+ case ISCSI_STATE_FAILED:
case ISCSI_STATE_IN_RECOVERY:
reason = FAILURE_SESSION_IN_RECOVERY;
- goto reject;
+ sc->result = DID_IMM_RETRY << 16;
+ break;
case ISCSI_STATE_LOGGING_OUT:
reason = FAILURE_SESSION_LOGGING_OUT;
- goto reject;
+ sc->result = DID_IMM_RETRY << 16;
+ break;
case ISCSI_STATE_RECOVERY_FAILED:
reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
sc->result = DID_TRANSPORT_FAILFAST << 16;
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 11/13] libiscsi: check if iscsi host has work queue before queueing work
2009-05-13 22:57 ` [PATCH 10/13] libiscsi: don't let io sit in queue when session has failed michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 12/13] libiscsi: add task aborted state michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
Instead of having libiscsi check if the offload bit is set, have
it check if the lld created a work queue. I think this is more
clear.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 21 +++++++++++----------
1 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 57eb3af..dafa054 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -81,7 +81,8 @@ inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
struct Scsi_Host *shost = conn->session->host;
struct iscsi_host *ihost = shost_priv(shost);
- queue_work(ihost->workq, &conn->xmitwork);
+ if (ihost->workq)
+ queue_work(ihost->workq, &conn->xmitwork);
}
EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
@@ -110,10 +111,8 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
* xmit thread
*/
if (!list_empty(&session->leadconn->cmdqueue) ||
- !list_empty(&session->leadconn->mgmtqueue)) {
- if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
- iscsi_conn_queue_work(session->leadconn);
- }
+ !list_empty(&session->leadconn->mgmtqueue))
+ iscsi_conn_queue_work(session->leadconn);
}
}
EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
@@ -555,6 +554,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
char *data, uint32_t data_size)
{
struct iscsi_session *session = conn->session;
+ struct iscsi_host *ihost = shost_priv(session->host);
struct iscsi_task *task;
itt_t itt;
@@ -618,7 +618,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
task->conn->session->age);
}
- if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
+ if (!ihost->workq) {
if (iscsi_prep_mgmt_task(conn, task))
goto free_task;
@@ -1368,6 +1368,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
{
struct iscsi_cls_session *cls_session;
struct Scsi_Host *host;
+ struct iscsi_host *ihost;
int reason = 0;
struct iscsi_session *session;
struct iscsi_conn *conn;
@@ -1378,6 +1379,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
sc->SCp.ptr = NULL;
host = sc->device->host;
+ ihost = shost_priv(host);
spin_unlock(host->host_lock);
cls_session = starget_to_session(scsi_target(sc->device));
@@ -1440,7 +1442,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
goto reject;
}
- if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
+ if (!ihost->workq) {
reason = iscsi_prep_scsi_cmd_pdu(task);
if (reason) {
if (reason == -ENOMEM) {
@@ -1673,7 +1675,7 @@ void iscsi_suspend_tx(struct iscsi_conn *conn)
struct iscsi_host *ihost = shost_priv(shost);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
+ if (ihost->workq)
flush_workqueue(ihost->workq);
}
EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
@@ -1681,8 +1683,7 @@ EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
static void iscsi_start_tx(struct iscsi_conn *conn)
{
clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
- iscsi_conn_queue_work(conn);
+ iscsi_conn_queue_work(conn);
}
/*
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 12/13] libiscsi: add task aborted state
2009-05-13 22:57 ` [PATCH 11/13] libiscsi: check if iscsi host has work queue before queueing work michaelc
@ 2009-05-13 22:57 ` michaelc
2009-05-13 22:57 ` [PATCH 13/13] libiscsi: add debug printks for iscsi command completion path michaelc
0 siblings, 1 reply; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
If a task did not complete normally due to a TMF, libiscsi will
now complete the task with the state ISCSI_TASK_ABRT_TMF. Drivers
like bnx2i that need to free resources if a command did not complete normally
can then check the task state. If a driver does not need to send
a special command if we have dropped the session then they can check
for ISCSI_TASK_ABRT_SESS_RECOV.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/infiniband/ulp/iser/iscsi_iser.c | 7 +--
drivers/scsi/libiscsi.c | 60 +++++++++++++++++------------
drivers/scsi/libiscsi_tcp.c | 4 +-
include/scsi/libiscsi.h | 2 +
4 files changed, 41 insertions(+), 32 deletions(-)
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index ffbe0c7..0ba6ec8 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -257,11 +257,8 @@ static void iscsi_iser_cleanup_task(struct iscsi_task *task)
{
struct iscsi_iser_task *iser_task = task->dd_data;
- /*
- * mgmt tasks do not need special cleanup and we do not
- * allocate anything in the init task callout
- */
- if (!task->sc || task->state == ISCSI_TASK_PENDING)
+ /* mgmt tasks do not need special cleanup */
+ if (!task->sc)
return;
if (iser_task->status == ISER_TASK_STATUS_STARTED) {
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index dafa054..b00be6c 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -443,18 +443,20 @@ EXPORT_SYMBOL_GPL(iscsi_put_task);
/**
* iscsi_complete_task - finish a task
* @task: iscsi cmd task
+ * @state: state to complete task with
*
* Must be called with session lock.
*/
-static void iscsi_complete_task(struct iscsi_task *task)
+static void iscsi_complete_task(struct iscsi_task *task, int state)
{
struct iscsi_conn *conn = task->conn;
- if (task->state == ISCSI_TASK_COMPLETED)
+ if (task->state == ISCSI_TASK_COMPLETED ||
+ task->state == ISCSI_TASK_ABRT_TMF ||
+ task->state == ISCSI_TASK_ABRT_SESS_RECOV)
return;
WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
-
- task->state = ISCSI_TASK_COMPLETED;
+ task->state = state;
if (!list_empty(&task->running))
list_del_init(&task->running);
@@ -478,6 +480,7 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
{
struct iscsi_conn *conn = task->conn;
struct scsi_cmnd *sc;
+ int state;
/*
* if a command completes and we get a successful tmf response
@@ -488,14 +491,20 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
if (!sc)
return;
- if (task->state == ISCSI_TASK_PENDING)
+ if (task->state == ISCSI_TASK_PENDING) {
/*
* cmd never made it to the xmit thread, so we should not count
* the cmd in the sequencing
*/
conn->session->queued_cmdsn--;
+ /* it was never sent so just complete like normal */
+ state = ISCSI_TASK_COMPLETED;
+ } else if (err == DID_TRANSPORT_DISRUPTED)
+ state = ISCSI_TASK_ABRT_SESS_RECOV;
+ else
+ state = ISCSI_TASK_ABRT_TMF;
- sc->result = err;
+ sc->result = err << 16;
if (!scsi_bidi_cmnd(sc))
scsi_set_resid(sc, scsi_bufflen(sc));
else {
@@ -503,7 +512,7 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
scsi_in(sc)->resid = scsi_in(sc)->length;
}
- iscsi_complete_task(task);
+ iscsi_complete_task(task, state);
}
static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
@@ -731,7 +740,7 @@ out:
ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n",
sc, sc->result, task->itt);
conn->scsirsp_pdus_cnt++;
- iscsi_complete_task(task);
+ iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
}
/**
@@ -769,7 +778,7 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
"[sc %p res %d itt 0x%x]\n",
sc, sc->result, task->itt);
conn->scsirsp_pdus_cnt++;
- iscsi_complete_task(task);
+ iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
}
static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
@@ -990,7 +999,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
}
iscsi_tmf_rsp(conn, hdr);
- iscsi_complete_task(task);
+ iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
break;
case ISCSI_OP_NOOP_IN:
iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
@@ -1008,7 +1017,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
goto recv_pdu;
mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
- iscsi_complete_task(task);
+ iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
break;
default:
rc = ISCSI_ERR_BAD_OPCODE;
@@ -1020,7 +1029,7 @@ out:
recv_pdu:
if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
rc = ISCSI_ERR_CONN_FAILED;
- iscsi_complete_task(task);
+ iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
return rc;
}
EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
@@ -1262,7 +1271,7 @@ check_mgmt:
struct iscsi_task, running);
list_del_init(&conn->task->running);
if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
- fail_scsi_task(conn->task, DID_IMM_RETRY << 16);
+ fail_scsi_task(conn->task, DID_IMM_RETRY);
continue;
}
rc = iscsi_prep_scsi_cmd_pdu(conn->task);
@@ -1273,7 +1282,7 @@ check_mgmt:
conn->task = NULL;
goto again;
} else
- fail_scsi_task(conn->task, DID_ABORT << 16);
+ fail_scsi_task(conn->task, DID_ABORT);
continue;
}
rc = iscsi_xmit_task(conn);
@@ -1469,7 +1478,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
prepd_reject:
sc->scsi_done = NULL;
- iscsi_complete_task(task);
+ iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
reject:
spin_unlock(&session->lock);
ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
@@ -1479,7 +1488,7 @@ reject:
prepd_fault:
sc->scsi_done = NULL;
- iscsi_complete_task(task);
+ iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
fault:
spin_unlock(&session->lock);
ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
@@ -1665,7 +1674,7 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
ISCSI_DBG_SESSION(conn->session,
"failing sc %p itt 0x%x state %d\n",
task->sc, task->itt, task->state);
- fail_scsi_task(task, error << 16);
+ fail_scsi_task(task, error);
}
}
@@ -1868,7 +1877,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
}
if (task->state == ISCSI_TASK_PENDING) {
- fail_scsi_task(task, DID_ABORT << 16);
+ fail_scsi_task(task, DID_ABORT);
goto success;
}
@@ -1899,7 +1908,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
* then sent more data for the cmd.
*/
spin_lock(&session->lock);
- fail_scsi_task(task, DID_ABORT << 16);
+ fail_scsi_task(task, DID_ABORT);
conn->tmf_state = TMF_INITIAL;
spin_unlock(&session->lock);
iscsi_start_tx(conn);
@@ -2572,7 +2581,7 @@ static void
fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
{
struct iscsi_task *task;
- int i;
+ int i, state;
for (i = 0; i < conn->session->cmds_max; i++) {
task = conn->session->cmds[i];
@@ -2585,7 +2594,11 @@ fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
ISCSI_DBG_SESSION(conn->session,
"failing mgmt itt 0x%x state %d\n",
task->itt, task->state);
- iscsi_complete_task(task);
+ state = ISCSI_TASK_ABRT_SESS_RECOV;
+ if (task->state == ISCSI_TASK_PENDING)
+ state = ISCSI_TASK_COMPLETED;
+ iscsi_complete_task(task, state);
+
}
}
@@ -2642,10 +2655,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
* flush queues.
*/
spin_lock_bh(&session->lock);
- if (flag == STOP_CONN_RECOVER)
- fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
- else
- fail_scsi_tasks(conn, -1, DID_ERROR);
+ fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
fail_mgmt_tasks(session, conn);
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index b84a1d8..2bc0709 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -440,8 +440,8 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
struct iscsi_tcp_task *tcp_task = task->dd_data;
struct iscsi_r2t_info *r2t;
- /* nothing to do for mgmt or pending tasks */
- if (!task->sc || task->state == ISCSI_TASK_PENDING)
+ /* nothing to do for mgmt */
+ if (!task->sc)
return;
/* flush task's r2t queues */
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index facae71..196525c 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -86,6 +86,8 @@ enum {
ISCSI_TASK_COMPLETED,
ISCSI_TASK_PENDING,
ISCSI_TASK_RUNNING,
+ ISCSI_TASK_ABRT_TMF, /* aborted due to TMF */
+ ISCSI_TASK_ABRT_SESS_RECOV, /* aborted due to session recovery */
};
struct iscsi_r2t_info {
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 13/13] libiscsi: add debug printks for iscsi command completion path
2009-05-13 22:57 ` [PATCH 12/13] libiscsi: add task aborted state michaelc
@ 2009-05-13 22:57 ` michaelc
0 siblings, 0 replies; 14+ messages in thread
From: michaelc @ 2009-05-13 22:57 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
This patch just adds some debug statements for the abort
and completion paths.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/libiscsi.c | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index b00be6c..59908ae 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -393,10 +393,12 @@ static void iscsi_free_task(struct iscsi_task *task)
struct iscsi_session *session = conn->session;
struct scsi_cmnd *sc = task->sc;
+ ISCSI_DBG_SESSION(session, "freeing task itt 0x%x state %d sc %p\n",
+ task->itt, task->state, task->sc);
+
session->tt->cleanup_task(task);
task->state = ISCSI_TASK_FREE;
task->sc = NULL;
-
/*
* login task is preallocated so do not free
*/
@@ -451,6 +453,9 @@ static void iscsi_complete_task(struct iscsi_task *task, int state)
{
struct iscsi_conn *conn = task->conn;
+ ISCSI_DBG_SESSION(conn->session,
+ "complete task itt 0x%x state %d sc %p\n",
+ task->itt, task->state, task->sc);
if (task->state == ISCSI_TASK_COMPLETED ||
task->state == ISCSI_TASK_ABRT_TMF ||
task->state == ISCSI_TASK_ABRT_SESS_RECOV)
@@ -1836,6 +1841,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
+ ISCSI_DBG_SESSION(session, "aborting sc %p\n", sc);
+
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
/*
@@ -1858,6 +1865,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
sc->SCp.phase != session->age) {
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
+ ISCSI_DBG_SESSION(session, "failing abort due to dropped "
+ "session.\n");
return FAILED;
}
--
1.5.2.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2009-05-13 22:57 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-13 22:57 iscsi update for 2.6.31 michaelc
2009-05-13 22:57 ` [PATCH 01/13] iscsi: pass ep connect shost michaelc
2009-05-13 22:57 ` [PATCH 02/13] libiscsi: check of LLD has a alloc pdu callout michaelc
2009-05-13 22:57 ` [PATCH 03/13] libiscsi: handle param allocation failures michaelc
2009-05-13 22:57 ` [PATCH 04/13] libiscsi: export iscsi_itt_to_task for bnx2i michaelc
2009-05-13 22:57 ` [PATCH 05/13] libiscsi: have iscsi_data_in_rsp call iscsi_update_cmdsn michaelc
2009-05-13 22:57 ` [PATCH 06/13] libiscsi: fix nop response/reply and session cleanup race michaelc
2009-05-13 22:57 ` [PATCH 07/13] libiscsi_tcp: update recv tracking for each skb instead of iscsi pdu michaelc
2009-05-13 22:57 ` [PATCH 08/13] libiscsi: fix iscsi transport checks to account for slower links michaelc
2009-05-13 22:57 ` [PATCH 09/13] libiscsi: handle cleanup task races michaelc
2009-05-13 22:57 ` [PATCH 10/13] libiscsi: don't let io sit in queue when session has failed michaelc
2009-05-13 22:57 ` [PATCH 11/13] libiscsi: check if iscsi host has work queue before queueing work michaelc
2009-05-13 22:57 ` [PATCH 12/13] libiscsi: add task aborted state michaelc
2009-05-13 22:57 ` [PATCH 13/13] libiscsi: add debug printks for iscsi command completion path michaelc
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).