Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target...
[firefly-linux-kernel-4.4.55.git] / drivers / target / iscsi / iscsi_target_parameters.c
index 240f7aa76ed1cfd962c6a16fd7eed27701023ee5..90b740048f26ee7151eda956b092e12fad74e70c 100644 (file)
@@ -334,6 +334,13 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
        if (!param)
                goto out;
 
+       param = iscsi_set_default_param(pl, MAXXMITDATASEGMENTLENGTH,
+                       INITIAL_MAXXMITDATASEGMENTLENGTH,
+                       PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_512_TO_16777215, USE_ALL);
+       if (!param)
+               goto out;
+
        param = iscsi_set_default_param(pl, MAXRECVDATASEGMENTLENGTH,
                        INITIAL_MAXRECVDATASEGMENTLENGTH,
                        PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
@@ -467,6 +474,8 @@ int iscsi_set_keys_to_negotiate(
                        SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
                        SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
+                       continue;
                } else if (!strcmp(param->name, MAXBURSTLENGTH)) {
                        SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, FIRSTBURSTLENGTH)) {
@@ -1056,7 +1065,8 @@ out:
        return proposer_values;
 }
 
-static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value)
+static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value,
+                               struct iscsi_conn *conn)
 {
        u8 acceptor_boolean_value = 0, proposer_boolean_value = 0;
        char *negoitated_value = NULL;
@@ -1131,8 +1141,35 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value)
                                return -1;
                }
 
-               if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
-                       SET_PSTATE_REPLY_OPTIONAL(param);
+               if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
+                       struct iscsi_param *param_mxdsl;
+                       unsigned long long tmp;
+                       int rc;
+
+                       rc = strict_strtoull(param->value, 0, &tmp);
+                       if (rc < 0)
+                               return -1;
+
+                       conn->conn_ops->MaxRecvDataSegmentLength = tmp;
+                       pr_debug("Saving op->MaxRecvDataSegmentLength from"
+                               " original initiator received value: %u\n",
+                               conn->conn_ops->MaxRecvDataSegmentLength);
+
+                       param_mxdsl = iscsi_find_param_from_key(
+                                               MAXXMITDATASEGMENTLENGTH,
+                                               conn->param_list);
+                       if (!param_mxdsl)
+                               return -1;
+
+                       rc = iscsi_update_param_value(param,
+                                               param_mxdsl->value);
+                       if (rc < 0)
+                               return -1;
+
+                       pr_debug("Updated %s to target MXDSL value: %s\n",
+                                       param->name, param->value);
+               }
+
        } else if (IS_TYPE_NUMBER_RANGE(param)) {
                negoitated_value = iscsi_get_value_from_number_range(
                                        param, value);
@@ -1526,8 +1563,9 @@ int iscsi_decode_text_input(
        u8 sender,
        char *textbuf,
        u32 length,
-       struct iscsi_param_list *param_list)
+       struct iscsi_conn *conn)
 {
+       struct iscsi_param_list *param_list = conn->param_list;
        char *tmpbuf, *start = NULL, *end = NULL;
 
        tmpbuf = kzalloc(length + 1, GFP_KERNEL);
@@ -1585,7 +1623,7 @@ int iscsi_decode_text_input(
                        }
                        SET_PSTATE_RESPONSE_GOT(param);
                } else {
-                       if (iscsi_check_acceptor_state(param, value) < 0) {
+                       if (iscsi_check_acceptor_state(param, value, conn) < 0) {
                                kfree(tmpbuf);
                                return -1;
                        }
@@ -1720,6 +1758,18 @@ void iscsi_set_connection_parameters(
        pr_debug("---------------------------------------------------"
                        "---------------\n");
        list_for_each_entry(param, &param_list->param_list, p_list) {
+               /*
+                * Special case to set MAXXMITDATASEGMENTLENGTH from the
+                * target requested MaxRecvDataSegmentLength, even though
+                * this key is not sent over the wire.
+                */
+               if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
+                       ops->MaxXmitDataSegmentLength =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("MaxXmitDataSegmentLength:     %s\n",
+                               param->value);
+               }
+
                if (!IS_PSTATE_ACCEPTOR(param) && !IS_PSTATE_PROPOSER(param))
                        continue;
                if (!strcmp(param->name, AUTHMETHOD)) {
@@ -1734,10 +1784,13 @@ void iscsi_set_connection_parameters(
                        pr_debug("DataDigest:                   %s\n",
                                param->value);
                } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
-                       ops->MaxRecvDataSegmentLength =
-                               simple_strtoul(param->value, &tmpptr, 0);
-                       pr_debug("MaxRecvDataSegmentLength:     %s\n",
-                               param->value);
+                       /*
+                        * At this point iscsi_check_acceptor_state() will have
+                        * set ops->MaxRecvDataSegmentLength from the original
+                        * initiator provided value.
+                        */
+                       pr_debug("MaxRecvDataSegmentLength:     %u\n",
+                               ops->MaxRecvDataSegmentLength);
                } else if (!strcmp(param->name, OFMARKER)) {
                        ops->OFMarker = !strcmp(param->value, YES);
                        pr_debug("OFMarker:                     %s\n",