changeset 10261:f3fec2334981

6740060 iscsit does not send or handle MaxRecvDataSegmentLength key properly 6862789 memory leak in stmfGetSessionList()
author Charles Ting <Charles.Ting@Sun.COM>
date Wed, 05 Aug 2009 15:31:33 -0400
parents 2896314db48b
children f0a682e100e9
files usr/src/lib/libstmf/common/stmf.c usr/src/uts/common/io/comstar/port/iscsit/iscsit.h usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c usr/src/uts/common/io/ib/clients/iser/iser_idm.c usr/src/uts/common/io/idm/idm.c usr/src/uts/common/io/idm/idm_so.c usr/src/uts/common/sys/idm/idm.h usr/src/uts/common/sys/idm/idm_impl.h usr/src/uts/common/sys/idm/idm_transport.h
diffstat 9 files changed, 206 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/libstmf/common/stmf.c	Wed Aug 05 11:20:52 2009 -0700
+++ b/usr/src/lib/libstmf/common/stmf.c	Wed Aug 05 15:31:33 2009 -0400
@@ -3541,7 +3541,7 @@
 	int cmd = STMF_IOCTL_SESSION_LIST;
 	int i;
 	stmf_iocdata_t stmfIoctl;
-	slist_scsi_session_t *fSessionList;
+	slist_scsi_session_t *fSessionList, *fSessionListP = NULL;
 	uint8_t ident[260];
 	uint32_t fSessionListSize;
 
@@ -3567,8 +3567,10 @@
 	fSessionListSize = ALLOC_SESSION;
 	fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t));
 	fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize);
+	fSessionListP = fSessionList;
 	if (fSessionList == NULL) {
-		return (STMF_ERROR_NOMEM);
+		ret = STMF_ERROR_NOMEM;
+		goto done;
 	}
 
 	ident[IDENT_LENGTH_BYTE] = devid->identLength;
@@ -3611,8 +3613,10 @@
 		    sizeof (slist_scsi_session_t);
 		fSessionList = realloc(fSessionList, fSessionListSize);
 		if (fSessionList == NULL) {
-			return (STMF_ERROR_NOMEM);
+			ret = STMF_ERROR_NOMEM;
+			goto done;
 		}
+		fSessionListP = fSessionList;
 		stmfIoctl.stmf_obuf_size = fSessionListSize;
 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
 		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
@@ -3667,6 +3671,7 @@
 	}
 done:
 	(void) close(fd);
+	free(fSessionListP);
 	return (ret);
 }
 
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h	Wed Aug 05 11:20:52 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h	Wed Aug 05 15:31:33 2009 -0400
@@ -44,6 +44,7 @@
 #define	ISCSIT_MAX_TIME2RETAIN			ISCSI_DEFAULT_TIME_TO_RETAIN
 #define	ISCSIT_MAX_OUTSTANDING_R2T		ISCSI_DEFAULT_MAX_OUT_R2T
 #define	ISCSIT_MAX_ERROR_RECOVERY_LEVEL		0
+#define	ISCSIT_MAX_OUTSTANDING_UNEXPECTED_PDUS	0
 
 #define	ISCSIT_DEFAULT_TPG	"iscsit-default-tpg"
 #define	ISCSIT_DEFAULT_TPGT	1
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c	Wed Aug 05 11:20:52 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c	Wed Aug 05 15:31:33 2009 -0400
@@ -189,6 +189,11 @@
 static void
 login_resp_complete_cb(idm_pdu_t *pdu, idm_status_t status);
 
+static idm_status_t
+iscsit_add_declarative_keys(iscsit_conn_t *ict);
+
+uint64_t max_dataseglen_target = ISCSIT_MAX_RECV_DATA_SEGMENT_LENGTH;
+
 idm_status_t
 iscsit_login_sm_init(iscsit_conn_t *ict)
 {
@@ -1000,6 +1005,10 @@
 			(void) iscsit_reply_numerical(ict,
 			    "TargetPortalGroupTag",
 			    (uint64_t)lsm->icl_tpgt_tag);
+			if (iscsit_add_declarative_keys(ict) !=
+			    IDM_STATUS_SUCCESS) {
+				goto request_fail;
+			}
 		}
 
 		ict->ict_op.op_initial_params_set = B_TRUE;
