git: 156e41c4b772 - stable/13 - iscsi: Handle unmapped I/O requests.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Wed, 11 May 2022 21:04:37 UTC
The branch stable/13 has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=156e41c4b772c80c0ab5f36fced54072d3dd70d8

commit 156e41c4b772c80c0ab5f36fced54072d3dd70d8
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-03-10 23:49:53 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-05-11 20:52:17 +0000

    iscsi: Handle unmapped I/O requests.
    
    Don't assume that csio->data_ptr is pointer to a data buffer that can
    be passed to icl_get_pdu_data and icl_append_data.  For unmapped I/O
    requests, csio->data_ptr is instead a pointer to a struct bio as
    indicated by CAM_DATA_BIO.  To support these requests, add
    icl_pdu_append_bio and icl_pdu_get_bio methods which pass a pointer to
    the bio and an offset and length relative to the bio's buffer.
    
    Note that only backends supporting unmapped requests need to implement
    these hooks.
    
    Implement simple no-op hooks for the iser backend.
    
    Reviewed by:    mav
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D34382
    
    (cherry picked from commit 7aab9c14a462e0871394bbc4e276affb79c8d173)
---
 sys/dev/iscsi/icl_conn_if.m  | 19 +++++++++++++++++++
 sys/dev/iscsi/icl_wrappers.h | 18 ++++++++++++++++++
 sys/dev/iscsi/iscsi.c        | 41 ++++++++++++++++++++++++++++++++++++++---
 sys/dev/iser/icl_iser.c      | 24 ++++++++++++++++++++++++
 4 files changed, 99 insertions(+), 3 deletions(-)

diff --git a/sys/dev/iscsi/icl_conn_if.m b/sys/dev/iscsi/icl_conn_if.m
index e46b8cdc20dc..1b424b0b0f31 100644
--- a/sys/dev/iscsi/icl_conn_if.m
+++ b/sys/dev/iscsi/icl_conn_if.m
@@ -30,6 +30,7 @@
 # $FreeBSD$
 #
 
+#include <sys/bio.h>
 #include <sys/socket.h>
 #include <dev/iscsi/icl.h>
 
@@ -50,6 +51,15 @@ METHOD size_t pdu_data_segment_length {
 	const struct icl_pdu *_ip;
 };
 
