LCOV - code coverage report
Current view: top level - lib/iscsi - iscsi.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 1020 2431 42.0 %
Date: 2024-07-14 19:08:03 Functions: 45 99 45.5 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
       3             :  *   Copyright (C) 2016 Intel Corporation.
       4             :  *   All rights reserved.
       5             :  */
       6             : 
       7             : #include "spdk/stdinc.h"
       8             : 
       9             : #include "spdk/base64.h"
      10             : #include "spdk/crc32.h"
      11             : #include "spdk/endian.h"
      12             : #include "spdk/env.h"
      13             : #include "spdk/likely.h"
      14             : #include "spdk/trace.h"
      15             : #include "spdk/sock.h"
      16             : #include "spdk/string.h"
      17             : #include "spdk/queue.h"
      18             : 
      19             : #include "iscsi/md5.h"
      20             : #include "iscsi/iscsi.h"
      21             : #include "iscsi/param.h"
      22             : #include "iscsi/tgt_node.h"
      23             : #include "iscsi/task.h"
      24             : #include "iscsi/conn.h"
      25             : #include "spdk/scsi.h"
      26             : #include "spdk/bdev.h"
      27             : #include "iscsi/portal_grp.h"
      28             : 
      29             : #include "spdk/log.h"
      30             : 
      31             : #include "spdk_internal/sgl.h"
      32             : 
      33             : #define MAX_TMPBUF 1024
      34             : 
      35             : struct spdk_iscsi_globals g_iscsi = {
      36             :         .mutex = PTHREAD_MUTEX_INITIALIZER,
      37             :         .portal_head = TAILQ_HEAD_INITIALIZER(g_iscsi.portal_head),
      38             :         .pg_head = TAILQ_HEAD_INITIALIZER(g_iscsi.pg_head),
      39             :         .ig_head = TAILQ_HEAD_INITIALIZER(g_iscsi.ig_head),
      40             :         .target_head = TAILQ_HEAD_INITIALIZER(g_iscsi.target_head),
      41             :         .auth_group_head = TAILQ_HEAD_INITIALIZER(g_iscsi.auth_group_head),
      42             :         .poll_group_head = TAILQ_HEAD_INITIALIZER(g_iscsi.poll_group_head),
      43             : };
      44             : 
      45             : #define MATCH_DIGEST_WORD(BUF, CRC32C) \
      46             :         (    ((((uint32_t) *((uint8_t *)(BUF)+0)) << 0)           \
      47             :             | (((uint32_t) *((uint8_t *)(BUF)+1)) << 8)           \
      48             :             | (((uint32_t) *((uint8_t *)(BUF)+2)) << 16)  \
      49             :             | (((uint32_t) *((uint8_t *)(BUF)+3)) << 24)) \
      50             :             == (CRC32C))
      51             : 
      52             : #ifndef SPDK_CONFIG_HAVE_ARC4RANDOM
      53             : static void
      54           0 : srandomdev(void)
      55             : {
      56             :         unsigned long seed;
      57             :         time_t now;
      58             :         pid_t pid;
      59             : 
      60           0 :         pid = getpid();
      61           0 :         now = time(NULL);
      62           0 :         seed = pid ^ now;
      63           0 :         srandom(seed);
      64           0 : }
      65             : 
      66             : static int g_arc4random_initialized = 0;
      67             : 
      68             : static uint32_t
      69           0 : arc4random(void)
      70             : {
      71             :         uint32_t r;
      72             :         uint32_t r1, r2;
      73             : 
      74           0 :         if (!g_arc4random_initialized) {
      75           0 :                 srandomdev();
      76           0 :                 g_arc4random_initialized = 1;
      77             :         }
      78           0 :         r1 = (uint32_t)(random() & 0xffff);
      79           0 :         r2 = (uint32_t)(random() & 0xffff);
      80           0 :         r = (r1 << 16) | r2;
      81           0 :         return r;
      82             : }
      83             : #endif /* SPDK_CONFIG_HAVE_ARC4RANDOM */
      84             : 
      85             : static void
      86           0 : gen_random(uint8_t *buf, size_t len)
      87             : {
      88             :         uint32_t r;
      89             :         size_t idx;
      90             : 
      91           0 :         for (idx = 0; idx < len; idx++) {
      92           0 :                 r = arc4random();
      93           0 :                 buf[idx] = (uint8_t) r;
      94             :         }
      95           0 : }
      96             : 
      97             : static uint64_t
      98           2 : iscsi_get_isid(const uint8_t isid[6])
      99             : {
     100           2 :         return (uint64_t)isid[0] << 40 |
     101           2 :                (uint64_t)isid[1] << 32 |
     102           2 :                (uint64_t)isid[2] << 24 |
     103           2 :                (uint64_t)isid[3] << 16 |
     104           4 :                (uint64_t)isid[4] << 8 |
     105           2 :                (uint64_t)isid[5];
     106             : }
     107             : 
     108             : static int
     109           0 : bin2hex(char *buf, size_t len, const uint8_t *data, size_t data_len)
     110             : {
     111           0 :         const char *digits = "0123456789ABCDEF";
     112           0 :         size_t total = 0;
     113             :         size_t idx;
     114             : 
     115           0 :         if (len < 3) {
     116           0 :                 return -1;
     117             :         }
     118           0 :         buf[total] = '0';
     119           0 :         total++;
     120           0 :         buf[total] = 'x';
     121           0 :         total++;
     122           0 :         buf[total] = '\0';
     123             : 
     124           0 :         for (idx = 0; idx < data_len; idx++) {
     125           0 :                 if (total + 3 > len) {
     126           0 :                         buf[total] = '\0';
     127           0 :                         return - 1;
     128             :                 }
     129           0 :                 buf[total] = digits[(data[idx] >> 4) & 0x0fU];
     130           0 :                 total++;
     131           0 :                 buf[total] = digits[data[idx] & 0x0fU];
     132           0 :                 total++;
     133             :         }
     134           0 :         buf[total] = '\0';
     135           0 :         return total;
     136             : }
     137             : 
     138             : static int
     139           0 : hex2bin(uint8_t *data, size_t data_len, const char *str)
     140             : {
     141           0 :         const char *digits = "0123456789ABCDEF";
     142             :         const char *dp;
     143             :         const char *p;
     144           0 :         size_t total = 0;
     145             :         int n0, n1;
     146             : 
     147           0 :         p = str;
     148           0 :         if (p[0] != '0' && (p[1] != 'x' && p[1] != 'X')) {
     149           0 :                 return -1;
     150             :         }
     151           0 :         p += 2;
     152             : 
     153           0 :         while (p[0] != '\0' && p[1] != '\0') {
     154           0 :                 if (total >= data_len) {
     155           0 :                         return -1;
     156             :                 }
     157           0 :                 dp = strchr(digits, toupper((int) p[0]));
     158           0 :                 if (dp == NULL) {
     159           0 :                         return -1;
     160             :                 }
     161           0 :                 n0 = (int)(dp - digits);
     162           0 :                 dp = strchr(digits, toupper((int) p[1]));
     163           0 :                 if (dp == NULL) {
     164           0 :                         return -1;
     165             :                 }
     166           0 :                 n1 = (int)(dp - digits);
     167             : 
     168           0 :                 data[total] = (uint8_t)(((n0 & 0x0fU) << 4) | (n1 & 0x0fU));
     169           0 :                 total++;
     170           0 :                 p += 2;
     171             :         }
     172           0 :         return total;
     173             : }
     174             : 
     175             : static int
     176          14 : iscsi_reject(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu,
     177             :              int reason)
     178             : {
     179             :         struct spdk_iscsi_pdu *rsp_pdu;
     180             :         struct iscsi_bhs_reject *rsph;
     181             :         uint8_t *data;
     182             :         int total_ahs_len;
     183             :         int data_len;
     184             :         int alloc_len;
     185             : 
     186          14 :         pdu->is_rejected = true;
     187             : 
     188          14 :         total_ahs_len = pdu->bhs.total_ahs_len;
     189          14 :         data_len = 0;
     190          14 :         alloc_len = ISCSI_BHS_LEN + (4 * total_ahs_len);
     191             : 
     192          14 :         if (conn->header_digest) {
     193           0 :                 alloc_len += ISCSI_DIGEST_LEN;
     194             :         }
     195             : 
     196          14 :         data = calloc(1, alloc_len);
     197          14 :         if (!data) {
     198           0 :                 SPDK_ERRLOG("calloc() failed for data segment\n");
     199           0 :                 return -ENOMEM;
     200             :         }
     201             : 
     202          14 :         SPDK_DEBUGLOG(iscsi, "Reject PDU reason=%d\n", reason);
     203             : 
     204          14 :         if (conn->sess != NULL) {
     205          13 :                 SPDK_DEBUGLOG(iscsi,
     206             :                               "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
     207             :                               conn->StatSN, conn->sess->ExpCmdSN,
     208             :                               conn->sess->MaxCmdSN);
     209             :         } else {
     210           1 :                 SPDK_DEBUGLOG(iscsi, "StatSN=%u\n", conn->StatSN);
     211             :         }
     212             : 
     213          14 :         memcpy(data, &pdu->bhs, ISCSI_BHS_LEN);
     214          14 :         data_len += ISCSI_BHS_LEN;
     215             : 
     216          14 :         if (total_ahs_len != 0) {
     217           0 :                 total_ahs_len = spdk_min((4 * total_ahs_len), ISCSI_AHS_LEN);
     218           0 :                 memcpy(data + data_len, pdu->ahs, total_ahs_len);
     219           0 :                 data_len += total_ahs_len;
     220             :         }
     221             : 
     222          14 :         if (conn->header_digest) {
     223           0 :                 memcpy(data + data_len, pdu->header_digest, ISCSI_DIGEST_LEN);
     224           0 :                 data_len += ISCSI_DIGEST_LEN;
     225             :         }
     226             : 
     227          14 :         rsp_pdu = iscsi_get_pdu(conn);
     228          14 :         if (rsp_pdu == NULL) {
     229           0 :                 free(data);
     230           0 :                 return -ENOMEM;
     231             :         }
     232             : 
     233          14 :         rsph = (struct iscsi_bhs_reject *)&rsp_pdu->bhs;
     234          14 :         rsp_pdu->data = data;
     235          14 :         rsph->opcode = ISCSI_OP_REJECT;
     236          14 :         rsph->flags |= 0x80; /* bit 0 is default to 1 */
     237          14 :         rsph->reason = reason;
     238          14 :         DSET24(rsph->data_segment_len, data_len);
     239             : 
     240          14 :         rsph->ffffffff = 0xffffffffU;
     241          14 :         to_be32(&rsph->stat_sn, conn->StatSN);
     242          14 :         conn->StatSN++;
     243             : 
     244          14 :         if (conn->sess != NULL) {
     245          13 :                 to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
     246          13 :                 to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
     247             :         } else {
     248           1 :                 to_be32(&rsph->exp_cmd_sn, 1);
     249           1 :                 to_be32(&rsph->max_cmd_sn, 1);
     250             :         }
     251             : 
     252          14 :         SPDK_LOGDUMP(iscsi, "PDU", (void *)&rsp_pdu->bhs, ISCSI_BHS_LEN);
     253             : 
     254          14 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
     255             : 
     256          14 :         return 0;
     257             : }
     258             : 
     259             : uint32_t
     260           0 : iscsi_pdu_calc_header_digest(struct spdk_iscsi_pdu *pdu)
     261             : {
     262             :         uint32_t crc32c;
     263           0 :         uint32_t ahs_len_bytes = pdu->bhs.total_ahs_len * 4;
     264             : 
     265           0 :         crc32c = SPDK_CRC32C_INITIAL;
     266           0 :         crc32c = spdk_crc32c_update(&pdu->bhs, ISCSI_BHS_LEN, crc32c);
     267             : 
     268           0 :         if (ahs_len_bytes) {
     269           0 :                 crc32c = spdk_crc32c_update(pdu->ahs, ahs_len_bytes, crc32c);
     270             :         }
     271             : 
     272             :         /* BHS and AHS are always 4-byte multiples in length, so no padding is necessary. */
     273             : 
     274             :         /* Finalize CRC by inverting all bits. */
     275           0 :         return crc32c ^ SPDK_CRC32C_XOR;
     276             : }
     277             : 
     278             : /* Calculate CRC for each partial data segment. */
     279             : static void
     280           1 : iscsi_pdu_calc_partial_data_digest(struct spdk_iscsi_pdu *pdu)
     281             : {
     282           1 :         struct iovec iov;
     283             :         uint32_t num_blocks;
     284             : 
     285           1 :         if (spdk_likely(!pdu->dif_insert_or_strip)) {
     286           1 :                 pdu->crc32c = spdk_crc32c_update(pdu->data,
     287           1 :                                                  pdu->data_valid_bytes - pdu->data_offset,
     288             :                                                  pdu->crc32c);
     289             :         } else {
     290           0 :                 iov.iov_base = pdu->data;
     291           0 :                 iov.iov_len = pdu->data_buf_len;
     292           0 :                 num_blocks = pdu->data_buf_len / pdu->dif_ctx.block_size;
     293             : 
     294           0 :                 spdk_dif_update_crc32c(&iov, 1, num_blocks, &pdu->crc32c, &pdu->dif_ctx);
     295             :         }
     296           1 : }
     297             : 
     298             : static uint32_t
     299           1 : iscsi_pdu_calc_partial_data_digest_done(struct spdk_iscsi_pdu *pdu)
     300             : {
     301           1 :         uint32_t crc32c = pdu->crc32c;
     302             :         uint32_t mod;
     303             : 
     304             :         /* Include padding bytes into CRC if any. */
     305           1 :         mod = pdu->data_valid_bytes % ISCSI_ALIGNMENT;
     306           1 :         if (mod != 0) {
     307           0 :                 uint32_t pad_length = ISCSI_ALIGNMENT - mod;
     308           0 :                 uint8_t pad[3] = {0, 0, 0};
     309             : 
     310           0 :                 assert(pad_length > 0);
     311           0 :                 assert(pad_length <= sizeof(pad));
     312           0 :                 crc32c = spdk_crc32c_update(pad, pad_length, crc32c);
     313             :         }
     314             : 
     315             :         /* Finalize CRC by inverting all bits. */
     316           1 :         return crc32c ^ SPDK_CRC32C_XOR;
     317             : }
     318             : 
     319             : uint32_t
     320           0 : iscsi_pdu_calc_data_digest(struct spdk_iscsi_pdu *pdu)
     321             : {
     322           0 :         uint32_t data_len = DGET24(pdu->bhs.data_segment_len);
     323           0 :         uint32_t crc32c;
     324             :         uint32_t mod;
     325           0 :         struct iovec iov;
     326             :         uint32_t num_blocks;
     327             : 
     328             :         /* Initialize CRC. */
     329           0 :         crc32c = SPDK_CRC32C_INITIAL;
     330             : 
     331             :         /* Calculate CRC for the whole data segment. */
     332           0 :         if (spdk_likely(!pdu->dif_insert_or_strip)) {
     333           0 :                 crc32c = spdk_crc32c_update(pdu->data, data_len, crc32c);
     334             :         } else {
     335           0 :                 iov.iov_base = pdu->data;
     336           0 :                 iov.iov_len = pdu->data_buf_len;
     337           0 :                 num_blocks = pdu->data_buf_len / pdu->dif_ctx.block_size;
     338             : 
     339           0 :                 spdk_dif_update_crc32c(&iov, 1, num_blocks, &crc32c, &pdu->dif_ctx);
     340             :         }
     341             : 
     342             :         /* Include padding bytes into CRC if any. */
     343           0 :         mod = data_len % ISCSI_ALIGNMENT;
     344           0 :         if (mod != 0) {
     345           0 :                 uint32_t pad_length = ISCSI_ALIGNMENT - mod;
     346           0 :                 uint8_t pad[3] = {0, 0, 0};
     347           0 :                 assert(pad_length > 0);
     348           0 :                 assert(pad_length <= sizeof(pad));
     349           0 :                 crc32c = spdk_crc32c_update(pad, pad_length, crc32c);
     350             :         }
     351             : 
     352             :         /* Finalize CRC by inverting all bits. */
     353           0 :         return crc32c ^ SPDK_CRC32C_XOR;
     354             : }
     355             : 
     356             : static int
     357          17 : iscsi_conn_read_data_segment(struct spdk_iscsi_conn *conn,
     358             :                              struct spdk_iscsi_pdu *pdu,
     359             :                              uint32_t data_offset, uint32_t data_len)
     360             : {
     361          17 :         struct iovec buf_iov, iovs[32];
     362             :         int rc, _rc;
     363             : 
     364          17 :         if (spdk_likely(!pdu->dif_insert_or_strip)) {
     365          17 :                 return iscsi_conn_read_data(conn, data_len, pdu->data + data_offset);
     366             :         } else {
     367           0 :                 buf_iov.iov_base = pdu->data;
     368           0 :                 buf_iov.iov_len = pdu->data_buf_len;
     369           0 :                 rc = spdk_dif_set_md_interleave_iovs(iovs, 32, &buf_iov, 1,
     370             :                                                      data_offset, data_len, NULL,
     371           0 :                                                      &pdu->dif_ctx);
     372           0 :                 if (rc > 0) {
     373           0 :                         rc = iscsi_conn_readv_data(conn, iovs, rc);
     374           0 :                         if (rc > 0) {
     375           0 :                                 _rc = spdk_dif_generate_stream(&buf_iov, 1, data_offset, rc,
     376             :                                                                &pdu->dif_ctx);
     377           0 :                                 if (_rc != 0) {
     378           0 :                                         SPDK_ERRLOG("DIF generate failed\n");
     379           0 :                                         rc = _rc;
     380             :                                 }
     381             :                         }
     382             :                 } else {
     383           0 :                         SPDK_ERRLOG("Setup iovs for interleaved metadata failed\n");
     384             :                 }
     385           0 :                 return rc;
     386             :         }
     387             : }
     388             : 
     389             : /* Build iovec array to leave metadata space for every data block
     390             :  * when reading data segment from socket.
     391             :  */
     392             : static inline bool
     393           4 : _iscsi_sgl_append_with_md(struct spdk_iov_sgl *s,
     394             :                           void *buf, uint32_t buf_len, uint32_t data_len,
     395             :                           struct spdk_dif_ctx *dif_ctx)
     396             : {
     397             :         int rc;
     398           4 :         uint32_t total_size = 0;
     399           4 :         struct iovec buf_iov;
     400             : 
     401           4 :         if (s->iov_offset >= data_len) {
     402           1 :                 s->iov_offset -= data_len;
     403             :         } else {
     404           3 :                 buf_iov.iov_base = buf;
     405           3 :                 buf_iov.iov_len = buf_len;
     406           3 :                 rc = spdk_dif_set_md_interleave_iovs(s->iov, s->iovcnt, &buf_iov, 1,
     407           3 :                                                      s->iov_offset, data_len - s->iov_offset,
     408             :                                                      &total_size, dif_ctx);
     409           3 :                 if (rc < 0) {
     410           0 :                         SPDK_ERRLOG("Failed to setup iovs for DIF strip\n");
     411           0 :                         return false;
     412             :                 }
     413             : 
     414           3 :                 s->total_size += total_size;
     415           3 :                 s->iov_offset = 0;
     416           3 :                 assert(s->iovcnt >= rc);
     417           3 :                 s->iovcnt -= rc;
     418           3 :                 s->iov += rc;
     419             : 
     420           3 :                 if (s->iovcnt == 0) {
     421           1 :                         return false;
     422             :                 }
     423             :         }
     424             : 
     425           3 :         return true;
     426             : }
     427             : 
     428             : int
     429          16 : iscsi_build_iovs(struct spdk_iscsi_conn *conn, struct iovec *iovs, int iovcnt,
     430             :                  struct spdk_iscsi_pdu *pdu, uint32_t *_mapped_length)
     431             : {
     432          16 :         struct spdk_iov_sgl sgl;
     433             :         int enable_digest;
     434             :         uint32_t total_ahs_len;
     435             :         uint32_t data_len;
     436             : 
     437          16 :         if (iovcnt == 0) {
     438           0 :                 return 0;
     439             :         }
     440             : 
     441          16 :         total_ahs_len = pdu->bhs.total_ahs_len;
     442          16 :         data_len = DGET24(pdu->bhs.data_segment_len);
     443          16 :         data_len = ISCSI_ALIGN(data_len);
     444             : 
     445          16 :         enable_digest = 1;
     446          16 :         if (pdu->bhs.opcode == ISCSI_OP_LOGIN_RSP) {
     447             :                 /* this PDU should be sent without digest */
     448           0 :                 enable_digest = 0;
     449             :         }
     450             : 
     451          16 :         spdk_iov_sgl_init(&sgl, iovs, iovcnt, pdu->writev_offset);
     452             : 
     453             :         /* BHS */
     454          16 :         if (!spdk_iov_sgl_append(&sgl, (uint8_t *)&pdu->bhs, ISCSI_BHS_LEN)) {
     455           1 :                 goto end;
     456             :         }
     457             :         /* AHS */
     458          15 :         if (total_ahs_len > 0) {
     459           0 :                 if (!spdk_iov_sgl_append(&sgl, pdu->ahs, 4 * total_ahs_len)) {
     460           0 :                         goto end;
     461             :                 }
     462             :         }
     463             : 
     464             :         /* Header Digest */
     465          15 :         if (enable_digest && conn->header_digest) {
     466          15 :                 if (!spdk_iov_sgl_append(&sgl, pdu->header_digest, ISCSI_DIGEST_LEN)) {
     467           1 :                         goto end;
     468             :                 }
     469             :         }
     470             : 
     471             :         /* Data Segment */
     472          14 :         if (data_len > 0) {
     473          14 :                 if (!pdu->dif_insert_or_strip) {
     474          10 :                         if (!spdk_iov_sgl_append(&sgl, pdu->data, data_len)) {
     475           1 :                                 goto end;
     476             :                         }
     477             :                 } else {
     478           4 :                         if (!_iscsi_sgl_append_with_md(&sgl, pdu->data, pdu->data_buf_len,
     479             :                                                        data_len, &pdu->dif_ctx)) {
     480           1 :                                 goto end;
     481             :                         }
     482             :                 }
     483             :         }
     484             : 
     485             :         /* Data Digest */
     486          12 :         if (enable_digest && conn->data_digest && data_len != 0) {
     487          12 :                 spdk_iov_sgl_append(&sgl, pdu->data_digest, ISCSI_DIGEST_LEN);
     488             :         }
     489             : 
     490          16 : end:
     491          16 :         if (_mapped_length != NULL) {
     492          16 :                 *_mapped_length = sgl.total_size;
     493             :         }
     494             : 
     495          16 :         return iovcnt - sgl.iovcnt;
     496             : }
     497             : 
     498             : void
     499           0 : iscsi_free_sess(struct spdk_iscsi_sess *sess)
     500             : {
     501           0 :         if (sess == NULL) {
     502           0 :                 return;
     503             :         }
     504             : 
     505           0 :         sess->tag = 0;
     506           0 :         sess->target = NULL;
     507           0 :         sess->session_type = SESSION_TYPE_INVALID;
     508           0 :         iscsi_param_free(sess->params);
     509           0 :         free(sess->conns);
     510           0 :         spdk_scsi_port_free(&sess->initiator_port);
     511           0 :         spdk_mempool_put(g_iscsi.session_pool, (void *)sess);
     512             : }
     513             : 
     514             : static int
     515           0 : create_iscsi_sess(struct spdk_iscsi_conn *conn,
     516             :                   struct spdk_iscsi_tgt_node *target,
     517             :                   enum session_type session_type)
     518             : {
     519             :         struct spdk_iscsi_sess *sess;
     520             :         int rc;
     521             : 
     522           0 :         sess = spdk_mempool_get(g_iscsi.session_pool);
     523           0 :         if (!sess) {
     524           0 :                 SPDK_ERRLOG("Unable to get session object\n");
     525           0 :                 SPDK_ERRLOG("MaxSessions set to %d\n", g_iscsi.MaxSessions);
     526           0 :                 return -ENOMEM;
     527             :         }
     528             : 
     529             :         /* configuration values */
     530           0 :         pthread_mutex_lock(&g_iscsi.mutex);
     531             : 
     532           0 :         sess->MaxConnections = g_iscsi.MaxConnectionsPerSession;
     533           0 :         sess->MaxOutstandingR2T = DEFAULT_MAXOUTSTANDINGR2T;
     534             : 
     535           0 :         sess->DefaultTime2Wait = g_iscsi.DefaultTime2Wait;
     536           0 :         sess->DefaultTime2Retain = g_iscsi.DefaultTime2Retain;
     537           0 :         sess->FirstBurstLength = g_iscsi.FirstBurstLength;
     538           0 :         sess->MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH;
     539           0 :         sess->InitialR2T = DEFAULT_INITIALR2T;
     540           0 :         sess->ImmediateData = g_iscsi.ImmediateData;
     541           0 :         sess->DataPDUInOrder = DEFAULT_DATAPDUINORDER;
     542           0 :         sess->DataSequenceInOrder = DEFAULT_DATASEQUENCEINORDER;
     543           0 :         sess->ErrorRecoveryLevel = g_iscsi.ErrorRecoveryLevel;
     544             : 
     545           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     546             : 
     547           0 :         sess->tag = conn->pg_tag;
     548             : 
     549           0 :         sess->conns = calloc(sess->MaxConnections, sizeof(*sess->conns));
     550           0 :         if (!sess->conns) {
     551           0 :                 spdk_mempool_put(g_iscsi.session_pool, (void *)sess);
     552           0 :                 SPDK_ERRLOG("calloc() failed for connection array\n");
     553           0 :                 return -ENOMEM;
     554             :         }
     555             : 
     556           0 :         sess->connections = 0;
     557             : 
     558           0 :         sess->conns[sess->connections] = conn;
     559           0 :         sess->connections++;
     560             : 
     561           0 :         sess->params = NULL;
     562           0 :         sess->target = target;
     563           0 :         sess->isid = 0;
     564           0 :         sess->session_type = session_type;
     565           0 :         sess->current_text_itt = 0xffffffffU;
     566             : 
     567             :         /* set default params */
     568           0 :         rc = iscsi_sess_params_init(&sess->params);
     569           0 :         if (rc < 0) {
     570           0 :                 SPDK_ERRLOG("iscsi_sess_params_init() failed\n");
     571           0 :                 goto error_return;
     572             :         }
     573             :         /* replace with config value */
     574           0 :         rc = iscsi_param_set_int(sess->params, "MaxConnections",
     575             :                                  sess->MaxConnections);
     576           0 :         if (rc < 0) {
     577           0 :                 SPDK_ERRLOG("iscsi_param_set_int() failed\n");
     578           0 :                 goto error_return;
     579             :         }
     580             : 
     581           0 :         rc = iscsi_param_set_int(sess->params, "MaxOutstandingR2T",
     582             :                                  sess->MaxOutstandingR2T);
     583           0 :         if (rc < 0) {
     584           0 :                 SPDK_ERRLOG("iscsi_param_set_int() failed\n");
     585           0 :                 goto error_return;
     586             :         }
     587             : 
     588           0 :         rc = iscsi_param_set_int(sess->params, "DefaultTime2Wait",
     589             :                                  sess->DefaultTime2Wait);
     590           0 :         if (rc < 0) {
     591           0 :                 SPDK_ERRLOG("iscsi_param_set_int() failed\n");
     592           0 :                 goto error_return;
     593             :         }
     594             : 
     595           0 :         rc = iscsi_param_set_int(sess->params, "DefaultTime2Retain",
     596             :                                  sess->DefaultTime2Retain);
     597           0 :         if (rc < 0) {
     598           0 :                 SPDK_ERRLOG("iscsi_param_set_int() failed\n");
     599           0 :                 goto error_return;
     600             :         }
     601             : 
     602           0 :         rc = iscsi_param_set_int(sess->params, "FirstBurstLength",
     603             :                                  sess->FirstBurstLength);
     604           0 :         if (rc < 0) {
     605           0 :                 SPDK_ERRLOG("iscsi_param_set_int() failed\n");
     606           0 :                 goto error_return;
     607             :         }
     608             : 
     609           0 :         rc = iscsi_param_set_int(sess->params, "MaxBurstLength",
     610             :                                  sess->MaxBurstLength);
     611           0 :         if (rc < 0) {
     612           0 :                 SPDK_ERRLOG("iscsi_param_set_int() failed\n");
     613           0 :                 goto error_return;
     614             :         }
     615             : 
     616           0 :         rc = iscsi_param_set(sess->params, "InitialR2T",
     617           0 :                              sess->InitialR2T ? "Yes" : "No");
     618           0 :         if (rc < 0) {
     619           0 :                 SPDK_ERRLOG("iscsi_param_set() failed\n");
     620           0 :                 goto error_return;
     621             :         }
     622             : 
     623           0 :         rc = iscsi_param_set(sess->params, "ImmediateData",
     624           0 :                              sess->ImmediateData ? "Yes" : "No");
     625           0 :         if (rc < 0) {
     626           0 :                 SPDK_ERRLOG("iscsi_param_set() failed\n");
     627           0 :                 goto error_return;
     628             :         }
     629             : 
     630           0 :         rc = iscsi_param_set(sess->params, "DataPDUInOrder",
     631           0 :                              sess->DataPDUInOrder ? "Yes" : "No");
     632           0 :         if (rc < 0) {
     633           0 :                 SPDK_ERRLOG("iscsi_param_set() failed\n");
     634           0 :                 goto error_return;
     635             :         }
     636             : 
     637           0 :         rc = iscsi_param_set(sess->params, "DataSequenceInOrder",
     638           0 :                              sess->DataSequenceInOrder ? "Yes" : "No");
     639           0 :         if (rc < 0) {
     640           0 :                 SPDK_ERRLOG("iscsi_param_set() failed\n");
     641           0 :                 goto error_return;
     642             :         }
     643             : 
     644           0 :         rc = iscsi_param_set_int(sess->params, "ErrorRecoveryLevel",
     645             :                                  sess->ErrorRecoveryLevel);
     646           0 :         if (rc < 0) {
     647           0 :                 SPDK_ERRLOG("iscsi_param_set_int() failed\n");
     648           0 :                 goto error_return;
     649             :         }
     650             : 
     651             :         /* realloc buffer */
     652           0 :         rc = iscsi_param_set_int(conn->params, "MaxRecvDataSegmentLength",
     653           0 :                                  conn->MaxRecvDataSegmentLength);
     654           0 :         if (rc < 0) {
     655           0 :                 SPDK_ERRLOG("iscsi_param_set_int() failed\n");
     656           0 :                 goto error_return;
     657             :         }
     658             : 
     659             :         /* sess for first connection of session */
     660           0 :         conn->sess = sess;
     661           0 :         return 0;
     662             : 
     663           0 : error_return:
     664           0 :         iscsi_free_sess(sess);
     665           0 :         conn->sess = NULL;
     666           0 :         return -1;
     667             : }
     668             : 
     669             : static struct spdk_iscsi_sess *
     670           2 : get_iscsi_sess_by_tsih(uint16_t tsih)
     671             : {
     672             :         struct spdk_iscsi_sess *session;
     673             : 
     674           2 :         if (tsih == 0 || tsih > g_iscsi.MaxSessions) {
     675           1 :                 return NULL;
     676             :         }
     677             : 
     678           1 :         session = g_iscsi.session[tsih - 1];
     679           1 :         assert(tsih == session->tsih);
     680             : 
     681           1 :         return session;
     682             : }
     683             : 
     684             : static uint8_t
     685           2 : append_iscsi_sess(struct spdk_iscsi_conn *conn,
     686             :                   const char *initiator_port_name, uint16_t tsih, uint16_t cid)
     687             : {
     688             :         struct spdk_iscsi_sess *sess;
     689             : 
     690           2 :         SPDK_DEBUGLOG(iscsi, "append session: init port name=%s, tsih=%u, cid=%u\n",
     691             :                       initiator_port_name, tsih, cid);
     692             : 
     693           2 :         sess = get_iscsi_sess_by_tsih(tsih);
     694           2 :         if (sess == NULL) {
     695           1 :                 SPDK_ERRLOG("spdk_get_iscsi_sess_by_tsih failed\n");
     696           1 :                 return ISCSI_LOGIN_CONN_ADD_FAIL;
     697             :         }
     698           1 :         if ((conn->pg_tag != sess->tag) ||
     699           0 :             (strcasecmp(initiator_port_name, spdk_scsi_port_get_name(sess->initiator_port)) != 0) ||
     700           0 :             (conn->target != sess->target)) {
     701             :                 /* no match */
     702           1 :                 SPDK_ERRLOG("no MCS session for init port name=%s, tsih=%d, cid=%d\n",
     703             :                             initiator_port_name, tsih, cid);
     704           1 :                 return ISCSI_LOGIN_CONN_ADD_FAIL;
     705             :         }
     706             : 
     707           0 :         if (sess->connections >= sess->MaxConnections) {
     708             :                 /* no slot for connection */
     709           0 :                 SPDK_ERRLOG("too many connections for init port name=%s, tsih=%d, cid=%d\n",
     710             :                             initiator_port_name, tsih, cid);
     711           0 :                 return ISCSI_LOGIN_TOO_MANY_CONNECTIONS;
     712             :         }
     713             : 
     714           0 :         SPDK_DEBUGLOG(iscsi, "Connections (tsih %d): %d\n", sess->tsih, sess->connections);
     715           0 :         conn->sess = sess;
     716             : 
     717             :         /*
     718             :          * TODO: need a mutex or other sync mechanism to protect the session's
     719             :          *  connection list.
     720             :          */
     721           0 :         sess->conns[sess->connections] = conn;
     722           0 :         sess->connections++;
     723             : 
     724           0 :         return 0;
     725             : }
     726             : 
     727             : static int
     728           0 : iscsi_append_text(const char *key, const char *val, uint8_t *data,
     729             :                   int alloc_len, int data_len)
     730             : {
     731             :         int total;
     732             :         int len;
     733             : 
     734           0 :         total = data_len;
     735           0 :         if (alloc_len < 1) {
     736           0 :                 return 0;
     737             :         }
     738           0 :         if (total > alloc_len) {
     739           0 :                 total = alloc_len;
     740           0 :                 data[total - 1] = '\0';
     741           0 :                 return total;
     742             :         }
     743             : 
     744           0 :         if (alloc_len - total < 1) {
     745           0 :                 SPDK_ERRLOG("data space small %d\n", alloc_len);
     746           0 :                 return total;
     747             :         }
     748           0 :         len = snprintf((char *) data + total, alloc_len - total, "%s=%s", key, val);
     749           0 :         total += len + 1;
     750             : 
     751           0 :         return total;
     752             : }
     753             : 
     754             : static int
     755           0 : iscsi_append_param(struct spdk_iscsi_conn *conn, const char *key,
     756             :                    uint8_t *data, int alloc_len, int data_len)
     757             : {
     758             :         struct iscsi_param *param;
     759             : 
     760           0 :         param = iscsi_param_find(conn->params, key);
     761           0 :         if (param == NULL) {
     762           0 :                 param = iscsi_param_find(conn->sess->params, key);
     763           0 :                 if (param == NULL) {
     764           0 :                         SPDK_DEBUGLOG(iscsi, "no key %.64s\n", key);
     765           0 :                         return data_len;
     766             :                 }
     767             :         }
     768           0 :         return iscsi_append_text(param->key, param->val, data,
     769             :                                  alloc_len, data_len);
     770             : }
     771             : 
     772             : static int
     773           0 : iscsi_auth_params(struct spdk_iscsi_conn *conn,
     774             :                   struct iscsi_param *params, const char *method, uint8_t *data,
     775             :                   int alloc_len, int data_len)
     776             : {
     777             :         char *in_val;
     778           0 :         char *in_next;
     779             :         char *new_val;
     780             :         const char *algorithm;
     781             :         const char *name;
     782             :         const char *response;
     783             :         const char *identifier;
     784             :         const char *challenge;
     785             :         int total;
     786             :         int rc;
     787             : 
     788           0 :         if (conn == NULL || params == NULL || method == NULL) {
     789           0 :                 return -1;
     790             :         }
     791           0 :         if (strcasecmp(method, "CHAP") == 0) {
     792             :                 /* method OK */
     793             :         } else {
     794           0 :                 SPDK_ERRLOG("unsupported AuthMethod %.64s\n", method);
     795           0 :                 return -1;
     796             :         }
     797             : 
     798           0 :         total = data_len;
     799           0 :         if (alloc_len < 1) {
     800           0 :                 return 0;
     801             :         }
     802           0 :         if (total > alloc_len) {
     803           0 :                 total = alloc_len;
     804           0 :                 data[total - 1] = '\0';
     805           0 :                 return total;
     806             :         }
     807             : 
     808             :         /* for temporary store */
     809           0 :         in_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
     810           0 :         if (!in_val) {
     811           0 :                 SPDK_ERRLOG("malloc() failed for temporary store\n");
     812           0 :                 return -ENOMEM;
     813             :         }
     814             : 
     815             :         /* CHAP method (RFC1994) */
     816           0 :         if ((algorithm = iscsi_param_get_val(params, "CHAP_A")) != NULL) {
     817           0 :                 if (conn->auth.chap_phase != ISCSI_CHAP_PHASE_WAIT_A) {
     818           0 :                         SPDK_ERRLOG("CHAP sequence error\n");
     819           0 :                         goto error_return;
     820             :                 }
     821             : 
     822             :                 /* CHAP_A is LIST type */
     823           0 :                 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", algorithm);
     824           0 :                 in_next = in_val;
     825           0 :                 while ((new_val = spdk_strsepq(&in_next, ",")) != NULL) {
     826           0 :                         if (strcasecmp(new_val, "5") == 0) {
     827             :                                 /* CHAP with MD5 */
     828           0 :                                 break;
     829             :                         }
     830             :                 }
     831           0 :                 if (new_val == NULL) {
     832           0 :                         snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Reject");
     833           0 :                         new_val = in_val;
     834           0 :                         iscsi_append_text("CHAP_A", new_val, data, alloc_len, total);
     835           0 :                         goto error_return;
     836             :                 }
     837             :                 /* selected algorithm is 5 (MD5) */
     838           0 :                 SPDK_DEBUGLOG(iscsi, "got CHAP_A=%s\n", new_val);
     839           0 :                 total = iscsi_append_text("CHAP_A", new_val, data, alloc_len, total);
     840             : 
     841             :                 /* Identifier is one octet */
     842           0 :                 gen_random(conn->auth.chap_id, 1);
     843           0 :                 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d",
     844           0 :                          (int) conn->auth.chap_id[0]);
     845           0 :                 total = iscsi_append_text("CHAP_I", in_val, data, alloc_len, total);
     846             : 
     847             :                 /* Challenge Value is a variable stream of octets */
     848             :                 /* (binary length MUST not exceed 1024 bytes) */
     849           0 :                 conn->auth.chap_challenge_len = ISCSI_CHAP_CHALLENGE_LEN;
     850           0 :                 gen_random(conn->auth.chap_challenge, conn->auth.chap_challenge_len);
     851           0 :                 bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN,
     852           0 :                         conn->auth.chap_challenge, conn->auth.chap_challenge_len);
     853           0 :                 total = iscsi_append_text("CHAP_C", in_val, data, alloc_len, total);
     854             : 
     855           0 :                 conn->auth.chap_phase = ISCSI_CHAP_PHASE_WAIT_NR;
     856           0 :         } else if ((name = iscsi_param_get_val(params, "CHAP_N")) != NULL) {
     857           0 :                 uint8_t resmd5[SPDK_MD5DIGEST_LEN];
     858           0 :                 uint8_t tgtmd5[SPDK_MD5DIGEST_LEN];
     859           0 :                 struct spdk_md5ctx md5ctx;
     860           0 :                 size_t decoded_len = 0;
     861             : 
     862           0 :                 if (conn->auth.chap_phase != ISCSI_CHAP_PHASE_WAIT_NR) {
     863           0 :                         SPDK_ERRLOG("CHAP sequence error\n");
     864           0 :                         goto error_return;
     865             :                 }
     866             : 
     867           0 :                 response = iscsi_param_get_val(params, "CHAP_R");
     868           0 :                 if (response == NULL) {
     869           0 :                         SPDK_ERRLOG("no response\n");
     870           0 :                         goto error_return;
     871             :                 }
     872           0 :                 if (response[0] == '0' &&
     873           0 :                     (response[1] == 'x' || response[1] == 'X')) {
     874           0 :                         rc = hex2bin(resmd5, SPDK_MD5DIGEST_LEN, response);
     875           0 :                         if (rc < 0 || rc != SPDK_MD5DIGEST_LEN) {
     876           0 :                                 SPDK_ERRLOG("response format error\n");
     877           0 :                                 goto error_return;
     878             :                         }
     879           0 :                 } else if (response[0] == '0' &&
     880           0 :                            (response[1] == 'b' || response[1] == 'B')) {
     881           0 :                         response += 2;
     882           0 :                         rc = spdk_base64_decode(resmd5, &decoded_len, response);
     883           0 :                         if (rc < 0 || decoded_len != SPDK_MD5DIGEST_LEN) {
     884           0 :                                 SPDK_ERRLOG("response format error\n");
     885           0 :                                 goto error_return;
     886             :                         }
     887             :                 } else {
     888           0 :                         SPDK_ERRLOG("response format error\n");
     889           0 :                         goto error_return;
     890             :                 }
     891           0 :                 SPDK_DEBUGLOG(iscsi, "got CHAP_N/CHAP_R\n");
     892             : 
     893           0 :                 SPDK_DEBUGLOG(iscsi, "ag_tag=%d\n", conn->chap_group);
     894             : 
     895           0 :                 rc = iscsi_chap_get_authinfo(&conn->auth, name, conn->chap_group);
     896           0 :                 if (rc < 0) {
     897             :                         /* SPDK_ERRLOG("auth user or secret is missing\n"); */
     898           0 :                         SPDK_ERRLOG("iscsi_chap_get_authinfo() failed\n");
     899           0 :                         goto error_return;
     900             :                 }
     901           0 :                 if (conn->auth.user[0] == '\0' || conn->auth.secret[0] == '\0') {
     902             :                         /* SPDK_ERRLOG("auth user or secret is missing\n"); */
     903           0 :                         SPDK_ERRLOG("auth failed (name %.64s)\n", name);
     904           0 :                         goto error_return;
     905             :                 }
     906             : 
     907           0 :                 md5init(&md5ctx);
     908             :                 /* Identifier */
     909           0 :                 md5update(&md5ctx, conn->auth.chap_id, 1);
     910             :                 /* followed by secret */
     911           0 :                 md5update(&md5ctx, conn->auth.secret,
     912           0 :                           strlen(conn->auth.secret));
     913             :                 /* followed by Challenge Value */
     914           0 :                 md5update(&md5ctx, conn->auth.chap_challenge,
     915           0 :                           conn->auth.chap_challenge_len);
     916             :                 /* tgtmd5 is expecting Response Value */
     917           0 :                 md5final(tgtmd5, &md5ctx);
     918             : 
     919           0 :                 bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN, tgtmd5, SPDK_MD5DIGEST_LEN);
     920             : 
     921             : #if 0
     922             :                 SPDK_DEBUGLOG(iscsi, "tgtmd5=%s, resmd5=%s\n", in_val, response);
     923             :                 spdk_dump("tgtmd5", tgtmd5, SPDK_MD5DIGEST_LEN);
     924             :                 spdk_dump("resmd5", resmd5, SPDK_MD5DIGEST_LEN);
     925             : #endif
     926             : 
     927             :                 /* compare MD5 digest */
     928           0 :                 if (memcmp(tgtmd5, resmd5, SPDK_MD5DIGEST_LEN) != 0) {
     929             :                         /* not match */
     930             :                         /* SPDK_ERRLOG("auth user or secret is missing\n"); */
     931           0 :                         SPDK_ERRLOG("auth failed (name %.64s)\n", name);
     932           0 :                         goto error_return;
     933             :                 }
     934             :                 /* OK initiator's secret */
     935           0 :                 conn->authenticated = true;
     936             : 
     937             :                 /* mutual CHAP? */
     938           0 :                 identifier = iscsi_param_get_val(params, "CHAP_I");
     939           0 :                 if (identifier != NULL) {
     940           0 :                         conn->auth.chap_mid[0] = (uint8_t) strtol(identifier, NULL, 10);
     941           0 :                         challenge = iscsi_param_get_val(params, "CHAP_C");
     942           0 :                         if (challenge == NULL) {
     943           0 :                                 SPDK_ERRLOG("CHAP sequence error\n");
     944           0 :                                 goto error_return;
     945             :                         }
     946           0 :                         if (challenge[0] == '0' &&
     947           0 :                             (challenge[1] == 'x' || challenge[1] == 'X')) {
     948           0 :                                 rc = hex2bin(conn->auth.chap_mchallenge,
     949             :                                              ISCSI_CHAP_CHALLENGE_LEN, challenge);
     950           0 :                                 if (rc < 0) {
     951           0 :                                         SPDK_ERRLOG("challenge format error\n");
     952           0 :                                         goto error_return;
     953             :                                 }
     954           0 :                                 conn->auth.chap_mchallenge_len = rc;
     955           0 :                         } else if (challenge[0] == '0' &&
     956           0 :                                    (challenge[1] == 'b' || challenge[1] == 'B')) {
     957           0 :                                 challenge += 2;
     958           0 :                                 rc = spdk_base64_decode(conn->auth.chap_mchallenge,
     959             :                                                         &decoded_len, challenge);
     960           0 :                                 if (rc < 0) {
     961           0 :                                         SPDK_ERRLOG("challenge format error\n");
     962           0 :                                         goto error_return;
     963             :                                 }
     964           0 :                                 conn->auth.chap_mchallenge_len = decoded_len;
     965             :                         } else {
     966           0 :                                 SPDK_ERRLOG("challenge format error\n");
     967           0 :                                 goto error_return;
     968             :                         }
     969             : #if 0
     970             :                         spdk_dump("MChallenge", conn->auth.chap_mchallenge,
     971             :                                   conn->auth.chap_mchallenge_len);
     972             : #endif
     973           0 :                         SPDK_DEBUGLOG(iscsi, "got CHAP_I/CHAP_C\n");
     974             : 
     975           0 :                         if (conn->auth.muser[0] == '\0' || conn->auth.msecret[0] == '\0') {
     976             :                                 /* SPDK_ERRLOG("mutual auth user or secret is missing\n"); */
     977           0 :                                 SPDK_ERRLOG("auth failed (name %.64s)\n", name);
     978           0 :                                 goto error_return;
     979             :                         }
     980             : 
     981           0 :                         md5init(&md5ctx);
     982             :                         /* Identifier */
     983           0 :                         md5update(&md5ctx, conn->auth.chap_mid, 1);
     984             :                         /* followed by secret */
     985           0 :                         md5update(&md5ctx, conn->auth.msecret,
     986           0 :                                   strlen(conn->auth.msecret));
     987             :                         /* followed by Challenge Value */
     988           0 :                         md5update(&md5ctx, conn->auth.chap_mchallenge,
     989           0 :                                   conn->auth.chap_mchallenge_len);
     990             :                         /* tgtmd5 is Response Value */
     991           0 :                         md5final(tgtmd5, &md5ctx);
     992             : 
     993           0 :                         bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN, tgtmd5, SPDK_MD5DIGEST_LEN);
     994             : 
     995           0 :                         total = iscsi_append_text("CHAP_N", conn->auth.muser, data,
     996             :                                                   alloc_len, total);
     997           0 :                         total = iscsi_append_text("CHAP_R", in_val, data, alloc_len, total);
     998             :                 } else {
     999             :                         /* not mutual */
    1000           0 :                         if (conn->mutual_chap) {
    1001           0 :                                 SPDK_ERRLOG("required mutual CHAP\n");
    1002           0 :                                 goto error_return;
    1003             :                         }
    1004             :                 }
    1005             : 
    1006           0 :                 conn->auth.chap_phase = ISCSI_CHAP_PHASE_END;
    1007             :         } else {
    1008             :                 /* not found CHAP keys */
    1009           0 :                 SPDK_DEBUGLOG(iscsi, "start CHAP\n");
    1010           0 :                 conn->auth.chap_phase = ISCSI_CHAP_PHASE_WAIT_A;
    1011             :         }
    1012             : 
    1013           0 :         free(in_val);
    1014           0 :         return total;
    1015             : 
    1016           0 : error_return:
    1017           0 :         conn->auth.chap_phase = ISCSI_CHAP_PHASE_WAIT_A;
    1018           0 :         free(in_val);
    1019           0 :         return -1;
    1020             : }
    1021             : 
    1022             : static int
    1023           0 : iscsi_check_values(struct spdk_iscsi_conn *conn)
    1024             : {
    1025           0 :         if (conn->sess->FirstBurstLength > conn->sess->MaxBurstLength) {
    1026           0 :                 SPDK_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
    1027             :                             conn->sess->FirstBurstLength,
    1028             :                             conn->sess->MaxBurstLength);
    1029           0 :                 return -1;
    1030             :         }
    1031           0 :         if (conn->sess->FirstBurstLength > g_iscsi.FirstBurstLength) {
    1032           0 :                 SPDK_ERRLOG("FirstBurstLength(%d) > iSCSI target restriction(%d)\n",
    1033             :                             conn->sess->FirstBurstLength, g_iscsi.FirstBurstLength);
    1034           0 :                 return -1;
    1035             :         }
    1036           0 :         if (conn->sess->MaxBurstLength > 0x00ffffff) {
    1037           0 :                 SPDK_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n",
    1038             :                             conn->sess->MaxBurstLength);
    1039           0 :                 return -1;
    1040             :         }
    1041             : 
    1042           0 :         if (conn->MaxRecvDataSegmentLength < 512) {
    1043           0 :                 SPDK_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
    1044             :                             conn->MaxRecvDataSegmentLength);
    1045           0 :                 return -1;
    1046             :         }
    1047           0 :         if (conn->MaxRecvDataSegmentLength > 0x00ffffff) {
    1048           0 :                 SPDK_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
    1049             :                             conn->MaxRecvDataSegmentLength);
    1050           0 :                 return -1;
    1051             :         }
    1052           0 :         return 0;
    1053             : }
    1054             : 
    1055             : static int
    1056           0 : iscsi_conn_params_update(struct spdk_iscsi_conn *conn)
    1057             : {
    1058             :         int rc;
    1059             :         uint32_t recv_buf_size;
    1060             : 
    1061             :         /* update internal variables */
    1062           0 :         rc = iscsi_copy_param2var(conn);
    1063           0 :         if (rc < 0) {
    1064           0 :                 SPDK_ERRLOG("iscsi_copy_param2var() failed\n");
    1065           0 :                 if (conn->state < ISCSI_CONN_STATE_EXITING) {
    1066           0 :                         conn->state = ISCSI_CONN_STATE_EXITING;
    1067             :                 }
    1068           0 :                 return rc;
    1069             :         }
    1070             : 
    1071             :         /* check value */
    1072           0 :         rc = iscsi_check_values(conn);
    1073           0 :         if (rc < 0) {
    1074           0 :                 SPDK_ERRLOG("iscsi_check_values() failed\n");
    1075           0 :                 if (conn->state < ISCSI_CONN_STATE_EXITING) {
    1076           0 :                         conn->state = ISCSI_CONN_STATE_EXITING;
    1077             :                 }
    1078             :         }
    1079             : 
    1080           0 :         if (conn->sock == NULL) {
    1081           0 :                 SPDK_INFOLOG(iscsi, "socket is already closed.\n");
    1082           0 :                 return -ENXIO;
    1083             :         }
    1084             : 
    1085             :         /* The socket receive buffer may need to be adjusted based on the new parameters */
    1086             : 
    1087             :         /* Don't allow the recv buffer to be 0 or very large. */
    1088           0 :         recv_buf_size = spdk_max(0x1000, spdk_min(0x2000, conn->sess->FirstBurstLength));
    1089             : 
    1090             :         /* Add in extra space for the PDU */
    1091           0 :         recv_buf_size += ISCSI_BHS_LEN + ISCSI_AHS_LEN;
    1092             : 
    1093           0 :         if (conn->header_digest) {
    1094           0 :                 recv_buf_size += ISCSI_DIGEST_LEN;
    1095             :         }
    1096             : 
    1097           0 :         if (conn->data_digest) {
    1098           0 :                 recv_buf_size += ISCSI_DIGEST_LEN;
    1099             :         }
    1100             : 
    1101             :         /* Set up to buffer up to 4 commands with immediate data at once */
    1102           0 :         if (spdk_sock_set_recvbuf(conn->sock, recv_buf_size * 4) < 0) {
    1103             :                 /* Not fatal. */
    1104             :         }
    1105             : 
    1106           0 :         return rc;
    1107             : }
    1108             : 
    1109             : static void
    1110           0 : iscsi_conn_login_pdu_err_complete(void *arg)
    1111             : {
    1112           0 :         struct spdk_iscsi_conn *conn = arg;
    1113             : 
    1114           0 :         if (conn->full_feature) {
    1115           0 :                 iscsi_conn_params_update(conn);
    1116             :         }
    1117           0 : }
    1118             : 
    1119             : static void
    1120           0 : iscsi_conn_login_pdu_success_complete(void *arg)
    1121             : {
    1122           0 :         struct spdk_iscsi_conn *conn = arg;
    1123             : 
    1124             : 
    1125           0 :         if (conn->state >= ISCSI_CONN_STATE_EXITING) {
    1126             :                 /* Connection is being exited before this callback is executed. */
    1127           0 :                 SPDK_DEBUGLOG(iscsi, "Connection is already exited.\n");
    1128           0 :                 return;
    1129             :         }
    1130           0 :         if (conn->full_feature) {
    1131           0 :                 if (iscsi_conn_params_update(conn) != 0) {
    1132           0 :                         return;
    1133             :                 }
    1134             :         }
    1135           0 :         if (conn->full_feature != 0) {
    1136           0 :                 iscsi_conn_schedule(conn);
    1137             :         }
    1138             : }
    1139             : 
    1140             : /*
    1141             :  * The response function of spdk_iscsi_op_login
    1142             :  */
    1143             : static void
    1144           3 : iscsi_op_login_response(struct spdk_iscsi_conn *conn,
    1145             :                         struct spdk_iscsi_pdu *rsp_pdu, struct iscsi_param *params,
    1146             :                         iscsi_conn_xfer_complete_cb cb_fn)
    1147             : {
    1148             :         struct iscsi_bhs_login_rsp *rsph;
    1149             : 
    1150           3 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1151           3 :         rsph->version_max = ISCSI_VERSION;
    1152           3 :         rsph->version_act = ISCSI_VERSION;
    1153           3 :         DSET24(rsph->data_segment_len, rsp_pdu->data_segment_len);
    1154             : 
    1155           3 :         to_be32(&rsph->stat_sn, conn->StatSN);
    1156           3 :         conn->StatSN++;
    1157             : 
    1158           3 :         if (conn->sess != NULL) {
    1159           0 :                 to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
    1160           0 :                 to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
    1161             :         } else {
    1162           3 :                 to_be32(&rsph->exp_cmd_sn, rsp_pdu->cmd_sn);
    1163           3 :                 to_be32(&rsph->max_cmd_sn, rsp_pdu->cmd_sn);
    1164             :         }
    1165             : 
    1166           3 :         SPDK_LOGDUMP(iscsi, "PDU", (uint8_t *)rsph, ISCSI_BHS_LEN);
    1167           3 :         SPDK_LOGDUMP(iscsi, "DATA", rsp_pdu->data, rsp_pdu->data_segment_len);
    1168             : 
    1169             :         /* Set T/CSG/NSG to reserved if login error. */
    1170           3 :         if (rsph->status_class != 0) {
    1171           3 :                 rsph->flags &= ~(ISCSI_LOGIN_TRANSIT | ISCSI_LOGIN_CURRENT_STAGE_MASK |
    1172             :                                  ISCSI_LOGIN_NEXT_STAGE_MASK);
    1173             :         }
    1174           3 :         iscsi_param_free(params);
    1175           3 :         iscsi_conn_write_pdu(conn, rsp_pdu, cb_fn, conn);
    1176           3 : }
    1177             : 
    1178             : /*
    1179             :  * The function which is used to initialize the internal response data
    1180             :  * structure of iscsi login function.
    1181             :  * return:
    1182             :  * 0, success;
    1183             :  * otherwise, error;
    1184             :  */
    1185             : static int
    1186           4 : iscsi_op_login_rsp_init(struct spdk_iscsi_conn *conn,
    1187             :                         struct spdk_iscsi_pdu *pdu, struct spdk_iscsi_pdu *rsp_pdu)
    1188             : {
    1189             :         struct iscsi_bhs_login_req *reqh;
    1190             :         struct iscsi_bhs_login_rsp *rsph;
    1191             : 
    1192           4 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1193           4 :         rsph->opcode = ISCSI_OP_LOGIN_RSP;
    1194           4 :         rsph->status_class = ISCSI_CLASS_SUCCESS;
    1195           4 :         rsph->status_detail = ISCSI_LOGIN_ACCEPT;
    1196           4 :         rsp_pdu->data_segment_len = 0;
    1197             : 
    1198             :         /* The default MaxRecvDataSegmentLength 8192 is used during login. - RFC3720 */
    1199           4 :         rsp_pdu->data = calloc(1, 8192);
    1200           4 :         if (!rsp_pdu->data) {
    1201           0 :                 SPDK_ERRLOG("calloc() failed for data segment\n");
    1202           0 :                 rsph->status_class = ISCSI_CLASS_TARGET_ERROR;
    1203           0 :                 rsph->status_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
    1204           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1205             :         }
    1206           4 :         rsp_pdu->data_buf_len = 8192;
    1207             : 
    1208           4 :         reqh = (struct iscsi_bhs_login_req *)&pdu->bhs;
    1209           4 :         rsph->flags |= (reqh->flags & (ISCSI_LOGIN_TRANSIT | ISCSI_LOGIN_CONTINUE |
    1210             :                                        ISCSI_LOGIN_CURRENT_STAGE_MASK));
    1211           4 :         if (ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags)) {
    1212           2 :                 rsph->flags |= (reqh->flags & ISCSI_LOGIN_NEXT_STAGE_MASK);
    1213             :         }
    1214             : 
    1215             :         /* We don't need to convert from network byte order. Just store it */
    1216           4 :         memcpy(&rsph->isid, reqh->isid, 6);
    1217           4 :         rsph->tsih = reqh->tsih;
    1218           4 :         rsph->itt = reqh->itt;
    1219           4 :         rsp_pdu->cmd_sn = from_be32(&reqh->cmd_sn);
    1220             : 
    1221           4 :         if (rsph->tsih) {
    1222           0 :                 rsph->stat_sn = reqh->exp_stat_sn;
    1223             :         }
    1224             : 
    1225           4 :         SPDK_LOGDUMP(iscsi, "PDU", (uint8_t *)&pdu->bhs, ISCSI_BHS_LEN);
    1226             : 
    1227           4 :         SPDK_DEBUGLOG(iscsi,
    1228             :                       "T=%d, C=%d, CSG=%d, NSG=%d, Min=%d, Max=%d, ITT=%x\n",
    1229             :                       ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags),
    1230             :                       ISCSI_BHS_LOGIN_GET_CBIT(rsph->flags),
    1231             :                       ISCSI_BHS_LOGIN_GET_CSG(rsph->flags),
    1232             :                       ISCSI_BHS_LOGIN_GET_NSG(rsph->flags),
    1233             :                       reqh->version_min, reqh->version_max, from_be32(&rsph->itt));
    1234             : 
    1235           4 :         if (conn->sess != NULL) {
    1236           0 :                 SPDK_DEBUGLOG(iscsi,
    1237             :                               "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u,"
    1238             :                               "MaxCmdSN=%u\n", rsp_pdu->cmd_sn,
    1239             :                               from_be32(&rsph->stat_sn), conn->StatSN,
    1240             :                               conn->sess->ExpCmdSN,
    1241             :                               conn->sess->MaxCmdSN);
    1242             :         } else {
    1243           4 :                 SPDK_DEBUGLOG(iscsi,
    1244             :                               "CmdSN=%u, ExpStatSN=%u, StatSN=%u\n",
    1245             :                               rsp_pdu->cmd_sn, from_be32(&rsph->stat_sn),
    1246             :                               conn->StatSN);
    1247             :         }
    1248             : 
    1249           4 :         if (ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags) &&
    1250           2 :             ISCSI_BHS_LOGIN_GET_CBIT(rsph->flags)) {
    1251           1 :                 SPDK_ERRLOG("transit error\n");
    1252           1 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1253           1 :                 rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
    1254           1 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1255             :         }
    1256             :         /* make sure reqh->version_max < ISCSI_VERSION */
    1257           3 :         if (reqh->version_min > ISCSI_VERSION) {
    1258           1 :                 SPDK_ERRLOG("unsupported version min %d/max %d, expecting %d\n", reqh->version_min,
    1259             :                             reqh->version_max, ISCSI_VERSION);
    1260             :                 /* Unsupported version */
    1261             :                 /* set all reserved flag to zero */
    1262           1 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1263           1 :                 rsph->status_detail = ISCSI_LOGIN_UNSUPPORTED_VERSION;
    1264           1 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1265             :         }
    1266             : 
    1267           2 :         if ((ISCSI_BHS_LOGIN_GET_NSG(rsph->flags) == ISCSI_NSG_RESERVED_CODE) &&
    1268           1 :             ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags)) {
    1269             :                 /* set NSG and other bits to zero */
    1270           1 :                 rsph->flags &= ~(ISCSI_LOGIN_NEXT_STAGE_MASK | ISCSI_LOGIN_TRANSIT |
    1271             :                                  ISCSI_LOGIN_CURRENT_STAGE_MASK);
    1272           1 :                 SPDK_ERRLOG("Received reserved NSG code: %d\n", ISCSI_NSG_RESERVED_CODE);
    1273             :                 /* Initiator error */
    1274           1 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1275           1 :                 rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
    1276           1 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1277             :         }
    1278             : 
    1279           1 :         return 0;
    1280             : }
    1281             : 
    1282             : static int
    1283           0 : iscsi_op_login_store_incoming_params(struct spdk_iscsi_conn *conn,
    1284             :                                      struct spdk_iscsi_pdu *pdu, struct spdk_iscsi_pdu *rsp_pdu,
    1285             :                                      struct iscsi_param **params)
    1286             : {
    1287             :         struct iscsi_bhs_login_req *reqh;
    1288             :         struct iscsi_bhs_login_rsp *rsph;
    1289             :         int rc;
    1290             : 
    1291           0 :         reqh = (struct iscsi_bhs_login_req *)&pdu->bhs;
    1292           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1293             : 
    1294           0 :         rc = iscsi_parse_params(params, pdu->data,
    1295           0 :                                 pdu->data_segment_len, ISCSI_BHS_LOGIN_GET_CBIT(reqh->flags),
    1296             :                                 &conn->partial_text_parameter);
    1297           0 :         if (rc < 0) {
    1298           0 :                 SPDK_ERRLOG("iscsi_parse_params() failed\n");
    1299           0 :                 iscsi_param_free(*params);
    1300           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1301           0 :                 rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
    1302           0 :                 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
    1303             :         }
    1304             : 
    1305           0 :         return 0;
    1306             : }
    1307             : 
    1308             : /*
    1309             :  * This function is used to initialize the port info
    1310             :  * return
    1311             :  * 0: success
    1312             :  * otherwise: error
    1313             :  */
    1314             : static int
    1315           0 : iscsi_op_login_initialize_port(struct spdk_iscsi_conn *conn,
    1316             :                                struct spdk_iscsi_pdu *rsp_pdu,
    1317             :                                char *initiator_port_name,
    1318             :                                uint32_t name_length,
    1319             :                                struct iscsi_param *params)
    1320             : {
    1321             :         const char *val;
    1322             :         struct iscsi_bhs_login_rsp *rsph;
    1323           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1324             : 
    1325             :         /* Initiator Name and Port */
    1326           0 :         val = iscsi_param_get_val(params, "InitiatorName");
    1327           0 :         if (val == NULL) {
    1328           0 :                 SPDK_ERRLOG("InitiatorName is empty\n");
    1329             :                 /* Missing parameter */
    1330           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1331           0 :                 rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
    1332           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1333             :         }
    1334           0 :         snprintf(conn->initiator_name, sizeof(conn->initiator_name), "%s", val);
    1335           0 :         snprintf(initiator_port_name, name_length,
    1336           0 :                  "%s,i,0x%12.12" PRIx64, val, iscsi_get_isid(rsph->isid));
    1337           0 :         spdk_strlwr(conn->initiator_name);
    1338           0 :         spdk_strlwr(initiator_port_name);
    1339           0 :         SPDK_DEBUGLOG(iscsi, "Initiator name: %s\n", conn->initiator_name);
    1340           0 :         SPDK_DEBUGLOG(iscsi, "Initiator port: %s\n", initiator_port_name);
    1341             : 
    1342           0 :         return 0;
    1343             : }
    1344             : 
    1345             : /*
    1346             :  * This function is used to judge the session type
    1347             :  * return
    1348             :  * 0: success
    1349             :  * Other value: error
    1350             :  */
    1351             : static int
    1352           0 : iscsi_op_login_session_type(struct spdk_iscsi_conn *conn,
    1353             :                             struct spdk_iscsi_pdu *rsp_pdu,
    1354             :                             enum session_type *session_type,
    1355             :                             struct iscsi_param *params)
    1356             : {
    1357             :         const char *session_type_str;
    1358             :         struct iscsi_bhs_login_rsp *rsph;
    1359             : 
    1360           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1361           0 :         session_type_str = iscsi_param_get_val(params, "SessionType");
    1362           0 :         if (session_type_str == NULL) {
    1363           0 :                 if (rsph->tsih != 0) {
    1364           0 :                         *session_type = SESSION_TYPE_NORMAL;
    1365             :                 } else {
    1366           0 :                         SPDK_ERRLOG("SessionType is empty\n");
    1367             :                         /* Missing parameter */
    1368           0 :                         rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1369           0 :                         rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
    1370           0 :                         return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1371             :                 }
    1372             :         } else {
    1373           0 :                 if (strcasecmp(session_type_str, "Discovery") == 0) {
    1374           0 :                         *session_type = SESSION_TYPE_DISCOVERY;
    1375           0 :                 } else if (strcasecmp(session_type_str, "Normal") == 0) {
    1376           0 :                         *session_type = SESSION_TYPE_NORMAL;
    1377             :                 } else {
    1378           0 :                         *session_type = SESSION_TYPE_INVALID;
    1379           0 :                         SPDK_ERRLOG("SessionType is invalid\n");
    1380             :                         /* Missing parameter */
    1381           0 :                         rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1382           0 :                         rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
    1383           0 :                         return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1384             :                 }
    1385             :         }
    1386           0 :         SPDK_DEBUGLOG(iscsi, "Session Type: %s\n", session_type_str);
    1387             : 
    1388           0 :         return 0;
    1389             : }
    1390             : 
    1391             : /*
    1392             :  * This function is used to check the target info
    1393             :  * return:
    1394             :  * 0: success
    1395             :  * otherwise: error
    1396             :  */
    1397             : static int
    1398           7 : iscsi_op_login_check_target(struct spdk_iscsi_conn *conn,
    1399             :                             struct spdk_iscsi_pdu *rsp_pdu,
    1400             :                             const char *target_name,
    1401             :                             struct spdk_iscsi_tgt_node **target)
    1402             : {
    1403             :         struct iscsi_bhs_login_rsp *rsph;
    1404           7 :         char buf[MAX_TMPBUF] = {};
    1405             : 
    1406           7 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1407           7 :         *target = iscsi_find_tgt_node(target_name);
    1408           7 :         if (*target == NULL) {
    1409           1 :                 SPDK_WARNLOG("target %s not found\n", target_name);
    1410             :                 /* Not found */
    1411           1 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1412           1 :                 rsph->status_detail = ISCSI_LOGIN_TARGET_NOT_FOUND;
    1413           1 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1414             :         }
    1415           6 :         if (iscsi_tgt_node_is_destructed(*target)) {
    1416           0 :                 SPDK_ERRLOG("target %s is removed\n", target_name);
    1417           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1418           0 :                 rsph->status_detail = ISCSI_LOGIN_TARGET_REMOVED;
    1419           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1420             :         }
    1421           6 :         if (iscsi_tgt_node_is_redirected(conn, *target, buf, MAX_TMPBUF)) {
    1422           0 :                 SPDK_INFOLOG(iscsi, "target %s is redirected\n", target_name);
    1423           0 :                 rsp_pdu->data_segment_len = iscsi_append_text("TargetAddress",
    1424             :                                             buf,
    1425             :                                             rsp_pdu->data,
    1426           0 :                                             rsp_pdu->data_buf_len,
    1427           0 :                                             rsp_pdu->data_segment_len);
    1428           0 :                 rsph->status_class = ISCSI_CLASS_REDIRECT;
    1429           0 :                 rsph->status_detail = ISCSI_LOGIN_TARGET_TEMPORARILY_MOVED;
    1430           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1431             :         }
    1432           6 :         if (!iscsi_tgt_node_access(conn, *target, conn->initiator_name,
    1433           6 :                                    conn->initiator_addr)) {
    1434           1 :                 SPDK_ERRLOG("access denied\n");
    1435           1 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1436           1 :                 rsph->status_detail = ISCSI_LOGIN_AUTHORIZATION_FAIL;
    1437           1 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1438             :         }
    1439             : 
    1440           5 :         return 0;
    1441             : }
    1442             : 
    1443             : /*
    1444             :  * This function use to check the session
    1445             :  * return:
    1446             :  * 0, success
    1447             :  * otherwise: error
    1448             :  */
    1449             : static int
    1450           4 : iscsi_op_login_check_session(struct spdk_iscsi_conn *conn,
    1451             :                              struct spdk_iscsi_pdu *rsp_pdu,
    1452             :                              char *initiator_port_name, int cid)
    1453             : 
    1454             : {
    1455           4 :         int rc = 0;
    1456             :         struct iscsi_bhs_login_rsp *rsph;
    1457             : 
    1458           4 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1459             :         /* check existing session */
    1460           4 :         SPDK_DEBUGLOG(iscsi, "isid=%"PRIx64", tsih=%u, cid=%u\n",
    1461             :                       iscsi_get_isid(rsph->isid), from_be16(&rsph->tsih), cid);
    1462           4 :         if (rsph->tsih != 0) {
    1463             :                 /* multiple connections */
    1464           2 :                 rc = append_iscsi_sess(conn, initiator_port_name,
    1465           2 :                                        from_be16(&rsph->tsih), cid);
    1466           2 :                 if (rc != 0) {
    1467           2 :                         SPDK_ERRLOG("isid=%"PRIx64", tsih=%u, cid=%u:"
    1468             :                                     "spdk_append_iscsi_sess() failed\n",
    1469             :                                     iscsi_get_isid(rsph->isid), from_be16(&rsph->tsih),
    1470             :                                     cid);
    1471             :                         /* Can't include in session */
    1472           2 :                         rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1473           2 :                         rsph->status_detail = rc;
    1474           2 :                         return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1475             :                 }
    1476           2 :         } else if (!g_iscsi.AllowDuplicateIsid) {
    1477             :                 /* new session, drop old sess by the initiator */
    1478           1 :                 iscsi_drop_conns(conn, initiator_port_name, 0 /* drop old */);
    1479             :         }
    1480             : 
    1481           2 :         return rc;
    1482             : }
    1483             : 
    1484             : /*
    1485             :  * This function is used to del the original param and update it with new
    1486             :  * value
    1487             :  * return:
    1488             :  * 0: success
    1489             :  * otherwise: error
    1490             :  */
    1491             : static int
    1492           0 : iscsi_op_login_update_param(struct spdk_iscsi_conn *conn,
    1493             :                             const char *key, const char *value,
    1494             :                             const char *list)
    1495             : {
    1496           0 :         int rc = 0;
    1497             :         struct iscsi_param *new_param, *orig_param;
    1498             :         int index;
    1499             : 
    1500           0 :         orig_param = iscsi_param_find(conn->params, key);
    1501           0 :         if (orig_param == NULL) {
    1502           0 :                 SPDK_ERRLOG("orig_param %s not found\n", key);
    1503           0 :                 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
    1504             :         }
    1505             : 
    1506           0 :         index = orig_param->state_index;
    1507           0 :         rc = iscsi_param_del(&conn->params, key);
    1508           0 :         if (rc < 0) {
    1509           0 :                 SPDK_ERRLOG("iscsi_param_del(%s) failed\n", key);
    1510           0 :                 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
    1511             :         }
    1512           0 :         rc = iscsi_param_add(&conn->params, key, value, list, ISPT_LIST);
    1513           0 :         if (rc < 0) {
    1514           0 :                 SPDK_ERRLOG("iscsi_param_add() failed\n");
    1515           0 :                 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
    1516             :         }
    1517           0 :         new_param = iscsi_param_find(conn->params, key);
    1518           0 :         if (new_param == NULL) {
    1519           0 :                 SPDK_ERRLOG("iscsi_param_find() failed\n");
    1520           0 :                 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
    1521             :         }
    1522           0 :         new_param->state_index = index;
    1523           0 :         return rc;
    1524             : }
    1525             : 
    1526             : static int
    1527           2 : iscsi_negotiate_chap_param(struct spdk_iscsi_conn *conn)
    1528             : {
    1529           2 :         int rc = 0;
    1530             : 
    1531           2 :         if (conn->disable_chap) {
    1532           0 :                 rc = iscsi_op_login_update_param(conn, "AuthMethod", "None", "None");
    1533           2 :         } else if (conn->require_chap) {
    1534           0 :                 rc = iscsi_op_login_update_param(conn, "AuthMethod", "CHAP", "CHAP");
    1535             :         }
    1536             : 
    1537           2 :         return rc;
    1538             : }
    1539             : 
    1540             : /*
    1541             :  * The function which is used to handle the part of session discovery
    1542             :  * return:
    1543             :  * 0, success;
    1544             :  * otherwise: error;
    1545             :  */
    1546             : static int
    1547           0 : iscsi_op_login_session_discovery_chap(struct spdk_iscsi_conn *conn)
    1548             : {
    1549           0 :         return iscsi_negotiate_chap_param(conn);
    1550             : }
    1551             : 
    1552             : /*
    1553             :  * This function is used to update the param related with chap
    1554             :  * return:
    1555             :  * 0: success
    1556             :  * otherwise: error
    1557             :  */
    1558             : static int
    1559           2 : iscsi_op_login_negotiate_chap_param(struct spdk_iscsi_conn *conn,
    1560             :                                     struct spdk_iscsi_tgt_node *target)
    1561             : {
    1562           2 :         conn->disable_chap = target->disable_chap;
    1563           2 :         conn->require_chap = target->require_chap;
    1564           2 :         conn->mutual_chap = target->mutual_chap;
    1565           2 :         conn->chap_group = target->chap_group;
    1566             : 
    1567           2 :         return iscsi_negotiate_chap_param(conn);
    1568             : }
    1569             : 
    1570             : static int
    1571           2 : iscsi_op_login_negotiate_digest_param(struct spdk_iscsi_conn *conn,
    1572             :                                       struct spdk_iscsi_tgt_node *target)
    1573             : {
    1574             :         int rc;
    1575             : 
    1576           2 :         if (target->header_digest) {
    1577             :                 /*
    1578             :                  * User specified header digests, so update the list of
    1579             :                  *  HeaderDigest values to remove "None" so that only
    1580             :                  *  initiators who support CRC32C can connect.
    1581             :                  */
    1582           0 :                 rc = iscsi_op_login_update_param(conn, "HeaderDigest", "CRC32C", "CRC32C");
    1583           0 :                 if (rc < 0) {
    1584           0 :                         return rc;
    1585             :                 }
    1586             :         }
    1587             : 
    1588           2 :         if (target->data_digest) {
    1589             :                 /*
    1590             :                  * User specified data digests, so update the list of
    1591             :                  *  DataDigest values to remove "None" so that only
    1592             :                  *  initiators who support CRC32C can connect.
    1593             :                  */
    1594           0 :                 rc = iscsi_op_login_update_param(conn, "DataDigest", "CRC32C", "CRC32C");
    1595           0 :                 if (rc < 0) {
    1596           0 :                         return rc;
    1597             :                 }
    1598             :         }
    1599             : 
    1600           2 :         return 0;
    1601             : }
    1602             : 
    1603             : /*
    1604             :  * The function which is used to handle the part of normal login session
    1605             :  * return:
    1606             :  * 0, success;
    1607             :  * SPDK_ISCSI_LOGIN_ERROR_PARAMETER, parameter error;
    1608             :  */
    1609             : static int
    1610           7 : iscsi_op_login_session_normal(struct spdk_iscsi_conn *conn,
    1611             :                               struct spdk_iscsi_pdu *rsp_pdu,
    1612             :                               char *initiator_port_name,
    1613             :                               struct iscsi_param *params,
    1614             :                               int cid)
    1615             : {
    1616           7 :         struct spdk_iscsi_tgt_node *target = NULL;
    1617             :         const char *target_name;
    1618             :         const char *target_short_name;
    1619             :         struct iscsi_bhs_login_rsp *rsph;
    1620           7 :         int rc = 0;
    1621             : 
    1622           7 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1623           7 :         target_name = iscsi_param_get_val(params, "TargetName");
    1624             : 
    1625           7 :         if (target_name == NULL) {
    1626           3 :                 SPDK_ERRLOG("TargetName is empty\n");
    1627             :                 /* Missing parameter */
    1628           3 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1629           3 :                 rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
    1630           3 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1631             :         }
    1632             : 
    1633           4 :         memset(conn->target_short_name, 0, MAX_TARGET_NAME);
    1634           4 :         target_short_name = strstr(target_name, ":");
    1635           4 :         if (target_short_name != NULL) {
    1636           4 :                 target_short_name++; /* Advance past the ':' */
    1637           4 :                 if (strlen(target_short_name) >= MAX_TARGET_NAME) {
    1638           0 :                         SPDK_ERRLOG("Target Short Name (%s) is more than %u characters\n",
    1639             :                                     target_short_name, MAX_TARGET_NAME);
    1640             :                         /* Invalid request */
    1641           0 :                         rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1642           0 :                         rsph->status_detail = ISCSI_LOGIN_INVALID_LOGIN_REQUEST;
    1643           0 :                         return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1644             :                 }
    1645           4 :                 snprintf(conn->target_short_name, MAX_TARGET_NAME, "%s",
    1646             :                          target_short_name);
    1647             :         }
    1648             : 
    1649           4 :         pthread_mutex_lock(&g_iscsi.mutex);
    1650           4 :         rc = iscsi_op_login_check_target(conn, rsp_pdu, target_name, &target);
    1651           4 :         pthread_mutex_unlock(&g_iscsi.mutex);
    1652             : 
    1653           4 :         if (rc < 0) {
    1654           0 :                 return rc;
    1655             :         }
    1656             : 
    1657           4 :         conn->target = target;
    1658           4 :         conn->dev = target->dev;
    1659           8 :         conn->target_port = spdk_scsi_dev_find_port_by_id(target->dev,
    1660           4 :                             conn->pg_tag);
    1661             : 
    1662           4 :         rc = iscsi_op_login_check_session(conn, rsp_pdu,
    1663             :                                           initiator_port_name, cid);
    1664           4 :         if (rc < 0) {
    1665           2 :                 return rc;
    1666             :         }
    1667             : 
    1668             :         /* force target flags */
    1669           2 :         pthread_mutex_lock(&target->mutex);
    1670           2 :         rc = iscsi_op_login_negotiate_chap_param(conn, target);
    1671           2 :         pthread_mutex_unlock(&target->mutex);
    1672             : 
    1673           2 :         if (rc == 0) {
    1674           2 :                 rc = iscsi_op_login_negotiate_digest_param(conn, target);
    1675             :         }
    1676             : 
    1677           2 :         if (rc != 0) {
    1678             :                 /* Invalid request */
    1679           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1680           0 :                 rsph->status_detail = ISCSI_LOGIN_INVALID_LOGIN_REQUEST;
    1681             :         }
    1682             : 
    1683           2 :         return rc;
    1684             : }
    1685             : 
    1686             : /*
    1687             :  * This function is used to set the info in the connection data structure
    1688             :  * return
    1689             :  * 0: success
    1690             :  * otherwise: error
    1691             :  */
    1692             : static int
    1693           0 : iscsi_op_login_set_conn_info(struct spdk_iscsi_conn *conn,
    1694             :                              struct spdk_iscsi_pdu *rsp_pdu,
    1695             :                              char *initiator_port_name,
    1696             :                              enum session_type session_type, int cid)
    1697             : {
    1698           0 :         int rc = 0;
    1699             :         struct spdk_iscsi_tgt_node *target;
    1700             :         struct iscsi_bhs_login_rsp *rsph;
    1701           0 :         struct spdk_scsi_port *initiator_port;
    1702             : 
    1703           0 :         target = conn->target;
    1704             : 
    1705           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1706           0 :         conn->authenticated = false;
    1707           0 :         conn->auth.chap_phase = ISCSI_CHAP_PHASE_WAIT_A;
    1708           0 :         conn->cid = cid;
    1709             : 
    1710           0 :         if (conn->sess == NULL) {
    1711             :                 /* create initiator port */
    1712           0 :                 initiator_port = spdk_scsi_port_create(iscsi_get_isid(rsph->isid), 0, initiator_port_name);
    1713           0 :                 if (initiator_port == NULL) {
    1714           0 :                         SPDK_ERRLOG("create_port() failed\n");
    1715           0 :                         rsph->status_class = ISCSI_CLASS_TARGET_ERROR;
    1716           0 :                         rsph->status_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
    1717           0 :                         return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1718             :                 }
    1719             : 
    1720             :                 /* new session */
    1721           0 :                 rc = create_iscsi_sess(conn, target, session_type);
    1722           0 :                 if (rc < 0) {
    1723           0 :                         spdk_scsi_port_free(&initiator_port);
    1724           0 :                         SPDK_ERRLOG("create_sess() failed\n");
    1725           0 :                         rsph->status_class = ISCSI_CLASS_TARGET_ERROR;
    1726           0 :                         rsph->status_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
    1727           0 :                         return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1728             :                 }
    1729             :                 /* initialize parameters */
    1730           0 :                 conn->sess->initiator_port = initiator_port;
    1731           0 :                 conn->StatSN = from_be32(&rsph->stat_sn);
    1732           0 :                 conn->sess->isid = iscsi_get_isid(rsph->isid);
    1733             : 
    1734             :                 /* Initiator port TransportID */
    1735           0 :                 spdk_scsi_port_set_iscsi_transport_id(conn->sess->initiator_port,
    1736           0 :                                                       conn->initiator_name,
    1737           0 :                                                       conn->sess->isid);
    1738             : 
    1739             :                 /* Discovery sessions will not have a target. */
    1740           0 :                 if (target != NULL) {
    1741           0 :                         conn->sess->queue_depth = target->queue_depth;
    1742             :                 } else {
    1743             :                         /*
    1744             :                          * Assume discovery sessions have an effective command
    1745             :                          *  windows size of 1.
    1746             :                          */
    1747           0 :                         conn->sess->queue_depth = 1;
    1748             :                 }
    1749           0 :                 conn->sess->ExpCmdSN = rsp_pdu->cmd_sn;
    1750           0 :                 conn->sess->MaxCmdSN = rsp_pdu->cmd_sn + conn->sess->queue_depth - 1;
    1751             :         }
    1752             : 
    1753           0 :         conn->initiator_port = conn->sess->initiator_port;
    1754             : 
    1755           0 :         return 0;
    1756             : }
    1757             : 
    1758             : /*
    1759             :  * This function is used to set the target info
    1760             :  * return
    1761             :  * 0: success
    1762             :  * otherwise: error
    1763             :  */
    1764             : static int
    1765           0 : iscsi_op_login_set_target_info(struct spdk_iscsi_conn *conn,
    1766             :                                struct spdk_iscsi_pdu *rsp_pdu,
    1767             :                                enum session_type session_type)
    1768             : {
    1769           0 :         char buf[MAX_TMPBUF];
    1770             :         const char *val;
    1771           0 :         int rc = 0;
    1772           0 :         struct spdk_iscsi_tgt_node *target = conn->target;
    1773             : 
    1774             :         /* declarative parameters */
    1775           0 :         if (target != NULL) {
    1776           0 :                 pthread_mutex_lock(&target->mutex);
    1777           0 :                 if (target->alias[0] != '\0') {
    1778           0 :                         snprintf(buf, sizeof buf, "%s", target->alias);
    1779             :                 } else {
    1780           0 :                         snprintf(buf, sizeof buf, "%s", "");
    1781             :                 }
    1782           0 :                 pthread_mutex_unlock(&target->mutex);
    1783           0 :                 rc = iscsi_param_set(conn->sess->params, "TargetAlias", buf);
    1784           0 :                 if (rc < 0) {
    1785           0 :                         SPDK_ERRLOG("iscsi_param_set() failed\n");
    1786           0 :                         return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
    1787             :                 }
    1788             :         }
    1789           0 :         snprintf(buf, sizeof buf, "%s:%s,%d", conn->portal_host, conn->portal_port,
    1790             :                  conn->pg_tag);
    1791           0 :         rc = iscsi_param_set(conn->sess->params, "TargetAddress", buf);
    1792           0 :         if (rc < 0) {
    1793           0 :                 SPDK_ERRLOG("iscsi_param_set() failed\n");
    1794           0 :                 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
    1795             :         }
    1796           0 :         snprintf(buf, sizeof buf, "%d", conn->pg_tag);
    1797           0 :         rc = iscsi_param_set(conn->sess->params, "TargetPortalGroupTag", buf);
    1798           0 :         if (rc < 0) {
    1799           0 :                 SPDK_ERRLOG("iscsi_param_set() failed\n");
    1800           0 :                 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
    1801             :         }
    1802             : 
    1803             :         /* write in response */
    1804           0 :         if (target != NULL) {
    1805           0 :                 val = iscsi_param_get_val(conn->sess->params, "TargetAlias");
    1806           0 :                 if (val != NULL && strlen(val) != 0) {
    1807           0 :                         rsp_pdu->data_segment_len = iscsi_append_param(conn,
    1808             :                                                     "TargetAlias",
    1809             :                                                     rsp_pdu->data,
    1810           0 :                                                     rsp_pdu->data_buf_len,
    1811           0 :                                                     rsp_pdu->data_segment_len);
    1812             :                 }
    1813           0 :                 if (session_type == SESSION_TYPE_DISCOVERY) {
    1814           0 :                         rsp_pdu->data_segment_len = iscsi_append_param(conn,
    1815             :                                                     "TargetAddress",
    1816             :                                                     rsp_pdu->data,
    1817           0 :                                                     rsp_pdu->data_buf_len,
    1818           0 :                                                     rsp_pdu->data_segment_len);
    1819             :                 }
    1820           0 :                 rsp_pdu->data_segment_len = iscsi_append_param(conn,
    1821             :                                             "TargetPortalGroupTag",
    1822             :                                             rsp_pdu->data,
    1823           0 :                                             rsp_pdu->data_buf_len,
    1824           0 :                                             rsp_pdu->data_segment_len);
    1825             :         }
    1826             : 
    1827           0 :         return rc;
    1828             : }
    1829             : 
    1830             : /*
    1831             :  * This function is used to handle the login of iscsi initiator when there is
    1832             :  * no session
    1833             :  * return:
    1834             :  * 0, success;
    1835             :  * SPDK_ISCSI_LOGIN_ERROR_PARAMETER, parameter error;
    1836             :  * SPDK_ISCSI_LOGIN_ERROR_RESPONSE,  used to notify the login fail.
    1837             :  */
    1838             : static int
    1839           0 : iscsi_op_login_phase_none(struct spdk_iscsi_conn *conn,
    1840             :                           struct spdk_iscsi_pdu *rsp_pdu,
    1841             :                           struct iscsi_param *params, int cid)
    1842             : {
    1843           0 :         enum session_type session_type;
    1844           0 :         char initiator_port_name[MAX_INITIATOR_PORT_NAME];
    1845             :         struct iscsi_bhs_login_rsp *rsph;
    1846           0 :         int rc = 0;
    1847           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1848             : 
    1849           0 :         conn->target = NULL;
    1850           0 :         conn->dev = NULL;
    1851             : 
    1852           0 :         rc = iscsi_op_login_initialize_port(conn, rsp_pdu, initiator_port_name,
    1853             :                                             MAX_INITIATOR_PORT_NAME, params);
    1854           0 :         if (rc < 0) {
    1855           0 :                 return rc;
    1856             :         }
    1857             : 
    1858           0 :         rc = iscsi_op_login_session_type(conn, rsp_pdu, &session_type, params);
    1859           0 :         if (rc < 0) {
    1860           0 :                 return rc;
    1861             :         }
    1862             : 
    1863             :         /* Target Name and Port */
    1864           0 :         if (session_type == SESSION_TYPE_NORMAL) {
    1865           0 :                 rc = iscsi_op_login_session_normal(conn, rsp_pdu,
    1866             :                                                    initiator_port_name,
    1867             :                                                    params, cid);
    1868           0 :                 if (rc < 0) {
    1869           0 :                         return rc;
    1870             :                 }
    1871             : 
    1872           0 :         } else if (session_type == SESSION_TYPE_DISCOVERY) {
    1873           0 :                 rsph->tsih = 0;
    1874             : 
    1875             :                 /* force target flags */
    1876           0 :                 pthread_mutex_lock(&g_iscsi.mutex);
    1877           0 :                 rc = iscsi_op_login_session_discovery_chap(conn);
    1878           0 :                 pthread_mutex_unlock(&g_iscsi.mutex);
    1879           0 :                 if (rc < 0) {
    1880           0 :                         return rc;
    1881             :                 }
    1882             :         } else {
    1883           0 :                 SPDK_ERRLOG("unknown session type\n");
    1884             :                 /* Missing parameter */
    1885           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1886           0 :                 rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
    1887           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1888             :         }
    1889             : 
    1890           0 :         rc = iscsi_op_login_set_conn_info(conn, rsp_pdu, initiator_port_name,
    1891             :                                           session_type, cid);
    1892           0 :         if (rc < 0) {
    1893           0 :                 return rc;
    1894             :         }
    1895             : 
    1896             :         /* limit conns on discovery session */
    1897           0 :         if (session_type == SESSION_TYPE_DISCOVERY) {
    1898           0 :                 conn->sess->MaxConnections = 1;
    1899           0 :                 rc = iscsi_param_set_int(conn->sess->params,
    1900             :                                          "MaxConnections",
    1901           0 :                                          conn->sess->MaxConnections);
    1902           0 :                 if (rc < 0) {
    1903           0 :                         SPDK_ERRLOG("iscsi_param_set_int() failed\n");
    1904           0 :                         return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
    1905             :                 }
    1906             :         }
    1907             : 
    1908           0 :         return iscsi_op_login_set_target_info(conn, rsp_pdu, session_type);
    1909             : }
    1910             : 
    1911             : /*
    1912             :  * This function is used to set the csg bit case in rsp
    1913             :  * return:
    1914             :  * 0, success
    1915             :  * otherwise: error
    1916             :  */
    1917             : static int
    1918           0 : iscsi_op_login_rsp_handle_csg_bit(struct spdk_iscsi_conn *conn,
    1919             :                                   struct spdk_iscsi_pdu *rsp_pdu,
    1920             :                                   struct iscsi_param *params)
    1921             : {
    1922             :         const char *auth_method;
    1923             :         int rc;
    1924             :         struct iscsi_bhs_login_rsp *rsph;
    1925           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    1926             : 
    1927           0 :         switch (ISCSI_BHS_LOGIN_GET_CSG(rsph->flags)) {
    1928           0 :         case ISCSI_SECURITY_NEGOTIATION_PHASE:
    1929             :                 /* SecurityNegotiation */
    1930           0 :                 auth_method = iscsi_param_get_val(conn->params, "AuthMethod");
    1931           0 :                 if (auth_method == NULL) {
    1932           0 :                         SPDK_ERRLOG("AuthMethod is empty\n");
    1933             :                         /* Missing parameter */
    1934           0 :                         rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1935           0 :                         rsph->status_detail = ISCSI_LOGIN_MISSING_PARMS;
    1936           0 :                         return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1937             :                 }
    1938           0 :                 if (strcasecmp(auth_method, "None") == 0) {
    1939           0 :                         conn->authenticated = true;
    1940             :                 } else {
    1941           0 :                         rc = iscsi_auth_params(conn, params, auth_method,
    1942           0 :                                                rsp_pdu->data, rsp_pdu->data_buf_len,
    1943           0 :                                                rsp_pdu->data_segment_len);
    1944           0 :                         if (rc < 0) {
    1945           0 :                                 SPDK_ERRLOG("iscsi_auth_params() failed\n");
    1946             :                                 /* Authentication failure */
    1947           0 :                                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1948           0 :                                 rsph->status_detail = ISCSI_LOGIN_AUTHENT_FAIL;
    1949           0 :                                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1950             :                         }
    1951           0 :                         rsp_pdu->data_segment_len = rc;
    1952           0 :                         if (!conn->authenticated) {
    1953             :                                 /* not complete */
    1954           0 :                                 rsph->flags &= ~ISCSI_LOGIN_TRANSIT;
    1955             :                         } else {
    1956           0 :                                 if (conn->auth.chap_phase != ISCSI_CHAP_PHASE_END) {
    1957           0 :                                         SPDK_DEBUGLOG(iscsi, "CHAP phase not complete");
    1958             :                                 }
    1959             :                         }
    1960             : 
    1961           0 :                         SPDK_LOGDUMP(iscsi, "Negotiated Auth Params",
    1962             :                                      rsp_pdu->data, rsp_pdu->data_segment_len);
    1963             :                 }
    1964           0 :                 break;
    1965             : 
    1966           0 :         case ISCSI_OPERATIONAL_NEGOTIATION_PHASE:
    1967             :                 /* LoginOperationalNegotiation */
    1968           0 :                 if (conn->state == ISCSI_CONN_STATE_INVALID) {
    1969           0 :                         if (conn->require_chap) {
    1970             :                                 /* Authentication failure */
    1971           0 :                                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1972           0 :                                 rsph->status_detail = ISCSI_LOGIN_AUTHENT_FAIL;
    1973           0 :                                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1974             :                         } else {
    1975             :                                 /* AuthMethod=None */
    1976           0 :                                 conn->authenticated = true;
    1977             :                         }
    1978             :                 }
    1979           0 :                 if (!conn->authenticated) {
    1980           0 :                         SPDK_ERRLOG("authentication error\n");
    1981             :                         /* Authentication failure */
    1982           0 :                         rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1983           0 :                         rsph->status_detail = ISCSI_LOGIN_AUTHENT_FAIL;
    1984           0 :                         return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1985             :                 }
    1986           0 :                 break;
    1987             : 
    1988           0 :         case ISCSI_FULL_FEATURE_PHASE:
    1989             :                 /* FullFeaturePhase */
    1990           0 :                 SPDK_ERRLOG("XXX Login in FullFeaturePhase\n");
    1991             :                 /* Initiator error */
    1992           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    1993           0 :                 rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
    1994           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    1995             : 
    1996           0 :         default:
    1997           0 :                 SPDK_ERRLOG("unknown stage\n");
    1998             :                 /* Initiator error */
    1999           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    2000           0 :                 rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
    2001           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    2002             :         }
    2003             : 
    2004           0 :         return 0;
    2005             : }
    2006             : 
    2007             : /* This function is used to notify the session info
    2008             :  * return
    2009             :  * 0: success
    2010             :  * otherwise: error
    2011             :  */
    2012             : static int
    2013           0 : iscsi_op_login_notify_session_info(struct spdk_iscsi_conn *conn,
    2014             :                                    struct spdk_iscsi_pdu *rsp_pdu)
    2015             : {
    2016             :         struct iscsi_bhs_login_rsp *rsph;
    2017             : 
    2018           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    2019           0 :         if (conn->sess->session_type == SESSION_TYPE_NORMAL) {
    2020             :                 /* normal session */
    2021           0 :                 SPDK_DEBUGLOG(iscsi, "Login from %s (%s) on %s tgt_node%d"
    2022             :                               " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
    2023             :                               " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
    2024             :                               conn->initiator_name, conn->initiator_addr,
    2025             :                               conn->target->name, conn->target->num,
    2026             :                               conn->portal_host, conn->portal_port, conn->pg_tag,
    2027             :                               conn->sess->isid, conn->sess->tsih, conn->cid,
    2028             :                               (iscsi_param_eq_val(conn->params, "HeaderDigest", "CRC32C")
    2029             :                                ? "on" : "off"),
    2030             :                               (iscsi_param_eq_val(conn->params, "DataDigest", "CRC32C")
    2031             :                                ? "on" : "off"));
    2032           0 :         } else if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
    2033             :                 /* discovery session */
    2034           0 :                 SPDK_DEBUGLOG(iscsi, "Login(discovery) from %s (%s) on"
    2035             :                               " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
    2036             :                               " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
    2037             :                               conn->initiator_name, conn->initiator_addr,
    2038             :                               conn->portal_host, conn->portal_port, conn->pg_tag,
    2039             :                               conn->sess->isid, conn->sess->tsih, conn->cid,
    2040             :                               (iscsi_param_eq_val(conn->params, "HeaderDigest", "CRC32C")
    2041             :                                ? "on" : "off"),
    2042             :                               (iscsi_param_eq_val(conn->params, "DataDigest", "CRC32C")
    2043             :                                ? "on" : "off"));
    2044             :         } else {
    2045           0 :                 SPDK_ERRLOG("unknown session type\n");
    2046             :                 /* Initiator error */
    2047           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    2048           0 :                 rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
    2049           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    2050             :         }
    2051             : 
    2052           0 :         return 0;
    2053             : }
    2054             : 
    2055             : /*
    2056             :  * This function is to handle the tbit cases
    2057             :  * return
    2058             :  * 0: success
    2059             :  * otherwise error
    2060             :  */
    2061             : static int
    2062           0 : iscsi_op_login_rsp_handle_t_bit(struct spdk_iscsi_conn *conn,
    2063             :                                 struct spdk_iscsi_pdu *rsp_pdu)
    2064             : {
    2065             :         int rc;
    2066             :         struct iscsi_bhs_login_rsp *rsph;
    2067           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    2068             : 
    2069           0 :         switch (ISCSI_BHS_LOGIN_GET_NSG(rsph->flags)) {
    2070           0 :         case ISCSI_SECURITY_NEGOTIATION_PHASE:
    2071             :                 /* SecurityNegotiation */
    2072           0 :                 conn->login_phase = ISCSI_SECURITY_NEGOTIATION_PHASE;
    2073           0 :                 break;
    2074             : 
    2075           0 :         case ISCSI_OPERATIONAL_NEGOTIATION_PHASE:
    2076             :                 /* LoginOperationalNegotiation */
    2077           0 :                 conn->login_phase = ISCSI_OPERATIONAL_NEGOTIATION_PHASE;
    2078           0 :                 break;
    2079             : 
    2080           0 :         case ISCSI_FULL_FEATURE_PHASE:
    2081             :                 /* FullFeaturePhase */
    2082           0 :                 conn->login_phase = ISCSI_FULL_FEATURE_PHASE;
    2083           0 :                 to_be16(&rsph->tsih, conn->sess->tsih);
    2084             : 
    2085           0 :                 rc = iscsi_op_login_notify_session_info(conn, rsp_pdu);
    2086           0 :                 if (rc < 0) {
    2087           0 :                         return rc;
    2088             :                 }
    2089             : 
    2090           0 :                 conn->full_feature = 1;
    2091           0 :                 if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
    2092           0 :                         spdk_trace_owner_append_description(conn->trace_id, "discovery");
    2093             :                 } else {
    2094           0 :                         assert(conn->target != NULL);
    2095           0 :                         spdk_trace_owner_append_description(conn->trace_id, conn->target->name);
    2096             :                 }
    2097           0 :                 break;
    2098             : 
    2099           0 :         default:
    2100           0 :                 SPDK_ERRLOG("unknown stage\n");
    2101             :                 /* Initiator error */
    2102           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    2103           0 :                 rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
    2104           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    2105             :         }
    2106             : 
    2107           0 :         return 0;
    2108             : }
    2109             : 
    2110             : /*
    2111             :  * This function is used to set the values of the internal data structure used
    2112             :  * by spdk_iscsi_op_login function
    2113             :  * return:
    2114             :  * 0, used to notify the a successful login
    2115             :  * SPDK_ISCSI_LOGIN_ERROR_RESPONSE,  used to notify a failure login.
    2116             :  */
    2117             : static int
    2118           0 : iscsi_op_login_rsp_handle(struct spdk_iscsi_conn *conn,
    2119             :                           struct spdk_iscsi_pdu *rsp_pdu, struct iscsi_param **params)
    2120             : {
    2121             :         int rc;
    2122             :         struct iscsi_bhs_login_rsp *rsph;
    2123           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    2124             : 
    2125             :         /* negotiate parameters */
    2126           0 :         rc = iscsi_negotiate_params(conn, params, rsp_pdu->data,
    2127           0 :                                     rsp_pdu->data_buf_len,
    2128           0 :                                     rsp_pdu->data_segment_len);
    2129           0 :         if (rc < 0) {
    2130             :                 /*
    2131             :                  * iscsi_negotiate_params just returns -1 on failure,
    2132             :                  *  so translate this into meaningful response codes and
    2133             :                  *  return values.
    2134             :                  */
    2135           0 :                 rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    2136           0 :                 rsph->status_detail = ISCSI_LOGIN_INITIATOR_ERROR;
    2137           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    2138             :         }
    2139             : 
    2140           0 :         rsp_pdu->data_segment_len = rc;
    2141           0 :         SPDK_LOGDUMP(iscsi, "Negotiated Params", rsp_pdu->data, rc);
    2142             : 
    2143             :         /* handle the CSG bit case */
    2144           0 :         rc = iscsi_op_login_rsp_handle_csg_bit(conn, rsp_pdu, *params);
    2145           0 :         if (rc < 0) {
    2146           0 :                 return rc;
    2147             :         }
    2148             : 
    2149             :         /* handle the T bit case */
    2150           0 :         if (ISCSI_BHS_LOGIN_GET_TBIT(rsph->flags)) {
    2151           0 :                 rc = iscsi_op_login_rsp_handle_t_bit(conn, rsp_pdu);
    2152             :         }
    2153             : 
    2154           0 :         return rc;
    2155             : }
    2156             : 
    2157             : static int
    2158           7 : iscsi_pdu_hdr_op_login(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    2159             : {
    2160             :         int rc;
    2161             :         struct iscsi_bhs_login_req *reqh;
    2162             :         struct spdk_iscsi_pdu *rsp_pdu;
    2163             : 
    2164           7 :         if (conn->full_feature && conn->sess != NULL &&
    2165           1 :             conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
    2166           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    2167             :         }
    2168             : 
    2169           6 :         reqh = (struct iscsi_bhs_login_req *)&pdu->bhs;
    2170           6 :         pdu->cmd_sn = from_be32(&reqh->cmd_sn);
    2171             : 
    2172             :         /* During login processing, use the 8KB default FirstBurstLength as
    2173             :          *  our maximum data segment length value.
    2174             :          */
    2175           6 :         if (pdu->data_segment_len > SPDK_ISCSI_FIRST_BURST_LENGTH) {
    2176           1 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    2177             :         }
    2178             : 
    2179           5 :         rsp_pdu = iscsi_get_pdu(conn);
    2180           5 :         if (rsp_pdu == NULL) {
    2181           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    2182             :         }
    2183           4 :         rc = iscsi_op_login_rsp_init(conn, pdu, rsp_pdu);
    2184           4 :         if (rc < 0) {
    2185           3 :                 iscsi_op_login_response(conn, rsp_pdu, NULL, iscsi_conn_login_pdu_err_complete);
    2186           3 :                 return 0;
    2187             :         }
    2188             : 
    2189           1 :         conn->login_rsp_pdu = rsp_pdu;
    2190           1 :         return 0;
    2191             : }
    2192             : 
    2193             : static int
    2194           0 : iscsi_pdu_payload_op_login(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    2195             : {
    2196             :         int rc;
    2197             :         struct iscsi_bhs_login_req *reqh;
    2198             :         struct spdk_iscsi_pdu *rsp_pdu;
    2199           0 :         struct iscsi_param *params = NULL;
    2200             :         int cid;
    2201             : 
    2202           0 :         if (conn->login_rsp_pdu == NULL) {
    2203           0 :                 return 0;
    2204             :         }
    2205             : 
    2206           0 :         spdk_poller_unregister(&conn->login_timer);
    2207           0 :         rsp_pdu = conn->login_rsp_pdu;
    2208             : 
    2209           0 :         reqh = (struct iscsi_bhs_login_req *)&pdu->bhs;
    2210           0 :         cid = from_be16(&reqh->cid);
    2211             : 
    2212           0 :         rc = iscsi_op_login_store_incoming_params(conn, pdu, rsp_pdu, &params);
    2213           0 :         if (rc < 0) {
    2214           0 :                 iscsi_op_login_response(conn, rsp_pdu, NULL, iscsi_conn_login_pdu_err_complete);
    2215           0 :                 return 0;
    2216             :         }
    2217             : 
    2218           0 :         if (conn->state == ISCSI_CONN_STATE_INVALID) {
    2219           0 :                 rc = iscsi_op_login_phase_none(conn, rsp_pdu, params, cid);
    2220           0 :                 if (rc == SPDK_ISCSI_LOGIN_ERROR_RESPONSE || rc == SPDK_ISCSI_LOGIN_ERROR_PARAMETER) {
    2221           0 :                         iscsi_op_login_response(conn, rsp_pdu, params, iscsi_conn_login_pdu_err_complete);
    2222           0 :                         return 0;
    2223             :                 }
    2224             :         }
    2225             : 
    2226           0 :         rc = iscsi_op_login_rsp_handle(conn, rsp_pdu, &params);
    2227           0 :         if (rc == SPDK_ISCSI_LOGIN_ERROR_RESPONSE) {
    2228           0 :                 iscsi_op_login_response(conn, rsp_pdu, params, iscsi_conn_login_pdu_err_complete);
    2229           0 :                 return 0;
    2230             :         }
    2231             : 
    2232           0 :         conn->state = ISCSI_CONN_STATE_RUNNING;
    2233           0 :         iscsi_op_login_response(conn, rsp_pdu, params, iscsi_conn_login_pdu_success_complete);
    2234           0 :         return 0;
    2235             : }
    2236             : 
    2237             : static int
    2238           7 : iscsi_pdu_hdr_op_text(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    2239             : {
    2240             :         uint32_t task_tag;
    2241             :         uint32_t ExpStatSN;
    2242             :         int F_bit, C_bit;
    2243             :         struct iscsi_bhs_text_req *reqh;
    2244             : 
    2245           7 :         if (pdu->data_segment_len > iscsi_get_max_immediate_data_size()) {
    2246           1 :                 SPDK_ERRLOG("data segment len(=%zu) > immediate data len(=%"PRIu32")\n",
    2247             :                             pdu->data_segment_len, iscsi_get_max_immediate_data_size());
    2248           1 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    2249             :         }
    2250             : 
    2251           6 :         reqh = (struct iscsi_bhs_text_req *)&pdu->bhs;
    2252             : 
    2253           6 :         F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
    2254           6 :         C_bit = !!(reqh->flags & ISCSI_TEXT_CONTINUE);
    2255           6 :         task_tag = from_be32(&reqh->itt);
    2256           6 :         ExpStatSN = from_be32(&reqh->exp_stat_sn);
    2257             : 
    2258           6 :         SPDK_DEBUGLOG(iscsi, "I=%d, F=%d, C=%d, ITT=%x, TTT=%x\n",
    2259             :                       reqh->immediate, F_bit, C_bit, task_tag, from_be32(&reqh->ttt));
    2260             : 
    2261           6 :         SPDK_DEBUGLOG(iscsi,
    2262             :                       "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
    2263             :                       pdu->cmd_sn, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
    2264             :                       conn->sess->MaxCmdSN);
    2265             : 
    2266           6 :         if (ExpStatSN != conn->StatSN) {
    2267             : #if 0
    2268             :                 SPDK_ERRLOG("StatSN(%u) error\n", ExpStatSN);
    2269             :                 return -1;
    2270             : #else
    2271             :                 /* StarPort have a bug */
    2272           3 :                 SPDK_DEBUGLOG(iscsi, "StatSN(%u) rewound\n", ExpStatSN);
    2273           3 :                 conn->StatSN = ExpStatSN;
    2274             : #endif
    2275             :         }
    2276             : 
    2277           6 :         if (F_bit && C_bit) {
    2278           1 :                 SPDK_ERRLOG("final and continue\n");
    2279           1 :                 return -1;
    2280             :         }
    2281             : 
    2282             :         /*
    2283             :          * If this is the first text op in a sequence, save the ITT so we can
    2284             :          * compare it against the ITT for subsequent ops in the same sequence.
    2285             :          * If a subsequent text op in same sequence has a different ITT, reject
    2286             :          * that PDU.
    2287             :          */
    2288           5 :         if (conn->sess->current_text_itt == 0xffffffffU) {
    2289           1 :                 conn->sess->current_text_itt = task_tag;
    2290           4 :         } else if (conn->sess->current_text_itt != task_tag) {
    2291           1 :                 SPDK_ERRLOG("The correct itt is %u, and the current itt is %u...\n",
    2292             :                             conn->sess->current_text_itt, task_tag);
    2293           1 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    2294             :         }
    2295             : 
    2296           4 :         return 0;
    2297             : }
    2298             : 
    2299             : static void
    2300           0 : iscsi_conn_text_pdu_complete(void *arg)
    2301             : {
    2302           0 :         struct spdk_iscsi_conn *conn = arg;
    2303             : 
    2304           0 :         iscsi_conn_params_update(conn);
    2305           0 : }
    2306             : 
    2307             : static int
    2308           1 : iscsi_pdu_payload_op_text(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    2309             : {
    2310           1 :         struct iscsi_param *params = NULL;
    2311             :         struct spdk_iscsi_pdu *rsp_pdu;
    2312             :         uint8_t *data;
    2313             :         uint64_t lun;
    2314             :         uint32_t task_tag;
    2315             :         const char *val;
    2316             :         int F_bit, C_bit;
    2317             :         int data_len;
    2318             :         int alloc_len;
    2319             :         int rc;
    2320             :         struct iscsi_bhs_text_req *reqh;
    2321             :         struct iscsi_bhs_text_resp *rsph;
    2322             : 
    2323           1 :         data_len = 0;
    2324           1 :         alloc_len = conn->MaxRecvDataSegmentLength;
    2325             : 
    2326           1 :         reqh = (struct iscsi_bhs_text_req *)&pdu->bhs;
    2327             : 
    2328           1 :         F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
    2329           1 :         C_bit = !!(reqh->flags & ISCSI_TEXT_CONTINUE);
    2330           1 :         lun = from_be64(&reqh->lun);
    2331           1 :         task_tag = from_be32(&reqh->itt);
    2332             : 
    2333             :         /* store incoming parameters */
    2334           1 :         rc = iscsi_parse_params(&params, pdu->data, pdu->data_segment_len,
    2335             :                                 C_bit, &conn->partial_text_parameter);
    2336           1 :         if (rc < 0) {
    2337           0 :                 SPDK_ERRLOG("iscsi_parse_params() failed\n");
    2338           0 :                 iscsi_param_free(params);
    2339           0 :                 return -1;
    2340             :         }
    2341             : 
    2342           1 :         if (pdu->data_segment_len == 0 && params == NULL) {
    2343           1 :                 params = conn->params_text;
    2344           1 :                 conn->params_text = NULL;
    2345             :         }
    2346             : 
    2347           1 :         data = calloc(1, alloc_len);
    2348           1 :         if (!data) {
    2349           0 :                 SPDK_ERRLOG("calloc() failed for data segment\n");
    2350           0 :                 iscsi_param_free(params);
    2351           0 :                 return -ENOMEM;
    2352             :         }
    2353             : 
    2354             :         /* negotiate parameters */
    2355           1 :         data_len = iscsi_negotiate_params(conn, &params,
    2356             :                                           data, alloc_len, data_len);
    2357           1 :         if (data_len < 0) {
    2358           0 :                 SPDK_ERRLOG("iscsi_negotiate_params() failed\n");
    2359           0 :                 iscsi_param_free(params);
    2360           0 :                 free(data);
    2361           0 :                 return -1;
    2362             :         }
    2363             : 
    2364             :         /* sendtargets is special case */
    2365           1 :         val = iscsi_param_get_val(params, "SendTargets");
    2366           1 :         if (val != NULL) {
    2367           0 :                 if (iscsi_param_eq_val(conn->sess->params,
    2368             :                                        "SessionType", "Discovery")) {
    2369           0 :                         if (strcasecmp(val, "") == 0) {
    2370           0 :                                 val = "ALL";
    2371             :                         }
    2372             : 
    2373           0 :                         data_len = iscsi_send_tgts(conn,
    2374           0 :                                                    conn->initiator_name,
    2375             :                                                    val, data, alloc_len,
    2376             :                                                    data_len);
    2377             :                 } else {
    2378           0 :                         if (strcasecmp(val, "") == 0) {
    2379           0 :                                 val = conn->target->name;
    2380             :                         }
    2381             : 
    2382           0 :                         if (strcasecmp(val, "ALL") == 0) {
    2383             :                                 /* not in discovery session */
    2384           0 :                                 data_len = iscsi_append_text("SendTargets", "Reject",
    2385             :                                                              data, alloc_len, data_len);
    2386             :                         } else {
    2387           0 :                                 data_len = iscsi_send_tgts(conn,
    2388           0 :                                                            conn->initiator_name,
    2389             :                                                            val, data, alloc_len,
    2390             :                                                            data_len);
    2391             :                         }
    2392             :                 }
    2393             : 
    2394           0 :                 if (conn->send_tgt_completed_size != 0) {
    2395           0 :                         F_bit = 0;
    2396           0 :                         C_bit = 1;
    2397             :                 }
    2398             :         } else {
    2399           1 :                 if (iscsi_param_eq_val(conn->sess->params, "SessionType", "Discovery")) {
    2400           0 :                         iscsi_param_free(params);
    2401           0 :                         free(data);
    2402           0 :                         return SPDK_ISCSI_CONNECTION_FATAL;
    2403             :                 }
    2404             :         }
    2405             : 
    2406           1 :         if (spdk_likely(conn->send_tgt_completed_size == 0)) {
    2407           1 :                 iscsi_param_free(params);
    2408             :         } else {
    2409           0 :                 conn->params_text = params;
    2410             :         }
    2411           1 :         SPDK_LOGDUMP(iscsi, "Negotiated Params", data, data_len);
    2412             : 
    2413             :         /* response PDU */
    2414           1 :         rsp_pdu = iscsi_get_pdu(conn);
    2415           1 :         if (rsp_pdu == NULL) {
    2416           0 :                 free(data);
    2417           0 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    2418             :         }
    2419           1 :         rsph = (struct iscsi_bhs_text_resp *)&rsp_pdu->bhs;
    2420             : 
    2421           1 :         rsp_pdu->data = data;
    2422           1 :         rsph->opcode = ISCSI_OP_TEXT_RSP;
    2423             : 
    2424           1 :         if (F_bit) {
    2425           0 :                 rsph->flags |= ISCSI_FLAG_FINAL;
    2426             :         }
    2427             : 
    2428           1 :         if (C_bit) {
    2429           1 :                 rsph->flags |= ISCSI_TEXT_CONTINUE;
    2430             :         }
    2431             : 
    2432           1 :         DSET24(rsph->data_segment_len, data_len);
    2433           1 :         to_be64(&rsph->lun, lun);
    2434           1 :         to_be32(&rsph->itt, task_tag);
    2435             : 
    2436           1 :         if (F_bit) {
    2437           0 :                 rsph->ttt = 0xffffffffU;
    2438           0 :                 conn->sess->current_text_itt = 0xffffffffU;
    2439             :         } else {
    2440           1 :                 to_be32(&rsph->ttt, 1 + conn->id);
    2441             :         }
    2442             : 
    2443           1 :         to_be32(&rsph->stat_sn, conn->StatSN);
    2444           1 :         conn->StatSN++;
    2445             : 
    2446           1 :         if (reqh->immediate == 0) {
    2447           1 :                 conn->sess->MaxCmdSN++;
    2448             :         }
    2449             : 
    2450           1 :         to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
    2451           1 :         to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
    2452             : 
    2453           1 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_text_pdu_complete, conn);
    2454           1 :         return 0;
    2455             : }
    2456             : 
    2457             : static void
    2458           0 : iscsi_conn_logout_pdu_complete(void *arg)
    2459             : {
    2460           0 :         struct spdk_iscsi_conn *conn = arg;
    2461             : 
    2462           0 :         if (conn->sess == NULL) {
    2463             :                 /*
    2464             :                  * login failed but initiator still sent a logout rather than
    2465             :                  *  just closing the TCP connection.
    2466             :                  */
    2467           0 :                 SPDK_DEBUGLOG(iscsi, "Logout(login failed) from %s (%s) on"
    2468             :                               " (%s:%s,%d)\n",
    2469             :                               conn->initiator_name, conn->initiator_addr,
    2470             :                               conn->portal_host, conn->portal_port, conn->pg_tag);
    2471           0 :         } else if (iscsi_param_eq_val(conn->sess->params, "SessionType", "Normal")) {
    2472           0 :                 SPDK_DEBUGLOG(iscsi, "Logout from %s (%s) on %s tgt_node%d"
    2473             :                               " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
    2474             :                               " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
    2475             :                               conn->initiator_name, conn->initiator_addr,
    2476             :                               conn->target->name, conn->target->num,
    2477             :                               conn->portal_host, conn->portal_port, conn->pg_tag,
    2478             :                               conn->sess->isid, conn->sess->tsih, conn->cid,
    2479             :                               (iscsi_param_eq_val(conn->params, "HeaderDigest", "CRC32C")
    2480             :                                ? "on" : "off"),
    2481             :                               (iscsi_param_eq_val(conn->params, "DataDigest", "CRC32C")
    2482             :                                ? "on" : "off"));
    2483             :         } else {
    2484             :                 /* discovery session */
    2485           0 :                 SPDK_DEBUGLOG(iscsi, "Logout(discovery) from %s (%s) on"
    2486             :                               " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
    2487             :                               " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
    2488             :                               conn->initiator_name, conn->initiator_addr,
    2489             :                               conn->portal_host, conn->portal_port, conn->pg_tag,
    2490             :                               conn->sess->isid, conn->sess->tsih, conn->cid,
    2491             :                               (iscsi_param_eq_val(conn->params, "HeaderDigest", "CRC32C")
    2492             :                                ? "on" : "off"),
    2493             :                               (iscsi_param_eq_val(conn->params, "DataDigest", "CRC32C")
    2494             :                                ? "on" : "off"));
    2495             :         }
    2496           0 : }
    2497             : 
    2498             : static int
    2499           5 : iscsi_pdu_hdr_op_logout(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    2500             : {
    2501             :         struct spdk_iscsi_pdu *rsp_pdu;
    2502             :         uint32_t task_tag;
    2503             :         uint32_t ExpStatSN;
    2504             :         int response;
    2505             :         struct iscsi_bhs_logout_req *reqh;
    2506             :         struct iscsi_bhs_logout_resp *rsph;
    2507             :         uint16_t cid;
    2508             : 
    2509           5 :         reqh = (struct iscsi_bhs_logout_req *)&pdu->bhs;
    2510             : 
    2511           5 :         cid = from_be16(&reqh->cid);
    2512           5 :         task_tag = from_be32(&reqh->itt);
    2513           5 :         ExpStatSN = from_be32(&reqh->exp_stat_sn);
    2514             : 
    2515           5 :         SPDK_DEBUGLOG(iscsi, "reason=%d, ITT=%x, cid=%d\n",
    2516             :                       reqh->reason, task_tag, cid);
    2517             : 
    2518           5 :         if (conn->sess != NULL) {
    2519           4 :                 if (conn->sess->session_type == SESSION_TYPE_DISCOVERY &&
    2520           1 :                     reqh->reason != ISCSI_LOGOUT_REASON_CLOSE_SESSION) {
    2521           1 :                         SPDK_ERRLOG("Target can accept logout only with reason \"close the session\" "
    2522             :                                     "on discovery session. %d is not acceptable reason.\n",
    2523             :                                     reqh->reason);
    2524           1 :                         return SPDK_ISCSI_CONNECTION_FATAL;
    2525             :                 }
    2526             : 
    2527           3 :                 SPDK_DEBUGLOG(iscsi,
    2528             :                               "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
    2529             :                               pdu->cmd_sn, ExpStatSN, conn->StatSN,
    2530             :                               conn->sess->ExpCmdSN, conn->sess->MaxCmdSN);
    2531             : 
    2532           3 :                 if (pdu->cmd_sn != conn->sess->ExpCmdSN) {
    2533           3 :                         SPDK_DEBUGLOG(iscsi, "CmdSN(%u) might have dropped\n", pdu->cmd_sn);
    2534             :                         /* ignore error */
    2535             :                 }
    2536             :         } else {
    2537           1 :                 SPDK_DEBUGLOG(iscsi, "CmdSN=%u, ExpStatSN=%u, StatSN=%u\n",
    2538             :                               pdu->cmd_sn, ExpStatSN, conn->StatSN);
    2539             :         }
    2540             : 
    2541           4 :         if (ExpStatSN != conn->StatSN) {
    2542           3 :                 SPDK_DEBUGLOG(iscsi, "StatSN(%u/%u) might have dropped\n",
    2543             :                               ExpStatSN, conn->StatSN);
    2544             :                 /* ignore error */
    2545             :         }
    2546             : 
    2547           4 :         if (conn->cid == cid) {
    2548             :                 /* connection or session closed successfully */
    2549           3 :                 response = 0;
    2550           3 :                 iscsi_conn_logout(conn);
    2551             :         } else {
    2552           1 :                 response = 1;
    2553             :         }
    2554             : 
    2555             :         /* response PDU */
    2556           4 :         rsp_pdu = iscsi_get_pdu(conn);
    2557           4 :         if (rsp_pdu == NULL) {
    2558           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    2559             :         }
    2560           3 :         rsph = (struct iscsi_bhs_logout_resp *)&rsp_pdu->bhs;
    2561           3 :         rsp_pdu->data = NULL;
    2562           3 :         rsph->opcode = ISCSI_OP_LOGOUT_RSP;
    2563           3 :         rsph->flags |= 0x80; /* bit 0 must be 1 */
    2564           3 :         rsph->response = response;
    2565           3 :         DSET24(rsph->data_segment_len, 0);
    2566           3 :         to_be32(&rsph->itt, task_tag);
    2567             : 
    2568           3 :         if (conn->sess != NULL) {
    2569           2 :                 to_be32(&rsph->stat_sn, conn->StatSN);
    2570           2 :                 conn->StatSN++;
    2571             : 
    2572           2 :                 if (conn->sess->connections == 1) {
    2573           2 :                         conn->sess->MaxCmdSN++;
    2574             :                 }
    2575             : 
    2576           2 :                 to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
    2577           2 :                 to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
    2578             :         } else {
    2579           1 :                 to_be32(&rsph->stat_sn, conn->StatSN);
    2580           1 :                 conn->StatSN++;
    2581           1 :                 to_be32(&rsph->exp_cmd_sn, pdu->cmd_sn);
    2582           1 :                 to_be32(&rsph->max_cmd_sn, pdu->cmd_sn);
    2583             :         }
    2584             : 
    2585           3 :         rsph->time_2_wait = 0;
    2586           3 :         rsph->time_2_retain = 0;
    2587             : 
    2588           3 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_logout_pdu_complete, conn);
    2589             : 
    2590           3 :         return 0;
    2591             : }
    2592             : 
    2593             : static int
    2594           9 : iscsi_send_r2t(struct spdk_iscsi_conn *conn,
    2595             :                struct spdk_iscsi_task *task, int offset,
    2596             :                int len, uint32_t transfer_tag, uint32_t *R2TSN)
    2597             : {
    2598             :         struct spdk_iscsi_pdu *rsp_pdu;
    2599             :         struct iscsi_bhs_r2t *rsph;
    2600             :         uint64_t fmt_lun;
    2601             : 
    2602             :         /* R2T PDU */
    2603           9 :         rsp_pdu = iscsi_get_pdu(conn);
    2604           9 :         if (rsp_pdu == NULL) {
    2605           0 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    2606             :         }
    2607           9 :         rsph = (struct iscsi_bhs_r2t *)&rsp_pdu->bhs;
    2608           9 :         rsp_pdu->data = NULL;
    2609           9 :         rsph->opcode = ISCSI_OP_R2T;
    2610           9 :         rsph->flags |= 0x80; /* bit 0 is default to 1 */
    2611           9 :         fmt_lun = spdk_scsi_lun_id_int_to_fmt(task->lun_id);
    2612           9 :         to_be64(&rsph->lun, fmt_lun);
    2613           9 :         to_be32(&rsph->itt, task->tag);
    2614           9 :         to_be32(&rsph->ttt, transfer_tag);
    2615             : 
    2616           9 :         to_be32(&rsph->stat_sn, conn->StatSN);
    2617           9 :         to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
    2618           9 :         to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
    2619             : 
    2620           9 :         to_be32(&rsph->r2t_sn, *R2TSN);
    2621           9 :         *R2TSN += 1;
    2622             : 
    2623           9 :         task->r2t_datasn = 0; /* next expected datasn to ack */
    2624             : 
    2625           9 :         to_be32(&rsph->buffer_offset, (uint32_t)offset);
    2626           9 :         to_be32(&rsph->desired_xfer_len, (uint32_t)len);
    2627           9 :         task->desired_data_transfer_length = (size_t)len;
    2628             : 
    2629             :         /* we need to hold onto this task/cmd because until the PDU has been
    2630             :          * written out */
    2631           9 :         rsp_pdu->task = task;
    2632           9 :         task->scsi.ref++;
    2633             : 
    2634           9 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
    2635             : 
    2636           9 :         return 0;
    2637             : }
    2638             : 
    2639             : /* This function is used to remove the r2t pdu from snack_pdu_list by < task, r2t_sn> info */
    2640             : static struct spdk_iscsi_pdu *
    2641           0 : iscsi_remove_r2t_pdu_from_snack_list(struct spdk_iscsi_conn *conn,
    2642             :                                      struct spdk_iscsi_task *task,
    2643             :                                      uint32_t r2t_sn)
    2644             : {
    2645             :         struct spdk_iscsi_pdu *pdu;
    2646             :         struct iscsi_bhs_r2t *r2t_header;
    2647             : 
    2648           0 :         TAILQ_FOREACH(pdu, &conn->snack_pdu_list, tailq) {
    2649           0 :                 if (pdu->bhs.opcode == ISCSI_OP_R2T) {
    2650           0 :                         r2t_header = (struct iscsi_bhs_r2t *)&pdu->bhs;
    2651           0 :                         if (pdu->task == task &&
    2652           0 :                             from_be32(&r2t_header->r2t_sn) == r2t_sn) {
    2653           0 :                                 TAILQ_REMOVE(&conn->snack_pdu_list, pdu, tailq);
    2654           0 :                                 return pdu;
    2655             :                         }
    2656             :                 }
    2657             :         }
    2658             : 
    2659           0 :         return NULL;
    2660             : }
    2661             : 
    2662             : /* This function is used re-send the r2t packet */
    2663             : static int
    2664           0 : iscsi_send_r2t_recovery(struct spdk_iscsi_conn *conn,
    2665             :                         struct spdk_iscsi_task *task, uint32_t r2t_sn,
    2666             :                         bool send_new_r2tsn)
    2667             : {
    2668             :         struct spdk_iscsi_pdu *pdu;
    2669             :         struct iscsi_bhs_r2t *rsph;
    2670             :         uint32_t transfer_len;
    2671             :         uint32_t len;
    2672             :         int rc;
    2673             : 
    2674             :         /* remove the r2t pdu from the snack_list */
    2675           0 :         pdu = iscsi_remove_r2t_pdu_from_snack_list(conn, task, r2t_sn);
    2676           0 :         if (!pdu) {
    2677           0 :                 SPDK_DEBUGLOG(iscsi, "No pdu is found\n");
    2678           0 :                 return -1;
    2679             :         }
    2680             : 
    2681             :         /* flag
    2682             :          * false: only need to re-send the old r2t with changing statsn
    2683             :          * true: we send a r2t with new r2tsn
    2684             :          */
    2685           0 :         if (!send_new_r2tsn) {
    2686           0 :                 to_be32(&pdu->bhs.stat_sn, conn->StatSN);
    2687           0 :                 iscsi_conn_write_pdu(conn, pdu, iscsi_conn_pdu_generic_complete, NULL);
    2688             :         } else {
    2689           0 :                 rsph = (struct iscsi_bhs_r2t *)&pdu->bhs;
    2690           0 :                 transfer_len = from_be32(&rsph->desired_xfer_len);
    2691             : 
    2692             :                 /* still need to increase the acked r2tsn */
    2693           0 :                 task->acked_r2tsn++;
    2694           0 :                 len = spdk_min(conn->sess->MaxBurstLength,
    2695             :                                (transfer_len - task->next_expected_r2t_offset));
    2696             : 
    2697             :                 /* remove the old_r2t_pdu */
    2698           0 :                 iscsi_conn_free_pdu(conn, pdu);
    2699             : 
    2700             :                 /* re-send a new r2t pdu */
    2701           0 :                 rc = iscsi_send_r2t(conn, task, task->next_expected_r2t_offset,
    2702             :                                     len, task->ttt, &task->R2TSN);
    2703           0 :                 if (rc < 0) {
    2704           0 :                         return SPDK_ISCSI_CONNECTION_FATAL;
    2705             :                 }
    2706             :         }
    2707             : 
    2708           0 :         return 0;
    2709             : }
    2710             : 
    2711             : static int
    2712          20 : add_transfer_task(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
    2713             : {
    2714             :         uint32_t transfer_len;
    2715             :         size_t max_burst_len;
    2716             :         size_t segment_len;
    2717             :         size_t data_len;
    2718             :         int len;
    2719             :         int rc;
    2720             :         int data_out_req;
    2721             : 
    2722          20 :         transfer_len = task->scsi.transfer_len;
    2723          20 :         data_len = iscsi_task_get_pdu(task)->data_segment_len;
    2724          20 :         max_burst_len = conn->sess->MaxBurstLength;
    2725          20 :         segment_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
    2726          20 :         data_out_req = 1 + (transfer_len - data_len - 1) / segment_len;
    2727          20 :         task->data_out_cnt = data_out_req;
    2728             : 
    2729             :         /*
    2730             :          * If we already have too many tasks using R2T, then queue this task
    2731             :          *  and start sending R2T for it after some of the tasks using R2T/data
    2732             :          *  out buffers complete.
    2733             :          */
    2734          20 :         if (conn->pending_r2t >= g_iscsi.MaxR2TPerConnection) {
    2735           4 :                 TAILQ_INSERT_TAIL(&conn->queued_r2t_tasks, task, link);
    2736           4 :                 return 0;
    2737             :         }
    2738             : 
    2739          16 :         conn->data_out_cnt += data_out_req;
    2740          16 :         conn->pending_r2t++;
    2741             : 
    2742          16 :         task->next_expected_r2t_offset = data_len;
    2743          16 :         task->current_r2t_length = 0;
    2744          16 :         task->R2TSN = 0;
    2745             :         /* According to RFC3720 10.8.5, 0xffffffff is
    2746             :          * reserved for TTT in R2T.
    2747             :          */
    2748          16 :         if (++conn->ttt == 0xffffffffu) {
    2749           0 :                 conn->ttt = 0;
    2750             :         }
    2751          16 :         task->ttt = conn->ttt;
    2752             : 
    2753          22 :         while (data_len != transfer_len) {
    2754           8 :                 len = spdk_min(max_burst_len, (transfer_len - data_len));
    2755           8 :                 rc = iscsi_send_r2t(conn, task, data_len, len,
    2756             :                                     task->ttt, &task->R2TSN);
    2757           8 :                 if (rc < 0) {
    2758           0 :                         SPDK_ERRLOG("iscsi_send_r2t() failed\n");
    2759           0 :                         return rc;
    2760             :                 }
    2761           8 :                 data_len += len;
    2762           8 :                 task->next_r2t_offset = data_len;
    2763           8 :                 task->outstanding_r2t++;
    2764           8 :                 if (conn->sess->MaxOutstandingR2T == task->outstanding_r2t) {
    2765           2 :                         break;
    2766             :                 }
    2767             :         }
    2768             : 
    2769          16 :         TAILQ_INSERT_TAIL(&conn->active_r2t_tasks, task, link);
    2770          16 :         task->is_r2t_active = true;
    2771          16 :         return 0;
    2772             : }
    2773             : 
    2774             : /* If there are additional large writes queued for R2Ts, start them now.
    2775             :  *  This is called when a large write is just completed or when multiple LUNs
    2776             :  *  are attached and large write tasks for the specific LUN are cleared.
    2777             :  */
    2778             : static void
    2779           9 : start_queued_transfer_tasks(struct spdk_iscsi_conn *conn)
    2780             : {
    2781             :         struct spdk_iscsi_task *task, *tmp;
    2782             : 
    2783          12 :         TAILQ_FOREACH_SAFE(task, &conn->queued_r2t_tasks, link, tmp) {
    2784           4 :                 if (conn->pending_r2t < g_iscsi.MaxR2TPerConnection) {
    2785           3 :                         TAILQ_REMOVE(&conn->queued_r2t_tasks, task, link);
    2786           3 :                         add_transfer_task(conn, task);
    2787             :                 } else {
    2788           1 :                         break;
    2789             :                 }
    2790             :         }
    2791           9 : }
    2792             : 
    2793             : bool
    2794           5 : iscsi_del_transfer_task(struct spdk_iscsi_conn *conn, uint32_t task_tag)
    2795             : {
    2796             :         struct spdk_iscsi_task *task, *tmp;
    2797             : 
    2798           5 :         TAILQ_FOREACH_SAFE(task, &conn->active_r2t_tasks, link, tmp) {
    2799           5 :                 if (task->tag == task_tag) {
    2800           5 :                         assert(conn->data_out_cnt >= task->data_out_cnt);
    2801           5 :                         conn->data_out_cnt -= task->data_out_cnt;
    2802             : 
    2803           5 :                         assert(conn->pending_r2t > 0);
    2804           5 :                         conn->pending_r2t--;
    2805             : 
    2806           5 :                         assert(task->is_r2t_active == true);
    2807           5 :                         TAILQ_REMOVE(&conn->active_r2t_tasks, task, link);
    2808           5 :                         task->is_r2t_active = false;
    2809           5 :                         iscsi_task_put(task);
    2810             : 
    2811           5 :                         start_queued_transfer_tasks(conn);
    2812           5 :                         return true;
    2813             :                 }
    2814             :         }
    2815           0 :         return false;
    2816             : }
    2817             : 
    2818             : void
    2819           4 : iscsi_clear_all_transfer_task(struct spdk_iscsi_conn *conn,
    2820             :                               struct spdk_scsi_lun *lun,
    2821             :                               struct spdk_iscsi_pdu *pdu)
    2822             : {
    2823             :         struct spdk_iscsi_task *task, *task_tmp;
    2824             :         struct spdk_iscsi_pdu *pdu_tmp;
    2825             : 
    2826          16 :         TAILQ_FOREACH_SAFE(task, &conn->active_r2t_tasks, link, task_tmp) {
    2827          12 :                 pdu_tmp = iscsi_task_get_pdu(task);
    2828          12 :                 if ((lun == NULL || lun == task->scsi.lun) &&
    2829           6 :                     (pdu == NULL || spdk_sn32_lt(pdu_tmp->cmd_sn, pdu->cmd_sn))) {
    2830           6 :                         task->outstanding_r2t = 0;
    2831           6 :                         task->next_r2t_offset = 0;
    2832           6 :                         task->next_expected_r2t_offset = 0;
    2833           6 :                         task->current_data_offset = 0;
    2834           6 :                         assert(conn->data_out_cnt >= task->data_out_cnt);
    2835           6 :                         conn->data_out_cnt -= task->data_out_cnt;
    2836           6 :                         assert(conn->pending_r2t > 0);
    2837           6 :                         conn->pending_r2t--;
    2838             : 
    2839           6 :                         TAILQ_REMOVE(&conn->active_r2t_tasks, task, link);
    2840           6 :                         task->is_r2t_active = false;
    2841           6 :                         if (lun != NULL && spdk_scsi_lun_is_removing(lun)) {
    2842           5 :                                 spdk_scsi_task_process_null_lun(&task->scsi);
    2843           5 :                                 iscsi_task_response(conn, task);
    2844             :                         }
    2845           6 :                         iscsi_task_put(task);
    2846             :                 }
    2847             :         }
    2848             : 
    2849           7 :         TAILQ_FOREACH_SAFE(task, &conn->queued_r2t_tasks, link, task_tmp) {
    2850           3 :                 pdu_tmp = iscsi_task_get_pdu(task);
    2851           3 :                 if ((lun == NULL || lun == task->scsi.lun) &&
    2852           0 :                     (pdu == NULL || spdk_sn32_lt(pdu_tmp->cmd_sn, pdu->cmd_sn))) {
    2853           0 :                         TAILQ_REMOVE(&conn->queued_r2t_tasks, task, link);
    2854           0 :                         task->is_r2t_active = false;
    2855           0 :                         if (lun != NULL && spdk_scsi_lun_is_removing(lun)) {
    2856           0 :                                 spdk_scsi_task_process_null_lun(&task->scsi);
    2857           0 :                                 iscsi_task_response(conn, task);
    2858             :                         }
    2859           0 :                         iscsi_task_put(task);
    2860             :                 }
    2861             :         }
    2862             : 
    2863           4 :         start_queued_transfer_tasks(conn);
    2864           4 : }
    2865             : 
    2866             : static struct spdk_iscsi_task *
    2867          65 : get_transfer_task(struct spdk_iscsi_conn *conn, uint32_t transfer_tag)
    2868             : {
    2869             :         struct spdk_iscsi_task *task;
    2870             : 
    2871         121 :         TAILQ_FOREACH(task, &conn->active_r2t_tasks, link) {
    2872         105 :                 if (task->ttt == transfer_tag) {
    2873          49 :                         return task;
    2874             :                 }
    2875             :         }
    2876             : 
    2877          16 :         return NULL;
    2878             : }
    2879             : 
    2880             : static void
    2881           0 : iscsi_conn_datain_pdu_complete(void *arg)
    2882             : {
    2883           0 :         struct spdk_iscsi_conn *conn = arg;
    2884             : 
    2885           0 :         iscsi_conn_handle_queued_datain_tasks(conn);
    2886           0 : }
    2887             : 
    2888             : static int
    2889           2 : iscsi_send_datain(struct spdk_iscsi_conn *conn,
    2890             :                   struct spdk_iscsi_task *task, int datain_flag,
    2891             :                   int residual_len, int offset, int DataSN, int len)
    2892             : {
    2893             :         struct spdk_iscsi_pdu *rsp_pdu;
    2894             :         struct iscsi_bhs_data_in *rsph;
    2895             :         uint32_t task_tag;
    2896             :         uint32_t transfer_tag;
    2897             :         int F_bit, U_bit, O_bit, S_bit;
    2898             :         struct spdk_iscsi_task *primary;
    2899             :         struct spdk_scsi_lun *lun_dev;
    2900             : 
    2901           2 :         primary = iscsi_task_get_primary(task);
    2902             : 
    2903             :         /* DATA PDU */
    2904           2 :         rsp_pdu = iscsi_get_pdu(conn);
    2905           2 :         rsph = (struct iscsi_bhs_data_in *)&rsp_pdu->bhs;
    2906           2 :         rsp_pdu->data = task->scsi.iovs[0].iov_base + offset;
    2907           2 :         rsp_pdu->data_buf_len = task->scsi.iovs[0].iov_len - offset;
    2908           2 :         rsp_pdu->data_valid_bytes = len;
    2909           2 :         rsp_pdu->data_from_mempool = true;
    2910             : 
    2911           2 :         task_tag = task->tag;
    2912           2 :         transfer_tag = 0xffffffffU;
    2913             : 
    2914           2 :         F_bit = datain_flag & ISCSI_FLAG_FINAL;
    2915           2 :         O_bit = datain_flag & ISCSI_DATAIN_OVERFLOW;
    2916           2 :         U_bit = datain_flag & ISCSI_DATAIN_UNDERFLOW;
    2917           2 :         S_bit = datain_flag & ISCSI_DATAIN_STATUS;
    2918             : 
    2919             :         /*
    2920             :          * we need to hold onto this task/cmd because until the
    2921             :          * PDU has been written out
    2922             :          */
    2923           2 :         rsp_pdu->task = task;
    2924           2 :         task->scsi.ref++;
    2925             : 
    2926           2 :         rsph->opcode = ISCSI_OP_SCSI_DATAIN;
    2927             : 
    2928           2 :         if (F_bit) {
    2929           2 :                 rsph->flags |= ISCSI_FLAG_FINAL;
    2930             :         }
    2931             : 
    2932             :         /* we leave the A_bit clear */
    2933             : 
    2934           2 :         if (F_bit && S_bit)  {
    2935           1 :                 if (O_bit) {
    2936           0 :                         rsph->flags |= ISCSI_DATAIN_OVERFLOW;
    2937             :                 }
    2938             : 
    2939           1 :                 if (U_bit) {
    2940           1 :                         rsph->flags |= ISCSI_DATAIN_UNDERFLOW;
    2941             :                 }
    2942             :         }
    2943             : 
    2944           2 :         if (S_bit) {
    2945           1 :                 rsph->flags |= ISCSI_DATAIN_STATUS;
    2946           1 :                 rsph->status = task->scsi.status;
    2947             :         }
    2948             : 
    2949           2 :         DSET24(rsph->data_segment_len, len);
    2950             : 
    2951           2 :         to_be32(&rsph->itt, task_tag);
    2952           2 :         to_be32(&rsph->ttt, transfer_tag);
    2953             : 
    2954           2 :         if (S_bit) {
    2955           1 :                 to_be32(&rsph->stat_sn, conn->StatSN);
    2956           1 :                 conn->StatSN++;
    2957             :         }
    2958             : 
    2959           2 :         if (F_bit && S_bit && !iscsi_task_is_immediate(primary)) {
    2960           1 :                 conn->sess->MaxCmdSN++;
    2961             :         }
    2962             : 
    2963           2 :         to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
    2964           2 :         to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
    2965             : 
    2966           2 :         to_be32(&rsph->data_sn, DataSN);
    2967             : 
    2968           2 :         if (conn->sess->ErrorRecoveryLevel >= 1) {
    2969           0 :                 primary->datain_datasn = DataSN;
    2970             :         }
    2971           2 :         DataSN++;
    2972             : 
    2973           2 :         offset += task->scsi.offset;
    2974           2 :         to_be32(&rsph->buffer_offset, (uint32_t)offset);
    2975             : 
    2976           2 :         if (F_bit && S_bit) {
    2977           1 :                 to_be32(&rsph->res_cnt, residual_len);
    2978             :         }
    2979             : 
    2980           2 :         lun_dev = spdk_scsi_dev_get_lun(conn->dev, task->lun_id);
    2981           2 :         if (spdk_likely(lun_dev != NULL)) {
    2982           2 :                 if (spdk_unlikely(spdk_scsi_lun_get_dif_ctx(lun_dev, &task->scsi,
    2983             :                                   &rsp_pdu->dif_ctx))) {
    2984           0 :                         rsp_pdu->dif_insert_or_strip = true;
    2985             :                 }
    2986             :         }
    2987             : 
    2988           2 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_datain_pdu_complete, conn);
    2989             : 
    2990           2 :         return DataSN;
    2991             : }
    2992             : 
    2993             : static int
    2994           4 : iscsi_transfer_in(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
    2995             : {
    2996             :         uint32_t DataSN;
    2997             :         uint32_t transfer_len;
    2998             :         uint32_t data_len;
    2999             :         uint32_t segment_len;
    3000             :         uint32_t offset;
    3001           4 :         uint32_t residual_len = 0;
    3002             :         int sent_status;
    3003             :         uint32_t len;
    3004           4 :         int datain_flag = 0;
    3005             :         int datain_seq_cnt;
    3006             :         int i;
    3007             :         uint32_t sequence_end;
    3008             :         struct spdk_iscsi_task *primary;
    3009             : 
    3010           4 :         primary = iscsi_task_get_primary(task);
    3011           4 :         segment_len = conn->MaxRecvDataSegmentLength;
    3012           4 :         data_len = task->scsi.data_transferred;
    3013           4 :         transfer_len = task->scsi.length;
    3014             : 
    3015           4 :         if (task->scsi.status != SPDK_SCSI_STATUS_GOOD) {
    3016           1 :                 return 0;
    3017             :         }
    3018             : 
    3019           3 :         if (data_len < transfer_len) {
    3020             :                 /* underflow */
    3021           3 :                 SPDK_DEBUGLOG(iscsi, "Underflow %u/%u\n", data_len, transfer_len);
    3022           3 :                 residual_len = transfer_len - data_len;
    3023           3 :                 transfer_len = data_len;
    3024           3 :                 datain_flag |= ISCSI_DATAIN_UNDERFLOW;
    3025           0 :         } else if (data_len > transfer_len) {
    3026             :                 /* overflow */
    3027           0 :                 SPDK_DEBUGLOG(iscsi, "Overflow %u/%u\n", data_len, transfer_len);
    3028           0 :                 residual_len = data_len - transfer_len;
    3029           0 :                 datain_flag |= ISCSI_DATAIN_OVERFLOW;
    3030             :         } else {
    3031           0 :                 SPDK_DEBUGLOG(iscsi, "Transfer %u\n", transfer_len);
    3032           0 :                 residual_len = 0;
    3033             :         }
    3034             : 
    3035           3 :         DataSN = primary->datain_datasn;
    3036           3 :         sent_status = 0;
    3037             : 
    3038             :         /* calculate the number of sequences for all data-in pdus */
    3039           3 :         datain_seq_cnt = 1 + ((transfer_len - 1) / (int)conn->sess->MaxBurstLength);
    3040        4101 :         for (i = 0; i < datain_seq_cnt; i++) {
    3041        4098 :                 offset = i * conn->sess->MaxBurstLength;
    3042        4098 :                 sequence_end = spdk_min(((i + 1) * conn->sess->MaxBurstLength),
    3043             :                                         transfer_len);
    3044             : 
    3045             :                 /* send data split by segment_len */
    3046        4100 :                 for (; offset < sequence_end; offset += segment_len) {
    3047           2 :                         len = spdk_min(segment_len, (sequence_end - offset));
    3048             : 
    3049           2 :                         datain_flag &= ~(ISCSI_FLAG_FINAL | ISCSI_DATAIN_STATUS);
    3050             : 
    3051           2 :                         if (offset + len == sequence_end) {
    3052             :                                 /* last PDU in a sequence */
    3053           2 :                                 datain_flag |= ISCSI_FLAG_FINAL;
    3054           2 :                                 if (task->scsi.sense_data_len == 0) {
    3055             :                                         /* The last pdu in all data-in pdus */
    3056           1 :                                         if ((offset + len) == transfer_len &&
    3057           1 :                                             (primary->bytes_completed == primary->scsi.transfer_len)) {
    3058           1 :                                                 datain_flag |= ISCSI_DATAIN_STATUS;
    3059           1 :                                                 sent_status = 1;
    3060             :                                         }
    3061             :                                 }
    3062             :                         }
    3063             : 
    3064           2 :                         SPDK_DEBUGLOG(iscsi, "Transfer=%d, Offset=%d, Len=%d\n",
    3065             :                                       sequence_end, offset, len);
    3066           2 :                         SPDK_DEBUGLOG(iscsi, "StatSN=%u, DataSN=%u, Offset=%u, Len=%d\n",
    3067             :                                       conn->StatSN, DataSN, offset, len);
    3068             : 
    3069           2 :                         DataSN = iscsi_send_datain(conn, task, datain_flag, residual_len,
    3070             :                                                    offset, DataSN, len);
    3071             :                 }
    3072             :         }
    3073             : 
    3074           3 :         if (task != primary) {
    3075           0 :                 primary->scsi.data_transferred += task->scsi.data_transferred;
    3076             :         }
    3077           3 :         primary->datain_datasn = DataSN;
    3078             : 
    3079           3 :         return sent_status;
    3080             : }
    3081             : 
    3082             : void
    3083           9 : iscsi_task_response(struct spdk_iscsi_conn *conn,
    3084             :                     struct spdk_iscsi_task *task)
    3085             : {
    3086             :         struct spdk_iscsi_pdu *rsp_pdu;
    3087             :         struct iscsi_bhs_scsi_resp *rsph;
    3088             :         uint32_t task_tag;
    3089             :         uint32_t transfer_len;
    3090             :         size_t residual_len;
    3091             :         size_t data_len;
    3092             :         int O_bit, U_bit;
    3093             :         int rc;
    3094             :         struct spdk_iscsi_task *primary;
    3095             : 
    3096           9 :         primary = iscsi_task_get_primary(task);
    3097             : 
    3098           9 :         transfer_len = primary->scsi.transfer_len;
    3099           9 :         task_tag = task->tag;
    3100             : 
    3101             :         /* transfer data from logical unit */
    3102             :         /* (direction is view of initiator side) */
    3103           9 :         if (iscsi_task_is_read(primary)) {
    3104           4 :                 rc = iscsi_transfer_in(conn, task);
    3105           4 :                 if (rc > 0) {
    3106             :                         /* sent status by last DATAIN PDU */
    3107           1 :                         return;
    3108             :                 }
    3109             : 
    3110           3 :                 if (primary->bytes_completed != primary->scsi.transfer_len) {
    3111           0 :                         return;
    3112             :                 }
    3113             :         }
    3114             : 
    3115           8 :         O_bit = U_bit = 0;
    3116           8 :         residual_len = 0;
    3117           8 :         data_len = primary->scsi.data_transferred;
    3118             : 
    3119           8 :         if ((transfer_len != 0) &&
    3120           8 :             (task->scsi.status == SPDK_SCSI_STATUS_GOOD)) {
    3121           7 :                 if (data_len < transfer_len) {
    3122             :                         /* underflow */
    3123           7 :                         SPDK_DEBUGLOG(iscsi, "Underflow %zu/%u\n", data_len, transfer_len);
    3124           7 :                         residual_len = transfer_len - data_len;
    3125           7 :                         U_bit = 1;
    3126           0 :                 } else if (data_len > transfer_len) {
    3127             :                         /* overflow */
    3128           0 :                         SPDK_DEBUGLOG(iscsi, "Overflow %zu/%u\n", data_len, transfer_len);
    3129           0 :                         residual_len = data_len - transfer_len;
    3130           0 :                         O_bit = 1;
    3131             :                 } else {
    3132           0 :                         SPDK_DEBUGLOG(iscsi, "Transfer %u\n", transfer_len);
    3133             :                 }
    3134             :         }
    3135             : 
    3136             :         /* response PDU */
    3137           8 :         rsp_pdu = iscsi_get_pdu(conn);
    3138           8 :         assert(rsp_pdu != NULL);
    3139           8 :         rsph = (struct iscsi_bhs_scsi_resp *)&rsp_pdu->bhs;
    3140           8 :         assert(task->scsi.sense_data_len <= sizeof(rsp_pdu->sense.data));
    3141           8 :         memcpy(rsp_pdu->sense.data, task->scsi.sense_data, task->scsi.sense_data_len);
    3142           8 :         to_be16(&rsp_pdu->sense.length, task->scsi.sense_data_len);
    3143           8 :         rsp_pdu->data = (uint8_t *)&rsp_pdu->sense;
    3144           8 :         rsp_pdu->data_from_mempool = true;
    3145             : 
    3146             :         /*
    3147             :          * we need to hold onto this task/cmd because until the
    3148             :          * PDU has been written out
    3149             :          */
    3150           8 :         rsp_pdu->task = task;
    3151           8 :         task->scsi.ref++;
    3152             : 
    3153           8 :         rsph->opcode = ISCSI_OP_SCSI_RSP;
    3154           8 :         rsph->flags |= 0x80; /* bit 0 is default to 1 */
    3155             : 
    3156           8 :         if (O_bit) {
    3157           0 :                 rsph->flags |= ISCSI_SCSI_OVERFLOW;
    3158             :         }
    3159             : 
    3160           8 :         if (U_bit) {
    3161           7 :                 rsph->flags |= ISCSI_SCSI_UNDERFLOW;
    3162             :         }
    3163             : 
    3164           8 :         rsph->status = task->scsi.status;
    3165           8 :         if (task->scsi.sense_data_len) {
    3166             :                 /* SenseLength (2 bytes) + SenseData  */
    3167           2 :                 DSET24(rsph->data_segment_len, 2 + task->scsi.sense_data_len);
    3168             :         }
    3169           8 :         to_be32(&rsph->itt, task_tag);
    3170             : 
    3171           8 :         to_be32(&rsph->stat_sn, conn->StatSN);
    3172           8 :         conn->StatSN++;
    3173             : 
    3174           8 :         if (!iscsi_task_is_immediate(primary)) {
    3175           8 :                 conn->sess->MaxCmdSN++;
    3176             :         }
    3177             : 
    3178           8 :         to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
    3179           8 :         to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
    3180             : 
    3181           8 :         to_be32(&rsph->bi_read_res_cnt, 0);
    3182           8 :         to_be32(&rsph->res_cnt, residual_len);
    3183             : 
    3184           8 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
    3185             : }
    3186             : 
    3187             : /*
    3188             :  *  This function compare the input pdu's bhs with the pdu's bhs associated by
    3189             :  *  active_r2t_tasks and queued_r2t_tasks in a connection
    3190             :  */
    3191             : static bool
    3192           0 : iscsi_compare_pdu_bhs_within_existed_r2t_tasks(struct spdk_iscsi_conn *conn,
    3193             :                 struct spdk_iscsi_pdu *pdu)
    3194             : {
    3195             :         struct spdk_iscsi_task  *task;
    3196             : 
    3197           0 :         TAILQ_FOREACH(task, &conn->active_r2t_tasks, link) {
    3198           0 :                 if (!memcmp(&pdu->bhs, iscsi_task_get_bhs(task), ISCSI_BHS_LEN)) {
    3199           0 :                         return true;
    3200             :                 }
    3201             :         }
    3202             : 
    3203           0 :         TAILQ_FOREACH(task, &conn->queued_r2t_tasks, link) {
    3204           0 :                 if (!memcmp(&pdu->bhs, iscsi_task_get_bhs(task), ISCSI_BHS_LEN)) {
    3205           0 :                         return true;
    3206             :                 }
    3207             :         }
    3208             : 
    3209           0 :         return false;
    3210             : }
    3211             : 
    3212             : void
    3213           4 : iscsi_queue_task(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
    3214             : {
    3215           4 :         spdk_trace_record(TRACE_ISCSI_TASK_QUEUE, conn->trace_id, task->scsi.length,
    3216             :                           (uintptr_t)task, (uintptr_t)task->pdu);
    3217           4 :         task->is_queued = true;
    3218           4 :         spdk_scsi_dev_queue_task(conn->dev, &task->scsi);
    3219           4 : }
    3220             : 
    3221             : static int
    3222           0 : iscsi_pdu_payload_op_scsi_read(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
    3223             : {
    3224           0 :         if (task->scsi.transfer_len <= SPDK_BDEV_LARGE_BUF_MAX_SIZE) {
    3225           0 :                 task->parent = NULL;
    3226           0 :                 task->scsi.offset = 0;
    3227           0 :                 task->scsi.length = task->scsi.transfer_len;
    3228           0 :                 spdk_scsi_task_set_data(&task->scsi, NULL, 0);
    3229             : 
    3230           0 :                 iscsi_queue_task(conn, task);
    3231           0 :                 return 0;
    3232             :         } else {
    3233           0 :                 TAILQ_INIT(&task->subtask_list);
    3234           0 :                 task->current_data_offset = 0;
    3235           0 :                 TAILQ_INSERT_TAIL(&conn->queued_datain_tasks, task, link);
    3236             : 
    3237           0 :                 return iscsi_conn_handle_queued_datain_tasks(conn);
    3238             :         }
    3239             : }
    3240             : 
    3241             : static int
    3242           4 : iscsi_submit_write_subtask(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task,
    3243             :                            struct spdk_iscsi_pdu *pdu, struct spdk_mobj *mobj)
    3244             : {
    3245             :         struct spdk_iscsi_task *subtask;
    3246             : 
    3247           4 :         subtask = iscsi_task_get(conn, task, iscsi_task_cpl);
    3248           4 :         if (subtask == NULL) {
    3249           0 :                 SPDK_ERRLOG("Unable to acquire subtask\n");
    3250           0 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    3251             :         }
    3252           4 :         subtask->scsi.offset = task->current_data_offset;
    3253           4 :         subtask->scsi.length = mobj->data_len;
    3254           4 :         iscsi_task_associate_pdu(subtask, pdu);
    3255             : 
    3256           4 :         task->current_data_offset += mobj->data_len;
    3257             : 
    3258           4 :         if (spdk_likely(!pdu->dif_insert_or_strip)) {
    3259           4 :                 spdk_scsi_task_set_data(&subtask->scsi, mobj->buf, mobj->data_len);
    3260             :         } else {
    3261           0 :                 spdk_scsi_task_set_data(&subtask->scsi, mobj->buf, pdu->data_buf_len);
    3262             :         }
    3263             : 
    3264           4 :         iscsi_queue_task(conn, subtask);
    3265           4 :         return 0;
    3266             : }
    3267             : 
    3268             : static int
    3269           2 : iscsi_pdu_payload_op_scsi_write(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
    3270             : {
    3271             :         struct spdk_iscsi_pdu *pdu;
    3272             :         struct iscsi_bhs_scsi_req *reqh;
    3273             :         uint32_t transfer_len;
    3274             :         struct spdk_mobj *mobj;
    3275             :         int rc;
    3276             : 
    3277           2 :         pdu = iscsi_task_get_pdu(task);
    3278           2 :         reqh = (struct iscsi_bhs_scsi_req *)&pdu->bhs;
    3279             : 
    3280           2 :         transfer_len = task->scsi.transfer_len;
    3281             : 
    3282           2 :         if (reqh->final_bit &&
    3283           2 :             pdu->data_segment_len < transfer_len) {
    3284             :                 /* needs R2T */
    3285           2 :                 rc = add_transfer_task(conn, task);
    3286           2 :                 if (rc < 0) {
    3287           0 :                         SPDK_ERRLOG("add_transfer_task() failed\n");
    3288           0 :                         iscsi_task_put(task);
    3289           0 :                         return SPDK_ISCSI_CONNECTION_FATAL;
    3290             :                 }
    3291             : 
    3292             :                 /* immediate writes */
    3293           2 :                 if (pdu->data_segment_len != 0) {
    3294           1 :                         mobj = pdu->mobj[0];
    3295           1 :                         assert(mobj != NULL);
    3296             : 
    3297           1 :                         if (!pdu->dif_insert_or_strip &&
    3298           1 :                             mobj->data_len < SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
    3299             :                                 /* continue aggregation until the first data buffer is full. */
    3300           1 :                                 iscsi_task_set_mobj(task, mobj);
    3301           1 :                                 pdu->mobj[0] = NULL;
    3302             :                         } else {
    3303             :                                 /* we are doing the first partial write task */
    3304           0 :                                 rc = iscsi_submit_write_subtask(conn, task, pdu, mobj);
    3305           0 :                                 if (rc < 0) {
    3306           0 :                                         iscsi_task_put(task);
    3307           0 :                                         return SPDK_ISCSI_CONNECTION_FATAL;
    3308             :                                 }
    3309             :                         }
    3310             :                 }
    3311           2 :                 return 0;
    3312             :         }
    3313             : 
    3314           0 :         if (pdu->data_segment_len == transfer_len) {
    3315             :                 /* we are doing small writes with no R2T */
    3316           0 :                 if (spdk_likely(!pdu->dif_insert_or_strip)) {
    3317           0 :                         spdk_scsi_task_set_data(&task->scsi, pdu->data, pdu->data_segment_len);
    3318             :                 } else {
    3319           0 :                         spdk_scsi_task_set_data(&task->scsi, pdu->data, pdu->data_buf_len);
    3320             :                 }
    3321           0 :                 task->scsi.length = transfer_len;
    3322             :         }
    3323             : 
    3324           0 :         iscsi_queue_task(conn, task);
    3325           0 :         return 0;
    3326             : }
    3327             : 
    3328             : static int
    3329          14 : iscsi_pdu_hdr_op_scsi(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    3330             : {
    3331             :         struct spdk_iscsi_task  *task;
    3332             :         struct spdk_scsi_dev    *dev;
    3333             :         uint8_t *cdb;
    3334             :         uint64_t lun;
    3335             :         uint32_t task_tag;
    3336             :         uint32_t transfer_len;
    3337             :         int R_bit, W_bit;
    3338             :         int lun_i;
    3339             :         struct iscsi_bhs_scsi_req *reqh;
    3340             : 
    3341          14 :         if (conn->sess->session_type != SESSION_TYPE_NORMAL) {
    3342           2 :                 SPDK_ERRLOG("ISCSI_OP_SCSI not allowed in discovery and invalid session\n");
    3343           2 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    3344             :         }
    3345             : 
    3346          12 :         reqh = (struct iscsi_bhs_scsi_req *)&pdu->bhs;
    3347             : 
    3348          12 :         R_bit = reqh->read_bit;
    3349          12 :         W_bit = reqh->write_bit;
    3350          12 :         lun = from_be64(&reqh->lun);
    3351          12 :         task_tag = from_be32(&reqh->itt);
    3352          12 :         transfer_len = from_be32(&reqh->expected_data_xfer_len);
    3353          12 :         cdb = reqh->cdb;
    3354             : 
    3355          12 :         SPDK_LOGDUMP(iscsi, "CDB", cdb, 16);
    3356             : 
    3357          12 :         task = iscsi_task_get(conn, NULL, iscsi_task_cpl);
    3358          12 :         if (!task) {
    3359           0 :                 SPDK_ERRLOG("Unable to acquire task\n");
    3360           0 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    3361             :         }
    3362             : 
    3363          12 :         iscsi_task_associate_pdu(task, pdu);
    3364          12 :         lun_i = spdk_scsi_lun_id_fmt_to_int(lun);
    3365          12 :         task->lun_id = lun_i;
    3366          12 :         dev = conn->dev;
    3367          12 :         task->scsi.lun = spdk_scsi_dev_get_lun(dev, lun_i);
    3368             : 
    3369          12 :         if ((R_bit != 0) && (W_bit != 0)) {
    3370           1 :                 SPDK_ERRLOG("Bidirectional CDB is not supported\n");
    3371           1 :                 iscsi_task_put(task);
    3372           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    3373             :         }
    3374             : 
    3375          11 :         task->scsi.cdb = cdb;
    3376          11 :         task->tag = task_tag;
    3377          11 :         task->scsi.transfer_len = transfer_len;
    3378          11 :         task->scsi.target_port = conn->target_port;
    3379          11 :         task->scsi.initiator_port = conn->initiator_port;
    3380          11 :         task->parent = NULL;
    3381          11 :         task->scsi.status = SPDK_SCSI_STATUS_GOOD;
    3382             : 
    3383          11 :         if (task->scsi.lun == NULL) {
    3384           1 :                 spdk_scsi_task_process_null_lun(&task->scsi);
    3385           1 :                 iscsi_task_cpl(&task->scsi);
    3386           1 :                 return 0;
    3387             :         }
    3388             : 
    3389             :         /* no bi-directional support */
    3390          10 :         if (R_bit) {
    3391           1 :                 task->scsi.dxfer_dir = SPDK_SCSI_DIR_FROM_DEV;
    3392           9 :         } else if (W_bit) {
    3393           7 :                 task->scsi.dxfer_dir = SPDK_SCSI_DIR_TO_DEV;
    3394             : 
    3395           7 :                 if ((conn->sess->ErrorRecoveryLevel >= 1) &&
    3396           0 :                     (iscsi_compare_pdu_bhs_within_existed_r2t_tasks(conn, pdu))) {
    3397           0 :                         iscsi_task_response(conn, task);
    3398           0 :                         iscsi_task_put(task);
    3399           0 :                         return 0;
    3400             :                 }
    3401             : 
    3402           7 :                 if (pdu->data_segment_len > iscsi_get_max_immediate_data_size()) {
    3403           1 :                         SPDK_ERRLOG("data segment len(=%zu) > immediate data len(=%"PRIu32")\n",
    3404             :                                     pdu->data_segment_len, iscsi_get_max_immediate_data_size());
    3405           1 :                         iscsi_task_put(task);
    3406           1 :                         return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    3407             :                 }
    3408             : 
    3409           6 :                 if (pdu->data_segment_len > transfer_len) {
    3410           1 :                         SPDK_ERRLOG("data segment len(=%zu) > task transfer len(=%d)\n",
    3411             :                                     pdu->data_segment_len, transfer_len);
    3412           1 :                         iscsi_task_put(task);
    3413           1 :                         return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    3414             :                 }
    3415             : 
    3416             :                 /* check the ImmediateData and also pdu->data_segment_len */
    3417           5 :                 if ((!conn->sess->ImmediateData && (pdu->data_segment_len > 0)) ||
    3418           4 :                     (pdu->data_segment_len > conn->sess->FirstBurstLength)) {
    3419           2 :                         iscsi_task_put(task);
    3420           2 :                         return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    3421             :                 }
    3422             : 
    3423           3 :                 if (spdk_unlikely(spdk_scsi_lun_get_dif_ctx(task->scsi.lun, &task->scsi, &pdu->dif_ctx))) {
    3424           0 :                         pdu->dif_insert_or_strip = true;
    3425           3 :                 } else if (reqh->final_bit && pdu->data_segment_len < transfer_len) {
    3426           2 :                         pdu->data_buf_len = spdk_min(transfer_len,
    3427             :                                                      SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
    3428             :                 }
    3429             :         } else {
    3430             :                 /* neither R nor W bit set */
    3431           2 :                 task->scsi.dxfer_dir = SPDK_SCSI_DIR_NONE;
    3432           2 :                 if (transfer_len > 0) {
    3433           1 :                         iscsi_task_put(task);
    3434           1 :                         SPDK_ERRLOG("Reject scsi cmd with EDTL > 0 but (R | W) == 0\n");
    3435           1 :                         return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
    3436             :                 }
    3437             :         }
    3438             : 
    3439           5 :         pdu->task = task;
    3440           5 :         return 0;
    3441             : }
    3442             : 
    3443             : static int
    3444           2 : iscsi_pdu_payload_op_scsi(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    3445             : {
    3446             :         struct spdk_iscsi_task *task;
    3447             : 
    3448           2 :         if (pdu->task == NULL) {
    3449           0 :                 return 0;
    3450             :         }
    3451             : 
    3452           2 :         task = pdu->task;
    3453             : 
    3454           2 :         if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) {
    3455           0 :                 spdk_scsi_task_process_null_lun(&task->scsi);
    3456           0 :                 iscsi_task_cpl(&task->scsi);
    3457           0 :                 return 0;
    3458             :         }
    3459             : 
    3460           2 :         switch (task->scsi.dxfer_dir) {
    3461           0 :         case SPDK_SCSI_DIR_FROM_DEV:
    3462           0 :                 return iscsi_pdu_payload_op_scsi_read(conn, task);
    3463           2 :         case SPDK_SCSI_DIR_TO_DEV:
    3464           2 :                 return iscsi_pdu_payload_op_scsi_write(conn, task);
    3465           0 :         case SPDK_SCSI_DIR_NONE:
    3466           0 :                 iscsi_queue_task(conn, task);
    3467           0 :                 return 0;
    3468           0 :         default:
    3469           0 :                 assert(false);
    3470             :                 iscsi_task_put(task);
    3471             :                 break;
    3472             :         }
    3473             : 
    3474             :         return SPDK_ISCSI_CONNECTION_FATAL;
    3475             : }
    3476             : 
    3477             : void
    3478           7 : iscsi_task_mgmt_response(struct spdk_iscsi_conn *conn,
    3479             :                          struct spdk_iscsi_task *task)
    3480             : {
    3481             :         struct spdk_iscsi_pdu *rsp_pdu;
    3482             :         struct iscsi_bhs_task_req *reqh;
    3483             :         struct iscsi_bhs_task_resp *rsph;
    3484             : 
    3485           7 :         if (task->pdu == NULL) {
    3486             :                 /*
    3487             :                  * This was an internally generated task management command,
    3488             :                  *  usually from LUN cleanup when a connection closes.
    3489             :                  */
    3490           0 :                 return;
    3491             :         }
    3492             : 
    3493           7 :         reqh = (struct iscsi_bhs_task_req *)&task->pdu->bhs;
    3494             :         /* response PDU */
    3495           7 :         rsp_pdu = iscsi_get_pdu(conn);
    3496           7 :         rsph = (struct iscsi_bhs_task_resp *)&rsp_pdu->bhs;
    3497           7 :         rsph->opcode = ISCSI_OP_TASK_RSP;
    3498           7 :         rsph->flags |= 0x80; /* bit 0 default to 1 */
    3499           7 :         switch (task->scsi.response) {
    3500           0 :         case SPDK_SCSI_TASK_MGMT_RESP_COMPLETE:
    3501           0 :                 rsph->response = ISCSI_TASK_FUNC_RESP_COMPLETE;
    3502           0 :                 break;
    3503           0 :         case SPDK_SCSI_TASK_MGMT_RESP_SUCCESS:
    3504           0 :                 rsph->response = ISCSI_TASK_FUNC_RESP_COMPLETE;
    3505           0 :                 break;
    3506           1 :         case SPDK_SCSI_TASK_MGMT_RESP_REJECT:
    3507           1 :                 rsph->response = ISCSI_TASK_FUNC_REJECTED;
    3508           1 :                 break;
    3509           1 :         case SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN:
    3510           1 :                 rsph->response = ISCSI_TASK_FUNC_RESP_LUN_NOT_EXIST;
    3511           1 :                 break;
    3512           0 :         case SPDK_SCSI_TASK_MGMT_RESP_TARGET_FAILURE:
    3513           0 :                 rsph->response = ISCSI_TASK_FUNC_REJECTED;
    3514           0 :                 break;
    3515           5 :         case SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED:
    3516           5 :                 rsph->response = ISCSI_TASK_FUNC_RESP_FUNC_NOT_SUPPORTED;
    3517           5 :                 break;
    3518             :         }
    3519           7 :         rsph->itt = reqh->itt;
    3520             : 
    3521           7 :         to_be32(&rsph->stat_sn, conn->StatSN);
    3522           7 :         conn->StatSN++;
    3523             : 
    3524           7 :         if (reqh->immediate == 0) {
    3525           7 :                 conn->sess->MaxCmdSN++;
    3526             :         }
    3527             : 
    3528           7 :         to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
    3529           7 :         to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
    3530             : 
    3531           7 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
    3532             : }
    3533             : 
    3534             : static void
    3535           0 : iscsi_queue_mgmt_task(struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)
    3536             : {
    3537             :         struct spdk_scsi_lun *lun;
    3538             : 
    3539           0 :         lun = spdk_scsi_dev_get_lun(conn->dev, task->lun_id);
    3540           0 :         if (lun == NULL) {
    3541           0 :                 task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
    3542           0 :                 iscsi_task_mgmt_response(conn, task);
    3543           0 :                 iscsi_task_put(task);
    3544           0 :                 return;
    3545             :         }
    3546             : 
    3547           0 :         spdk_scsi_dev_queue_mgmt_task(conn->dev, &task->scsi);
    3548             : }
    3549             : 
    3550             : static int
    3551           0 : _iscsi_op_abort_task(void *arg)
    3552             : {
    3553           0 :         struct spdk_iscsi_task *task = arg;
    3554             :         int rc;
    3555             : 
    3556           0 :         rc = iscsi_conn_abort_queued_datain_task(task->conn, task->scsi.abort_id);
    3557           0 :         if (rc != 0) {
    3558           0 :                 return SPDK_POLLER_BUSY;
    3559             :         }
    3560             : 
    3561           0 :         spdk_poller_unregister(&task->mgmt_poller);
    3562           0 :         iscsi_queue_mgmt_task(task->conn, task);
    3563           0 :         return SPDK_POLLER_BUSY;
    3564             : }
    3565             : 
    3566             : static void
    3567           0 : iscsi_op_abort_task(struct spdk_iscsi_task *task, uint32_t ref_task_tag)
    3568             : {
    3569           0 :         task->scsi.abort_id = ref_task_tag;
    3570           0 :         task->scsi.function = SPDK_SCSI_TASK_FUNC_ABORT_TASK;
    3571           0 :         task->mgmt_poller = SPDK_POLLER_REGISTER(_iscsi_op_abort_task, task, 10);
    3572           0 : }
    3573             : 
    3574             : static int
    3575           0 : _iscsi_op_abort_task_set(void *arg)
    3576             : {
    3577           0 :         struct spdk_iscsi_task *task = arg;
    3578             :         int rc;
    3579             : 
    3580           0 :         rc = iscsi_conn_abort_queued_datain_tasks(task->conn, task->scsi.lun,
    3581             :                         task->pdu);
    3582           0 :         if (rc != 0) {
    3583           0 :                 return SPDK_POLLER_BUSY;
    3584             :         }
    3585             : 
    3586           0 :         spdk_poller_unregister(&task->mgmt_poller);
    3587           0 :         iscsi_queue_mgmt_task(task->conn, task);
    3588           0 :         return SPDK_POLLER_BUSY;
    3589             : }
    3590             : 
    3591             : void
    3592           0 : iscsi_op_abort_task_set(struct spdk_iscsi_task *task, uint8_t function)
    3593             : {
    3594           0 :         task->scsi.function = function;
    3595           0 :         task->mgmt_poller = SPDK_POLLER_REGISTER(_iscsi_op_abort_task_set, task, 10);
    3596           0 : }
    3597             : 
    3598             : static int
    3599           8 : iscsi_pdu_hdr_op_task(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    3600             : {
    3601             :         struct iscsi_bhs_task_req *reqh;
    3602             :         uint64_t lun;
    3603             :         uint32_t task_tag;
    3604             :         uint32_t ref_task_tag;
    3605             :         uint8_t function;
    3606             :         int lun_i;
    3607             :         struct spdk_iscsi_task *task;
    3608             :         struct spdk_scsi_dev *dev;
    3609             : 
    3610           8 :         if (conn->sess->session_type != SESSION_TYPE_NORMAL) {
    3611           1 :                 SPDK_ERRLOG("ISCSI_OP_TASK not allowed in discovery and invalid session\n");
    3612           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    3613             :         }
    3614             : 
    3615           7 :         reqh = (struct iscsi_bhs_task_req *)&pdu->bhs;
    3616           7 :         function = reqh->flags & ISCSI_TASK_FUNCTION_MASK;
    3617           7 :         lun = from_be64(&reqh->lun);
    3618           7 :         task_tag = from_be32(&reqh->itt);
    3619           7 :         ref_task_tag = from_be32(&reqh->ref_task_tag);
    3620             : 
    3621           7 :         SPDK_DEBUGLOG(iscsi, "I=%d, func=%d, ITT=%x, ref TT=%x, LUN=0x%16.16"PRIx64"\n",
    3622             :                       reqh->immediate, function, task_tag, ref_task_tag, lun);
    3623             : 
    3624           7 :         SPDK_DEBUGLOG(iscsi, "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
    3625             :                       conn->StatSN, conn->sess->ExpCmdSN, conn->sess->MaxCmdSN);
    3626             : 
    3627           7 :         lun_i = spdk_scsi_lun_id_fmt_to_int(lun);
    3628           7 :         dev = conn->dev;
    3629             : 
    3630           7 :         task = iscsi_task_get(conn, NULL, iscsi_task_mgmt_cpl);
    3631           7 :         if (!task) {
    3632           0 :                 SPDK_ERRLOG("Unable to acquire task\n");
    3633           0 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    3634             :         }
    3635             : 
    3636           7 :         iscsi_task_associate_pdu(task, pdu);
    3637           7 :         task->scsi.target_port = conn->target_port;
    3638           7 :         task->scsi.initiator_port = conn->initiator_port;
    3639           7 :         task->tag = task_tag;
    3640           7 :         task->scsi.lun = spdk_scsi_dev_get_lun(dev, lun_i);
    3641           7 :         task->lun_id = lun_i;
    3642             : 
    3643           7 :         if (task->scsi.lun == NULL) {
    3644           1 :                 task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_INVALID_LUN;
    3645           1 :                 iscsi_task_mgmt_response(conn, task);
    3646           1 :                 iscsi_task_put(task);
    3647           1 :                 return 0;
    3648             :         }
    3649             : 
    3650           6 :         switch (function) {
    3651             :         /* abort task identified by Referenced Task Tag field */
    3652           0 :         case ISCSI_TASK_FUNC_ABORT_TASK:
    3653           0 :                 SPDK_NOTICELOG("ABORT_TASK\n");
    3654             : 
    3655           0 :                 iscsi_del_transfer_task(conn, ref_task_tag);
    3656           0 :                 iscsi_op_abort_task(task, ref_task_tag);
    3657           0 :                 return 0;
    3658             : 
    3659             :         /* abort all tasks issued via this session on the LUN */
    3660           0 :         case ISCSI_TASK_FUNC_ABORT_TASK_SET:
    3661           0 :                 SPDK_NOTICELOG("ABORT_TASK_SET\n");
    3662             : 
    3663           0 :                 iscsi_clear_all_transfer_task(conn, task->scsi.lun, pdu);
    3664           0 :                 iscsi_op_abort_task_set(task, SPDK_SCSI_TASK_FUNC_ABORT_TASK_SET);
    3665           0 :                 return 0;
    3666             : 
    3667           1 :         case ISCSI_TASK_FUNC_CLEAR_TASK_SET:
    3668           1 :                 task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
    3669           1 :                 SPDK_NOTICELOG("CLEAR_TASK_SET (Unsupported)\n");
    3670           1 :                 break;
    3671             : 
    3672           1 :         case ISCSI_TASK_FUNC_CLEAR_ACA:
    3673           1 :                 task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
    3674           1 :                 SPDK_NOTICELOG("CLEAR_ACA (Unsupported)\n");
    3675           1 :                 break;
    3676             : 
    3677           0 :         case ISCSI_TASK_FUNC_LOGICAL_UNIT_RESET:
    3678           0 :                 SPDK_NOTICELOG("LOGICAL_UNIT_RESET\n");
    3679             : 
    3680           0 :                 iscsi_clear_all_transfer_task(conn, task->scsi.lun, pdu);
    3681           0 :                 iscsi_op_abort_task_set(task, SPDK_SCSI_TASK_FUNC_LUN_RESET);
    3682           0 :                 return 0;
    3683             : 
    3684           1 :         case ISCSI_TASK_FUNC_TARGET_WARM_RESET:
    3685           1 :                 SPDK_NOTICELOG("TARGET_WARM_RESET (Unsupported)\n");
    3686           1 :                 task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
    3687           1 :                 break;
    3688             : 
    3689           1 :         case ISCSI_TASK_FUNC_TARGET_COLD_RESET:
    3690           1 :                 SPDK_NOTICELOG("TARGET_COLD_RESET (Unsupported)\n");
    3691           1 :                 task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
    3692           1 :                 break;
    3693             : 
    3694           1 :         case ISCSI_TASK_FUNC_TASK_REASSIGN:
    3695           1 :                 SPDK_NOTICELOG("TASK_REASSIGN (Unsupported)\n");
    3696           1 :                 task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT_FUNC_NOT_SUPPORTED;
    3697           1 :                 break;
    3698             : 
    3699           1 :         default:
    3700           1 :                 SPDK_ERRLOG("unsupported function %d\n", function);
    3701           1 :                 task->scsi.response = SPDK_SCSI_TASK_MGMT_RESP_REJECT;
    3702           1 :                 break;
    3703             :         }
    3704             : 
    3705           6 :         iscsi_task_mgmt_response(conn, task);
    3706           6 :         iscsi_task_put(task);
    3707           6 :         return 0;
    3708             : }
    3709             : 
    3710             : static int
    3711           4 : iscsi_pdu_hdr_op_nopout(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    3712             : {
    3713             :         struct iscsi_bhs_nop_out *reqh;
    3714             :         uint32_t task_tag;
    3715             :         uint32_t transfer_tag;
    3716             :         int I_bit;
    3717             : 
    3718           4 :         if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
    3719           1 :                 SPDK_ERRLOG("ISCSI_OP_NOPOUT not allowed in discovery session\n");
    3720           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    3721             :         }
    3722             : 
    3723           3 :         reqh = (struct iscsi_bhs_nop_out *)&pdu->bhs;
    3724           3 :         I_bit = reqh->immediate;
    3725             : 
    3726           3 :         if (pdu->data_segment_len > SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
    3727           1 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    3728             :         }
    3729             : 
    3730           2 :         task_tag = from_be32(&reqh->itt);
    3731           2 :         transfer_tag = from_be32(&reqh->ttt);
    3732             : 
    3733           2 :         SPDK_DEBUGLOG(iscsi, "I=%d, ITT=%x, TTT=%x\n",
    3734             :                       I_bit, task_tag, transfer_tag);
    3735             : 
    3736           2 :         SPDK_DEBUGLOG(iscsi, "CmdSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
    3737             :                       pdu->cmd_sn, conn->StatSN, conn->sess->ExpCmdSN,
    3738             :                       conn->sess->MaxCmdSN);
    3739             : 
    3740           2 :         if (transfer_tag != 0xFFFFFFFF && transfer_tag != (uint32_t)conn->id) {
    3741           2 :                 SPDK_ERRLOG("invalid transfer tag 0x%x\n", transfer_tag);
    3742             :                 /*
    3743             :                  * Technically we should probably fail the connection here, but for now
    3744             :                  *  just print the error message and continue.
    3745             :                  */
    3746             :         }
    3747             : 
    3748           2 :         if (task_tag == 0xffffffffU && I_bit == 0) {
    3749           1 :                 SPDK_ERRLOG("got NOPOUT ITT=0xffffffff, I=0\n");
    3750           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    3751             :         }
    3752             : 
    3753           1 :         return 0;
    3754             : }
    3755             : 
    3756             : static int
    3757           0 : iscsi_pdu_payload_op_nopout(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    3758             : {
    3759             :         struct spdk_iscsi_pdu *rsp_pdu;
    3760             :         struct iscsi_bhs_nop_out *reqh;
    3761             :         struct iscsi_bhs_nop_in *rsph;
    3762             :         uint8_t *data;
    3763             :         uint64_t lun;
    3764             :         uint32_t task_tag;
    3765             :         int I_bit;
    3766             :         int data_len;
    3767             : 
    3768           0 :         reqh = (struct iscsi_bhs_nop_out *)&pdu->bhs;
    3769           0 :         I_bit = reqh->immediate;
    3770             : 
    3771           0 :         data_len = pdu->data_segment_len;
    3772           0 :         if (data_len > conn->MaxRecvDataSegmentLength) {
    3773           0 :                 data_len = conn->MaxRecvDataSegmentLength;
    3774             :         }
    3775             : 
    3776           0 :         lun = from_be64(&reqh->lun);
    3777           0 :         task_tag = from_be32(&reqh->itt);
    3778             : 
    3779             :         /*
    3780             :          * We don't actually check to see if this is a response to the NOP-In
    3781             :          * that we sent.  Our goal is to just verify that the initiator is
    3782             :          * alive and responding to commands, not to verify that it tags
    3783             :          * NOP-Outs correctly
    3784             :          */
    3785           0 :         conn->nop_outstanding = false;
    3786             : 
    3787           0 :         if (task_tag == 0xffffffffU) {
    3788           0 :                 assert(I_bit == 1);
    3789           0 :                 SPDK_DEBUGLOG(iscsi, "got NOPOUT ITT=0xffffffff\n");
    3790           0 :                 return 0;
    3791             :         }
    3792             : 
    3793           0 :         data = calloc(1, data_len);
    3794           0 :         if (!data) {
    3795           0 :                 SPDK_ERRLOG("calloc() failed for ping data\n");
    3796           0 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    3797             :         }
    3798             : 
    3799             :         /* response of NOPOUT */
    3800           0 :         if (data_len > 0) {
    3801             :                 /* copy ping data */
    3802           0 :                 memcpy(data, pdu->data, data_len);
    3803             :         }
    3804             : 
    3805             :         /* response PDU */
    3806           0 :         rsp_pdu = iscsi_get_pdu(conn);
    3807           0 :         assert(rsp_pdu != NULL);
    3808             : 
    3809           0 :         rsph = (struct iscsi_bhs_nop_in *)&rsp_pdu->bhs;
    3810           0 :         rsp_pdu->data = data;
    3811           0 :         rsph->opcode = ISCSI_OP_NOPIN;
    3812           0 :         rsph->flags |= 0x80; /* bit 0 default to 1 */
    3813           0 :         DSET24(rsph->data_segment_len, data_len);
    3814           0 :         to_be64(&rsph->lun, lun);
    3815           0 :         to_be32(&rsph->itt, task_tag);
    3816           0 :         to_be32(&rsph->ttt, 0xffffffffU);
    3817             : 
    3818           0 :         to_be32(&rsph->stat_sn, conn->StatSN);
    3819           0 :         conn->StatSN++;
    3820             : 
    3821           0 :         if (I_bit == 0) {
    3822           0 :                 conn->sess->MaxCmdSN++;
    3823             :         }
    3824             : 
    3825           0 :         to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
    3826           0 :         to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
    3827             : 
    3828           0 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
    3829           0 :         conn->last_nopin = spdk_get_ticks();
    3830             : 
    3831           0 :         return 0;
    3832             : }
    3833             : 
    3834             : /* This function returns the spdk_scsi_task by searching the snack list via
    3835             :  * task transfertag and the pdu's opcode
    3836             :  */
    3837             : static struct spdk_iscsi_task *
    3838           0 : get_scsi_task_from_ttt(struct spdk_iscsi_conn *conn, uint32_t transfer_tag)
    3839             : {
    3840             :         struct spdk_iscsi_pdu *pdu;
    3841             :         struct iscsi_bhs_data_in *datain_bhs;
    3842             : 
    3843           0 :         TAILQ_FOREACH(pdu, &conn->snack_pdu_list, tailq) {
    3844           0 :                 if (pdu->bhs.opcode == ISCSI_OP_SCSI_DATAIN) {
    3845           0 :                         datain_bhs = (struct iscsi_bhs_data_in *)&pdu->bhs;
    3846           0 :                         if (from_be32(&datain_bhs->ttt) == transfer_tag) {
    3847           0 :                                 return pdu->task;
    3848             :                         }
    3849             :                 }
    3850             :         }
    3851             : 
    3852           0 :         return NULL;
    3853             : }
    3854             : 
    3855             : /* This function returns the spdk_scsi_task by searching the snack list via
    3856             :  * initiator task tag and the pdu's opcode
    3857             :  */
    3858             : static struct spdk_iscsi_task *
    3859           0 : get_scsi_task_from_itt(struct spdk_iscsi_conn *conn,
    3860             :                        uint32_t task_tag, enum iscsi_op opcode)
    3861             : {
    3862             :         struct spdk_iscsi_pdu *pdu;
    3863             : 
    3864           0 :         TAILQ_FOREACH(pdu, &conn->snack_pdu_list, tailq) {
    3865           0 :                 if (pdu->bhs.opcode == opcode &&
    3866           0 :                     pdu->task != NULL &&
    3867           0 :                     pdu->task->tag == task_tag) {
    3868           0 :                         return pdu->task;
    3869             :                 }
    3870             :         }
    3871             : 
    3872           0 :         return NULL;
    3873             : }
    3874             : 
    3875             : /* This function is used to handle the r2t snack */
    3876             : static int
    3877           0 : iscsi_handle_r2t_snack(struct spdk_iscsi_conn *conn,
    3878             :                        struct spdk_iscsi_task *task,
    3879             :                        struct spdk_iscsi_pdu *pdu, uint32_t beg_run,
    3880             :                        uint32_t run_length, int32_t task_tag)
    3881             : {
    3882             :         int32_t last_r2tsn;
    3883             :         int i;
    3884             : 
    3885           0 :         if (beg_run < task->acked_r2tsn) {
    3886           0 :                 SPDK_ERRLOG("ITT: 0x%08x, R2T SNACK requests retransmission of"
    3887             :                             "R2TSN: from 0x%08x to 0x%08x. But it has already"
    3888             :                             "ack to R2TSN:0x%08x, protocol error.\n",
    3889             :                             task_tag, beg_run, (beg_run + run_length),
    3890             :                             (task->acked_r2tsn - 1));
    3891           0 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    3892             :         }
    3893             : 
    3894           0 :         if (run_length) {
    3895           0 :                 if ((beg_run + run_length) > task->R2TSN) {
    3896           0 :                         SPDK_ERRLOG("ITT: 0x%08x, received R2T SNACK with"
    3897             :                                     "BegRun: 0x%08x, RunLength: 0x%08x, exceeds"
    3898             :                                     "current R2TSN: 0x%08x, protocol error.\n",
    3899             :                                     task_tag, beg_run, run_length,
    3900             :                                     task->R2TSN);
    3901             : 
    3902           0 :                         return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
    3903             :                 }
    3904           0 :                 last_r2tsn = (beg_run + run_length);
    3905             :         } else {
    3906           0 :                 last_r2tsn = task->R2TSN;
    3907             :         }
    3908             : 
    3909           0 :         for (i = beg_run; i < last_r2tsn; i++) {
    3910           0 :                 if (iscsi_send_r2t_recovery(conn, task, i, false) < 0) {
    3911           0 :                         SPDK_ERRLOG("The r2t_sn=%d of r2t_task=%p is not sent\n", i, task);
    3912             :                 }
    3913             :         }
    3914           0 :         return 0;
    3915             : }
    3916             : 
    3917             : /* This function is used to recover the data in packet */
    3918             : static int
    3919           0 : iscsi_handle_recovery_datain(struct spdk_iscsi_conn *conn,
    3920             :                              struct spdk_iscsi_task *task,
    3921             :                              struct spdk_iscsi_pdu *pdu, uint32_t beg_run,
    3922             :                              uint32_t run_length, uint32_t task_tag)
    3923             : {
    3924             :         struct spdk_iscsi_pdu *old_pdu, *pdu_temp;
    3925             :         uint32_t i;
    3926             :         struct iscsi_bhs_data_in *datain_header;
    3927             :         uint32_t last_statsn;
    3928             : 
    3929           0 :         task = iscsi_task_get_primary(task);
    3930             : 
    3931           0 :         SPDK_DEBUGLOG(iscsi, "iscsi_handle_recovery_datain\n");
    3932             : 
    3933           0 :         if (beg_run < task->acked_data_sn) {
    3934           0 :                 SPDK_ERRLOG("ITT: 0x%08x, DATA IN SNACK requests retransmission of"
    3935             :                             "DATASN: from 0x%08x to 0x%08x but already acked to "
    3936             :                             "DATASN: 0x%08x protocol error\n",
    3937             :                             task_tag, beg_run,
    3938             :                             (beg_run + run_length), (task->acked_data_sn - 1));
    3939             : 
    3940           0 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    3941             :         }
    3942             : 
    3943           0 :         if (run_length == 0) {
    3944             :                 /* as the DataSN begins at 0 */
    3945           0 :                 run_length = task->datain_datasn + 1;
    3946             :         }
    3947             : 
    3948           0 :         if ((beg_run + run_length - 1) > task->datain_datasn) {
    3949           0 :                 SPDK_ERRLOG("Initiator requests BegRun: 0x%08x, RunLength:"
    3950             :                             "0x%08x greater than maximum DataSN: 0x%08x.\n",
    3951             :                             beg_run, run_length, task->datain_datasn);
    3952             : 
    3953           0 :                 return -1;
    3954             :         } else {
    3955           0 :                 last_statsn = beg_run + run_length - 1;
    3956             :         }
    3957             : 
    3958           0 :         for (i = beg_run; i <= last_statsn; i++) {
    3959           0 :                 TAILQ_FOREACH_SAFE(old_pdu, &conn->snack_pdu_list, tailq, pdu_temp) {
    3960           0 :                         if (old_pdu->bhs.opcode == ISCSI_OP_SCSI_DATAIN) {
    3961           0 :                                 datain_header = (struct iscsi_bhs_data_in *)&old_pdu->bhs;
    3962           0 :                                 if (from_be32(&datain_header->itt) == task_tag &&
    3963           0 :                                     from_be32(&datain_header->data_sn) == i) {
    3964           0 :                                         TAILQ_REMOVE(&conn->snack_pdu_list, old_pdu, tailq);
    3965           0 :                                         iscsi_conn_write_pdu(conn, old_pdu, old_pdu->cb_fn, old_pdu->cb_arg);
    3966           0 :                                         break;
    3967             :                                 }
    3968             :                         }
    3969             :                 }
    3970             :         }
    3971           0 :         return 0;
    3972             : }
    3973             : 
    3974             : /* This function is used to handle the status snack */
    3975             : static int
    3976           0 : iscsi_handle_status_snack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    3977             : {
    3978             :         uint32_t beg_run;
    3979             :         uint32_t run_length;
    3980             :         struct iscsi_bhs_snack_req *reqh;
    3981             :         uint32_t i;
    3982             :         uint32_t last_statsn;
    3983             :         bool found_pdu;
    3984             :         struct spdk_iscsi_pdu *old_pdu;
    3985             : 
    3986           0 :         reqh = (struct iscsi_bhs_snack_req *)&pdu->bhs;
    3987           0 :         beg_run = from_be32(&reqh->beg_run);
    3988           0 :         run_length = from_be32(&reqh->run_len);
    3989             : 
    3990           0 :         SPDK_DEBUGLOG(iscsi, "beg_run=%d, run_length=%d, conn->StatSN="
    3991             :                       "%d, conn->exp_statsn=%d\n", beg_run, run_length,
    3992             :                       conn->StatSN, conn->exp_statsn);
    3993             : 
    3994           0 :         if (!beg_run) {
    3995           0 :                 beg_run = conn->exp_statsn;
    3996           0 :         } else if (beg_run < conn->exp_statsn) {
    3997           0 :                 SPDK_ERRLOG("Got Status SNACK Begrun: 0x%08x, RunLength: 0x%08x "
    3998             :                             "but already got ExpStatSN: 0x%08x on CID:%hu.\n",
    3999             :                             beg_run, run_length, conn->StatSN, conn->cid);
    4000             : 
    4001           0 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
    4002             :         }
    4003             : 
    4004           0 :         last_statsn = (!run_length) ? conn->StatSN : (beg_run + run_length);
    4005             : 
    4006           0 :         for (i = beg_run; i < last_statsn; i++) {
    4007           0 :                 found_pdu = false;
    4008           0 :                 TAILQ_FOREACH(old_pdu, &conn->snack_pdu_list, tailq) {
    4009           0 :                         if (from_be32(&old_pdu->bhs.stat_sn) == i) {
    4010           0 :                                 found_pdu = true;
    4011           0 :                                 break;
    4012             :                         }
    4013             :                 }
    4014             : 
    4015           0 :                 if (!found_pdu) {
    4016           0 :                         SPDK_ERRLOG("Unable to find StatSN: 0x%08x. For a Status"
    4017             :                                     "SNACK, assuming this is a proactive SNACK "
    4018             :                                     "for an untransmitted StatSN, ignoring.\n",
    4019             :                                     beg_run);
    4020             :                 } else {
    4021           0 :                         TAILQ_REMOVE(&conn->snack_pdu_list, old_pdu, tailq);
    4022           0 :                         iscsi_conn_write_pdu(conn, old_pdu, old_pdu->cb_fn, old_pdu->cb_arg);
    4023             :                 }
    4024             :         }
    4025             : 
    4026           0 :         return 0;
    4027             : }
    4028             : 
    4029             : /* This function is used to handle the data ack snack */
    4030             : static int
    4031           0 : iscsi_handle_data_ack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    4032             : {
    4033             :         uint32_t transfer_tag;
    4034             :         uint32_t beg_run;
    4035             :         uint32_t run_length;
    4036             :         struct spdk_iscsi_pdu *old_pdu;
    4037             :         uint32_t old_datasn;
    4038             :         struct iscsi_bhs_snack_req *reqh;
    4039             :         struct spdk_iscsi_task *task;
    4040             :         struct iscsi_bhs_data_in *datain_header;
    4041             :         struct spdk_iscsi_task *primary;
    4042             : 
    4043           0 :         reqh = (struct iscsi_bhs_snack_req *)&pdu->bhs;
    4044           0 :         transfer_tag = from_be32(&reqh->ttt);
    4045           0 :         beg_run = from_be32(&reqh->beg_run);
    4046           0 :         run_length = from_be32(&reqh->run_len);
    4047           0 :         task = NULL;
    4048           0 :         datain_header = NULL;
    4049             : 
    4050           0 :         SPDK_DEBUGLOG(iscsi, "beg_run=%d,transfer_tag=%d,run_len=%d\n",
    4051             :                       beg_run, transfer_tag, run_length);
    4052             : 
    4053           0 :         task = get_scsi_task_from_ttt(conn, transfer_tag);
    4054           0 :         if (!task) {
    4055           0 :                 SPDK_ERRLOG("Data ACK SNACK for TTT: 0x%08x is invalid.\n",
    4056             :                             transfer_tag);
    4057           0 :                 goto reject_return;
    4058             :         }
    4059             : 
    4060           0 :         primary = iscsi_task_get_primary(task);
    4061           0 :         if ((run_length != 0) || (beg_run < primary->acked_data_sn)) {
    4062           0 :                 SPDK_ERRLOG("TTT: 0x%08x Data ACK SNACK BegRUN: %d is less than "
    4063             :                             "the next expected acked DataSN: %d\n",
    4064             :                             transfer_tag, beg_run, primary->acked_data_sn);
    4065           0 :                 goto reject_return;
    4066             :         }
    4067             : 
    4068           0 :         primary->acked_data_sn = beg_run;
    4069             : 
    4070             :         /* To free the pdu */
    4071           0 :         TAILQ_FOREACH(old_pdu, &conn->snack_pdu_list, tailq) {
    4072           0 :                 if (old_pdu->bhs.opcode == ISCSI_OP_SCSI_DATAIN) {
    4073           0 :                         datain_header = (struct iscsi_bhs_data_in *) &old_pdu->bhs;
    4074           0 :                         old_datasn = from_be32(&datain_header->data_sn);
    4075           0 :                         if ((from_be32(&datain_header->ttt) == transfer_tag) &&
    4076           0 :                             (old_datasn == beg_run - 1)) {
    4077           0 :                                 TAILQ_REMOVE(&conn->snack_pdu_list, old_pdu, tailq);
    4078           0 :                                 iscsi_conn_free_pdu(conn, old_pdu);
    4079           0 :                                 break;
    4080             :                         }
    4081             :                 }
    4082             :         }
    4083             : 
    4084           0 :         SPDK_DEBUGLOG(iscsi, "Received Data ACK SNACK for TTT: 0x%08x,"
    4085             :                       " updated acked DataSN to 0x%08x.\n", transfer_tag,
    4086             :                       (task->acked_data_sn - 1));
    4087             : 
    4088           0 :         return 0;
    4089             : 
    4090           0 : reject_return:
    4091           0 :         return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_SNACK);
    4092             : }
    4093             : 
    4094             : /* This function is used to handle the snack request from the initiator */
    4095             : static int
    4096           0 : iscsi_pdu_hdr_op_snack(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    4097             : {
    4098             :         struct iscsi_bhs_snack_req *reqh;
    4099             :         struct spdk_iscsi_task *task;
    4100             :         int type;
    4101             :         uint32_t task_tag;
    4102             :         uint32_t beg_run;
    4103             :         uint32_t run_length;
    4104             :         int rc;
    4105             : 
    4106           0 :         if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
    4107           0 :                 SPDK_ERRLOG("ISCSI_OP_SNACK not allowed in  discovery session\n");
    4108           0 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    4109             :         }
    4110             : 
    4111           0 :         reqh = (struct iscsi_bhs_snack_req *)&pdu->bhs;
    4112           0 :         if (!conn->sess->ErrorRecoveryLevel) {
    4113           0 :                 SPDK_ERRLOG("Got a SNACK request in ErrorRecoveryLevel=0\n");
    4114           0 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    4115             :         }
    4116             : 
    4117           0 :         type = reqh->flags & ISCSI_FLAG_SNACK_TYPE_MASK;
    4118           0 :         SPDK_DEBUGLOG(iscsi, "The value of type is %d\n", type);
    4119             : 
    4120           0 :         switch (type) {
    4121           0 :         case 0:
    4122           0 :                 reqh = (struct iscsi_bhs_snack_req *)&pdu->bhs;
    4123           0 :                 task_tag = from_be32(&reqh->itt);
    4124           0 :                 beg_run = from_be32(&reqh->beg_run);
    4125           0 :                 run_length = from_be32(&reqh->run_len);
    4126             : 
    4127           0 :                 SPDK_DEBUGLOG(iscsi, "beg_run=%d, run_length=%d, "
    4128             :                               "task_tag=%x, transfer_tag=%u\n", beg_run,
    4129             :                               run_length, task_tag, from_be32(&reqh->ttt));
    4130             : 
    4131           0 :                 task = get_scsi_task_from_itt(conn, task_tag,
    4132             :                                               ISCSI_OP_SCSI_DATAIN);
    4133           0 :                 if (task) {
    4134           0 :                         return iscsi_handle_recovery_datain(conn, task, pdu,
    4135             :                                                             beg_run, run_length, task_tag);
    4136             :                 }
    4137           0 :                 task = get_scsi_task_from_itt(conn, task_tag, ISCSI_OP_R2T);
    4138           0 :                 if (task) {
    4139           0 :                         return iscsi_handle_r2t_snack(conn, task, pdu, beg_run,
    4140             :                                                       run_length, task_tag);
    4141             :                 }
    4142           0 :                 SPDK_ERRLOG("It is Neither datain nor r2t recovery request\n");
    4143           0 :                 rc = -1;
    4144           0 :                 break;
    4145           0 :         case ISCSI_FLAG_SNACK_TYPE_STATUS:
    4146           0 :                 rc = iscsi_handle_status_snack(conn, pdu);
    4147           0 :                 break;
    4148           0 :         case ISCSI_FLAG_SNACK_TYPE_DATA_ACK:
    4149           0 :                 rc = iscsi_handle_data_ack(conn, pdu);
    4150           0 :                 break;
    4151           0 :         case ISCSI_FLAG_SNACK_TYPE_RDATA:
    4152           0 :                 SPDK_ERRLOG("R-Data SNACK is Not Supported int spdk\n");
    4153           0 :                 rc = iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    4154           0 :                 break;
    4155           0 :         default:
    4156           0 :                 SPDK_ERRLOG("Unknown SNACK type %d, protocol error\n", type);
    4157           0 :                 rc = iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    4158           0 :                 break;
    4159             :         }
    4160             : 
    4161           0 :         return rc;
    4162             : }
    4163             : 
    4164             : static inline uint32_t
    4165          47 : iscsi_get_mobj_max_data_len(struct spdk_mobj *mobj)
    4166             : {
    4167          47 :         if (mobj->mp == g_iscsi.pdu_immediate_data_pool) {
    4168           0 :                 return iscsi_get_max_immediate_data_size();
    4169             :         } else {
    4170          47 :                 return SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
    4171             :         }
    4172             : }
    4173             : 
    4174             : static int
    4175          22 : iscsi_pdu_hdr_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    4176             : {
    4177             :         struct spdk_iscsi_task  *task;
    4178             :         struct iscsi_bhs_data_out *reqh;
    4179             :         struct spdk_scsi_lun    *lun_dev;
    4180             :         struct spdk_mobj        *mobj;
    4181             :         uint32_t transfer_tag;
    4182             :         uint32_t task_tag;
    4183             :         uint32_t transfer_len;
    4184             :         uint32_t DataSN;
    4185             :         uint32_t buffer_offset;
    4186             :         uint32_t len;
    4187             :         uint32_t current_desired_data_transfer_length;
    4188             :         int F_bit;
    4189             :         int rc;
    4190             : 
    4191          22 :         if (conn->sess->session_type == SESSION_TYPE_DISCOVERY) {
    4192           1 :                 SPDK_ERRLOG("ISCSI_OP_SCSI_DATAOUT not allowed in discovery session\n");
    4193           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    4194             :         }
    4195             : 
    4196          21 :         reqh = (struct iscsi_bhs_data_out *)&pdu->bhs;
    4197          21 :         F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
    4198          21 :         transfer_tag = from_be32(&reqh->ttt);
    4199          21 :         task_tag = from_be32(&reqh->itt);
    4200          21 :         DataSN = from_be32(&reqh->data_sn);
    4201          21 :         buffer_offset = from_be32(&reqh->buffer_offset);
    4202             : 
    4203          21 :         if (pdu->data_segment_len > SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
    4204           1 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    4205             :         }
    4206             : 
    4207          20 :         task = get_transfer_task(conn, transfer_tag);
    4208          20 :         if (task == NULL) {
    4209           1 :                 SPDK_ERRLOG("Not found task for transfer_tag=%x\n", transfer_tag);
    4210           1 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
    4211             :         }
    4212             : 
    4213          19 :         lun_dev = spdk_scsi_dev_get_lun(conn->dev, task->lun_id);
    4214          19 :         current_desired_data_transfer_length = task->desired_data_transfer_length;
    4215             : 
    4216          19 :         if (pdu->data_segment_len > task->desired_data_transfer_length) {
    4217           2 :                 SPDK_ERRLOG("the dataout pdu data length is larger than the value sent by R2T PDU\n");
    4218           2 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    4219             :         }
    4220             : 
    4221          17 :         if (task->tag != task_tag) {
    4222           1 :                 SPDK_ERRLOG("The r2t task tag is %u, and the dataout task tag is %u\n",
    4223             :                             task->tag, task_tag);
    4224           1 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
    4225             :         }
    4226             : 
    4227          16 :         if (DataSN != task->r2t_datasn) {
    4228           1 :                 SPDK_ERRLOG("DataSN(%u) exp=%d error\n", DataSN, task->r2t_datasn);
    4229           1 :                 if (conn->sess->ErrorRecoveryLevel >= 1) {
    4230           0 :                         rc = iscsi_send_r2t_recovery(conn, task, task->acked_r2tsn, true);
    4231           0 :                         if (rc == 0) {
    4232           0 :                                 return 0;
    4233             :                         }
    4234             :                 }
    4235           1 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    4236             :         }
    4237             : 
    4238          15 :         if (buffer_offset != task->next_expected_r2t_offset) {
    4239           1 :                 SPDK_ERRLOG("offset(%u) error\n", buffer_offset);
    4240           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    4241             :         }
    4242             : 
    4243          14 :         transfer_len = task->scsi.transfer_len;
    4244          14 :         task->current_r2t_length += pdu->data_segment_len;
    4245          14 :         task->next_expected_r2t_offset += pdu->data_segment_len;
    4246          14 :         task->r2t_datasn++;
    4247             : 
    4248          14 :         if (task->current_r2t_length > conn->sess->MaxBurstLength) {
    4249           1 :                 SPDK_ERRLOG("R2T burst(%u) > MaxBurstLength(%u)\n",
    4250             :                             task->current_r2t_length,
    4251             :                             conn->sess->MaxBurstLength);
    4252           1 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    4253             :         }
    4254             : 
    4255          13 :         if (F_bit) {
    4256             :                 /*
    4257             :                  * This R2T burst is done. Clear the length before we
    4258             :                  *  receive a PDU for the next R2t burst.
    4259             :                  */
    4260           3 :                 task->current_r2t_length = 0;
    4261             :         }
    4262             : 
    4263          13 :         if (task->next_expected_r2t_offset == transfer_len) {
    4264           2 :                 task->acked_r2tsn++;
    4265          11 :         } else if (F_bit && (task->next_r2t_offset < transfer_len)) {
    4266           1 :                 task->acked_r2tsn++;
    4267           1 :                 len = spdk_min(conn->sess->MaxBurstLength,
    4268             :                                (transfer_len - task->next_r2t_offset));
    4269           1 :                 rc = iscsi_send_r2t(conn, task, task->next_r2t_offset, len,
    4270             :                                     task->ttt, &task->R2TSN);
    4271           1 :                 if (rc < 0) {
    4272           0 :                         SPDK_ERRLOG("iscsi_send_r2t() failed\n");
    4273             :                 }
    4274           1 :                 task->next_r2t_offset += len;
    4275             :         }
    4276             : 
    4277          13 :         if (lun_dev == NULL) {
    4278           1 :                 SPDK_DEBUGLOG(iscsi, "LUN %d is removed, reject this PDU.\n",
    4279             :                               task->lun_id);
    4280           1 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    4281          12 :         } else if (spdk_unlikely(spdk_scsi_lun_get_dif_ctx(lun_dev, &task->scsi, &pdu->dif_ctx))) {
    4282           0 :                 pdu->dif_insert_or_strip = true;
    4283             :         }
    4284             : 
    4285          12 :         mobj = iscsi_task_get_mobj(task);
    4286          12 :         if (mobj == NULL) {
    4287           3 :                 if (!pdu->dif_insert_or_strip) {
    4288             :                         /* More Data-OUT PDUs may follow. Increase the buffer size up to
    4289             :                          * SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH to merge them into a
    4290             :                          * single subtask.
    4291             :                          */
    4292           3 :                         pdu->data_buf_len = spdk_min(current_desired_data_transfer_length,
    4293             :                                                      SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
    4294             :                 }
    4295             :         } else {
    4296             :                 /* Set up the data buffer from the one saved by the primary task. */
    4297           9 :                 pdu->mobj[0] = mobj;
    4298           9 :                 pdu->data = (void *)((uint64_t)mobj->buf + mobj->data_len);
    4299           9 :                 pdu->data_from_mempool = true;
    4300           9 :                 pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(iscsi_get_mobj_max_data_len(mobj));
    4301             : 
    4302           9 :                 iscsi_task_set_mobj(task, NULL);
    4303             :         }
    4304             : 
    4305          12 :         return 0;
    4306             : }
    4307             : 
    4308             : static int
    4309          10 : iscsi_pdu_payload_op_data(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    4310             : {
    4311             :         struct spdk_iscsi_task *task;
    4312             :         struct iscsi_bhs_data_out *reqh;
    4313             :         struct spdk_mobj *mobj;
    4314             :         uint32_t transfer_tag;
    4315             :         int F_bit;
    4316             :         int rc;
    4317             : 
    4318          10 :         reqh = (struct iscsi_bhs_data_out *)&pdu->bhs;
    4319          10 :         F_bit = !!(reqh->flags & ISCSI_FLAG_FINAL);
    4320          10 :         transfer_tag = from_be32(&reqh->ttt);
    4321             : 
    4322          10 :         task = get_transfer_task(conn, transfer_tag);
    4323          10 :         if (spdk_unlikely(task == NULL)) {
    4324           0 :                 SPDK_ERRLOG("Not found for transfer_tag=%x\n", transfer_tag);
    4325           0 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_INVALID_PDU_FIELD);
    4326             :         }
    4327             : 
    4328          10 :         if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) {
    4329           0 :                 SPDK_DEBUGLOG(iscsi, "LUN %d is removed, reject this PDU.\n",
    4330             :                               task->lun_id);
    4331           0 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    4332             :         }
    4333             : 
    4334             :         /* If current PDU is final in a sequence, submit all received data,
    4335             :          * otherwise, continue aggregation until the first data buffer is full.
    4336             :          * We do not use SGL and instead create a subtask per data buffer. Hence further
    4337             :          * aggregation does not improve any performance.
    4338             :          */
    4339          10 :         mobj = pdu->mobj[0];
    4340          10 :         assert(mobj != NULL);
    4341             : 
    4342          10 :         if (F_bit || mobj->data_len >= SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH ||
    4343           7 :             pdu->dif_insert_or_strip) {
    4344           3 :                 rc = iscsi_submit_write_subtask(conn, task, pdu, mobj);
    4345           3 :                 if (rc != 0) {
    4346           0 :                         return rc;
    4347             :                 }
    4348             :         } else {
    4349           7 :                 assert(pdu->mobj[1] == NULL);
    4350           7 :                 iscsi_task_set_mobj(task, mobj);
    4351           7 :                 pdu->mobj[0] = NULL;
    4352           7 :                 return 0;
    4353             :         }
    4354             : 
    4355           3 :         mobj = pdu->mobj[1];
    4356           3 :         if (mobj == NULL) {
    4357           1 :                 return 0;
    4358             :         }
    4359             : 
    4360           2 :         assert(pdu->dif_insert_or_strip == false);
    4361           2 :         assert(mobj->data_len < SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
    4362             : 
    4363           2 :         if (F_bit) {
    4364           1 :                 return iscsi_submit_write_subtask(conn, task, pdu, mobj);
    4365             :         } else {
    4366           1 :                 iscsi_task_set_mobj(task, mobj);
    4367           1 :                 pdu->mobj[1] = NULL;
    4368           1 :                 return 0;
    4369             :         }
    4370             : }
    4371             : 
    4372             : static void
    4373           0 : init_login_reject_response(struct spdk_iscsi_pdu *pdu, struct spdk_iscsi_pdu *rsp_pdu)
    4374             : {
    4375             :         struct iscsi_bhs_login_rsp *rsph;
    4376             : 
    4377           0 :         memset(rsp_pdu, 0, sizeof(struct spdk_iscsi_pdu));
    4378           0 :         rsph = (struct iscsi_bhs_login_rsp *)&rsp_pdu->bhs;
    4379           0 :         rsph->version_max = ISCSI_VERSION;
    4380           0 :         rsph->version_act = ISCSI_VERSION;
    4381           0 :         rsph->opcode = ISCSI_OP_LOGIN_RSP;
    4382           0 :         rsph->status_class = ISCSI_CLASS_INITIATOR_ERROR;
    4383           0 :         rsph->status_detail = ISCSI_LOGIN_INVALID_LOGIN_REQUEST;
    4384           0 :         rsph->itt = pdu->bhs.itt;
    4385           0 : }
    4386             : 
    4387             : static void
    4388           0 : iscsi_pdu_dump(struct spdk_iscsi_pdu *pdu)
    4389             : {
    4390           0 :         spdk_log_dump(stderr, "PDU", (uint8_t *)&pdu->bhs, ISCSI_BHS_LEN);
    4391           0 : }
    4392             : 
    4393             : /* This function is used to refree the pdu when it is acknowledged */
    4394             : static void
    4395           0 : remove_acked_pdu(struct spdk_iscsi_conn *conn, uint32_t ExpStatSN)
    4396             : {
    4397             :         struct spdk_iscsi_pdu *pdu, *pdu_temp;
    4398             :         uint32_t stat_sn;
    4399             : 
    4400           0 :         conn->exp_statsn = spdk_min(ExpStatSN, conn->StatSN);
    4401           0 :         TAILQ_FOREACH_SAFE(pdu, &conn->snack_pdu_list, tailq, pdu_temp) {
    4402           0 :                 stat_sn = from_be32(&pdu->bhs.stat_sn);
    4403           0 :                 if (spdk_sn32_lt(stat_sn, conn->exp_statsn)) {
    4404           0 :                         TAILQ_REMOVE(&conn->snack_pdu_list, pdu, tailq);
    4405           0 :                         iscsi_conn_free_pdu(conn, pdu);
    4406             :                 }
    4407             :         }
    4408           0 : }
    4409             : 
    4410             : static int
    4411          14 : iscsi_update_cmdsn(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    4412             : {
    4413             :         int opcode;
    4414             :         uint32_t ExpStatSN;
    4415             :         int I_bit;
    4416             :         struct spdk_iscsi_sess *sess;
    4417             :         struct iscsi_bhs_scsi_req *reqh;
    4418             : 
    4419          14 :         sess = conn->sess;
    4420          14 :         if (!sess) {
    4421           0 :                 SPDK_ERRLOG("Connection has no associated session!\n");
    4422           0 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    4423             :         }
    4424             : 
    4425          14 :         opcode = pdu->bhs.opcode;
    4426          14 :         reqh = (struct iscsi_bhs_scsi_req *)&pdu->bhs;
    4427             : 
    4428          14 :         pdu->cmd_sn = from_be32(&reqh->cmd_sn);
    4429             : 
    4430          14 :         I_bit = reqh->immediate;
    4431          14 :         if (I_bit == 0) {
    4432          21 :                 if (spdk_sn32_lt(pdu->cmd_sn, sess->ExpCmdSN) ||
    4433           7 :                     spdk_sn32_gt(pdu->cmd_sn, sess->MaxCmdSN)) {
    4434           7 :                         if (sess->session_type == SESSION_TYPE_NORMAL &&
    4435             :                             opcode != ISCSI_OP_SCSI_DATAOUT) {
    4436           0 :                                 SPDK_ERRLOG("CmdSN(%u) ignore (ExpCmdSN=%u, MaxCmdSN=%u)\n",
    4437             :                                             pdu->cmd_sn, sess->ExpCmdSN, sess->MaxCmdSN);
    4438             : 
    4439           0 :                                 if (sess->ErrorRecoveryLevel >= 1) {
    4440           0 :                                         SPDK_DEBUGLOG(iscsi, "Skip the error in ERL 1 and 2\n");
    4441             :                                 } else {
    4442           0 :                                         return SPDK_PDU_FATAL;
    4443             :                                 }
    4444             :                         }
    4445             :                 }
    4446           0 :         } else if (pdu->cmd_sn != sess->ExpCmdSN) {
    4447           0 :                 SPDK_ERRLOG("CmdSN(%u) error ExpCmdSN=%u\n", pdu->cmd_sn, sess->ExpCmdSN);
    4448             : 
    4449           0 :                 if (sess->ErrorRecoveryLevel >= 1) {
    4450           0 :                         SPDK_DEBUGLOG(iscsi, "Skip the error in ERL 1 and 2\n");
    4451           0 :                 } else if (opcode != ISCSI_OP_NOPOUT) {
    4452             :                         /*
    4453             :                          * The Linux initiator does not send valid CmdSNs for
    4454             :                          *  nopout under heavy load, so do not close the
    4455             :                          *  connection in that case.
    4456             :                          */
    4457           0 :                         return SPDK_ISCSI_CONNECTION_FATAL;
    4458             :                 }
    4459             :         }
    4460             : 
    4461          14 :         ExpStatSN = from_be32(&reqh->exp_stat_sn);
    4462          14 :         if (spdk_sn32_gt(ExpStatSN, conn->StatSN)) {
    4463           0 :                 SPDK_DEBUGLOG(iscsi, "StatSN(%u) advanced\n", ExpStatSN);
    4464           0 :                 ExpStatSN = conn->StatSN;
    4465             :         }
    4466             : 
    4467          14 :         if (sess->ErrorRecoveryLevel >= 1) {
    4468           0 :                 remove_acked_pdu(conn, ExpStatSN);
    4469             :         }
    4470             : 
    4471          14 :         if (!I_bit && opcode != ISCSI_OP_SCSI_DATAOUT) {
    4472           3 :                 sess->ExpCmdSN++;
    4473             :         }
    4474             : 
    4475          14 :         return 0;
    4476             : }
    4477             : 
    4478             : static int
    4479          14 : iscsi_pdu_hdr_handle(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    4480             : {
    4481             :         int opcode;
    4482             :         int rc;
    4483          14 :         struct spdk_iscsi_pdu *rsp_pdu = NULL;
    4484             : 
    4485          14 :         if (pdu == NULL) {
    4486           0 :                 return -1;
    4487             :         }
    4488             : 
    4489          14 :         opcode = pdu->bhs.opcode;
    4490             : 
    4491          14 :         SPDK_DEBUGLOG(iscsi, "opcode %x\n", opcode);
    4492             : 
    4493          14 :         if (opcode == ISCSI_OP_LOGIN) {
    4494           0 :                 return iscsi_pdu_hdr_op_login(conn, pdu);
    4495             :         }
    4496             : 
    4497             :         /* connection in login phase but receive non-login opcode
    4498             :          * return response code 0x020b to initiator.
    4499             :          * */
    4500          14 :         if (!conn->full_feature && conn->state == ISCSI_CONN_STATE_RUNNING) {
    4501           0 :                 rsp_pdu = iscsi_get_pdu(conn);
    4502           0 :                 if (rsp_pdu == NULL) {
    4503           0 :                         return SPDK_ISCSI_CONNECTION_FATAL;
    4504             :                 }
    4505           0 :                 init_login_reject_response(pdu, rsp_pdu);
    4506           0 :                 iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
    4507           0 :                 SPDK_ERRLOG("Received opcode %d in login phase\n", opcode);
    4508           0 :                 return SPDK_ISCSI_LOGIN_ERROR_RESPONSE;
    4509          14 :         } else if (conn->state == ISCSI_CONN_STATE_INVALID) {
    4510           0 :                 SPDK_ERRLOG("before Full Feature\n");
    4511           0 :                 iscsi_pdu_dump(pdu);
    4512           0 :                 return SPDK_ISCSI_CONNECTION_FATAL;
    4513             :         }
    4514             : 
    4515          14 :         rc = iscsi_update_cmdsn(conn, pdu);
    4516          14 :         if (rc != 0) {
    4517           0 :                 return rc;
    4518             :         }
    4519             : 
    4520          14 :         switch (opcode) {
    4521           0 :         case ISCSI_OP_NOPOUT:
    4522           0 :                 rc = iscsi_pdu_hdr_op_nopout(conn, pdu);
    4523           0 :                 break;
    4524             : 
    4525           2 :         case ISCSI_OP_SCSI:
    4526           2 :                 rc = iscsi_pdu_hdr_op_scsi(conn, pdu);
    4527           2 :                 break;
    4528           0 :         case ISCSI_OP_TASK:
    4529           0 :                 rc = iscsi_pdu_hdr_op_task(conn, pdu);
    4530           0 :                 break;
    4531             : 
    4532           1 :         case ISCSI_OP_TEXT:
    4533           1 :                 rc = iscsi_pdu_hdr_op_text(conn, pdu);
    4534           1 :                 break;
    4535             : 
    4536           0 :         case ISCSI_OP_LOGOUT:
    4537           0 :                 rc = iscsi_pdu_hdr_op_logout(conn, pdu);
    4538           0 :                 break;
    4539             : 
    4540          11 :         case ISCSI_OP_SCSI_DATAOUT:
    4541          11 :                 rc = iscsi_pdu_hdr_op_data(conn, pdu);
    4542          11 :                 break;
    4543             : 
    4544           0 :         case ISCSI_OP_SNACK:
    4545           0 :                 rc = iscsi_pdu_hdr_op_snack(conn, pdu);
    4546           0 :                 break;
    4547             : 
    4548           0 :         default:
    4549           0 :                 SPDK_ERRLOG("unsupported opcode %x\n", opcode);
    4550           0 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    4551             :         }
    4552             : 
    4553          14 :         if (rc < 0) {
    4554           1 :                 SPDK_ERRLOG("processing PDU header (opcode=%x) failed on %s(%s)\n",
    4555             :                             opcode,
    4556             :                             conn->target_port != NULL ? spdk_scsi_port_get_name(conn->target_port) : "NULL",
    4557             :                             conn->initiator_port != NULL ? spdk_scsi_port_get_name(conn->initiator_port) : "NULL");
    4558             :         }
    4559             : 
    4560          14 :         return rc;
    4561             : }
    4562             : 
    4563             : static int
    4564          13 : iscsi_pdu_payload_handle(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    4565             : {
    4566             :         int opcode;
    4567          13 :         int rc = 0;
    4568             : 
    4569          13 :         opcode = pdu->bhs.opcode;
    4570             : 
    4571          13 :         SPDK_DEBUGLOG(iscsi, "opcode %x\n", opcode);
    4572             : 
    4573          13 :         switch (opcode) {
    4574           0 :         case ISCSI_OP_LOGIN:
    4575           0 :                 rc = iscsi_pdu_payload_op_login(conn, pdu);
    4576           0 :                 break;
    4577           0 :         case ISCSI_OP_NOPOUT:
    4578           0 :                 rc = iscsi_pdu_payload_op_nopout(conn, pdu);
    4579           0 :                 break;
    4580           2 :         case ISCSI_OP_SCSI:
    4581           2 :                 rc = iscsi_pdu_payload_op_scsi(conn, pdu);
    4582           2 :                 break;
    4583           0 :         case ISCSI_OP_TASK:
    4584           0 :                 break;
    4585           1 :         case ISCSI_OP_TEXT:
    4586           1 :                 rc = iscsi_pdu_payload_op_text(conn, pdu);
    4587           1 :                 break;
    4588           0 :         case ISCSI_OP_LOGOUT:
    4589           0 :                 break;
    4590          10 :         case ISCSI_OP_SCSI_DATAOUT:
    4591          10 :                 rc = iscsi_pdu_payload_op_data(conn, pdu);
    4592          10 :                 break;
    4593           0 :         case ISCSI_OP_SNACK:
    4594           0 :                 break;
    4595           0 :         default:
    4596           0 :                 SPDK_ERRLOG("unsupported opcode %x\n", opcode);
    4597           0 :                 return iscsi_reject(conn, pdu, ISCSI_REASON_PROTOCOL_ERROR);
    4598             :         }
    4599             : 
    4600          13 :         if (rc < 0) {
    4601           0 :                 SPDK_ERRLOG("processing PDU payload (opcode=%x) failed on %s(%s)\n",
    4602             :                             opcode,
    4603             :                             conn->target_port != NULL ? spdk_scsi_port_get_name(conn->target_port) : "NULL",
    4604             :                             conn->initiator_port != NULL ? spdk_scsi_port_get_name(conn->initiator_port) : "NULL");
    4605             :         }
    4606             : 
    4607          13 :         return rc;
    4608             : }
    4609             : 
    4610             : /* Return zero if completed to read payload, positive number if still in progress,
    4611             :  * or negative number if any error.
    4612             :  */
    4613             : static int
    4614          19 : iscsi_pdu_payload_read(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
    4615             : {
    4616             :         struct spdk_mempool *pool;
    4617             :         struct spdk_mobj *mobj;
    4618             :         uint32_t data_len;
    4619             :         uint32_t read_len;
    4620             :         uint32_t crc32c;
    4621             :         int rc;
    4622             :         uint32_t data_buf_len;
    4623             : 
    4624          19 :         data_len = pdu->data_segment_len;
    4625          19 :         read_len = data_len - pdu->data_valid_bytes;
    4626          19 :         data_buf_len = pdu->data_buf_len;
    4627             : 
    4628          19 :         mobj = pdu->mobj[0];
    4629          19 :         if (mobj == NULL) {
    4630           5 :                 if (data_buf_len <= iscsi_get_max_immediate_data_size()) {
    4631           1 :                         pool = g_iscsi.pdu_immediate_data_pool;
    4632           1 :                         data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(iscsi_get_max_immediate_data_size());
    4633           4 :                 } else if (data_buf_len <= SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
    4634           3 :                         pool = g_iscsi.pdu_data_out_pool;
    4635           3 :                         data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
    4636             :                 } else {
    4637           1 :                         SPDK_ERRLOG("Data(%d) > MaxSegment(%d)\n",
    4638             :                                     data_len, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
    4639           1 :                         return -1;
    4640             :                 }
    4641           4 :                 mobj = iscsi_datapool_get(pool);
    4642           4 :                 if (mobj == NULL) {
    4643           0 :                         return 1;
    4644             :                 }
    4645             : 
    4646           4 :                 pdu->data_buf_len = data_buf_len;
    4647             : 
    4648           4 :                 pdu->mobj[0] = mobj;
    4649           4 :                 pdu->data = mobj->buf;
    4650           4 :                 pdu->data_from_mempool = true;
    4651          14 :         } else if (mobj->data_len == iscsi_get_mobj_max_data_len(mobj) && read_len > 0) {
    4652           3 :                 mobj = pdu->mobj[1];
    4653           3 :                 if (mobj == NULL) {
    4654             :                         /* The first data buffer just ran out. Allocate the second data buffer and
    4655             :                          * continue reading the data segment.
    4656             :                          */
    4657           3 :                         assert(pdu->data_from_mempool == true);
    4658           3 :                         assert(!pdu->dif_insert_or_strip);
    4659             : 
    4660           3 :                         if (conn->data_digest) {
    4661           0 :                                 iscsi_pdu_calc_partial_data_digest(pdu);
    4662             :                         }
    4663           3 :                         mobj = iscsi_datapool_get(g_iscsi.pdu_data_out_pool);
    4664           3 :                         if (mobj == NULL) {
    4665           0 :                                 return 1;
    4666             :                         }
    4667           3 :                         pdu->mobj[1] = mobj;
    4668           3 :                         pdu->data = mobj->buf;
    4669           3 :                         pdu->data_offset = pdu->data_valid_bytes;
    4670           3 :                         pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
    4671             :                 }
    4672             :         }
    4673             : 
    4674             :         /* copy the actual data into local buffer */
    4675          18 :         read_len = spdk_min(read_len, iscsi_get_mobj_max_data_len(mobj) - mobj->data_len);
    4676             : 
    4677          18 :         if (read_len > 0) {
    4678          17 :                 rc = iscsi_conn_read_data_segment(conn,
    4679             :                                                   pdu,
    4680          17 :                                                   pdu->data_valid_bytes - pdu->data_offset,
    4681             :                                                   read_len);
    4682          17 :                 if (rc < 0) {
    4683           0 :                         return rc;
    4684             :                 }
    4685             : 
    4686          17 :                 mobj->data_len += rc;
    4687          17 :                 pdu->data_valid_bytes += rc;
    4688          17 :                 if (pdu->data_valid_bytes < data_len) {
    4689           3 :                         return 1;
    4690             :                 }
    4691             :         }
    4692             : 
    4693             :         /* copy out the data digest */
    4694          15 :         if (conn->data_digest &&
    4695           1 :             pdu->ddigest_valid_bytes < ISCSI_DIGEST_LEN) {
    4696           1 :                 rc = iscsi_conn_read_data(conn,
    4697           1 :                                           ISCSI_DIGEST_LEN - pdu->ddigest_valid_bytes,
    4698           1 :                                           pdu->data_digest + pdu->ddigest_valid_bytes);
    4699           1 :                 if (rc < 0) {
    4700           0 :                         return rc;
    4701             :                 }
    4702             : 
    4703           1 :                 pdu->ddigest_valid_bytes += rc;
    4704           1 :                 if (pdu->ddigest_valid_bytes < ISCSI_DIGEST_LEN) {
    4705           0 :                         return 1;
    4706             :                 }
    4707             :         }
    4708             : 
    4709             :         /* check data digest */
    4710          15 :         if (conn->data_digest) {
    4711           1 :                 iscsi_pdu_calc_partial_data_digest(pdu);
    4712           1 :                 crc32c = iscsi_pdu_calc_partial_data_digest_done(pdu);
    4713             : 
    4714           1 :                 rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c);
    4715           1 :                 if (rc == 0) {
    4716           0 :                         SPDK_ERRLOG("data digest error (%s)\n", conn->initiator_name);
    4717           0 :                         return -1;
    4718             :                 }
    4719             :         }
    4720             : 
    4721          15 :         return 0;
    4722             : }
    4723             : 
    4724             : static int
    4725           0 : iscsi_read_pdu(struct spdk_iscsi_conn *conn)
    4726             : {
    4727             :         enum iscsi_pdu_recv_state prev_state;
    4728             :         struct spdk_iscsi_pdu *pdu;
    4729             :         uint32_t crc32c;
    4730             :         int ahs_len;
    4731             :         int rc;
    4732             : 
    4733             :         do {
    4734           0 :                 prev_state = conn->pdu_recv_state;
    4735           0 :                 pdu = conn->pdu_in_progress;
    4736             : 
    4737           0 :                 switch (conn->pdu_recv_state) {
    4738           0 :                 case ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY:
    4739           0 :                         assert(conn->pdu_in_progress == NULL);
    4740             : 
    4741           0 :                         conn->pdu_in_progress = iscsi_get_pdu(conn);
    4742           0 :                         if (conn->pdu_in_progress == NULL) {
    4743           0 :                                 return SPDK_ISCSI_CONNECTION_FATAL;
    4744             :                         }
    4745           0 :                         conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_HDR;
    4746           0 :                         break;
    4747           0 :                 case ISCSI_PDU_RECV_STATE_AWAIT_PDU_HDR:
    4748           0 :                         if (pdu->bhs_valid_bytes < ISCSI_BHS_LEN) {
    4749           0 :                                 rc = iscsi_conn_read_data(conn,
    4750           0 :                                                           ISCSI_BHS_LEN - pdu->bhs_valid_bytes,
    4751           0 :                                                           (uint8_t *)&pdu->bhs + pdu->bhs_valid_bytes);
    4752           0 :                                 if (rc < 0) {
    4753           0 :                                         conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
    4754           0 :                                         break;
    4755             :                                 }
    4756           0 :                                 pdu->bhs_valid_bytes += rc;
    4757           0 :                                 if (pdu->bhs_valid_bytes < ISCSI_BHS_LEN) {
    4758           0 :                                         return 0;
    4759             :                                 }
    4760             :                         }
    4761             : 
    4762             :                         /* conn->is_logged_out must be checked after completing to process
    4763             :                          * logout request, i.e., before processing PDU header in this state
    4764             :                          * machine, otherwise logout response may not be sent to initiator
    4765             :                          * and initiator may get logout timeout.
    4766             :                          */
    4767           0 :                         if (spdk_unlikely(conn->is_logged_out)) {
    4768           0 :                                 SPDK_DEBUGLOG(iscsi, "pdu received after logout\n");
    4769           0 :                                 conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
    4770           0 :                                 break;
    4771             :                         }
    4772             : 
    4773           0 :                         pdu->data_segment_len = ISCSI_ALIGN(DGET24(pdu->bhs.data_segment_len));
    4774           0 :                         pdu->data_buf_len = pdu->data_segment_len;
    4775             : 
    4776             :                         /* AHS */
    4777           0 :                         ahs_len = pdu->bhs.total_ahs_len * 4;
    4778           0 :                         if (ahs_len > ISCSI_AHS_LEN) {
    4779           0 :                                 SPDK_DEBUGLOG(iscsi, "pdu ahs length %d is invalid\n", ahs_len);
    4780           0 :                                 conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
    4781           0 :                                 break;
    4782             :                         }
    4783             : 
    4784           0 :                         if (pdu->ahs_valid_bytes < ahs_len) {
    4785           0 :                                 rc = iscsi_conn_read_data(conn,
    4786           0 :                                                           ahs_len - pdu->ahs_valid_bytes,
    4787           0 :                                                           pdu->ahs + pdu->ahs_valid_bytes);
    4788           0 :                                 if (rc < 0) {
    4789           0 :                                         conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
    4790           0 :                                         break;
    4791             :                                 }
    4792             : 
    4793           0 :                                 pdu->ahs_valid_bytes += rc;
    4794           0 :                                 if (pdu->ahs_valid_bytes < ahs_len) {
    4795           0 :                                         return 0;
    4796             :                                 }
    4797             :                         }
    4798             : 
    4799             :                         /* Header Digest */
    4800           0 :                         if (conn->header_digest &&
    4801           0 :                             pdu->hdigest_valid_bytes < ISCSI_DIGEST_LEN) {
    4802           0 :                                 rc = iscsi_conn_read_data(conn,
    4803           0 :                                                           ISCSI_DIGEST_LEN - pdu->hdigest_valid_bytes,
    4804           0 :                                                           pdu->header_digest + pdu->hdigest_valid_bytes);
    4805           0 :                                 if (rc < 0) {
    4806           0 :                                         conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
    4807           0 :                                         break;
    4808             :                                 }
    4809             : 
    4810           0 :                                 pdu->hdigest_valid_bytes += rc;
    4811           0 :                                 if (pdu->hdigest_valid_bytes < ISCSI_DIGEST_LEN) {
    4812           0 :                                         return 0;
    4813             :                                 }
    4814             :                         }
    4815             : 
    4816           0 :                         if (conn->header_digest) {
    4817           0 :                                 crc32c = iscsi_pdu_calc_header_digest(pdu);
    4818           0 :                                 rc = MATCH_DIGEST_WORD(pdu->header_digest, crc32c);
    4819           0 :                                 if (rc == 0) {
    4820           0 :                                         SPDK_ERRLOG("header digest error (%s)\n", conn->initiator_name);
    4821           0 :                                         conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
    4822           0 :                                         break;
    4823             :                                 }
    4824             :                         }
    4825             : 
    4826           0 :                         rc = iscsi_pdu_hdr_handle(conn, pdu);
    4827           0 :                         if (rc < 0) {
    4828           0 :                                 SPDK_ERRLOG("Critical error is detected. Close the connection\n");
    4829           0 :                                 conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
    4830           0 :                                 break;
    4831             :                         }
    4832             : 
    4833           0 :                         conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD;
    4834           0 :                         break;
    4835           0 :                 case ISCSI_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD:
    4836           0 :                         if (pdu->data_segment_len != 0) {
    4837           0 :                                 rc = iscsi_pdu_payload_read(conn, pdu);
    4838           0 :                                 if (rc > 0) {
    4839           0 :                                         return 0;
    4840           0 :                                 } else if (rc < 0) {
    4841           0 :                                         conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
    4842           0 :                                         break;
    4843             :                                 }
    4844             :                         }
    4845             : 
    4846             :                         /* All data for this PDU has now been read from the socket. */
    4847           0 :                         spdk_trace_record(TRACE_ISCSI_READ_PDU, conn->trace_id, pdu->data_valid_bytes,
    4848             :                                           (uintptr_t)pdu, pdu->bhs.opcode);
    4849             : 
    4850           0 :                         if (!pdu->is_rejected) {
    4851           0 :                                 rc = iscsi_pdu_payload_handle(conn, pdu);
    4852             :                         } else {
    4853           0 :                                 rc = 0;
    4854             :                         }
    4855           0 :                         if (rc == 0) {
    4856           0 :                                 spdk_trace_record(TRACE_ISCSI_TASK_EXECUTED, conn->trace_id, 0, (uintptr_t)pdu);
    4857           0 :                                 iscsi_put_pdu(pdu);
    4858           0 :                                 conn->pdu_in_progress = NULL;
    4859           0 :                                 conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY;
    4860           0 :                                 return 1;
    4861             :                         } else {
    4862           0 :                                 conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
    4863             :                         }
    4864           0 :                         break;
    4865           0 :                 case ISCSI_PDU_RECV_STATE_ERROR:
    4866           0 :                         return SPDK_ISCSI_CONNECTION_FATAL;
    4867           0 :                 default:
    4868           0 :                         assert(false);
    4869             :                         SPDK_ERRLOG("code should not come here\n");
    4870             :                         break;
    4871             :                 }
    4872           0 :         } while (prev_state != conn->pdu_recv_state);
    4873             : 
    4874           0 :         return 0;
    4875             : }
    4876             : 
    4877             : #define GET_PDU_LOOP_COUNT      16
    4878             : 
    4879             : int
    4880           0 : iscsi_handle_incoming_pdus(struct spdk_iscsi_conn *conn)
    4881             : {
    4882             :         int i, rc;
    4883             : 
    4884             :         /* Read new PDUs from network */
    4885           0 :         for (i = 0; i < GET_PDU_LOOP_COUNT; i++) {
    4886           0 :                 rc = iscsi_read_pdu(conn);
    4887           0 :                 if (rc == 0) {
    4888           0 :                         break;
    4889           0 :                 } else if (rc < 0) {
    4890           0 :                         return rc;
    4891             :                 }
    4892             : 
    4893           0 :                 if (conn->is_stopped) {
    4894           0 :                         break;
    4895             :                 }
    4896             :         }
    4897             : 
    4898           0 :         return i;
    4899             : }

Generated by: LCOV version 1.15