Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 6 Feb 2015 21:03:26 +0000 (UTC)
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r278331 - in head: sys/cam/ctl usr.sbin/ctladm usr.sbin/ctld
Message-ID:  <201502062103.t16L3Qke032931@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trasz
Date: Fri Feb  6 21:03:25 2015
New Revision: 278331
URL: https://svnweb.freebsd.org/changeset/base/278331

Log:
  Make it possible to set (via ctl.conf(5)) and query (via ctladm islist -v)
  target iSCSI offload.  Add mechanism to query maximum receive data segment
  size supported by chosen hardware offload module, and use it in ctld(8)
  to determine the value to advertise to the other side.
  
  MFC after:	1 month
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/sys/cam/ctl/ctl_frontend_iscsi.c
  head/sys/cam/ctl/ctl_ioctl.h
  head/usr.sbin/ctladm/ctladm.c
  head/usr.sbin/ctld/ctl.conf.5
  head/usr.sbin/ctld/ctld.c
  head/usr.sbin/ctld/ctld.h
  head/usr.sbin/ctld/kernel.c
  head/usr.sbin/ctld/login.c
  head/usr.sbin/ctld/parse.y
  head/usr.sbin/ctld/token.l

Modified: head/sys/cam/ctl/ctl_frontend_iscsi.c
==============================================================================
--- head/sys/cam/ctl/ctl_frontend_iscsi.c	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/sys/cam/ctl/ctl_frontend_iscsi.c	Fri Feb  6 21:03:25 2015	(r278331)
@@ -1222,7 +1222,7 @@ cfiscsi_session_unregister_initiator(str
 }
 
 static struct cfiscsi_session *