+METHOD int pdu_append_bio {
+	struct icl_conn *_ic;
+	struct icl_pdu *_ip;
+	struct bio *_bp;
+	size_t _offset;
+	size_t _len;
+	int _flags;
+};
+
 METHOD int pdu_append_data {
 	struct icl_conn *_ic;
 	struct icl_pdu *_ip;
@@ -58,6 +68,15 @@ METHOD int pdu_append_data {
 	int _flags;
 };
 
+METHOD void pdu_get_bio {
+	struct icl_conn *_ic;
+	struct icl_pdu *_ip;
+	size_t _pdu_off;
+	struct bio *_bp;
+	size_t _bio_off;
+	size_t _len;
+};
+
 METHOD void pdu_get_data {
 	struct icl_conn *_ic;
 	struct icl_pdu *_ip;
diff --git a/sys/dev/iscsi/icl_wrappers.h b/sys/dev/iscsi/icl_wrappers.h
index cc37771c7dba..c2f215c10607 100644
--- a/sys/dev/iscsi/icl_wrappers.h
+++ b/sys/dev/iscsi/icl_wrappers.h
@@ -38,6 +38,7 @@
 #ifndef ICL_WRAPPERS_H
 #define	ICL_WRAPPERS_H
 
+#include <sys/bio.h>
 #include <sys/kobj.h>
 
 #include <dev/iscsi/icl.h>
@@ -57,6 +58,15 @@ icl_pdu_data_segment_length(const struct icl_pdu *ip)
 	return (ICL_CONN_PDU_DATA_SEGMENT_LENGTH(ip->ip_conn, ip));
 }
 
+static inline int
+icl_pdu_append_bio(struct icl_pdu *ip, struct bio *bp, size_t offset,
+    size_t len, int flags)
+{
+
+	return (ICL_CONN_PDU_APPEND_BIO(ip->ip_conn, ip, bp, offset, len,
+	    flags));
+}
+
 static inline int
 icl_pdu_append_data(struct icl_pdu *ip, const void *addr, size_t len, int flags)
 {
@@ -64,6 +74,14 @@ icl_pdu_append_data(struct icl_pdu *ip, const void *addr, size_t len, int flags)
 	return (ICL_CONN_PDU_APPEND_DATA(ip->ip_conn, ip, addr, len, flags));
 }
 
+static inline void
+icl_pdu_get_bio(struct icl_pdu *ip, size_t pdu_off, struct bio *bp,
+    size_t bio_off, size_t len)
+{
+
+	ICL_CONN_PDU_GET_BIO(ip->ip_conn, ip, pdu_off, bp, bio_off, len);
+}
+
 static inline void
 icl_pdu_get_data(struct icl_pdu *ip, size_t off, void *addr, size_t len)
 {
diff --git a/sys/dev/iscsi/iscsi.c b/sys/dev/iscsi/iscsi.c
index 155faa0910e4..e4bfb6a353d2 100644
--- a/sys/dev/iscsi/iscsi.c
+++ b/sys/dev/iscsi/iscsi.c
@@ -33,6 +33,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/bio.h>
 #include <sys/condvar.h>
 #include <sys/conf.h>
 #include <sys/endian.h>
@@ -1059,6 +1060,24 @@ iscsi_pdu_handle_task_response(struct icl_pdu *response)
 	icl_pdu_free(response);
 }
 
+static void
+iscsi_pdu_get_data_csio(struct icl_pdu *response, size_t pdu_offset,
+    struct ccb_scsiio *csio, size_t oreceived, size_t data_segment_len)
+{
+	switch (csio->ccb_h.flags & CAM_DATA_MASK) {
+	case CAM_DATA_BIO:
+		icl_pdu_get_bio(response, pdu_offset,
+		    (struct bio *)csio->data_ptr, oreceived, data_segment_len);
+		break;
+	case CAM_DATA_VADDR:
+		icl_pdu_get_data(response, pdu_offset,
+		    csio->data_ptr + oreceived, data_segment_len);
+		break;
+	default:
+		__assert_unreachable();
+	}
+}
+
 static void
 iscsi_pdu_handle_data_in(struct icl_pdu *response)
 {
@@ -1137,7 +1156,7 @@ iscsi_pdu_handle_data_in(struct icl_pdu *response)
 		iscsi_outstanding_remove(is, io);
 	ISCSI_SESSION_UNLOCK(is);
 
-	icl_pdu_get_data(response, 0, csio->data_ptr + oreceived, data_segment_len);
+	iscsi_pdu_get_data_csio(response, 0, csio, oreceived, data_segment_len);
 
 	/*
 	 * XXX: Check F.
@@ -1188,6 +1207,22 @@ iscsi_pdu_handle_logout_response(struct icl_pdu *response)
 	icl_pdu_free(response);
 }
 
+static int
+iscsi_pdu_append_data_csio(struct icl_pdu *request, struct ccb_scsiio *csio,
+    size_t off, size_t len, int how)
+{
+	switch (csio->ccb_h.flags & CAM_DATA_MASK) {
+	case CAM_DATA_BIO:
+		return (icl_pdu_append_bio(request,
+			(struct bio *)csio->data_ptr, off, len, how));
+	case CAM_DATA_VADDR:
+		return (icl_pdu_append_data(request, csio->data_ptr + off, len,
+		    how));
+	default:
+		__assert_unreachable();
+	}
+}
+
 static void
 iscsi_pdu_handle_r2t(struct icl_pdu *response)
 {
@@ -1282,7 +1317,7 @@ iscsi_pdu_handle_r2t(struct icl_pdu *response)
 		    bhsr2t->bhsr2t_target_transfer_tag;
 		bhsdo->bhsdo_datasn = htonl(datasn);
 		bhsdo->bhsdo_buffer_offset = htonl(off);
-		error = icl_pdu_append_data(request, csio->data_ptr + off, len,
+		error = iscsi_pdu_append_data_csio(request, csio, off, len,
 		    M_NOWAIT | ICL_NOCOPY);
 		if (error != 0) {
 			ISCSI_SESSION_WARN(is, "failed to allocate memory; "
@@ -2387,7 +2422,7 @@ iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb)
 			len = is->is_conn->ic_max_send_data_segment_length;
 		}
 
-		error = icl_pdu_append_data(request, csio->data_ptr, len,
+		error = iscsi_pdu_append_data_csio(request, csio, 0, len,
 		    M_NOWAIT | ICL_NOCOPY);
 		if (error != 0) {
 			iscsi_outstanding_remove(is, io);
diff --git a/sys/dev/iser/icl_iser.c b/sys/dev/iser/icl_iser.c
index 2c2514a1422b..140b5622385d 100644
--- a/sys/dev/iser/icl_iser.c
+++ b/sys/dev/iser/icl_iser.c
@@ -43,6 +43,7 @@ static void iser_conn_release(struct icl_conn *ic);
 static icl_conn_new_pdu_t	iser_conn_new_pdu;
 static icl_conn_pdu_free_t	iser_conn_pdu_free;
 static icl_conn_pdu_data_segment_length_t iser_conn_pdu_data_segment_length;
+static icl_conn_pdu_append_bio_t	iser_conn_pdu_append_bio;
 static icl_conn_pdu_append_data_t	iser_conn_pdu_append_data;
 static icl_conn_pdu_queue_t	iser_conn_pdu_queue;
 static icl_conn_handoff_t	iser_conn_handoff;
@@ -51,12 +52,14 @@ static icl_conn_close_t		iser_conn_close;
 static icl_conn_connect_t	iser_conn_connect;
 static icl_conn_task_setup_t	iser_conn_task_setup;
 static icl_conn_task_done_t	iser_conn_task_done;
+static icl_conn_pdu_get_bio_t	iser_conn_pdu_get_bio;
 static icl_conn_pdu_get_data_t	iser_conn_pdu_get_data;
 
 static kobj_method_t icl_iser_methods[] = {
 	KOBJMETHOD(icl_conn_new_pdu, iser_conn_new_pdu),
 	KOBJMETHOD(icl_conn_pdu_free, iser_conn_pdu_free),
 	KOBJMETHOD(icl_conn_pdu_data_segment_length, iser_conn_pdu_data_segment_length),
+	KOBJMETHOD(icl_conn_pdu_append_bio, iser_conn_pdu_append_bio),
 	KOBJMETHOD(icl_conn_pdu_append_data, iser_conn_pdu_append_data),
 	KOBJMETHOD(icl_conn_pdu_queue, iser_conn_pdu_queue),
 	KOBJMETHOD(icl_conn_handoff, iser_conn_handoff),
@@ -65,6 +68,7 @@ static kobj_method_t icl_iser_methods[] = {
 	KOBJMETHOD(icl_conn_connect, iser_conn_connect),
 	KOBJMETHOD(icl_conn_task_setup, iser_conn_task_setup),
 	KOBJMETHOD(icl_conn_task_done, iser_conn_task_done),
+	KOBJMETHOD(icl_conn_pdu_get_bio, iser_conn_pdu_get_bio),
 	KOBJMETHOD(icl_conn_pdu_get_data, iser_conn_pdu_get_data),
 	{ 0, 0 }
 };
@@ -108,6 +112,18 @@ out:
 	return (ret);
 }
 
+int
+iser_conn_pdu_append_bio(struct icl_conn *ic, struct icl_pdu *request,
+			 struct bio *bp, size_t offset, size_t len, int flags)
+{
+	MPASS(!((request->ip_bhs->bhs_opcode & ISCSI_OPCODE_MASK) ==
+	    ISCSI_BHS_OPCODE_LOGIN_REQUEST ||
+	    (request->ip_bhs->bhs_opcode & ISCSI_OPCODE_MASK) ==
+	    ISCSI_BHS_OPCODE_TEXT_REQUEST));
+
+	return (0);
+}
+
 int
 iser_conn_pdu_append_data(struct icl_conn *ic, struct icl_pdu *request,
 			  const void *addr, size_t len, int flags)
@@ -126,6 +142,14 @@ iser_conn_pdu_append_data(struct icl_conn *ic, struct icl_pdu *request,
 	return (0);
 }
 
+void
+iser_conn_pdu_get_bio(struct icl_conn *ic, struct icl_pdu *ip,
+		      size_t pdu_off, struct bio *bp, size_t bio_off,
+		      size_t len)
+{
+	MPASS(ip->ip_data_mbuf == NULL);
+}
+
 void
 iser_conn_pdu_get_data(struct icl_conn *ic, struct icl_pdu *ip,
 		       size_t off, void *addr, size_t len)