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

Generated by: LCOV version 1.15