@@ -2261,11 +2270,12 @@
 		    ISCSI_MAX_CONNECTIONS,
 		    ISCSIT_MAX_CONNECTIONS);
 		break;
+		/* this is a declartive param */
 	case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
 		kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx,
 		    ISCSI_MIN_RECV_DATA_SEGMENT_LENGTH,
 		    ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH,
-		    ISCSIT_MAX_RECV_DATA_SEGMENT_LENGTH);
+		    ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
 		break;
 	case KI_MAX_BURST_LENGTH:
 		kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx,
@@ -2412,22 +2422,27 @@
 	kv_status_t		kvrc;
 	int			nvrc;
 
-	if (value != iscsit_value) {
-		/* Respond back to initiator with our value */
-		value = iscsit_value;
-		lsm->icl_login_transit = B_FALSE;
-		nvrc = 0;
+	if (ikvx->ik_declarative) {
+		nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, nvp);
 	} else {
-		/* Add this to our negotiated values */
-		nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values,
-		    nvp);
+		if (value != iscsit_value) {
+			/* Respond back to initiator with our value */
+			value = iscsit_value;
+			lsm->icl_login_transit = B_FALSE;
+			nvrc = 0;
+		} else {
+			/* Add this to our negotiated values */
+			nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values,
+			    nvp);
+		}
+
+		/* Response of Simple-value Negotiation */
+		if (nvrc == 0) {
+			nvrc = nvlist_add_boolean_value(
+			    lsm->icl_response_nvlist, ikvx->ik_key_name, value);
+		}
 	}
 
-	/* Response of Simple-value Negotiation */
-	if (nvrc == 0 && !ikvx->ik_declarative) {
-		nvrc = nvlist_add_boolean_value(
-		    lsm->icl_response_nvlist, ikvx->ik_key_name, value);
-	}
 	kvrc = idm_nvstat_to_kvstat(nvrc);
 
 	return (kvrc);
@@ -2446,6 +2461,9 @@
 	/* Validate against standard */
 	if ((value < iscsi_min_value) || (value > iscsi_max_value)) {
 		kvrc = KV_VALUE_ERROR;
+	} else if (ikvx->ik_declarative) {
+		nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, nvp);
+		kvrc = idm_nvstat_to_kvstat(nvrc);
 	} else {
 		if (value > iscsit_max_value) {
 			/* Respond back to initiator with our value */
@@ -2459,7 +2477,7 @@
 		}
 
 		/* Response of Simple-value Negotiation */
-		if (nvrc == 0 && !ikvx->ik_declarative) {
+		if (nvrc == 0) {
 			nvrc = nvlist_add_uint64(lsm->icl_response_nvlist,
 			    ikvx->ik_key_name, value);
 		}
@@ -2577,3 +2595,44 @@
 		ict->ict_op.op_error_recovery_level = uint64_val;
 	}
 }
