Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*******************************************************************************
0003  * This file contains the iSCSI Target DataIN value generation functions.
0004  *
0005  * (c) Copyright 2007-2013 Datera, Inc.
0006  *
0007  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
0008  *
0009  ******************************************************************************/
0010 
0011 #include <linux/slab.h>
0012 #include <scsi/iscsi_proto.h>
0013 #include <target/iscsi/iscsi_target_core.h>
0014 #include "iscsi_target_seq_pdu_list.h"
0015 #include "iscsi_target_erl1.h"
0016 #include "iscsi_target_util.h"
0017 #include "iscsi_target.h"
0018 #include "iscsi_target_datain_values.h"
0019 
0020 struct iscsi_datain_req *iscsit_allocate_datain_req(void)
0021 {
0022     struct iscsi_datain_req *dr;
0023 
0024     dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC);
0025     if (!dr) {
0026         pr_err("Unable to allocate memory for"
0027                 " struct iscsi_datain_req\n");
0028         return NULL;
0029     }
0030     INIT_LIST_HEAD(&dr->cmd_datain_node);
0031 
0032     return dr;
0033 }
0034 
0035 void iscsit_attach_datain_req(struct iscsit_cmd *cmd, struct iscsi_datain_req *dr)
0036 {
0037     spin_lock(&cmd->datain_lock);
0038     list_add_tail(&dr->cmd_datain_node, &cmd->datain_list);
0039     spin_unlock(&cmd->datain_lock);
0040 }
0041 
0042 void iscsit_free_datain_req(struct iscsit_cmd *cmd, struct iscsi_datain_req *dr)
0043 {
0044     spin_lock(&cmd->datain_lock);
0045     list_del(&dr->cmd_datain_node);
0046     spin_unlock(&cmd->datain_lock);
0047 
0048     kmem_cache_free(lio_dr_cache, dr);
0049 }
0050 
0051 void iscsit_free_all_datain_reqs(struct iscsit_cmd *cmd)
0052 {
0053     struct iscsi_datain_req *dr, *dr_tmp;
0054 
0055     spin_lock(&cmd->datain_lock);
0056     list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) {
0057         list_del(&dr->cmd_datain_node);
0058         kmem_cache_free(lio_dr_cache, dr);
0059     }
0060     spin_unlock(&cmd->datain_lock);
0061 }
0062 
0063 struct iscsi_datain_req *iscsit_get_datain_req(struct iscsit_cmd *cmd)
0064 {
0065     if (list_empty(&cmd->datain_list)) {
0066         pr_err("cmd->datain_list is empty for ITT:"
0067             " 0x%08x\n", cmd->init_task_tag);
0068         return NULL;
0069     }
0070 
0071     return list_first_entry(&cmd->datain_list, struct iscsi_datain_req,
0072                 cmd_datain_node);
0073 }
0074 
0075 /*
0076  *  For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.
0077  */
0078 static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(
0079     struct iscsit_cmd *cmd,
0080     struct iscsi_datain *datain)
0081 {
0082     u32 next_burst_len, read_data_done, read_data_left;
0083     struct iscsit_conn *conn = cmd->conn;
0084     struct iscsi_datain_req *dr;
0085 
0086     dr = iscsit_get_datain_req(cmd);
0087     if (!dr)
0088         return NULL;
0089 
0090     if (dr->recovery && dr->generate_recovery_values) {
0091         if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
0092                     cmd, dr) < 0)
0093             return NULL;
0094 
0095         dr->generate_recovery_values = 0;
0096     }
0097 
0098     next_burst_len = (!dr->recovery) ?
0099             cmd->next_burst_len : dr->next_burst_len;
0100     read_data_done = (!dr->recovery) ?
0101             cmd->read_data_done : dr->read_data_done;
0102 
0103     read_data_left = (cmd->se_cmd.data_length - read_data_done);
0104     if (!read_data_left) {
0105         pr_err("ITT: 0x%08x read_data_left is zero!\n",
0106                 cmd->init_task_tag);
0107         return NULL;
0108     }
0109 
0110     if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) &&
0111         (read_data_left <= (conn->sess->sess_ops->MaxBurstLength -
0112          next_burst_len))) {
0113         datain->length = read_data_left;
0114 
0115         datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
0116         if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
0117             datain->flags |= ISCSI_FLAG_DATA_ACK;
0118     } else {
0119         if ((next_burst_len +
0120              conn->conn_ops->MaxRecvDataSegmentLength) <
0121              conn->sess->sess_ops->MaxBurstLength) {
0122             datain->length =
0123                 conn->conn_ops->MaxRecvDataSegmentLength;
0124             next_burst_len += datain->length;
0125         } else {
0126             datain->length = (conn->sess->sess_ops->MaxBurstLength -
0127                       next_burst_len);
0128             next_burst_len = 0;
0129 
0130             datain->flags |= ISCSI_FLAG_CMD_FINAL;
0131             if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
0132                 datain->flags |= ISCSI_FLAG_DATA_ACK;
0133         }
0134     }
0135 
0136     datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
0137     datain->offset = read_data_done;
0138 
0139     if (!dr->recovery) {
0140         cmd->next_burst_len = next_burst_len;
0141         cmd->read_data_done += datain->length;
0142     } else {
0143         dr->next_burst_len = next_burst_len;
0144         dr->read_data_done += datain->length;
0145     }
0146 
0147     if (!dr->recovery) {
0148         if (datain->flags & ISCSI_FLAG_DATA_STATUS)
0149             dr->dr_complete = DATAIN_COMPLETE_NORMAL;
0150 
0151         return dr;
0152     }
0153 
0154     if (!dr->runlength) {
0155         if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
0156             dr->dr_complete =
0157                 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
0158                 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
0159                 DATAIN_COMPLETE_CONNECTION_RECOVERY;
0160         }
0161     } else {
0162         if ((dr->begrun + dr->runlength) == dr->data_sn) {
0163             dr->dr_complete =
0164                 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
0165                 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
0166                 DATAIN_COMPLETE_CONNECTION_RECOVERY;
0167         }
0168     }
0169 
0170     return dr;
0171 }
0172 
0173 /*
0174  *  For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes.
0175  */
0176 static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
0177     struct iscsit_cmd *cmd,
0178     struct iscsi_datain *datain)
0179 {
0180     u32 offset, read_data_done, read_data_left, seq_send_order;
0181     struct iscsit_conn *conn = cmd->conn;
0182     struct iscsi_datain_req *dr;
0183     struct iscsi_seq *seq;
0184 
0185     dr = iscsit_get_datain_req(cmd);
0186     if (!dr)
0187         return NULL;
0188 
0189     if (dr->recovery && dr->generate_recovery_values) {
0190         if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
0191                     cmd, dr) < 0)
0192             return NULL;
0193 
0194         dr->generate_recovery_values = 0;
0195     }
0196 
0197     read_data_done = (!dr->recovery) ?
0198             cmd->read_data_done : dr->read_data_done;
0199     seq_send_order = (!dr->recovery) ?
0200             cmd->seq_send_order : dr->seq_send_order;
0201 
0202     read_data_left = (cmd->se_cmd.data_length - read_data_done);
0203     if (!read_data_left) {
0204         pr_err("ITT: 0x%08x read_data_left is zero!\n",
0205                 cmd->init_task_tag);
0206         return NULL;
0207     }
0208 
0209     seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
0210     if (!seq)
0211         return NULL;
0212 
0213     seq->sent = 1;
0214 
0215     if (!dr->recovery && !seq->next_burst_len)
0216         seq->first_datasn = cmd->data_sn;
0217 
0218     offset = (seq->offset + seq->next_burst_len);
0219 
0220     if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
0221          cmd->se_cmd.data_length) {
0222         datain->length = (cmd->se_cmd.data_length - offset);
0223         datain->offset = offset;
0224 
0225         datain->flags |= ISCSI_FLAG_CMD_FINAL;
0226         if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
0227             datain->flags |= ISCSI_FLAG_DATA_ACK;
0228 
0229         seq->next_burst_len = 0;
0230         seq_send_order++;
0231     } else {
0232         if ((seq->next_burst_len +
0233              conn->conn_ops->MaxRecvDataSegmentLength) <
0234              conn->sess->sess_ops->MaxBurstLength) {
0235             datain->length =
0236                 conn->conn_ops->MaxRecvDataSegmentLength;
0237             datain->offset = (seq->offset + seq->next_burst_len);
0238 
0239             seq->next_burst_len += datain->length;
0240         } else {
0241             datain->length = (conn->sess->sess_ops->MaxBurstLength -
0242                       seq->next_burst_len);
0243             datain->offset = (seq->offset + seq->next_burst_len);
0244 
0245             datain->flags |= ISCSI_FLAG_CMD_FINAL;
0246             if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
0247                 datain->flags |= ISCSI_FLAG_DATA_ACK;
0248 
0249             seq->next_burst_len = 0;
0250             seq_send_order++;
0251         }
0252     }
0253 
0254     if ((read_data_done + datain->length) == cmd->se_cmd.data_length)
0255         datain->flags |= ISCSI_FLAG_DATA_STATUS;
0256 
0257     datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
0258     if (!dr->recovery) {
0259         cmd->seq_send_order = seq_send_order;
0260         cmd->read_data_done += datain->length;
0261     } else {
0262         dr->seq_send_order = seq_send_order;
0263         dr->read_data_done += datain->length;
0264     }
0265 
0266     if (!dr->recovery) {
0267         if (datain->flags & ISCSI_FLAG_CMD_FINAL)
0268             seq->last_datasn = datain->data_sn;
0269         if (datain->flags & ISCSI_FLAG_DATA_STATUS)
0270             dr->dr_complete = DATAIN_COMPLETE_NORMAL;
0271 
0272         return dr;
0273     }
0274 
0275     if (!dr->runlength) {
0276         if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
0277             dr->dr_complete =
0278                 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
0279                 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
0280                 DATAIN_COMPLETE_CONNECTION_RECOVERY;
0281         }
0282     } else {
0283         if ((dr->begrun + dr->runlength) == dr->data_sn) {
0284             dr->dr_complete =
0285                 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
0286                 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
0287                 DATAIN_COMPLETE_CONNECTION_RECOVERY;
0288         }
0289     }
0290 
0291     return dr;
0292 }
0293 
0294 /*
0295  *  For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No.
0296  */
0297 static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
0298     struct iscsit_cmd *cmd,
0299     struct iscsi_datain *datain)
0300 {
0301     u32 next_burst_len, read_data_done, read_data_left;
0302     struct iscsit_conn *conn = cmd->conn;
0303     struct iscsi_datain_req *dr;
0304     struct iscsi_pdu *pdu;
0305 
0306     dr = iscsit_get_datain_req(cmd);
0307     if (!dr)
0308         return NULL;
0309 
0310     if (dr->recovery && dr->generate_recovery_values) {
0311         if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
0312                     cmd, dr) < 0)
0313             return NULL;
0314 
0315         dr->generate_recovery_values = 0;
0316     }
0317 
0318     next_burst_len = (!dr->recovery) ?
0319             cmd->next_burst_len : dr->next_burst_len;
0320     read_data_done = (!dr->recovery) ?
0321             cmd->read_data_done : dr->read_data_done;
0322 
0323     read_data_left = (cmd->se_cmd.data_length - read_data_done);
0324     if (!read_data_left) {
0325         pr_err("ITT: 0x%08x read_data_left is zero!\n",
0326                 cmd->init_task_tag);
0327         return dr;
0328     }
0329 
0330     pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL);
0331     if (!pdu)
0332         return dr;
0333 
0334     if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) {
0335         pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
0336         if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
0337             pdu->flags |= ISCSI_FLAG_DATA_ACK;
0338 
0339         next_burst_len = 0;
0340     } else {
0341         if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) <
0342              conn->sess->sess_ops->MaxBurstLength)
0343             next_burst_len += pdu->length;
0344         else {
0345             pdu->flags |= ISCSI_FLAG_CMD_FINAL;
0346             if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
0347                 pdu->flags |= ISCSI_FLAG_DATA_ACK;
0348 
0349             next_burst_len = 0;
0350         }
0351     }
0352 
0353     pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
0354     if (!dr->recovery) {
0355         cmd->next_burst_len = next_burst_len;
0356         cmd->read_data_done += pdu->length;
0357     } else {
0358         dr->next_burst_len = next_burst_len;
0359         dr->read_data_done += pdu->length;
0360     }
0361 
0362     datain->flags = pdu->flags;
0363     datain->length = pdu->length;
0364     datain->offset = pdu->offset;
0365     datain->data_sn = pdu->data_sn;
0366 
0367     if (!dr->recovery) {
0368         if (datain->flags & ISCSI_FLAG_DATA_STATUS)
0369             dr->dr_complete = DATAIN_COMPLETE_NORMAL;
0370 
0371         return dr;
0372     }
0373 
0374     if (!dr->runlength) {
0375         if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
0376             dr->dr_complete =
0377                 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
0378                 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
0379                 DATAIN_COMPLETE_CONNECTION_RECOVERY;
0380         }
0381     } else {
0382         if ((dr->begrun + dr->runlength) == dr->data_sn) {
0383             dr->dr_complete =
0384                 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
0385                 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
0386                 DATAIN_COMPLETE_CONNECTION_RECOVERY;
0387         }
0388     }
0389 
0390     return dr;
0391 }
0392 
0393 /*
0394  *  For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No.
0395  */
0396 static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
0397     struct iscsit_cmd *cmd,
0398     struct iscsi_datain *datain)
0399 {
0400     u32 read_data_done, read_data_left, seq_send_order;
0401     struct iscsit_conn *conn = cmd->conn;
0402     struct iscsi_datain_req *dr;
0403     struct iscsi_pdu *pdu;
0404     struct iscsi_seq *seq = NULL;
0405 
0406     dr = iscsit_get_datain_req(cmd);
0407     if (!dr)
0408         return NULL;
0409 
0410     if (dr->recovery && dr->generate_recovery_values) {
0411         if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
0412                     cmd, dr) < 0)
0413             return NULL;
0414 
0415         dr->generate_recovery_values = 0;
0416     }
0417 
0418     read_data_done = (!dr->recovery) ?
0419             cmd->read_data_done : dr->read_data_done;
0420     seq_send_order = (!dr->recovery) ?
0421             cmd->seq_send_order : dr->seq_send_order;
0422 
0423     read_data_left = (cmd->se_cmd.data_length - read_data_done);
0424     if (!read_data_left) {
0425         pr_err("ITT: 0x%08x read_data_left is zero!\n",
0426                 cmd->init_task_tag);
0427         return NULL;
0428     }
0429 
0430     seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
0431     if (!seq)
0432         return NULL;
0433 
0434     seq->sent = 1;
0435 
0436     if (!dr->recovery && !seq->next_burst_len)
0437         seq->first_datasn = cmd->data_sn;
0438 
0439     pdu = iscsit_get_pdu_holder_for_seq(cmd, seq);
0440     if (!pdu)
0441         return NULL;
0442 
0443     if (seq->pdu_send_order == seq->pdu_count) {
0444         pdu->flags |= ISCSI_FLAG_CMD_FINAL;
0445         if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
0446             pdu->flags |= ISCSI_FLAG_DATA_ACK;
0447 
0448         seq->next_burst_len = 0;
0449         seq_send_order++;
0450     } else
0451         seq->next_burst_len += pdu->length;
0452 
0453     if ((read_data_done + pdu->length) == cmd->se_cmd.data_length)
0454         pdu->flags |= ISCSI_FLAG_DATA_STATUS;
0455 
0456     pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
0457     if (!dr->recovery) {
0458         cmd->seq_send_order = seq_send_order;
0459         cmd->read_data_done += pdu->length;
0460     } else {
0461         dr->seq_send_order = seq_send_order;
0462         dr->read_data_done += pdu->length;
0463     }
0464 
0465     datain->flags = pdu->flags;
0466     datain->length = pdu->length;
0467     datain->offset = pdu->offset;
0468     datain->data_sn = pdu->data_sn;
0469 
0470     if (!dr->recovery) {
0471         if (datain->flags & ISCSI_FLAG_CMD_FINAL)
0472             seq->last_datasn = datain->data_sn;
0473         if (datain->flags & ISCSI_FLAG_DATA_STATUS)
0474             dr->dr_complete = DATAIN_COMPLETE_NORMAL;
0475 
0476         return dr;
0477     }
0478 
0479     if (!dr->runlength) {
0480         if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
0481             dr->dr_complete =
0482                 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
0483                 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
0484                 DATAIN_COMPLETE_CONNECTION_RECOVERY;
0485         }
0486     } else {
0487         if ((dr->begrun + dr->runlength) == dr->data_sn) {
0488             dr->dr_complete =
0489                 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
0490                 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
0491                 DATAIN_COMPLETE_CONNECTION_RECOVERY;
0492         }
0493     }
0494 
0495     return dr;
0496 }
0497 
0498 struct iscsi_datain_req *iscsit_get_datain_values(
0499     struct iscsit_cmd *cmd,
0500     struct iscsi_datain *datain)
0501 {
0502     struct iscsit_conn *conn = cmd->conn;
0503 
0504     if (conn->sess->sess_ops->DataSequenceInOrder &&
0505         conn->sess->sess_ops->DataPDUInOrder)
0506         return iscsit_set_datain_values_yes_and_yes(cmd, datain);
0507     else if (!conn->sess->sess_ops->DataSequenceInOrder &&
0508           conn->sess->sess_ops->DataPDUInOrder)
0509         return iscsit_set_datain_values_no_and_yes(cmd, datain);
0510     else if (conn->sess->sess_ops->DataSequenceInOrder &&
0511          !conn->sess->sess_ops->DataPDUInOrder)
0512         return iscsit_set_datain_values_yes_and_no(cmd, datain);
0513     else if (!conn->sess->sess_ops->DataSequenceInOrder &&
0514            !conn->sess->sess_ops->DataPDUInOrder)
0515         return iscsit_set_datain_values_no_and_no(cmd, datain);
0516 
0517     return NULL;
0518 }
0519 EXPORT_SYMBOL(iscsit_get_datain_values);