* [RFC 01/11] iscsi-target: Add iscsit_transport API template
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
2013-03-08 4:14 ` Roland Dreier
2013-03-22 17:23 ` Andy Grover
2013-03-08 1:45 ` [RFC 02/11] iscsi-target: Initial traditional TCP conversion to iscsit_transport Nicholas A. Bellinger
` (9 subsequent siblings)
10 siblings, 2 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab@linux-iscsi.org>
Add basic struct iscsit_transport API template to allow iscsi-target for
running with external transport modules using existing iscsi_target_core.h
code.
For all external modules, this calls try_module_get() and module_put()
to obtain + release an external iscsit_transport module reference count.
Also include the iscsi-target symbols necessary in iscsi_transport.h to
allow external transport modules to function.
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/target/iscsi/Makefile | 3 +-
drivers/target/iscsi/iscsi_target_transport.c | 57 ++++++++++++++++++
include/target/iscsi/iscsi_transport.h | 77 +++++++++++++++++++++++++
3 files changed, 136 insertions(+), 1 deletions(-)
create mode 100644 drivers/target/iscsi/iscsi_target_transport.c
create mode 100644 include/target/iscsi/iscsi_transport.h
diff --git a/drivers/target/iscsi/Makefile b/drivers/target/iscsi/Makefile
index 5b9a2cf..13a9240 100644
--- a/drivers/target/iscsi/Makefile
+++ b/drivers/target/iscsi/Makefile
@@ -15,6 +15,7 @@ iscsi_target_mod-y += iscsi_target_parameters.o \
iscsi_target_util.o \
iscsi_target.o \
iscsi_target_configfs.o \
- iscsi_target_stat.o
+ iscsi_target_stat.o \
+ iscsi_target_transport.o
obj-$(CONFIG_ISCSI_TARGET) += iscsi_target_mod.o
diff --git a/drivers/target/iscsi/iscsi_target_transport.c b/drivers/target/iscsi/iscsi_target_transport.c
new file mode 100644
index 0000000..4ffd965
--- /dev/null
+++ b/drivers/target/iscsi/iscsi_target_transport.c
@@ -0,0 +1,57 @@
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <target/iscsi/iscsi_transport.h>
+
+static LIST_HEAD(g_transport_list);
+static DEFINE_MUTEX(transport_mutex);
+
+struct iscsit_transport *iscsit_get_transport(int type)
+{
+ struct iscsit_transport *t;
+
+ mutex_lock(&transport_mutex);
+ list_for_each_entry(t, &g_transport_list, t_node) {
+ if (t->transport_type == type) {
+ if (t->owner && !try_module_get(t->owner)) {
+ t = NULL;
+ }
+ mutex_unlock(&transport_mutex);
+ return t;
+ }
+ }
+ mutex_unlock(&transport_mutex);
+
+ return NULL;
+}
+EXPORT_SYMBOL(iscsit_get_transport);
+
+void iscsit_put_transport(struct iscsit_transport *t)
+{
+ if (t->owner)
+ module_put(t->owner);
+}
+EXPORT_SYMBOL(iscsit_put_transport);
+
+int iscsit_create_transport(struct iscsit_transport *t)
+{
+ INIT_LIST_HEAD(&t->t_node);
+
+ mutex_lock(&transport_mutex);
+ list_add_tail(&t->t_node, &g_transport_list);
+ mutex_unlock(&transport_mutex);
+
+ printk("Created iSCSI transport: %s\n", t->name);
+
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_create_transport);
+
+void iscsit_destroy_transport(struct iscsit_transport *t)
+{
+ mutex_lock(&transport_mutex);
+ list_del(&t->t_node);
+ mutex_unlock(&transport_mutex);
+
+ printk("Destroyed iSCSI transport: %s\n", t->name);
+}
+EXPORT_SYMBOL(iscsit_destroy_transport);
diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h
new file mode 100644
index 0000000..c885376
--- /dev/null
+++ b/include/target/iscsi/iscsi_transport.h
@@ -0,0 +1,77 @@
+#include <linux/module.h>
+#include <linux/list.h>
+#include "../../../drivers/target/iscsi/iscsi_target_core.h"
+
+struct iscsit_transport {
+#define ISCSIT_TRANSPORT_NAME 16
+ char name[ISCSIT_TRANSPORT_NAME];
+ int transport_type;
+ struct module *owner;
+ struct list_head t_node;
+ int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
+ int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
+ void (*iscsit_free_np)(struct iscsi_np *);
+ void (*iscsit_free_conn)(struct iscsi_conn *);
+ struct iscsi_cmd *(*iscsit_alloc_cmd)(struct iscsi_conn *, gfp_t);
+ void (*iscsit_unmap_cmd)(struct iscsi_cmd *, struct iscsi_conn *);
+ void (*iscsit_free_cmd)(struct iscsi_cmd *);
+ int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
+ int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);
+ int (*iscsit_immediate_queue)(struct iscsi_conn *, struct iscsi_cmd *, int);
+ int (*iscsit_response_queue)(struct iscsi_conn *, struct iscsi_cmd *, int);
+};
+
+/*
+ * From iscsi_target_transport.c
+ */
+
+extern int iscsit_create_transport(struct iscsit_transport *);
+extern void iscsit_destroy_transport(struct iscsit_transport *);
+extern struct iscsit_transport *iscsit_get_transport(int);
+extern void iscsit_put_transport(struct iscsit_transport *);
+
+/*
+ * From iscsi_target.c
+ */
+extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *,
+ struct iscsi_cmd *);
+extern int iscsit_setup_scsi_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+ unsigned char *);
+extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
+extern int iscsit_process_scsi_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+ struct iscsi_scsi_req *);
+extern int iscsit_check_dataout_hdr(struct iscsi_conn *, unsigned char *,
+ struct iscsi_cmd **);
+extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *,
+ bool);
+extern int iscsit_handle_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
+ unsigned char *);
+extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+ unsigned char *);
+extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+ unsigned char *);
+extern void iscsit_build_rsp_pdu(struct iscsi_cmd *, struct iscsi_conn *,
+ bool, struct iscsi_scsi_rsp *);
+extern void iscsit_build_nopin_rsp(struct iscsi_cmd *, struct iscsi_conn *,
+ struct iscsi_nopin *, bool);
+extern void iscsit_build_task_mgt_rsp(struct iscsi_cmd *, struct iscsi_conn *,
+ struct iscsi_tm_rsp *);
+extern int iscsit_build_logout_rsp(struct iscsi_cmd *, struct iscsi_conn *,
+ struct iscsi_logout_rsp *);
+extern int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
+/*
+ * From iscsi_target_device.c
+ */
+extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *);
+
+/*
+ * From iscsi_target_tmr.c
+ */
+extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
+
+/*
+ * From iscsi_target_util.c
+ */
+extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
+extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *, __be32);
+extern void iscsit_free_cmd(struct iscsi_cmd *);
--
1.7.2.5
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [RFC 01/11] iscsi-target: Add iscsit_transport API template
2013-03-08 1:45 ` [RFC 01/11] iscsi-target: Add iscsit_transport API template Nicholas A. Bellinger
@ 2013-03-08 4:14 ` Roland Dreier
[not found] ` <CAG4TOxM=PDYXCAMNdRx629aAP+XF7oZmykg0k4b+a688PzzayA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-03-08 12:36 ` Or Gerlitz
2013-03-22 17:23 ` Andy Grover
1 sibling, 2 replies; 35+ messages in thread
From: Roland Dreier @ 2013-03-08 4:14 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Or Gerlitz,
Alexander Nezhinsky
On Thu, Mar 7, 2013 at 5:45 PM, Nicholas A. Bellinger
<nab@linux-iscsi.org> wrote:
> +EXPORT_SYMBOL(iscsit_get_transport);
It's not clear to me why this needs to be exported. Who would use it
outside the core iscsi target module?
^ permalink raw reply [flat|nested] 35+ messages in thread[parent not found: <CAG4TOxM=PDYXCAMNdRx629aAP+XF7oZmykg0k4b+a688PzzayA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [RFC 01/11] iscsi-target: Add iscsit_transport API template
[not found] ` <CAG4TOxM=PDYXCAMNdRx629aAP+XF7oZmykg0k4b+a688PzzayA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2013-03-08 6:02 ` Nicholas A. Bellinger
2013-03-08 16:59 ` Roland Dreier
0 siblings, 1 reply; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 6:02 UTC (permalink / raw)
To: Roland Dreier
Cc: target-devel, linux-rdma, linux-scsi, Or Gerlitz,
Alexander Nezhinsky
On Thu, 2013-03-07 at 20:14 -0800, Roland Dreier wrote:
> On Thu, Mar 7, 2013 at 5:45 PM, Nicholas A. Bellinger
> <nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org> wrote:
> > +EXPORT_SYMBOL(iscsit_get_transport);
>
> It's not clear to me why this needs to be exported. Who would use it
> outside the core iscsi target module?
Oversight on my part. Dropping the unnecessary export of
iscsit_get_transport() and iscsit_put_transport() from iscsi-target code
now..
Also, realistically, I don't expect module code beyond ib_isert.ko to
ever use the definitions in include/target/iscsi/ either.
Or and I discussed this point in the last status call, and given what
the initiator did originally (eg: export iscsi_transport) he asked to
keep it under drivers/infiniband/ulp/isert/ with the extra include bits.
I'd have a slight preference to move iser-target code under
drivers/target/iscsi/, and not put anything into include/target/iscsi/
if there won't be another module that uses it..
Do you have a preference here..?
--nab
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [RFC 01/11] iscsi-target: Add iscsit_transport API template
2013-03-08 6:02 ` Nicholas A. Bellinger
@ 2013-03-08 16:59 ` Roland Dreier
0 siblings, 0 replies; 35+ messages in thread
From: Roland Dreier @ 2013-03-08 16:59 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Or Gerlitz,
Alexander Nezhinsky
On Thu, Mar 7, 2013 at 10:02 PM, Nicholas A. Bellinger
<nab@linux-iscsi.org> wrote:
> Or and I discussed this point in the last status call, and given what
> the initiator did originally (eg: export iscsi_transport) he asked to
> keep it under drivers/infiniband/ulp/isert/ with the extra include bits.
>
> I'd have a slight preference to move iser-target code under
> drivers/target/iscsi/, and not put anything into include/target/iscsi/
> if there won't be another module that uses it..
>
> Do you have a preference here..?
It's not really something that matters to me.
- R.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC 01/11] iscsi-target: Add iscsit_transport API template
2013-03-08 4:14 ` Roland Dreier
[not found] ` <CAG4TOxM=PDYXCAMNdRx629aAP+XF7oZmykg0k4b+a688PzzayA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2013-03-08 12:36 ` Or Gerlitz
2013-03-08 21:26 ` Nicholas A. Bellinger
1 sibling, 1 reply; 35+ messages in thread
From: Or Gerlitz @ 2013-03-08 12:36 UTC (permalink / raw)
To: Roland Dreier, Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Or Gerlitz,
Alexander Nezhinsky
On Fri, Mar 8, 2013 at 6:14 AM, Roland Dreier <roland@kernel.org> wrote:
> Nicholas A. Bellinger <nab@linux-iscsi.org> wrote:
> > +EXPORT_SYMBOL(iscsit_get_transport);
> It's not clear to me why this needs to be exported. Who would use it
> outside the core iscsi target module?
Yep, as Nic noted, we're adding here an iscsi transport concept e.g in
the same manner Mike did libiscsi back in 2005/6 when the iser
initiator was pushed. This allows for multiple iscsi flavours to use a
common code for common functionality. In the initiator area initially
there were iscsi tcp and iser, later few iscsi HW offloads were merged
too. Same story here. I think that the point is whether or not these
APIs are needed, since once we agree on that, we need an header file
and exporting of functions. As libiscsi.h resided under include/ it
makes sense to me for this include to be located there too.
Or.
Or.
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [RFC 01/11] iscsi-target: Add iscsit_transport API template
2013-03-08 12:36 ` Or Gerlitz
@ 2013-03-08 21:26 ` Nicholas A. Bellinger
0 siblings, 0 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 21:26 UTC (permalink / raw)
To: Or Gerlitz
Cc: Roland Dreier, target-devel, linux-rdma, linux-scsi, Or Gerlitz,
Alexander Nezhinsky
On Fri, 2013-03-08 at 14:36 +0200, Or Gerlitz wrote:
> On Fri, Mar 8, 2013 at 6:14 AM, Roland Dreier <roland@kernel.org> wrote:
> > Nicholas A. Bellinger <nab@linux-iscsi.org> wrote:
> > > +EXPORT_SYMBOL(iscsit_get_transport);
>
> > It's not clear to me why this needs to be exported. Who would use it
> > outside the core iscsi target module?
>
> Yep, as Nic noted, we're adding here an iscsi transport concept e.g in
> the same manner Mike did libiscsi back in 2005/6 when the iser
> initiator was pushed. This allows for multiple iscsi flavours to use a
> common code for common functionality. In the initiator area initially
> there were iscsi tcp and iser, later few iscsi HW offloads were merged
> too. Same story here. I think that the point is whether or not these
> APIs are needed, since once we agree on that, we need an header file
> and exporting of functions. As libiscsi.h resided under include/ it
> makes sense to me for this include to be located there too.
So my main concern with putting iscsit_transport definitions into
include/target/iscsi/ is the number of dependencies required from
iscsi_target_core.h.
Currently with iscsi_cmd embedded into isert_cmd, this will require most
existing iscsi_target_core.h definitions to be pushed out into
include/target/iscsi/. This also includes some namespace conflicts
between libiscsi.h and iscsi_target_core.h, but those can be solved
easily enough.
I'm still leaning towards just keeping iscsi_transport.h definitions
local to drivers/target/iscsi, if there is really not going to be other
drivers aside from ib_isert that end up using it. If there was interest
in traditional iscsi-target HW offloads using this interface then the
story would be different, but every HW offload that I've seen thus far
using LIO is based on out-of-tree NIC code to start.
--nab
>
> Or.
>
> Or.
> --
> To unsubscribe from this list: send the line "unsubscribe target-devel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC 01/11] iscsi-target: Add iscsit_transport API template
2013-03-08 1:45 ` [RFC 01/11] iscsi-target: Add iscsit_transport API template Nicholas A. Bellinger
2013-03-08 4:14 ` Roland Dreier
@ 2013-03-22 17:23 ` Andy Grover
2013-03-22 22:29 ` Nicholas A. Bellinger
1 sibling, 1 reply; 35+ messages in thread
From: Andy Grover @ 2013-03-22 17:23 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On 03/07/2013 05:45 PM, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
>
> Add basic struct iscsit_transport API template to allow iscsi-target for
> running with external transport modules using existing iscsi_target_core.h
> code.
>
> For all external modules, this calls try_module_get() and module_put()
> to obtain + release an external iscsit_transport module reference count.
>
> Also include the iscsi-target symbols necessary in iscsi_transport.h to
> allow external transport modules to function.
>
> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> ---
> drivers/target/iscsi/Makefile | 3 +-
> drivers/target/iscsi/iscsi_target_transport.c | 57 ++++++++++++++++++
> include/target/iscsi/iscsi_transport.h | 77 +++++++++++++++++++++++++
> 3 files changed, 136 insertions(+), 1 deletions(-)
> create mode 100644 drivers/target/iscsi/iscsi_target_transport.c
> create mode 100644 include/target/iscsi/iscsi_transport.h
>
> diff --git a/drivers/target/iscsi/Makefile b/drivers/target/iscsi/Makefile
> index 5b9a2cf..13a9240 100644
> --- a/drivers/target/iscsi/Makefile
> +++ b/drivers/target/iscsi/Makefile
> @@ -15,6 +15,7 @@ iscsi_target_mod-y += iscsi_target_parameters.o \
> iscsi_target_util.o \
> iscsi_target.o \
> iscsi_target_configfs.o \
> - iscsi_target_stat.o
> + iscsi_target_stat.o \
> + iscsi_target_transport.o
>
> obj-$(CONFIG_ISCSI_TARGET) += iscsi_target_mod.o
> diff --git a/drivers/target/iscsi/iscsi_target_transport.c b/drivers/target/iscsi/iscsi_target_transport.c
> new file mode 100644
> index 0000000..4ffd965
> --- /dev/null
> +++ b/drivers/target/iscsi/iscsi_target_transport.c
> @@ -0,0 +1,57 @@
> +#include <linux/spinlock.h>
> +#include <linux/list.h>
> +#include <target/iscsi/iscsi_transport.h>
> +
> +static LIST_HEAD(g_transport_list);
> +static DEFINE_MUTEX(transport_mutex);
> +
> +struct iscsit_transport *iscsit_get_transport(int type)
> +{
> + struct iscsit_transport *t;
> +
> + mutex_lock(&transport_mutex);
> + list_for_each_entry(t, &g_transport_list, t_node) {
> + if (t->transport_type == type) {
> + if (t->owner && !try_module_get(t->owner)) {
> + t = NULL;
> + }
> + mutex_unlock(&transport_mutex);
> + return t;
> + }
> + }
> + mutex_unlock(&transport_mutex);
> +
> + return NULL;
> +}
> +EXPORT_SYMBOL(iscsit_get_transport);
> +
> +void iscsit_put_transport(struct iscsit_transport *t)
> +{
> + if (t->owner)
> + module_put(t->owner);
> +}
> +EXPORT_SYMBOL(iscsit_put_transport);
> +
> +int iscsit_create_transport(struct iscsit_transport *t)
> +{
> + INIT_LIST_HEAD(&t->t_node);
> +
> + mutex_lock(&transport_mutex);
> + list_add_tail(&t->t_node, &g_transport_list);
> + mutex_unlock(&transport_mutex);
> +
> + printk("Created iSCSI transport: %s\n", t->name);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(iscsit_create_transport);
> +
> +void iscsit_destroy_transport(struct iscsit_transport *t)
> +{
> + mutex_lock(&transport_mutex);
> + list_del(&t->t_node);
> + mutex_unlock(&transport_mutex);
> +
> + printk("Destroyed iSCSI transport: %s\n", t->name);
> +}
I don't think create/destroy are the right names to use here - I suggest
register/unregister or something like that?
Please also make sure to turn those printks in to pr_something() for the
final version.
-- Andy
> +EXPORT_SYMBOL(iscsit_destroy_transport);
> diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h
> new file mode 100644
> index 0000000..c885376
> --- /dev/null
> +++ b/include/target/iscsi/iscsi_transport.h
> @@ -0,0 +1,77 @@
> +#include <linux/module.h>
> +#include <linux/list.h>
> +#include "../../../drivers/target/iscsi/iscsi_target_core.h"
> +
> +struct iscsit_transport {
> +#define ISCSIT_TRANSPORT_NAME 16
> + char name[ISCSIT_TRANSPORT_NAME];
> + int transport_type;
> + struct module *owner;
> + struct list_head t_node;
> + int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
> + int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
> + void (*iscsit_free_np)(struct iscsi_np *);
> + void (*iscsit_free_conn)(struct iscsi_conn *);
> + struct iscsi_cmd *(*iscsit_alloc_cmd)(struct iscsi_conn *, gfp_t);
> + void (*iscsit_unmap_cmd)(struct iscsi_cmd *, struct iscsi_conn *);
> + void (*iscsit_free_cmd)(struct iscsi_cmd *);
> + int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
> + int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);
> + int (*iscsit_immediate_queue)(struct iscsi_conn *, struct iscsi_cmd *, int);
> + int (*iscsit_response_queue)(struct iscsi_conn *, struct iscsi_cmd *, int);
> +};
> +
> +/*
> + * From iscsi_target_transport.c
> + */
> +
> +extern int iscsit_create_transport(struct iscsit_transport *);
> +extern void iscsit_destroy_transport(struct iscsit_transport *);
> +extern struct iscsit_transport *iscsit_get_transport(int);
> +extern void iscsit_put_transport(struct iscsit_transport *);
> +
> +/*
> + * From iscsi_target.c
> + */
> +extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *,
> + struct iscsi_cmd *);
> +extern int iscsit_setup_scsi_cmd(struct iscsi_conn *, struct iscsi_cmd *,
> + unsigned char *);
> +extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
> +extern int iscsit_process_scsi_cmd(struct iscsi_conn *, struct iscsi_cmd *,
> + struct iscsi_scsi_req *);
> +extern int iscsit_check_dataout_hdr(struct iscsi_conn *, unsigned char *,
> + struct iscsi_cmd **);
> +extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *,
> + bool);
> +extern int iscsit_handle_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
> + unsigned char *);
> +extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *,
> + unsigned char *);
> +extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *,
> + unsigned char *);
> +extern void iscsit_build_rsp_pdu(struct iscsi_cmd *, struct iscsi_conn *,
> + bool, struct iscsi_scsi_rsp *);
> +extern void iscsit_build_nopin_rsp(struct iscsi_cmd *, struct iscsi_conn *,
> + struct iscsi_nopin *, bool);
> +extern void iscsit_build_task_mgt_rsp(struct iscsi_cmd *, struct iscsi_conn *,
> + struct iscsi_tm_rsp *);
> +extern int iscsit_build_logout_rsp(struct iscsi_cmd *, struct iscsi_conn *,
> + struct iscsi_logout_rsp *);
> +extern int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
> +/*
> + * From iscsi_target_device.c
> + */
> +extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *);
> +
> +/*
> + * From iscsi_target_tmr.c
> + */
> +extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
> +
> +/*
> + * From iscsi_target_util.c
> + */
> +extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
> +extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *, __be32);
> +extern void iscsit_free_cmd(struct iscsi_cmd *);
>
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [RFC 01/11] iscsi-target: Add iscsit_transport API template
2013-03-22 17:23 ` Andy Grover
@ 2013-03-22 22:29 ` Nicholas A. Bellinger
0 siblings, 0 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-22 22:29 UTC (permalink / raw)
To: Andy Grover
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On Fri, 2013-03-22 at 10:23 -0700, Andy Grover wrote:
> On 03/07/2013 05:45 PM, Nicholas A. Bellinger wrote:
> > From: Nicholas Bellinger <nab@linux-iscsi.org>
> >
> > Add basic struct iscsit_transport API template to allow iscsi-target for
> > running with external transport modules using existing iscsi_target_core.h
> > code.
> >
> > For all external modules, this calls try_module_get() and module_put()
> > to obtain + release an external iscsit_transport module reference count.
> >
> > Also include the iscsi-target symbols necessary in iscsi_transport.h to
> > allow external transport modules to function.
> >
> > Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> > ---
> > drivers/target/iscsi/Makefile | 3 +-
> > drivers/target/iscsi/iscsi_target_transport.c | 57 ++++++++++++++++++
> > include/target/iscsi/iscsi_transport.h | 77 +++++++++++++++++++++++++
> > 3 files changed, 136 insertions(+), 1 deletions(-)
> > create mode 100644 drivers/target/iscsi/iscsi_target_transport.c
> > create mode 100644 include/target/iscsi/iscsi_transport.h
> >
> > diff --git a/drivers/target/iscsi/Makefile b/drivers/target/iscsi/Makefile
> > index 5b9a2cf..13a9240 100644
> > --- a/drivers/target/iscsi/Makefile
> > +++ b/drivers/target/iscsi/Makefile
> > @@ -15,6 +15,7 @@ iscsi_target_mod-y += iscsi_target_parameters.o \
> > iscsi_target_util.o \
> > iscsi_target.o \
> > iscsi_target_configfs.o \
> > - iscsi_target_stat.o
> > + iscsi_target_stat.o \
> > + iscsi_target_transport.o
> >
> > obj-$(CONFIG_ISCSI_TARGET) += iscsi_target_mod.o
> > diff --git a/drivers/target/iscsi/iscsi_target_transport.c b/drivers/target/iscsi/iscsi_target_transport.c
> > new file mode 100644
> > index 0000000..4ffd965
> > --- /dev/null
> > +++ b/drivers/target/iscsi/iscsi_target_transport.c
> > @@ -0,0 +1,57 @@
> > +#include <linux/spinlock.h>
> > +#include <linux/list.h>
> > +#include <target/iscsi/iscsi_transport.h>
> > +
> > +static LIST_HEAD(g_transport_list);
> > +static DEFINE_MUTEX(transport_mutex);
> > +
> > +struct iscsit_transport *iscsit_get_transport(int type)
> > +{
> > + struct iscsit_transport *t;
> > +
> > + mutex_lock(&transport_mutex);
> > + list_for_each_entry(t, &g_transport_list, t_node) {
> > + if (t->transport_type == type) {
> > + if (t->owner && !try_module_get(t->owner)) {
> > + t = NULL;
> > + }
> > + mutex_unlock(&transport_mutex);
> > + return t;
> > + }
> > + }
> > + mutex_unlock(&transport_mutex);
> > +
> > + return NULL;
> > +}
> > +EXPORT_SYMBOL(iscsit_get_transport);
> > +
> > +void iscsit_put_transport(struct iscsit_transport *t)
> > +{
> > + if (t->owner)
> > + module_put(t->owner);
> > +}
> > +EXPORT_SYMBOL(iscsit_put_transport);
> > +
> > +int iscsit_create_transport(struct iscsit_transport *t)
> > +{
> > + INIT_LIST_HEAD(&t->t_node);
> > +
> > + mutex_lock(&transport_mutex);
> > + list_add_tail(&t->t_node, &g_transport_list);
> > + mutex_unlock(&transport_mutex);
> > +
> > + printk("Created iSCSI transport: %s\n", t->name);
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL(iscsit_create_transport);
> > +
> > +void iscsit_destroy_transport(struct iscsit_transport *t)
> > +{
> > + mutex_lock(&transport_mutex);
> > + list_del(&t->t_node);
> > + mutex_unlock(&transport_mutex);
> > +
> > + printk("Destroyed iSCSI transport: %s\n", t->name);
> > +}
>
> I don't think create/destroy are the right names to use here - I suggest
> register/unregister or something like that?
>
Fair enough. Renamed to register/unregister in the forth-coming RFC-v2
> Please also make sure to turn those printks in to pr_something() for the
> final version.
>
Done.
Thanks,
--nab
^ permalink raw reply [flat|nested] 35+ messages in thread
* [RFC 02/11] iscsi-target: Initial traditional TCP conversion to iscsit_transport
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
2013-03-08 1:45 ` [RFC 01/11] iscsi-target: Add iscsit_transport API template Nicholas A. Bellinger
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
2013-03-22 17:23 ` Andy Grover
2013-03-08 1:45 ` [RFC 03/11] iscsi-target: Add iser-target parameter keys + setup during login Nicholas A. Bellinger
` (8 subsequent siblings)
10 siblings, 1 reply; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab@linux-iscsi.org>
This patch performs the initial conversion of existing traditional iscsi
to use iscsit_transport API callers. This includes:
- iscsi-np cleanups for iscsit_transport_type
- Add iscsi-np transport calls w/ ->iscsit_setup_up() and ->iscsit_free_np()
- Convert login thread process context to use ->iscsit_accept_np() for
connections with pre-allocated struct iscsi_conn
- Convert existing socket accept code to iscsit_accept_np()
- Convert login RX/TX callers to use ->iscsit_get_login_rx() and
->iscsit_put_login_tx() to exchange request/response PDUs
- Convert existing socket login RX/TX calls into iscsit_get_login_rx()
and iscsit_put_login_tx()
- Change iscsit_close_connection() to invoke ->iscsit_free_conn() +
iscsit_put_transport() calls.
- Add iscsit_create_transport() + iscsit_destroy_transport() calls
to module init/exit
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/target/iscsi/iscsi_target.c | 35 ++-
drivers/target/iscsi/iscsi_target_core.h | 15 +-
drivers/target/iscsi/iscsi_target_login.c | 411 ++++++++++++++++--------
drivers/target/iscsi/iscsi_target_login.h | 6 +
drivers/target/iscsi/iscsi_target_nego.c | 185 ++----------
drivers/target/iscsi/iscsi_target_nego.h | 11 +-
drivers/target/iscsi/iscsi_target_parameters.c | 12 +-
drivers/target/iscsi/iscsi_target_tpg.c | 6 +-
drivers/target/iscsi/iscsi_target_util.c | 27 +--
9 files changed, 376 insertions(+), 332 deletions(-)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 23a98e6..4dc1c9b 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -49,6 +49,8 @@
#include "iscsi_target_device.h"
#include "iscsi_target_stat.h"
+#include <target/iscsi/iscsi_transport.h>
+
static LIST_HEAD(g_tiqn_list);
static LIST_HEAD(g_np_list);
static DEFINE_SPINLOCK(tiqn_lock);
@@ -400,8 +402,7 @@ struct iscsi_np *iscsit_add_np(
spin_unlock_bh(&np_lock);
pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
- np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
- "TCP" : "SCTP");
+ np->np_ip, np->np_port, np->np_transport->name);
return np;
}
@@ -440,11 +441,10 @@ int iscsit_reset_np_thread(
return 0;
}
-static int iscsit_del_np_comm(struct iscsi_np *np)
+static void iscsit_free_np(struct iscsi_np *np)
{
if (np->np_socket)
sock_release(np->np_socket);
- return 0;
}
int iscsit_del_np(struct iscsi_np *np)
@@ -466,20 +466,32 @@ int iscsit_del_np(struct iscsi_np *np)
send_sig(SIGINT, np->np_thread, 1);
kthread_stop(np->np_thread);
}
- iscsit_del_np_comm(np);
+
+ np->np_transport->iscsit_free_np(np);
spin_lock_bh(&np_lock);
list_del(&np->np_list);
spin_unlock_bh(&np_lock);
pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
- np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
- "TCP" : "SCTP");
+ np->np_ip, np->np_port, np->np_transport->name);
+ iscsit_put_transport(np->np_transport);
kfree(np);
return 0;
}
+static struct iscsit_transport iscsi_target_transport = {
+ .name = "iSCSI/TCP",
+ .transport_type = ISCSI_TCP,
+ .owner = NULL,
+ .iscsit_setup_np = iscsit_setup_np,
+ .iscsit_accept_np = iscsit_accept_np,
+ .iscsit_free_np = iscsit_free_np,
+ .iscsit_get_login_rx = iscsit_get_login_rx,
+ .iscsit_put_login_tx = iscsit_put_login_tx,
+};
+
static int __init iscsi_target_init_module(void)
{
int ret = 0;
@@ -556,6 +568,8 @@ static int __init iscsi_target_init_module(void)
goto ooo_out;
}
+ iscsit_create_transport(&iscsi_target_transport);
+
if (iscsit_load_discovery_tpg() < 0)
goto r2t_out;
@@ -586,6 +600,7 @@ static void __exit iscsi_target_cleanup_module(void)
iscsi_deallocate_thread_sets();
iscsi_thread_set_free();
iscsit_release_discovery_tpg();
+ iscsit_destroy_transport(&iscsi_target_transport);
kmem_cache_destroy(lio_cmd_cache);
kmem_cache_destroy(lio_qr_cache);
kmem_cache_destroy(lio_dr_cache);
@@ -4045,6 +4060,12 @@ int iscsit_close_connection(
if (conn->sock)
sock_release(conn->sock);
+
+ if (conn->conn_transport->iscsit_free_conn)
+ conn->conn_transport->iscsit_free_conn(conn);
+
+ iscsit_put_transport(conn->conn_transport);
+
conn->thread_set = NULL;
pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 7a333d2..2587677 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -60,7 +60,7 @@
#define ISCSI_IOV_DATA_BUFFER 5
-enum tpg_np_network_transport_table {
+enum iscsit_transport_type {
ISCSI_TCP = 0,
ISCSI_SCTP_TCP = 1,
ISCSI_SCTP_UDP = 2,
@@ -503,6 +503,7 @@ struct iscsi_conn {
u16 login_port;
u16 local_port;
int net_size;
+ int login_family;
u32 auth_id;
u32 conn_flags;
/* Used for iscsi_tx_login_rsp() */
@@ -562,9 +563,12 @@ struct iscsi_conn {
struct list_head immed_queue_list;
struct list_head response_queue_list;
struct iscsi_conn_ops *conn_ops;
+ struct iscsi_login *conn_login;
+ struct iscsit_transport *conn_transport;
struct iscsi_param_list *param_list;
/* Used for per connection auth state machine */
void *auth_protocol;
+ void *context;
struct iscsi_login_thread_s *login_thread;
struct iscsi_portal_group *tpg;
/* Pointer to parent session */
@@ -663,6 +667,8 @@ struct iscsi_login {
u8 first_request;
u8 version_min;
u8 version_max;
+ u8 login_complete;
+ u8 login_failed;
char isid[6];
u32 cmd_sn;
itt_t init_task_tag;
@@ -670,10 +676,11 @@ struct iscsi_login {
u32 rsp_length;
u16 cid;
u16 tsih;
- char *req;
- char *rsp;
+ char req[ISCSI_HDR_LEN];
+ char rsp[ISCSI_HDR_LEN];
char *req_buf;
char *rsp_buf;
+ struct iscsi_conn *conn;
} ____cacheline_aligned;
struct iscsi_node_attrib {
@@ -754,6 +761,8 @@ struct iscsi_np {
struct task_struct *np_thread;
struct timer_list np_login_timer;
struct iscsi_portal_group *np_login_tpg;
+ void *np_context;
+ struct iscsit_transport *np_transport;
struct list_head np_list;
} ____cacheline_aligned;
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index fdb632f..9354a5f 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -39,8 +39,39 @@
#include "iscsi_target.h"
#include "iscsi_target_parameters.h"
-static int iscsi_login_init_conn(struct iscsi_conn *conn)
+#include <target/iscsi/iscsi_transport.h>
+
+static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
{
+ struct iscsi_login *login;
+
+ login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
+ if (!login) {
+ pr_err("Unable to allocate memory for struct iscsi_login.\n");
+ return NULL;
+ }
+ login->conn = conn;
+ login->first_request = 1;
+
+ login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+ if (!login->req_buf) {
+ pr_err("Unable to allocate memory for response buffer.\n");
+ goto out_login;
+ }
+
+ login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+ if (!login->rsp_buf) {
+ pr_err("Unable to allocate memory for request buffer.\n");
+ goto out_req_buf;
+ }
+
+ conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
+ if (!conn->conn_ops) {
+ pr_err("Unable to allocate memory for"
+ " struct iscsi_conn_ops.\n");
+ goto out_rsp_buf;
+ }
+
init_waitqueue_head(&conn->queues_wq);
INIT_LIST_HEAD(&conn->conn_list);
INIT_LIST_HEAD(&conn->conn_cmd_list);
@@ -62,10 +93,21 @@ static int iscsi_login_init_conn(struct iscsi_conn *conn)
if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) {
pr_err("Unable to allocate conn->conn_cpumask\n");
- return -ENOMEM;
+ goto out_conn_ops;
}
+ conn->conn_login = login;
- return 0;
+ return login;
+
+out_conn_ops:
+ kfree(conn->conn_ops);
+out_rsp_buf:
+ kfree(login->rsp_buf);
+out_req_buf:
+ kfree(login->req_buf);
+out_login:
+ kfree(login);
+ return NULL;
}
/*
@@ -635,7 +677,13 @@ static int iscsi_post_login_handler(
spin_unlock_bh(&sess->conn_lock);
iscsi_post_login_start_timers(conn);
- iscsi_activate_thread_set(conn, ts);
+
+ if (conn->conn_transport == ISCSI_TCP) {
+ iscsi_activate_thread_set(conn, ts);
+ } else {
+ printk("Not calling iscsi_activate_thread_set....\n");
+ dump_stack();
+ }
/*
* Determine CPU mask to ensure connection's RX and TX kthreads
* are scheduled on the same CPU.
@@ -764,11 +812,11 @@ static void iscsi_stop_login_thread_timer(struct iscsi_np *np)
spin_unlock_bh(&np->np_thread_lock);
}
-int iscsi_target_setup_login_socket(
+int iscsit_setup_np(
struct iscsi_np *np,
struct __kernel_sockaddr_storage *sockaddr)
{
- struct socket *sock;
+ struct socket *sock = NULL;
int backlog = 5, ret, opt = 0, len;
switch (np->np_network_transport) {
@@ -784,15 +832,15 @@ int iscsi_target_setup_login_socket(
np->np_ip_proto = IPPROTO_SCTP;
np->np_sock_type = SOCK_SEQPACKET;
break;
- case ISCSI_IWARP_TCP:
- case ISCSI_IWARP_SCTP:
- case ISCSI_INFINIBAND:
default:
pr_err("Unsupported network_transport: %d\n",
np->np_network_transport);
return -EINVAL;
}
+ np->np_ip_proto = IPPROTO_TCP;
+ np->np_sock_type = SOCK_STREAM;
+
ret = sock_create(sockaddr->ss_family, np->np_sock_type,
np->np_ip_proto, &sock);
if (ret < 0) {
@@ -856,7 +904,6 @@ int iscsi_target_setup_login_socket(
}
return 0;
-
fail:
np->np_socket = NULL;
if (sock)
@@ -864,21 +911,168 @@ fail:
return ret;
}
+int iscsi_target_setup_login_socket(
+ struct iscsi_np *np,
+ struct __kernel_sockaddr_storage *sockaddr)
+{
+ struct iscsit_transport *t;
+ int rc;
+
+ t = iscsit_get_transport(np->np_network_transport);
+ if (!t)
+ return -EINVAL;
+
+ rc = t->iscsit_setup_np(np, sockaddr);
+ if (rc < 0)
+ return rc;
+
+ np->np_transport = t;
+ printk("Set np->np_transport to %p -> %s\n", np->np_transport,
+ np->np_transport->name);
+ return 0;
+}
+
+int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
+{
+ struct socket *new_sock, *sock = np->np_socket;
+ struct sockaddr_in sock_in;
+ struct sockaddr_in6 sock_in6;
+ int rc, err;
+
+ rc = kernel_accept(sock, &new_sock, 0);
+ if (rc < 0)
+ return rc;
+
+ conn->sock = new_sock;
+ conn->login_family = np->np_sockaddr.ss_family;
+ printk("iSCSI/TCP: Setup conn->sock from new_sock: %p\n", new_sock);
+
+ if (np->np_sockaddr.ss_family == AF_INET6) {
+ memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
+
+ rc = conn->sock->ops->getname(conn->sock,
+ (struct sockaddr *)&sock_in6, &err, 1);
+ if (!rc) {
+ snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
+ &sock_in6.sin6_addr.in6_u);
+ conn->login_port = ntohs(sock_in6.sin6_port);
+ }
+
+ rc = conn->sock->ops->getname(conn->sock,
+ (struct sockaddr *)&sock_in6, &err, 0);
+ if (!rc) {
+ snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
+ &sock_in6.sin6_addr.in6_u);
+ conn->local_port = ntohs(sock_in6.sin6_port);
+ }
+ } else {
+ memset(&sock_in, 0, sizeof(struct sockaddr_in));
+
+ rc = conn->sock->ops->getname(conn->sock,
+ (struct sockaddr *)&sock_in, &err, 1);
+ if (!rc) {
+ sprintf(conn->login_ip, "%pI4",
+ &sock_in.sin_addr.s_addr);
+ conn->login_port = ntohs(sock_in.sin_port);
+ }
+
+ rc = conn->sock->ops->getname(conn->sock,
+ (struct sockaddr *)&sock_in, &err, 0);
+ if (!rc) {
+ sprintf(conn->local_ip, "%pI4",
+ &sock_in.sin_addr.s_addr);
+ conn->local_port = ntohs(sock_in.sin_port);
+ }
+ }
+
+ return 0;
+}
+
+int iscsit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+ struct iscsi_login_req *login_req;
+ u32 padding = 0, payload_length;
+
+ if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
+ return -1;
+
+ login_req = (struct iscsi_login_req *)login->req;
+ payload_length = ntoh24(login_req->dlength);
+ padding = ((-payload_length) & 3);
+
+ pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
+ " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
+ login_req->flags, login_req->itt, login_req->cmdsn,
+ login_req->exp_statsn, login_req->cid, payload_length);
+ /*
+ * Setup the initial iscsi_login values from the leading
+ * login request PDU.
+ */
+ if (login->first_request) {
+ login_req = (struct iscsi_login_req *)login->req;
+ login->leading_connection = (!login_req->tsih) ? 1 : 0;
+ login->current_stage =
+ (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
+ login->version_min = login_req->min_version;
+ login->version_max = login_req->max_version;
+ memcpy(login->isid, login_req->isid, 6);
+ login->cmd_sn = be32_to_cpu(login_req->cmdsn);
+ login->init_task_tag = login_req->itt;
+ login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
+ login->cid = be16_to_cpu(login_req->cid);
+ login->tsih = be16_to_cpu(login_req->tsih);
+ }
+
+ if (iscsi_target_check_login_request(conn, login) < 0)
+ return -1;
+
+ memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
+ if (iscsi_login_rx_data(conn, login->req_buf,
+ payload_length + padding) < 0)
+ return -1;
+
+ return 0;
+}
+
+int iscsit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
+ u32 length)
+{
+ if (iscsi_login_tx_data(conn, login->rsp, login->rsp_buf, length) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t)
+{
+ int rc;
+
+ if (!t->owner) {
+ conn->conn_transport = t;
+ return 0;
+ }
+
+ rc = try_module_get(t->owner);
+ if (!rc) {
+ pr_err("try_module_get() failed for %s\n", t->name);
+ return -EINVAL;
+ }
+
+ conn->conn_transport = t;
+ return 0;
+}
+
static int __iscsi_target_login_thread(struct iscsi_np *np)
{
- u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0;
- int err, ret = 0, stop;
+ u8 *buffer, zero_tsih = 0;
+ int ret = 0, rc, stop;
struct iscsi_conn *conn = NULL;
struct iscsi_login *login;
struct iscsi_portal_group *tpg = NULL;
- struct socket *new_sock, *sock;
- struct kvec iov;
struct iscsi_login_req *pdu;
- struct sockaddr_in sock_in;
- struct sockaddr_in6 sock_in6;
flush_signals(current);
- sock = np->np_socket;
spin_lock_bh(&np->np_thread_lock);
if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
@@ -889,75 +1083,76 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
}
spin_unlock_bh(&np->np_thread_lock);
- if (kernel_accept(sock, &new_sock, 0) < 0) {
- spin_lock_bh(&np->np_thread_lock);
- if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
- spin_unlock_bh(&np->np_thread_lock);
- complete(&np->np_restart_comp);
- /* Get another socket */
- return 1;
- }
- spin_unlock_bh(&np->np_thread_lock);
- goto out;
- }
- iscsi_start_login_thread_timer(np);
-
conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
if (!conn) {
pr_err("Could not allocate memory for"
" new connection\n");
- sock_release(new_sock);
/* Get another socket */
return 1;
}
-
pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
conn->conn_state = TARG_CONN_STATE_FREE;
- conn->sock = new_sock;
- pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
- conn->conn_state = TARG_CONN_STATE_XPT_UP;
+ if (iscsit_conn_set_transport(conn, np->np_transport) < 0) {
+ kfree(conn);
+ return 1;
+ }
- /*
- * Allocate conn->conn_ops early as a failure calling
- * iscsit_tx_login_rsp() below will call tx_data().
- */
- conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
- if (!conn->conn_ops) {
- pr_err("Unable to allocate memory for"
- " struct iscsi_conn_ops.\n");
- goto new_sess_out;
+ rc = np->np_transport->iscsit_accept_np(np, conn);
+ if (rc == -ENOSYS) {
+ complete(&np->np_restart_comp);
+ iscsit_put_transport(conn->conn_transport);
+ kfree(conn);
+ conn = NULL;
+ goto exit;
+ } else if (rc < 0) {
+ spin_lock_bh(&np->np_thread_lock);
+ if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+ spin_unlock_bh(&np->np_thread_lock);
+ complete(&np->np_restart_comp);
+ if (ret == -ENODEV) {
+ iscsit_put_transport(conn->conn_transport);
+ kfree(conn);
+ conn = NULL;
+ goto out;
+ }
+ /* Get another socket */
+ return 1;
+ }
+ spin_unlock_bh(&np->np_thread_lock);
+ iscsit_put_transport(conn->conn_transport);
+ kfree(conn);
+ conn = NULL;
+ goto out;
}
/*
* Perform the remaining iSCSI connection initialization items..
*/
- if (iscsi_login_init_conn(conn) < 0)
- goto new_sess_out;
-
- memset(buffer, 0, ISCSI_HDR_LEN);
- memset(&iov, 0, sizeof(struct kvec));
- iov.iov_base = buffer;
- iov.iov_len = ISCSI_HDR_LEN;
-
- if (rx_data(conn, &iov, 1, ISCSI_HDR_LEN) <= 0) {
- pr_err("rx_data() returned an error.\n");
+ login = iscsi_login_init_conn(conn);
+ if (!login) {
goto new_sess_out;
}
- iscsi_opcode = (buffer[0] & ISCSI_OPCODE_MASK);
- if (!(iscsi_opcode & ISCSI_OP_LOGIN)) {
- pr_err("First opcode is not login request,"
- " failing login request.\n");
- goto new_sess_out;
- }
+ iscsi_start_login_thread_timer(np);
- pdu = (struct iscsi_login_req *) buffer;
+ pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
+ conn->conn_state = TARG_CONN_STATE_XPT_UP;
+ /*
+ * This will process the first login request + payload..
+ */
+ rc = np->np_transport->iscsit_get_login_rx(conn, login);
+ if (rc == 1)
+ return 1;
+ else if (rc < 0)
+ goto new_sess_out;
+ buffer = &login->req[0];
+ pdu = (struct iscsi_login_req *)buffer;
/*
* Used by iscsit_tx_login_rsp() for Login Resonses PDUs
* when Status-Class != 0.
*/
- conn->login_itt = pdu->itt;
+ conn->login_itt = pdu->itt;
spin_lock_bh(&np->np_thread_lock);
if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
@@ -970,61 +1165,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
}
spin_unlock_bh(&np->np_thread_lock);
- if (np->np_sockaddr.ss_family == AF_INET6) {
- memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
-
- if (conn->sock->ops->getname(conn->sock,
- (struct sockaddr *)&sock_in6, &err, 1) < 0) {
- pr_err("sock_ops->getname() failed.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
- snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
- &sock_in6.sin6_addr.in6_u);
- conn->login_port = ntohs(sock_in6.sin6_port);
-
- if (conn->sock->ops->getname(conn->sock,
- (struct sockaddr *)&sock_in6, &err, 0) < 0) {
- pr_err("sock_ops->getname() failed.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
- snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
- &sock_in6.sin6_addr.in6_u);
- conn->local_port = ntohs(sock_in6.sin6_port);
-
- } else {
- memset(&sock_in, 0, sizeof(struct sockaddr_in));
-
- if (conn->sock->ops->getname(conn->sock,
- (struct sockaddr *)&sock_in, &err, 1) < 0) {
- pr_err("sock_ops->getname() failed.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
- sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr);
- conn->login_port = ntohs(sock_in.sin_port);
-
- if (conn->sock->ops->getname(conn->sock,
- (struct sockaddr *)&sock_in, &err, 0) < 0) {
- pr_err("sock_ops->getname() failed.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
- sprintf(conn->local_ip, "%pI4", &sock_in.sin_addr.s_addr);
- conn->local_port = ntohs(sock_in.sin_port);
- }
-
conn->network_transport = np->np_network_transport;
pr_debug("Received iSCSI login request from %s on %s Network"
- " Portal %s:%hu\n", conn->login_ip,
- (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP",
- conn->local_ip, conn->local_port);
+ " Portal %s:%hu\n", conn->login_ip, np->np_transport->name,
+ conn->local_ip, conn->local_port);
pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
conn->conn_state = TARG_CONN_STATE_IN_LOGIN;
@@ -1053,13 +1198,17 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0)
goto new_sess_out;
}
-
/*
- * This will process the first login request, and call
- * iscsi_target_locate_portal(), and return a valid struct iscsi_login.
+ * SessionType: Discovery
+ *
+ * Locates Default Portal
+ *
+ * SessionType: Normal
+ *
+ * Locates Target Portal from NP -> Target IQN
*/
- login = iscsi_target_init_negotiation(np, conn, buffer);
- if (!login) {
+ rc = iscsi_target_locate_portal(np, conn, login);
+ if (rc < 0) {
tpg = conn->tpg;
goto new_sess_out;
}
@@ -1071,15 +1220,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
}
if (zero_tsih) {
- if (iscsi_login_zero_tsih_s2(conn) < 0) {
- iscsi_target_nego_release(login, conn);
+ if (iscsi_login_zero_tsih_s2(conn) < 0)
goto new_sess_out;
- }
} else {
- if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) {
- iscsi_target_nego_release(login, conn);
+ if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0)
goto old_sess_out;
- }
}
if (iscsi_target_start_negotiation(login, conn) < 0)
@@ -1156,8 +1301,18 @@ old_sess_out:
iscsi_release_param_list(conn->param_list);
conn->param_list = NULL;
}
- if (conn->sock)
+ iscsi_target_nego_release(conn);
+
+ if (conn->sock) {
sock_release(conn->sock);
+ conn->sock = NULL;
+ }
+
+ if (conn->conn_transport->iscsit_free_conn)
+ conn->conn_transport->iscsit_free_conn(conn);
+
+ iscsit_put_transport(conn->conn_transport);
+
kfree(conn);
if (tpg) {
@@ -1175,11 +1330,13 @@ out:
/* Wait for another socket.. */
if (!stop)
return 1;
-
+exit:
iscsi_stop_login_thread_timer(np);
spin_lock_bh(&np->np_thread_lock);
np->np_thread_state = ISCSI_NP_THREAD_EXIT;
+ np->np_thread = NULL;
spin_unlock_bh(&np->np_thread_lock);
+
return 0;
}
diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h
index 091dcae..63efd28 100644
--- a/drivers/target/iscsi/iscsi_target_login.h
+++ b/drivers/target/iscsi/iscsi_target_login.h
@@ -4,8 +4,14 @@
extern int iscsi_login_setup_crypto(struct iscsi_conn *);
extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *);
extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32);
+extern int iscsit_setup_np(struct iscsi_np *,
+ struct __kernel_sockaddr_storage *);
extern int iscsi_target_setup_login_socket(struct iscsi_np *,
struct __kernel_sockaddr_storage *);
+extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *);
+extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
+extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
+extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
extern int iscsi_target_login_thread(void *);
extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *);
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 9d902ae..8bc7e97 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -22,6 +22,7 @@
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
+#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_core.h"
#include "iscsi_target_parameters.h"
@@ -169,7 +170,7 @@ static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn)
kfree(conn->auth_protocol);
}
-static int iscsi_target_check_login_request(
+int iscsi_target_check_login_request(
struct iscsi_conn *conn,
struct iscsi_login *login)
{
@@ -352,11 +353,8 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
padding = ((-login->rsp_length) & 3);
- if (iscsi_login_tx_data(
- conn,
- login->rsp,
- login->rsp_buf,
- login->rsp_length + padding) < 0)
+ if (conn->conn_transport->iscsit_put_login_tx(conn, login,
+ login->rsp_length + padding) < 0)
return -1;
login->rsp_length = 0;
@@ -368,72 +366,12 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
return 0;
}
-static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
-{
- u32 padding = 0, payload_length;
- struct iscsi_login_req *login_req;
-
- if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
- return -1;
-
- login_req = (struct iscsi_login_req *) login->req;
- payload_length = ntoh24(login_req->dlength);
-
- pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
- " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
- login_req->flags, login_req->itt, login_req->cmdsn,
- login_req->exp_statsn, login_req->cid, payload_length);
-
- if (iscsi_target_check_login_request(conn, login) < 0)
- return -1;
-
- padding = ((-payload_length) & 3);
- memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
-
- if (iscsi_login_rx_data(
- conn,
- login->req_buf,
- payload_length + padding) < 0)
- return -1;
-
- return 0;
-}
-
static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
{
if (iscsi_target_do_tx_login_io(conn, login) < 0)
return -1;
- if (iscsi_target_do_rx_login_io(conn, login) < 0)
- return -1;
-
- return 0;
-}
-
-static int iscsi_target_get_initial_payload(
- struct iscsi_conn *conn,
- struct iscsi_login *login)
-{
- u32 padding = 0, payload_length;
- struct iscsi_login_req *login_req;
-
- login_req = (struct iscsi_login_req *) login->req;
- payload_length = ntoh24(login_req->dlength);
-
- pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
- " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
- login_req->flags, login_req->itt, login_req->cmdsn,
- login_req->exp_statsn, payload_length);
-
- if (iscsi_target_check_login_request(conn, login) < 0)
- return -1;
-
- padding = ((-payload_length) & 3);
-
- if (iscsi_login_rx_data(
- conn,
- login->req_buf,
- payload_length + padding) < 0)
+ if (conn->conn_transport->iscsit_get_login_rx(conn, login) < 0)
return -1;
return 0;
@@ -693,6 +631,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo
return -1;
if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
login->tsih = conn->sess->tsih;
+ login->login_complete = 1;
if (iscsi_target_do_tx_login_io(conn,
login) < 0)
return -1;
@@ -737,7 +676,7 @@ static void iscsi_initiatorname_tolower(
/*
* Processes the first Login Request..
*/
-static int iscsi_target_locate_portal(
+int iscsi_target_locate_portal(
struct iscsi_np *np,
struct iscsi_conn *conn,
struct iscsi_login *login)
@@ -746,29 +685,13 @@ static int iscsi_target_locate_portal(
char *tmpbuf, *start = NULL, *end = NULL, *key, *value;
struct iscsi_session *sess = conn->sess;
struct iscsi_tiqn *tiqn;
- struct iscsi_login_req *login_req;
+ struct iscsi_login_req *login_req;
u32 payload_length;
int sessiontype = 0, ret = 0;
login_req = (struct iscsi_login_req *) login->req;
payload_length = ntoh24(login_req->dlength);
- login->first_request = 1;
- login->leading_connection = (!login_req->tsih) ? 1 : 0;
- login->current_stage =
- (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
- login->version_min = login_req->min_version;
- login->version_max = login_req->max_version;
- memcpy(login->isid, login_req->isid, 6);
- login->cmd_sn = be32_to_cpu(login_req->cmdsn);
- login->init_task_tag = login_req->itt;
- login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
- login->cid = be16_to_cpu(login_req->cid);
- login->tsih = be16_to_cpu(login_req->tsih);
-
- if (iscsi_target_get_initial_payload(conn, login) < 0)
- return -1;
-
tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL);
if (!tmpbuf) {
pr_err("Unable to allocate memory for tmpbuf.\n");
@@ -800,6 +723,8 @@ static int iscsi_target_locate_portal(
start += strlen(key) + strlen(value) + 2;
}
+ printk("i_buf: %s, s_buf: %s, t_buf: %s\n", i_buf, s_buf, t_buf);
+
/*
* See 5.3. Login Phase.
*/
@@ -958,100 +883,30 @@ out:
return ret;
}
-struct iscsi_login *iscsi_target_init_negotiation(
- struct iscsi_np *np,
- struct iscsi_conn *conn,
- char *login_pdu)
-{
- struct iscsi_login *login;
-
- login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
- if (!login) {
- pr_err("Unable to allocate memory for struct iscsi_login.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- return NULL;
- }
-
- login->req = kmemdup(login_pdu, ISCSI_HDR_LEN, GFP_KERNEL);
- if (!login->req) {
- pr_err("Unable to allocate memory for Login Request.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- goto out;
- }
-
- login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
- if (!login->req_buf) {
- pr_err("Unable to allocate memory for response buffer.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- goto out;
- }
- /*
- * SessionType: Discovery
- *
- * Locates Default Portal
- *
- * SessionType: Normal
- *
- * Locates Target Portal from NP -> Target IQN
- */
- if (iscsi_target_locate_portal(np, conn, login) < 0) {
- goto out;
- }
-
- return login;
-out:
- kfree(login->req);
- kfree(login->req_buf);
- kfree(login);
-
- return NULL;
-}
-
int iscsi_target_start_negotiation(
struct iscsi_login *login,
struct iscsi_conn *conn)
{
- int ret = -1;
-
- login->rsp = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
- if (!login->rsp) {
- pr_err("Unable to allocate memory for"
- " Login Response.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- ret = -1;
- goto out;
- }
-
- login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
- if (!login->rsp_buf) {
- pr_err("Unable to allocate memory for"
- " request buffer.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- ret = -1;
- goto out;
- }
+ int ret;
ret = iscsi_target_do_login(conn, login);
-out:
if (ret != 0)
iscsi_remove_failed_auth_entry(conn);
- iscsi_target_nego_release(login, conn);
+ iscsi_target_nego_release(conn);
return ret;
}
-void iscsi_target_nego_release(
- struct iscsi_login *login,
- struct iscsi_conn *conn)
+void iscsi_target_nego_release(struct iscsi_conn *conn)
{
- kfree(login->req);
- kfree(login->rsp);
+ struct iscsi_login *login = conn->conn_login;
+
+ if (!login)
+ return;
+
kfree(login->req_buf);
kfree(login->rsp_buf);
kfree(login);
+
+ conn->conn_login = NULL;
}
diff --git a/drivers/target/iscsi/iscsi_target_nego.h b/drivers/target/iscsi/iscsi_target_nego.h
index 92e133a..f021cbd 100644
--- a/drivers/target/iscsi/iscsi_target_nego.h
+++ b/drivers/target/iscsi/iscsi_target_nego.h
@@ -7,11 +7,14 @@
extern void convert_null_to_semi(char *, int);
extern int extract_param(const char *, const char *, unsigned int, char *,
unsigned char *);
-extern struct iscsi_login *iscsi_target_init_negotiation(
- struct iscsi_np *, struct iscsi_conn *, char *);
+extern int iscsi_target_check_login_request(struct iscsi_conn *,
+ struct iscsi_login *);
+extern int iscsi_target_get_initial_payload(struct iscsi_conn *,
+ struct iscsi_login *);
+extern int iscsi_target_locate_portal(struct iscsi_np *, struct iscsi_conn *,
+ struct iscsi_login *);
extern int iscsi_target_start_negotiation(
struct iscsi_login *, struct iscsi_conn *);
-extern void iscsi_target_nego_release(
- struct iscsi_login *, struct iscsi_conn *);
+extern void iscsi_target_nego_release(struct iscsi_conn *);
#endif /* ISCSI_TARGET_NEGO_H */
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index ca2be40..84ce94a 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -59,7 +59,7 @@ int iscsi_login_tx_data(
char *text_buf,
int text_length)
{
- int length, tx_sent;
+ int length, tx_sent, iov_cnt = 1;
struct kvec iov[2];
length = (ISCSI_HDR_LEN + text_length);
@@ -67,8 +67,12 @@ int iscsi_login_tx_data(
memset(&iov[0], 0, 2 * sizeof(struct kvec));
iov[0].iov_len = ISCSI_HDR_LEN;
iov[0].iov_base = pdu_buf;
- iov[1].iov_len = text_length;
- iov[1].iov_base = text_buf;
+
+ if (text_buf && text_length) {
+ iov[1].iov_len = text_length;
+ iov[1].iov_base = text_buf;
+ iov_cnt++;
+ }
/*
* Initial Marker-less Interval.
@@ -77,7 +81,7 @@ int iscsi_login_tx_data(
*/
conn->if_marker += length;
- tx_sent = tx_data(conn, &iov[0], 2, length);
+ tx_sent = tx_data(conn, &iov[0], iov_cnt, length);
if (tx_sent != length) {
pr_err("tx_data returned %d, expecting %d.\n",
tx_sent, length);
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index ee8f8c6..439260b 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -31,6 +31,8 @@
#include "iscsi_target.h"
#include "iscsi_target_parameters.h"
+#include <target/iscsi/iscsi_transport.h>
+
struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt)
{
struct iscsi_portal_group *tpg;
@@ -508,7 +510,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n",
tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
- (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
+ np->np_transport->name);
return tpg_np;
}
@@ -522,7 +524,7 @@ static int iscsit_tpg_release_np(
pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n",
tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
- (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
+ np->np_transport->name);
tpg_np->tpg_np = NULL;
tpg_np->tpg = NULL;
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 7ce3505..4cf1e7f 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -24,6 +24,7 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include <target/target_core_configfs.h>
+#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_core.h"
#include "iscsi_target_parameters.h"
@@ -1226,34 +1227,19 @@ send_datacrc:
*/
int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail)
{
- u8 iscsi_hdr[ISCSI_HDR_LEN];
- int err;
- struct kvec iov;
struct iscsi_login_rsp *hdr;
+ struct iscsi_login *login = conn->conn_login;
+ login->login_failed = 1;
iscsit_collect_login_stats(conn, status_class, status_detail);
- memset(&iov, 0, sizeof(struct kvec));
- memset(&iscsi_hdr, 0x0, ISCSI_HDR_LEN);
-
- hdr = (struct iscsi_login_rsp *)&iscsi_hdr;
+ hdr = (struct iscsi_login_rsp *)&login->rsp[0];
hdr->opcode = ISCSI_OP_LOGIN_RSP;
hdr->status_class = status_class;
hdr->status_detail = status_detail;
hdr->itt = conn->login_itt;
- iov.iov_base = &iscsi_hdr;
- iov.iov_len = ISCSI_HDR_LEN;
-
- PRINT_BUFF(iscsi_hdr, ISCSI_HDR_LEN);
-
- err = tx_data(conn, &iov, 1, ISCSI_HDR_LEN);
- if (err != ISCSI_HDR_LEN) {
- pr_err("tx_data returned less than expected\n");
- return -1;
- }
-
- return 0;
+ return conn->conn_transport->iscsit_put_login_tx(conn, login, 0);
}
void iscsit_print_session_params(struct iscsi_session *sess)
@@ -1432,7 +1418,8 @@ void iscsit_collect_login_stats(
strcpy(ls->last_intr_fail_name,
(intrname ? intrname->value : "Unknown"));
- ls->last_intr_fail_ip_family = conn->sock->sk->sk_family;
+ ls->last_intr_fail_ip_family = conn->login_family;
+
snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE,
"%s", conn->login_ip);
ls->last_fail_time = get_jiffies_64();
--
1.7.2.5
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [RFC 02/11] iscsi-target: Initial traditional TCP conversion to iscsit_transport
2013-03-08 1:45 ` [RFC 02/11] iscsi-target: Initial traditional TCP conversion to iscsit_transport Nicholas A. Bellinger
@ 2013-03-22 17:23 ` Andy Grover
2013-03-22 22:38 ` Nicholas A. Bellinger
0 siblings, 1 reply; 35+ messages in thread
From: Andy Grover @ 2013-03-22 17:23 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On 03/07/2013 05:45 PM, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
>
> This patch performs the initial conversion of existing traditional iscsi
> to use iscsit_transport API callers. This includes:
>
> - iscsi-np cleanups for iscsit_transport_type
> - Add iscsi-np transport calls w/ ->iscsit_setup_up() and ->iscsit_free_np()
> - Convert login thread process context to use ->iscsit_accept_np() for
> connections with pre-allocated struct iscsi_conn
> - Convert existing socket accept code to iscsit_accept_np()
> - Convert login RX/TX callers to use ->iscsit_get_login_rx() and
> ->iscsit_put_login_tx() to exchange request/response PDUs
> - Convert existing socket login RX/TX calls into iscsit_get_login_rx()
> and iscsit_put_login_tx()
> - Change iscsit_close_connection() to invoke ->iscsit_free_conn() +
> iscsit_put_transport() calls.
> - Add iscsit_create_transport() + iscsit_destroy_transport() calls
> to module init/exit
>
> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> ---
> drivers/target/iscsi/iscsi_target.c | 35 ++-
> drivers/target/iscsi/iscsi_target_core.h | 15 +-
> drivers/target/iscsi/iscsi_target_login.c | 411 ++++++++++++++++--------
> drivers/target/iscsi/iscsi_target_login.h | 6 +
> drivers/target/iscsi/iscsi_target_nego.c | 185 ++----------
> drivers/target/iscsi/iscsi_target_nego.h | 11 +-
> drivers/target/iscsi/iscsi_target_parameters.c | 12 +-
> drivers/target/iscsi/iscsi_target_tpg.c | 6 +-
> drivers/target/iscsi/iscsi_target_util.c | 27 +--
> 9 files changed, 376 insertions(+), 332 deletions(-)
>
> diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
> index 23a98e6..4dc1c9b 100644
> --- a/drivers/target/iscsi/iscsi_target.c
> +++ b/drivers/target/iscsi/iscsi_target.c
> @@ -49,6 +49,8 @@
> #include "iscsi_target_device.h"
> #include "iscsi_target_stat.h"
>
> +#include <target/iscsi/iscsi_transport.h>
> +
> static LIST_HEAD(g_tiqn_list);
> static LIST_HEAD(g_np_list);
> static DEFINE_SPINLOCK(tiqn_lock);
> @@ -400,8 +402,7 @@ struct iscsi_np *iscsit_add_np(
> spin_unlock_bh(&np_lock);
>
> pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
> - np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
> - "TCP" : "SCTP");
> + np->np_ip, np->np_port, np->np_transport->name);
>
> return np;
> }
> @@ -440,11 +441,10 @@ int iscsit_reset_np_thread(
> return 0;
> }
>
> -static int iscsit_del_np_comm(struct iscsi_np *np)
> +static void iscsit_free_np(struct iscsi_np *np)
> {
> if (np->np_socket)
> sock_release(np->np_socket);
> - return 0;
> }
>
> int iscsit_del_np(struct iscsi_np *np)
> @@ -466,20 +466,32 @@ int iscsit_del_np(struct iscsi_np *np)
> send_sig(SIGINT, np->np_thread, 1);
> kthread_stop(np->np_thread);
> }
> - iscsit_del_np_comm(np);
> +
> + np->np_transport->iscsit_free_np(np);
>
> spin_lock_bh(&np_lock);
> list_del(&np->np_list);
> spin_unlock_bh(&np_lock);
>
> pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
> - np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
> - "TCP" : "SCTP");
> + np->np_ip, np->np_port, np->np_transport->name);
>
> + iscsit_put_transport(np->np_transport);
> kfree(np);
> return 0;
> }
>
> +static struct iscsit_transport iscsi_target_transport = {
> + .name = "iSCSI/TCP",
> + .transport_type = ISCSI_TCP,
> + .owner = NULL,
> + .iscsit_setup_np = iscsit_setup_np,
> + .iscsit_accept_np = iscsit_accept_np,
> + .iscsit_free_np = iscsit_free_np,
> + .iscsit_get_login_rx = iscsit_get_login_rx,
> + .iscsit_put_login_tx = iscsit_put_login_tx,
> +};
> +
> static int __init iscsi_target_init_module(void)
> {
> int ret = 0;
> @@ -556,6 +568,8 @@ static int __init iscsi_target_init_module(void)
> goto ooo_out;
> }
>
> + iscsit_create_transport(&iscsi_target_transport);
> +
> if (iscsit_load_discovery_tpg() < 0)
> goto r2t_out;
>
> @@ -586,6 +600,7 @@ static void __exit iscsi_target_cleanup_module(void)
> iscsi_deallocate_thread_sets();
> iscsi_thread_set_free();
> iscsit_release_discovery_tpg();
> + iscsit_destroy_transport(&iscsi_target_transport);
> kmem_cache_destroy(lio_cmd_cache);
> kmem_cache_destroy(lio_qr_cache);
> kmem_cache_destroy(lio_dr_cache);
> @@ -4045,6 +4060,12 @@ int iscsit_close_connection(
>
> if (conn->sock)
> sock_release(conn->sock);
> +
> + if (conn->conn_transport->iscsit_free_conn)
> + conn->conn_transport->iscsit_free_conn(conn);
For all the function pointers in conn_transport, won't they always be
there? If so, can we just call them w/o checking?
> +
> + iscsit_put_transport(conn->conn_transport);
> +
> conn->thread_set = NULL;
>
> pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
> diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
> index 7a333d2..2587677 100644
> --- a/drivers/target/iscsi/iscsi_target_core.h
> +++ b/drivers/target/iscsi/iscsi_target_core.h
> @@ -60,7 +60,7 @@
>
> #define ISCSI_IOV_DATA_BUFFER 5
>
> -enum tpg_np_network_transport_table {
> +enum iscsit_transport_type {
> ISCSI_TCP = 0,
> ISCSI_SCTP_TCP = 1,
> ISCSI_SCTP_UDP = 2,
> @@ -503,6 +503,7 @@ struct iscsi_conn {
> u16 login_port;
> u16 local_port;
> int net_size;
> + int login_family;
> u32 auth_id;
> u32 conn_flags;
> /* Used for iscsi_tx_login_rsp() */
> @@ -562,9 +563,12 @@ struct iscsi_conn {
> struct list_head immed_queue_list;
> struct list_head response_queue_list;
> struct iscsi_conn_ops *conn_ops;
> + struct iscsi_login *conn_login;
> + struct iscsit_transport *conn_transport;
> struct iscsi_param_list *param_list;
> /* Used for per connection auth state machine */
> void *auth_protocol;
> + void *context;
> struct iscsi_login_thread_s *login_thread;
> struct iscsi_portal_group *tpg;
> /* Pointer to parent session */
> @@ -663,6 +667,8 @@ struct iscsi_login {
> u8 first_request;
> u8 version_min;
> u8 version_max;
> + u8 login_complete;
> + u8 login_failed;
> char isid[6];
> u32 cmd_sn;
> itt_t init_task_tag;
> @@ -670,10 +676,11 @@ struct iscsi_login {
> u32 rsp_length;
> u16 cid;
> u16 tsih;
> - char *req;
> - char *rsp;
> + char req[ISCSI_HDR_LEN];
> + char rsp[ISCSI_HDR_LEN];
> char *req_buf;
> char *rsp_buf;
> + struct iscsi_conn *conn;
> } ____cacheline_aligned;
>
> struct iscsi_node_attrib {
> @@ -754,6 +761,8 @@ struct iscsi_np {
> struct task_struct *np_thread;
> struct timer_list np_login_timer;
> struct iscsi_portal_group *np_login_tpg;
> + void *np_context;
> + struct iscsit_transport *np_transport;
> struct list_head np_list;
> } ____cacheline_aligned;
>
> diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
> index fdb632f..9354a5f 100644
> --- a/drivers/target/iscsi/iscsi_target_login.c
> +++ b/drivers/target/iscsi/iscsi_target_login.c
> @@ -39,8 +39,39 @@
> #include "iscsi_target.h"
> #include "iscsi_target_parameters.h"
>
> -static int iscsi_login_init_conn(struct iscsi_conn *conn)
> +#include <target/iscsi/iscsi_transport.h>
> +
> +static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
> {
> + struct iscsi_login *login;
> +
> + login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
> + if (!login) {
> + pr_err("Unable to allocate memory for struct iscsi_login.\n");
> + return NULL;
> + }
> + login->conn = conn;
> + login->first_request = 1;
> +
> + login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
> + if (!login->req_buf) {
> + pr_err("Unable to allocate memory for response buffer.\n");
> + goto out_login;
> + }
> +
> + login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
> + if (!login->rsp_buf) {
> + pr_err("Unable to allocate memory for request buffer.\n");
> + goto out_req_buf;
> + }
> +
> + conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
> + if (!conn->conn_ops) {
> + pr_err("Unable to allocate memory for"
> + " struct iscsi_conn_ops.\n");
> + goto out_rsp_buf;
> + }
> +
> init_waitqueue_head(&conn->queues_wq);
> INIT_LIST_HEAD(&conn->conn_list);
> INIT_LIST_HEAD(&conn->conn_cmd_list);
> @@ -62,10 +93,21 @@ static int iscsi_login_init_conn(struct iscsi_conn *conn)
>
> if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) {
> pr_err("Unable to allocate conn->conn_cpumask\n");
> - return -ENOMEM;
> + goto out_conn_ops;
> }
> + conn->conn_login = login;
>
> - return 0;
> + return login;
> +
> +out_conn_ops:
> + kfree(conn->conn_ops);
> +out_rsp_buf:
> + kfree(login->rsp_buf);
> +out_req_buf:
> + kfree(login->req_buf);
> +out_login:
> + kfree(login);
> + return NULL;
> }
>
> /*
> @@ -635,7 +677,13 @@ static int iscsi_post_login_handler(
> spin_unlock_bh(&sess->conn_lock);
>
> iscsi_post_login_start_timers(conn);
> - iscsi_activate_thread_set(conn, ts);
> +
> + if (conn->conn_transport == ISCSI_TCP) {
> + iscsi_activate_thread_set(conn, ts);
I thought conn_transport was a pointer? It looks like it's being
compared against an enum here.
> + } else {
> + printk("Not calling iscsi_activate_thread_set....\n");
> + dump_stack();
Left-in debug code?
> + }
> /*
> * Determine CPU mask to ensure connection's RX and TX kthreads
> * are scheduled on the same CPU.
> @@ -764,11 +812,11 @@ static void iscsi_stop_login_thread_timer(struct iscsi_np *np)
> spin_unlock_bh(&np->np_thread_lock);
> }
>
> -int iscsi_target_setup_login_socket(
> +int iscsit_setup_np(
> struct iscsi_np *np,
> struct __kernel_sockaddr_storage *sockaddr)
> {
> - struct socket *sock;
> + struct socket *sock = NULL;
> int backlog = 5, ret, opt = 0, len;
>
> switch (np->np_network_transport) {
> @@ -784,15 +832,15 @@ int iscsi_target_setup_login_socket(
> np->np_ip_proto = IPPROTO_SCTP;
> np->np_sock_type = SOCK_SEQPACKET;
> break;
> - case ISCSI_IWARP_TCP:
> - case ISCSI_IWARP_SCTP:
> - case ISCSI_INFINIBAND:
> default:
> pr_err("Unsupported network_transport: %d\n",
> np->np_network_transport);
> return -EINVAL;
> }
>
> + np->np_ip_proto = IPPROTO_TCP;
> + np->np_sock_type = SOCK_STREAM;
> +
> ret = sock_create(sockaddr->ss_family, np->np_sock_type,
> np->np_ip_proto, &sock);
> if (ret < 0) {
> @@ -856,7 +904,6 @@ int iscsi_target_setup_login_socket(
> }
>
> return 0;
> -
> fail:
> np->np_socket = NULL;
> if (sock)
> @@ -864,21 +911,168 @@ fail:
> return ret;
> }
>
> +int iscsi_target_setup_login_socket(
> + struct iscsi_np *np,
> + struct __kernel_sockaddr_storage *sockaddr)
> +{
> + struct iscsit_transport *t;
> + int rc;
> +
> + t = iscsit_get_transport(np->np_network_transport);
> + if (!t)
> + return -EINVAL;
> +
> + rc = t->iscsit_setup_np(np, sockaddr);
> + if (rc < 0)
> + return rc;
> +
> + np->np_transport = t;
> + printk("Set np->np_transport to %p -> %s\n", np->np_transport,
> + np->np_transport->name);
> + return 0;
> +}
> +
> +int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
> +{
> + struct socket *new_sock, *sock = np->np_socket;
> + struct sockaddr_in sock_in;
> + struct sockaddr_in6 sock_in6;
> + int rc, err;
> +
> + rc = kernel_accept(sock, &new_sock, 0);
> + if (rc < 0)
> + return rc;
> +
> + conn->sock = new_sock;
> + conn->login_family = np->np_sockaddr.ss_family;
> + printk("iSCSI/TCP: Setup conn->sock from new_sock: %p\n", new_sock);
> +
> + if (np->np_sockaddr.ss_family == AF_INET6) {
> + memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
> +
> + rc = conn->sock->ops->getname(conn->sock,
> + (struct sockaddr *)&sock_in6, &err, 1);
> + if (!rc) {
> + snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
> + &sock_in6.sin6_addr.in6_u);
> + conn->login_port = ntohs(sock_in6.sin6_port);
> + }
> +
> + rc = conn->sock->ops->getname(conn->sock,
> + (struct sockaddr *)&sock_in6, &err, 0);
> + if (!rc) {
> + snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
> + &sock_in6.sin6_addr.in6_u);
> + conn->local_port = ntohs(sock_in6.sin6_port);
> + }
> + } else {
> + memset(&sock_in, 0, sizeof(struct sockaddr_in));
> +
> + rc = conn->sock->ops->getname(conn->sock,
> + (struct sockaddr *)&sock_in, &err, 1);
> + if (!rc) {
> + sprintf(conn->login_ip, "%pI4",
> + &sock_in.sin_addr.s_addr);
> + conn->login_port = ntohs(sock_in.sin_port);
> + }
> +
> + rc = conn->sock->ops->getname(conn->sock,
> + (struct sockaddr *)&sock_in, &err, 0);
> + if (!rc) {
> + sprintf(conn->local_ip, "%pI4",
> + &sock_in.sin_addr.s_addr);
> + conn->local_port = ntohs(sock_in.sin_port);
> + }
> + }
> +
> + return 0;
> +}
> +
> +int iscsit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
> +{
> + struct iscsi_login_req *login_req;
> + u32 padding = 0, payload_length;
> +
> + if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
> + return -1;
> +
> + login_req = (struct iscsi_login_req *)login->req;
> + payload_length = ntoh24(login_req->dlength);
> + padding = ((-payload_length) & 3);
> +
> + pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
> + " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
> + login_req->flags, login_req->itt, login_req->cmdsn,
> + login_req->exp_statsn, login_req->cid, payload_length);
> + /*
> + * Setup the initial iscsi_login values from the leading
> + * login request PDU.
> + */
> + if (login->first_request) {
> + login_req = (struct iscsi_login_req *)login->req;
> + login->leading_connection = (!login_req->tsih) ? 1 : 0;
> + login->current_stage =
> + (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
> + login->version_min = login_req->min_version;
> + login->version_max = login_req->max_version;
> + memcpy(login->isid, login_req->isid, 6);
> + login->cmd_sn = be32_to_cpu(login_req->cmdsn);
> + login->init_task_tag = login_req->itt;
> + login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
> + login->cid = be16_to_cpu(login_req->cid);
> + login->tsih = be16_to_cpu(login_req->tsih);
> + }
> +
> + if (iscsi_target_check_login_request(conn, login) < 0)
> + return -1;
Better return values?
> +
> + memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
> + if (iscsi_login_rx_data(conn, login->req_buf,
> + payload_length + padding) < 0)
> + return -1;
> +
> + return 0;
> +}
> +
> +int iscsit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
> + u32 length)
> +{
> + if (iscsi_login_tx_data(conn, login->rsp, login->rsp_buf, length) < 0)
> + return -1;
> +
> + return 0;
> +}
> +
> +static int
> +iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t)
> +{
> + int rc;
> +
> + if (!t->owner) {
> + conn->conn_transport = t;
> + return 0;
> + }
> +
> + rc = try_module_get(t->owner);
> + if (!rc) {
> + pr_err("try_module_get() failed for %s\n", t->name);
> + return -EINVAL;
> + }
> +
> + conn->conn_transport = t;
> + return 0;
> +}
> +
> static int __iscsi_target_login_thread(struct iscsi_np *np)
> {
> - u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0;
> - int err, ret = 0, stop;
> + u8 *buffer, zero_tsih = 0;
> + int ret = 0, rc, stop;
> struct iscsi_conn *conn = NULL;
> struct iscsi_login *login;
> struct iscsi_portal_group *tpg = NULL;
> - struct socket *new_sock, *sock;
> - struct kvec iov;
> struct iscsi_login_req *pdu;
> - struct sockaddr_in sock_in;
> - struct sockaddr_in6 sock_in6;
>
> flush_signals(current);
> - sock = np->np_socket;
>
> spin_lock_bh(&np->np_thread_lock);
> if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
> @@ -889,75 +1083,76 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
> }
> spin_unlock_bh(&np->np_thread_lock);
>
> - if (kernel_accept(sock, &new_sock, 0) < 0) {
> - spin_lock_bh(&np->np_thread_lock);
> - if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
> - spin_unlock_bh(&np->np_thread_lock);
> - complete(&np->np_restart_comp);
> - /* Get another socket */
> - return 1;
> - }
> - spin_unlock_bh(&np->np_thread_lock);
> - goto out;
> - }
> - iscsi_start_login_thread_timer(np);
> -
> conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
> if (!conn) {
> pr_err("Could not allocate memory for"
> " new connection\n");
> - sock_release(new_sock);
> /* Get another socket */
> return 1;
> }
> -
> pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
> conn->conn_state = TARG_CONN_STATE_FREE;
> - conn->sock = new_sock;
>
> - pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
> - conn->conn_state = TARG_CONN_STATE_XPT_UP;
> + if (iscsit_conn_set_transport(conn, np->np_transport) < 0) {
> + kfree(conn);
> + return 1;
> + }
>
> - /*
> - * Allocate conn->conn_ops early as a failure calling
> - * iscsit_tx_login_rsp() below will call tx_data().
> - */
> - conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
> - if (!conn->conn_ops) {
> - pr_err("Unable to allocate memory for"
> - " struct iscsi_conn_ops.\n");
> - goto new_sess_out;
> + rc = np->np_transport->iscsit_accept_np(np, conn);
> + if (rc == -ENOSYS) {
> + complete(&np->np_restart_comp);
> + iscsit_put_transport(conn->conn_transport);
> + kfree(conn);
> + conn = NULL;
> + goto exit;
> + } else if (rc < 0) {
> + spin_lock_bh(&np->np_thread_lock);
> + if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
> + spin_unlock_bh(&np->np_thread_lock);
> + complete(&np->np_restart_comp);
> + if (ret == -ENODEV) {
> + iscsit_put_transport(conn->conn_transport);
> + kfree(conn);
> + conn = NULL;
> + goto out;
> + }
> + /* Get another socket */
> + return 1;
> + }
> + spin_unlock_bh(&np->np_thread_lock);
> + iscsit_put_transport(conn->conn_transport);
> + kfree(conn);
> + conn = NULL;
> + goto out;
> }
> /*
> * Perform the remaining iSCSI connection initialization items..
> */
> - if (iscsi_login_init_conn(conn) < 0)
> - goto new_sess_out;
> -
> - memset(buffer, 0, ISCSI_HDR_LEN);
> - memset(&iov, 0, sizeof(struct kvec));
> - iov.iov_base = buffer;
> - iov.iov_len = ISCSI_HDR_LEN;
> -
> - if (rx_data(conn, &iov, 1, ISCSI_HDR_LEN) <= 0) {
> - pr_err("rx_data() returned an error.\n");
> + login = iscsi_login_init_conn(conn);
> + if (!login) {
> goto new_sess_out;
> }
>
> - iscsi_opcode = (buffer[0] & ISCSI_OPCODE_MASK);
> - if (!(iscsi_opcode & ISCSI_OP_LOGIN)) {
> - pr_err("First opcode is not login request,"
> - " failing login request.\n");
> - goto new_sess_out;
> - }
> + iscsi_start_login_thread_timer(np);
>
> - pdu = (struct iscsi_login_req *) buffer;
> + pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
> + conn->conn_state = TARG_CONN_STATE_XPT_UP;
> + /*
> + * This will process the first login request + payload..
> + */
> + rc = np->np_transport->iscsit_get_login_rx(conn, login);
> + if (rc == 1)
> + return 1;
> + else if (rc < 0)
> + goto new_sess_out;
>
> + buffer = &login->req[0];
> + pdu = (struct iscsi_login_req *)buffer;
> /*
> * Used by iscsit_tx_login_rsp() for Login Resonses PDUs
> * when Status-Class != 0.
> */
> - conn->login_itt = pdu->itt;
> + conn->login_itt = pdu->itt;
>
> spin_lock_bh(&np->np_thread_lock);
> if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
> @@ -970,61 +1165,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
> }
> spin_unlock_bh(&np->np_thread_lock);
>
> - if (np->np_sockaddr.ss_family == AF_INET6) {
> - memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
> -
> - if (conn->sock->ops->getname(conn->sock,
> - (struct sockaddr *)&sock_in6, &err, 1) < 0) {
> - pr_err("sock_ops->getname() failed.\n");
> - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> - ISCSI_LOGIN_STATUS_TARGET_ERROR);
> - goto new_sess_out;
> - }
> - snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
> - &sock_in6.sin6_addr.in6_u);
> - conn->login_port = ntohs(sock_in6.sin6_port);
> -
> - if (conn->sock->ops->getname(conn->sock,
> - (struct sockaddr *)&sock_in6, &err, 0) < 0) {
> - pr_err("sock_ops->getname() failed.\n");
> - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> - ISCSI_LOGIN_STATUS_TARGET_ERROR);
> - goto new_sess_out;
> - }
> - snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
> - &sock_in6.sin6_addr.in6_u);
> - conn->local_port = ntohs(sock_in6.sin6_port);
> -
> - } else {
> - memset(&sock_in, 0, sizeof(struct sockaddr_in));
> -
> - if (conn->sock->ops->getname(conn->sock,
> - (struct sockaddr *)&sock_in, &err, 1) < 0) {
> - pr_err("sock_ops->getname() failed.\n");
> - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> - ISCSI_LOGIN_STATUS_TARGET_ERROR);
> - goto new_sess_out;
> - }
> - sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr);
> - conn->login_port = ntohs(sock_in.sin_port);
> -
> - if (conn->sock->ops->getname(conn->sock,
> - (struct sockaddr *)&sock_in, &err, 0) < 0) {
> - pr_err("sock_ops->getname() failed.\n");
> - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> - ISCSI_LOGIN_STATUS_TARGET_ERROR);
> - goto new_sess_out;
> - }
> - sprintf(conn->local_ip, "%pI4", &sock_in.sin_addr.s_addr);
> - conn->local_port = ntohs(sock_in.sin_port);
> - }
> -
> conn->network_transport = np->np_network_transport;
>
> pr_debug("Received iSCSI login request from %s on %s Network"
> - " Portal %s:%hu\n", conn->login_ip,
> - (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP",
> - conn->local_ip, conn->local_port);
> + " Portal %s:%hu\n", conn->login_ip, np->np_transport->name,
> + conn->local_ip, conn->local_port);
>
> pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
> conn->conn_state = TARG_CONN_STATE_IN_LOGIN;
> @@ -1053,13 +1198,17 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
> if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0)
> goto new_sess_out;
> }
> -
> /*
> - * This will process the first login request, and call
> - * iscsi_target_locate_portal(), and return a valid struct iscsi_login.
> + * SessionType: Discovery
> + *
> + * Locates Default Portal
> + *
> + * SessionType: Normal
> + *
> + * Locates Target Portal from NP -> Target IQN
> */
> - login = iscsi_target_init_negotiation(np, conn, buffer);
> - if (!login) {
> + rc = iscsi_target_locate_portal(np, conn, login);
> + if (rc < 0) {
> tpg = conn->tpg;
> goto new_sess_out;
> }
> @@ -1071,15 +1220,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
> }
>
> if (zero_tsih) {
> - if (iscsi_login_zero_tsih_s2(conn) < 0) {
> - iscsi_target_nego_release(login, conn);
> + if (iscsi_login_zero_tsih_s2(conn) < 0)
> goto new_sess_out;
> - }
> } else {
> - if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) {
> - iscsi_target_nego_release(login, conn);
> + if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0)
> goto old_sess_out;
> - }
> }
>
> if (iscsi_target_start_negotiation(login, conn) < 0)
> @@ -1156,8 +1301,18 @@ old_sess_out:
> iscsi_release_param_list(conn->param_list);
> conn->param_list = NULL;
> }
> - if (conn->sock)
> + iscsi_target_nego_release(conn);
> +
> + if (conn->sock) {
> sock_release(conn->sock);
> + conn->sock = NULL;
> + }
> +
> + if (conn->conn_transport->iscsit_free_conn)
> + conn->conn_transport->iscsit_free_conn(conn);
> +
> + iscsit_put_transport(conn->conn_transport);
> +
> kfree(conn);
>
> if (tpg) {
> @@ -1175,11 +1330,13 @@ out:
> /* Wait for another socket.. */
> if (!stop)
> return 1;
> -
> +exit:
> iscsi_stop_login_thread_timer(np);
> spin_lock_bh(&np->np_thread_lock);
> np->np_thread_state = ISCSI_NP_THREAD_EXIT;
> + np->np_thread = NULL;
> spin_unlock_bh(&np->np_thread_lock);
> +
> return 0;
> }
>
> diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h
> index 091dcae..63efd28 100644
> --- a/drivers/target/iscsi/iscsi_target_login.h
> +++ b/drivers/target/iscsi/iscsi_target_login.h
> @@ -4,8 +4,14 @@
> extern int iscsi_login_setup_crypto(struct iscsi_conn *);
> extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *);
> extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32);
> +extern int iscsit_setup_np(struct iscsi_np *,
> + struct __kernel_sockaddr_storage *);
> extern int iscsi_target_setup_login_socket(struct iscsi_np *,
> struct __kernel_sockaddr_storage *);
> +extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *);
> +extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
> +extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
> +extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
> extern int iscsi_target_login_thread(void *);
> extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *);
>
> diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
> index 9d902ae..8bc7e97 100644
> --- a/drivers/target/iscsi/iscsi_target_nego.c
> +++ b/drivers/target/iscsi/iscsi_target_nego.c
> @@ -22,6 +22,7 @@
> #include <scsi/iscsi_proto.h>
> #include <target/target_core_base.h>
> #include <target/target_core_fabric.h>
> +#include <target/iscsi/iscsi_transport.h>
>
> #include "iscsi_target_core.h"
> #include "iscsi_target_parameters.h"
> @@ -169,7 +170,7 @@ static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn)
> kfree(conn->auth_protocol);
> }
>
> -static int iscsi_target_check_login_request(
> +int iscsi_target_check_login_request(
> struct iscsi_conn *conn,
> struct iscsi_login *login)
> {
> @@ -352,11 +353,8 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
>
> padding = ((-login->rsp_length) & 3);
>
> - if (iscsi_login_tx_data(
> - conn,
> - login->rsp,
> - login->rsp_buf,
> - login->rsp_length + padding) < 0)
> + if (conn->conn_transport->iscsit_put_login_tx(conn, login,
> + login->rsp_length + padding) < 0)
> return -1;
>
> login->rsp_length = 0;
> @@ -368,72 +366,12 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
> return 0;
> }
>
> -static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
> -{
> - u32 padding = 0, payload_length;
> - struct iscsi_login_req *login_req;
> -
> - if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
> - return -1;
> -
> - login_req = (struct iscsi_login_req *) login->req;
> - payload_length = ntoh24(login_req->dlength);
> -
> - pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
> - " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
> - login_req->flags, login_req->itt, login_req->cmdsn,
> - login_req->exp_statsn, login_req->cid, payload_length);
> -
> - if (iscsi_target_check_login_request(conn, login) < 0)
> - return -1;
> -
> - padding = ((-payload_length) & 3);
> - memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
> -
> - if (iscsi_login_rx_data(
> - conn,
> - login->req_buf,
> - payload_length + padding) < 0)
> - return -1;
> -
> - return 0;
> -}
> -
> static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
> {
> if (iscsi_target_do_tx_login_io(conn, login) < 0)
> return -1;
>
> - if (iscsi_target_do_rx_login_io(conn, login) < 0)
> - return -1;
> -
> - return 0;
> -}
> -
> -static int iscsi_target_get_initial_payload(
> - struct iscsi_conn *conn,
> - struct iscsi_login *login)
> -{
> - u32 padding = 0, payload_length;
> - struct iscsi_login_req *login_req;
> -
> - login_req = (struct iscsi_login_req *) login->req;
> - payload_length = ntoh24(login_req->dlength);
> -
> - pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
> - " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
> - login_req->flags, login_req->itt, login_req->cmdsn,
> - login_req->exp_statsn, payload_length);
> -
> - if (iscsi_target_check_login_request(conn, login) < 0)
> - return -1;
> -
> - padding = ((-payload_length) & 3);
> -
> - if (iscsi_login_rx_data(
> - conn,
> - login->req_buf,
> - payload_length + padding) < 0)
> + if (conn->conn_transport->iscsit_get_login_rx(conn, login) < 0)
> return -1;
>
> return 0;
> @@ -693,6 +631,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo
> return -1;
> if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
> login->tsih = conn->sess->tsih;
> + login->login_complete = 1;
> if (iscsi_target_do_tx_login_io(conn,
> login) < 0)
> return -1;
> @@ -737,7 +676,7 @@ static void iscsi_initiatorname_tolower(
> /*
> * Processes the first Login Request..
> */
> -static int iscsi_target_locate_portal(
> +int iscsi_target_locate_portal(
> struct iscsi_np *np,
> struct iscsi_conn *conn,
> struct iscsi_login *login)
> @@ -746,29 +685,13 @@ static int iscsi_target_locate_portal(
> char *tmpbuf, *start = NULL, *end = NULL, *key, *value;
> struct iscsi_session *sess = conn->sess;
> struct iscsi_tiqn *tiqn;
> - struct iscsi_login_req *login_req;
> + struct iscsi_login_req *login_req;
tab got replaced by spaces?
-- Andy
> u32 payload_length;
> int sessiontype = 0, ret = 0;
>
> login_req = (struct iscsi_login_req *) login->req;
> payload_length = ntoh24(login_req->dlength);
>
> - login->first_request = 1;
> - login->leading_connection = (!login_req->tsih) ? 1 : 0;
> - login->current_stage =
> - (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
> - login->version_min = login_req->min_version;
> - login->version_max = login_req->max_version;
> - memcpy(login->isid, login_req->isid, 6);
> - login->cmd_sn = be32_to_cpu(login_req->cmdsn);
> - login->init_task_tag = login_req->itt;
> - login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
> - login->cid = be16_to_cpu(login_req->cid);
> - login->tsih = be16_to_cpu(login_req->tsih);
> -
> - if (iscsi_target_get_initial_payload(conn, login) < 0)
> - return -1;
> -
> tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL);
> if (!tmpbuf) {
> pr_err("Unable to allocate memory for tmpbuf.\n");
> @@ -800,6 +723,8 @@ static int iscsi_target_locate_portal(
> start += strlen(key) + strlen(value) + 2;
> }
>
> + printk("i_buf: %s, s_buf: %s, t_buf: %s\n", i_buf, s_buf, t_buf);
> +
> /*
> * See 5.3. Login Phase.
> */
> @@ -958,100 +883,30 @@ out:
> return ret;
> }
>
> -struct iscsi_login *iscsi_target_init_negotiation(
> - struct iscsi_np *np,
> - struct iscsi_conn *conn,
> - char *login_pdu)
> -{
> - struct iscsi_login *login;
> -
> - login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
> - if (!login) {
> - pr_err("Unable to allocate memory for struct iscsi_login.\n");
> - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> - ISCSI_LOGIN_STATUS_NO_RESOURCES);
> - return NULL;
> - }
> -
> - login->req = kmemdup(login_pdu, ISCSI_HDR_LEN, GFP_KERNEL);
> - if (!login->req) {
> - pr_err("Unable to allocate memory for Login Request.\n");
> - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> - ISCSI_LOGIN_STATUS_NO_RESOURCES);
> - goto out;
> - }
> -
> - login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
> - if (!login->req_buf) {
> - pr_err("Unable to allocate memory for response buffer.\n");
> - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> - ISCSI_LOGIN_STATUS_NO_RESOURCES);
> - goto out;
> - }
> - /*
> - * SessionType: Discovery
> - *
> - * Locates Default Portal
> - *
> - * SessionType: Normal
> - *
> - * Locates Target Portal from NP -> Target IQN
> - */
> - if (iscsi_target_locate_portal(np, conn, login) < 0) {
> - goto out;
> - }
> -
> - return login;
> -out:
> - kfree(login->req);
> - kfree(login->req_buf);
> - kfree(login);
> -
> - return NULL;
> -}
> -
> int iscsi_target_start_negotiation(
> struct iscsi_login *login,
> struct iscsi_conn *conn)
> {
> - int ret = -1;
> -
> - login->rsp = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
> - if (!login->rsp) {
> - pr_err("Unable to allocate memory for"
> - " Login Response.\n");
> - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> - ISCSI_LOGIN_STATUS_NO_RESOURCES);
> - ret = -1;
> - goto out;
> - }
> -
> - login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
> - if (!login->rsp_buf) {
> - pr_err("Unable to allocate memory for"
> - " request buffer.\n");
> - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> - ISCSI_LOGIN_STATUS_NO_RESOURCES);
> - ret = -1;
> - goto out;
> - }
> + int ret;
>
> ret = iscsi_target_do_login(conn, login);
> -out:
> if (ret != 0)
> iscsi_remove_failed_auth_entry(conn);
>
> - iscsi_target_nego_release(login, conn);
> + iscsi_target_nego_release(conn);
> return ret;
> }
>
> -void iscsi_target_nego_release(
> - struct iscsi_login *login,
> - struct iscsi_conn *conn)
> +void iscsi_target_nego_release(struct iscsi_conn *conn)
> {
> - kfree(login->req);
> - kfree(login->rsp);
> + struct iscsi_login *login = conn->conn_login;
> +
> + if (!login)
> + return;
> +
> kfree(login->req_buf);
> kfree(login->rsp_buf);
> kfree(login);
> +
> + conn->conn_login = NULL;
> }
> diff --git a/drivers/target/iscsi/iscsi_target_nego.h b/drivers/target/iscsi/iscsi_target_nego.h
> index 92e133a..f021cbd 100644
> --- a/drivers/target/iscsi/iscsi_target_nego.h
> +++ b/drivers/target/iscsi/iscsi_target_nego.h
> @@ -7,11 +7,14 @@
> extern void convert_null_to_semi(char *, int);
> extern int extract_param(const char *, const char *, unsigned int, char *,
> unsigned char *);
> -extern struct iscsi_login *iscsi_target_init_negotiation(
> - struct iscsi_np *, struct iscsi_conn *, char *);
> +extern int iscsi_target_check_login_request(struct iscsi_conn *,
> + struct iscsi_login *);
> +extern int iscsi_target_get_initial_payload(struct iscsi_conn *,
> + struct iscsi_login *);
> +extern int iscsi_target_locate_portal(struct iscsi_np *, struct iscsi_conn *,
> + struct iscsi_login *);
> extern int iscsi_target_start_negotiation(
> struct iscsi_login *, struct iscsi_conn *);
> -extern void iscsi_target_nego_release(
> - struct iscsi_login *, struct iscsi_conn *);
> +extern void iscsi_target_nego_release(struct iscsi_conn *);
>
> #endif /* ISCSI_TARGET_NEGO_H */
> diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
> index ca2be40..84ce94a 100644
> --- a/drivers/target/iscsi/iscsi_target_parameters.c
> +++ b/drivers/target/iscsi/iscsi_target_parameters.c
> @@ -59,7 +59,7 @@ int iscsi_login_tx_data(
> char *text_buf,
> int text_length)
> {
> - int length, tx_sent;
> + int length, tx_sent, iov_cnt = 1;
> struct kvec iov[2];
>
> length = (ISCSI_HDR_LEN + text_length);
> @@ -67,8 +67,12 @@ int iscsi_login_tx_data(
> memset(&iov[0], 0, 2 * sizeof(struct kvec));
> iov[0].iov_len = ISCSI_HDR_LEN;
> iov[0].iov_base = pdu_buf;
> - iov[1].iov_len = text_length;
> - iov[1].iov_base = text_buf;
> +
> + if (text_buf && text_length) {
> + iov[1].iov_len = text_length;
> + iov[1].iov_base = text_buf;
> + iov_cnt++;
> + }
>
> /*
> * Initial Marker-less Interval.
> @@ -77,7 +81,7 @@ int iscsi_login_tx_data(
> */
> conn->if_marker += length;
>
> - tx_sent = tx_data(conn, &iov[0], 2, length);
> + tx_sent = tx_data(conn, &iov[0], iov_cnt, length);
> if (tx_sent != length) {
> pr_err("tx_data returned %d, expecting %d.\n",
> tx_sent, length);
> diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
> index ee8f8c6..439260b 100644
> --- a/drivers/target/iscsi/iscsi_target_tpg.c
> +++ b/drivers/target/iscsi/iscsi_target_tpg.c
> @@ -31,6 +31,8 @@
> #include "iscsi_target.h"
> #include "iscsi_target_parameters.h"
>
> +#include <target/iscsi/iscsi_transport.h>
> +
> struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt)
> {
> struct iscsi_portal_group *tpg;
> @@ -508,7 +510,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
>
> pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n",
> tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
> - (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
> + np->np_transport->name);
>
> return tpg_np;
> }
> @@ -522,7 +524,7 @@ static int iscsit_tpg_release_np(
>
> pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n",
> tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
> - (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
> + np->np_transport->name);
>
> tpg_np->tpg_np = NULL;
> tpg_np->tpg = NULL;
> diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
> index 7ce3505..4cf1e7f 100644
> --- a/drivers/target/iscsi/iscsi_target_util.c
> +++ b/drivers/target/iscsi/iscsi_target_util.c
> @@ -24,6 +24,7 @@
> #include <target/target_core_base.h>
> #include <target/target_core_fabric.h>
> #include <target/target_core_configfs.h>
> +#include <target/iscsi/iscsi_transport.h>
>
> #include "iscsi_target_core.h"
> #include "iscsi_target_parameters.h"
> @@ -1226,34 +1227,19 @@ send_datacrc:
> */
> int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail)
> {
> - u8 iscsi_hdr[ISCSI_HDR_LEN];
> - int err;
> - struct kvec iov;
> struct iscsi_login_rsp *hdr;
> + struct iscsi_login *login = conn->conn_login;
>
> + login->login_failed = 1;
> iscsit_collect_login_stats(conn, status_class, status_detail);
>
> - memset(&iov, 0, sizeof(struct kvec));
> - memset(&iscsi_hdr, 0x0, ISCSI_HDR_LEN);
> -
> - hdr = (struct iscsi_login_rsp *)&iscsi_hdr;
> + hdr = (struct iscsi_login_rsp *)&login->rsp[0];
> hdr->opcode = ISCSI_OP_LOGIN_RSP;
> hdr->status_class = status_class;
> hdr->status_detail = status_detail;
> hdr->itt = conn->login_itt;
>
> - iov.iov_base = &iscsi_hdr;
> - iov.iov_len = ISCSI_HDR_LEN;
> -
> - PRINT_BUFF(iscsi_hdr, ISCSI_HDR_LEN);
> -
> - err = tx_data(conn, &iov, 1, ISCSI_HDR_LEN);
> - if (err != ISCSI_HDR_LEN) {
> - pr_err("tx_data returned less than expected\n");
> - return -1;
> - }
> -
> - return 0;
> + return conn->conn_transport->iscsit_put_login_tx(conn, login, 0);
> }
>
> void iscsit_print_session_params(struct iscsi_session *sess)
> @@ -1432,7 +1418,8 @@ void iscsit_collect_login_stats(
> strcpy(ls->last_intr_fail_name,
> (intrname ? intrname->value : "Unknown"));
>
> - ls->last_intr_fail_ip_family = conn->sock->sk->sk_family;
> + ls->last_intr_fail_ip_family = conn->login_family;
> +
> snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE,
> "%s", conn->login_ip);
> ls->last_fail_time = get_jiffies_64();
>
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [RFC 02/11] iscsi-target: Initial traditional TCP conversion to iscsit_transport
2013-03-22 17:23 ` Andy Grover
@ 2013-03-22 22:38 ` Nicholas A. Bellinger
0 siblings, 0 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-22 22:38 UTC (permalink / raw)
To: Andy Grover
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On Fri, 2013-03-22 at 10:23 -0700, Andy Grover wrote:
> On 03/07/2013 05:45 PM, Nicholas A. Bellinger wrote:
> > From: Nicholas Bellinger <nab@linux-iscsi.org>
> >
> > This patch performs the initial conversion of existing traditional iscsi
> > to use iscsit_transport API callers. This includes:
> >
> > - iscsi-np cleanups for iscsit_transport_type
> > - Add iscsi-np transport calls w/ ->iscsit_setup_up() and ->iscsit_free_np()
> > - Convert login thread process context to use ->iscsit_accept_np() for
> > connections with pre-allocated struct iscsi_conn
> > - Convert existing socket accept code to iscsit_accept_np()
> > - Convert login RX/TX callers to use ->iscsit_get_login_rx() and
> > ->iscsit_put_login_tx() to exchange request/response PDUs
> > - Convert existing socket login RX/TX calls into iscsit_get_login_rx()
> > and iscsit_put_login_tx()
> > - Change iscsit_close_connection() to invoke ->iscsit_free_conn() +
> > iscsit_put_transport() calls.
> > - Add iscsit_create_transport() + iscsit_destroy_transport() calls
> > to module init/exit
> >
> > Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> > ---
> > drivers/target/iscsi/iscsi_target.c | 35 ++-
> > drivers/target/iscsi/iscsi_target_core.h | 15 +-
> > drivers/target/iscsi/iscsi_target_login.c | 411 ++++++++++++++++--------
> > drivers/target/iscsi/iscsi_target_login.h | 6 +
> > drivers/target/iscsi/iscsi_target_nego.c | 185 ++----------
> > drivers/target/iscsi/iscsi_target_nego.h | 11 +-
> > drivers/target/iscsi/iscsi_target_parameters.c | 12 +-
> > drivers/target/iscsi/iscsi_target_tpg.c | 6 +-
> > drivers/target/iscsi/iscsi_target_util.c | 27 +--
> > 9 files changed, 376 insertions(+), 332 deletions(-)
> >
> > diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
> > index 23a98e6..4dc1c9b 100644
> > --- a/drivers/target/iscsi/iscsi_target.c
> > +++ b/drivers/target/iscsi/iscsi_target.c
<SNIP>
> > @@ -4045,6 +4060,12 @@ int iscsit_close_connection(
> >
> > if (conn->sock)
> > sock_release(conn->sock);
> > +
> > + if (conn->conn_transport->iscsit_free_conn)
> > + conn->conn_transport->iscsit_free_conn(conn);
>
> For all the function pointers in conn_transport, won't they always be
> there? If so, can we just call them w/o checking?
For this case, no. ->iscsit_free_conn() is currently present for only
ib_isert.ko code.
> > diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
> > index fdb632f..9354a5f 100644
> > --- a/drivers/target/iscsi/iscsi_target_login.c
> > +++ b/drivers/target/iscsi/iscsi_target_login.c
<SNIP>
> > @@ -635,7 +677,13 @@ static int iscsi_post_login_handler(
> > spin_unlock_bh(&sess->conn_lock);
> >
> > iscsi_post_login_start_timers(conn);
> > - iscsi_activate_thread_set(conn, ts);
> > +
> > + if (conn->conn_transport == ISCSI_TCP) {
> > + iscsi_activate_thread_set(conn, ts);
>
> I thought conn_transport was a pointer? It looks like it's being
> compared against an enum here.
>
This has already been removed for RFC-v2 code.
> > + } else {
> > + printk("Not calling iscsi_activate_thread_set....\n");
> > + dump_stack();
>
> Left-in debug code?
Ditto here too..
>
> > +int iscsit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
> > +{
> > + struct iscsi_login_req *login_req;
> > + u32 padding = 0, payload_length;
> > +
> > + if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
> > + return -1;
> > +
> > + login_req = (struct iscsi_login_req *)login->req;
> > + payload_length = ntoh24(login_req->dlength);
> > + padding = ((-payload_length) & 3);
> > +
> > + pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
> > + " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
> > + login_req->flags, login_req->itt, login_req->cmdsn,
> > + login_req->exp_statsn, login_req->cid, payload_length);
> > + /*
> > + * Setup the initial iscsi_login values from the leading
> > + * login request PDU.
> > + */
> > + if (login->first_request) {
> > + login_req = (struct iscsi_login_req *)login->req;
> > + login->leading_connection = (!login_req->tsih) ? 1 : 0;
> > + login->current_stage =
> > + (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
> > + login->version_min = login_req->min_version;
> > + login->version_max = login_req->max_version;
> > + memcpy(login->isid, login_req->isid, 6);
> > + login->cmd_sn = be32_to_cpu(login_req->cmdsn);
> > + login->init_task_tag = login_req->itt;
> > + login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
> > + login->cid = be16_to_cpu(login_req->cid);
> > + login->tsih = be16_to_cpu(login_req->tsih);
> > + }
> > +
> > + if (iscsi_target_check_login_request(conn, login) < 0)
> > + return -1;
>
> Better return values?
>
In the failure case here, iscsit_tx_login_rsp() will have already been
called to queue the login response with the appropriate status class +
non-zero status detail.
> > @@ -737,7 +676,7 @@ static void iscsi_initiatorname_tolower(
> > /*
> > * Processes the first Login Request..
> > */
> > -static int iscsi_target_locate_portal(
> > +int iscsi_target_locate_portal(
> > struct iscsi_np *np,
> > struct iscsi_conn *conn,
> > struct iscsi_login *login)
> > @@ -746,29 +685,13 @@ static int iscsi_target_locate_portal(
> > char *tmpbuf, *start = NULL, *end = NULL, *key, *value;
> > struct iscsi_session *sess = conn->sess;
> > struct iscsi_tiqn *tiqn;
> > - struct iscsi_login_req *login_req;
> > + struct iscsi_login_req *login_req;
>
> tab got replaced by spaces?
>
Fixed.
Thanks,
--nab
^ permalink raw reply [flat|nested] 35+ messages in thread
* [RFC 03/11] iscsi-target: Add iser-target parameter keys + setup during login
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
2013-03-08 1:45 ` [RFC 01/11] iscsi-target: Add iscsit_transport API template Nicholas A. Bellinger
2013-03-08 1:45 ` [RFC 02/11] iscsi-target: Initial traditional TCP conversion to iscsit_transport Nicholas A. Bellinger
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
2013-03-22 17:23 ` Andy Grover
[not found] ` <1362707116-31406-1-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
` (7 subsequent siblings)
10 siblings, 1 reply; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab@linux-iscsi.org>
This patch adds RDMAExtensions, InitiatorRecvDataSegmentLength and
TargetRecvDataSegmentLength parameters keys necessary for iser-target
login to occur.
This includes setting the necessary parameters during login path
code within iscsi_login_zero_tsih_s2(), and currently PAGE_SIZE
aligning the target's advertised MRDSL for immediate data and
unsolicited data-out incoming payloads.
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/target/iscsi/iscsi_target_core.h | 10 +++
drivers/target/iscsi/iscsi_target_login.c | 69 +++++++++++++++++++---
drivers/target/iscsi/iscsi_target_parameters.c | 75 ++++++++++++++++++++++--
drivers/target/iscsi/iscsi_target_parameters.h | 16 +++++-
4 files changed, 156 insertions(+), 14 deletions(-)
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 2587677..553cc1a 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -244,6 +244,11 @@ struct iscsi_conn_ops {
u8 IFMarker; /* [0,1] == [No,Yes] */
u32 OFMarkInt; /* [1..65535] */
u32 IFMarkInt; /* [1..65535] */
+ /*
+ * iSER specific connection parameters
+ */
+ u32 InitiatorRecvDataSegmentLength; /* [512..2**24-1] */
+ u32 TargetRecvDataSegmentLength; /* [512..2**24-1] */
};
struct iscsi_sess_ops {
@@ -265,6 +270,10 @@ struct iscsi_sess_ops {
u8 DataSequenceInOrder; /* [0,1] == [No,Yes] */
u8 ErrorRecoveryLevel; /* [0..2] */
u8 SessionType; /* [0,1] == [Normal,Discovery]*/
+ /*
+ * iSER specific session parameters
+ */
+ u8 RDMAExtentions; /* [0,1] == [No,Yes] */
};
struct iscsi_queue_req {
@@ -284,6 +293,7 @@ struct iscsi_data_count {
};
struct iscsi_param_list {
+ bool iser;
struct list_head param_list;
struct list_head extra_response_list;
};
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 9354a5f..bc4e0f8 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -343,6 +343,7 @@ static int iscsi_login_zero_tsih_s2(
struct iscsi_node_attrib *na;
struct iscsi_session *sess = conn->sess;
unsigned char buf[32];
+ bool iser = false;
sess->tpg = conn->tpg;
@@ -364,7 +365,10 @@ static int iscsi_login_zero_tsih_s2(
return -1;
}
- iscsi_set_keys_to_negotiate(0, conn->param_list);
+ if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
+ iser = true;
+
+ iscsi_set_keys_to_negotiate(conn->param_list, iser);
if (sess->sess_ops->SessionType)
return iscsi_set_keys_irrelevant_for_discovery(
@@ -402,6 +406,56 @@ static int iscsi_login_zero_tsih_s2(
if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0)
return -1;
+ /*
+ * Set RDMAExtensions=Yes by default for iSER enabled network portals
+ */
+ if (iser == true) {
+ struct iscsi_param *param;
+ unsigned long mrdsl, off;
+ int rc;
+
+ sprintf(buf, "RDMAExtensions=Yes");
+ if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_NO_RESOURCES);
+ return -1;
+ }
+ /*
+ * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for
+ * Immediate Data + Unsolicitied Data-OUT if necessary..
+ */
+ param = iscsi_find_param_from_key("MaxRecvDataSegmentLength",
+ conn->param_list);
+ if (!param) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_NO_RESOURCES);
+ return -1;
+ }
+ rc = strict_strtoul(param->value, 0, &mrdsl);
+ if (rc < 0) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_NO_RESOURCES);
+ return -1;
+ }
+ off = mrdsl % PAGE_SIZE;
+ if (!off)
+ return 0;
+
+ if (mrdsl < PAGE_SIZE)
+ mrdsl = PAGE_SIZE;
+ else
+ mrdsl -= off;
+
+ pr_warn("Aligning ISER MaxRecvDataSegmentLength: %lu down"
+ " to PAGE_SIZE\n", mrdsl);
+
+ sprintf(buf, "MaxRecvDataSegmentLength=%lu\n", mrdsl);
+ if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_NO_RESOURCES);
+ return -1;
+ }
+ }
return 0;
}
@@ -481,6 +535,7 @@ static int iscsi_login_non_zero_tsih_s2(
struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
struct se_session *se_sess, *se_sess_tmp;
struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
+ bool iser = false;
spin_lock_bh(&se_tpg->session_lock);
list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
@@ -530,7 +585,10 @@ static int iscsi_login_non_zero_tsih_s2(
return -1;
}
- iscsi_set_keys_to_negotiate(0, conn->param_list);
+ if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
+ iser = true;
+
+ iscsi_set_keys_to_negotiate(conn->param_list, iser);
/*
* Need to send TargetPortalGroupTag back in first login response
* on any iSCSI connection where the Initiator provides TargetName.
@@ -678,12 +736,7 @@ static int iscsi_post_login_handler(
iscsi_post_login_start_timers(conn);
- if (conn->conn_transport == ISCSI_TCP) {
- iscsi_activate_thread_set(conn, ts);
- } else {
- printk("Not calling iscsi_activate_thread_set....\n");
- dump_stack();
- }
+ iscsi_activate_thread_set(conn, ts);
/*
* Determine CPU mask to ensure connection's RX and TX kthreads
* are scheduled on the same CPU.
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 84ce94a..b9ed7c2 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -433,6 +433,28 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
TYPERANGE_MARKINT, USE_INITIAL_ONLY);
if (!param)
goto out;
+ /*
+ * Extra parameters for ISER from RFC-5046
+ */
+ param = iscsi_set_default_param(pl, RDMAEXTENTIONS, INITIAL_RDMAEXTENTIONS,
+ PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
+ TYPERANGE_BOOL_AND, USE_LEADING_ONLY);
+ if (!param)
+ goto out;
+
+ param = iscsi_set_default_param(pl, INITIATORRECVDATASEGMENTLENGTH,
+ INITIAL_INITIATORRECVDATASEGMENTLENGTH,
+ PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+ TYPERANGE_512_TO_16777215, USE_ALL);
+ if (!param)
+ goto out;
+
+ param = iscsi_set_default_param(pl, TARGETRECVDATASEGMENTLENGTH,
+ INITIAL_TARGETRECVDATASEGMENTLENGTH,
+ PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+ TYPERANGE_512_TO_16777215, USE_ALL);
+ if (!param)
+ goto out;
*param_list_ptr = pl;
return 0;
@@ -442,19 +464,23 @@ out:
}
int iscsi_set_keys_to_negotiate(
- int sessiontype,
- struct iscsi_param_list *param_list)
+ struct iscsi_param_list *param_list,
+ bool iser)
{
struct iscsi_param *param;
+ param_list->iser = iser;
+
list_for_each_entry(param, ¶m_list->param_list, p_list) {
param->state = 0;
if (!strcmp(param->name, AUTHMETHOD)) {
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, HEADERDIGEST)) {
- SET_PSTATE_NEGOTIATE(param);
+ if (iser == false)
+ SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, DATADIGEST)) {
- SET_PSTATE_NEGOTIATE(param);
+ if (iser == false)
+ SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, MAXCONNECTIONS)) {
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, TARGETNAME)) {
@@ -473,7 +499,8 @@ int iscsi_set_keys_to_negotiate(
} else if (!strcmp(param->name, IMMEDIATEDATA)) {
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
- SET_PSTATE_NEGOTIATE(param);
+ if (iser == false)
+ SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
continue;
} else if (!strcmp(param->name, MAXBURSTLENGTH)) {
@@ -502,6 +529,15 @@ int iscsi_set_keys_to_negotiate(
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, OFMARKINT)) {
SET_PSTATE_NEGOTIATE(param);
+ } else if (!strcmp(param->name, RDMAEXTENTIONS)) {
+ if (iser == true)
+ SET_PSTATE_NEGOTIATE(param);
+ } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {
+ if (iser == true)
+ SET_PSTATE_NEGOTIATE(param);
+ } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) {
+ if (iser == true)
+ SET_PSTATE_NEGOTIATE(param);
}
}
@@ -544,6 +580,12 @@ int iscsi_set_keys_irrelevant_for_discovery(
param->state &= ~PSTATE_NEGOTIATE;
else if (!strcmp(param->name, OFMARKINT))
param->state &= ~PSTATE_NEGOTIATE;
+ else if (!strcmp(param->name, RDMAEXTENTIONS))
+ param->state &= ~PSTATE_NEGOTIATE;
+ else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH))
+ param->state &= ~PSTATE_NEGOTIATE;
+ else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH))
+ param->state &= ~PSTATE_NEGOTIATE;
}
return 0;
@@ -1759,6 +1801,9 @@ void iscsi_set_connection_parameters(
* this key is not sent over the wire.
*/
if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
+ if (param_list->iser == true)
+ continue;
+
ops->MaxXmitDataSegmentLength =
simple_strtoul(param->value, &tmpptr, 0);
pr_debug("MaxXmitDataSegmentLength: %s\n",
@@ -1804,6 +1849,22 @@ void iscsi_set_connection_parameters(
simple_strtoul(param->value, &tmpptr, 0);
pr_debug("IFMarkInt: %s\n",
param->value);
+ } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {
+ ops->InitiatorRecvDataSegmentLength =
+ simple_strtoul(param->value, &tmpptr, 0);
+ pr_debug("InitiatorRecvDataSegmentLength: %s\n",
+ param->value);
+ ops->MaxRecvDataSegmentLength =
+ ops->InitiatorRecvDataSegmentLength;
+ pr_debug("Set MRDSL from InitiatorRecvDataSegmentLength\n");
+ } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) {
+ ops->TargetRecvDataSegmentLength =
+ simple_strtoul(param->value, &tmpptr, 0);
+ pr_debug("TargetRecvDataSegmentLength: %s\n",
+ param->value);
+ ops->MaxXmitDataSegmentLength =
+ ops->TargetRecvDataSegmentLength;
+ pr_debug("Set MXDSL from TargetRecvDataSegmentLength\n");
}
}
pr_debug("----------------------------------------------------"
@@ -1916,6 +1977,10 @@ void iscsi_set_session_parameters(
ops->SessionType = !strcmp(param->value, DISCOVERY);
pr_debug("SessionType: %s\n",
param->value);
+ } else if (!strcmp(param->name, RDMAEXTENTIONS)) {
+ ops->RDMAExtentions = !strcmp(param->value, YES);
+ pr_debug("RDMAExtentions: %s\n",
+ param->value);
}
}
pr_debug("----------------------------------------------------"
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
index 1e1b750..f31b9c4 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.h
+++ b/drivers/target/iscsi/iscsi_target_parameters.h
@@ -27,7 +27,7 @@ extern void iscsi_dump_conn_ops(struct iscsi_conn_ops *);
extern void iscsi_dump_sess_ops(struct iscsi_sess_ops *);
extern void iscsi_print_params(struct iscsi_param_list *);
extern int iscsi_create_default_params(struct iscsi_param_list **);
-extern int iscsi_set_keys_to_negotiate(int, struct iscsi_param_list *);
+extern int iscsi_set_keys_to_negotiate(struct iscsi_param_list *, bool);
extern int iscsi_set_keys_irrelevant_for_discovery(struct iscsi_param_list *);
extern int iscsi_copy_param_list(struct iscsi_param_list **,
struct iscsi_param_list *, int);
@@ -89,6 +89,13 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
#define X_EXTENSIONKEY_CISCO_OLD "X-com.cisco.iscsi.draft"
/*
+ * Parameter names of iSCSI Extentions for RDMA (iSER). See RFC-5046
+ */
+#define RDMAEXTENTIONS "RDMAExtensions"
+#define INITIATORRECVDATASEGMENTLENGTH "InitiatorRecvDataSegmentLength"
+#define TARGETRECVDATASEGMENTLENGTH "TargetRecvDataSegmentLength"
+
+/*
* For AuthMethod.
*/
#define KRB5 "KRB5"
@@ -133,6 +140,13 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
#define INITIAL_OFMARKINT "2048~65535"
/*
+ * Initial values for iSER parameters following RFC-5046 Section 6
+ */
+#define INITIAL_RDMAEXTENTIONS NO
+#define INITIAL_INITIATORRECVDATASEGMENTLENGTH "262144"
+#define INITIAL_TARGETRECVDATASEGMENTLENGTH "8192"
+
+/*
* For [Header,Data]Digests.
*/
#define CRC32C "CRC32C"
--
1.7.2.5
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [RFC 03/11] iscsi-target: Add iser-target parameter keys + setup during login
2013-03-08 1:45 ` [RFC 03/11] iscsi-target: Add iser-target parameter keys + setup during login Nicholas A. Bellinger
@ 2013-03-22 17:23 ` Andy Grover
2013-03-22 22:57 ` Nicholas A. Bellinger
0 siblings, 1 reply; 35+ messages in thread
From: Andy Grover @ 2013-03-22 17:23 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On 03/07/2013 05:45 PM, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
>
> This patch adds RDMAExtensions, InitiatorRecvDataSegmentLength and
> TargetRecvDataSegmentLength parameters keys necessary for iser-target
> login to occur.
>
> This includes setting the necessary parameters during login path
> code within iscsi_login_zero_tsih_s2(), and currently PAGE_SIZE
> aligning the target's advertised MRDSL for immediate data and
> unsolicited data-out incoming payloads.
>
> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> ---
> drivers/target/iscsi/iscsi_target_core.h | 10 +++
> drivers/target/iscsi/iscsi_target_login.c | 69 +++++++++++++++++++---
> drivers/target/iscsi/iscsi_target_parameters.c | 75 ++++++++++++++++++++++--
> drivers/target/iscsi/iscsi_target_parameters.h | 16 +++++-
> 4 files changed, 156 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
> index 2587677..553cc1a 100644
> --- a/drivers/target/iscsi/iscsi_target_core.h
> +++ b/drivers/target/iscsi/iscsi_target_core.h
> @@ -244,6 +244,11 @@ struct iscsi_conn_ops {
> u8 IFMarker; /* [0,1] == [No,Yes] */
> u32 OFMarkInt; /* [1..65535] */
> u32 IFMarkInt; /* [1..65535] */
> + /*
> + * iSER specific connection parameters
> + */
> + u32 InitiatorRecvDataSegmentLength; /* [512..2**24-1] */
> + u32 TargetRecvDataSegmentLength; /* [512..2**24-1] */
> };
>
> struct iscsi_sess_ops {
> @@ -265,6 +270,10 @@ struct iscsi_sess_ops {
> u8 DataSequenceInOrder; /* [0,1] == [No,Yes] */
> u8 ErrorRecoveryLevel; /* [0..2] */
> u8 SessionType; /* [0,1] == [Normal,Discovery]*/
> + /*
> + * iSER specific session parameters
> + */
> + u8 RDMAExtentions; /* [0,1] == [No,Yes] */
Typo throughout.
> };
>
> struct iscsi_queue_req {
> @@ -284,6 +293,7 @@ struct iscsi_data_count {
> };
>
> struct iscsi_param_list {
> + bool iser;
> struct list_head param_list;
> struct list_head extra_response_list;
> };
> diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
> index 9354a5f..bc4e0f8 100644
> --- a/drivers/target/iscsi/iscsi_target_login.c
> +++ b/drivers/target/iscsi/iscsi_target_login.c
> @@ -343,6 +343,7 @@ static int iscsi_login_zero_tsih_s2(
> struct iscsi_node_attrib *na;
> struct iscsi_session *sess = conn->sess;
> unsigned char buf[32];
> + bool iser = false;
>
> sess->tpg = conn->tpg;
>
> @@ -364,7 +365,10 @@ static int iscsi_login_zero_tsih_s2(
> return -1;
> }
>
> - iscsi_set_keys_to_negotiate(0, conn->param_list);
> + if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
> + iser = true;
> +
> + iscsi_set_keys_to_negotiate(conn->param_list, iser);
>
> if (sess->sess_ops->SessionType)
> return iscsi_set_keys_irrelevant_for_discovery(
> @@ -402,6 +406,56 @@ static int iscsi_login_zero_tsih_s2(
>
> if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0)
> return -1;
> + /*
> + * Set RDMAExtensions=Yes by default for iSER enabled network portals
> + */
> + if (iser == true) {
if (iser) {
> + struct iscsi_param *param;
> + unsigned long mrdsl, off;
> + int rc;
> +
> + sprintf(buf, "RDMAExtensions=Yes");
> + if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
> + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> + ISCSI_LOGIN_STATUS_NO_RESOURCES);
> + return -1;
> + }
> + /*
> + * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for
> + * Immediate Data + Unsolicitied Data-OUT if necessary..
> + */
> + param = iscsi_find_param_from_key("MaxRecvDataSegmentLength",
> + conn->param_list);
> + if (!param) {
> + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> + ISCSI_LOGIN_STATUS_NO_RESOURCES);
> + return -1;
> + }
> + rc = strict_strtoul(param->value, 0, &mrdsl);
> + if (rc < 0) {
> + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> + ISCSI_LOGIN_STATUS_NO_RESOURCES);
> + return -1;
> + }
> + off = mrdsl % PAGE_SIZE;
> + if (!off)
> + return 0;
> +
> + if (mrdsl < PAGE_SIZE)
> + mrdsl = PAGE_SIZE;
> + else
> + mrdsl -= off;
Is there some PAGE_ROUND_DOWN macro we might use here?
> +
> + pr_warn("Aligning ISER MaxRecvDataSegmentLength: %lu down"
> + " to PAGE_SIZE\n", mrdsl);
> +
> + sprintf(buf, "MaxRecvDataSegmentLength=%lu\n", mrdsl);
> + if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
> + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> + ISCSI_LOGIN_STATUS_NO_RESOURCES);
> + return -1;
> + }
> + }
>
> return 0;
> }
> @@ -481,6 +535,7 @@ static int iscsi_login_non_zero_tsih_s2(
> struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
> struct se_session *se_sess, *se_sess_tmp;
> struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
> + bool iser = false;
>
> spin_lock_bh(&se_tpg->session_lock);
> list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
> @@ -530,7 +585,10 @@ static int iscsi_login_non_zero_tsih_s2(
> return -1;
> }
>
> - iscsi_set_keys_to_negotiate(0, conn->param_list);
> + if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
> + iser = true;
Can we avoid type checks in the transport-neutral code?
> +
> + iscsi_set_keys_to_negotiate(conn->param_list, iser);
Maybe it's too ugly to go that far, but it might be nicer to pass
conn_transport to this fn and check transport_type inside, instead of
passing the iser bool.
-- Andy
> /*
> * Need to send TargetPortalGroupTag back in first login response
> * on any iSCSI connection where the Initiator provides TargetName.
> @@ -678,12 +736,7 @@ static int iscsi_post_login_handler(
>
> iscsi_post_login_start_timers(conn);
>
> - if (conn->conn_transport == ISCSI_TCP) {
> - iscsi_activate_thread_set(conn, ts);
> - } else {
> - printk("Not calling iscsi_activate_thread_set....\n");
> - dump_stack();
> - }
> + iscsi_activate_thread_set(conn, ts);
> /*
> * Determine CPU mask to ensure connection's RX and TX kthreads
> * are scheduled on the same CPU.
> diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
> index 84ce94a..b9ed7c2 100644
> --- a/drivers/target/iscsi/iscsi_target_parameters.c
> +++ b/drivers/target/iscsi/iscsi_target_parameters.c
> @@ -433,6 +433,28 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
> TYPERANGE_MARKINT, USE_INITIAL_ONLY);
> if (!param)
> goto out;
> + /*
> + * Extra parameters for ISER from RFC-5046
> + */
> + param = iscsi_set_default_param(pl, RDMAEXTENTIONS, INITIAL_RDMAEXTENTIONS,
> + PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
> + TYPERANGE_BOOL_AND, USE_LEADING_ONLY);
> + if (!param)
> + goto out;
> +
> + param = iscsi_set_default_param(pl, INITIATORRECVDATASEGMENTLENGTH,
> + INITIAL_INITIATORRECVDATASEGMENTLENGTH,
> + PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
> + TYPERANGE_512_TO_16777215, USE_ALL);
> + if (!param)
> + goto out;
> +
> + param = iscsi_set_default_param(pl, TARGETRECVDATASEGMENTLENGTH,
> + INITIAL_TARGETRECVDATASEGMENTLENGTH,
> + PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
> + TYPERANGE_512_TO_16777215, USE_ALL);
> + if (!param)
> + goto out;
>
> *param_list_ptr = pl;
> return 0;
> @@ -442,19 +464,23 @@ out:
> }
>
> int iscsi_set_keys_to_negotiate(
> - int sessiontype,
> - struct iscsi_param_list *param_list)
> + struct iscsi_param_list *param_list,
> + bool iser)
> {
> struct iscsi_param *param;
>
> + param_list->iser = iser;
> +
> list_for_each_entry(param, ¶m_list->param_list, p_list) {
> param->state = 0;
> if (!strcmp(param->name, AUTHMETHOD)) {
> SET_PSTATE_NEGOTIATE(param);
> } else if (!strcmp(param->name, HEADERDIGEST)) {
> - SET_PSTATE_NEGOTIATE(param);
> + if (iser == false)
> + SET_PSTATE_NEGOTIATE(param);
> } else if (!strcmp(param->name, DATADIGEST)) {
> - SET_PSTATE_NEGOTIATE(param);
> + if (iser == false)
> + SET_PSTATE_NEGOTIATE(param);
> } else if (!strcmp(param->name, MAXCONNECTIONS)) {
> SET_PSTATE_NEGOTIATE(param);
> } else if (!strcmp(param->name, TARGETNAME)) {
> @@ -473,7 +499,8 @@ int iscsi_set_keys_to_negotiate(
> } else if (!strcmp(param->name, IMMEDIATEDATA)) {
> SET_PSTATE_NEGOTIATE(param);
> } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
> - SET_PSTATE_NEGOTIATE(param);
> + if (iser == false)
> + SET_PSTATE_NEGOTIATE(param);
> } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
> continue;
> } else if (!strcmp(param->name, MAXBURSTLENGTH)) {
> @@ -502,6 +529,15 @@ int iscsi_set_keys_to_negotiate(
> SET_PSTATE_NEGOTIATE(param);
> } else if (!strcmp(param->name, OFMARKINT)) {
> SET_PSTATE_NEGOTIATE(param);
> + } else if (!strcmp(param->name, RDMAEXTENTIONS)) {
> + if (iser == true)
> + SET_PSTATE_NEGOTIATE(param);
> + } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {
> + if (iser == true)
> + SET_PSTATE_NEGOTIATE(param);
> + } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) {
> + if (iser == true)
> + SET_PSTATE_NEGOTIATE(param);
> }
> }
>
> @@ -544,6 +580,12 @@ int iscsi_set_keys_irrelevant_for_discovery(
> param->state &= ~PSTATE_NEGOTIATE;
> else if (!strcmp(param->name, OFMARKINT))
> param->state &= ~PSTATE_NEGOTIATE;
> + else if (!strcmp(param->name, RDMAEXTENTIONS))
> + param->state &= ~PSTATE_NEGOTIATE;
> + else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH))
> + param->state &= ~PSTATE_NEGOTIATE;
> + else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH))
> + param->state &= ~PSTATE_NEGOTIATE;
> }
>
> return 0;
> @@ -1759,6 +1801,9 @@ void iscsi_set_connection_parameters(
> * this key is not sent over the wire.
> */
> if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
> + if (param_list->iser == true)
> + continue;
> +
> ops->MaxXmitDataSegmentLength =
> simple_strtoul(param->value, &tmpptr, 0);
> pr_debug("MaxXmitDataSegmentLength: %s\n",
> @@ -1804,6 +1849,22 @@ void iscsi_set_connection_parameters(
> simple_strtoul(param->value, &tmpptr, 0);
> pr_debug("IFMarkInt: %s\n",
> param->value);
> + } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {
> + ops->InitiatorRecvDataSegmentLength =
> + simple_strtoul(param->value, &tmpptr, 0);
> + pr_debug("InitiatorRecvDataSegmentLength: %s\n",
> + param->value);
> + ops->MaxRecvDataSegmentLength =
> + ops->InitiatorRecvDataSegmentLength;
> + pr_debug("Set MRDSL from InitiatorRecvDataSegmentLength\n");
> + } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) {
> + ops->TargetRecvDataSegmentLength =
> + simple_strtoul(param->value, &tmpptr, 0);
> + pr_debug("TargetRecvDataSegmentLength: %s\n",
> + param->value);
> + ops->MaxXmitDataSegmentLength =
> + ops->TargetRecvDataSegmentLength;
> + pr_debug("Set MXDSL from TargetRecvDataSegmentLength\n");
> }
> }
> pr_debug("----------------------------------------------------"
> @@ -1916,6 +1977,10 @@ void iscsi_set_session_parameters(
> ops->SessionType = !strcmp(param->value, DISCOVERY);
> pr_debug("SessionType: %s\n",
> param->value);
> + } else if (!strcmp(param->name, RDMAEXTENTIONS)) {
> + ops->RDMAExtentions = !strcmp(param->value, YES);
> + pr_debug("RDMAExtentions: %s\n",
> + param->value);
> }
> }
> pr_debug("----------------------------------------------------"
> diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
> index 1e1b750..f31b9c4 100644
> --- a/drivers/target/iscsi/iscsi_target_parameters.h
> +++ b/drivers/target/iscsi/iscsi_target_parameters.h
> @@ -27,7 +27,7 @@ extern void iscsi_dump_conn_ops(struct iscsi_conn_ops *);
> extern void iscsi_dump_sess_ops(struct iscsi_sess_ops *);
> extern void iscsi_print_params(struct iscsi_param_list *);
> extern int iscsi_create_default_params(struct iscsi_param_list **);
> -extern int iscsi_set_keys_to_negotiate(int, struct iscsi_param_list *);
> +extern int iscsi_set_keys_to_negotiate(struct iscsi_param_list *, bool);
> extern int iscsi_set_keys_irrelevant_for_discovery(struct iscsi_param_list *);
> extern int iscsi_copy_param_list(struct iscsi_param_list **,
> struct iscsi_param_list *, int);
> @@ -89,6 +89,13 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
> #define X_EXTENSIONKEY_CISCO_OLD "X-com.cisco.iscsi.draft"
>
> /*
> + * Parameter names of iSCSI Extentions for RDMA (iSER). See RFC-5046
> + */
> +#define RDMAEXTENTIONS "RDMAExtensions"
> +#define INITIATORRECVDATASEGMENTLENGTH "InitiatorRecvDataSegmentLength"
> +#define TARGETRECVDATASEGMENTLENGTH "TargetRecvDataSegmentLength"
> +
> +/*
> * For AuthMethod.
> */
> #define KRB5 "KRB5"
> @@ -133,6 +140,13 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
> #define INITIAL_OFMARKINT "2048~65535"
>
> /*
> + * Initial values for iSER parameters following RFC-5046 Section 6
> + */
> +#define INITIAL_RDMAEXTENTIONS NO
> +#define INITIAL_INITIATORRECVDATASEGMENTLENGTH "262144"
> +#define INITIAL_TARGETRECVDATASEGMENTLENGTH "8192"
> +
> +/*
> * For [Header,Data]Digests.
> */
> #define CRC32C "CRC32C"
>
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [RFC 03/11] iscsi-target: Add iser-target parameter keys + setup during login
2013-03-22 17:23 ` Andy Grover
@ 2013-03-22 22:57 ` Nicholas A. Bellinger
0 siblings, 0 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-22 22:57 UTC (permalink / raw)
To: Andy Grover
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On Fri, 2013-03-22 at 10:23 -0700, Andy Grover wrote:
> On 03/07/2013 05:45 PM, Nicholas A. Bellinger wrote:
> > From: Nicholas Bellinger <nab@linux-iscsi.org>
> >
> > This patch adds RDMAExtensions, InitiatorRecvDataSegmentLength and
> > TargetRecvDataSegmentLength parameters keys necessary for iser-target
> > login to occur.
> >
> > This includes setting the necessary parameters during login path
> > code within iscsi_login_zero_tsih_s2(), and currently PAGE_SIZE
> > aligning the target's advertised MRDSL for immediate data and
> > unsolicited data-out incoming payloads.
> >
> > Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> > ---
> > drivers/target/iscsi/iscsi_target_core.h | 10 +++
> > drivers/target/iscsi/iscsi_target_login.c | 69 +++++++++++++++++++---
> > drivers/target/iscsi/iscsi_target_parameters.c | 75 ++++++++++++++++++++++--
> > drivers/target/iscsi/iscsi_target_parameters.h | 16 +++++-
> > 4 files changed, 156 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
> > index 2587677..553cc1a 100644
> > --- a/drivers/target/iscsi/iscsi_target_core.h
> > +++ b/drivers/target/iscsi/iscsi_target_core.h
> > @@ -244,6 +244,11 @@ struct iscsi_conn_ops {
> > u8 IFMarker; /* [0,1] == [No,Yes] */
> > u32 OFMarkInt; /* [1..65535] */
> > u32 IFMarkInt; /* [1..65535] */
> > + /*
> > + * iSER specific connection parameters
> > + */
> > + u32 InitiatorRecvDataSegmentLength; /* [512..2**24-1] */
> > + u32 TargetRecvDataSegmentLength; /* [512..2**24-1] */
> > };
> >
> > struct iscsi_sess_ops {
> > @@ -265,6 +270,10 @@ struct iscsi_sess_ops {
> > u8 DataSequenceInOrder; /* [0,1] == [No,Yes] */
> > u8 ErrorRecoveryLevel; /* [0..2] */
> > u8 SessionType; /* [0,1] == [Normal,Discovery]*/
> > + /*
> > + * iSER specific session parameters
> > + */
> > + u8 RDMAExtentions; /* [0,1] == [No,Yes] */
>
> Typo throughout.
>
Whoops.. Fixed.
> > };
> >
> > struct iscsi_queue_req {
> > @@ -284,6 +293,7 @@ struct iscsi_data_count {
> > };
> >
> > struct iscsi_param_list {
> > + bool iser;
> > struct list_head param_list;
> > struct list_head extra_response_list;
> > };
> > diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
> > index 9354a5f..bc4e0f8 100644
> > --- a/drivers/target/iscsi/iscsi_target_login.c
> > +++ b/drivers/target/iscsi/iscsi_target_login.c
> > @@ -343,6 +343,7 @@ static int iscsi_login_zero_tsih_s2(
> > struct iscsi_node_attrib *na;
> > struct iscsi_session *sess = conn->sess;
> > unsigned char buf[32];
> > + bool iser = false;
> >
> > sess->tpg = conn->tpg;
> >
> > @@ -364,7 +365,10 @@ static int iscsi_login_zero_tsih_s2(
> > return -1;
> > }
> >
> > - iscsi_set_keys_to_negotiate(0, conn->param_list);
> > + if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
> > + iser = true;
> > +
> > + iscsi_set_keys_to_negotiate(conn->param_list, iser);
> >
> > if (sess->sess_ops->SessionType)
> > return iscsi_set_keys_irrelevant_for_discovery(
> > @@ -402,6 +406,56 @@ static int iscsi_login_zero_tsih_s2(
> >
> > if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0)
> > return -1;
> > + /*
> > + * Set RDMAExtensions=Yes by default for iSER enabled network portals
> > + */
> > + if (iser == true) {
>
> if (iser) {
Changed.
>
> > + struct iscsi_param *param;
> > + unsigned long mrdsl, off;
> > + int rc;
> > +
> > + sprintf(buf, "RDMAExtensions=Yes");
> > + if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
> > + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> > + ISCSI_LOGIN_STATUS_NO_RESOURCES);
> > + return -1;
> > + }
> > + /*
> > + * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for
> > + * Immediate Data + Unsolicitied Data-OUT if necessary..
> > + */
> > + param = iscsi_find_param_from_key("MaxRecvDataSegmentLength",
> > + conn->param_list);
> > + if (!param) {
> > + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> > + ISCSI_LOGIN_STATUS_NO_RESOURCES);
> > + return -1;
> > + }
> > + rc = strict_strtoul(param->value, 0, &mrdsl);
> > + if (rc < 0) {
> > + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> > + ISCSI_LOGIN_STATUS_NO_RESOURCES);
> > + return -1;
> > + }
> > + off = mrdsl % PAGE_SIZE;
> > + if (!off)
> > + return 0;
> > +
> > + if (mrdsl < PAGE_SIZE)
> > + mrdsl = PAGE_SIZE;
> > + else
> > + mrdsl -= off;
>
> Is there some PAGE_ROUND_DOWN macro we might use here?
>
Not AFAICT in current code..
> > +
> > + pr_warn("Aligning ISER MaxRecvDataSegmentLength: %lu down"
> > + " to PAGE_SIZE\n", mrdsl);
> > +
> > + sprintf(buf, "MaxRecvDataSegmentLength=%lu\n", mrdsl);
> > + if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
> > + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
> > + ISCSI_LOGIN_STATUS_NO_RESOURCES);
> > + return -1;
> > + }
> > + }
> >
> > return 0;
> > }
> > @@ -481,6 +535,7 @@ static int iscsi_login_non_zero_tsih_s2(
> > struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
> > struct se_session *se_sess, *se_sess_tmp;
> > struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
> > + bool iser = false;
> >
> > spin_lock_bh(&se_tpg->session_lock);
> > list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
> > @@ -530,7 +585,10 @@ static int iscsi_login_non_zero_tsih_s2(
> > return -1;
> > }
> >
> > - iscsi_set_keys_to_negotiate(0, conn->param_list);
> > + if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
> > + iser = true;
>
> Can we avoid type checks in the transport-neutral code?
>
For this case, not AFAICT. As sess->sess_ops->RDMAExtensions has not
been setup yet.
> > +
> > + iscsi_set_keys_to_negotiate(conn->param_list, iser);
>
> Maybe it's too ugly to go that far, but it might be nicer to pass
> conn_transport to this fn and check transport_type inside, instead of
> passing the iser bool.
>
I'd like to avoid any more transport_type other than the single one
mentioned above.
Thanks,
--nab
^ permalink raw reply [flat|nested] 35+ messages in thread
[parent not found: <1362707116-31406-1-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>]
* [RFC 04/11] iscsi-target: Add per transport iscsi_cmd alloc/free
[not found] ` <1362707116-31406-1-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
2013-03-08 14:29 ` Asias He
[not found] ` <1362707116-31406-5-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
2013-03-08 1:45 ` [RFC 06/11] iscsi-target: Refactor TX queue logic + export response PDU creation Nicholas A. Bellinger
1 sibling, 2 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
This patch converts struct iscsi_cmd memory allocation + free to use
->iscsit_alloc_cmd() + ->iscsit_free_cmd() iscsit_transport API caller,
and export iscsit_allocate_cmd() + iscsit_free_cmd() symbols
Also update iscsit_free_cmd() to include a final ->iscsit_unmap_cmd()
API call.
Signed-off-by: Nicholas Bellinger <nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
---
drivers/target/iscsi/iscsi_target.c | 2 +
drivers/target/iscsi/iscsi_target_util.c | 34 ++++++++++++++++++++++++++---
drivers/target/iscsi/iscsi_target_util.h | 2 +
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 4dc1c9b..9cd7b7b 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -488,6 +488,8 @@ static struct iscsit_transport iscsi_target_transport = {
.iscsit_setup_np = iscsit_setup_np,
.iscsit_accept_np = iscsit_accept_np,
.iscsit_free_np = iscsit_free_np,
+ .iscsit_alloc_cmd = iscsit_alloc_cmd,
+ .iscsit_free_cmd = iscsit_cache_free_cmd,
.iscsit_get_login_rx = iscsit_get_login_rx,
.iscsit_put_login_tx = iscsit_put_login_tx,
};
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 4cf1e7f..4a86034 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -149,6 +149,17 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
spin_unlock_bh(&cmd->r2t_lock);
}
+struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
+{
+ struct iscsi_cmd *cmd;
+
+ cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
+ if (!cmd)
+ return NULL;
+
+ return cmd;
+}
+
/*
* May be called from software interrupt (timer) context for allocating
* iSCSI NopINs.
@@ -157,13 +168,12 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
{
struct iscsi_cmd *cmd;
- cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
+ cmd = conn->conn_transport->iscsit_alloc_cmd(conn, gfp_mask);
if (!cmd) {
pr_err("Unable to allocate memory for struct iscsi_cmd.\n");
return NULL;
}
-
- cmd->conn = conn;
+ cmd->conn = conn;
INIT_LIST_HEAD(&cmd->i_conn_node);
INIT_LIST_HEAD(&cmd->datain_list);
INIT_LIST_HEAD(&cmd->cmd_r2t_list);
@@ -176,6 +186,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
return cmd;
}
+EXPORT_SYMBOL(iscsit_allocate_cmd);
struct iscsi_seq *iscsit_get_seq_holder_for_datain(
struct iscsi_cmd *cmd,
@@ -661,6 +672,11 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
spin_unlock_bh(&conn->response_queue_lock);
}
+void iscsit_cache_free_cmd(struct iscsi_cmd *cmd)
+{
+ kmem_cache_free(lio_cmd_cache, cmd);
+}
+
void iscsit_release_cmd(struct iscsi_cmd *cmd)
{
struct iscsi_conn *conn = cmd->conn;
@@ -679,17 +695,26 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
iscsit_remove_cmd_from_response_queue(cmd, conn);
}
- kmem_cache_free(lio_cmd_cache, cmd);
+ conn->conn_transport->iscsit_free_cmd(cmd);
}
void iscsit_free_cmd(struct iscsi_cmd *cmd)
{
+ struct iscsi_conn *conn = cmd->conn;
/*
* Determine if a struct se_cmd is associated with
* this struct iscsi_cmd.
*/
switch (cmd->iscsi_opcode) {
case ISCSI_OP_SCSI_CMD:
+ if (cmd->data_direction == DMA_TO_DEVICE)
+ iscsit_stop_dataout_timer(cmd);
+
+ if (conn->conn_transport->iscsit_unmap_cmd)
+ conn->conn_transport->iscsit_unmap_cmd(cmd, conn);
+ /*
+ * Fallthrough
+ */
case ISCSI_OP_SCSI_TMFUNC:
transport_generic_free_cmd(&cmd->se_cmd, 1);
break;
@@ -709,6 +734,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd)
break;
}
}
+EXPORT_SYMBOL(iscsit_free_cmd);
int iscsit_check_session_usage_count(struct iscsi_session *sess)
{
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index 894d0f8..854ce89 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -8,6 +8,7 @@ extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32);
extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *);
extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *);
+extern struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *, gfp_t);
extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
@@ -27,6 +28,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_c
extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
+extern void iscsit_cache_free_cmd(struct iscsi_cmd *);
extern void iscsit_release_cmd(struct iscsi_cmd *);
extern void iscsit_free_cmd(struct iscsi_cmd *);
extern int iscsit_check_session_usage_count(struct iscsi_session *);
--
1.7.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [RFC 04/11] iscsi-target: Add per transport iscsi_cmd alloc/free
2013-03-08 1:45 ` [RFC 04/11] iscsi-target: Add per transport iscsi_cmd alloc/free Nicholas A. Bellinger
@ 2013-03-08 14:29 ` Asias He
2013-03-08 20:47 ` Nicholas A. Bellinger
[not found] ` <1362707116-31406-5-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
1 sibling, 1 reply; 35+ messages in thread
From: Asias He @ 2013-03-08 14:29 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On Fri, Mar 8, 2013 at 9:45 AM, Nicholas A. Bellinger
<nab@linux-iscsi.org> wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
>
> This patch converts struct iscsi_cmd memory allocation + free to use
> ->iscsit_alloc_cmd() + ->iscsit_free_cmd() iscsit_transport API caller,
> and export iscsit_allocate_cmd() + iscsit_free_cmd() symbols
>
> Also update iscsit_free_cmd() to include a final ->iscsit_unmap_cmd()
> API call.
>
> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> ---
> drivers/target/iscsi/iscsi_target.c | 2 +
> drivers/target/iscsi/iscsi_target_util.c | 34 ++++++++++++++++++++++++++---
> drivers/target/iscsi/iscsi_target_util.h | 2 +
> 3 files changed, 34 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
> index 4dc1c9b..9cd7b7b 100644
> --- a/drivers/target/iscsi/iscsi_target.c
> +++ b/drivers/target/iscsi/iscsi_target.c
> @@ -488,6 +488,8 @@ static struct iscsit_transport iscsi_target_transport = {
> .iscsit_setup_np = iscsit_setup_np,
> .iscsit_accept_np = iscsit_accept_np,
> .iscsit_free_np = iscsit_free_np,
> + .iscsit_alloc_cmd = iscsit_alloc_cmd,
> + .iscsit_free_cmd = iscsit_cache_free_cmd,
> .iscsit_get_login_rx = iscsit_get_login_rx,
> .iscsit_put_login_tx = iscsit_put_login_tx,
> };
> diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
> index 4cf1e7f..4a86034 100644
> --- a/drivers/target/iscsi/iscsi_target_util.c
> +++ b/drivers/target/iscsi/iscsi_target_util.c
> @@ -149,6 +149,17 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
> spin_unlock_bh(&cmd->r2t_lock);
> }
>
> +struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
> +{
> + struct iscsi_cmd *cmd;
> +
> + cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
> + if (!cmd)
> + return NULL;
Is this check necessary?
> + return cmd;
> +}
> +
> /*
> * May be called from software interrupt (timer) context for allocating
> * iSCSI NopINs.
> @@ -157,13 +168,12 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
> {
> struct iscsi_cmd *cmd;
>
> - cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
> + cmd = conn->conn_transport->iscsit_alloc_cmd(conn, gfp_mask);
> if (!cmd) {
> pr_err("Unable to allocate memory for struct iscsi_cmd.\n");
> return NULL;
> }
> -
> - cmd->conn = conn;
> + cmd->conn = conn;
> INIT_LIST_HEAD(&cmd->i_conn_node);
> INIT_LIST_HEAD(&cmd->datain_list);
> INIT_LIST_HEAD(&cmd->cmd_r2t_list);
> @@ -176,6 +186,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
>
> return cmd;
> }
> +EXPORT_SYMBOL(iscsit_allocate_cmd);
>
> struct iscsi_seq *iscsit_get_seq_holder_for_datain(
> struct iscsi_cmd *cmd,
> @@ -661,6 +672,11 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
> spin_unlock_bh(&conn->response_queue_lock);
> }
>
> +void iscsit_cache_free_cmd(struct iscsi_cmd *cmd)
> +{
> + kmem_cache_free(lio_cmd_cache, cmd);
> +}
> +
> void iscsit_release_cmd(struct iscsi_cmd *cmd)
> {
> struct iscsi_conn *conn = cmd->conn;
> @@ -679,17 +695,26 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
> iscsit_remove_cmd_from_response_queue(cmd, conn);
> }
>
> - kmem_cache_free(lio_cmd_cache, cmd);
> + conn->conn_transport->iscsit_free_cmd(cmd);
> }
>
> void iscsit_free_cmd(struct iscsi_cmd *cmd)
> {
> + struct iscsi_conn *conn = cmd->conn;
> /*
> * Determine if a struct se_cmd is associated with
> * this struct iscsi_cmd.
> */
> switch (cmd->iscsi_opcode) {
> case ISCSI_OP_SCSI_CMD:
> + if (cmd->data_direction == DMA_TO_DEVICE)
> + iscsit_stop_dataout_timer(cmd);
> +
> + if (conn->conn_transport->iscsit_unmap_cmd)
> + conn->conn_transport->iscsit_unmap_cmd(cmd, conn);
> + /*
> + * Fallthrough
> + */
> case ISCSI_OP_SCSI_TMFUNC:
> transport_generic_free_cmd(&cmd->se_cmd, 1);
> break;
> @@ -709,6 +734,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd)
> break;
> }
> }
> +EXPORT_SYMBOL(iscsit_free_cmd);
>
> int iscsit_check_session_usage_count(struct iscsi_session *sess)
> {
> diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
> index 894d0f8..854ce89 100644
> --- a/drivers/target/iscsi/iscsi_target_util.h
> +++ b/drivers/target/iscsi/iscsi_target_util.h
> @@ -8,6 +8,7 @@ extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32);
> extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
> extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *);
> extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *);
> +extern struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *, gfp_t);
> extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
> extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
> extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
> @@ -27,6 +28,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_c
> extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
> extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
> extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
> +extern void iscsit_cache_free_cmd(struct iscsi_cmd *);
> extern void iscsit_release_cmd(struct iscsi_cmd *);
> extern void iscsit_free_cmd(struct iscsi_cmd *);
> extern int iscsit_check_session_usage_count(struct iscsi_session *);
> --
> 1.7.2.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe target-devel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Asias
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [RFC 04/11] iscsi-target: Add per transport iscsi_cmd alloc/free
2013-03-08 14:29 ` Asias He
@ 2013-03-08 20:47 ` Nicholas A. Bellinger
0 siblings, 0 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 20:47 UTC (permalink / raw)
To: Asias He
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On Fri, 2013-03-08 at 22:29 +0800, Asias He wrote:
> On Fri, Mar 8, 2013 at 9:45 AM, Nicholas A. Bellinger
> <nab@linux-iscsi.org> wrote:
> > From: Nicholas Bellinger <nab@linux-iscsi.org>
> >
> > This patch converts struct iscsi_cmd memory allocation + free to use
> > ->iscsit_alloc_cmd() + ->iscsit_free_cmd() iscsit_transport API caller,
> > and export iscsit_allocate_cmd() + iscsit_free_cmd() symbols
> >
> > Also update iscsit_free_cmd() to include a final ->iscsit_unmap_cmd()
> > API call.
> >
> > Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> > ---
> > drivers/target/iscsi/iscsi_target.c | 2 +
> > drivers/target/iscsi/iscsi_target_util.c | 34 ++++++++++++++++++++++++++---
> > drivers/target/iscsi/iscsi_target_util.h | 2 +
> > 3 files changed, 34 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
> > index 4dc1c9b..9cd7b7b 100644
> > --- a/drivers/target/iscsi/iscsi_target.c
> > +++ b/drivers/target/iscsi/iscsi_target.c
> > @@ -488,6 +488,8 @@ static struct iscsit_transport iscsi_target_transport = {
> > .iscsit_setup_np = iscsit_setup_np,
> > .iscsit_accept_np = iscsit_accept_np,
> > .iscsit_free_np = iscsit_free_np,
> > + .iscsit_alloc_cmd = iscsit_alloc_cmd,
> > + .iscsit_free_cmd = iscsit_cache_free_cmd,
> > .iscsit_get_login_rx = iscsit_get_login_rx,
> > .iscsit_put_login_tx = iscsit_put_login_tx,
> > };
> > diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
> > index 4cf1e7f..4a86034 100644
> > --- a/drivers/target/iscsi/iscsi_target_util.c
> > +++ b/drivers/target/iscsi/iscsi_target_util.c
> > @@ -149,6 +149,17 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
> > spin_unlock_bh(&cmd->r2t_lock);
> > }
> >
> > +struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
> > +{
> > + struct iscsi_cmd *cmd;
> > +
> > + cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
> > + if (!cmd)
> > + return NULL;
>
> Is this check necessary?
>
Nope, dropping this now.
Thanks for reviewing!
--nab
^ permalink raw reply [flat|nested] 35+ messages in thread
[parent not found: <1362707116-31406-5-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>]
* Re: [RFC 04/11] iscsi-target: Add per transport iscsi_cmd alloc/free
[not found] ` <1362707116-31406-5-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
@ 2013-03-22 17:23 ` Andy Grover
2013-03-22 22:59 ` Nicholas A. Bellinger
0 siblings, 1 reply; 35+ messages in thread
From: Andy Grover @ 2013-03-22 17:23 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On 03/07/2013 05:45 PM, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
>
> This patch converts struct iscsi_cmd memory allocation + free to use
> ->iscsit_alloc_cmd() + ->iscsit_free_cmd() iscsit_transport API caller,
> and export iscsit_allocate_cmd() + iscsit_free_cmd() symbols
>
> Also update iscsit_free_cmd() to include a final ->iscsit_unmap_cmd()
> API call.
>
> Signed-off-by: Nicholas Bellinger <nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
> ---
> drivers/target/iscsi/iscsi_target.c | 2 +
> drivers/target/iscsi/iscsi_target_util.c | 34 ++++++++++++++++++++++++++---
> drivers/target/iscsi/iscsi_target_util.h | 2 +
> 3 files changed, 34 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
> index 4dc1c9b..9cd7b7b 100644
> --- a/drivers/target/iscsi/iscsi_target.c
> +++ b/drivers/target/iscsi/iscsi_target.c
> @@ -488,6 +488,8 @@ static struct iscsit_transport iscsi_target_transport = {
> .iscsit_setup_np = iscsit_setup_np,
> .iscsit_accept_np = iscsit_accept_np,
> .iscsit_free_np = iscsit_free_np,
> + .iscsit_alloc_cmd = iscsit_alloc_cmd,
> + .iscsit_free_cmd = iscsit_cache_free_cmd,
> .iscsit_get_login_rx = iscsit_get_login_rx,
> .iscsit_put_login_tx = iscsit_put_login_tx,
> };
> diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
> index 4cf1e7f..4a86034 100644
> --- a/drivers/target/iscsi/iscsi_target_util.c
> +++ b/drivers/target/iscsi/iscsi_target_util.c
> @@ -149,6 +149,17 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
> spin_unlock_bh(&cmd->r2t_lock);
> }
>
> +struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
> +{
> + struct iscsi_cmd *cmd;
> +
> + cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
> + if (!cmd)
> + return NULL;
> +
> + return cmd;
> +}
> +
> /*
> * May be called from software interrupt (timer) context for allocating
> * iSCSI NopINs.
> @@ -157,13 +168,12 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
> {
> struct iscsi_cmd *cmd;
>
> - cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
> + cmd = conn->conn_transport->iscsit_alloc_cmd(conn, gfp_mask);
> if (!cmd) {
> pr_err("Unable to allocate memory for struct iscsi_cmd.\n");
> return NULL;
> }
> -
> - cmd->conn = conn;
> + cmd->conn = conn;
> INIT_LIST_HEAD(&cmd->i_conn_node);
> INIT_LIST_HEAD(&cmd->datain_list);
> INIT_LIST_HEAD(&cmd->cmd_r2t_list);
> @@ -176,6 +186,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
>
> return cmd;
> }
> +EXPORT_SYMBOL(iscsit_allocate_cmd);
>
> struct iscsi_seq *iscsit_get_seq_holder_for_datain(
> struct iscsi_cmd *cmd,
> @@ -661,6 +672,11 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
> spin_unlock_bh(&conn->response_queue_lock);
> }
>
> +void iscsit_cache_free_cmd(struct iscsi_cmd *cmd)
Caching is an implementation detail, rename to iscsit_free_cmd()?
> +{
> + kmem_cache_free(lio_cmd_cache, cmd);
> +}
> +
> void iscsit_release_cmd(struct iscsi_cmd *cmd)
> {
> struct iscsi_conn *conn = cmd->conn;
> @@ -679,17 +695,26 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
> iscsit_remove_cmd_from_response_queue(cmd, conn);
> }
>
> - kmem_cache_free(lio_cmd_cache, cmd);
> + conn->conn_transport->iscsit_free_cmd(cmd);
> }
>
> void iscsit_free_cmd(struct iscsi_cmd *cmd)
> {
> + struct iscsi_conn *conn = cmd->conn;
> /*
> * Determine if a struct se_cmd is associated with
> * this struct iscsi_cmd.
> */
> switch (cmd->iscsi_opcode) {
> case ISCSI_OP_SCSI_CMD:
> + if (cmd->data_direction == DMA_TO_DEVICE)
> + iscsit_stop_dataout_timer(cmd);
> +
> + if (conn->conn_transport->iscsit_unmap_cmd)
> + conn->conn_transport->iscsit_unmap_cmd(cmd, conn);
Don't check, just call it?
-- Andy
> + /*
> + * Fallthrough
> + */
> case ISCSI_OP_SCSI_TMFUNC:
> transport_generic_free_cmd(&cmd->se_cmd, 1);
> break;
> @@ -709,6 +734,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd)
> break;
> }
> }
> +EXPORT_SYMBOL(iscsit_free_cmd);
>
> int iscsit_check_session_usage_count(struct iscsi_session *sess)
> {
> diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
> index 894d0f8..854ce89 100644
> --- a/drivers/target/iscsi/iscsi_target_util.h
> +++ b/drivers/target/iscsi/iscsi_target_util.h
> @@ -8,6 +8,7 @@ extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32);
> extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
> extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *);
> extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *);
> +extern struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *, gfp_t);
> extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
> extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
> extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
> @@ -27,6 +28,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_c
> extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
> extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
> extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
> +extern void iscsit_cache_free_cmd(struct iscsi_cmd *);
> extern void iscsit_release_cmd(struct iscsi_cmd *);
> extern void iscsit_free_cmd(struct iscsi_cmd *);
> extern int iscsit_check_session_usage_count(struct iscsi_session *);
>
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [RFC 04/11] iscsi-target: Add per transport iscsi_cmd alloc/free
2013-03-22 17:23 ` Andy Grover
@ 2013-03-22 22:59 ` Nicholas A. Bellinger
0 siblings, 0 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-22 22:59 UTC (permalink / raw)
To: Andy Grover
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky
On Fri, 2013-03-22 at 10:23 -0700, Andy Grover wrote:
> On 03/07/2013 05:45 PM, Nicholas A. Bellinger wrote:
> > From: Nicholas Bellinger <nab@linux-iscsi.org>
> >
> > This patch converts struct iscsi_cmd memory allocation + free to use
> > ->iscsit_alloc_cmd() + ->iscsit_free_cmd() iscsit_transport API caller,
> > and export iscsit_allocate_cmd() + iscsit_free_cmd() symbols
> >
> > Also update iscsit_free_cmd() to include a final ->iscsit_unmap_cmd()
> > API call.
> >
> > Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> > ---
> > drivers/target/iscsi/iscsi_target.c | 2 +
> > drivers/target/iscsi/iscsi_target_util.c | 34 ++++++++++++++++++++++++++---
> > drivers/target/iscsi/iscsi_target_util.h | 2 +
> > 3 files changed, 34 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
> > index 4dc1c9b..9cd7b7b 100644
> > --- a/drivers/target/iscsi/iscsi_target.c
> > +++ b/drivers/target/iscsi/iscsi_target.c
<SNIP>
> > @@ -176,6 +186,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
> >
> > return cmd;
> > }
> > +EXPORT_SYMBOL(iscsit_allocate_cmd);
> >
> > struct iscsi_seq *iscsit_get_seq_holder_for_datain(
> > struct iscsi_cmd *cmd,
> > @@ -661,6 +672,11 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
> > spin_unlock_bh(&conn->response_queue_lock);
> > }
> >
> > +void iscsit_cache_free_cmd(struct iscsi_cmd *cmd)
>
> Caching is an implementation detail, rename to iscsit_free_cmd()?
>
Already removed for forth-coming RFC-v2 code.
> > +{
> > + kmem_cache_free(lio_cmd_cache, cmd);
> > +}
> > +
> > void iscsit_release_cmd(struct iscsi_cmd *cmd)
> > {
> > struct iscsi_conn *conn = cmd->conn;
> > @@ -679,17 +695,26 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
> > iscsit_remove_cmd_from_response_queue(cmd, conn);
> > }
> >
> > - kmem_cache_free(lio_cmd_cache, cmd);
> > + conn->conn_transport->iscsit_free_cmd(cmd);
> > }
> >
> > void iscsit_free_cmd(struct iscsi_cmd *cmd)
> > {
> > + struct iscsi_conn *conn = cmd->conn;
> > /*
> > * Determine if a struct se_cmd is associated with
> > * this struct iscsi_cmd.
> > */
> > switch (cmd->iscsi_opcode) {
> > case ISCSI_OP_SCSI_CMD:
> > + if (cmd->data_direction == DMA_TO_DEVICE)
> > + iscsit_stop_dataout_timer(cmd);
> > +
> > + if (conn->conn_transport->iscsit_unmap_cmd)
> > + conn->conn_transport->iscsit_unmap_cmd(cmd, conn);
>
> Don't check, just call it?
>
->iscsit_unmap_cmd() has been dropped entirety for RFC-v2 code.
--nab
^ permalink raw reply [flat|nested] 35+ messages in thread
* [RFC 06/11] iscsi-target: Refactor TX queue logic + export response PDU creation
[not found] ` <1362707116-31406-1-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
2013-03-08 1:45 ` [RFC 04/11] iscsi-target: Add per transport iscsi_cmd alloc/free Nicholas A. Bellinger
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
1 sibling, 0 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
This patch refactors TX immediate + response queue handling to use
the new iscsit_transport API callers, and exports the necessary
traditional iscsi PDU response creation functions for iser-target
to utilize.
This includes:
- Add iscsit_build_datain_pdu() for DATAIN PDU init + convert
iscsit_build_datain_pdu()
- Add iscsit_build_logout_rsp() for LOGOUT_RSP PDU init + convert
iscsit_send_logout()
- Add iscsit_build_nopin_rsp() for NOPIN_RSP PDU init + convert
iscsit_send_nopin()
- Add iscsit_build_rsp_pdu() for SCSI_RSP PDU init + convert
iscsit_send_response()
- Add iscsit_build_task_mgt_rsp for TM_RSP PDU init + convert
iscsit_send_task_mgt_rsp()
- Refactor immediate queue state switch into iscsit_immediate_queue()
- Convert handle_immediate_queue() to use iscsit_transport caller
- Refactor response queue state switch into iscsit_response_queue()
- Convert handle_response_queue to use iscsit_transport caller
- Export iscsit_logout_post_handler(), iscsit_increment_maxcmdsn()
and iscsit_tmr_post_handler() for external transport module usage
Signed-off-by: Nicholas Bellinger <nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
---
drivers/target/iscsi/iscsi_target.c | 619 +++++++++++++++-------------
drivers/target/iscsi/iscsi_target_device.c | 1 +
drivers/target/iscsi/iscsi_target_tmr.c | 1 +
3 files changed, 342 insertions(+), 279 deletions(-)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index fbdc75a..a72b695 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -70,8 +70,7 @@ struct kmem_cache *lio_ooo_cache;
struct kmem_cache *lio_r2t_cache;
static int iscsit_handle_immediate_data(struct iscsi_cmd *,
- unsigned char *buf, u32);
-static int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
+ struct iscsi_scsi_req *, u32);
struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *buf)
{
@@ -481,6 +480,9 @@ int iscsit_del_np(struct iscsi_np *np)
return 0;
}
+static int iscsit_immediate_queue(struct iscsi_conn *, struct iscsi_cmd *, int);
+static int iscsit_response_queue(struct iscsi_conn *, struct iscsi_cmd *, int);
+
static struct iscsit_transport iscsi_target_transport = {
.name = "iSCSI/TCP",
.transport_type = ISCSI_TCP,
@@ -492,6 +494,8 @@ static struct iscsit_transport iscsi_target_transport = {
.iscsit_free_cmd = iscsit_cache_free_cmd,
.iscsit_get_login_rx = iscsit_get_login_rx,
.iscsit_put_login_tx = iscsit_put_login_tx,
+ .iscsit_immediate_queue = iscsit_immediate_queue,
+ .iscsit_response_queue = iscsit_response_queue,
};
static int __init iscsi_target_init_module(void)
@@ -2513,18 +2517,60 @@ static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn)
}
}
-static int iscsit_send_data_in(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+static void
+iscsit_build_datain_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_datain *datain, struct iscsi_data_rsp *hdr,
+ bool set_statsn)
{
- int iov_ret = 0, set_statsn = 0;
- u32 iov_count = 0, tx_size = 0;
+ hdr->opcode = ISCSI_OP_SCSI_DATA_IN;
+ hdr->flags = datain->flags;
+ if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+ if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) {
+ hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW;
+ hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
+ } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) {
+ hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW;
+ hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
+ }
+ }
+ hton24(hdr->dlength, datain->length);
+ if (hdr->flags & ISCSI_FLAG_DATA_ACK)
+ int_to_scsilun(cmd->se_cmd.orig_fe_lun,
+ (struct scsi_lun *)&hdr->lun);
+ else
+ put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
+
+ hdr->itt = cmd->init_task_tag;
+
+ if (hdr->flags & ISCSI_FLAG_DATA_ACK)
+ hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
+ else
+ hdr->ttt = cpu_to_be32(0xFFFFFFFF);
+ if (set_statsn)
+ hdr->statsn = cpu_to_be32(cmd->stat_sn);
+ else
+ hdr->statsn = cpu_to_be32(0xFFFFFFFF);
+
+ hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
+ hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ hdr->datasn = cpu_to_be32(datain->data_sn);
+ hdr->offset = cpu_to_be32(datain->offset);
+
+ pr_debug("Built DataIN ITT: 0x%08x, StatSN: 0x%08x,"
+ " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
+ cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn),
+ ntohl(hdr->offset), datain->length, conn->cid);
+}
+
+static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct iscsi_data_rsp *hdr = (struct iscsi_data_rsp *)&cmd->pdu[0];
struct iscsi_datain datain;
struct iscsi_datain_req *dr;
- struct iscsi_data_rsp *hdr;
struct kvec *iov;
- int eodr = 0;
- int ret;
+ u32 iov_count = 0, tx_size = 0;
+ int eodr = 0, ret, iov_ret;
+ bool set_statsn = false;
memset(&datain, 0, sizeof(struct iscsi_datain));
dr = iscsit_get_datain_values(cmd, &datain);
@@ -2533,7 +2579,6 @@ static int iscsit_send_data_in(
cmd->init_task_tag);
return -1;
}
-
/*
* Be paranoid and double check the logic for now.
*/
@@ -2541,7 +2586,7 @@ static int iscsit_send_data_in(
pr_err("Command ITT: 0x%08x, datain.offset: %u and"
" datain.length: %u exceeds cmd->data_length: %u\n",
cmd->init_task_tag, datain.offset, datain.length,
- cmd->se_cmd.data_length);
+ cmd->se_cmd.data_length);
return -1;
}
@@ -2565,47 +2610,13 @@ static int iscsit_send_data_in(
(dr->dr_complete == DATAIN_COMPLETE_CONNECTION_RECOVERY)) {
iscsit_increment_maxcmdsn(cmd, conn->sess);
cmd->stat_sn = conn->stat_sn++;
- set_statsn = 1;
+ set_statsn = true;
} else if (dr->dr_complete ==
- DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY)
- set_statsn = 1;
+ DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY)
+ set_statsn = true;
}
- hdr = (struct iscsi_data_rsp *) cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
- hdr->opcode = ISCSI_OP_SCSI_DATA_IN;
- hdr->flags = datain.flags;
- if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
- if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) {
- hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW;
- hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
- } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) {
- hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW;
- hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
- }
- }
- hton24(hdr->dlength, datain.length);
- if (hdr->flags & ISCSI_FLAG_DATA_ACK)
- int_to_scsilun(cmd->se_cmd.orig_fe_lun,
- (struct scsi_lun *)&hdr->lun);
- else
- put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
-
- hdr->itt = cmd->init_task_tag;
-
- if (hdr->flags & ISCSI_FLAG_DATA_ACK)
- hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
- else
- hdr->ttt = cpu_to_be32(0xFFFFFFFF);
- if (set_statsn)
- hdr->statsn = cpu_to_be32(cmd->stat_sn);
- else
- hdr->statsn = cpu_to_be32(0xFFFFFFFF);
-
- hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
- hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
- hdr->datasn = cpu_to_be32(datain.data_sn);
- hdr->offset = cpu_to_be32(datain.offset);
+ iscsit_build_datain_pdu(cmd, conn, &datain, hdr, set_statsn);
iov = &cmd->iov_data[0];
iov[iov_count].iov_base = cmd->pdu;
@@ -2616,7 +2627,7 @@ static int iscsit_send_data_in(
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
+ (unsigned char *)cmd->pdu, ISCSI_HDR_LEN,
0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -2626,7 +2637,8 @@ static int iscsit_send_data_in(
" for DataIN PDU 0x%08x\n", *header_digest);
}
- iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[1], datain.offset, datain.length);
+ iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[1],
+ datain.offset, datain.length);
if (iov_ret < 0)
return -1;
@@ -2657,11 +2669,6 @@ static int iscsit_send_data_in(
cmd->iov_data_count = iov_count;
cmd->tx_size = tx_size;
- pr_debug("Built DataIN ITT: 0x%08x, StatSN: 0x%08x,"
- " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
- cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn),
- ntohl(hdr->offset), datain.length, conn->cid);
-
/* sendpage is preferred but can't insert markers */
if (!conn->conn_ops->IFMarker)
ret = iscsit_fe_sendpage_sg(cmd, conn);
@@ -2684,16 +2691,13 @@ static int iscsit_send_data_in(
return eodr;
}
-static int iscsit_send_logout_response(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+int
+iscsit_build_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_logout_rsp *hdr)
{
- int niov = 0, tx_size;
struct iscsi_conn *logout_conn = NULL;
struct iscsi_conn_recovery *cr = NULL;
struct iscsi_session *sess = conn->sess;
- struct kvec *iov;
- struct iscsi_logout_rsp *hdr;
/*
* The actual shutting down of Sessions and/or Connections
* for CLOSESESSION and CLOSECONNECTION Logout Requests
@@ -2762,9 +2766,6 @@ static int iscsit_send_logout_response(
return -1;
}
- tx_size = ISCSI_HDR_LEN;
- hdr = (struct iscsi_logout_rsp *)cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
hdr->opcode = ISCSI_OP_LOGOUT_RSP;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
hdr->response = cmd->logout_response;
@@ -2776,6 +2777,27 @@ static int iscsit_send_logout_response(
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ pr_debug("Built Logout Response ITT: 0x%08x StatSN:"
+ " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n",
+ cmd->init_task_tag, cmd->stat_sn, hdr->response,
+ cmd->logout_cid, conn->cid);
+
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_build_logout_rsp);
+
+static int
+iscsit_send_logout(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct kvec *iov;
+ int niov = 0, tx_size, rc;
+
+ rc = iscsit_build_logout_rsp(cmd, conn,
+ (struct iscsi_logout_rsp *)&cmd->pdu[0]);
+ if (rc < 0)
+ return rc;
+
+ tx_size = ISCSI_HDR_LEN;
iov = &cmd->iov_misc[0];
iov[niov].iov_base = cmd->pdu;
iov[niov++].iov_len = ISCSI_HDR_LEN;
@@ -2784,7 +2806,7 @@ static int iscsit_send_logout_response(
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
+ (unsigned char *)&cmd->pdu[0], ISCSI_HDR_LEN,
0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -2795,14 +2817,37 @@ static int iscsit_send_logout_response(
cmd->iov_misc_count = niov;
cmd->tx_size = tx_size;
- pr_debug("Sending Logout Response ITT: 0x%08x StatSN:"
- " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n",
- cmd->init_task_tag, cmd->stat_sn, hdr->response,
- cmd->logout_cid, conn->cid);
-
return 0;
}
+void
+iscsit_build_nopin_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_nopin *hdr, bool nopout_response)
+{
+ hdr->opcode = ISCSI_OP_NOOP_IN;
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ hton24(hdr->dlength, cmd->buf_ptr_size);
+ if (nopout_response)
+ put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
+ hdr->itt = cmd->init_task_tag;
+ hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
+ cmd->stat_sn = (nopout_response) ? conn->stat_sn++ :
+ conn->stat_sn;
+ hdr->statsn = cpu_to_be32(cmd->stat_sn);
+
+ if (nopout_response)
+ iscsit_increment_maxcmdsn(cmd, conn->sess);
+
+ hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
+ hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+
+ pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x,"
+ " StatSN: 0x%08x, Length %u\n", (nopout_response) ?
+ "Solicitied" : "Unsolicitied", cmd->init_task_tag,
+ cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size);
+}
+EXPORT_SYMBOL(iscsit_build_nopin_rsp);
+
/*
* Unsolicited NOPIN, either requesting a response or not.
*/
@@ -2811,20 +2856,10 @@ static int iscsit_send_unsolicited_nopin(
struct iscsi_conn *conn,
int want_response)
{
- int tx_size = ISCSI_HDR_LEN;
- struct iscsi_nopin *hdr;
- int ret;
+ struct iscsi_nopin *hdr = (struct iscsi_nopin *)&cmd->pdu[0];
+ int tx_size = ISCSI_HDR_LEN, ret;
- hdr = (struct iscsi_nopin *) cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
- hdr->opcode = ISCSI_OP_NOOP_IN;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- hdr->itt = cmd->init_task_tag;
- hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
- cmd->stat_sn = conn->stat_sn;
- hdr->statsn = cpu_to_be32(cmd->stat_sn);
- hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
- hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ iscsit_build_nopin_rsp(cmd, conn, hdr, false);
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
@@ -2860,31 +2895,17 @@ static int iscsit_send_unsolicited_nopin(
return 0;
}
-static int iscsit_send_nopin_response(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+static int
+iscsit_send_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
{
- int niov = 0, tx_size;
- u32 padding = 0;
+ struct iscsi_nopin *hdr = (struct iscsi_nopin *)&cmd->pdu[0];
struct kvec *iov;
- struct iscsi_nopin *hdr;
-
- tx_size = ISCSI_HDR_LEN;
- hdr = (struct iscsi_nopin *) cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
- hdr->opcode = ISCSI_OP_NOOP_IN;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- hton24(hdr->dlength, cmd->buf_ptr_size);
- put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
- hdr->itt = cmd->init_task_tag;
- hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
- cmd->stat_sn = conn->stat_sn++;
- hdr->statsn = cpu_to_be32(cmd->stat_sn);
+ u32 padding = 0;
+ int niov = 0, tx_size;
- iscsit_increment_maxcmdsn(cmd, conn->sess);
- hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
- hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ iscsit_build_nopin_rsp(cmd, conn, hdr, true);
+ tx_size = ISCSI_HDR_LEN;
iov = &cmd->iov_misc[0];
iov[niov].iov_base = cmd->pdu;
iov[niov++].iov_len = ISCSI_HDR_LEN;
@@ -2940,10 +2961,6 @@ static int iscsit_send_nopin_response(
cmd->iov_misc_count = niov;
cmd->tx_size = tx_size;
- pr_debug("Sending NOPIN Response ITT: 0x%08x, TTT:"
- " 0x%08x, StatSN: 0x%08x, Length %u\n", cmd->init_task_tag,
- cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size);
-
return 0;
}
@@ -3110,24 +3127,16 @@ int iscsit_build_r2ts_for_cmd(
return 0;
}
-static int iscsit_send_status(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+void iscsit_build_rsp_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ bool inc_stat_sn, struct iscsi_scsi_rsp *hdr)
{
- u8 iov_count = 0, recovery;
- u32 padding = 0, tx_size = 0;
- struct iscsi_scsi_rsp *hdr;
- struct kvec *iov;
-
- recovery = (cmd->i_state != ISTATE_SEND_STATUS);
- if (!recovery)
+ if (inc_stat_sn)
cmd->stat_sn = conn->stat_sn++;
spin_lock_bh(&conn->sess->session_stats_lock);
conn->sess->rsp_pdus++;
spin_unlock_bh(&conn->sess->session_stats_lock);
- hdr = (struct iscsi_scsi_rsp *) cmd->pdu;
memset(hdr, 0, ISCSI_HDR_LEN);
hdr->opcode = ISCSI_OP_SCSI_CMD_RSP;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
@@ -3147,6 +3156,23 @@ static int iscsit_send_status(
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ pr_debug("Built SCSI Response, ITT: 0x%08x, StatSN: 0x%08x,"
+ " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n",
+ cmd->init_task_tag, cmd->stat_sn, cmd->se_cmd.scsi_status,
+ cmd->se_cmd.scsi_status, conn->cid);
+}
+EXPORT_SYMBOL(iscsit_build_rsp_pdu);
+
+static int iscsit_send_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct iscsi_scsi_rsp *hdr = (struct iscsi_scsi_rsp *)&cmd->pdu[0];
+ struct kvec *iov;
+ u32 padding = 0, tx_size = 0;
+ int iov_count = 0;
+ bool inc_stat_sn = (cmd->i_state == ISTATE_SEND_STATUS);
+
+ iscsit_build_rsp_pdu(cmd, conn, inc_stat_sn, hdr);
+
iov = &cmd->iov_misc[0];
iov[iov_count].iov_base = cmd->pdu;
iov[iov_count++].iov_len = ISCSI_HDR_LEN;
@@ -3201,7 +3227,7 @@ static int iscsit_send_status(
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
+ (unsigned char *)cmd->pdu, ISCSI_HDR_LEN,
0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -3213,11 +3239,6 @@ static int iscsit_send_status(
cmd->iov_misc_count = iov_count;
cmd->tx_size = tx_size;
- pr_debug("Built %sSCSI Response, ITT: 0x%08x, StatSN: 0x%08x,"
- " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n",
- (!recovery) ? "" : "Recovery ", cmd->init_task_tag,
- cmd->stat_sn, 0x00, cmd->se_cmd.scsi_status, conn->cid);
-
return 0;
}
@@ -3240,16 +3261,12 @@ static u8 iscsit_convert_tcm_tmr_rsp(struct se_tmr_req *se_tmr)
}
}
-static int iscsit_send_task_mgt_rsp(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+void
+iscsit_build_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_tm_rsp *hdr)
{
struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
- struct iscsi_tm_rsp *hdr;
- u32 tx_size = 0;
- hdr = (struct iscsi_tm_rsp *) cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP;
hdr->flags = ISCSI_FLAG_CMD_FINAL;
hdr->response = iscsit_convert_tcm_tmr_rsp(se_tmr);
@@ -3261,6 +3278,20 @@ static int iscsit_send_task_mgt_rsp(
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ pr_debug("Built Task Management Response ITT: 0x%08x,"
+ " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n",
+ cmd->init_task_tag, cmd->stat_sn, hdr->response, conn->cid);
+}
+EXPORT_SYMBOL(iscsit_build_task_mgt_rsp);
+
+static int
+iscsit_send_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct iscsi_tm_rsp *hdr = (struct iscsi_tm_rsp *)&cmd->pdu[0];
+ u32 tx_size = 0;
+
+ iscsit_build_task_mgt_rsp(cmd, conn, hdr);
+
cmd->iov_misc[0].iov_base = cmd->pdu;
cmd->iov_misc[0].iov_len = ISCSI_HDR_LEN;
tx_size += ISCSI_HDR_LEN;
@@ -3281,10 +3312,6 @@ static int iscsit_send_task_mgt_rsp(
cmd->iov_misc_count = 1;
cmd->tx_size = tx_size;
- pr_debug("Built Task Management Response ITT: 0x%08x,"
- " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n",
- cmd->init_task_tag, cmd->stat_sn, hdr->response, conn->cid);
-
return 0;
}
@@ -3596,55 +3623,41 @@ static inline void iscsit_thread_check_cpumask(
set_cpus_allowed_ptr(p, conn->conn_cpumask);
}
-static int handle_immediate_queue(struct iscsi_conn *conn)
+static int
+iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
{
- struct iscsi_queue_req *qr;
- struct iscsi_cmd *cmd;
- u8 state;
int ret;
- while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) {
- atomic_set(&conn->check_immediate_queue, 0);
- cmd = qr->cmd;
- state = qr->state;
- kmem_cache_free(lio_qr_cache, qr);
-
- switch (state) {
- case ISTATE_SEND_R2T:
- ret = iscsit_send_r2t(cmd, conn);
- if (ret < 0)
- goto err;
- break;
- case ISTATE_REMOVE:
- if (cmd->data_direction == DMA_TO_DEVICE)
- iscsit_stop_dataout_timer(cmd);
-
- spin_lock_bh(&conn->cmd_lock);
- list_del(&cmd->i_conn_node);
- spin_unlock_bh(&conn->cmd_lock);
+ switch (state) {
+ case ISTATE_SEND_R2T:
+ ret = iscsit_send_r2t(cmd, conn);
+ if (ret < 0)
+ goto err;
+ break;
+ case ISTATE_REMOVE:
+ spin_lock_bh(&conn->cmd_lock);
+ list_del(&cmd->i_conn_node);
+ spin_unlock_bh(&conn->cmd_lock);
- iscsit_free_cmd(cmd);
- continue;
- case ISTATE_SEND_NOPIN_WANT_RESPONSE:
- iscsit_mod_nopin_response_timer(conn);
- ret = iscsit_send_unsolicited_nopin(cmd,
- conn, 1);
- if (ret < 0)
- goto err;
- break;
- case ISTATE_SEND_NOPIN_NO_RESPONSE:
- ret = iscsit_send_unsolicited_nopin(cmd,
- conn, 0);
- if (ret < 0)
- goto err;
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag, state,
- conn->cid);
+ iscsit_free_cmd(cmd);
+ break;
+ case ISTATE_SEND_NOPIN_WANT_RESPONSE:
+ iscsit_mod_nopin_response_timer(conn);
+ ret = iscsit_send_unsolicited_nopin(cmd, conn, 1);
+ if (ret < 0)
goto err;
- }
+ break;
+ case ISTATE_SEND_NOPIN_NO_RESPONSE:
+ ret = iscsit_send_unsolicited_nopin(cmd, conn, 0);
+ if (ret < 0)
+ goto err;
+ break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+ cmd->iscsi_opcode, cmd->init_task_tag, state,
+ conn->cid);
+ goto err;
}
return 0;
@@ -3653,124 +3666,150 @@ err:
return -1;
}
-static int handle_response_queue(struct iscsi_conn *conn)
+static int
+iscsit_handle_immediate_queue(struct iscsi_conn *conn)
{
+ struct iscsit_transport *t = conn->conn_transport;
struct iscsi_queue_req *qr;
struct iscsi_cmd *cmd;
u8 state;
int ret;
- while ((qr = iscsit_get_cmd_from_response_queue(conn))) {
+ while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) {
+ atomic_set(&conn->check_immediate_queue, 0);
cmd = qr->cmd;
state = qr->state;
kmem_cache_free(lio_qr_cache, qr);
-check_rsp_state:
- switch (state) {
- case ISTATE_SEND_DATAIN:
- ret = iscsit_send_data_in(cmd, conn);
- if (ret < 0)
- goto err;
- else if (!ret)
- /* more drs */
- goto check_rsp_state;
- else if (ret == 1) {
- /* all done */
- spin_lock_bh(&cmd->istate_lock);
- cmd->i_state = ISTATE_SENT_STATUS;
- spin_unlock_bh(&cmd->istate_lock);
- continue;
- } else if (ret == 2) {
- /* Still must send status,
- SCF_TRANSPORT_TASK_SENSE was set */
- spin_lock_bh(&cmd->istate_lock);
- cmd->i_state = ISTATE_SEND_STATUS;
- spin_unlock_bh(&cmd->istate_lock);
- state = ISTATE_SEND_STATUS;
- goto check_rsp_state;
- }
-
- break;
- case ISTATE_SEND_STATUS:
- case ISTATE_SEND_STATUS_RECOVERY:
- ret = iscsit_send_status(cmd, conn);
- break;
- case ISTATE_SEND_LOGOUTRSP:
- ret = iscsit_send_logout_response(cmd, conn);
- break;
- case ISTATE_SEND_ASYNCMSG:
- ret = iscsit_send_conn_drop_async_message(
- cmd, conn);
- break;
- case ISTATE_SEND_NOPIN:
- ret = iscsit_send_nopin_response(cmd, conn);
- break;
- case ISTATE_SEND_REJECT:
- ret = iscsit_send_reject(cmd, conn);
- break;
- case ISTATE_SEND_TASKMGTRSP:
- ret = iscsit_send_task_mgt_rsp(cmd, conn);
- if (ret != 0)
- break;
- ret = iscsit_tmr_post_handler(cmd, conn);
- if (ret != 0)
- iscsit_fall_back_to_erl0(conn->sess);
- break;
- case ISTATE_SEND_TEXTRSP:
- ret = iscsit_send_text_rsp(cmd, conn);
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag,
- state, conn->cid);
- goto err;
- }
+ ret = t->iscsit_immediate_queue(conn, cmd, state);
if (ret < 0)
- goto err;
+ return ret;
+ }
+
+ return 0;
+}
- if (iscsit_send_tx_data(cmd, conn, 1) < 0) {
- iscsit_tx_thread_wait_for_tcp(conn);
- iscsit_unmap_iovec(cmd);
+static int
+iscsit_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
+{
+ int ret;
+
+check_rsp_state:
+ switch (state) {
+ case ISTATE_SEND_DATAIN:
+ ret = iscsit_send_datain(cmd, conn);
+ if (ret < 0)
goto err;
+ else if (!ret)
+ /* more drs */
+ goto check_rsp_state;
+ else if (ret == 1) {
+ /* all done */
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+ return 0;
+ } else if (ret == 2) {
+ /* Still must send status,
+ SCF_TRANSPORT_TASK_SENSE was set */
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SEND_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+ state = ISTATE_SEND_STATUS;
+ goto check_rsp_state;
}
- iscsit_unmap_iovec(cmd);
- switch (state) {
- case ISTATE_SEND_LOGOUTRSP:
- if (!iscsit_logout_post_handler(cmd, conn))
- goto restart;
- /* fall through */
- case ISTATE_SEND_STATUS:
- case ISTATE_SEND_ASYNCMSG:
- case ISTATE_SEND_NOPIN:
- case ISTATE_SEND_STATUS_RECOVERY:
- case ISTATE_SEND_TEXTRSP:
- case ISTATE_SEND_TASKMGTRSP:
+ break;
+ case ISTATE_SEND_STATUS:
+ case ISTATE_SEND_STATUS_RECOVERY:
+ ret = iscsit_send_response(cmd, conn);
+ if (!ret) {
spin_lock_bh(&cmd->istate_lock);
cmd->i_state = ISTATE_SENT_STATUS;
spin_unlock_bh(&cmd->istate_lock);
+ return 0;
+ }
+ break;
+ case ISTATE_SEND_LOGOUTRSP:
+ ret = iscsit_send_logout(cmd, conn);
+ break;
+ case ISTATE_SEND_ASYNCMSG:
+ ret = iscsit_send_conn_drop_async_message(cmd, conn);
+ break;
+ case ISTATE_SEND_NOPIN:
+ ret = iscsit_send_nopin(cmd, conn);
+ if (!ret) {
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+ return 0;
+ }
+ break;
+ case ISTATE_SEND_REJECT:
+ ret = iscsit_send_reject(cmd, conn);
+ break;
+ case ISTATE_SEND_TASKMGTRSP:
+ ret = iscsit_send_task_mgt_rsp(cmd, conn);
+ if (ret != 0)
break;
- case ISTATE_SEND_REJECT:
- if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
- cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
- complete(&cmd->reject_comp);
- goto err;
- }
+ ret = iscsit_tmr_post_handler(cmd, conn);
+ if (ret != 0)
+ iscsit_fall_back_to_erl0(conn->sess);
+ break;
+ case ISTATE_SEND_TEXTRSP:
+ ret = iscsit_send_text_rsp(cmd, conn);
+ break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+ cmd->iscsi_opcode, cmd->init_task_tag,
+ state, conn->cid);
+ goto err;
+ }
+ if (ret < 0)
+ goto err;
+
+ if (iscsit_send_tx_data(cmd, conn, 1) < 0) {
+ iscsit_tx_thread_wait_for_tcp(conn);
+ iscsit_unmap_iovec(cmd);
+ goto err;
+ }
+ iscsit_unmap_iovec(cmd);
+
+ switch (state) {
+ case ISTATE_SEND_LOGOUTRSP:
+ if (!iscsit_logout_post_handler(cmd, conn))
+ goto restart;
+ /* fall through */
+ case ISTATE_SEND_STATUS:
+ case ISTATE_SEND_ASYNCMSG:
+ case ISTATE_SEND_NOPIN:
+ case ISTATE_SEND_STATUS_RECOVERY:
+ case ISTATE_SEND_TEXTRSP:
+ case ISTATE_SEND_TASKMGTRSP:
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+ break;
+ case ISTATE_SEND_REJECT:
+ if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
+ cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
complete(&cmd->reject_comp);
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag,
- cmd->i_state, conn->cid);
goto err;
}
-
- if (atomic_read(&conn->check_immediate_queue))
- break;
+ complete(&cmd->reject_comp);
+ break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+ cmd->iscsi_opcode, cmd->init_task_tag,
+ cmd->i_state, conn->cid);
+ goto err;
}
+ if (atomic_read(&conn->check_immediate_queue))
+ return 1;
+
return 0;
err:
@@ -3779,6 +3818,27 @@ restart:
return -EAGAIN;
}
+static int iscsit_handle_response_queue(struct iscsi_conn *conn)
+{
+ struct iscsit_transport *t = conn->conn_transport;
+ struct iscsi_queue_req *qr;
+ struct iscsi_cmd *cmd;
+ u8 state;
+ int ret;
+
+ while ((qr = iscsit_get_cmd_from_response_queue(conn))) {
+ cmd = qr->cmd;
+ state = qr->state;
+ kmem_cache_free(lio_qr_cache, qr);
+
+ ret = t->iscsit_response_queue(conn, cmd, state);
+ if (ret == 1 || ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
int iscsi_target_tx_thread(void *arg)
{
int ret = 0;
@@ -3812,11 +3872,11 @@ restart:
signal_pending(current))
goto transport_err;
- ret = handle_immediate_queue(conn);
+ ret = iscsit_handle_immediate_queue(conn);
if (ret < 0)
goto transport_err;
- ret = handle_response_queue(conn);
+ ret = iscsit_handle_response_queue(conn);
if (ret == -EAGAIN)
goto restart;
else if (ret < 0)
@@ -4414,7 +4474,7 @@ static void iscsit_logout_post_handler_diffcid(
/*
* Return of 0 causes the TX thread to restart.
*/
-static int iscsit_logout_post_handler(
+int iscsit_logout_post_handler(
struct iscsi_cmd *cmd,
struct iscsi_conn *conn)
{
@@ -4472,6 +4532,7 @@ static int iscsit_logout_post_handler(
}
return ret;
}
+EXPORT_SYMBOL(iscsit_logout_post_handler);
void iscsit_fail_session(struct iscsi_session *sess)
{
diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c
index bcc4098..4edcc47 100644
--- a/drivers/target/iscsi/iscsi_target_device.c
+++ b/drivers/target/iscsi/iscsi_target_device.c
@@ -65,3 +65,4 @@ void iscsit_increment_maxcmdsn(struct iscsi_cmd *cmd, struct iscsi_session *sess
pr_debug("Updated MaxCmdSN to 0x%08x\n", sess->max_cmd_sn);
mutex_unlock(&sess->cmdsn_mutex);
}
+EXPORT_SYMBOL(iscsit_increment_maxcmdsn);
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index 9d4417a..5ae13ae 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -471,6 +471,7 @@ int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
return 0;
}
+EXPORT_SYMBOL(iscsit_tmr_post_handler);
/*
* Nothing to do here, but leave it for good measure. :-)
--
1.7.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [RFC 05/11] iscsi-target: Refactor RX PDU logic + export request PDU handling
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
` (3 preceding siblings ...)
[not found] ` <1362707116-31406-1-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
[not found] ` <1362707116-31406-6-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
2013-03-08 1:45 ` [RFC 07/11] iscsi-target: Add iser network portal attribute Nicholas A. Bellinger
` (5 subsequent siblings)
10 siblings, 1 reply; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab@linux-iscsi.org>
This patch refactors existing traditional iscsi RX side PDU handling
to use iscsit_transport, and exports the necessary logic for external
transport modules.
This includes:
- Refactor iscsit_handle_scsi_cmd() into PDU setup / processing
- Add updated iscsit_handle_scsi_cmd() for tradtional iscsi code
- Add iscsit_set_unsoliticed_dataout() wrapper
- Refactor iscsit_handle_data_out() into PDU check / processing
- Add updated iscsit_handle_data_out() for tradtional iscsi code
- Add iscsit_handle_nop_out() + iscsit_handle_task_mgt_cmd() to
accept pre-allocated struct iscsi_cmd
- Add iscsit_build_r2ts_for_cmd() RDMAExtentions check to
post ISTATE_SEND_R2T to TX immediate queue to start RDMA READ
- Refactor main traditional iscsi iscsi_target_rx_thread() PDU switch
into iscsi_target_rx_opcode() using iscsit_allocate_cmd()
- Turn iscsi_target_rx_thread() process context into NOP for
ib_isert side work-queue.
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/target/iscsi/iscsi_target.c | 463 +++++++++++++++++++-----------
drivers/target/iscsi/iscsi_target.h | 1 +
drivers/target/iscsi/iscsi_target_erl1.c | 8 +-
drivers/target/iscsi/iscsi_target_util.c | 1 +
4 files changed, 295 insertions(+), 178 deletions(-)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 9cd7b7b..fbdc75a 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -703,6 +703,7 @@ int iscsit_add_reject_from_cmd(
return (!fail_conn) ? 0 : -1;
}
+EXPORT_SYMBOL(iscsit_add_reject_from_cmd);
/*
* Map some portion of the allocated scatterlist to an iovec, suitable for
@@ -793,12 +794,10 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
return 0;
}
-static int iscsit_handle_scsi_cmd(
- struct iscsi_conn *conn,
- unsigned char *buf)
+int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
{
- int data_direction, payload_length, cmdsn_ret = 0, immed_ret;
- struct iscsi_cmd *cmd = NULL;
+ int data_direction, payload_length;
struct iscsi_scsi_req *hdr;
int iscsi_task_attr;
int sam_task_attr;
@@ -821,8 +820,8 @@ static int iscsit_handle_scsi_cmd(
!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL"
" not set. Bad iSCSI Initiator.\n");
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
if (((hdr->flags & ISCSI_FLAG_CMD_READ) ||
@@ -842,8 +841,8 @@ static int iscsit_handle_scsi_cmd(
pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE"
" set when Expected Data Transfer Length is 0 for"
" CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]);
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
done:
@@ -852,29 +851,29 @@ done:
pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE"
" MUST be set if Expected Data Transfer Length is not 0."
" Bad iSCSI Initiator\n");
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
if ((hdr->flags & ISCSI_FLAG_CMD_READ) &&
(hdr->flags & ISCSI_FLAG_CMD_WRITE)) {
pr_err("Bidirectional operations not supported!\n");
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
pr_err("Illegally set Immediate Bit in iSCSI Initiator"
" Scsi Command PDU.\n");
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
if (payload_length && !conn->sess->sess_ops->ImmediateData) {
pr_err("ImmediateData=No but DataSegmentLength=%u,"
" protocol error.\n", payload_length);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if ((be32_to_cpu(hdr->data_length )== payload_length) &&
@@ -882,43 +881,38 @@ done:
pr_err("Expected Data Transfer Length and Length of"
" Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"
" bit is not set protocol error\n");
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if (payload_length > be32_to_cpu(hdr->data_length)) {
pr_err("DataSegmentLength: %u is greater than"
" EDTL: %u, protocol error.\n", payload_length,
hdr->data_length);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
pr_err("DataSegmentLength: %u is greater than"
" MaxXmitDataSegmentLength: %u, protocol error.\n",
payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if (payload_length > conn->sess->sess_ops->FirstBurstLength) {
pr_err("DataSegmentLength: %u is greater than"
" FirstBurstLength: %u, protocol error.\n",
payload_length, conn->sess->sess_ops->FirstBurstLength);
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
(hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE :
DMA_NONE;
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
- if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1,
- buf, conn);
-
cmd->data_direction = data_direction;
iscsi_task_attr = hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK;
/*
@@ -983,7 +977,8 @@ done:
pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x,"
" ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt,
- hdr->cmdsn, hdr->data_length, payload_length, conn->cid);
+ hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length,
+ conn->cid);
cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd,
scsilun_to_int(&hdr->lun));
@@ -1017,12 +1012,24 @@ attach_cmd:
*/
core_alua_check_nonop_delay(&cmd->se_cmd);
- if (iscsit_allocate_iovecs(cmd) < 0) {
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 0, buf, cmd);
- }
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_setup_scsi_cmd);
+void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *cmd)
+{
+ iscsit_set_dataout_sequence_values(cmd);
+
+ spin_lock_bh(&cmd->dataout_timeout_lock);
+ iscsit_start_dataout_timer(cmd, cmd->conn);
+ spin_unlock_bh(&cmd->dataout_timeout_lock);
+}
+EXPORT_SYMBOL(iscsit_set_unsoliticed_dataout);
+
+int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ struct iscsi_scsi_req *hdr)
+{
+ int cmdsn_ret = 0;
/*
* Check the CmdSN against ExpCmdSN/MaxCmdSN here if
* the Immediate Bit is not set, and no Immediate
@@ -1040,7 +1047,7 @@ attach_cmd:
else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
+ 1, 0, (unsigned char *)hdr, cmd);
}
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
@@ -1049,13 +1056,8 @@ attach_cmd:
* If no Immediate Data is attached, it's OK to return now.
*/
if (!cmd->immediate_data) {
- if (!cmd->sense_reason && cmd->unsolicited_data) {
- iscsit_set_dataout_sequence_values(cmd);
-
- spin_lock_bh(&cmd->dataout_timeout_lock);
- iscsit_start_dataout_timer(cmd, cmd->conn);
- spin_unlock_bh(&cmd->dataout_timeout_lock);
- }
+ if (!cmd->sense_reason && cmd->unsolicited_data)
+ iscsit_set_unsoliticed_dataout(cmd);
return 0;
}
@@ -1065,21 +1067,33 @@ attach_cmd:
* thread. They are processed in CmdSN order by
* iscsit_check_received_cmdsn() below.
*/
- if (cmd->sense_reason) {
- immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
- goto after_immediate_data;
- }
+ if (cmd->sense_reason)
+ return 1;
/*
* Call directly into transport_generic_new_cmd() to perform
* the backend memory allocation.
*/
cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd);
- if (cmd->sense_reason) {
- immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
+ if (cmd->sense_reason)
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_process_scsi_cmd);
+
+static int
+iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
+ bool dump_payload)
+{
+ int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
+ /*
+ * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
+ */
+ if (dump_payload == true)
goto after_immediate_data;
- }
- immed_ret = iscsit_handle_immediate_data(cmd, buf, payload_length);
+ immed_ret = iscsit_handle_immediate_data(cmd, hdr,
+ cmd->first_burst_len);
after_immediate_data:
if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) {
/*
@@ -1087,26 +1101,19 @@ after_immediate_data:
* DataCRC, check against ExpCmdSN/MaxCmdSN if
* Immediate Bit is not set.
*/
- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
- /*
- * Special case for Unsupported SAM WRITE Opcodes
- * and ImmediateData=Yes.
- */
+ cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, hdr->cmdsn);
+
if (cmd->sense_reason) {
- if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
+ if (iscsit_dump_data_payload(cmd->conn,
+ cmd->first_burst_len, 1) < 0)
return -1;
- } else if (cmd->unsolicited_data) {
- iscsit_set_dataout_sequence_values(cmd);
-
- spin_lock_bh(&cmd->dataout_timeout_lock);
- iscsit_start_dataout_timer(cmd, cmd->conn);
- spin_unlock_bh(&cmd->dataout_timeout_lock);
- }
+ } else if (cmd->unsolicited_data)
+ iscsit_set_unsoliticed_dataout(cmd);
if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
+ 1, 0, (unsigned char *)hdr, cmd);
} else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
/*
@@ -1121,13 +1128,46 @@ after_immediate_data:
* CmdSN and issue a retry to plug the sequence.
*/
cmd->i_state = ISTATE_REMOVE;
- iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
+ iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, cmd->i_state);
} else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */
return -1;
return 0;
}
+int iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
+{
+ struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)buf;
+ int rc, immed_data;
+ bool dump_payload = false;
+
+ rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
+ if (rc < 0)
+ return rc;
+ /*
+ * Allocation iovecs needed for struct socket operations for
+ * traditional iSCSI block I/O.
+ */
+ if (iscsit_allocate_iovecs(cmd) < 0) {
+ return iscsit_add_reject_from_cmd(
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, 0, buf, cmd);
+ }
+ immed_data = cmd->immediate_data;
+
+ rc = iscsit_process_scsi_cmd(conn, cmd, hdr);
+ if (rc < 0)
+ return rc;
+ else if (rc > 0)
+ dump_payload = true;
+
+ if (!immed_data)
+ return 0;
+
+ return iscsit_get_immediate_data(cmd, hdr, cmd->first_burst_len);
+}
+
static u32 iscsit_do_crypto_hash_sg(
struct hash_desc *hash,
struct iscsi_cmd *cmd,
@@ -1190,20 +1230,16 @@ static void iscsit_do_crypto_hash_buf(
crypto_hash_final(hash, data_crc);
}
-static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
+int
+iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
+ struct iscsi_cmd **out_cmd)
{
- int iov_ret, ooo_cmdsn = 0, ret;
- u8 data_crc_failed = 0;
- u32 checksum, iov_count = 0, padding = 0, rx_got = 0;
- u32 rx_size = 0, payload_length;
+ struct iscsi_data *hdr = (struct iscsi_data *)buf;
struct iscsi_cmd *cmd = NULL;
struct se_cmd *se_cmd;
- struct iscsi_data *hdr;
- struct kvec *iov;
unsigned long flags;
-
- hdr = (struct iscsi_data *) buf;
- payload_length = ntoh24(hdr->dlength);
+ u32 payload_length = ntoh24(hdr->dlength);
+ int rc;
if (!payload_length) {
pr_err("DataOUT payload is ZERO, protocol error.\n");
@@ -1236,7 +1272,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
pr_debug("Got DataOut ITT: 0x%08x, TTT: 0x%08x,"
" DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
- hdr->itt, hdr->ttt, hdr->datasn, hdr->offset,
+ hdr->itt, hdr->ttt, hdr->datasn, ntohl(hdr->offset),
payload_length, conn->cid);
if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
@@ -1328,12 +1364,26 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
* Preform DataSN, DataSequenceInOrder, DataPDUInOrder, and
* within-command recovery checks before receiving the payload.
*/
- ret = iscsit_check_pre_dataout(cmd, buf);
- if (ret == DATAOUT_WITHIN_COMMAND_RECOVERY)
+ rc = iscsit_check_pre_dataout(cmd, buf);
+ if (rc == DATAOUT_WITHIN_COMMAND_RECOVERY)
return 0;
- else if (ret == DATAOUT_CANNOT_RECOVER)
+ else if (rc == DATAOUT_CANNOT_RECOVER)
return -1;
+ *out_cmd = cmd;
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_check_dataout_hdr);
+
+static int
+iscsit_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ struct iscsi_data *hdr)
+{
+ struct kvec *iov;
+ u32 checksum, iov_count = 0, padding = 0, rx_got = 0, rx_size = 0;
+ u32 payload_length = ntoh24(hdr->dlength);
+ int iov_ret, data_crc_failed = 0;
+
rx_size += payload_length;
iov = &cmd->iov_data[0];
@@ -1386,17 +1436,27 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
payload_length);
}
}
+
+ return data_crc_failed;
+}
+
+int
+iscsit_check_dataout_payload(struct iscsi_cmd *cmd, struct iscsi_data *hdr,
+ bool data_crc_failed)
+{
+ struct iscsi_conn *conn = cmd->conn;
+ int rc, ooo_cmdsn;
/*
* Increment post receive data and CRC values or perform
* within-command recovery.
*/
- ret = iscsit_check_post_dataout(cmd, buf, data_crc_failed);
- if ((ret == DATAOUT_NORMAL) || (ret == DATAOUT_WITHIN_COMMAND_RECOVERY))
+ rc = iscsit_check_post_dataout(cmd, (unsigned char *)hdr, data_crc_failed);
+ if ((rc == DATAOUT_NORMAL) || (rc == DATAOUT_WITHIN_COMMAND_RECOVERY))
return 0;
- else if (ret == DATAOUT_SEND_R2T) {
+ else if (rc == DATAOUT_SEND_R2T) {
iscsit_set_dataout_sequence_values(cmd);
iscsit_build_r2ts_for_cmd(cmd, conn, false);
- } else if (ret == DATAOUT_SEND_TO_TRANSPORT) {
+ } else if (rc == DATAOUT_SEND_TO_TRANSPORT) {
/*
* Handle extra special case for out of order
* Unsolicited Data Out.
@@ -1417,15 +1477,37 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
return 0;
}
+EXPORT_SYMBOL(iscsit_check_dataout_payload);
-static int iscsit_handle_nop_out(
- struct iscsi_conn *conn,
- unsigned char *buf)
+static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
+{
+ struct iscsi_cmd *cmd;
+ struct iscsi_data *hdr = (struct iscsi_data *)buf;
+ int rc;
+ bool data_crc_failed = false;
+
+ rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
+ if (rc < 0)
+ return rc;
+ else if (!cmd)
+ return 0;
+
+ rc = iscsit_get_dataout(conn, cmd, hdr);
+ if (rc < 0)
+ return rc;
+ else if (rc > 0)
+ data_crc_failed = true;
+
+ return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed);
+}
+
+int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
{
unsigned char *ping_data = NULL;
int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size;
u32 checksum, data_crc, padding = 0, payload_length;
- struct iscsi_cmd *cmd = NULL;
+ struct iscsi_cmd *cmd_p = NULL;
struct kvec *iov = NULL;
struct iscsi_nopout *hdr;
@@ -1448,7 +1530,7 @@ static int iscsit_handle_nop_out(
buf, conn);
}
- pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%09x,"
+ pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x,"
" CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
hdr->itt == RESERVED_ITT ? "Response" : "Request",
hdr->itt, hdr->ttt, hdr->cmdsn, hdr->exp_statsn,
@@ -1461,7 +1543,6 @@ static int iscsit_handle_nop_out(
* can contain ping data.
*/
if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
return iscsit_add_reject(
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
@@ -1596,14 +1677,14 @@ static int iscsit_handle_nop_out(
/*
* This was a response to a unsolicited NOPIN ping.
*/
- cmd = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
- if (!cmd)
+ cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
+ if (!cmd_p)
return -1;
iscsit_stop_nopin_response_timer(conn);
- cmd->i_state = ISTATE_REMOVE;
- iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
+ cmd_p->i_state = ISTATE_REMOVE;
+ iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
iscsit_start_nopin_timer(conn);
} else {
/*
@@ -1627,12 +1708,12 @@ ping_out:
kfree(ping_data);
return ret;
}
+EXPORT_SYMBOL(iscsit_handle_nop_out);
-static int iscsit_handle_task_mgt_cmd(
- struct iscsi_conn *conn,
- unsigned char *buf)
+int
+iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
{
- struct iscsi_cmd *cmd;
struct se_tmr_req *se_tmr;
struct iscsi_tmr_req *tmr_req;
struct iscsi_tm *hdr;
@@ -1661,18 +1742,13 @@ static int iscsit_handle_task_mgt_cmd(
pr_err("Task Management Request TASK_REASSIGN not"
" issued as immediate command, bad iSCSI Initiator"
"implementation\n");
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG)
hdr->refcmdsn = cpu_to_be32(ISCSI_RESERVED_TAG);
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
- if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, buf, conn);
-
cmd->data_direction = DMA_NONE;
cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL);
@@ -1843,6 +1919,7 @@ attach:
iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
return 0;
}
+EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);
/* #warning FIXME: Support Text Command parameters besides SendTargets */
static int iscsit_handle_text_cmd(
@@ -2105,13 +2182,12 @@ int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *cmd, struct iscsi_conn
return 0;
}
-static int iscsit_handle_logout_cmd(
- struct iscsi_conn *conn,
- unsigned char *buf)
+int
+iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
{
int cmdsn_ret, logout_remove = 0;
u8 reason_code = 0;
- struct iscsi_cmd *cmd;
struct iscsi_logout *hdr;
struct iscsi_tiqn *tiqn = iscsit_snmp_get_tiqn(conn);
@@ -2135,14 +2211,10 @@ static int iscsit_handle_logout_cmd(
if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) {
pr_err("Received logout request on connection that"
" is not in logged in state, ignoring request.\n");
+ iscsit_release_cmd(cmd);
return 0;
}
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
- if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1,
- buf, conn);
-
cmd->iscsi_opcode = ISCSI_OP_LOGOUT;
cmd->i_state = ISTATE_SEND_LOGOUTRSP;
cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
@@ -2192,6 +2264,7 @@ static int iscsit_handle_logout_cmd(
return logout_remove;
}
+EXPORT_SYMBOL(iscsit_handle_logout_cmd);
static int iscsit_handle_snack(
struct iscsi_conn *conn,
@@ -2259,7 +2332,7 @@ static void iscsit_rx_thread_wait_for_tcp(struct iscsi_conn *conn)
static int iscsit_handle_immediate_data(
struct iscsi_cmd *cmd,
- unsigned char *buf,
+ struct iscsi_scsi_req *hdr,
u32 length)
{
int iov_ret, rx_got = 0, rx_size = 0;
@@ -2315,12 +2388,12 @@ static int iscsit_handle_immediate_data(
" in ERL=0.\n");
iscsit_add_reject_from_cmd(
ISCSI_REASON_DATA_DIGEST_ERROR,
- 1, 0, buf, cmd);
+ 1, 0, (unsigned char *)hdr, cmd);
return IMMEDIATE_DATA_CANNOT_RECOVER;
} else {
iscsit_add_reject_from_cmd(
ISCSI_REASON_DATA_DIGEST_ERROR,
- 0, 0, buf, cmd);
+ 0, 0, (unsigned char *)hdr, cmd);
return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
}
} else {
@@ -2962,6 +3035,12 @@ int iscsit_build_r2ts_for_cmd(
int first_r2t = 1;
u32 offset = 0, xfer_len = 0;
+ if (conn->sess->sess_ops->RDMAExtentions) {
+ iscsit_stop_dataout_timer(cmd);
+ iscsit_add_cmd_to_immediate_queue(cmd, conn, ISTATE_SEND_R2T);
+ return 0;
+ }
+
spin_lock_bh(&cmd->r2t_lock);
if (cmd->cmd_flags & ICF_SENT_LAST_R2T) {
spin_unlock_bh(&cmd->r2t_lock);
@@ -3751,6 +3830,83 @@ out:
return 0;
}
+static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
+{
+ struct iscsi_hdr *hdr = (struct iscsi_hdr *)buf;
+ struct iscsi_cmd *cmd;
+ int ret = 0;
+
+ switch (hdr->opcode & ISCSI_OPCODE_MASK) {
+ case ISCSI_OP_SCSI_CMD:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, buf, conn);
+
+ ret = iscsit_handle_scsi_cmd(conn, cmd, buf);
+ break;
+ case ISCSI_OP_SCSI_DATA_OUT:
+ ret = iscsit_handle_data_out(conn, buf);
+ break;
+ case ISCSI_OP_NOOP_OUT:
+ cmd = NULL;
+ if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, buf, conn);
+ }
+ ret = iscsit_handle_nop_out(conn, cmd, buf);
+ break;
+ case ISCSI_OP_SCSI_TMFUNC:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, buf, conn);
+
+ ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
+ break;
+ case ISCSI_OP_TEXT:
+ ret = iscsit_handle_text_cmd(conn, buf);
+ break;
+ case ISCSI_OP_LOGOUT:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, buf, conn);
+
+ ret = iscsit_handle_logout_cmd(conn, cmd, buf);
+ if (ret > 0)
+ wait_for_completion_timeout(&conn->conn_logout_comp,
+ SECONDS_FOR_LOGOUT_COMP * HZ);
+ break;
+ case ISCSI_OP_SNACK:
+ ret = iscsit_handle_snack(conn, buf);
+ break;
+ default:
+ pr_err("Got unknown iSCSI OpCode: 0x%02x\n", hdr->opcode);
+ if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+ pr_err("Cannot recover from unknown"
+ " opcode while ERL=0, closing iSCSI connection.\n");
+ return -1;
+ }
+ if (!conn->conn_ops->OFMarker) {
+ pr_err("Unable to recover from unknown"
+ " opcode while OFMarker=No, closing iSCSI"
+ " connection.\n");
+ return -1;
+ }
+ if (iscsit_recover_from_unknown_opcode(conn) < 0) {
+ pr_err("Unable to recover from unknown"
+ " opcode, closing iSCSI connection.\n");
+ return -1;
+ }
+ break;
+ }
+
+ return ret;
+}
+
int iscsi_target_rx_thread(void *arg)
{
int ret;
@@ -3770,6 +3926,18 @@ restart:
if (!conn)
goto out;
+ if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
+ struct completion comp;
+ int rc;
+
+ init_completion(&comp);
+ rc = wait_for_completion_interruptible(&comp);
+ if (rc < 0)
+ goto transport_err;
+
+ goto out;
+ }
+
while (!kthread_should_stop()) {
/*
* Ensure that both TX and RX per connection kthreads
@@ -3841,62 +4009,9 @@ restart:
goto transport_err;
}
- switch (opcode) {
- case ISCSI_OP_SCSI_CMD:
- if (iscsit_handle_scsi_cmd(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_SCSI_DATA_OUT:
- if (iscsit_handle_data_out(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_NOOP_OUT:
- if (iscsit_handle_nop_out(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_SCSI_TMFUNC:
- if (iscsit_handle_task_mgt_cmd(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_TEXT:
- if (iscsit_handle_text_cmd(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_LOGOUT:
- ret = iscsit_handle_logout_cmd(conn, buffer);
- if (ret > 0) {
- wait_for_completion_timeout(&conn->conn_logout_comp,
- SECONDS_FOR_LOGOUT_COMP * HZ);
- goto transport_err;
- } else if (ret < 0)
- goto transport_err;
- break;
- case ISCSI_OP_SNACK:
- if (iscsit_handle_snack(conn, buffer) < 0)
- goto transport_err;
- break;
- default:
- pr_err("Got unknown iSCSI OpCode: 0x%02x\n",
- opcode);
- if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
- pr_err("Cannot recover from unknown"
- " opcode while ERL=0, closing iSCSI connection"
- ".\n");
- goto transport_err;
- }
- if (!conn->conn_ops->OFMarker) {
- pr_err("Unable to recover from unknown"
- " opcode while OFMarker=No, closing iSCSI"
- " connection.\n");
- goto transport_err;
- }
- if (iscsit_recover_from_unknown_opcode(conn) < 0) {
- pr_err("Unable to recover from unknown"
- " opcode, closing iSCSI connection.\n");
- goto transport_err;
- }
- break;
- }
+ ret = iscsi_target_rx_opcode(conn, buffer);
+ if (ret < 0)
+ goto transport_err;
}
transport_err:
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
index b1a1e63..97c8c94 100644
--- a/drivers/target/iscsi/iscsi_target.h
+++ b/drivers/target/iscsi/iscsi_target.h
@@ -16,6 +16,7 @@ extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
struct iscsi_portal_group *);
extern int iscsit_del_np(struct iscsi_np *);
extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *);
+extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *, struct iscsi_conn *);
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 0b52a23..8bf9d6d 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -53,6 +53,9 @@ int iscsit_dump_data_payload(
u32 length, padding, offset = 0, size;
struct kvec iov;
+ if (conn->sess->sess_ops->RDMAExtentions)
+ return 0;
+
length = (buf_len > OFFLOAD_BUF_SIZE) ? OFFLOAD_BUF_SIZE : buf_len;
buf = kzalloc(length, GFP_ATOMIC);
@@ -999,10 +1002,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
if (transport_check_aborted_status(se_cmd, 1) != 0)
return 0;
- iscsit_set_dataout_sequence_values(cmd);
- spin_lock_bh(&cmd->dataout_timeout_lock);
- iscsit_start_dataout_timer(cmd, cmd->conn);
- spin_unlock_bh(&cmd->dataout_timeout_lock);
+ iscsit_set_unsoliticed_dataout(cmd);
}
return transport_handle_cdb_direct(&cmd->se_cmd);
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 4a86034..e547277 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -316,6 +316,7 @@ int iscsit_sequence_cmd(
return ret;
}
+EXPORT_SYMBOL(iscsit_sequence_cmd);
int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf)
{
--
1.7.2.5
^ permalink raw reply related [flat|nested] 35+ messages in thread* [RFC 07/11] iscsi-target: Add iser network portal attribute
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
` (4 preceding siblings ...)
2013-03-08 1:45 ` [RFC 05/11] iscsi-target: Refactor RX PDU logic + export request PDU handling Nicholas A. Bellinger
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
2013-03-08 1:45 ` [RFC 08/11] iser-target: Add base + proto includes Nicholas A. Bellinger
` (4 subsequent siblings)
10 siblings, 0 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab@linux-iscsi.org>
This patch adds a new network portal attribute for iser, that lives
under existing iscsi-target configfs layout at:
/sys/kernel/config/target/iscsi/$TARGETNAME/$TPGT/np/$PORTAL/iser
When lio_target_np_store_iser() is enabled, iscsit_tpg_add_network_portal()
will attempt to start an rdma_cma network portal for iser-target, only if
the external ib_isert module transport has been loaded.
When disabled, iscsit_tpg_del_network_portal() will cease iser login service
on the network portal, and release any external ib_isert module reference.
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/target/iscsi/iscsi_target_configfs.c | 75 ++++++++++++++++++++++++++
1 files changed, 75 insertions(+), 0 deletions(-)
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 78d75c8..c4625dd 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -124,8 +124,83 @@ out:
TF_NP_BASE_ATTR(lio_target, sctp, S_IRUGO | S_IWUSR);
+static ssize_t lio_target_np_show_iser(
+ struct se_tpg_np *se_tpg_np,
+ char *page)
+{
+ struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
+ struct iscsi_tpg_np, se_tpg_np);
+ struct iscsi_tpg_np *tpg_np_iser;
+ ssize_t rb;
+
+ tpg_np_iser = iscsit_tpg_locate_child_np(tpg_np, ISCSI_INFINIBAND);
+ if (tpg_np_iser)
+ rb = sprintf(page, "1\n");
+ else
+ rb = sprintf(page, "0\n");
+
+ return rb;
+}
+
+static ssize_t lio_target_np_store_iser(
+ struct se_tpg_np *se_tpg_np,
+ const char *page,
+ size_t count)
+{
+ struct iscsi_np *np;
+ struct iscsi_portal_group *tpg;
+ struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
+ struct iscsi_tpg_np, se_tpg_np);
+ struct iscsi_tpg_np *tpg_np_iser = NULL;
+ char *endptr;
+ u32 op;
+ int rc;
+
+ op = simple_strtoul(page, &endptr, 0);
+ if ((op != 1) && (op != 0)) {
+ pr_err("Illegal value for tpg_enable: %u\n", op);
+ return -EINVAL;
+ }
+ np = tpg_np->tpg_np;
+ if (!np) {
+ pr_err("Unable to locate struct iscsi_np from"
+ " struct iscsi_tpg_np\n");
+ return -EINVAL;
+ }
+
+ tpg = tpg_np->tpg;
+ if (iscsit_get_tpg(tpg) < 0)
+ return -EINVAL;
+
+ if (op) {
+ tpg_np_iser = iscsit_tpg_add_network_portal(tpg, &np->np_sockaddr,
+ np->np_ip, tpg_np, ISCSI_INFINIBAND);
+ if (!tpg_np_iser || IS_ERR(tpg_np_iser))
+ goto out;
+ } else {
+ tpg_np_iser = iscsit_tpg_locate_child_np(tpg_np, ISCSI_INFINIBAND);
+ if (!tpg_np_iser)
+ goto out;
+
+ rc = iscsit_tpg_del_network_portal(tpg, tpg_np_iser);
+ if (rc < 0)
+ goto out;
+ }
+
+ printk("lio_target_np_store_iser() done, op: %d\n", op);
+
+ iscsit_put_tpg(tpg);
+ return count;
+out:
+ iscsit_put_tpg(tpg);
+ return -EINVAL;
+}
+
+TF_NP_BASE_ATTR(lio_target, iser, S_IRUGO | S_IWUSR);
+
static struct configfs_attribute *lio_target_portal_attrs[] = {
&lio_target_np_sctp.attr,
+ &lio_target_np_iser.attr,
NULL,
};
--
1.7.2.5
^ permalink raw reply related [flat|nested] 35+ messages in thread* [RFC 08/11] iser-target: Add base + proto includes
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
` (5 preceding siblings ...)
2013-03-08 1:45 ` [RFC 07/11] iscsi-target: Add iser network portal attribute Nicholas A. Bellinger
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
2013-03-14 11:26 ` Or Gerlitz
2013-03-08 1:45 ` [RFC 09/11] iser-target: Add logic for verbs Nicholas A. Bellinger
` (3 subsequent siblings)
10 siblings, 1 reply; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/infiniband/ulp/isert/isert_base.h | 123 ++++++++++++++++++++++++++++
drivers/infiniband/ulp/isert/isert_proto.h | 47 +++++++++++
2 files changed, 170 insertions(+), 0 deletions(-)
create mode 100644 drivers/infiniband/ulp/isert/isert_base.h
create mode 100644 drivers/infiniband/ulp/isert/isert_proto.h
diff --git a/drivers/infiniband/ulp/isert/isert_base.h b/drivers/infiniband/ulp/isert/isert_base.h
new file mode 100644
index 0000000..a7c8bc9
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/isert_base.h
@@ -0,0 +1,123 @@
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_fmr_pool.h>
+#include <rdma/rdma_cm.h>
+
+#define ISERT_RDMA_LISTEN_BACKLOG 10
+
+enum isert_desc_type {
+ ISCSI_TX_CONTROL,
+ ISCSI_TX_DATAIN
+};
+
+enum iser_ib_op_code {
+ ISER_IB_RECV,
+ ISER_IB_SEND,
+ ISER_IB_RDMA_WRITE,
+ ISER_IB_RDMA_READ,
+};
+
+enum iser_conn_state {
+ ISER_CONN_INIT,
+ ISER_CONN_UP,
+ ISER_CONN_TERMINATING,
+ ISER_CONN_DOWN,
+};
+
+struct iser_rx_desc {
+ struct iser_hdr iser_header;
+ struct iscsi_hdr iscsi_header;
+ char data[ISER_RECV_DATA_SEG_LEN];
+ u64 dma_addr;
+ struct ib_sge rx_sg;
+ char pad[ISER_RX_PAD_SIZE];
+} __attribute__((packed));
+
+struct isert_rx_desc {
+ struct isert_conn *desc_conn;
+ struct work_struct desc_work;
+ struct iser_rx_desc desc;
+} __attribute__((packed));
+
+struct iser_tx_desc {
+ struct iser_hdr iser_header;
+ struct iscsi_hdr iscsi_header;
+ enum isert_desc_type type;
+ u64 dma_addr;
+ struct ib_sge tx_sg[2];
+ int num_sge;
+ struct isert_cmd *isert_cmd;
+ struct ib_send_wr send_wr;
+} __attribute__((packed));
+
+struct isert_rdma_wr {
+ struct list_head wr_list;
+ struct isert_cmd *isert_cmd;
+ enum iser_ib_op_code iser_ib_op;
+ struct ib_sge *ib_sge;
+ int num_sge;
+ struct scatterlist *sge;
+ int send_wr_num;
+ struct ib_send_wr *send_wr;
+};
+
+struct isert_cmd {
+ uint32_t read_stag;
+ uint32_t write_stag;
+ uint64_t read_va;
+ uint64_t write_va;
+ u64 sense_buf_dma;
+ u32 sense_buf_len;
+ u32 read_va_off;
+ u32 write_va_off;
+ u32 rdma_wr_num;
+ struct isert_conn *conn;
+ struct iscsi_cmd iscsi_cmd;
+ struct ib_sge *ib_sge;
+ struct iser_tx_desc tx_desc;
+ struct isert_rdma_wr rdma_wr;
+ struct work_struct comp_work;
+ struct kref cmd_kref;
+};
+
+struct isert_conn {
+ enum iser_conn_state state;
+ int post_recv_buf_count;
+ atomic_t post_send_buf_count;
+ u32 responder_resources;
+ u32 initiator_depth;
+ u32 max_sge;
+ char *login_buf;
+ char *login_req_buf;
+ char *login_rsp_buf;
+ u64 login_req_dma;
+ u64 login_rsp_dma;
+ unsigned int conn_rx_desc_head;
+ struct isert_rx_desc *conn_rx_descs;
+ struct ib_recv_wr conn_rx_wr[ISERT_MIN_POSTED_RX];
+ struct iscsi_conn *conn;
+ struct list_head conn_accept_node;
+ struct completion conn_login_comp;
+ struct iser_tx_desc conn_login_tx_desc;
+ struct rdma_cm_id *conn_cm_id;
+ struct ib_pd *conn_pd;
+ struct ib_cq *conn_rx_cq;
+ struct ib_cq *conn_tx_cq;
+ struct ib_mr *conn_mr;
+ struct ib_qp *conn_qp;
+ struct tasklet_struct conn_rx_tasklet;
+ struct tasklet_struct conn_tx_tasklet;
+ struct work_struct conn_logout_work;
+ wait_queue_head_t conn_wait;
+ struct kref conn_kref;
+};
+
+struct isert_np {
+ wait_queue_head_t np_accept_wq;
+ struct rdma_cm_id *np_cm_id;
+ struct mutex np_accept_mutex;
+ struct list_head np_accept_list;
+ struct completion np_login_comp;
+};
diff --git a/drivers/infiniband/ulp/isert/isert_proto.h b/drivers/infiniband/ulp/isert/isert_proto.h
new file mode 100644
index 0000000..ae38b92
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/isert_proto.h
@@ -0,0 +1,47 @@
+/* From iscsi_iser.h */
+
+struct iser_hdr {
+ u8 flags;
+ u8 rsvd[3];
+ __be32 write_stag; /* write rkey */
+ __be64 write_va;
+ __be32 read_stag; /* read rkey */
+ __be64 read_va;
+} __attribute__((packed));
+
+/*Constant PDU lengths calculations */
+#define ISER_HEADERS_LEN (sizeof(struct iser_hdr) + sizeof(struct iscsi_hdr))
+
+#define ISER_RECV_DATA_SEG_LEN 8192
+#define ISER_RX_PAYLOAD_SIZE (ISER_HEADERS_LEN + ISER_RECV_DATA_SEG_LEN)
+#define ISER_RX_LOGIN_SIZE (ISER_HEADERS_LEN + ISCSI_DEF_MAX_RECV_SEG_LEN)
+
+/* QP settings */
+/* Maximal bounds on received asynchronous PDUs */
+#define ISERT_MAX_TX_MISC_PDUS 4 /* NOOP_IN(2) , ASYNC_EVENT(2) */
+
+#define ISERT_MAX_RX_MISC_PDUS 6 /* NOOP_OUT(2), TEXT(1), *
+ * SCSI_TMFUNC(2), LOGOUT(1) */
+
+#define ISCSI_DEF_XMIT_CMDS_MAX 128 /* from libiscsi.h, must be power of 2 */
+
+#define ISERT_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX)
+
+#define ISERT_MIN_POSTED_RX (ISCSI_DEF_XMIT_CMDS_MAX >> 2)
+
+#define ISERT_INFLIGHT_DATAOUTS 8
+
+#define ISERT_QP_MAX_REQ_DTOS (ISCSI_DEF_XMIT_CMDS_MAX * \
+ (1 + ISERT_INFLIGHT_DATAOUTS) + \
+ ISERT_MAX_TX_MISC_PDUS + \
+ ISERT_MAX_RX_MISC_PDUS)
+
+#define ISER_RX_PAD_SIZE (16384 - (ISER_RX_PAYLOAD_SIZE + \
+ sizeof(u64) + sizeof(struct ib_sge)))
+
+#define ISER_VER 0x10
+#define ISER_WSV 0x08
+#define ISER_RSV 0x04
+#define ISCSI_CTRL 0x10
+#define ISER_HELLO 0x20
+#define ISER_HELLORPLY 0x30
--
1.7.2.5
^ permalink raw reply related [flat|nested] 35+ messages in thread* [RFC 09/11] iser-target: Add logic for verbs
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
` (6 preceding siblings ...)
2013-03-08 1:45 ` [RFC 08/11] iser-target: Add base + proto includes Nicholas A. Bellinger
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
2013-03-14 11:19 ` Or Gerlitz
[not found] ` <1362707116-31406-10-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
2013-03-08 1:45 ` [RFC 10/11] iser-target: Add logic for core Nicholas A. Bellinger
` (2 subsequent siblings)
10 siblings, 2 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/infiniband/ulp/isert/isert_verbs.c | 476 ++++++++++++++++++++++++++++
drivers/infiniband/ulp/isert/isert_verbs.h | 5 +
2 files changed, 481 insertions(+), 0 deletions(-)
create mode 100644 drivers/infiniband/ulp/isert/isert_verbs.c
create mode 100644 drivers/infiniband/ulp/isert/isert_verbs.h
diff --git a/drivers/infiniband/ulp/isert/isert_verbs.c b/drivers/infiniband/ulp/isert/isert_verbs.c
new file mode 100644
index 0000000..2b44eb8
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/isert_verbs.c
@@ -0,0 +1,476 @@
+/*******************************************************************************
+ * This file contains iSCSI extentions for RDMA (iSER) Verbs
+ *
+ * (c) Copyright 2013 RisingTide Systems LLC.
+ *
+ * Nicholas A. Bellinger <nab@linux-iscsi.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ ****************************************************************************/
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_fmr_pool.h>
+#include <rdma/rdma_cm.h>
+#include <target/iscsi/iscsi_transport.h>
+
+#include "isert_proto.h"
+#include "isert_base.h"
+#include "isert_core.h"
+
+#define ISERT_ADDR_ROUTE_TIMEOUT 1000
+
+#define ISERT_MAX_CONN 8
+#define ISER_MAX_RX_CQ_LEN (ISERT_QP_MAX_RECV_DTOS * ISERT_MAX_CONN)
+#define ISER_MAX_TX_CQ_LEN (ISERT_QP_MAX_REQ_DTOS * ISERT_MAX_CONN)
+
+static void
+isert_qp_event_callback(struct ib_event *e, void *context)
+{
+ pr_err("isert_qp_event_callback event: %d\n", e->event);
+}
+
+static int
+isert_query_device(struct ib_device *ib_dev, struct ib_device_attr *devattr)
+{
+ int ret;
+
+ ret = ib_query_device(ib_dev, devattr);
+ if (ret) {
+ pr_err("ib_query_device() failed: %d\n", ret);
+ return ret;
+ }
+ pr_debug("devattr->max_mr_size: 0x%016Lx\n", devattr->max_mr_size);
+ pr_debug("devattr->page_size_cap: 0x%016Lx\n", devattr->page_size_cap);
+ pr_debug("devattr->max_qp: %d\n", devattr->max_qp);
+ pr_debug("devattr->max_qp_wr: %d\n", devattr->max_qp_wr);
+ pr_debug("devattr->device_cap_flags: 0x%08x\n", devattr->device_cap_flags);
+ pr_debug("devattr->max_sge: %d\n", devattr->max_sge);
+ pr_debug("devattr->max_sge_rd: %d\n", devattr->max_sge_rd);
+ pr_debug("devattr->max_cq: %d\n", devattr->max_cq);
+ pr_debug("devattr->max_cqe: %d\n", devattr->max_cqe);
+ pr_debug("devattr->max_mr: %d\n", devattr->max_mr);
+ pr_debug("devattr->max_pd: %d\n", devattr->max_pd);
+ pr_debug("devattr->max_rdd: %d\n", devattr->max_rdd);
+ pr_debug("devattr->max_mw: %d\n", devattr->max_mw);
+ pr_debug("devattr->max_srq: %d\n", devattr->max_srq);
+ pr_debug("devattr->max_srq_wr: %d\n", devattr->max_srq_wr);
+ pr_debug("devattr->max_srq_sge: %d\n", devattr->max_srq_sge);
+
+ return 0;
+}
+
+static int
+isert_conn_setup_qp(struct isert_conn *isert_conn, struct rdma_cm_id *cma_id)
+{
+ struct ib_qp_init_attr attr;
+ struct ib_device_attr devattr;
+ int ret;
+
+ memset(&devattr, 0, sizeof(struct ib_device_attr));
+ ret = isert_query_device(cma_id->device, &devattr);
+
+ memset(&attr, 0, sizeof(struct ib_qp_init_attr));
+ attr.event_handler = isert_qp_event_callback;
+ attr.qp_context = isert_conn;
+ attr.send_cq = isert_conn->conn_tx_cq;
+ attr.recv_cq = isert_conn->conn_rx_cq;
+ attr.cap.max_send_wr = ISERT_QP_MAX_REQ_DTOS;
+ attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS;
+#warning FIXME: max_sge hardcoded to 16
+#if 0
+ attr.cap.max_send_sge = devattr.max_sge;
+ isert_conn->max_sge = devattr.max_sge;
+#else
+ attr.cap.max_send_sge = 16;
+ isert_conn->max_sge = 16;
+#endif
+ attr.cap.max_recv_sge = 1;
+ attr.sq_sig_type = IB_SIGNAL_REQ_WR;
+ attr.qp_type = IB_QPT_RC;
+
+ pr_debug("isert_conn_setup_qp cma_id->device: %p\n", cma_id->device);
+ pr_debug("isert_conn_setup_qp conn_pd->device: %p\n", isert_conn->conn_pd->device);
+
+ ret = rdma_create_qp(cma_id, isert_conn->conn_pd, &attr);
+ if (ret) {
+ pr_err("rdma_create_qp failed for cma_id %d\n", ret);
+ return ret;
+ }
+ isert_conn->conn_qp = cma_id->qp;
+ pr_debug("rdma_create_qp() returned success >>>>>>>>>>>>>>>>>>>>>>>>>.\n");
+
+ return 0;
+}
+
+static void
+isert_cq_event_callback(struct ib_event *e, void *context)
+{
+ pr_debug("isert_cq_event_callback event: %d\n", e->event);
+
+ switch(e->event) {
+ case IB_EVENT_QP_LAST_WQE_REACHED:
+ pr_warn("Reached TX IB_EVENT_QP_LAST_WQE_REACHED:\n");
+ break;
+ default:
+ pr_warn("Unknown e->event; %d\n", e->event);
+ break;
+ }
+}
+
+static int
+isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
+{
+ struct iscsi_np *np = cma_id->context;
+ struct isert_np *isert_np = np->np_context;
+ struct isert_conn *isert_conn;
+ struct ib_device *ib_dev = cma_id->device;
+ int ret;
+
+ pr_debug("Entering isert_connect_request cma_id: %p, context: %p\n",
+ cma_id, cma_id->context);
+
+ isert_conn = kzalloc(sizeof(struct isert_conn), GFP_KERNEL);
+ if (!isert_conn) {
+ pr_err("Unable to allocate isert_conn\n");
+ return -ENOMEM;
+ }
+ isert_conn->state = ISER_CONN_INIT;
+ INIT_LIST_HEAD(&isert_conn->conn_accept_node);
+ init_completion(&isert_conn->conn_login_comp);
+ init_waitqueue_head(&isert_conn->conn_wait);
+ kref_init(&isert_conn->conn_kref);
+ kref_get(&isert_conn->conn_kref);
+
+ cma_id->context = isert_conn;
+ pr_debug("isert_connect_request: Setup new cma_id->context: %p\n", cma_id->context);
+ isert_conn->conn_cm_id = cma_id;
+ isert_conn->responder_resources = event->param.conn.responder_resources;
+ isert_conn->initiator_depth = event->param.conn.initiator_depth;
+ pr_debug("Using responder_resources: %u initiator_depth: %u\n",
+ isert_conn->responder_resources, isert_conn->initiator_depth);
+
+ isert_conn->login_buf = kzalloc(ISCSI_DEF_MAX_RECV_SEG_LEN +
+ ISER_RX_LOGIN_SIZE, GFP_KERNEL);
+ if (!isert_conn->login_buf) {
+ pr_err("Unable to allocate isert_conn->login_buf\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ isert_conn->login_req_buf = isert_conn->login_buf;
+ isert_conn->login_rsp_buf = isert_conn->login_buf + ISCSI_DEF_MAX_RECV_SEG_LEN;
+ pr_debug("Set login_buf: %p login_req_buf: %p login_rsp_buf: %p\n",
+ isert_conn->login_buf, isert_conn->login_req_buf,
+ isert_conn->login_rsp_buf);
+
+ isert_conn->login_req_dma = ib_dma_map_single(ib_dev,
+ (void *)isert_conn->login_req_buf,
+ ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_FROM_DEVICE);
+
+ ret = ib_dma_mapping_error(ib_dev, isert_conn->login_req_dma);
+ if (ret) {
+ pr_err("ib_dma_mapping_error failed for login_req_dma: %d\n", ret);
+ isert_conn->login_req_dma = 0;
+ goto out_login_buf;
+ }
+
+ isert_conn->login_rsp_dma = ib_dma_map_single(ib_dev,
+ (void *)isert_conn->login_rsp_buf,
+ ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE);
+
+ ret = ib_dma_mapping_error(ib_dev, isert_conn->login_rsp_dma);
+ if (ret) {
+ pr_err("ib_dma_mapping_error failed for login_rsp_dma: %d\n", ret);
+ isert_conn->login_rsp_dma = 0;
+ goto out_req_dma_map;
+ }
+
+ isert_conn->conn_pd = ib_alloc_pd(ib_dev);
+ if (IS_ERR(isert_conn->conn_pd)) {
+ ret = PTR_ERR(isert_conn->conn_pd);
+ pr_err("ib_alloc_pd failed for conn_pd: %d\n", ret);
+ goto out_rsp_dma_map;
+ }
+
+ isert_conn->conn_rx_cq = ib_create_cq(ib_dev, isert_cq_rx_callback,
+ isert_cq_event_callback,
+ (void *)isert_conn,
+ ISER_MAX_RX_CQ_LEN, 0);
+ if (IS_ERR(isert_conn->conn_rx_cq)) {
+ ret = PTR_ERR(isert_conn->conn_rx_cq);
+ pr_err("ib_create_cq failed for conn_rx_cq: %d\n", ret);
+ goto out_alloc_pd;
+ }
+
+ isert_conn->conn_tx_cq = ib_create_cq(ib_dev, isert_cq_tx_callback,
+ isert_cq_event_callback,
+ (void *)isert_conn,
+ ISER_MAX_TX_CQ_LEN, 0);
+ if (IS_ERR(isert_conn->conn_tx_cq)) {
+ ret = PTR_ERR(isert_conn->conn_tx_cq);
+ pr_err("ib_create_cq failed for conn_tx_cq: %d\n", ret);
+ goto out_rx_cq;
+ }
+
+ ret = ib_req_notify_cq(isert_conn->conn_rx_cq, IB_CQ_NEXT_COMP);
+ if (ret) {
+ pr_err("ib_req_notify_cq failed for conn_rx_cq: %d\n", ret);
+ goto out_tx_cq;
+ }
+ ret = ib_req_notify_cq(isert_conn->conn_tx_cq, IB_CQ_NEXT_COMP);
+ if (ret) {
+ pr_err("ib_req_notify_cq failed for conn_tx_cq: %d\n", ret);
+ goto out_tx_cq;
+ }
+
+ tasklet_init(&isert_conn->conn_rx_tasklet, iser_cq_rx_tasklet,
+ (unsigned long)isert_conn);
+ tasklet_init(&isert_conn->conn_tx_tasklet, iser_cq_tx_tasklet,
+ (unsigned long)isert_conn);
+
+ isert_conn->conn_mr = ib_get_dma_mr(isert_conn->conn_pd,
+ IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE |
+ IB_ACCESS_REMOTE_READ);
+ if (IS_ERR(isert_conn->conn_mr)) {
+ ret = PTR_ERR(isert_conn->conn_mr);
+ pr_err("ib_get_dma_mr failed for conn->conn_mr: %d\n", ret);
+ goto out_tx_cq;
+ }
+
+ ret = isert_conn_setup_qp(isert_conn, cma_id);
+ if (ret)
+ goto out_conn_mr;
+
+ mutex_lock(&isert_np->np_accept_mutex);
+ list_add_tail(&isert_np->np_accept_list, &isert_conn->conn_accept_node);
+ mutex_unlock(&isert_np->np_accept_mutex);
+
+ pr_debug("isert_connect_request() waking up np_accept_wq: np: %p\n", np);
+ wake_up(&isert_np->np_accept_wq);
+ return 0;
+
+out_conn_mr:
+ ib_dereg_mr(isert_conn->conn_mr);
+ tasklet_kill(&isert_conn->conn_rx_tasklet);
+ tasklet_kill(&isert_conn->conn_tx_tasklet);
+out_tx_cq:
+ ib_destroy_cq(isert_conn->conn_tx_cq);
+out_rx_cq:
+ ib_destroy_cq(isert_conn->conn_rx_cq);
+out_alloc_pd:
+ ib_dealloc_pd(isert_conn->conn_pd);
+out_rsp_dma_map:
+ ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma,
+ ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE);
+out_req_dma_map:
+ ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
+ ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_FROM_DEVICE);
+out_login_buf:
+ kfree(isert_conn->login_buf);
+out:
+ kfree(isert_conn);
+ return ret;
+}
+
+static void
+isert_connect_release(struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+
+ pr_debug("Entering isert_connect_release(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+
+ if (isert_conn->conn_qp)
+ rdma_destroy_qp(isert_conn->conn_cm_id);
+
+ isert_free_rx_descriptors(isert_conn);
+
+ tasklet_kill(&isert_conn->conn_rx_tasklet);
+ tasklet_kill(&isert_conn->conn_tx_tasklet);
+
+ ib_dereg_mr(isert_conn->conn_mr);
+ ib_destroy_cq(isert_conn->conn_tx_cq);
+ ib_destroy_cq(isert_conn->conn_rx_cq);
+ ib_dealloc_pd(isert_conn->conn_pd);
+
+ if (isert_conn->conn_cm_id != NULL)
+ rdma_destroy_id(isert_conn->conn_cm_id);
+
+ if (isert_conn->login_buf) {
+ ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma,
+ ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE);
+ ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
+ ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_FROM_DEVICE);
+ kfree(isert_conn->login_buf);
+ }
+ kfree(isert_conn);
+
+ pr_debug("Leaving isert_connect_release >>>>>>>>>>>>\n");
+}
+
+static void
+isert_connected_handler(struct rdma_cm_id *cma_id)
+{
+ return;
+}
+
+static void
+isert_release_conn_kref(struct kref *kref)
+{
+ struct isert_conn *isert_conn = container_of(kref,
+ struct isert_conn, conn_kref);
+
+ pr_debug("Calling isert_connect_release for final kref %s/%d\n",
+ current->comm, current->pid);
+
+ isert_connect_release(isert_conn);
+}
+
+void
+isert_put_conn(struct isert_conn *isert_conn)
+{
+ kref_put(&isert_conn->conn_kref, isert_release_conn_kref);
+}
+
+static void
+isert_disconnect_work(struct work_struct *work)
+{
+ struct isert_conn *isert_conn = container_of(work,
+ struct isert_conn, conn_logout_work);
+
+ pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+
+ if (isert_conn->post_recv_buf_count == 0 &&
+ atomic_read(&isert_conn->post_send_buf_count) == 0) {
+
+ pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
+ isert_conn->state = ISER_CONN_DOWN;
+ wake_up(&isert_conn->conn_wait);
+ }
+
+ isert_put_conn(isert_conn);
+}
+
+static void
+isert_disconnected_handler(struct rdma_cm_id *cma_id)
+{
+ struct isert_conn *isert_conn = (struct isert_conn *)cma_id->context;
+
+ INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work);
+ schedule_work(&isert_conn->conn_logout_work);
+}
+
+int
+isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
+{
+ int ret = 0;
+
+ pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n",
+ event->event, event->status, cma_id->context, cma_id);
+
+ switch (event->event) {
+ case RDMA_CM_EVENT_CONNECT_REQUEST:
+ pr_debug("RDMA_CM_EVENT_CONNECT_REQUEST: >>>>>>>>>>>>>>>\n");
+ ret = isert_connect_request(cma_id, event);
+ break;
+ case RDMA_CM_EVENT_ESTABLISHED:
+ pr_debug("RDMA_CM_EVENT_ESTABLISHED >>>>>>>>>>>>>>\n");
+ isert_connected_handler(cma_id);
+ break;
+ case RDMA_CM_EVENT_DISCONNECTED:
+ pr_debug("RDMA_CM_EVENT_DISCONNECTED: >>>>>>>>>>>>>>\n");
+ isert_disconnected_handler(cma_id);
+ break;
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ case RDMA_CM_EVENT_ADDR_CHANGE:
+ break;
+ case RDMA_CM_EVENT_ADDR_ERROR:
+ case RDMA_CM_EVENT_ROUTE_ERROR:
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ default:
+ pr_err("Unknown RDMA CMA event: %d\n", event->event);
+ break;
+ }
+
+ if (ret != 0) {
+ pr_err("isert_cma_handler failed RDMA_CM_EVENT: 0x%08x,"
+ " ret: %d\n", event->event, ret);
+ dump_stack();
+ }
+
+ return ret;
+}
+
+int
+isert_post_recv(struct isert_conn *isert_conn, u32 count)
+{
+ struct ib_recv_wr *rx_wr, *rx_wr_failed;
+ int i, ret;
+ unsigned int rx_head = isert_conn->conn_rx_desc_head;
+ struct isert_rx_desc *rx_desc;
+ struct iser_rx_desc *desc;
+
+ for (rx_wr = isert_conn->conn_rx_wr, i = 0; i < count; i++, rx_wr++) {
+ rx_desc = &isert_conn->conn_rx_descs[rx_head];
+ desc = &rx_desc->desc;
+ rx_wr->wr_id = (unsigned long)desc;
+ rx_wr->sg_list = &desc->rx_sg;
+ rx_wr->num_sge = 1;
+ rx_wr->next = rx_wr + 1;
+ rx_head = (rx_head + 1) & (ISERT_QP_MAX_RECV_DTOS - 1);
+ }
+
+ rx_wr--;
+ rx_wr->next = NULL; /* mark end of work requests list */
+
+ isert_conn->post_recv_buf_count += count;
+ ret = ib_post_recv(isert_conn->conn_qp, isert_conn->conn_rx_wr,
+ &rx_wr_failed);
+ if (ret) {
+ pr_err("ib_post_recv() failed with ret: %d\n", ret);
+ isert_conn->post_recv_buf_count -= count;
+ } else {
+ pr_debug("isert_post_recv(): Posted %d RX buffers\n", count);
+ isert_conn->conn_rx_desc_head = rx_head;
+ }
+ return ret;
+}
+
+int
+isert_post_send(struct isert_conn *isert_conn, struct iser_tx_desc *tx_desc)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_send_wr send_wr, *send_wr_failed;
+ int ret;
+
+ ib_dma_sync_single_for_device(ib_dev, tx_desc->dma_addr,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
+
+ send_wr.next = NULL;
+ send_wr.wr_id = (unsigned long)tx_desc;
+ send_wr.sg_list = tx_desc->tx_sg;
+ send_wr.num_sge = tx_desc->num_sge;
+ send_wr.opcode = IB_WR_SEND;
+ send_wr.send_flags = IB_SEND_SIGNALED;
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ ret = ib_post_send(isert_conn->conn_qp, &send_wr, &send_wr_failed);
+ if (ret) {
+ pr_err("ib_post_send() failed, ret: %d\n", ret);
+ atomic_dec(&isert_conn->post_send_buf_count);
+ }
+
+ return ret;
+}
diff --git a/drivers/infiniband/ulp/isert/isert_verbs.h b/drivers/infiniband/ulp/isert/isert_verbs.h
new file mode 100644
index 0000000..da7924d
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/isert_verbs.h
@@ -0,0 +1,5 @@
+extern void isert_connect_release(struct isert_conn *);
+extern void isert_put_conn(struct isert_conn *);
+extern int isert_cma_handler(struct rdma_cm_id *, struct rdma_cm_event *);
+extern int isert_post_recv(struct isert_conn *, u32);
+extern int isert_post_send(struct isert_conn *, struct iser_tx_desc *);
--
1.7.2.5
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [RFC 09/11] iser-target: Add logic for verbs
2013-03-08 1:45 ` [RFC 09/11] iser-target: Add logic for verbs Nicholas A. Bellinger
@ 2013-03-14 11:19 ` Or Gerlitz
[not found] ` <1362707116-31406-10-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
1 sibling, 0 replies; 35+ messages in thread
From: Or Gerlitz @ 2013-03-14 11:19 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier,
Alexander Nezhinsky
On 08/03/2013 03:45, Nicholas A. Bellinger wrote:
> +++ b/drivers/infiniband/ulp/isert/isert_verbs.c
> +#define ISERT_ADDR_ROUTE_TIMEOUT 1000
remove this define, its irrelevant and you don't use that anywhere
> +static void
> +isert_qp_event_callback(struct ib_event *e, void *context)
> +{
> + pr_err("isert_qp_event_callback event: %d\n", e->event);
> +}
To be on the safe side, when the event is IB_EVENT_COMM_EST (which means
that the login request was received by the HCA before the connection was
fully established), call rdma_notify (id, IB_EVENT_COMM_EST) with the id
being the one pointed from qp->qp_context->isert_conn
> +
> +static int
> +isert_query_device(struct ib_device *ib_dev, struct ib_device_attr *devattr)
> +{
> + int ret;
> +
> + ret = ib_query_device(ib_dev, devattr);
> + if (ret) {
> + pr_err("ib_query_device() failed: %d\n", ret);
> + return ret;
> + }
> + pr_debug("devattr->max_mr_size: 0x%016Lx\n", devattr->max_mr_size);
running user space "ibv_devinfo -v" will give the same effect... no need
to dump this here, maybe
except for max_sge that you need.
> + pr_debug("devattr->page_size_cap: 0x%016Lx\n", devattr->page_size_cap);
> + pr_debug("devattr->max_qp: %d\n", devattr->max_qp);
> + pr_debug("devattr->max_qp_wr: %d\n", devattr->max_qp_wr);
> + pr_debug("devattr->device_cap_flags: 0x%08x\n", devattr->device_cap_flags);
> + pr_debug("devattr->max_sge: %d\n", devattr->max_sge);
> + pr_debug("devattr->max_sge_rd: %d\n", devattr->max_sge_rd);
> + pr_debug("devattr->max_cq: %d\n", devattr->max_cq);
> + pr_debug("devattr->max_cqe: %d\n", devattr->max_cqe);
> + pr_debug("devattr->max_mr: %d\n", devattr->max_mr);
> + pr_debug("devattr->max_pd: %d\n", devattr->max_pd);
> + pr_debug("devattr->max_rdd: %d\n", devattr->max_rdd);
> + pr_debug("devattr->max_mw: %d\n", devattr->max_mw);
> + pr_debug("devattr->max_srq: %d\n", devattr->max_srq);
> + pr_debug("devattr->max_srq_wr: %d\n", devattr->max_srq_wr);
> + pr_debug("devattr->max_srq_sge: %d\n", devattr->max_srq_sge);
> +
> + return 0;
> +}
[...]
> +
> +
> +int
> +isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
> +{
> + int ret = 0;
> +
> + pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n",
> + event->event, event->status, cma_id->context, cma_id);
> +
> + switch (event->event) {
> + case RDMA_CM_EVENT_CONNECT_REQUEST:
> + pr_debug("RDMA_CM_EVENT_CONNECT_REQUEST: >>>>>>>>>>>>>>>\n");
> + ret = isert_connect_request(cma_id, event);
> + break;
> + case RDMA_CM_EVENT_ESTABLISHED:
> + pr_debug("RDMA_CM_EVENT_ESTABLISHED >>>>>>>>>>>>>>\n");
> + isert_connected_handler(cma_id);
> + break;
> + case RDMA_CM_EVENT_DISCONNECTED:
> + pr_debug("RDMA_CM_EVENT_DISCONNECTED: >>>>>>>>>>>>>>\n");
> + isert_disconnected_handler(cma_id);
> + break;
> + case RDMA_CM_EVENT_DEVICE_REMOVAL:
> + case RDMA_CM_EVENT_ADDR_CHANGE:
> + break;
> + case RDMA_CM_EVENT_ADDR_ERROR:
> + case RDMA_CM_EVENT_ROUTE_ERROR:
> + case RDMA_CM_EVENT_CONNECT_ERROR:
> + default:
> + pr_err("Unknown RDMA CMA event: %d\n", event->event);
> + break;
> + }
> +
ADDR_ERROR and ROUTE_ERROR you can remove from here, since you don't
call rdma_resolve_addr nor rdma_resolve_route, they
will not be delivered to you.
^ permalink raw reply [flat|nested] 35+ messages in thread[parent not found: <1362707116-31406-10-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>]
* Re: [RFC 09/11] iser-target: Add logic for verbs
[not found] ` <1362707116-31406-10-git-send-email-nab-IzHhD5pYlfBP7FQvKIMDCQ@public.gmane.org>
@ 2013-03-14 11:42 ` Or Gerlitz
0 siblings, 0 replies; 35+ messages in thread
From: Or Gerlitz @ 2013-03-14 11:42 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier,
Alexander Nezhinsky
On 08/03/2013 03:45, Nicholas A. Bellinger wrote:
> isert_conn->conn_rx_cq = ib_create_cq(ib_dev, isert_cq_rx_callback,
> + isert_cq_event_callback,
> + (void *)isert_conn,
> + ISER_MAX_RX_CQ_LEN, 0);
[...]
> +
> + isert_conn->conn_tx_cq = ib_create_cq(ib_dev, isert_cq_tx_callback,
> + isert_cq_event_callback,
> + (void *)isert_conn,
> + ISER_MAX_TX_CQ_LEN, 0);
Two comments here:
1. This code always attaches the CQ to vector #0 of the IB device.
Typically vectors are associated with IRQs and IRQs are
"affiniated" with cores, so processing of completions for all
connections will be carried out on single core at a given time.
What can be done here is to use different vectors for different CQs. The
possible vector values are from 0 to ib_dev->num_comp_vectors - 1
2. A dedicated CQ pair is used per connection which might not scale well.
What can be done here, is to use a global context per IB device which
holds a pool of CQs (created on different vectors, per the previous item),
and for each new connection, attach its QP to a CQ pair from this pool,
e.g as done in drivers/infiniband/ulp/iser/iser_verbs.c ::
iser_create_device_ib_res()
note that FWIW this context can hold also a global PD and DMA_MR objects
to be used by all the connections opened on the device. The context can
be opened on demand (1st connection that hits this IB device) and closed
on non-demand (last connection).
Or.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 35+ messages in thread
* [RFC 10/11] iser-target: Add logic for core
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
` (7 preceding siblings ...)
2013-03-08 1:45 ` [RFC 09/11] iser-target: Add logic for verbs Nicholas A. Bellinger
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
2013-03-14 11:08 ` Or Gerlitz
2013-03-14 11:58 ` Or Gerlitz
2013-03-08 1:45 ` [RFC 11/11] iser-target: Add Makefile + Kconfig Nicholas A. Bellinger
2013-03-14 8:17 ` [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Or Gerlitz
10 siblings, 2 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/infiniband/ulp/isert/isert_core.c | 1720 +++++++++++++++++++++++++++++
drivers/infiniband/ulp/isert/isert_core.h | 12 +
2 files changed, 1732 insertions(+), 0 deletions(-)
create mode 100644 drivers/infiniband/ulp/isert/isert_core.c
create mode 100644 drivers/infiniband/ulp/isert/isert_core.h
diff --git a/drivers/infiniband/ulp/isert/isert_core.c b/drivers/infiniband/ulp/isert/isert_core.c
new file mode 100644
index 0000000..846911f
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/isert_core.c
@@ -0,0 +1,1720 @@
+/*******************************************************************************
+ * This file contains iSCSI extentions for RDMA (iSER) for iscsi_target_mod
+ *
+ * (c) Copyright 2013 RisingTide Systems LLC.
+ *
+ * Nicholas A. Bellinger <nab@linux-iscsi.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ ****************************************************************************/
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_fmr_pool.h>
+#include <rdma/rdma_cm.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/iscsi/iscsi_transport.h>
+
+#include "isert_proto.h"
+#include "isert_base.h"
+#include "isert_core.h"
+#include "isert_verbs.h"
+
+static struct workqueue_struct *isert_rx_wq;
+static struct workqueue_struct *isert_comp_wq;
+
+static void
+isert_create_send_desc(struct isert_conn *isert_conn,
+ struct isert_cmd *isert_cmd,
+ struct iser_tx_desc *tx_desc)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+
+ ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
+
+ memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr));
+ tx_desc->iser_header.flags = ISER_VER;
+
+ tx_desc->num_sge = 1;
+ tx_desc->isert_cmd = isert_cmd;
+
+ if (tx_desc->tx_sg[0].lkey != isert_conn->conn_mr->lkey) {
+ tx_desc->tx_sg[0].lkey = isert_conn->conn_mr->lkey;
+ pr_debug("tx_desc %p lkey mismatch, fixing\n", tx_desc);
+ }
+}
+
+static int
+isert_init_tx_hdrs(struct isert_conn *isert_conn,
+ struct iser_tx_desc *tx_desc)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ u64 dma_addr;
+
+ dma_addr = ib_dma_map_single(ib_dev, (void *)tx_desc,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(ib_dev, dma_addr)) {
+ pr_err("ib_dma_mapping_error() failed\n");
+ return -ENOMEM;
+ }
+
+ tx_desc->dma_addr = dma_addr;
+ tx_desc->tx_sg[0].addr = tx_desc->dma_addr;
+ tx_desc->tx_sg[0].length = ISER_HEADERS_LEN;
+ tx_desc->tx_sg[0].lkey = isert_conn->conn_mr->lkey;
+
+ pr_debug("isert_init_tx_hdrs: Setup tx_sg[0].addr: 0x%llx length: %u,"
+ " lkey: 0x%08x\n", tx_desc->tx_sg[0].addr,
+ tx_desc->tx_sg[0].length, tx_desc->tx_sg[0].lkey);
+
+ return 0;
+}
+
+static int
+isert_alloc_rx_descriptors(struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct isert_rx_desc *rx_desc;
+ struct iser_rx_desc *desc;
+ struct ib_sge *rx_sg;
+ u64 dma_addr;
+ int i, j;
+
+ isert_conn->conn_rx_descs = kzalloc(ISERT_QP_MAX_RECV_DTOS *
+ sizeof(struct isert_rx_desc), GFP_KERNEL);
+ if (!isert_conn->conn_rx_descs)
+ goto fail;
+
+ rx_desc = isert_conn->conn_rx_descs;
+
+ for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++) {
+ desc = &rx_desc->desc;
+
+ dma_addr = ib_dma_map_single(ib_dev, (void *)desc,
+ ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+ if (ib_dma_mapping_error(ib_dev, dma_addr))
+ goto dma_map_fail;
+
+ desc->dma_addr = dma_addr;
+
+ rx_sg = &desc->rx_sg;
+ rx_sg->addr = desc->dma_addr;
+ rx_sg->length = ISER_RX_PAYLOAD_SIZE;
+ rx_sg->lkey = isert_conn->conn_mr->lkey;
+ }
+
+ isert_conn->conn_rx_desc_head = 0;
+ return 0;
+
+dma_map_fail:
+ rx_desc = isert_conn->conn_rx_descs;
+ for (j = 0; j < i; j++, rx_desc++) {
+ desc = &rx_desc->desc;
+ ib_dma_unmap_single(ib_dev, desc->dma_addr,
+ ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+ }
+ kfree(isert_conn->conn_rx_descs);
+ isert_conn->conn_rx_descs = NULL;
+fail:
+ return -ENOMEM;
+}
+
+void
+isert_free_rx_descriptors(struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct isert_rx_desc *rx_desc;
+ struct iser_rx_desc *desc;
+ int i;
+
+ if (!isert_conn->conn_rx_descs)
+ return;
+
+ rx_desc = isert_conn->conn_rx_descs;
+ for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++) {
+ desc = &rx_desc->desc;
+ ib_dma_unmap_single(ib_dev, desc->dma_addr,
+ ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+ }
+
+ kfree(isert_conn->conn_rx_descs);
+ isert_conn->conn_rx_descs = NULL;
+}
+
+static int isert_rdma_post_recvl(struct isert_conn *);
+
+static int
+isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
+ u32 length)
+{
+ struct isert_conn *isert_conn = conn->context;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct iser_tx_desc *tx_desc = &isert_conn->conn_login_tx_desc;
+ int ret;
+
+ isert_create_send_desc(isert_conn, NULL, tx_desc);
+
+ pr_debug("Copying login->rsp into tx_desc->iscsi_header\n");
+ memcpy(&tx_desc->iscsi_header, &login->rsp[0], sizeof(struct iscsi_hdr));
+
+ isert_init_tx_hdrs(isert_conn, tx_desc);
+
+ if (length > 0) {
+ struct ib_sge *tx_dsg = &tx_desc->tx_sg[1];
+
+ ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_rsp_dma,
+ length, DMA_TO_DEVICE);
+
+ pr_debug("memcpy TX login->rsp_buf to isert_conn->login_rsp_buf,"
+ " length: %u\n", length);
+ memcpy(isert_conn->login_rsp_buf, login->rsp_buf, length);
+
+ ib_dma_sync_single_for_device(ib_dev, isert_conn->login_rsp_dma,
+ length, DMA_TO_DEVICE);
+
+ tx_dsg->addr = isert_conn->login_rsp_dma;
+ tx_dsg->length = length;
+ tx_dsg->lkey = isert_conn->conn_mr->lkey;
+ tx_desc->num_sge = 2;
+ }
+ if (!login->login_failed) {
+ if (login->login_complete) {
+ pr_debug("isert_put_login_tx, detected login_complete=1, calling"
+ " isert_alloc_rx_descriptors >>>>>>>>>>>>>>>\n");
+
+ ret = isert_alloc_rx_descriptors(isert_conn);
+ if (ret)
+ return ret;
+
+ pr_debug("isert_put_login_tx, detected login_complete=1, calling "
+ "isert_post_recv to post ISERT_MIN_POSTED_RX: %d\n",
+ ISERT_MIN_POSTED_RX);
+
+ ret = isert_post_recv(isert_conn, ISERT_MIN_POSTED_RX);
+ if (ret)
+ return ret;
+
+ isert_conn->state = ISER_CONN_UP;
+ goto post_send;
+ }
+
+ ret = isert_rdma_post_recvl(isert_conn);
+ if (ret)
+ return ret;
+ }
+post_send:
+ ret = isert_post_send(isert_conn, tx_desc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void
+isert_rx_login_req(struct isert_rx_desc *rx_desc, int rx_buflen,
+ struct isert_conn *isert_conn)
+{
+ struct iser_rx_desc *desc = &rx_desc->desc;
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_login *login = conn->conn_login;
+ int size;
+
+ if (!login) {
+ pr_err("conn->conn_login is NULL\n");
+ dump_stack();
+ return;
+ }
+
+ if (login->first_request) {
+ struct iscsi_login_req *login_req =
+ (struct iscsi_login_req *)&desc->iscsi_header;
+ /*
+ * Setup the initial iscsi_login values from the leading
+ * login request PDU.
+ */
+ login->leading_connection = (!login_req->tsih) ? 1 : 0;
+ login->current_stage =
+ (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
+ login->version_min = login_req->min_version;
+ login->version_max = login_req->max_version;
+ memcpy(login->isid, login_req->isid, 6);
+ login->cmd_sn = be32_to_cpu(login_req->cmdsn);
+ login->init_task_tag = login_req->itt;
+ login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
+ login->cid = be16_to_cpu(login_req->cid);
+ login->tsih = be16_to_cpu(login_req->tsih);
+ }
+
+ memcpy(&login->req[0], (void *)&desc->iscsi_header, ISCSI_HDR_LEN);
+
+ size = min(rx_buflen, MAX_KEY_VALUE_PAIRS);
+ pr_debug("Using login payload size: %d, rx_buflen: %d MAX_KEY_VALUE_PAIRS: %d\n",
+ size, rx_buflen, MAX_KEY_VALUE_PAIRS);
+ memcpy(login->req_buf, &desc->data[0], size);
+
+ complete(&isert_conn->conn_login_comp);
+}
+
+static struct iscsi_cmd
+*isert_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp)
+{
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct isert_cmd *isert_cmd;
+
+ isert_cmd = kzalloc(sizeof(struct isert_cmd), gfp);
+ if (!isert_cmd) {
+ pr_err("Unable to allocate isert_cmd\n");
+ return NULL;
+ }
+ isert_cmd->conn = isert_conn;
+
+ kref_init(&isert_cmd->cmd_kref);
+ kref_get(&isert_cmd->cmd_kref);
+
+ return &isert_cmd->iscsi_cmd;
+}
+
+static int
+isert_handle_scsi_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
+ struct iser_rx_desc *rx_desc, unsigned char *buf)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)buf;
+ struct scatterlist *sg;
+ int imm_data, imm_data_len, unsol_data, sg_nents, rc;
+ bool dump_payload = false;
+
+ rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
+ if (rc < 0)
+ return rc;
+
+ imm_data = cmd->immediate_data;
+ imm_data_len = cmd->first_burst_len;
+ unsol_data = cmd->unsolicited_data;
+
+ rc = iscsit_process_scsi_cmd(conn, cmd, hdr);
+ if (rc < 0)
+ return 0;
+ else if (rc > 0) {
+ dump_payload = true;
+ goto sequence_cmd;
+ }
+
+ if (!imm_data)
+ return 0;
+
+ sg = &cmd->se_cmd.t_data_sg[0];
+ sg_nents = max(1UL, DIV_ROUND_UP(imm_data_len, PAGE_SIZE));
+
+ pr_debug("Copying Immediate SG: %p sg_nents: %u from %p"
+ " imm_data_len: %d\n", sg, sg_nents, &rx_desc->data[0],
+ imm_data_len);
+
+ sg_copy_from_buffer(sg, sg_nents, &rx_desc->data[0], imm_data_len);
+
+ cmd->write_data_done += imm_data_len;
+
+ if (cmd->write_data_done == cmd->se_cmd.data_length) {
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
+ cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
+ spin_unlock_bh(&cmd->istate_lock);
+ }
+
+sequence_cmd:
+ rc = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+
+ if (!rc && dump_payload == false && unsol_data)
+ iscsit_set_unsoliticed_dataout(cmd);
+
+ if (rc == CMDSN_ERROR_CANNOT_RECOVER)
+ return iscsit_add_reject_from_cmd(
+ ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 0, (unsigned char *)hdr, cmd);
+
+ return 0;
+}
+
+static int
+isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
+ struct iser_rx_desc *rx_desc, unsigned char *buf)
+{
+ struct scatterlist *sg_start;
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_cmd *cmd = NULL;
+ struct iscsi_data *hdr = (struct iscsi_data *)buf;
+ u32 unsol_data_len = ntoh24(hdr->dlength);
+ int rc, sg_nents, sg_off, page_off;
+
+ rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
+ if (rc < 0)
+ return rc;
+ else if (!cmd)
+ return 0;
+
+#warning FIXME: Unexpected unsolicited_data out
+ if (!cmd->unsolicited_data) {
+ pr_err("Received unexpected solicited data payload\n");
+ dump_stack();
+ return -1;
+ }
+
+ pr_debug("Unsolicited DataOut unsol_data_len: %u, write_data_done: %u,"
+ " data_length: %u\n", unsol_data_len, cmd->write_data_done,
+ cmd->se_cmd.data_length);
+
+ sg_off = cmd->write_data_done / PAGE_SIZE;
+ sg_start = &cmd->se_cmd.t_data_sg[sg_off];
+ sg_nents = max(1UL, DIV_ROUND_UP(unsol_data_len, PAGE_SIZE));
+ page_off = cmd->write_data_done % PAGE_SIZE;
+#warning FIXME: Non page-aligned unsolicited_data out
+ if (page_off) {
+ pr_err("Received unexpected non-page aligned solicited"
+ " data payload\n");
+ dump_stack();
+ return -1;
+ }
+ pr_debug("Copying DataOut: sg_start: %p, sg_off: %u sg_nents: %u from"
+ " %p %u\n", sg_start, sg_off, sg_nents, &rx_desc->data[0],
+ unsol_data_len);
+
+ sg_copy_from_buffer(sg_start, sg_nents, &rx_desc->data[0],
+ unsol_data_len);
+
+ rc = iscsit_check_dataout_payload(cmd, hdr, false);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int
+isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
+ uint32_t read_stag, uint64_t read_va,
+ uint32_t write_stag, uint64_t write_va)
+{
+ struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_cmd *cmd;
+ struct isert_cmd *isert_cmd;
+ int ret = -EINVAL;
+ u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK);
+
+ switch (opcode) {
+ case ISCSI_OP_SCSI_CMD:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
+ isert_cmd->read_stag = read_stag;
+ isert_cmd->read_va = read_va;
+ isert_cmd->write_stag = write_stag;
+ isert_cmd->write_va = write_va;
+
+ ret = isert_handle_scsi_cmd(isert_conn, isert_cmd,
+ rx_desc, (unsigned char *)hdr);
+ break;
+ case ISCSI_OP_NOOP_OUT:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr);
+ break;
+ case ISCSI_OP_SCSI_DATA_OUT:
+ ret = isert_handle_iscsi_dataout(isert_conn, rx_desc,
+ (unsigned char *)hdr);
+ break;
+ case ISCSI_OP_SCSI_TMFUNC:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ ret = iscsit_handle_task_mgt_cmd(conn, cmd, (unsigned char *)hdr);
+ break;
+ case ISCSI_OP_LOGOUT:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr);
+ if (ret > 0)
+ wait_for_completion_timeout(&conn->conn_logout_comp,
+ SECONDS_FOR_LOGOUT_COMP * HZ);
+ break;
+ default:
+ pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode);
+ dump_stack();
+ break;
+ }
+
+ return ret;
+}
+
+static void
+isert_rx_do_work(struct work_struct *work)
+{
+ struct isert_rx_desc *rx_desc = container_of(work,
+ struct isert_rx_desc, desc_work);
+ struct isert_conn *isert_conn = rx_desc->desc_conn;
+ struct iser_rx_desc *desc = &rx_desc->desc;
+ struct iser_hdr *iser_hdr = &desc->iser_header;
+ uint64_t read_va = 0, write_va = 0;
+ uint32_t read_stag = 0, write_stag = 0;
+ int rc;
+
+ switch (iser_hdr->flags & 0xF0) {
+ case ISCSI_CTRL:
+ if (iser_hdr->flags & ISER_RSV) {
+ read_stag = be32_to_cpu(iser_hdr->read_stag);
+ read_va = be64_to_cpu(iser_hdr->read_va);
+ pr_debug("ISER_RSV: read_stag: 0x%08x read_va: 0x%16llx\n",
+ read_stag, (unsigned long long)read_va);
+ }
+ if (iser_hdr->flags & ISER_WSV) {
+ write_stag = be32_to_cpu(iser_hdr->write_stag);
+ write_va = be64_to_cpu(iser_hdr->write_va);
+ pr_debug("ISER_WSV: write__stag: 0x%08x write_va: 0x%16llx\n",
+ write_stag, (unsigned long long)write_va);
+ }
+
+ pr_debug("ISER ISCSI_CTRL PDU\n");
+ break;
+ case ISER_HELLO:
+ pr_err("iSER Hello message\n");
+ break;
+ default:
+ pr_warn("Unknown iSER hdr flags: 0x%02x\n", iser_hdr->flags);
+ break;
+ }
+
+ rc = isert_rx_opcode(isert_conn, desc,
+ read_stag, read_va, write_stag, write_va);
+}
+
+static void
+isert_rx_queue_desc(struct isert_rx_desc *rx_desc, int rx_buflen,
+ struct isert_conn *isert_conn)
+{
+ INIT_WORK(&rx_desc->desc_work, isert_rx_do_work);
+ queue_work(isert_rx_wq, &rx_desc->desc_work);
+}
+
+static void
+isert_rx_completion(struct iser_rx_desc *desc, struct isert_conn *isert_conn,
+ unsigned long xfer_len)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct isert_rx_desc *rx_desc = container_of(desc,
+ struct isert_rx_desc, desc);
+ struct iscsi_hdr *hdr;
+ u64 rx_dma;
+ int rx_buflen, outstanding;
+
+ rx_desc->desc_conn = isert_conn;
+
+ if ((char *)desc == isert_conn->login_req_buf) {
+ rx_dma = isert_conn->login_req_dma;
+// rx_buflen = ISER_RX_LOGIN_SIZE;
+ rx_buflen = xfer_len;
+ pr_debug("ISER login_buf: Using rx_dma: 0x%llx, rx_buflen: %d\n",
+ rx_dma, rx_buflen);
+ } else {
+ rx_dma = desc->dma_addr;
+ rx_buflen = ISER_RX_PAYLOAD_SIZE;
+ pr_debug("ISER req_buf: Using rx_dma: 0x%llx, rx_buflen: %d\n",
+ rx_dma, rx_buflen);
+ }
+
+ ib_dma_sync_single_for_cpu(ib_dev, rx_dma, rx_buflen, DMA_FROM_DEVICE);
+
+ hdr = &desc->iscsi_header;
+ pr_debug("iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %lu\n",
+ hdr->opcode, hdr->itt, hdr->flags, (int)xfer_len - ISER_HEADERS_LEN);
+
+ if ((char *)desc == isert_conn->login_req_buf) {
+ isert_rx_login_req(rx_desc, rx_buflen, isert_conn);
+ } else {
+ isert_rx_queue_desc(rx_desc, rx_buflen, isert_conn);
+ }
+ ib_dma_sync_single_for_device(ib_dev, rx_dma, rx_buflen, DMA_FROM_DEVICE);
+
+ isert_conn->post_recv_buf_count--;
+ pr_debug("iSERT: Decremented post_recv_buf_count: %d\n",
+ isert_conn->post_recv_buf_count);
+
+ if ((char *)desc == isert_conn->login_req_buf)
+ return;
+
+ outstanding = isert_conn->post_recv_buf_count;
+ if (outstanding + ISERT_MIN_POSTED_RX <= ISERT_QP_MAX_RECV_DTOS) {
+ int err, count = min(ISERT_QP_MAX_RECV_DTOS - outstanding,
+ ISERT_MIN_POSTED_RX);
+ err = isert_post_recv(isert_conn, count);
+ if (err) {
+ pr_err("isert_post_recv() count: %d failed, %d\n",
+ count, err);
+ }
+ }
+}
+
+static void
+isert_cmd_kref_free(struct kref *kref)
+{
+ struct isert_cmd *isert_cmd = container_of(kref,
+ struct isert_cmd, cmd_kref);
+
+ kfree(isert_cmd);
+}
+
+static void
+isert_put_cmd(struct isert_cmd *isert_cmd)
+{
+ kref_put(&isert_cmd->cmd_kref, isert_cmd_kref_free);
+}
+
+static void
+isert_unmap_tx_desc(struct iser_tx_desc *tx_desc, struct ib_device *ib_dev)
+{
+ if (tx_desc->dma_addr != 0) {
+ pr_debug("Calling ib_dma_unmap_single for tx_desc->dma_addr\n");
+ ib_dma_unmap_single(ib_dev, tx_desc->dma_addr,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
+ tx_desc->dma_addr = 0;
+ }
+}
+
+static void
+isert_completion_put(struct iser_tx_desc *tx_desc, struct isert_cmd *isert_cmd,
+ struct ib_device *ib_dev)
+{
+ if (isert_cmd->sense_buf_dma != 0) {
+ pr_debug("Calling ib_dma_unmap_single for isert_cmd->sense_buf_dma\n");
+ ib_dma_unmap_single(ib_dev, isert_cmd->sense_buf_dma,
+ isert_cmd->sense_buf_len, DMA_TO_DEVICE);
+ isert_cmd->sense_buf_dma = 0;
+ }
+
+ isert_unmap_tx_desc(tx_desc, ib_dev);
+ isert_put_cmd(isert_cmd);
+}
+
+static void
+isert_do_rdma_read_comp(struct work_struct *work)
+{
+ struct isert_cmd *isert_cmd = container_of(work,
+ struct isert_cmd, comp_work);
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct ib_device *ib_dev = isert_cmd->conn->conn_cm_id->device;
+
+ if (wr->sge) {
+ pr_debug("isert_do_rdma_read_comp: Unmapping wr->sge from t_data_sg\n");
+ ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge, DMA_TO_DEVICE);
+ wr->sge = NULL;
+ }
+
+ if (isert_cmd->ib_sge) {
+ pr_debug("isert_do_rdma_read_comp: Freeing isert_cmd->ib_sge\n");
+ kfree(isert_cmd->ib_sge);
+ isert_cmd->ib_sge = NULL;
+ }
+
+ cmd->write_data_done = se_cmd->data_length;
+
+ pr_debug("isert_do_rdma_read_comp, calling target_execute_cmd\n");
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
+ cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
+ spin_unlock_bh(&cmd->istate_lock);
+
+ target_execute_cmd(se_cmd);
+}
+
+static void
+isert_completion_rdma_read(struct iser_tx_desc *tx_desc,
+ struct isert_cmd *isert_cmd)
+{
+ INIT_WORK(&isert_cmd->comp_work, isert_do_rdma_read_comp);
+ queue_work(isert_comp_wq, &isert_cmd->comp_work);
+}
+
+static void
+isert_do_control_comp(struct work_struct *work)
+{
+ struct isert_cmd *isert_cmd = container_of(work,
+ struct isert_cmd, comp_work);
+ struct isert_conn *isert_conn = isert_cmd->conn;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+
+ switch (cmd->i_state) {
+ case ISTATE_SEND_TASKMGTRSP:
+ pr_debug("Calling iscsit_tmr_post_handler >>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+ iscsit_tmr_post_handler(cmd, cmd->conn);
+ break;
+ case ISTATE_SEND_LOGOUTRSP:
+ pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+ iscsit_logout_post_handler(cmd, cmd->conn);
+ break;
+ default:
+ pr_err("Unknown isert_do_control_comp i_state: %d\n", cmd->i_state);
+ dump_stack();
+ break;
+ }
+
+ cmd->i_state = ISTATE_SENT_STATUS;
+ isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev);
+}
+
+static void
+isert_response_completion(struct iser_tx_desc *tx_desc,
+ struct isert_cmd *isert_cmd,
+ struct isert_conn *isert_conn,
+ struct ib_device *ib_dev)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+
+ if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
+ cmd->i_state == ISTATE_SEND_LOGOUTRSP) {
+ INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp);
+ queue_work(isert_comp_wq, &isert_cmd->comp_work);
+ return;
+ }
+ cmd->i_state = ISTATE_SENT_STATUS;
+
+ isert_completion_put(tx_desc, isert_cmd, ib_dev);
+}
+
+static void
+isert_send_completion(struct iser_tx_desc *tx_desc,
+ struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+ struct isert_rdma_wr *wr;
+
+ atomic_dec(&isert_conn->post_send_buf_count);
+
+ if (!isert_cmd) {
+ isert_unmap_tx_desc(tx_desc, ib_dev);
+ return;
+ }
+ wr = &isert_cmd->rdma_wr;
+
+ switch (wr->iser_ib_op) {
+ case ISER_IB_RECV:
+ pr_err("isert_send_completion: Got ISER_IB_RECV\n");
+ dump_stack();
+ break;
+ case ISER_IB_SEND:
+ pr_debug("isert_send_completion: Got ISER_IB_SEND\n");
+ isert_response_completion(tx_desc, isert_cmd,
+ isert_conn, ib_dev);
+ break;
+ case ISER_IB_RDMA_WRITE:
+ pr_err("isert_send_completion: Got ISER_IB_RDMA_WRITE\n");
+ dump_stack();
+ break;
+ case ISER_IB_RDMA_READ:
+ pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n");
+ isert_completion_rdma_read(tx_desc, isert_cmd);
+ break;
+ default:
+ pr_err("Unknown wr->iser_ib_op: 0x%02x\n", wr->iser_ib_op);
+ dump_stack();
+ break;
+ }
+}
+
+static void
+isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+
+ if (tx_desc) {
+ struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+
+ if (!isert_cmd)
+ isert_unmap_tx_desc(tx_desc, ib_dev);
+ else
+ isert_completion_put(tx_desc, isert_cmd, ib_dev);
+ }
+
+ if (isert_conn->post_recv_buf_count == 0 &&
+ atomic_read(&isert_conn->post_send_buf_count) == 0) {
+
+ pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+ pr_debug("Calling wake_up(&isert_conn->conn_wait); for isert_cq_comp_err\n");
+
+ isert_conn->state = ISER_CONN_DOWN;
+ wake_up(&isert_conn->conn_wait);
+ }
+}
+
+void
+isert_dump_ib_wc(struct ib_wc *wc)
+{
+ pr_debug("wc->wr_id: %llu\n", wc->wr_id);
+ pr_debug("wc->status: 0x%08x\n", wc->status);
+ pr_debug("wc->opcode: 0x%08x\n", wc->opcode);
+ pr_debug("wc->vendor_err: 0x%08x\n", wc->vendor_err);
+ pr_debug("wc->byte_len: %u\n", wc->byte_len);
+ pr_debug("wc->qp: %p\n", wc->qp);
+ pr_debug("wc->src_qp: %u\n", wc->src_qp);
+ pr_debug("wc->wc_flags: 0x%08x\n", wc->wc_flags);
+ pr_debug("wc->pkey_index: %hu\n", wc->pkey_index);
+ pr_debug("wc->slid: %hu\n", wc->slid);
+ pr_debug("wc->sl: 0x%02x\n", wc->sl);
+ pr_debug("wc->dlid_path_bits: 0x%02x\n", wc->dlid_path_bits);
+ pr_debug("wc->port_num: 0x%02x\n", wc->port_num);
+}
+
+void
+iser_cq_tx_tasklet(unsigned long data)
+{
+ struct isert_conn *isert_conn = (struct isert_conn *)data;
+ struct ib_cq *tx_cq = isert_conn->conn_tx_cq;
+ struct iser_tx_desc *tx_desc;
+ struct ib_wc wc;
+
+ while (ib_poll_cq(tx_cq, 1, &wc) == 1) {
+ tx_desc = (struct iser_tx_desc *)(unsigned long)wc.wr_id;
+
+ if (wc.status == IB_WC_SUCCESS) {
+ isert_send_completion(tx_desc, isert_conn);
+ } else {
+ pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
+ isert_dump_ib_wc(&wc);
+ atomic_dec(&isert_conn->post_send_buf_count);
+ isert_cq_comp_err(tx_desc, isert_conn);
+ }
+ }
+
+ ib_req_notify_cq(tx_cq, IB_CQ_NEXT_COMP);
+}
+
+void
+isert_cq_tx_callback(struct ib_cq *cq, void *context)
+{
+ struct isert_conn *isert_conn = context;
+
+ tasklet_schedule(&isert_conn->conn_tx_tasklet);
+}
+
+void
+iser_cq_rx_tasklet(unsigned long data)
+{
+ struct isert_conn *isert_conn = (struct isert_conn *)data;
+ struct ib_cq *rx_cq = isert_conn->conn_rx_cq;
+ struct iser_rx_desc *rx_desc;
+ struct ib_wc wc;
+ unsigned long xfer_len;
+
+ while (ib_poll_cq(rx_cq, 1, &wc) == 1) {
+ rx_desc = (struct iser_rx_desc *)(unsigned long)wc.wr_id;
+
+ if (wc.status == IB_WC_SUCCESS) {
+ xfer_len = (unsigned long)wc.byte_len;
+ isert_rx_completion(rx_desc, isert_conn, xfer_len);
+ } else {
+ pr_debug("RX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
+ if (wc.status != IB_WC_WR_FLUSH_ERR)
+ isert_dump_ib_wc(&wc);
+
+ isert_conn->post_recv_buf_count--;
+ isert_cq_comp_err(NULL, isert_conn);
+ }
+ }
+
+ ib_req_notify_cq(rx_cq, IB_CQ_NEXT_COMP);
+}
+
+void
+isert_cq_rx_callback(struct ib_cq *cq, void *context)
+{
+ struct isert_conn *isert_conn = context;
+
+ tasklet_schedule(&isert_conn->conn_rx_tasklet);
+}
+
+static int
+isert_put_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr, *wr_failed;
+ struct iscsi_scsi_rsp *hdr = (struct iscsi_scsi_rsp *)
+ &isert_cmd->tx_desc.iscsi_header;
+ int ret;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_rsp_pdu(cmd, conn, true, hdr);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+ /*
+ * Attach SENSE DATA payload to iSCSI Response PDU
+ */
+ if (cmd->se_cmd.sense_buffer &&
+ ((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
+ (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
+ u32 padding, sense_len;
+
+ put_unaligned_be16(cmd->se_cmd.scsi_sense_length, cmd->sense_buffer);
+ cmd->se_cmd.scsi_sense_length += sizeof (__be16);
+
+ padding = -(cmd->se_cmd.scsi_sense_length) & 3;
+ hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length);
+ sense_len = cmd->se_cmd.scsi_sense_length + padding;
+
+ isert_cmd->sense_buf_dma = ib_dma_map_single(ib_dev,
+ (void *)cmd->sense_buffer, sense_len,
+ DMA_TO_DEVICE);
+
+ isert_cmd->sense_buf_len = sense_len;
+ ib_dma_sync_single_for_cpu(ib_dev, isert_cmd->sense_buf_dma,
+ sense_len, DMA_TO_DEVICE);
+ ib_dma_sync_single_for_device(ib_dev, isert_cmd->sense_buf_dma,
+ sense_len, DMA_TO_DEVICE);
+
+ tx_dsg->addr = isert_cmd->sense_buf_dma;
+ tx_dsg->length = sense_len;
+ tx_dsg->lkey = isert_conn->conn_mr->lkey;
+ isert_cmd->tx_desc.num_sge = 2;
+ }
+
+ isert_cmd->rdma_wr.iser_ib_op = ISER_IB_SEND;
+ send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc;
+ send_wr->opcode = IB_WR_SEND;
+ send_wr->send_flags = IB_SEND_SIGNALED;
+ send_wr->sg_list = &isert_cmd->tx_desc.tx_sg[0];
+ send_wr->num_sge = isert_cmd->tx_desc.num_sge;
+ send_wr->next = NULL;
+
+ pr_debug("Posting SCSI Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ ret = ib_post_send(isert_conn->conn_qp, &isert_cmd->tx_desc.send_wr,
+ &wr_failed);
+ if (ret) {
+ pr_err("isert_put_response() failed to post wr,"
+ " ret: %d\n", ret);
+ atomic_dec(&isert_conn->post_send_buf_count);
+ return ret;
+ }
+ return 0;
+}
+
+static int
+isert_put_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ bool nopout_response)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr, *wr_failed;
+ int ret;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_nopin_rsp(cmd, conn,
+ (struct iscsi_nopin *)&isert_cmd->tx_desc.iscsi_header,
+ nopout_response);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+ isert_cmd->rdma_wr.iser_ib_op = ISER_IB_SEND;
+ send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc;
+ send_wr->opcode = IB_WR_SEND;
+ send_wr->send_flags = IB_SEND_SIGNALED;
+ send_wr->sg_list = &isert_cmd->tx_desc.tx_sg[0];
+ send_wr->num_sge = isert_cmd->tx_desc.num_sge;
+ send_wr->next = NULL;
+
+ pr_debug("Posting NOPIN Reponse IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ ret = ib_post_send(isert_conn->conn_qp, &isert_cmd->tx_desc.send_wr,
+ &wr_failed);
+ if (ret) {
+ pr_err("isert_put_nopin() failed to post wr,"
+ " ret: %d\n", ret);
+ atomic_dec(&isert_conn->post_send_buf_count);
+ return ret;
+ }
+ return 0;
+}
+
+static int
+isert_put_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr, *wr_failed;
+ int ret;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_logout_rsp(cmd, conn,
+ (struct iscsi_logout_rsp *)&isert_cmd->tx_desc.iscsi_header);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+ isert_cmd->rdma_wr.iser_ib_op = ISER_IB_SEND;
+ send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc;
+ send_wr->opcode = IB_WR_SEND;
+ send_wr->send_flags = IB_SEND_SIGNALED;
+ send_wr->sg_list = &isert_cmd->tx_desc.tx_sg[0];
+ send_wr->num_sge = isert_cmd->tx_desc.num_sge;
+ send_wr->next = NULL;
+
+ pr_debug("Posting Logout Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ ret = ib_post_send(isert_conn->conn_qp, &isert_cmd->tx_desc.send_wr,
+ &wr_failed);
+ if (ret) {
+ pr_err("isert_put_logout_rsp() failed to post wr,"
+ " ret: %d\n", ret);
+ atomic_dec(&isert_conn->post_send_buf_count);
+ return ret;
+ }
+ return 0;
+}
+
+static int
+isert_put_tm_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr, *wr_failed;
+ int ret;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_task_mgt_rsp(cmd, conn,
+ (struct iscsi_tm_rsp *)&isert_cmd->tx_desc.iscsi_header);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+ isert_cmd->rdma_wr.iser_ib_op = ISER_IB_SEND;
+ send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc;
+ send_wr->opcode = IB_WR_SEND;
+ send_wr->send_flags = IB_SEND_SIGNALED;
+ send_wr->sg_list = &isert_cmd->tx_desc.tx_sg[0];
+ send_wr->num_sge = isert_cmd->tx_desc.num_sge;
+ send_wr->next = NULL;
+
+ pr_debug("Posting Task Management Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ ret = ib_post_send(isert_conn->conn_qp, &isert_cmd->tx_desc.send_wr,
+ &wr_failed);
+ if (ret) {
+ pr_err("isert_put_tm_rsp() failed to post wr,"
+ " ret: %d\n", ret);
+ atomic_dec(&isert_conn->post_send_buf_count);
+ return ret;
+ }
+ return 0;
+}
+
+static int
+isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
+ struct ib_sge *ib_sge, struct ib_send_wr *send_wr,
+ u32 data_left, u32 offset)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct scatterlist *sg_start, *tmp_sg;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ u32 sg_off, page_off;
+ int i = 0, sg_nents;
+
+ sg_off = offset / PAGE_SIZE;
+ sg_start = &cmd->se_cmd.t_data_sg[sg_off];
+ sg_nents = min(cmd->se_cmd.t_data_nents - sg_off, isert_conn->max_sge);
+ page_off = offset % PAGE_SIZE;
+
+ send_wr->sg_list = ib_sge;
+ send_wr->num_sge = sg_nents;
+ send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc;
+ /*
+ * Perform mapping of TCM scatterlist memory ib_sge dma_addr.
+ */
+ for_each_sg(sg_start, tmp_sg, sg_nents, i) {
+
+ pr_debug("ISER RDMA from SGL dma_addr: 0x%16llx dma_len: %u,"
+ "page_off: %u\n", (unsigned long long)tmp_sg->dma_address,
+ tmp_sg->length, page_off);
+
+ ib_sge->addr = ib_sg_dma_address(ib_dev, tmp_sg) + page_off;
+ ib_sge->length = min_t(u32, data_left,
+ ib_sg_dma_len(ib_dev, tmp_sg) - page_off);
+ ib_sge->lkey = isert_conn->conn_mr->lkey;
+
+ pr_debug("RDMA ib_sge: addr: 0x%16llx length: %u\n",
+ ib_sge->addr, ib_sge->length);
+ page_off = 0;
+ data_left -= ib_sge->length;
+ ib_sge++;
+ pr_debug("Incrementing ib_sge pointer to %p\n", ib_sge);
+ }
+
+ pr_debug("Set outgoing sg_list: %p num_sg: %u from TCM SGLs\n",
+ send_wr->sg_list, send_wr->num_sge);
+
+ return sg_nents;
+}
+
+static int
+isert_put_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *wr_failed, *send_wr;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_sge *ib_sge;
+ struct scatterlist *sg;
+ u32 offset = 0, data_len, data_left, rdma_write_max;
+ int rc, ret = 0, count, sg_nents, i, ib_sge_cnt;
+
+ pr_debug("RDMA_WRITE: data_length: %u\n", se_cmd->data_length);
+
+ sg = &se_cmd->t_data_sg[0];
+ sg_nents = se_cmd->t_data_nents;
+
+ count = ib_dma_map_sg(ib_dev, sg, sg_nents, DMA_TO_DEVICE);
+ if (unlikely(!count)) {
+ pr_err("Unable to map put_datain SGs\n");
+ return -EINVAL;
+ }
+ wr->sge = sg;
+ wr->num_sge = sg_nents;
+ pr_debug("Mapped IB count: %u sg: %p sg_nents: %u for"
+ " RDMA_WRITE\n", count, sg, sg_nents);
+
+ ib_sge = kzalloc(sizeof(struct ib_sge) * sg_nents, GFP_KERNEL);
+ if (!ib_sge) {
+ pr_warn("Unable to allocate datain ib_sge\n");
+ ret = -ENOMEM;
+ goto unmap_sg;
+ }
+ isert_cmd->ib_sge = ib_sge;
+
+ pr_debug("Allocated ib_sge: %p from t_data_ents: %d for RDMA_WRITE\n",
+ ib_sge, se_cmd->t_data_nents);
+
+ wr->send_wr_num = DIV_ROUND_UP(sg_nents, isert_conn->max_sge);
+ wr->send_wr = kzalloc(sizeof(struct ib_send_wr) * wr->send_wr_num,
+ GFP_KERNEL);
+ if (!wr->send_wr) {
+ pr_err("Unable to allocate wr->send_wr\n");
+ ret = -ENOMEM;
+ goto unmap_sg;
+ }
+ pr_debug("Allocated wr->send_wr: %p wr->send_wr_num: %u\n",
+ wr->send_wr, wr->send_wr_num);
+
+ iscsit_increment_maxcmdsn(cmd, conn->sess);
+ cmd->stat_sn = conn->stat_sn++;
+
+ wr->isert_cmd = isert_cmd;
+ rdma_write_max = isert_conn->max_sge * PAGE_SIZE;
+ data_left = se_cmd->data_length;
+
+ for (i = 0; i < wr->send_wr_num; i++) {
+ send_wr = &isert_cmd->rdma_wr.send_wr[i];
+ data_len = min(data_left, rdma_write_max);
+
+ send_wr->opcode = IB_WR_RDMA_WRITE;
+ send_wr->send_flags = 0;
+ send_wr->wr.rdma.remote_addr = isert_cmd->read_va + offset;
+ send_wr->wr.rdma.rkey = isert_cmd->read_stag;
+
+ ib_sge_cnt = isert_build_rdma_wr(isert_conn, isert_cmd, ib_sge,
+ send_wr, data_len, offset);
+ ib_sge += ib_sge_cnt;
+
+ if (i + 1 == wr->send_wr_num)
+ send_wr->next = &isert_cmd->tx_desc.send_wr;
+ else
+ send_wr->next = &wr->send_wr[i + 1];
+
+ offset += data_len;
+ data_left -= data_len;
+ }
+ /*
+ * Build isert_conn->tx_desc for iSCSI response PDU and attach
+ */
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_rsp_pdu(cmd, conn, false,
+ (struct iscsi_scsi_rsp *)&isert_cmd->tx_desc.iscsi_header);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+ wr->iser_ib_op = ISER_IB_SEND;
+ isert_cmd->tx_desc.send_wr.wr_id = (unsigned long)&isert_cmd->tx_desc;
+ isert_cmd->tx_desc.send_wr.opcode = IB_WR_SEND;
+ isert_cmd->tx_desc.send_wr.send_flags = IB_SEND_SIGNALED;
+ isert_cmd->tx_desc.send_wr.sg_list = &isert_cmd->tx_desc.tx_sg[0];
+ isert_cmd->tx_desc.send_wr.num_sge = isert_cmd->tx_desc.num_sge;
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
+ if (rc) {
+ pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
+ atomic_dec(&isert_conn->post_send_buf_count);
+ }
+ pr_debug("Posted RDMA_WRITE + Response for iSER Data READ\n");
+ return 1;
+
+unmap_sg:
+ ib_dma_unmap_sg(ib_dev, sg, sg_nents, DMA_TO_DEVICE);
+ return ret;
+}
+
+static int
+isert_get_dataout(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *wr_failed, *send_wr;
+ struct ib_sge *ib_sge;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct scatterlist *sg_start;
+ u32 sg_off, sg_nents, page_off, va_offset = 0;
+ u32 offset = 0, data_len, data_left, rdma_write_max;
+ int rc, ret = 0, count, i, ib_sge_cnt;
+
+ pr_debug("RDMA_READ: data_length: %u write_data_done: %u\n",
+ se_cmd->data_length, cmd->write_data_done);
+
+ sg_off = cmd->write_data_done / PAGE_SIZE;
+ sg_start = &cmd->se_cmd.t_data_sg[sg_off];
+ page_off = cmd->write_data_done % PAGE_SIZE;
+
+ pr_debug("RDMA_READ: sg_off: %d, sg_start: %p page_off: %d\n",
+ sg_off, sg_start, page_off);
+
+ data_left = se_cmd->data_length - cmd->write_data_done;
+ sg_nents = se_cmd->t_data_nents - sg_off;
+
+ pr_debug("RDMA_READ: data_left: %d, sg_nents: %d\n",
+ data_left, sg_nents);
+
+ count = ib_dma_map_sg(ib_dev, sg_start, sg_nents, DMA_FROM_DEVICE);
+ if (unlikely(!count)) {
+ pr_err("Unable to map get_dataout SGs\n");
+ return -EINVAL;
+ }
+ wr->sge = sg_start;
+ wr->num_sge = sg_nents;
+ pr_debug("Mapped IB count: %u sg_start: %p sg_nents: %u for"
+ " RDMA_READ\n", count, sg_start, sg_nents);
+
+ ib_sge = kzalloc(sizeof(struct ib_sge) * sg_nents, GFP_KERNEL);
+ if (!ib_sge) {
+ pr_warn("Unable to allocate dataout ib_sge\n");
+ ret = -ENOMEM;
+ goto unmap_sg;
+ }
+ isert_cmd->ib_sge = ib_sge;
+
+ pr_debug("Using ib_sge: %p from sg_ents: %d for RDMA_READ\n",
+ ib_sge, sg_nents);
+
+ wr->send_wr_num = DIV_ROUND_UP(sg_nents, isert_conn->max_sge);
+ wr->send_wr = kzalloc(sizeof(struct ib_send_wr) * wr->send_wr_num,
+ GFP_KERNEL);
+ if (!wr->send_wr) {
+ pr_debug("Unable to allocate wr->send_wr\n");
+ ret = -ENOMEM;
+ goto unmap_sg;
+ }
+ pr_debug("Allocated wr->send_wr: %p wr->send_wr_num: %u\n",
+ wr->send_wr, wr->send_wr_num);
+
+ isert_cmd->tx_desc.isert_cmd = isert_cmd;
+
+ wr->iser_ib_op = ISER_IB_RDMA_READ;
+ wr->isert_cmd = isert_cmd;
+ rdma_write_max = isert_conn->max_sge * PAGE_SIZE;
+ offset = cmd->write_data_done;
+
+ for (i = 0; i < wr->send_wr_num; i++) {
+ send_wr = &isert_cmd->rdma_wr.send_wr[i];
+ data_len = min(data_left, rdma_write_max);
+
+ send_wr->opcode = IB_WR_RDMA_READ;
+ send_wr->wr.rdma.remote_addr = isert_cmd->write_va + va_offset;
+ send_wr->wr.rdma.rkey = isert_cmd->write_stag;
+
+ ib_sge_cnt = isert_build_rdma_wr(isert_conn, isert_cmd, ib_sge,
+ send_wr, data_len, offset);
+ ib_sge += ib_sge_cnt;
+
+ if (i + 1 == wr->send_wr_num)
+ send_wr->send_flags = IB_SEND_SIGNALED;
+ else
+ send_wr->next = &wr->send_wr[i + 1];
+
+ offset += data_len;
+ va_offset += data_len;
+ data_left -= data_len;
+ }
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
+ if (rc) {
+ pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
+ atomic_dec(&isert_conn->post_send_buf_count);
+ }
+ pr_debug("Posted RDMA_READ memory for ISER Data WRITE\n");
+ return 0;
+
+unmap_sg:
+ ib_dma_unmap_sg(ib_dev, sg_start, sg_nents, DMA_FROM_DEVICE);
+ return ret;
+}
+
+static int
+isert_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
+{
+ int ret;
+
+ switch (state) {
+ case ISTATE_SEND_R2T:
+ ret = isert_get_dataout(cmd, conn);
+ break;
+ case ISTATE_SEND_NOPIN_WANT_RESPONSE:
+ ret = isert_put_nopin(cmd, conn, false);
+ break;
+ case ISTATE_REMOVE:
+ spin_lock_bh(&conn->cmd_lock);
+ list_del(&cmd->i_conn_node);
+ spin_unlock_bh(&conn->cmd_lock);
+
+ iscsit_free_cmd(cmd);
+ ret = 0;
+ break;
+ default:
+ pr_err("Unknown immediate state: 0x%02x\n", state);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+isert_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
+{
+ int ret;
+
+ switch (state) {
+ case ISTATE_SEND_DATAIN:
+ ret = isert_put_datain(cmd, conn);
+ break;
+ case ISTATE_SEND_STATUS:
+ ret = isert_put_response(cmd, conn);
+ break;
+ case ISTATE_SEND_LOGOUTRSP:
+ ret = isert_put_logout_rsp(cmd, conn);
+ if (!ret) {
+ pr_debug("Returning iSER Logout -EAGAIN\n");
+ ret = -EAGAIN;
+ }
+ break;
+ case ISTATE_SEND_NOPIN:
+ ret = isert_put_nopin(cmd, conn, true);
+ break;
+ case ISTATE_SEND_TASKMGTRSP:
+ ret = isert_put_tm_rsp(cmd, conn);
+ break;
+ default:
+ pr_err("Unknown response state: 0x%02x\n", state);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+isert_setup_np(struct iscsi_np *np,
+ struct __kernel_sockaddr_storage *ksockaddr)
+{
+ struct isert_np *isert_np;
+ struct rdma_cm_id *isert_lid;
+ struct sockaddr *sa;
+ int ret;
+
+ isert_np = kzalloc(sizeof(struct isert_np), GFP_KERNEL);
+ if (!isert_np) {
+ pr_err("Unable to allocate struct isert_np\n");
+ return -ENOMEM;
+ }
+ init_waitqueue_head(&isert_np->np_accept_wq);
+ mutex_init(&isert_np->np_accept_mutex);
+ INIT_LIST_HEAD(&isert_np->np_accept_list);
+ init_completion(&isert_np->np_login_comp);
+
+ sa = (struct sockaddr *)ksockaddr;
+ pr_debug("ksockaddr: %p, sa: %p\n", ksockaddr, sa);
+
+ isert_lid = rdma_create_id(isert_cma_handler, np, RDMA_PS_TCP,
+ IB_QPT_RC);
+ if (IS_ERR(isert_lid)) {
+ pr_err("rdma_create_id() for isert_listen_handler failed: %ld\n",
+ PTR_ERR(isert_lid));
+ return PTR_ERR(isert_lid);
+ }
+
+ ret = rdma_bind_addr(isert_lid, sa);
+ if (ret) {
+ pr_err("rdma_bind_addr() for isert_lid failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = rdma_listen(isert_lid, ISERT_RDMA_LISTEN_BACKLOG);
+ if (ret) {
+ pr_err("rdma_listen() for isert_lid failed: %d\n", ret);
+ return ret;
+ }
+
+ isert_np->np_cm_id = isert_lid;
+ np->np_context = isert_np;
+ pr_debug("Setup isert_lid->context: %p\n", isert_lid->context);
+
+ return 0;
+
+}
+
+static int
+isert_check_accept_queue(struct isert_np *isert_np)
+{
+ int empty;
+
+ mutex_lock(&isert_np->np_accept_mutex);
+ empty = list_empty(&isert_np->np_accept_list);
+ mutex_unlock(&isert_np->np_accept_mutex);
+
+ return empty;
+}
+
+static int
+isert_rdma_post_recvl(struct isert_conn *isert_conn)
+{
+ struct ib_recv_wr rx_wr, *rx_wr_fail;
+ struct ib_sge sge;
+ int ret;
+
+ memset(&sge, 0, sizeof(struct ib_sge));
+ sge.addr = isert_conn->login_req_dma;
+ sge.length = ISER_RX_LOGIN_SIZE;
+ sge.lkey = isert_conn->conn_mr->lkey;
+
+ pr_debug("Setup sge: addr: %llx length: %d 0x%08x\n",
+ sge.addr, sge.length, sge.lkey);
+
+ memset(&rx_wr, 0, sizeof(struct ib_recv_wr));
+ rx_wr.wr_id = (unsigned long)isert_conn->login_req_buf;
+ rx_wr.sg_list = &sge;
+ rx_wr.num_sge = 1;
+
+ isert_conn->post_recv_buf_count++;
+ ret = ib_post_recv(isert_conn->conn_qp, &rx_wr, &rx_wr_fail);
+ if (ret) {
+ pr_err("ib_post_recv() failed: %d\n", ret);
+ isert_conn->post_recv_buf_count--;
+ }
+
+ pr_debug("ib_post_recv(): returned success >>>>>>>>>>>>>>>>>>>>>>>>\n");
+
+ return ret;
+}
+
+static int
+isert_rdma_accept(struct isert_conn *isert_conn)
+{
+ struct rdma_cm_id *cm_id = isert_conn->conn_cm_id;
+ struct rdma_conn_param cp;
+ int ret;
+
+ memset(&cp, 0, sizeof(struct rdma_conn_param));
+ cp.responder_resources = isert_conn->responder_resources;
+ cp.initiator_depth = isert_conn->initiator_depth;
+ cp.retry_count = 7;
+ cp.rnr_retry_count = 7;
+
+ pr_debug("Before rdma_accept >>>>>>>>>>>>>>>>>>>>.\n");
+
+ ret = rdma_accept(cm_id, &cp);
+ if (ret) {
+ pr_err("rdma_accept() failed with: %d\n", ret);
+ return ret;
+ }
+
+ pr_debug("After rdma_accept >>>>>>>>>>>>>>>>>>>>>.\n");
+
+ return 0;
+}
+
+static int
+isert_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ int ret;
+
+ pr_debug("isert_get_login_rx() before conn_login_comp conn: %p login: %p"
+ " login->req: %p >>>>>>>>>>>>> \n", conn, login, login->req);
+ pr_debug("isert_get_login_rx() isert_conn: %p &isert_conn->conn_login_comp: %p\n",
+ isert_conn, &isert_conn->conn_login_comp);
+
+ ret = wait_for_completion_interruptible(&isert_conn->conn_login_comp);
+ if (ret)
+ return ret;
+
+ pr_debug("isert_get_login_rx() processing login->req: %p\n", login->req);
+ return 0;
+}
+
+static void
+isert_set_conn_info(struct iscsi_np *np, struct iscsi_conn *conn,
+ struct isert_conn *isert_conn)
+{
+ struct rdma_cm_id *cm_id = isert_conn->conn_cm_id;
+ struct rdma_route *cm_route = &cm_id->route;
+ struct sockaddr_in *sock_in;
+ struct sockaddr_in6 *sock_in6;
+
+ conn->login_family = np->np_sockaddr.ss_family;
+
+ if (np->np_sockaddr.ss_family == AF_INET6) {
+ sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.dst_addr;
+ snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
+ &sock_in6->sin6_addr.in6_u);
+ conn->login_port = ntohs(sock_in6->sin6_port);
+
+ sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.src_addr;
+ snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
+ &sock_in6->sin6_addr.in6_u);
+ conn->local_port = ntohs(sock_in6->sin6_port);
+ } else {
+ sock_in = (struct sockaddr_in *)&cm_route->addr.dst_addr;
+ sprintf(conn->login_ip, "%pI4",
+ &sock_in->sin_addr.s_addr);
+ conn->login_port = ntohs(sock_in->sin_port);
+
+ sock_in = (struct sockaddr_in *)&cm_route->addr.src_addr;
+ sprintf(conn->local_ip, "%pI4",
+ &sock_in->sin_addr.s_addr);
+ conn->local_port = ntohs(sock_in->sin_port);
+ }
+}
+
+static int
+isert_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
+{
+ struct isert_np *isert_np = (struct isert_np *)np->np_context;
+ struct isert_conn *isert_conn;
+ int max_accept = 0, ret;
+
+accept_wait:
+ ret = wait_event_interruptible(isert_np->np_accept_wq,
+ !isert_check_accept_queue(isert_np) ||
+ np->np_thread_state == ISCSI_NP_THREAD_RESET);
+ if (max_accept > 5)
+ return -ENODEV;
+
+ spin_lock_bh(&np->np_thread_lock);
+ if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+ spin_unlock_bh(&np->np_thread_lock);
+ pr_err("ISCSI_NP_THREAD_RESET for isert_accept_np\n");
+ return -ENODEV;
+ }
+ spin_unlock_bh(&np->np_thread_lock);
+
+ mutex_lock(&isert_np->np_accept_mutex);
+ if (list_empty(&isert_np->np_accept_list)) {
+ mutex_unlock(&isert_np->np_accept_mutex);
+ max_accept++;
+ goto accept_wait;
+ }
+ isert_conn = list_first_entry(&isert_np->np_accept_list,
+ struct isert_conn, conn_accept_node);
+ list_del_init(&isert_conn->conn_accept_node);
+ mutex_unlock(&isert_np->np_accept_mutex);
+
+ conn->context = isert_conn;
+ isert_conn->conn = conn;
+ max_accept = 0;
+
+ ret = isert_rdma_post_recvl(isert_conn);
+ if (ret)
+ return ret;
+
+ ret = isert_rdma_accept(isert_conn);
+ if (ret)
+ return ret;
+
+ isert_set_conn_info(np, conn, isert_conn);
+
+ pr_debug("Processing isert_accept_np: isert_conn: %p\n", isert_conn);
+ return 0;
+}
+
+static void
+isert_free_np(struct iscsi_np *np)
+{
+ struct isert_np *isert_np = (struct isert_np *)np->np_context;
+
+ rdma_destroy_id(isert_np->np_cm_id);
+
+ np->np_context = NULL;
+ kfree(isert_np);
+}
+
+static void isert_free_conn(struct iscsi_conn *conn)
+{
+ struct isert_conn *isert_conn = conn->context;
+
+ pr_debug("isert_free_conn: Before isert_put_conn\n");
+
+ if (isert_conn->conn_cm_id)
+ rdma_disconnect(isert_conn->conn_cm_id);
+
+ pr_debug("isert_free_conn: Before wait_event :%d\n", isert_conn->state);
+ wait_event(isert_conn->conn_wait, isert_conn->state == ISER_CONN_DOWN);
+ pr_debug("isert_free_conn: After wait_event >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+
+ isert_put_conn(isert_conn);
+}
+
+static void
+isert_unmap_cmd(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+ struct isert_conn *isert_conn = conn->context;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+
+ pr_debug("isert_unmap_cmd >>>>>>>>>>>>>>>>>>>>>>>\n");
+
+ if (wr->sge) {
+ ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge, DMA_TO_DEVICE);
+ wr->sge = NULL;
+ }
+
+ if (wr->send_wr) {
+ kfree(wr->send_wr);
+ wr->send_wr = NULL;
+ }
+
+ if (isert_cmd->ib_sge) {
+ kfree(isert_cmd->ib_sge);
+ isert_cmd->ib_sge = NULL;
+ }
+}
+
+static void
+isert_free_cmd(struct iscsi_cmd *cmd)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+
+ isert_put_cmd(isert_cmd);
+}
+
+static struct iscsit_transport iser_target_transport = {
+ .name = "IB/iSER",
+ .transport_type = ISCSI_INFINIBAND,
+ .owner = THIS_MODULE,
+ .iscsit_setup_np = isert_setup_np,
+ .iscsit_accept_np = isert_accept_np,
+ .iscsit_free_np = isert_free_np,
+ .iscsit_free_conn = isert_free_conn,
+ .iscsit_alloc_cmd = isert_alloc_cmd,
+ .iscsit_unmap_cmd = isert_unmap_cmd,
+ .iscsit_free_cmd = isert_free_cmd,
+ .iscsit_get_login_rx = isert_get_login_rx,
+ .iscsit_put_login_tx = isert_put_login_tx,
+ .iscsit_immediate_queue = isert_immediate_queue,
+ .iscsit_response_queue = isert_response_queue,
+};
+
+static int __init isert_init(void)
+{
+ int ret;
+
+ isert_rx_wq = alloc_workqueue("isert_rx_wq", WQ_MEM_RECLAIM, 1);
+ if (!isert_rx_wq) {
+ pr_err("Unable to allocate isert_rx_wq\n");
+ return -ENOMEM;
+ }
+
+ isert_comp_wq = alloc_workqueue("isert_comp_wq", 0, 0);
+ if (!isert_comp_wq) {
+ pr_err("Unable to allocate isert_comp_wq\n");
+ ret = -ENOMEM;
+ goto destroy_rx_wq;
+ }
+
+ iscsit_create_transport(&iser_target_transport);
+ pr_debug("iSER_TARGET[0] - Loaded iser_target_transport\n");
+
+ printk("ISER_HEADERS_LEN: %lu\n", ISER_HEADERS_LEN);
+ printk("ISER_RECV_DATA_SEG_LEN: %d\n", ISER_RECV_DATA_SEG_LEN);
+ printk("ISER_RX_PAYLOAD_SIZE: %lu\n", ISER_RX_PAYLOAD_SIZE);
+ printk("ISER_RX_PAD_SIZE: %lu\n", ISER_RX_PAD_SIZE);
+
+ return 0;
+
+destroy_rx_wq:
+ destroy_workqueue(isert_rx_wq);
+ return ret;
+}
+
+static void __exit isert_exit(void)
+{
+ destroy_workqueue(isert_comp_wq);
+ destroy_workqueue(isert_rx_wq);
+ iscsit_destroy_transport(&iser_target_transport);
+ pr_debug("iSER_TARGET[0] - Released iser_target_transport\n");
+}
+
+MODULE_DESCRIPTION("iSER-Target for mainline target infrastructure");
+MODULE_VERSION("0.1");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(isert_init);
+module_exit(isert_exit);
diff --git a/drivers/infiniband/ulp/isert/isert_core.h b/drivers/infiniband/ulp/isert/isert_core.h
new file mode 100644
index 0000000..02276e4
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/isert_core.h
@@ -0,0 +1,12 @@
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_fmr_pool.h>
+#include <rdma/rdma_cm.h>
+
+extern void iser_cq_tx_tasklet(unsigned long);
+extern void isert_cq_tx_callback(struct ib_cq *, void *);
+extern void iser_cq_rx_tasklet(unsigned long);
+extern void isert_cq_rx_callback(struct ib_cq *, void *);
+extern void isert_free_rx_descriptors(struct isert_conn *);
--
1.7.2.5
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [RFC 10/11] iser-target: Add logic for core
2013-03-08 1:45 ` [RFC 10/11] iser-target: Add logic for core Nicholas A. Bellinger
@ 2013-03-14 11:08 ` Or Gerlitz
2013-03-14 11:58 ` Or Gerlitz
1 sibling, 0 replies; 35+ messages in thread
From: Or Gerlitz @ 2013-03-14 11:08 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier,
Alexander Nezhinsky
On 08/03/2013 03:45, Nicholas A. Bellinger wrote:
> +void
> +isert_dump_ib_wc(struct ib_wc *wc)
> +{
> + pr_debug("wc->wr_id: %llu\n", wc->wr_id);
> + pr_debug("wc->status: 0x%08x\n", wc->status);
This helper is called for a CQ completion with error, but when this
happens all the WC fields except for the wr_id and the status aren't
defined, so there's no point in dumping them (can be terribly misleading)
> + pr_debug("wc->opcode: 0x%08x\n", wc->opcode);
> + pr_debug("wc->vendor_err: 0x%08x\n", wc->vendor_err);
> + pr_debug("wc->byte_len: %u\n", wc->byte_len);
> + pr_debug("wc->qp: %p\n", wc->qp);
> + pr_debug("wc->src_qp: %u\n", wc->src_qp);
> + pr_debug("wc->wc_flags: 0x%08x\n", wc->wc_flags);
> + pr_debug("wc->pkey_index: %hu\n", wc->pkey_index);
> + pr_debug("wc->slid: %hu\n", wc->slid);
> + pr_debug("wc->sl: 0x%02x\n", wc->sl);
> + pr_debug("wc->dlid_path_bits: 0x%02x\n", wc->dlid_path_bits);
> + pr_debug("wc->port_num: 0x%02x\n", wc->port_num);
> +}
> +
> +void
> +iser_cq_tx_tasklet(unsigned long data)
> +{
> + struct isert_conn *isert_conn = (struct isert_conn *)data;
> + struct ib_cq *tx_cq = isert_conn->conn_tx_cq;
> + struct iser_tx_desc *tx_desc;
> + struct ib_wc wc;
> +
> + while (ib_poll_cq(tx_cq, 1, &wc) == 1) {
> + tx_desc = (struct iser_tx_desc *)(unsigned long)wc.wr_id;
> +
> + if (wc.status == IB_WC_SUCCESS) {
> + isert_send_completion(tx_desc, isert_conn);
> + } else {
> + pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
> + isert_dump_ib_wc(&wc);
> + atomic_dec(&isert_conn->post_send_buf_count);
> + isert_cq_comp_err(tx_desc, isert_conn);
> + }
> + }
> +
> + ib_req_notify_cq(tx_cq, IB_CQ_NEXT_COMP);
> +}
> +
> +void
> +isert_cq_tx_callback(struct ib_cq *cq, void *context)
> +{
> + struct isert_conn *isert_conn = context;
> +
> + tasklet_schedule(&isert_conn->conn_tx_tasklet);
> +}
> +
> +void
> +iser_cq_rx_tasklet(unsigned long data)
> +{
> + struct isert_conn *isert_conn = (struct isert_conn *)data;
> + struct ib_cq *rx_cq = isert_conn->conn_rx_cq;
> + struct iser_rx_desc *rx_desc;
> + struct ib_wc wc;
> + unsigned long xfer_len;
> +
> + while (ib_poll_cq(rx_cq, 1, &wc) == 1) {
> + rx_desc = (struct iser_rx_desc *)(unsigned long)wc.wr_id;
> +
> + if (wc.status == IB_WC_SUCCESS) {
> + xfer_len = (unsigned long)wc.byte_len;
> + isert_rx_completion(rx_desc, isert_conn, xfer_len);
> + } else {
> + pr_debug("RX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
> + if (wc.status != IB_WC_WR_FLUSH_ERR)
> + isert_dump_ib_wc(&wc);
> +
> + isert_conn->post_recv_buf_count--;
> + isert_cq_comp_err(NULL, isert_conn);
> + }
> + }
> +
> + ib_req_notify_cq(rx_cq, IB_CQ_NEXT_COMP);
> +}
^ permalink raw reply [flat|nested] 35+ messages in thread* Re: [RFC 10/11] iser-target: Add logic for core
2013-03-08 1:45 ` [RFC 10/11] iser-target: Add logic for core Nicholas A. Bellinger
2013-03-14 11:08 ` Or Gerlitz
@ 2013-03-14 11:58 ` Or Gerlitz
1 sibling, 0 replies; 35+ messages in thread
From: Or Gerlitz @ 2013-03-14 11:58 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier,
Alexander Nezhinsky
On 08/03/2013 03:45, Nicholas A. Bellinger wrote:
> +void
> +iser_cq_tx_tasklet(unsigned long data)
> +{
> + struct isert_conn *isert_conn = (struct isert_conn *)data;
> + struct ib_cq *tx_cq = isert_conn->conn_tx_cq;
> + struct iser_tx_desc *tx_desc;
> + struct ib_wc wc;
> +
> + while (ib_poll_cq(tx_cq, 1, &wc) == 1) {
> + tx_desc = (struct iser_tx_desc *)(unsigned long)wc.wr_id;
> +
> + if (wc.status == IB_WC_SUCCESS) {
> + isert_send_completion(tx_desc, isert_conn);
> + } else {
> + pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
> + isert_dump_ib_wc(&wc);
> + atomic_dec(&isert_conn->post_send_buf_count);
> + isert_cq_comp_err(tx_desc, isert_conn);
> + }
> + }
> +
> + ib_req_notify_cq(tx_cq, IB_CQ_NEXT_COMP);
> +}
> +
> +void
> +isert_cq_tx_callback(struct ib_cq *cq, void *context)
> +{
> + struct isert_conn *isert_conn = context;
> +
> + tasklet_schedule(&isert_conn->conn_tx_tasklet);
> +}
> +
> +void
> +iser_cq_rx_tasklet(unsigned long data)
> +{
> + struct isert_conn *isert_conn = (struct isert_conn *)data;
> + struct ib_cq *rx_cq = isert_conn->conn_rx_cq;
> + struct iser_rx_desc *rx_desc;
> + struct ib_wc wc;
> + unsigned long xfer_len;
> +
> + while (ib_poll_cq(rx_cq, 1, &wc) == 1) {
> + rx_desc = (struct iser_rx_desc *)(unsigned long)wc.wr_id;
> +
> + if (wc.status == IB_WC_SUCCESS) {
> + xfer_len = (unsigned long)wc.byte_len;
> + isert_rx_completion(rx_desc, isert_conn, xfer_len);
> + } else {
> + pr_debug("RX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
> + if (wc.status != IB_WC_WR_FLUSH_ERR)
> + isert_dump_ib_wc(&wc);
> +
> + isert_conn->post_recv_buf_count--;
> + isert_cq_comp_err(NULL, isert_conn);
> + }
> + }
> +
> + ib_req_notify_cq(rx_cq, IB_CQ_NEXT_COMP);
> +}
We currently have here the following sequence of calls
isert_cq_rx_callback --> tasklet_schedule ... --> ...
ib_poll_cq --> isert_rx_completion --> isert_rx_queue_desc -->
isert_rx_queue_desc --> queue_work (context switch)
isert_cq_tx_callback --> tasklet_schedule ... --> ...
ib_poll_cq --> isert_send_completion --> isert_completion_rdma_read
--> queue_work (context switch)
which means we have one context switch from the CQ callback to tasklet
and then a PER IO context switch
from the tasklet to a kernel thread context which you might need for IO
submission into the backing store.
This can be optimized by having one context switch from the isert cq
callbacks to a kernel thread, with the work
item being "do polling" and then from the cq polling code do the
submission into the backing store without
any further context switches.
Or.
> +
> +void
> +isert_cq_rx_callback(struct ib_cq *cq, void *context)
> +{
> + struct isert_conn *isert_conn = context;
> +
> + tasklet_schedule(&isert_conn->conn_rx_tasklet);
> +}
^ permalink raw reply [flat|nested] 35+ messages in thread
* [RFC 11/11] iser-target: Add Makefile + Kconfig
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
` (8 preceding siblings ...)
2013-03-08 1:45 ` [RFC 10/11] iser-target: Add logic for core Nicholas A. Bellinger
@ 2013-03-08 1:45 ` Nicholas A. Bellinger
2013-03-14 8:17 ` [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Or Gerlitz
10 siblings, 0 replies; 35+ messages in thread
From: Nicholas A. Bellinger @ 2013-03-08 1:45 UTC (permalink / raw)
To: target-devel
Cc: linux-rdma, linux-scsi, Roland Dreier, Or Gerlitz,
Alexander Nezhinsky, Nicholas Bellinger
From: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/infiniband/Kconfig | 1 +
drivers/infiniband/Makefile | 1 +
drivers/infiniband/ulp/isert/Kconfig | 6 ++++++
drivers/infiniband/ulp/isert/Makefile | 5 +++++
4 files changed, 13 insertions(+), 0 deletions(-)
create mode 100644 drivers/infiniband/ulp/isert/Kconfig
create mode 100644 drivers/infiniband/ulp/isert/Makefile
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index a0f29c1..c85b56c 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -59,5 +59,6 @@ source "drivers/infiniband/ulp/srp/Kconfig"
source "drivers/infiniband/ulp/srpt/Kconfig"
source "drivers/infiniband/ulp/iser/Kconfig"
+source "drivers/infiniband/ulp/isert/Kconfig"
endif # INFINIBAND
diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
index bf846a1..b126fef 100644
--- a/drivers/infiniband/Makefile
+++ b/drivers/infiniband/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/
obj-$(CONFIG_INFINIBAND_SRPT) += ulp/srpt/
obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/
+obj-$(CONFIG_INFINIBAND_ISERT) += ulp/isert/
diff --git a/drivers/infiniband/ulp/isert/Kconfig b/drivers/infiniband/ulp/isert/Kconfig
new file mode 100644
index 0000000..c268a3b
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/Kconfig
@@ -0,0 +1,6 @@
+config INFINIBAND_ISERT
+ tristate "InfiniBand iSCSI Extentions for RDMA (iSER) Target support"
+ depends on INFINIBAND && TARGET_CORE && ISCSI_TARGET
+ ---help---
+
+ Support for iSCSI Extentions for RDMA (iSER) Target on Infiniband fabrics.
diff --git a/drivers/infiniband/ulp/isert/Makefile b/drivers/infiniband/ulp/isert/Makefile
new file mode 100644
index 0000000..2d0ac23
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -Idrivers/target -Idrivers/target/iscsi
+obj-$(CONFIG_INFINIBAND_ISERT) += ib_isert.o
+
+ib_isert-y := isert_core.o \
+ isert_verbs.o
--
1.7.2.5
^ permalink raw reply related [flat|nested] 35+ messages in thread* Re: [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target
2013-03-08 1:45 [RFC 00/11] Add support for iSCSI Extentions for RDMA (ISER) target Nicholas A. Bellinger
` (9 preceding siblings ...)
2013-03-08 1:45 ` [RFC 11/11] iser-target: Add Makefile + Kconfig Nicholas A. Bellinger
@ 2013-03-14 8:17 ` Or Gerlitz
10 siblings, 0 replies; 35+ messages in thread
From: Or Gerlitz @ 2013-03-14 8:17 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-rdma, linux-scsi, Roland Dreier,
Alexander Nezhinsky
On 08/03/2013 03:45, Nicholas A. Bellinger wrote:
> This series is first RFC for iSCSI Extentions for RDMA (ISER) target
> support with existing iscsi-target TCP based socket code for a future v3.10 merge.
>
> This code is available in git here:
> git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git iser_target-rfcv1
>
> Ths includes a basic iscsit_transport API that allows different transports
> to reside under a single iscsi-target configfs control plane, using an
> pre-defined network portal attribute to enable a rdma_cm listener on top
> of existing ipoib portals.
Hi Nic,
Here are quick few nits (...) which need to be sorted out for the next
version, I've picked them from running the patches through checkpatch
and sparse / gcc warnings checks
target-pending]# git format-patch -o /tmp/lio-iser-rfc
7b745c84a9f4ad62db4b67053fbceb5d706451af..
/tmp/lio-iser-rfc/0001-iscsi-target-Add-iscsit_transport-API-template.patch
/tmp/lio-iser-rfc/0002-iscsi-target-Initial-traditional-TCP-conversion-to-i.patch
/tmp/lio-iser-rfc/0003-iscsi-target-Add-iser-target-parameter-keys-setup-du.patch
/tmp/lio-iser-rfc/0004-iscsi-target-Add-per-transport-iscsi_cmd-alloc-free.patch
/tmp/lio-iser-rfc/0005-iscsi-target-Refactor-RX-PDU-logic-export-request-PD.patch
/tmp/lio-iser-rfc/0006-iscsi-target-Refactor-TX-queue-logic-export-response.patch
/tmp/lio-iser-rfc/0007-iscsi-target-Add-iser-network-portal-attribute.patch
/tmp/lio-iser-rfc/0008-iser-target-Add-base-proto-includes.patch
/tmp/lio-iser-rfc/0009-iser-target-Add-logic-for-verbs.patch
/tmp/lio-iser-rfc/0010-iser-target-Add-logic-for-core.patch
/tmp/lio-iser-rfc/0011-iser-target-Add-Makefile-Kconfig.patch
target-pending]# ./scripts/checkpatch.pl --strict /tmp/lio-iser-rfc/* |
grep total
total: 0 errors, 8 warnings, 0 checks, 142 lines checked
total: 1 errors, 14 warnings, 6 checks, 1097 lines checked
total: 0 errors, 15 warnings, 7 checks, 299 lines checked
total: 0 errors, 0 warnings, 0 checks, 106 lines checked
total: 0 errors, 13 warnings, 4 checks, 795 lines checked
total: 1 errors, 12 warnings, 2 checks, 877 lines checked
total: 0 errors, 5 warnings, 0 checks, 83 lines checked
total: 7 errors, 12 warnings, 1 checks, 170 lines checked
total: 1 errors, 9 warnings, 14 checks, 481 lines checked
total: 1 errors, 39 warnings, 43 checks, 1732 lines checked
total: 0 errors, 0 warnings, 0 checks, 21 lines checked
drivers/infiniband/ulp/isert/isert_core.c:774:1: warning: symbol
'isert_dump_ib_wc' was not declared. Should it be static?
drivers/infiniband/ulp/isert/isert_verbs.c:341:1: warning: symbol
'isert_put_conn' was not declared. Should it be static?
drivers/infiniband/ulp/isert/isert_verbs.c:375:1: warning: symbol
'isert_cma_handler' was not declared. Should it be static?
drivers/infiniband/ulp/isert/isert_verbs.c:416:1: warning: symbol
'isert_post_recv' was not declared. Should it be static?
drivers/infiniband/ulp/isert/isert_verbs.c:451:1: warning: symbol
'isert_post_send' was not declared. Should it be static?
drivers/infiniband/ulp/isert/isert_core.c: In function ?isert_rx_do_work?:
drivers/infiniband/ulp/isert/isert_core.c:481: warning: variable ?rc?
set but not used
Or.
^ permalink raw reply [flat|nested] 35+ messages in thread