+
+static idm_status_t
+iscsit_add_declarative_keys(iscsit_conn_t *ict)
+{
+	nvlist_t		*cfg_nv = NULL;
+	kv_status_t		kvrc;
+	int			nvrc;
+	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
+	uint8_t			error_class;
+	uint8_t			error_detail;
+	idm_status_t		idm_status;
+
+	if ((nvrc = nvlist_alloc(&cfg_nv, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
+		kvrc = idm_nvstat_to_kvstat(nvrc);
+		goto alloc_fail;
+	}
+	if ((nvrc = nvlist_add_uint64(cfg_nv, "MaxRecvDataSegmentLength",
+	    max_dataseglen_target)) != 0) {
+		kvrc = idm_nvstat_to_kvstat(nvrc);
+		goto done;
+	}
+	if ((nvrc = nvlist_add_uint64(cfg_nv, "MaxOutstandingUnexpectedPDUs",
+	    ISCSIT_MAX_OUTSTANDING_UNEXPECTED_PDUS)) != 0) {
+		kvrc = idm_nvstat_to_kvstat(nvrc);
+		goto done;
+	}
+
+	kvrc = idm_declare_key_values(ict->ict_ic, cfg_nv,
+	    lsm->icl_response_nvlist);
+done:
+	nvlist_free(cfg_nv);
+alloc_fail:
+	idm_kvstat_to_error(kvrc, &error_class, &error_detail);
+	if (error_class == ISCSI_STATUS_CLASS_SUCCESS) {
+		idm_status = IDM_STATUS_SUCCESS;
+	} else {
+		SET_LOGIN_ERROR(ict, error_class, error_detail);
+		idm_status = IDM_STATUS_FAIL;
+	}
+	return (idm_status);
+}
--- a/usr/src/uts/common/io/ib/clients/iser/iser_idm.c	Wed Aug 05 11:20:52 2009 -0700
+++ b/usr/src/uts/common/io/ib/clients/iser/iser_idm.c	Wed Aug 05 15:31:33 2009 -0400
@@ -48,6 +48,8 @@
 static idm_status_t iser_ini_enable_datamover(idm_conn_t *ic);
 static void iser_notice_key_values(struct idm_conn_s *ic,
     nvlist_t *negotiated_nvl);
+static kv_status_t iser_declare_key_values(struct idm_conn_s *ic,
+    nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
 static idm_status_t iser_free_task_rsrcs(idm_task_t *idt);
 static kv_status_t iser_negotiate_key_values(idm_conn_t *ic,
     nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
@@ -114,7 +116,8 @@
 	&iser_ini_conn_create,		/* it_ini_conn_create */
 	&iser_conn_destroy,		/* it_ini_conn_destroy */
 	&iser_ini_conn_connect,		/* it_ini_conn_connect */
-	&iser_conn_disconnect		/* it_ini_conn_disconnect */
+	&iser_conn_disconnect,		/* it_ini_conn_disconnect */
+	&iser_declare_key_values	/* it_declare_key_values */
 };
 
 /*
@@ -841,6 +844,31 @@
 }
 
 /*
+ * iser_declare_key_values() declares the declarative key values for
+ * this connection.
+ */
+/* ARGSUSED */
+static kv_status_t
+iser_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl,
+    nvlist_t *outgoing_nvl)
+{
+	kv_status_t		kvrc;
+	int			nvrc;
+	uint64_t		uint64_val;
+
+	if ((nvrc = nvlist_lookup_uint64(config_nvl,
+	    ISER_KV_KEY_NAME_MAX_OUTSTANDING_PDU, &uint64_val)) != ENOENT) {
+		ASSERT(nvrc == 0);
+		if (outgoing_nvl) {
+			nvrc = nvlist_add_uint64(outgoing_nvl,
+			    ISER_KV_KEY_NAME_MAX_OUTSTANDING_PDU, uint64_val);
+		}
+	}
+	kvrc = idm_nvstat_to_kvstat(nvrc);
+	return (kvrc);
+}
+
+/*
  * iser_notice_key_values() activates the negotiated key values for
  * this connection.
  */
--- a/usr/src/uts/common/io/idm/idm.c	Wed Aug 05 11:20:52 2009 -0700
+++ b/usr/src/uts/common/io/idm/idm.c	Wed Aug 05 15:31:33 2009 -0400
@@ -656,6 +656,20 @@
 }
 
 /*
+ * idm_declare_key_values()
+ * Activate an operational set of declarative parameters from the config_nvl,
+ * and return the selected values in the outgoing_nvl.
+ */
+kv_status_t
+idm_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl,
+    nvlist_t *outgoing_nvl)
+{
+	ASSERT(ic->ic_transport_ops != NULL);
+	return (ic->ic_transport_ops->it_declare_key_values(ic, config_nvl,
+	    outgoing_nvl));
+}
+
+/*
  * idm_buf_tx_to_ini
  *
  * This is IDM's implementation of the 'Put_Data' operational primitive.
--- a/usr/src/uts/common/io/idm/idm_so.c	Wed Aug 05 11:20:52 2009 -0700
+++ b/usr/src/uts/common/io/idm/idm_so.c	Wed Aug 05 15:31:33 2009 -0400
@@ -46,6 +46,7 @@
 #include <net/if.h>
 #include <sys/sockio.h>
 #include <sys/ksocket.h>
+#include <sys/iscsi_protocol.h>
 #include <sys/idm/idm.h>
 #include <sys/idm/idm_so.h>
 #include <sys/idm/idm_text.h>
@@ -101,6 +102,8 @@
     nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
 static void idm_so_notice_key_values(idm_conn_t *it,
     nvlist_t *negotiated_nvl);
+static kv_status_t idm_so_declare_key_values(idm_conn_t *it,
+    nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
 static boolean_t idm_so_conn_is_capable(idm_conn_req_t *ic,
     idm_transport_caps_t *caps);
 static idm_status_t idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen);
@@ -152,7 +155,8 @@
 	idm_so_ini_conn_create,		/* it_ini_conn_create */
 	idm_so_ini_conn_destroy,	/* it_ini_conn_destroy */
 	idm_so_ini_conn_connect,	/* it_ini_conn_connect */