-cfiscsi_session_new(struct cfiscsi_softc *softc)
+cfiscsi_session_new(struct cfiscsi_softc *softc, const char *offload)
 {
 	struct cfiscsi_session *cs;
 	int error;
@@ -1242,7 +1242,11 @@ cfiscsi_session_new(struct cfiscsi_softc
 	cv_init(&cs->cs_login_cv, "cfiscsi_login");
 #endif
 
-	cs->cs_conn = icl_new_conn(NULL, "cfiscsi", &cs->cs_lock);
+	cs->cs_conn = icl_new_conn(offload, "cfiscsi", &cs->cs_lock);
+	if (cs->cs_conn == NULL) {
+		free(cs, M_CFISCSI);
+		return (NULL);
+	}
 	cs->cs_conn->ic_receive = cfiscsi_receive_callback;
 	cs->cs_conn->ic_error = cfiscsi_error_callback;
 	cs->cs_conn->ic_prv0 = cs;
@@ -1325,7 +1329,7 @@ cfiscsi_accept(struct socket *so, struct
 {
 	struct cfiscsi_session *cs;
 
-	cs = cfiscsi_session_new(&cfiscsi_softc);
+	cs = cfiscsi_session_new(&cfiscsi_softc, NULL);
 	if (cs == NULL) {
 		CFISCSI_WARN("failed to create session");
 		return;
@@ -1469,7 +1473,7 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *
 		mtx_unlock(&cfiscsi_softc.lock);
 	} else {
 #endif
-		cs = cfiscsi_session_new(softc);
+		cs = cfiscsi_session_new(softc, cihp->offload);
 		if (cs == NULL) {
 			ci->status = CTL_ISCSI_ERROR;
 			snprintf(ci->error_str, sizeof(ci->error_str),
@@ -1620,6 +1624,7 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci)
 		    "<max_data_segment_length>%zd</max_data_segment_length>"
 		    "<immediate_data>%d</immediate_data>"
 		    "<iser>%d</iser>"
+		    "<offload>%s</offload>"
 		    "</connection>\n",
 		    cs->cs_id,
 		    cs->cs_initiator_name, cs->cs_initiator_addr, cs->cs_initiator_alias,
@@ -1629,7 +1634,8 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci)
 		    cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None",
 		    cs->cs_max_data_segment_length,
 		    cs->cs_immediate_data,
-		    cs->cs_conn->ic_iser);
+		    cs->cs_conn->ic_iser,
+		    cs->cs_conn->ic_offload);
 		if (error != 0)
 			break;
 	}
@@ -1749,6 +1755,26 @@ cfiscsi_ioctl_logout(struct ctl_iscsi *c
 	ci->status = CTL_ISCSI_OK;
 }
 
+static void
+cfiscsi_ioctl_limits(struct ctl_iscsi *ci)
+{
+	struct ctl_iscsi_limits_params *cilp;
+	int error;
+
+	cilp = (struct ctl_iscsi_limits_params *)&(ci->data);
+
+	error = icl_limits(cilp->offload, &cilp->data_segment_limit);
+	if (error != 0) {
+		ci->status = CTL_ISCSI_ERROR;
+		snprintf(ci->error_str, sizeof(ci->error_str),
+			"%s: icl_limits failed with error %d",
+			__func__, error);
+		return;
+	}
+
+	ci->status = CTL_ISCSI_OK;
+}
+
 #ifdef ICL_KERNEL_PROXY
 static void
 cfiscsi_ioctl_listen(struct ctl_iscsi *ci)
@@ -2176,6 +2202,9 @@ cfiscsi_ioctl(struct cdev *dev,
 	case CTL_ISCSI_LOGOUT:
 		cfiscsi_ioctl_logout(ci);
 		break;
+	case CTL_ISCSI_LIMITS:
+		cfiscsi_ioctl_limits(ci);
+		break;
 #ifdef ICL_KERNEL_PROXY
 	case CTL_ISCSI_LISTEN:
 		cfiscsi_ioctl_listen(ci);

Modified: head/sys/cam/ctl/ctl_ioctl.h
==============================================================================
--- head/sys/cam/ctl/ctl_ioctl.h	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/sys/cam/ctl/ctl_ioctl.h	Fri Feb  6 21:03:25 2015	(r278331)
@@ -657,6 +657,7 @@ typedef enum {
 	CTL_ISCSI_LIST,
 	CTL_ISCSI_LOGOUT,
 	CTL_ISCSI_TERMINATE,
+	CTL_ISCSI_LIMITS,
 #if defined(ICL_KERNEL_PROXY) || 1
 	/*
 	 * We actually need those in all cases, but leave the ICL_KERNEL_PROXY,
@@ -677,6 +678,7 @@ typedef enum {
 #define	CTL_ISCSI_NAME_LEN	224	/* 223 bytes, by RFC 3720, + '\0' */
 #define	CTL_ISCSI_ADDR_LEN	47	/* INET6_ADDRSTRLEN + '\0' */
 #define	CTL_ISCSI_ALIAS_LEN	128	/* Arbitrary. */
+#define	CTL_ISCSI_OFFLOAD_LEN	8	/* Arbitrary. */
 
 struct ctl_iscsi_handoff_params {
 	char			initiator_name[CTL_ISCSI_NAME_LEN];
@@ -698,11 +700,12 @@ struct ctl_iscsi_handoff_params {
 	uint32_t		max_burst_length;
 	uint32_t		first_burst_length;
 	uint32_t		immediate_data;
+	char			offload[CTL_ISCSI_OFFLOAD_LEN];
 #ifdef ICL_KERNEL_PROXY
 	int			connection_id;
-	int			spare[3];
+	int			spare[1];
 #else
-	int			spare[4];
+	int			spare[2];
 #endif
 };
 
@@ -733,6 +736,14 @@ struct ctl_iscsi_terminate_params {
 	int			spare[4];
 };
 
+struct ctl_iscsi_limits_params {
+	char			offload[CTL_ISCSI_OFFLOAD_LEN];
+						/* passed to kernel */
+	size_t			data_segment_limit;
+						/* passed to userland */
+	int			spare[4];
+};
+
 #ifdef ICL_KERNEL_PROXY
 struct ctl_iscsi_listen_params {
 	int				iser;
@@ -780,6 +791,7 @@ union ctl_iscsi_data {
 	struct ctl_iscsi_list_params		list;
 	struct ctl_iscsi_logout_params		logout;
 	struct ctl_iscsi_terminate_params	terminate;
+	struct ctl_iscsi_limits_params		limits;
 #ifdef ICL_KERNEL_PROXY
 	struct ctl_iscsi_listen_params		listen;
 	struct ctl_iscsi_accept_params		accept;

Modified: head/usr.sbin/ctladm/ctladm.c
==============================================================================
--- head/usr.sbin/ctladm/ctladm.c	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/usr.sbin/ctladm/ctladm.c	Fri Feb  6 21:03:25 2015	(r278331)
@@ -3439,6 +3439,7 @@ struct cctl_islist_conn {
 	char *header_digest;
 	char *data_digest;
 	char *max_data_segment_length;;
+	char *offload;;
 	int immediate_data;
 	int iser;
 	STAILQ_ENTRY(cctl_islist_conn) links;
@@ -3552,6 +3553,9 @@ cctl_islist_end_element(void *user_data,
 	} else if (strcmp(name, "max_data_segment_length") == 0) {
 		cur_conn->max_data_segment_length = str;
 		str = NULL;
+	} else if (strcmp(name, "offload") == 0) {
+		cur_conn->offload = str;
+		str = NULL;
 	} else if (strcmp(name, "immediate_data") == 0) {
 		cur_conn->immediate_data = atoi(str);
 	} else if (strcmp(name, "iser") == 0) {
@@ -3672,6 +3676,7 @@ retry:
 			printf("DataSegmentLen:   %s\n", conn->max_data_segment_length);
 			printf("ImmediateData:    %s\n", conn->immediate_data ? "Yes" : "No");
 			printf("iSER (RDMA):      %s\n", conn->iser ? "Yes" : "No");
+			printf("Offload driver:   %s\n", conn->offload);
 			printf("\n");
 		}
 	} else {

Modified: head/usr.sbin/ctld/ctl.conf.5
==============================================================================
--- head/usr.sbin/ctld/ctl.conf.5	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/usr.sbin/ctld/ctl.conf.5	Fri Feb  6 21:03:25 2015	(r278331)
@@ -310,6 +310,8 @@ This clause is mutually exclusive with
 .Sy auth-group ;
 one cannot use
 both in a single target.
+.It Ic offload Ar driver
+Define iSCSI hardware offload driver to use for this target.
 .It Ic portal-group Ar name Op Ar agname
 Assign a previously defined portal group to the target.
 The default portal group is

Modified: head/usr.sbin/ctld/ctld.c
==============================================================================
--- head/usr.sbin/ctld/ctld.c	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/usr.sbin/ctld/ctld.c	Fri Feb  6 21:03:25 2015	(r278331)
@@ -1272,6 +1272,22 @@ target_set_redirection(struct target *ta
 	return (0);
 }
 
+int
+target_set_offload(struct target *target, const char *offload)
+{
+
+	if (target->t_offload != NULL) {
+		log_warnx("cannot set offload to \"%s\" for "
+		    "target \"%s\"; already defined",
+		    offload, target->t_name);
+		return (1);
+	}
+
+	target->t_offload = checked_strdup(offload);
+
+	return (0);
+}
+
 struct lun *
 lun_new(struct conf *conf, const char *name)
 {
@@ -1514,6 +1530,8 @@ conf_print(struct conf *conf)
 		fprintf(stderr, "target %s {\n", targ->t_name);
 		if (targ->t_alias != NULL)
 			fprintf(stderr, "\t alias %s\n", targ->t_alias);
+		if (targ->t_offload != NULL)
+			fprintf(stderr, "\t offload %s\n", targ->t_offload);
 		fprintf(stderr, "}\n");
 	}
 }

Modified: head/usr.sbin/ctld/ctld.h
==============================================================================
--- head/usr.sbin/ctld/ctld.h	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/usr.sbin/ctld/ctld.h	Fri Feb  6 21:03:25 2015	(r278331)
@@ -169,6 +169,7 @@ struct target {
 	TAILQ_HEAD(, port)		t_ports;
 	char				*t_name;
 	char				*t_alias;
+	char				*t_offload;
 	char				*t_redirection;
 };
 
@@ -223,6 +224,7 @@ struct connection {
 	struct sockaddr_storage	conn_initiator_sa;
 	uint32_t		conn_cmdsn;
 	uint32_t		conn_statsn;
+	size_t			conn_data_segment_limit;
 	size_t			conn_max_data_segment_length;
 	size_t			conn_max_burst_length;
 	int			conn_immediate_data;
@@ -344,6 +346,8 @@ struct target		*target_find(struct conf 
 			    const char *name);
 int			target_set_redirection(struct target *target,
 			    const char *addr);
+int			target_set_offload(struct target *target,
+			    const char *offload);
 
 struct lun		*lun_new(struct conf *conf, const char *name);
 void			lun_delete(struct lun *lun);
@@ -370,6 +374,8 @@ int			kernel_lun_add(struct lun *lun);
 int			kernel_lun_resize(struct lun *lun);
 int			kernel_lun_remove(struct lun *lun);
 void			kernel_handoff(struct connection *conn);
+void			kernel_limits(const char *offload,
+			    size_t *max_data_segment_length);
 int			kernel_port_add(struct port *port);
 int			kernel_port_update(struct port *port);
 int			kernel_port_remove(struct port *port);

Modified: head/usr.sbin/ctld/kernel.c
==============================================================================
--- head/usr.sbin/ctld/kernel.c	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/usr.sbin/ctld/kernel.c	Fri Feb  6 21:03:25 2015	(r278331)
@@ -799,6 +799,10 @@ kernel_handoff(struct connection *conn)
 	    sizeof(req.data.handoff.initiator_isid));
 	strlcpy(req.data.handoff.target_name,
 	    conn->conn_target->t_name, sizeof(req.data.handoff.target_name));
+	if (conn->conn_target->t_offload != NULL) {
+		strlcpy(req.data.handoff.offload,
+		    conn->conn_target->t_offload, sizeof(req.data.handoff.offload));
+	}
 #ifdef ICL_KERNEL_PROXY
 	if (proxy_mode)
 		req.data.handoff.connection_id = conn->conn_socket;
@@ -831,6 +835,39 @@ kernel_handoff(struct connection *conn)
 	}
 }
 
+void
+kernel_limits(const char *offload, size_t *max_data_segment_length)
+{
+	struct ctl_iscsi req;
+
+	bzero(&req, sizeof(req));
+
+	req.type = CTL_ISCSI_LIMITS;
+	if (offload != NULL) {
+		strlcpy(req.data.limits.offload, offload,
+		    sizeof(req.data.limits.offload));
+	}
+
+	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
+		log_err(1, "error issuing CTL_ISCSI ioctl; "
+		    "dropping connection");
+	}
+
+	if (req.status != CTL_ISCSI_OK) {
+		log_errx(1, "error returned from CTL iSCSI limits request: "
+		    "%s; dropping connection", req.error_str);
+	}
+
+	*max_data_segment_length = req.data.limits.data_segment_limit;
+	if (offload != NULL) {
+		log_debugx("MaxRecvDataSegment kernel limit for offload "
+		    "\"%s\" is %zd", offload, *max_data_segment_length);
+	} else {
+		log_debugx("MaxRecvDataSegment kernel limit is %zd",
+		    *max_data_segment_length);
+	}
+}
+
 int
 kernel_port_add(struct port *port)
 {

Modified: head/usr.sbin/ctld/login.c
==============================================================================
--- head/usr.sbin/ctld/login.c	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/usr.sbin/ctld/login.c	Fri Feb  6 21:03:25 2015	(r278331)
@@ -453,7 +453,8 @@ static void
 login_negotiate_key(struct pdu *request, const char *name,
     const char *value, bool skipped_security, struct keys *response_keys)
 {
-	int which, tmp;
+	int which;
+	size_t tmp;
 	struct connection *conn;
 
 	conn = request->pdu_connection;
@@ -552,13 +553,13 @@ login_negotiate_key(struct pdu *request,
 			log_errx(1, "received invalid "
 			    "MaxRecvDataSegmentLength");
 		}
-		if (tmp > MAX_DATA_SEGMENT_LENGTH) {
+		if (tmp > conn->conn_data_segment_limit) {
 			log_debugx("capping MaxRecvDataSegmentLength "
-			    "from %d to %d", tmp, MAX_DATA_SEGMENT_LENGTH);
-			tmp = MAX_DATA_SEGMENT_LENGTH;
+			    "from %zd to %zd", tmp, conn->conn_data_segment_limit);
+			tmp = conn->conn_data_segment_limit;
 		}
 		conn->conn_max_data_segment_length = tmp;
-		keys_add_int(response_keys, name, MAX_DATA_SEGMENT_LENGTH);
+		keys_add_int(response_keys, name, tmp);
 	} else if (strcmp(name, "MaxBurstLength") == 0) {
 		tmp = strtoul(value, NULL, 10);
 		if (tmp <= 0) {
@@ -566,7 +567,7 @@ login_negotiate_key(struct pdu *request,
 			log_errx(1, "received invalid MaxBurstLength");
 		}
 		if (tmp > MAX_BURST_LENGTH) {
-			log_debugx("capping MaxBurstLength from %d to %d",
+			log_debugx("capping MaxBurstLength from %zd to %d",
 			    tmp, MAX_BURST_LENGTH);
 			tmp = MAX_BURST_LENGTH;
 		}
@@ -579,10 +580,10 @@ login_negotiate_key(struct pdu *request,
 			log_errx(1, "received invalid "
 			    "FirstBurstLength");
 		}
-		if (tmp > MAX_DATA_SEGMENT_LENGTH) {
-			log_debugx("capping FirstBurstLength from %d to %d",
-			    tmp, MAX_DATA_SEGMENT_LENGTH);
-			tmp = MAX_DATA_SEGMENT_LENGTH;
+		if (tmp > conn->conn_data_segment_limit) {
+			log_debugx("capping FirstBurstLength from %zd to %zd",
+			    tmp, conn->conn_data_segment_limit);
+			tmp = conn->conn_data_segment_limit;
 		}
 		/*
 		 * We don't pass the value to the kernel; it only enforces
@@ -680,6 +681,18 @@ login_negotiate(struct connection *conn,
 	int i;
 	bool redirected, skipped_security;
 
+	if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
+		/*
+		 * Query the kernel for MaxDataSegmentLength it can handle.
+		 * In case of offload, it depends on hardware capabilities.
+		 */
+		assert(conn->conn_target != NULL);
+		kernel_limits(conn->conn_target->t_offload,
+		    &conn->conn_data_segment_limit);
+	} else {
+		conn->conn_data_segment_limit = MAX_DATA_SEGMENT_LENGTH;
+	}
+
 	if (request == NULL) {
 		log_debugx("beginning operational parameter negotiation; "
 		    "waiting for Login PDU");

Modified: head/usr.sbin/ctld/parse.y
==============================================================================
--- head/usr.sbin/ctld/parse.y	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/usr.sbin/ctld/parse.y	Fri Feb  6 21:03:25 2015	(r278331)
@@ -60,7 +60,7 @@ extern void	yyrestart(FILE *);
 %token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
 %token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER
 %token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT
-%token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION
+%token LISTEN LISTEN_ISER LUN MAXPROC OFFLOAD OPENING_BRACKET OPTION
 %token PATH PIDFILE PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR
 %token TARGET TIMEOUT 
 
@@ -463,6 +463,8 @@ target_entry:
 	|
 	target_initiator_portal
 	|
+	target_offload
+	|
 	target_portal_group
 	|
 	target_redirect
@@ -652,6 +654,17 @@ target_initiator_portal:	INITIATOR_PORTA
 	}
 	;
 
+target_offload:	OFFLOAD STR
+	{
+		int error;
+
+		error = target_set_offload(target, $2);
+		free($2);
+		if (error != 0)
+			return (1);
+	}
+	;
+
 target_portal_group:	PORTAL_GROUP STR STR
 	{
 		struct portal_group *tpg;

Modified: head/usr.sbin/ctld/token.l
==============================================================================
--- head/usr.sbin/ctld/token.l	Fri Feb  6 20:52:01 2015	(r278330)
+++ head/usr.sbin/ctld/token.l	Fri Feb  6 21:03:25 2015	(r278331)
@@ -65,6 +65,7 @@ listen			{ return LISTEN; }
 listen-iser		{ return LISTEN_ISER; }
 lun			{ return LUN; }
 maxproc			{ return MAXPROC; }
+offload			{ return OFFLOAD; }
 option			{ return OPTION; }
 path			{ return PATH; }
 pidfile			{ return PIDFILE; }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201502062103.t16L3Qke032931>