-	idm_so_conn_disconnect		/* it_ini_conn_disconnect */
+	idm_so_conn_disconnect,		/* it_ini_conn_disconnect */
+	idm_so_declare_key_values	/* it_declare_key_values */
 };
 
 /*
@@ -760,6 +764,12 @@
 	pdu->isp_hdrlen = sizeof (iscsi_hdr_t) +
 	    (bhs->hlength * sizeof (uint32_t));
 	pdu->isp_datalen = n2h24(bhs->dlength);
+	if (ic->ic_conn_type == CONN_TYPE_TGT &&
+	    pdu->isp_datalen > ic->ic_conn_params.max_recv_dataseglen) {
+		IDM_CONN_LOG(CE_WARN,
+		    "idm_sorecvhdr: exceeded the max data segment length");
+		return (IDM_STATUS_FAIL);
+	}
 	if (bhs->hlength > IDM_SORX_CACHE_AHSLEN) {
 		/* Allocate a new header segment and change the callback */
 		new_hdr = kmem_alloc(pdu->isp_hdrlen, KM_SLEEP);
@@ -985,6 +995,10 @@
 
 	/* Set the scoreboarding flag on this connection */
 	ic->ic_conn_flags |= IDM_CONN_USE_SCOREBOARD;
+	ic->ic_conn_params.max_recv_dataseglen =
+	    ISCSI_DEFAULT_MAX_RECV_SEG_LEN;
+	ic->ic_conn_params.max_xmit_dataseglen =
+	    ISCSI_DEFAULT_MAX_XMIT_SEG_LEN;
 
 	/*
 	 * Initialize tx thread mutex and list
@@ -1380,6 +1394,7 @@
 	int			nvrc;
 	idm_status_t		idm_status;
 	const idm_kv_xlate_t	*ikvx;
+	uint64_t		num_val;
 
 	for (nvp = nvlist_next_nvpair(negotiated_nvl, NULL);
 	    nvp != NULL; nvp = next_nvp) {
@@ -1398,12 +1413,64 @@
 			    negotiated_nvl, ikvx->ik_key_name);
 			ASSERT(nvrc == 0);
 			break;
+		case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
+			/*
+			 * Just pass the value down to idm layer.
+			 * No need to remove it from negotiated_nvl list here.
+			 */
+			nvrc = nvpair_value_uint64(nvp, &num_val);
+			ASSERT(nvrc == 0);
+			it->ic_conn_params.max_xmit_dataseglen =
+			    (uint32_t)num_val;
+			break;
 		default:
 			break;
 		}
 	}
 }
 
+/*
+ * idm_so_declare_key_values() declares the key values for this connection
+ */
+/* ARGSUSED */
+static kv_status_t
+idm_so_declare_key_values(idm_conn_t *it, nvlist_t *config_nvl,
+    nvlist_t *outgoing_nvl)
+{
+	char			*nvp_name;
+	nvpair_t		*nvp;
+	nvpair_t		*next_nvp;
+	kv_status_t		kvrc;
+	int			nvrc = 0;
+	const idm_kv_xlate_t	*ikvx;
+	uint64_t		num_val;
+
+	for (nvp = nvlist_next_nvpair(config_nvl, NULL);
+	    nvp != NULL && nvrc == 0; nvp = next_nvp) {
+		next_nvp = nvlist_next_nvpair(config_nvl, nvp);
+		nvp_name = nvpair_name(nvp);
+
+		ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name));
+		switch (ikvx->ik_key_id) {
+		case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
+			if ((nvrc = nvpair_value_uint64(nvp, &num_val)) != 0) {
+				break;
+			}
+			if (outgoing_nvl &&
+			    (nvrc = nvlist_add_uint64(outgoing_nvl,
+			    nvp_name, num_val)) != 0) {
+				break;
+			}
+			it->ic_conn_params.max_recv_dataseglen =
+			    (uint32_t)num_val;
+			break;
+		default:
+			break;
+		}
+	}
+	kvrc = idm_nvstat_to_kvstat(nvrc);
+	return (kvrc);
+}
 
 static idm_status_t
 idm_so_handle_digest(idm_conn_t *it, nvpair_t *digest_choice,
@@ -2489,7 +2556,7 @@
 
 	ic = idt->idt_ic;
 
-	max_dataseglen = 8192; /* Need value from login negotiation */
+	max_dataseglen = ic->ic_conn_params.max_xmit_dataseglen;
 	remainder = buf_region_length;
 
 	while (remainder) {
--- a/usr/src/uts/common/sys/idm/idm.h	Wed Aug 05 11:20:52 2009 -0700
+++ b/usr/src/uts/common/sys/idm/idm.h	Wed Aug 05 15:31:33 2009 -0400
@@ -380,6 +380,10 @@
 void
 idm_notice_key_values(idm_conn_t *ic, nvlist_t *negotiated_nvl);
 
+kv_status_t
+idm_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl,
+    nvlist_t *outgoing_nvl);
+
 /*
  * Buffer services
  */
--- a/usr/src/uts/common/sys/idm/idm_impl.h	Wed Aug 05 11:20:52 2009 -0700
+++ b/usr/src/uts/common/sys/idm/idm_impl.h	Wed Aug 05 15:31:33 2009 -0400
@@ -122,7 +122,8 @@
  * connection create, or during key-value negotiation at login
  */
 typedef struct idm_conn_params_s {
-	uint32_t		max_dataseglen;
+	uint32_t		max_recv_dataseglen;
+	uint32_t		max_xmit_dataseglen;
 	uint32_t		conn_login_max;
 	uint32_t		conn_login_interval;
 	boolean_t		nonblock_socket;
--- a/usr/src/uts/common/sys/idm/idm_transport.h	Wed Aug 05 11:20:52 2009 -0700
+++ b/usr/src/uts/common/sys/idm/idm_transport.h	Wed Aug 05 15:31:33 2009 -0400
@@ -109,6 +109,10 @@
 typedef void (transport_notice_key_values_op_t)(struct idm_conn_s *ic,
     nvlist_t *negotiated_nvl);
 
+/* Declare the declarative key value pairs */
+typedef kv_status_t (transport_declare_key_values_op_t)(struct idm_conn_s *ic,
+    nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
+
 /* Transport capability probe */
 typedef boolean_t (transport_conn_is_capable_op_t)(idm_conn_req_t *ic,
     struct idm_transport_caps_s *caps);
@@ -178,6 +182,7 @@
 	transport_ini_conn_destroy_op_t		*it_ini_conn_destroy;
 	transport_ini_conn_connect_op_t		*it_ini_conn_connect;
 	transport_ini_conn_disconnect_op_t	*it_ini_conn_disconnect;
+	transport_declare_key_values_op_t	*it_declare_key_values;
 } idm_transport_ops_t;
 
 /*