LCOV - code coverage report
Current view: top level - spdk/lib/iscsi - conn.c (source / functions) Hit Total Coverage
Test: Combined Lines: 596 903 66.0 %
Date: 2024-11-21 04:06:59 Functions: 56 66 84.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 366 3833 9.5 %

           Branch data     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/endian.h"
      10                 :            : #include "spdk/env.h"
      11                 :            : #include "spdk/likely.h"
      12                 :            : #include "spdk/thread.h"
      13                 :            : #include "spdk/queue.h"
      14                 :            : #include "spdk/trace.h"
      15                 :            : #include "spdk/sock.h"
      16                 :            : #include "spdk/string.h"
      17                 :            : 
      18                 :            : #include "spdk/log.h"
      19                 :            : 
      20                 :            : #include "iscsi/task.h"
      21                 :            : #include "iscsi/conn.h"
      22                 :            : #include "iscsi/tgt_node.h"
      23                 :            : #include "iscsi/portal_grp.h"
      24                 :            : 
      25                 :            : #define MAKE_DIGEST_WORD(BUF, CRC32C) \
      26                 :            :         (   ((*((uint8_t *)(BUF)+0)) = (uint8_t)((uint32_t)(CRC32C) >> 0)), \
      27                 :            :             ((*((uint8_t *)(BUF)+1)) = (uint8_t)((uint32_t)(CRC32C) >> 8)), \
      28                 :            :             ((*((uint8_t *)(BUF)+2)) = (uint8_t)((uint32_t)(CRC32C) >> 16)), \
      29                 :            :             ((*((uint8_t *)(BUF)+3)) = (uint8_t)((uint32_t)(CRC32C) >> 24)))
      30                 :            : 
      31                 :            : #define SPDK_ISCSI_CONNECTION_MEMSET(conn)              \
      32                 :            :         memset(&(conn)->portal, 0, sizeof(*(conn)) -     \
      33                 :            :                 offsetof(struct spdk_iscsi_conn, portal));
      34                 :            : 
      35                 :            : #define SPDK_ISCSI_CONNECTION_STATUS(status, rnstr) case(status): return(rnstr)
      36                 :            : 
      37                 :            : static struct spdk_iscsi_conn *g_conns_array = NULL;
      38                 :            : 
      39                 :            : static TAILQ_HEAD(, spdk_iscsi_conn) g_free_conns = TAILQ_HEAD_INITIALIZER(g_free_conns);
      40                 :            : static TAILQ_HEAD(, spdk_iscsi_conn) g_active_conns = TAILQ_HEAD_INITIALIZER(g_active_conns);
      41                 :            : 
      42                 :            : static pthread_mutex_t g_conns_mutex = PTHREAD_MUTEX_INITIALIZER;
      43                 :            : 
      44                 :            : static struct spdk_poller *g_shutdown_timer = NULL;
      45                 :            : 
      46                 :            : static void iscsi_conn_sock_cb(void *arg, struct spdk_sock_group *group,
      47                 :            :                                struct spdk_sock *sock);
      48                 :            : 
      49                 :            : static struct spdk_iscsi_conn *
      50                 :        565 : allocate_conn(void)
      51                 :            : {
      52                 :            :         struct spdk_iscsi_conn  *conn;
      53                 :            : 
      54         [ -  + ]:        565 :         pthread_mutex_lock(&g_conns_mutex);
      55                 :        565 :         conn = TAILQ_FIRST(&g_free_conns);
      56         [ +  - ]:        565 :         if (conn != NULL) {
      57   [ -  +  #  #  :        565 :                 assert(!conn->is_valid);
             #  #  #  # ]
      58   [ +  -  #  #  :        565 :                 TAILQ_REMOVE(&g_free_conns, conn, conn_link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
      59   [ -  +  #  # ]:        565 :                 SPDK_ISCSI_CONNECTION_MEMSET(conn);
      60   [ #  #  #  # ]:        565 :                 conn->is_valid = 1;
      61                 :            : 
      62   [ #  #  #  #  :        565 :                 TAILQ_INSERT_TAIL(&g_active_conns, conn, conn_link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
      63                 :          0 :         }
      64         [ -  + ]:        565 :         pthread_mutex_unlock(&g_conns_mutex);
      65                 :            : 
      66                 :        565 :         return conn;
      67                 :            : }
      68                 :            : 
      69                 :            : static void
      70                 :        565 : _free_conn(struct spdk_iscsi_conn *conn)
      71                 :            : {
      72   [ +  +  #  #  :        565 :         TAILQ_REMOVE(&g_active_conns, conn, conn_link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
      73                 :            : 
      74   [ -  +  #  # ]:        565 :         memset(conn->portal_host, 0, sizeof(conn->portal_host));
      75   [ -  +  #  # ]:        565 :         memset(conn->portal_port, 0, sizeof(conn->portal_port));
      76   [ #  #  #  # ]:        565 :         conn->is_valid = 0;
      77                 :            : 
      78   [ #  #  #  #  :        565 :         TAILQ_INSERT_TAIL(&g_free_conns, conn, conn_link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
      79                 :        565 : }
      80                 :            : 
      81                 :            : static void
      82                 :          0 : free_conn(struct spdk_iscsi_conn *conn)
      83                 :            : {
      84         [ #  # ]:          0 :         pthread_mutex_lock(&g_conns_mutex);
      85                 :          0 :         _free_conn(conn);
      86         [ #  # ]:          0 :         pthread_mutex_unlock(&g_conns_mutex);
      87                 :          0 : }
      88                 :            : 
      89                 :            : static void
      90                 :        548 : _iscsi_conns_cleanup(void)
      91                 :            : {
      92                 :        548 :         free(g_conns_array);
      93                 :        548 : }
      94                 :            : 
      95                 :            : int
      96                 :        548 : initialize_iscsi_conns(void)
      97                 :            : {
      98                 :            :         uint32_t i;
      99                 :            : 
     100   [ +  +  +  +  :        548 :         SPDK_DEBUGLOG(iscsi, "spdk_iscsi_init\n");
                   +  - ]
     101                 :            : 
     102                 :        548 :         g_conns_array = calloc(MAX_ISCSI_CONNECTIONS, sizeof(struct spdk_iscsi_conn));
     103         [ +  + ]:        548 :         if (g_conns_array == NULL) {
     104                 :          0 :                 return -ENOMEM;
     105                 :            :         }
     106                 :            : 
     107         [ +  + ]:     561700 :         for (i = 0; i < MAX_ISCSI_CONNECTIONS; i++) {
     108   [ +  -  +  -  :     561152 :                 g_conns_array[i].id = i;
                   +  - ]
     109   [ +  -  +  -  :     561152 :                 TAILQ_INSERT_TAIL(&g_free_conns, &g_conns_array[i], conn_link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
     110                 :      19456 :         }
     111                 :            : 
     112                 :        548 :         return 0;
     113                 :         19 : }
     114                 :            : 
     115                 :            : static void
     116                 :       1043 : iscsi_poll_group_add_conn(struct spdk_iscsi_poll_group *pg, struct spdk_iscsi_conn *conn)
     117                 :            : {
     118                 :            :         int rc;
     119                 :            : 
     120   [ #  #  #  #  :       1043 :         rc = spdk_sock_group_add_sock(pg->sock_group, conn->sock, iscsi_conn_sock_cb, conn);
             #  #  #  # ]
     121         [ -  + ]:       1043 :         if (rc < 0) {
     122   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("Failed to add sock=%p of conn=%p\n", conn->sock, conn);
     123                 :          0 :                 return;
     124                 :            :         }
     125                 :            : 
     126   [ #  #  #  # ]:       1043 :         conn->is_stopped = false;
     127   [ #  #  #  #  :       1043 :         STAILQ_INSERT_TAIL(&pg->connections, conn, pg_link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     128                 :          0 : }
     129                 :            : 
     130                 :            : static void
     131                 :       1043 : iscsi_poll_group_remove_conn(struct spdk_iscsi_poll_group *pg, struct spdk_iscsi_conn *conn)
     132                 :            : {
     133                 :            :         int rc;
     134                 :            : 
     135   [ -  +  #  #  :       1043 :         assert(conn->sock != NULL);
             #  #  #  # ]
     136   [ #  #  #  #  :       1043 :         rc = spdk_sock_group_remove_sock(pg->sock_group, conn->sock);
             #  #  #  # ]
     137         [ -  + ]:       1043 :         if (rc < 0) {
     138   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("Failed to remove sock=%p of conn=%p\n", conn->sock, conn);
     139                 :          0 :         }
     140                 :            : 
     141   [ #  #  #  # ]:       1043 :         conn->is_stopped = true;
     142   [ +  +  +  +  :       2028 :         STAILQ_REMOVE(&pg->connections, conn, spdk_iscsi_conn, pg_link);
          +  +  +  +  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     143                 :       1043 : }
     144                 :            : 
     145                 :            : static int
     146                 :          0 : login_timeout(void *arg)
     147                 :            : {
     148                 :          0 :         struct spdk_iscsi_conn *conn = arg;
     149                 :            : 
     150   [ #  #  #  #  :          0 :         if (conn->state < ISCSI_CONN_STATE_EXITING) {
                   #  # ]
     151   [ #  #  #  # ]:          0 :                 conn->state = ISCSI_CONN_STATE_EXITING;
     152                 :          0 :         }
     153         [ #  # ]:          0 :         spdk_poller_unregister(&conn->login_timer);
     154                 :            : 
     155                 :          0 :         return SPDK_POLLER_BUSY;
     156                 :            : }
     157                 :            : 
     158                 :            : static void
     159                 :        565 : iscsi_conn_start(void *ctx)
     160                 :            : {
     161                 :        565 :         struct spdk_iscsi_conn *conn = ctx;
     162                 :            : 
     163   [ #  #  #  # ]:        565 :         iscsi_poll_group_add_conn(conn->pg, conn);
     164                 :            : 
     165   [ #  #  #  # ]:        565 :         conn->login_timer = SPDK_POLLER_REGISTER(login_timeout, conn, ISCSI_LOGIN_TIMEOUT * 1000000);
     166                 :        565 : }
     167                 :            : 
     168                 :            : int
     169                 :        565 : iscsi_conn_construct(struct spdk_iscsi_portal *portal,
     170                 :            :                      struct spdk_sock *sock)
     171                 :            : {
     172                 :            :         struct spdk_iscsi_poll_group *pg;
     173                 :            :         struct spdk_iscsi_conn *conn;
     174                 :            :         int i, rc;
     175                 :            : 
     176                 :        565 :         conn = allocate_conn();
     177         [ -  + ]:        565 :         if (conn == NULL) {
     178                 :          0 :                 SPDK_ERRLOG("Could not allocate connection.\n");
     179                 :          0 :                 return -1;
     180                 :            :         }
     181                 :            : 
     182         [ -  + ]:        565 :         pthread_mutex_lock(&g_iscsi.mutex);
     183   [ #  #  #  #  :        565 :         conn->timeout = g_iscsi.timeout * spdk_get_ticks_hz(); /* seconds to TSC */
                   #  # ]
     184   [ #  #  #  #  :        565 :         conn->nopininterval = g_iscsi.nopininterval;
                   #  # ]
     185   [ #  #  #  # ]:        565 :         conn->nopininterval *= spdk_get_ticks_hz(); /* seconds to TSC */
     186   [ #  #  #  # ]:        565 :         conn->last_nopin = spdk_get_ticks();
     187   [ #  #  #  # ]:        565 :         conn->nop_outstanding = false;
     188   [ #  #  #  # ]:        565 :         conn->data_out_cnt = 0;
     189   [ #  #  #  # ]:        565 :         conn->data_in_cnt = 0;
     190   [ -  +  #  #  :        565 :         conn->disable_chap = portal->group->disable_chap;
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     191   [ -  +  #  #  :        565 :         conn->require_chap = portal->group->require_chap;
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     192   [ -  +  #  #  :        565 :         conn->mutual_chap = portal->group->mutual_chap;
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     193   [ #  #  #  #  :        565 :         conn->chap_group = portal->group->chap_group;
          #  #  #  #  #  
                #  #  # ]
     194         [ -  + ]:        565 :         pthread_mutex_unlock(&g_iscsi.mutex);
     195   [ #  #  #  # ]:        565 :         conn->MaxRecvDataSegmentLength = 8192; /* RFC3720(12.12) */
     196                 :            : 
     197   [ #  #  #  # ]:        565 :         conn->portal = portal;
     198   [ #  #  #  #  :        565 :         conn->pg_tag = portal->group->tag;
          #  #  #  #  #  
                #  #  # ]
     199   [ -  +  -  +  :        565 :         memcpy(conn->portal_host, portal->host, strlen(portal->host));
          -  +  #  #  #  
                #  #  # ]
     200   [ -  +  -  +  :        565 :         memcpy(conn->portal_port, portal->port, strlen(portal->port));
          -  +  #  #  #  
                #  #  # ]
     201   [ #  #  #  # ]:        565 :         conn->sock = sock;
     202                 :            : 
     203   [ #  #  #  # ]:        565 :         conn->state = ISCSI_CONN_STATE_INVALID;
     204   [ #  #  #  # ]:        565 :         conn->login_phase = ISCSI_SECURITY_NEGOTIATION_PHASE;
     205   [ #  #  #  # ]:        565 :         conn->ttt = 0;
     206                 :            : 
     207   [ #  #  #  # ]:        565 :         conn->partial_text_parameter = NULL;
     208                 :            : 
     209   [ +  +  #  # ]:       8475 :         for (i = 0; i < MAX_CONNECTION_PARAMS; i++) {
     210   [ #  #  #  #  :       7910 :                 conn->conn_param_state_negotiated[i] = false;
             #  #  #  # ]
     211                 :          0 :         }
     212                 :            : 
     213   [ +  +  #  # ]:      11300 :         for (i = 0; i < MAX_SESSION_PARAMS; i++) {
     214   [ #  #  #  #  :      10735 :                 conn->sess_param_state_negotiated[i] = false;
             #  #  #  # ]
     215                 :          0 :         }
     216                 :            : 
     217   [ #  #  #  # ]:        565 :         conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY;
     218                 :            : 
     219   [ #  #  #  #  :        565 :         TAILQ_INIT(&conn->write_pdu_list);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     220   [ #  #  #  #  :        565 :         TAILQ_INIT(&conn->snack_pdu_list);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     221   [ #  #  #  #  :        565 :         TAILQ_INIT(&conn->queued_r2t_tasks);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     222   [ #  #  #  #  :        565 :         TAILQ_INIT(&conn->active_r2t_tasks);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     223   [ #  #  #  #  :        565 :         TAILQ_INIT(&conn->queued_datain_tasks);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     224   [ #  #  #  #  :        565 :         TAILQ_INIT(&conn->luns);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     225                 :            : 
     226         [ #  # ]:        565 :         rc = spdk_sock_getaddr(sock, conn->target_addr, sizeof conn->target_addr, NULL,
     227         [ #  # ]:        565 :                                conn->initiator_addr, sizeof conn->initiator_addr, NULL);
     228         [ -  + ]:        565 :         if (rc < 0) {
     229                 :          0 :                 SPDK_ERRLOG("spdk_sock_getaddr() failed\n");
     230                 :          0 :                 goto error_return;
     231                 :            :         }
     232                 :            : 
     233                 :            :         /* set low water mark */
     234   [ #  #  #  # ]:        565 :         rc = spdk_sock_set_recvlowat(conn->sock, 1);
     235         [ -  + ]:        565 :         if (rc != 0) {
     236                 :          0 :                 SPDK_ERRLOG("spdk_sock_set_recvlowat() failed\n");
     237                 :          0 :                 goto error_return;
     238                 :            :         }
     239                 :            : 
     240                 :            :         /* set default params */
     241         [ #  # ]:        565 :         rc = iscsi_conn_params_init(&conn->params);
     242         [ -  + ]:        565 :         if (rc < 0) {
     243                 :          0 :                 SPDK_ERRLOG("iscsi_conn_params_init() failed\n");
     244                 :          0 :                 goto error_return;
     245                 :            :         }
     246   [ #  #  #  # ]:        565 :         conn->logout_request_timer = NULL;
     247   [ #  #  #  # ]:        565 :         conn->logout_timer = NULL;
     248   [ #  #  #  # ]:        565 :         conn->shutdown_timer = NULL;
     249   [ -  +  -  +  :        565 :         SPDK_DEBUGLOG(iscsi, "Launching connection on acceptor thread\n");
                   #  # ]
     250   [ #  #  #  # ]:        565 :         conn->pending_task_cnt = 0;
     251                 :            : 
     252                 :            :         /* Get the first poll group. */
     253   [ #  #  #  # ]:        565 :         pg = TAILQ_FIRST(&g_iscsi.poll_group_head);
     254         [ -  + ]:        565 :         if (pg == NULL) {
     255                 :          0 :                 SPDK_ERRLOG("There is no poll group.\n");
     256         [ #  # ]:          0 :                 assert(false);
     257                 :            :                 goto error_return;
     258                 :            :         }
     259                 :            : 
     260   [ #  #  #  # ]:        565 :         conn->pg = pg;
     261                 :        565 :         spdk_thread_send_msg(spdk_io_channel_get_thread(spdk_io_channel_from_ctx(pg)),
     262                 :          0 :                              iscsi_conn_start, conn);
     263                 :        565 :         return 0;
     264                 :            : 
     265                 :          0 : error_return:
     266   [ #  #  #  # ]:          0 :         iscsi_param_free(conn->params);
     267                 :          0 :         free_conn(conn);
     268                 :          0 :         return -1;
     269                 :          0 : }
     270                 :            : 
     271                 :            : void
     272                 :   24206085 : iscsi_conn_free_pdu(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
     273                 :            : {
     274                 :            :         iscsi_conn_xfer_complete_cb cb_fn;
     275                 :            :         void *cb_arg;
     276                 :            : 
     277   [ #  #  #  # ]:   24206085 :         cb_fn = pdu->cb_fn;
     278   [ #  #  #  # ]:   24206085 :         cb_arg = pdu->cb_arg;
     279                 :            : 
     280   [ -  +  #  # ]:   24206085 :         assert(cb_fn != NULL);
     281   [ #  #  #  # ]:   24206085 :         pdu->cb_fn = NULL;
     282                 :            : 
     283   [ +  +  #  #  :   24206085 :         if (pdu->task) {
                   #  # ]
     284   [ #  #  #  # ]:   23783851 :                 iscsi_task_put(pdu->task);
     285                 :          0 :         }
     286                 :   24206085 :         iscsi_put_pdu(pdu);
     287                 :            : 
     288   [ #  #  #  # ]:   24206085 :         cb_fn(cb_arg);
     289                 :   24206085 : }
     290                 :            : 
     291                 :            : static int
     292                 :        577 : iscsi_conn_free_tasks(struct spdk_iscsi_conn *conn)
     293                 :            : {
     294                 :            :         struct spdk_iscsi_pdu *pdu, *tmp_pdu;
     295                 :            :         struct spdk_iscsi_task *iscsi_task, *tmp_iscsi_task;
     296                 :            : 
     297   [ +  +  #  #  :        804 :         TAILQ_FOREACH_SAFE(pdu, &conn->snack_pdu_list, tailq, tmp_pdu) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     298   [ +  +  #  #  :        227 :                 TAILQ_REMOVE(&conn->snack_pdu_list, pdu, tailq);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     299                 :        227 :                 iscsi_conn_free_pdu(conn, pdu);
     300                 :          0 :         }
     301                 :            : 
     302   [ +  +  #  #  :        595 :         TAILQ_FOREACH_SAFE(iscsi_task, &conn->queued_datain_tasks, link, tmp_iscsi_task) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     303   [ +  +  +  +  :         18 :                 if (!iscsi_task->is_queued) {
             #  #  #  # ]
     304   [ +  +  #  #  :         15 :                         TAILQ_REMOVE(&conn->queued_datain_tasks, iscsi_task, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     305                 :         15 :                         iscsi_task_put(iscsi_task);
     306                 :          0 :                 }
     307                 :          0 :         }
     308                 :            : 
     309                 :            :         /* We have to parse conn->write_pdu_list in the end.  In iscsi_conn_free_pdu(),
     310                 :            :          *  iscsi_conn_handle_queued_datain_tasks() may be called, and
     311                 :            :          *  iscsi_conn_handle_queued_datain_tasks() will parse conn->queued_datain_tasks
     312                 :            :          *  and may stack some PDUs to conn->write_pdu_list.  Hence when we come here, we
     313                 :            :          *  have to ensure there is no associated task in conn->queued_datain_tasks.
     314                 :            :          */
     315   [ +  +  #  #  :        598 :         TAILQ_FOREACH_SAFE(pdu, &conn->write_pdu_list, tailq, tmp_pdu) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     316   [ +  +  #  #  :         21 :                 TAILQ_REMOVE(&conn->write_pdu_list, pdu, tailq);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     317                 :         21 :                 iscsi_conn_free_pdu(conn, pdu);
     318                 :          0 :         }
     319                 :            : 
     320   [ -  +  #  #  :        577 :         if (conn->pending_task_cnt) {
                   #  # ]
     321                 :          0 :                 return -1;
     322                 :            :         }
     323                 :            : 
     324                 :        577 :         return 0;
     325                 :          0 : }
     326                 :            : 
     327                 :            : static void
     328                 :        148 : iscsi_conn_cleanup_backend(struct spdk_iscsi_conn *conn)
     329                 :            : {
     330                 :            :         int rc;
     331                 :            :         struct spdk_iscsi_tgt_node *target;
     332                 :            : 
     333   [ +  -  #  #  :        148 :         if (conn->sess->connections > 1) {
          #  #  #  #  #  
                      # ]
     334                 :            :                 /* connection specific cleanup */
     335   [ -  +  -  +  :        148 :         } else if (!g_iscsi.AllowDuplicateIsid) {
                   #  # ]
     336                 :            :                 /*
     337                 :            :                  * a> a target is connected by a single initiator, cleanup backend cancels inflight
     338                 :            :                  *    IOs and the resources (of this initiator) are reclaimed as soon as possible.
     339                 :            :                  * b> a target is connected by multiple initiators, one of these initiators
     340                 :            :                  *    disconnects with inflight IOs, resetting backend bdev leads all the inflight
     341                 :            :                  *    IOs (of multiple initiators) aborted. In this scenario, drain inflight IOs of
     342                 :            :                  *    the disconnected initiator instead.
     343                 :            :                  */
     344   [ #  #  #  #  :          0 :                 target = conn->sess->target;
             #  #  #  # ]
     345   [ #  #  #  # ]:          0 :                 if (target != NULL && iscsi_get_active_conns(target) == 1) {
     346                 :          0 :                         rc = iscsi_tgt_node_cleanup_luns(conn, target);
     347         [ #  # ]:          0 :                         if (rc < 0) {
     348                 :          0 :                                 SPDK_ERRLOG("target abort failed\n");
     349                 :          0 :                         }
     350                 :          0 :                 }
     351                 :          0 :         }
     352                 :        148 : }
     353                 :            : 
     354                 :            : static void
     355                 :        565 : iscsi_conn_free(struct spdk_iscsi_conn *conn)
     356                 :            : {
     357                 :            :         struct spdk_iscsi_sess *sess;
     358                 :            :         int idx;
     359                 :            :         uint32_t i;
     360                 :            : 
     361         [ -  + ]:        565 :         pthread_mutex_lock(&g_conns_mutex);
     362                 :            : 
     363   [ +  +  #  #  :        565 :         if (conn->sess == NULL) {
                   #  # ]
     364                 :         10 :                 goto end;
     365                 :            :         }
     366                 :            : 
     367                 :        555 :         idx = -1;
     368   [ #  #  #  # ]:        555 :         sess = conn->sess;
     369   [ #  #  #  # ]:        555 :         conn->sess = NULL;
     370                 :            : 
     371   [ +  -  #  #  :        555 :         for (i = 0; i < sess->connections; i++) {
                   #  # ]
     372   [ +  -  #  #  :        555 :                 if (sess->conns[i] == conn) {
          #  #  #  #  #  
                      # ]
     373                 :        555 :                         idx = i;
     374                 :        555 :                         break;
     375                 :            :                 }
     376                 :          0 :         }
     377                 :            : 
     378         [ -  + ]:        555 :         if (idx < 0) {
     379                 :          0 :                 SPDK_ERRLOG("remove conn not found\n");
     380                 :          0 :         } else {
     381   [ -  +  #  #  :        555 :                 for (i = idx; i < sess->connections - 1; i++) {
                   #  # ]
     382   [ #  #  #  #  :          0 :                         sess->conns[i] = sess->conns[i + 1];
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     383                 :          0 :                 }
     384   [ #  #  #  #  :        555 :                 sess->conns[sess->connections - 1] = NULL;
          #  #  #  #  #  
                #  #  # ]
     385         [ #  # ]:        555 :                 sess->connections--;
     386                 :            : 
     387   [ +  -  #  #  :        555 :                 if (sess->connections == 0) {
                   #  # ]
     388                 :            :                         /* cleanup last connection */
     389   [ -  +  -  +  :        555 :                         SPDK_DEBUGLOG(iscsi,
                   #  # ]
     390                 :            :                                       "cleanup last conn free sess\n");
     391                 :        555 :                         iscsi_free_sess(sess);
     392                 :          0 :                 }
     393                 :            :         }
     394                 :            : 
     395   [ -  +  +  -  :        555 :         SPDK_DEBUGLOG(iscsi, "Terminating connections(tsih %d): %d\n",
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     396                 :            :                       sess->tsih, sess->connections);
     397                 :            : 
     398                 :        555 : end:
     399   [ -  +  -  +  :        565 :         SPDK_DEBUGLOG(iscsi, "cleanup free conn\n");
                   #  # ]
     400   [ #  #  #  # ]:        565 :         iscsi_param_free(conn->params);
     401                 :        565 :         _free_conn(conn);
     402                 :            : 
     403         [ -  + ]:        565 :         pthread_mutex_unlock(&g_conns_mutex);
     404                 :        565 : }
     405                 :            : 
     406                 :            : static void
     407                 :        660 : iscsi_conn_close_lun(struct spdk_iscsi_conn *conn,
     408                 :            :                      struct spdk_iscsi_lun *iscsi_lun)
     409                 :            : {
     410         [ -  + ]:        660 :         if (iscsi_lun == NULL) {
     411                 :          0 :                 return;
     412                 :            :         }
     413                 :            : 
     414   [ #  #  #  # ]:        660 :         spdk_scsi_lun_free_io_channel(iscsi_lun->desc);
     415   [ #  #  #  # ]:        660 :         spdk_scsi_lun_close(iscsi_lun->desc);
     416         [ #  # ]:        660 :         spdk_poller_unregister(&iscsi_lun->remove_poller);
     417                 :            : 
     418   [ +  +  #  #  :        660 :         TAILQ_REMOVE(&conn->luns, iscsi_lun, tailq);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     419                 :            : 
     420                 :        660 :         free(iscsi_lun);
     421                 :            : 
     422                 :          0 : }
     423                 :            : 
     424                 :            : static void
     425                 :        478 : iscsi_conn_close_luns(struct spdk_iscsi_conn *conn)
     426                 :            : {
     427                 :            :         struct spdk_iscsi_lun *iscsi_lun, *tmp;
     428                 :            : 
     429   [ +  +  #  #  :       1132 :         TAILQ_FOREACH_SAFE(iscsi_lun, &conn->luns, tailq, tmp) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     430                 :        654 :                 iscsi_conn_close_lun(conn, iscsi_lun);
     431                 :          0 :         }
     432                 :        478 : }
     433                 :            : 
     434                 :            : static bool
     435                 :          9 : iscsi_conn_check_tasks_for_lun(struct spdk_iscsi_conn *conn,
     436                 :            :                                struct spdk_scsi_lun *lun)
     437                 :            : {
     438                 :            :         struct spdk_iscsi_pdu *pdu, *tmp_pdu;
     439                 :            :         struct spdk_iscsi_task *task;
     440                 :            : 
     441   [ -  +  #  # ]:          9 :         assert(lun != NULL);
     442                 :            : 
     443                 :            :         /* We can remove deferred PDUs safely because they are already flushed. */
     444   [ -  +  #  #  :          9 :         TAILQ_FOREACH_SAFE(pdu, &conn->snack_pdu_list, tailq, tmp_pdu) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     445   [ #  #  #  #  :          0 :                 if (lun == pdu->task->scsi.lun) {
          #  #  #  #  #  
                #  #  # ]
     446   [ #  #  #  #  :          0 :                         TAILQ_REMOVE(&conn->snack_pdu_list, pdu, tailq);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     447                 :          0 :                         iscsi_conn_free_pdu(conn, pdu);
     448                 :          0 :                 }
     449                 :          0 :         }
     450                 :            : 
     451   [ -  +  #  #  :          9 :         TAILQ_FOREACH(task, &conn->queued_datain_tasks, link) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     452   [ #  #  #  #  :          0 :                 if (lun == task->scsi.lun) {
             #  #  #  # ]
     453                 :          0 :                         return false;
     454                 :            :                 }
     455                 :          0 :         }
     456                 :            : 
     457                 :            :         /* This check loop works even when connection exits in the middle of LUN hotplug
     458                 :            :          *  because all PDUs in write_pdu_list are removed in iscsi_conn_free_tasks().
     459                 :            :          */
     460   [ +  +  #  #  :         20 :         TAILQ_FOREACH(pdu, &conn->write_pdu_list, tailq) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     461   [ +  +  +  +  :         14 :                 if (pdu->task && lun == pdu->task->scsi.lun) {
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     462                 :          3 :                         return false;
     463                 :            :                 }
     464                 :          0 :         }
     465                 :            : 
     466                 :          6 :         return true;
     467                 :          0 : }
     468                 :            : 
     469                 :            : static int
     470                 :          9 : iscsi_conn_remove_lun(void *ctx)
     471                 :            : {
     472                 :          9 :         struct spdk_iscsi_lun *iscsi_lun = ctx;
     473   [ #  #  #  # ]:          9 :         struct spdk_iscsi_conn *conn = iscsi_lun->conn;
     474   [ #  #  #  # ]:          9 :         struct spdk_scsi_lun *lun = iscsi_lun->lun;
     475                 :            : 
     476         [ +  + ]:          9 :         if (!iscsi_conn_check_tasks_for_lun(conn, lun)) {
     477                 :          3 :                 return SPDK_POLLER_BUSY;
     478                 :            :         }
     479                 :          6 :         iscsi_conn_close_lun(conn, iscsi_lun);
     480                 :          6 :         return SPDK_POLLER_BUSY;
     481                 :          0 : }
     482                 :            : 
     483                 :            : static void
     484                 :          6 : _iscsi_conn_hotremove_lun(void *ctx)
     485                 :            : {
     486                 :          6 :         struct spdk_iscsi_lun *iscsi_lun = ctx;
     487   [ #  #  #  # ]:          6 :         struct spdk_iscsi_conn *conn = iscsi_lun->conn;
     488   [ #  #  #  # ]:          6 :         struct spdk_scsi_lun *lun = iscsi_lun->lun;
     489                 :            : 
     490   [ -  +  #  #  :          6 :         assert(spdk_io_channel_get_thread(spdk_io_channel_from_ctx(conn->pg)) ==
             #  #  #  # ]
     491                 :            :                spdk_get_thread());
     492                 :            : 
     493                 :            :         /* If a connection is already in stating status, just return */
     494   [ -  +  #  #  :          6 :         if (conn->state >= ISCSI_CONN_STATE_EXITING) {
                   #  # ]
     495                 :          0 :                 return;
     496                 :            :         }
     497                 :            : 
     498                 :          6 :         iscsi_clear_all_transfer_task(conn, lun, NULL);
     499                 :            : 
     500   [ #  #  #  # ]:          6 :         iscsi_lun->remove_poller = SPDK_POLLER_REGISTER(iscsi_conn_remove_lun, iscsi_lun,
     501                 :            :                                    1000);
     502                 :          0 : }
     503                 :            : 
     504                 :            : static void
     505                 :          6 : iscsi_conn_hotremove_lun(struct spdk_scsi_lun *lun, void *remove_ctx)
     506                 :            : {
     507                 :          6 :         struct spdk_iscsi_lun *iscsi_lun = remove_ctx;
     508   [ #  #  #  # ]:          6 :         struct spdk_iscsi_conn *conn = iscsi_lun->conn;
     509                 :            : 
     510   [ #  #  #  # ]:          6 :         spdk_thread_send_msg(spdk_io_channel_get_thread(spdk_io_channel_from_ctx(conn->pg)),
     511                 :          0 :                              _iscsi_conn_hotremove_lun, iscsi_lun);
     512                 :          6 : }
     513                 :            : 
     514                 :            : static int
     515                 :        660 : iscsi_conn_open_lun(struct spdk_iscsi_conn *conn, struct spdk_scsi_lun *lun)
     516                 :            : {
     517                 :            :         int rc;
     518                 :            :         struct spdk_iscsi_lun *iscsi_lun;
     519                 :            : 
     520                 :        660 :         iscsi_lun = calloc(1, sizeof(*iscsi_lun));
     521         [ -  + ]:        660 :         if (iscsi_lun == NULL) {
     522                 :          0 :                 return -ENOMEM;
     523                 :            :         }
     524                 :            : 
     525   [ #  #  #  # ]:        660 :         iscsi_lun->conn = conn;
     526   [ #  #  #  # ]:        660 :         iscsi_lun->lun = lun;
     527                 :            : 
     528         [ #  # ]:        660 :         rc = spdk_scsi_lun_open(lun, iscsi_conn_hotremove_lun, iscsi_lun, &iscsi_lun->desc);
     529         [ -  + ]:        660 :         if (rc != 0) {
     530                 :          0 :                 free(iscsi_lun);
     531                 :          0 :                 return rc;
     532                 :            :         }
     533                 :            : 
     534   [ #  #  #  # ]:        660 :         rc = spdk_scsi_lun_allocate_io_channel(iscsi_lun->desc);
     535         [ -  + ]:        660 :         if (rc != 0) {
     536   [ #  #  #  # ]:          0 :                 spdk_scsi_lun_close(iscsi_lun->desc);
     537                 :          0 :                 free(iscsi_lun);
     538                 :          0 :                 return rc;
     539                 :            :         }
     540                 :            : 
     541   [ #  #  #  #  :        660 :         TAILQ_INSERT_TAIL(&conn->luns, iscsi_lun, tailq);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     542                 :            : 
     543                 :        660 :         return 0;
     544                 :          0 : }
     545                 :            : 
     546                 :            : static int
     547                 :        478 : iscsi_conn_open_luns(struct spdk_iscsi_conn *conn)
     548                 :            : {
     549                 :            :         int rc;
     550                 :            :         struct spdk_scsi_lun *lun;
     551                 :            : 
     552   [ +  +  #  #  :       1138 :         for (lun = spdk_scsi_dev_get_first_lun(conn->dev); lun != NULL;
                   #  # ]
     553                 :        660 :              lun = spdk_scsi_dev_get_next_lun(lun)) {
     554                 :        660 :                 rc = iscsi_conn_open_lun(conn, lun);
     555         [ -  + ]:        660 :                 if (rc != 0) {
     556                 :          0 :                         goto error;
     557                 :            :                 }
     558                 :          0 :         }
     559                 :            : 
     560                 :        478 :         return 0;
     561                 :            : 
     562                 :          0 : error:
     563                 :          0 :         iscsi_conn_close_luns(conn);
     564                 :          0 :         return -1;
     565                 :          0 : }
     566                 :            : 
     567                 :            : /**
     568                 :            :  *  This function will stop executing the specified connection.
     569                 :            :  */
     570                 :            : static void
     571                 :        565 : iscsi_conn_stop(struct spdk_iscsi_conn *conn)
     572                 :            : {
     573                 :            :         struct spdk_iscsi_tgt_node *target;
     574                 :            : 
     575   [ -  +  #  #  :        565 :         assert(conn->state == ISCSI_CONN_STATE_EXITED);
             #  #  #  # ]
     576   [ -  +  #  #  :        565 :         assert(conn->data_in_cnt == 0);
             #  #  #  # ]
     577   [ -  +  #  #  :        565 :         assert(conn->data_out_cnt == 0);
             #  #  #  # ]
     578                 :            : 
     579   [ +  +  #  #  :        565 :         if (conn->sess != NULL &&
             #  #  #  # ]
     580   [ +  +  #  #  :        555 :             conn->sess->session_type == SESSION_TYPE_NORMAL &&
          #  #  #  #  #  
                      # ]
     581   [ +  +  #  # ]:        524 :             conn->full_feature) {
     582   [ #  #  #  #  :        478 :                 target = conn->sess->target;
             #  #  #  # ]
     583   [ -  +  #  # ]:        478 :                 pthread_mutex_lock(&target->mutex);
     584         [ #  # ]:        478 :                 target->num_active_conns--;
     585   [ -  +  #  # ]:        478 :                 pthread_mutex_unlock(&target->mutex);
     586                 :            : 
     587                 :        478 :                 iscsi_conn_close_luns(conn);
     588                 :          0 :         }
     589                 :            : 
     590   [ -  +  #  #  :        565 :         assert(spdk_io_channel_get_thread(spdk_io_channel_from_ctx(conn->pg)) ==
             #  #  #  # ]
     591                 :            :                spdk_get_thread());
     592                 :        565 : }
     593                 :            : 
     594                 :            : static int
     595                 :          0 : _iscsi_conn_check_shutdown(void *arg)
     596                 :            : {
     597                 :          0 :         struct spdk_iscsi_conn *conn = arg;
     598                 :            :         int rc;
     599                 :            : 
     600                 :          0 :         rc = iscsi_conn_free_tasks(conn);
     601         [ #  # ]:          0 :         if (rc < 0) {
     602                 :          0 :                 return SPDK_POLLER_BUSY;
     603                 :            :         }
     604                 :            : 
     605         [ #  # ]:          0 :         spdk_poller_unregister(&conn->shutdown_timer);
     606                 :            : 
     607                 :          0 :         iscsi_conn_stop(conn);
     608                 :          0 :         iscsi_conn_free(conn);
     609                 :            : 
     610                 :          0 :         return SPDK_POLLER_BUSY;
     611                 :          0 : }
     612                 :            : 
     613                 :            : static void
     614                 :        565 : _iscsi_conn_destruct(struct spdk_iscsi_conn *conn)
     615                 :            : {
     616                 :            :         int rc;
     617                 :            : 
     618   [ #  #  #  # ]:        565 :         iscsi_poll_group_remove_conn(conn->pg, conn);
     619         [ #  # ]:        565 :         spdk_sock_close(&conn->sock);
     620                 :        565 :         iscsi_clear_all_transfer_task(conn, NULL, NULL);
     621         [ #  # ]:        565 :         spdk_poller_unregister(&conn->logout_request_timer);
     622         [ #  # ]:        565 :         spdk_poller_unregister(&conn->logout_timer);
     623         [ #  # ]:        565 :         spdk_poller_unregister(&conn->login_timer);
     624                 :            : 
     625                 :        565 :         rc = iscsi_conn_free_tasks(conn);
     626         [ -  + ]:        565 :         if (rc < 0) {
     627                 :            :                 /* The connection cannot be freed yet. Check back later. */
     628   [ #  #  #  # ]:          0 :                 conn->shutdown_timer = SPDK_POLLER_REGISTER(_iscsi_conn_check_shutdown, conn, 1000);
     629                 :          0 :         } else {
     630                 :        565 :                 iscsi_conn_stop(conn);
     631                 :        565 :                 iscsi_conn_free(conn);
     632                 :            :         }
     633                 :        565 : }
     634                 :            : 
     635                 :            : static int
     636                 :          0 : _iscsi_conn_check_pending_tasks(void *arg)
     637                 :            : {
     638                 :          0 :         struct spdk_iscsi_conn *conn = arg;
     639                 :            : 
     640   [ #  #  #  #  :          0 :         if (conn->dev != NULL &&
             #  #  #  # ]
     641   [ #  #  #  #  :          0 :             spdk_scsi_dev_has_pending_tasks(conn->dev, conn->initiator_port)) {
             #  #  #  # ]
     642                 :          0 :                 return SPDK_POLLER_BUSY;
     643                 :            :         }
     644                 :            : 
     645         [ #  # ]:          0 :         spdk_poller_unregister(&conn->shutdown_timer);
     646                 :            : 
     647                 :          0 :         _iscsi_conn_destruct(conn);
     648                 :            : 
     649                 :          0 :         return SPDK_POLLER_BUSY;
     650                 :          0 : }
     651                 :            : 
     652                 :            : void
     653                 :        565 : iscsi_conn_destruct(struct spdk_iscsi_conn *conn)
     654                 :            : {
     655                 :            :         struct spdk_iscsi_pdu *pdu;
     656                 :            :         struct spdk_iscsi_task *task;
     657                 :            :         int opcode;
     658                 :            : 
     659                 :            :         /* If a connection is already in exited status, just return */
     660   [ -  +  #  #  :        565 :         if (conn->state >= ISCSI_CONN_STATE_EXITED) {
                   #  # ]
     661                 :          0 :                 return;
     662                 :            :         }
     663                 :            : 
     664   [ #  #  #  # ]:        565 :         conn->state = ISCSI_CONN_STATE_EXITED;
     665                 :            : 
     666                 :            :         /*
     667                 :            :          * Each connection pre-allocates its next PDU - make sure these get
     668                 :            :          *  freed here.
     669                 :            :          */
     670   [ #  #  #  # ]:        565 :         pdu = conn->pdu_in_progress;
     671         [ +  - ]:        565 :         if (pdu) {
     672                 :            :                 /* remove the task left in the PDU too. */
     673   [ #  #  #  # ]:        565 :                 task = pdu->task;
     674         [ -  + ]:        565 :                 if (task) {
     675   [ #  #  #  # ]:          0 :                         opcode = pdu->bhs.opcode;
     676         [ #  # ]:          0 :                         switch (opcode) {
     677                 :          0 :                         case ISCSI_OP_SCSI:
     678                 :            :                         case ISCSI_OP_SCSI_DATAOUT:
     679         [ #  # ]:          0 :                                 spdk_scsi_task_process_abort(&task->scsi);
     680         [ #  # ]:          0 :                                 iscsi_task_cpl(&task->scsi);
     681                 :          0 :                                 break;
     682                 :          0 :                         default:
     683                 :          0 :                                 SPDK_ERRLOG("unexpected opcode %x\n", opcode);
     684                 :          0 :                                 iscsi_task_put(task);
     685                 :          0 :                                 break;
     686                 :            :                         }
     687                 :          0 :                 }
     688                 :        565 :                 iscsi_put_pdu(pdu);
     689   [ #  #  #  # ]:        565 :                 conn->pdu_in_progress = NULL;
     690                 :          0 :         }
     691                 :            : 
     692   [ +  +  +  +  :        565 :         if (conn->sess != NULL && conn->pending_task_cnt > 0) {
          #  #  #  #  #  
                #  #  # ]
     693                 :        148 :                 iscsi_conn_cleanup_backend(conn);
     694                 :          0 :         }
     695                 :            : 
     696   [ +  +  -  +  :       1089 :         if (conn->dev != NULL &&
             #  #  #  # ]
     697   [ #  #  #  #  :        524 :             spdk_scsi_dev_has_pending_tasks(conn->dev, conn->initiator_port)) {
             #  #  #  # ]
     698   [ #  #  #  # ]:          0 :                 conn->shutdown_timer = SPDK_POLLER_REGISTER(_iscsi_conn_check_pending_tasks, conn, 1000);
     699                 :          0 :         } else {
     700                 :        565 :                 _iscsi_conn_destruct(conn);
     701                 :            :         }
     702                 :          0 : }
     703                 :            : 
     704                 :            : int
     705                 :        707 : iscsi_get_active_conns(struct spdk_iscsi_tgt_node *target)
     706                 :            : {
     707                 :            :         struct spdk_iscsi_conn *conn;
     708                 :        707 :         int num = 0;
     709                 :            : 
     710         [ +  + ]:        707 :         if (g_conns_array == MAP_FAILED) {
     711                 :          0 :                 return 0;
     712                 :            :         }
     713                 :            : 
     714         [ +  + ]:        707 :         pthread_mutex_lock(&g_conns_mutex);
     715   [ +  +  #  #  :        708 :         TAILQ_FOREACH(conn, &g_active_conns, conn_link) {
             #  #  #  # ]
     716   [ -  +  -  -  :          1 :                 if (target == NULL || conn->target == target) {
             #  #  #  # ]
     717         [ #  # ]:          1 :                         num++;
     718                 :          0 :                 }
     719                 :          0 :         }
     720         [ +  + ]:        707 :         pthread_mutex_unlock(&g_conns_mutex);
     721                 :        707 :         return num;
     722                 :         19 : }
     723                 :            : 
     724                 :            : static void
     725                 :        548 : iscsi_conn_check_shutdown_cb(void *arg1)
     726                 :            : {
     727                 :        548 :         _iscsi_conns_cleanup();
     728                 :        548 :         shutdown_iscsi_conns_done();
     729                 :        548 : }
     730                 :            : 
     731                 :            : static int
     732                 :        549 : iscsi_conn_check_shutdown(void *arg)
     733                 :            : {
     734         [ +  + ]:        549 :         if (iscsi_get_active_conns(NULL) != 0) {
     735                 :          1 :                 return SPDK_POLLER_BUSY;
     736                 :            :         }
     737                 :            : 
     738                 :        548 :         spdk_poller_unregister(&g_shutdown_timer);
     739                 :            : 
     740                 :        548 :         spdk_thread_send_msg(spdk_get_thread(), iscsi_conn_check_shutdown_cb, NULL);
     741                 :            : 
     742                 :        548 :         return SPDK_POLLER_BUSY;
     743                 :         19 : }
     744                 :            : 
     745                 :            : static void
     746                 :          8 : iscsi_send_logout_request(struct spdk_iscsi_conn *conn)
     747                 :            : {
     748                 :            :         struct spdk_iscsi_pdu *rsp_pdu;
     749                 :            :         struct iscsi_bhs_async *rsph;
     750                 :            : 
     751                 :          8 :         rsp_pdu = iscsi_get_pdu(conn);
     752   [ -  +  #  # ]:          8 :         assert(rsp_pdu != NULL);
     753                 :            : 
     754         [ #  # ]:          8 :         rsph = (struct iscsi_bhs_async *)&rsp_pdu->bhs;
     755   [ #  #  #  # ]:          8 :         rsp_pdu->data = NULL;
     756                 :            : 
     757         [ #  # ]:          8 :         rsph->opcode = ISCSI_OP_ASYNC;
     758         [ #  # ]:          8 :         to_be32(&rsph->ffffffff, 0xFFFFFFFF);
     759   [ #  #  #  # ]:          8 :         rsph->async_event = 1;
     760         [ #  # ]:          8 :         to_be16(&rsph->param3, ISCSI_LOGOUT_REQUEST_TIMEOUT);
     761                 :            : 
     762   [ #  #  #  #  :          8 :         to_be32(&rsph->stat_sn, conn->StatSN);
                   #  # ]
     763         [ #  # ]:          8 :         conn->StatSN++;
     764   [ #  #  #  #  :          8 :         to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
          #  #  #  #  #  
                      # ]
     765   [ #  #  #  #  :          8 :         to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
          #  #  #  #  #  
                      # ]
     766                 :            : 
     767                 :          8 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
     768                 :          8 : }
     769                 :            : 
     770                 :            : static int
     771                 :          0 : logout_request_timeout(void *arg)
     772                 :            : {
     773                 :          0 :         struct spdk_iscsi_conn *conn = arg;
     774                 :            : 
     775   [ #  #  #  #  :          0 :         if (conn->state < ISCSI_CONN_STATE_EXITING) {
                   #  # ]
     776   [ #  #  #  # ]:          0 :                 conn->state = ISCSI_CONN_STATE_EXITING;
     777                 :          0 :         }
     778                 :            : 
     779                 :          0 :         return SPDK_POLLER_BUSY;
     780                 :            : }
     781                 :            : 
     782                 :            : /* If the connection is running and logout is not requested yet, request logout
     783                 :            :  * to initiator and wait for the logout process to start.
     784                 :            :  */
     785                 :            : static void
     786                 :          8 : _iscsi_conn_request_logout(void *ctx)
     787                 :            : {
     788                 :          8 :         struct spdk_iscsi_conn *conn = ctx;
     789                 :            : 
     790   [ +  -  #  #  :          8 :         if (conn->state > ISCSI_CONN_STATE_RUNNING ||
             #  #  #  # ]
     791   [ -  +  #  # ]:          8 :             conn->logout_request_timer != NULL) {
     792                 :          0 :                 return;
     793                 :            :         }
     794                 :            : 
     795                 :          8 :         iscsi_send_logout_request(conn);
     796                 :            : 
     797   [ #  #  #  # ]:          8 :         conn->logout_request_timer = SPDK_POLLER_REGISTER(logout_request_timeout,
     798                 :            :                                      conn, ISCSI_LOGOUT_REQUEST_TIMEOUT * 1000000);
     799                 :          0 : }
     800                 :            : 
     801                 :            : static void
     802                 :          8 : iscsi_conn_request_logout(struct spdk_iscsi_conn *conn)
     803                 :            : {
     804                 :            :         struct spdk_thread *thread;
     805                 :            : 
     806   [ -  +  #  #  :          8 :         if (conn->state == ISCSI_CONN_STATE_INVALID) {
                   #  # ]
     807                 :            :                 /* Move it to EXITING state if the connection is in login. */
     808   [ #  #  #  # ]:          0 :                 conn->state = ISCSI_CONN_STATE_EXITING;
     809   [ +  -  #  #  :          8 :         } else if (conn->state == ISCSI_CONN_STATE_RUNNING &&
             #  #  #  # ]
     810   [ +  -  #  # ]:          8 :                    conn->logout_request_timer == NULL) {
     811   [ #  #  #  # ]:          8 :                 thread = spdk_io_channel_get_thread(spdk_io_channel_from_ctx(conn->pg));
     812                 :          8 :                 spdk_thread_send_msg(thread, _iscsi_conn_request_logout, conn);
     813                 :          0 :         }
     814                 :          8 : }
     815                 :            : 
     816                 :            : void
     817                 :        710 : iscsi_conns_request_logout(struct spdk_iscsi_tgt_node *target, int pg_tag)
     818                 :            : {
     819                 :            :         struct spdk_iscsi_conn  *conn;
     820                 :            : 
     821         [ +  + ]:        710 :         if (g_conns_array == MAP_FAILED) {
     822                 :          0 :                 return;
     823                 :            :         }
     824                 :            : 
     825         [ +  + ]:        710 :         pthread_mutex_lock(&g_conns_mutex);
     826   [ +  +  #  #  :        718 :         TAILQ_FOREACH(conn, &g_active_conns, conn_link) {
             #  #  #  # ]
     827   [ +  +  #  # ]:          8 :                 if ((target == NULL) ||
     828   [ +  -  +  -  :          4 :                     (conn->target == target && (pg_tag < 0 || conn->pg_tag == pg_tag))) {
          +  -  #  #  #  
                #  #  # ]
     829                 :          8 :                         iscsi_conn_request_logout(conn);
     830                 :          0 :                 }
     831                 :          0 :         }
     832         [ +  + ]:        710 :         pthread_mutex_unlock(&g_conns_mutex);
     833                 :         19 : }
     834                 :            : 
     835                 :            : void
     836                 :        548 : shutdown_iscsi_conns(void)
     837                 :            : {
     838                 :        548 :         iscsi_conns_request_logout(NULL, -1);
     839                 :            : 
     840                 :        548 :         g_shutdown_timer = SPDK_POLLER_REGISTER(iscsi_conn_check_shutdown, NULL, 1000);
     841                 :        548 : }
     842                 :            : 
     843                 :            : /* Do not set conn->state if the connection has already started exiting.
     844                 :            :  *  This ensures we do not move a connection from EXITED state back to EXITING.
     845                 :            :  */
     846                 :            : static void
     847                 :          0 : _iscsi_conn_drop(void *ctx)
     848                 :            : {
     849                 :          0 :         struct spdk_iscsi_conn *conn = ctx;
     850                 :            : 
     851   [ #  #  #  #  :          0 :         if (conn->state < ISCSI_CONN_STATE_EXITING) {
                   #  # ]
     852   [ #  #  #  # ]:          0 :                 conn->state = ISCSI_CONN_STATE_EXITING;
     853                 :          0 :         }
     854                 :          0 : }
     855                 :            : 
     856                 :            : int
     857                 :        160 : iscsi_drop_conns(struct spdk_iscsi_conn *conn, const char *conn_match,
     858                 :            :                  int drop_all)
     859                 :            : {
     860                 :            :         struct spdk_iscsi_conn  *xconn;
     861                 :            :         const char              *xconn_match;
     862                 :            :         struct spdk_thread      *thread;
     863                 :            :         int                     num;
     864                 :            : 
     865   [ -  +  -  +  :        160 :         SPDK_DEBUGLOG(iscsi, "iscsi_drop_conns\n");
                   #  # ]
     866                 :            : 
     867                 :        160 :         num = 0;
     868         [ #  # ]:        160 :         pthread_mutex_lock(&g_conns_mutex);
     869         [ -  + ]:        160 :         if (g_conns_array == MAP_FAILED) {
     870                 :          0 :                 goto exit;
     871                 :            :         }
     872                 :            : 
     873   [ +  +  #  #  :       1520 :         TAILQ_FOREACH(xconn, &g_active_conns, conn_link) {
             #  #  #  # ]
     874         [ +  + ]:       1360 :                 if (xconn == conn) {
     875                 :        160 :                         continue;
     876                 :            :                 }
     877                 :            : 
     878   [ +  -  -  +  :       1200 :                 if (!drop_all && xconn->initiator_port == NULL) {
             #  #  #  # ]
     879                 :          0 :                         continue;
     880                 :            :                 }
     881                 :            : 
     882                 :       1200 :                 xconn_match =
     883   [ -  +  #  #  :       1200 :                         drop_all ? xconn->initiator_name : spdk_scsi_port_get_name(xconn->initiator_port);
             #  #  #  # ]
     884                 :            : 
     885   [ -  +  -  +  :       1200 :                 if (!strcasecmp(conn_match, xconn_match) &&
             -  +  #  # ]
     886   [ #  #  #  #  :          0 :                     conn->target == xconn->target) {
             #  #  #  # ]
     887                 :            : 
     888         [ #  # ]:          0 :                         if (num == 0) {
     889                 :            :                                 /*
     890                 :            :                                  * Only print this message before we report the
     891                 :            :                                  *  first dropped connection.
     892                 :            :                                  */
     893   [ #  #  #  #  :          0 :                                 SPDK_ERRLOG("drop old connections %s by %s\n",
                   #  # ]
     894                 :            :                                             conn->target->name, conn_match);
     895                 :          0 :                         }
     896                 :            : 
     897         [ #  # ]:          0 :                         SPDK_ERRLOG("exiting conn by %s (%s)\n",
     898                 :            :                                     xconn_match, xconn->initiator_addr);
     899   [ #  #  #  #  :          0 :                         if (xconn->sess != NULL) {
                   #  # ]
     900   [ #  #  #  #  :          0 :                                 SPDK_DEBUGLOG(iscsi, "TSIH=%u\n", xconn->sess->tsih);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     901                 :          0 :                         } else {
     902   [ #  #  #  #  :          0 :                                 SPDK_DEBUGLOG(iscsi, "TSIH=xx\n");
                   #  # ]
     903                 :            :                         }
     904                 :            : 
     905   [ #  #  #  #  :          0 :                         SPDK_DEBUGLOG(iscsi, "CID=%u\n", xconn->cid);
          #  #  #  #  #  
                      # ]
     906                 :            : 
     907   [ #  #  #  # ]:          0 :                         thread = spdk_io_channel_get_thread(spdk_io_channel_from_ctx(xconn->pg));
     908                 :          0 :                         spdk_thread_send_msg(thread, _iscsi_conn_drop, xconn);
     909                 :            : 
     910         [ #  # ]:          0 :                         num++;
     911                 :          0 :                 }
     912                 :          0 :         }
     913                 :            : 
     914                 :        160 : exit:
     915         [ #  # ]:        160 :         pthread_mutex_unlock(&g_conns_mutex);
     916                 :            : 
     917         [ -  + ]:        160 :         if (num != 0) {
     918                 :          0 :                 SPDK_ERRLOG("exiting %d conns\n", num);
     919                 :          0 :         }
     920                 :            : 
     921                 :        160 :         return 0;
     922                 :            : }
     923                 :            : 
     924                 :            : static int
     925                 :         21 : _iscsi_conn_abort_queued_datain_task(struct spdk_iscsi_conn *conn,
     926                 :            :                                      struct spdk_iscsi_task *task)
     927                 :            : {
     928                 :            :         struct spdk_iscsi_task *subtask;
     929                 :            :         uint32_t remaining_size;
     930                 :            : 
     931   [ +  +  #  #  :         21 :         if (conn->data_in_cnt >= g_iscsi.MaxLargeDataInPerConnection) {
             #  #  #  # ]
     932                 :          6 :                 return -1;
     933                 :            :         }
     934                 :            : 
     935   [ -  +  #  #  :         15 :         assert(task->current_data_offset <= task->scsi.transfer_len);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     936                 :            :         /* Stop split and abort read I/O for remaining data. */
     937   [ +  -  #  #  :         15 :         if (task->current_data_offset < task->scsi.transfer_len) {
          #  #  #  #  #  
                #  #  # ]
     938   [ #  #  #  #  :         15 :                 remaining_size = task->scsi.transfer_len - task->current_data_offset;
          #  #  #  #  #  
                      # ]
     939                 :         15 :                 subtask = iscsi_task_get(conn, task, iscsi_task_cpl);
     940   [ -  +  #  # ]:         15 :                 assert(subtask != NULL);
     941   [ #  #  #  #  :         15 :                 subtask->scsi.offset = task->current_data_offset;
          #  #  #  #  #  
                      # ]
     942   [ #  #  #  #  :         15 :                 subtask->scsi.length = remaining_size;
                   #  # ]
     943         [ #  # ]:         15 :                 spdk_scsi_task_set_data(&subtask->scsi, NULL, 0);
     944   [ #  #  #  #  :         15 :                 task->current_data_offset += subtask->scsi.length;
          #  #  #  #  #  
                      # ]
     945                 :            : 
     946   [ #  #  #  #  :         15 :                 subtask->scsi.transfer_len = subtask->scsi.length;
          #  #  #  #  #  
                #  #  # ]
     947         [ #  # ]:         15 :                 spdk_scsi_task_process_abort(&subtask->scsi);
     948         [ #  # ]:         15 :                 iscsi_task_cpl(&subtask->scsi);
     949                 :          0 :         }
     950                 :            : 
     951                 :            :         /* Remove the primary task from the list because all subtasks are submitted
     952                 :            :          *  or aborted.
     953                 :            :          */
     954   [ -  +  #  #  :         15 :         assert(task->current_data_offset == task->scsi.transfer_len);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     955   [ +  +  #  #  :         15 :         TAILQ_REMOVE(&conn->queued_datain_tasks, task, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     956                 :         15 :         return 0;
     957                 :          0 : }
     958                 :            : 
     959                 :            : int
     960                 :          0 : iscsi_conn_abort_queued_datain_task(struct spdk_iscsi_conn *conn,
     961                 :            :                                     uint32_t ref_task_tag)
     962                 :            : {
     963                 :            :         struct spdk_iscsi_task *task;
     964                 :            : 
     965   [ #  #  #  #  :          0 :         TAILQ_FOREACH(task, &conn->queued_datain_tasks, link) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     966   [ #  #  #  #  :          0 :                 if (task->tag == ref_task_tag) {
                   #  # ]
     967                 :          0 :                         return _iscsi_conn_abort_queued_datain_task(conn, task);
     968                 :            :                 }
     969                 :          0 :         }
     970                 :            : 
     971                 :          0 :         return 0;
     972                 :          0 : }
     973                 :            : 
     974                 :            : int
     975                 :         13 : iscsi_conn_abort_queued_datain_tasks(struct spdk_iscsi_conn *conn,
     976                 :            :                                      struct spdk_scsi_lun *lun,
     977                 :            :                                      struct spdk_iscsi_pdu *pdu)
     978                 :            : {
     979                 :            :         struct spdk_iscsi_task *task, *task_tmp;
     980                 :            :         struct spdk_iscsi_pdu *pdu_tmp;
     981                 :            :         int rc;
     982                 :            : 
     983   [ +  +  #  #  :         46 :         TAILQ_FOREACH_SAFE(task, &conn->queued_datain_tasks, link, task_tmp) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     984                 :         33 :                 pdu_tmp = iscsi_task_get_pdu(task);
     985   [ +  -  +  +  :         33 :                 if ((lun == NULL || lun == task->scsi.lun) &&
          +  -  #  #  #  
                      # ]
     986   [ +  +  #  #  :         18 :                     (pdu == NULL || (spdk_sn32_lt(pdu_tmp->cmd_sn, pdu->cmd_sn)))) {
          #  #  #  #  #  
                      # ]
     987                 :          9 :                         rc = _iscsi_conn_abort_queued_datain_task(conn, task);
     988         [ -  + ]:          9 :                         if (rc != 0) {
     989                 :          0 :                                 return rc;
     990                 :            :                         }
     991                 :          0 :                 }
     992                 :          0 :         }
     993                 :            : 
     994                 :         13 :         return 0;
     995                 :          0 : }
     996                 :            : 
     997                 :            : int
     998                 :   12752325 : iscsi_conn_handle_queued_datain_tasks(struct spdk_iscsi_conn *conn)
     999                 :            : {
    1000                 :            :         struct spdk_iscsi_task *task;
    1001                 :            : 
    1002   [ +  +  #  #  :   25915759 :         while (!TAILQ_EMPTY(&conn->queued_datain_tasks) &&
          #  #  #  #  #  
                      # ]
    1003   [ +  +  #  #  :     454572 :                conn->data_in_cnt < g_iscsi.MaxLargeDataInPerConnection) {
                   #  # ]
    1004   [ #  #  #  #  :     411109 :                 task = TAILQ_FIRST(&conn->queued_datain_tasks);
                   #  # ]
    1005   [ -  +  #  #  :     411109 :                 assert(task->current_data_offset <= task->scsi.transfer_len);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1006   [ +  -  #  #  :     411109 :                 if (task->current_data_offset < task->scsi.transfer_len) {
          #  #  #  #  #  
                #  #  # ]
    1007                 :            :                         struct spdk_iscsi_task *subtask;
    1008                 :     411109 :                         uint32_t remaining_size = 0;
    1009                 :            : 
    1010   [ #  #  #  #  :     411109 :                         remaining_size = task->scsi.transfer_len - task->current_data_offset;
          #  #  #  #  #  
                      # ]
    1011                 :     411109 :                         subtask = iscsi_task_get(conn, task, iscsi_task_cpl);
    1012   [ -  +  #  # ]:     411109 :                         assert(subtask != NULL);
    1013   [ #  #  #  #  :     411109 :                         subtask->scsi.offset = task->current_data_offset;
          #  #  #  #  #  
                      # ]
    1014         [ #  # ]:     411109 :                         spdk_scsi_task_set_data(&subtask->scsi, NULL, 0);
    1015                 :            : 
    1016   [ -  +  #  #  :     411109 :                         if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) {
          #  #  #  #  #  
                      # ]
    1017                 :            :                                 /* Stop submitting split read I/Os for remaining data. */
    1018   [ #  #  #  #  :          0 :                                 TAILQ_REMOVE(&conn->queued_datain_tasks, task, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1019   [ #  #  #  # ]:          0 :                                 task->current_data_offset += remaining_size;
    1020   [ #  #  #  #  :          0 :                                 assert(task->current_data_offset == task->scsi.transfer_len);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1021   [ #  #  #  #  :          0 :                                 subtask->scsi.transfer_len = remaining_size;
                   #  # ]
    1022         [ #  # ]:          0 :                                 spdk_scsi_task_process_null_lun(&subtask->scsi);
    1023         [ #  # ]:          0 :                                 iscsi_task_cpl(&subtask->scsi);
    1024                 :          0 :                                 return 0;
    1025                 :            :                         }
    1026                 :            : 
    1027   [ #  #  #  #  :     411109 :                         subtask->scsi.length = spdk_min(SPDK_BDEV_LARGE_BUF_MAX_SIZE, remaining_size);
             #  #  #  # ]
    1028   [ #  #  #  #  :     411109 :                         task->current_data_offset += subtask->scsi.length;
          #  #  #  #  #  
                      # ]
    1029                 :     411109 :                         iscsi_queue_task(conn, subtask);
    1030                 :          0 :                 }
    1031   [ +  +  #  #  :     411109 :                 if (task->current_data_offset == task->scsi.transfer_len) {
          #  #  #  #  #  
                #  #  # ]
    1032   [ +  +  #  #  :     183448 :                         TAILQ_REMOVE(&conn->queued_datain_tasks, task, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1033                 :          0 :                 }
    1034                 :            :         }
    1035                 :   12752325 :         return 0;
    1036                 :          0 : }
    1037                 :            : 
    1038                 :            : void
    1039                 :          7 : iscsi_task_mgmt_cpl(struct spdk_scsi_task *scsi_task)
    1040                 :            : {
    1041                 :          7 :         struct spdk_iscsi_task *task = iscsi_task_from_scsi_task(scsi_task);
    1042                 :            : 
    1043   [ #  #  #  # ]:          7 :         iscsi_task_mgmt_response(task->conn, task);
    1044                 :          7 :         iscsi_task_put(task);
    1045                 :          7 : }
    1046                 :            : 
    1047                 :            : static void
    1048                 :     385653 : process_completed_read_subtask_list_in_order(struct spdk_iscsi_conn *conn,
    1049                 :            :                 struct spdk_iscsi_task *primary)
    1050                 :            : {
    1051                 :            :         struct spdk_iscsi_task *subtask, *tmp;
    1052                 :            : 
    1053   [ +  +  #  #  :     796840 :         TAILQ_FOREACH_SAFE(subtask, &primary->subtask_list, subtask_link, tmp) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1054   [ +  +  #  #  :     411208 :                 if (subtask->scsi.offset == primary->bytes_completed) {
          #  #  #  #  #  
                #  #  # ]
    1055   [ +  +  #  #  :     411187 :                         TAILQ_REMOVE(&primary->subtask_list, subtask, subtask_link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1056   [ #  #  #  #  :     411187 :                         primary->bytes_completed += subtask->scsi.length;
          #  #  #  #  #  
                      # ]
    1057   [ +  +  #  #  :     411187 :                         if (primary->bytes_completed == primary->scsi.transfer_len) {
          #  #  #  #  #  
                #  #  # ]
    1058                 :     183469 :                                 iscsi_task_put(primary);
    1059                 :          0 :                         }
    1060                 :     411187 :                         iscsi_task_response(conn, subtask);
    1061                 :     411187 :                         iscsi_task_put(subtask);
    1062                 :          0 :                 } else {
    1063                 :         21 :                         break;
    1064                 :            :                 }
    1065                 :          0 :         }
    1066                 :     385653 : }
    1067                 :            : 
    1068                 :            : static void
    1069                 :   12571477 : process_read_task_completion(struct spdk_iscsi_conn *conn,
    1070                 :            :                              struct spdk_iscsi_task *task,
    1071                 :            :                              struct spdk_iscsi_task *primary)
    1072                 :            : {
    1073                 :            :         struct spdk_iscsi_task *tmp;
    1074                 :            : 
    1075   [ +  +  #  #  :   12571477 :         if (task->scsi.status != SPDK_SCSI_STATUS_GOOD) {
             #  #  #  # ]
    1076   [ +  +  #  #  :       2610 :                 if (primary->scsi.status == SPDK_SCSI_STATUS_GOOD) {
             #  #  #  # ]
    1077                 :            :                         /* If the status of the completed subtask, task, is the
    1078                 :            :                          * first failure, copy it to out-of-order subtasks, and
    1079                 :            :                          * remember it as the status of the SCSI Read Command.
    1080                 :            :                          */
    1081   [ +  +  #  #  :          9 :                         TAILQ_FOREACH(tmp, &primary->subtask_list, subtask_link) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1082   [ #  #  #  # ]:          6 :                                 spdk_scsi_task_copy_status(&tmp->scsi, &task->scsi);
    1083                 :          0 :                         }
    1084   [ #  #  #  # ]:          3 :                         spdk_scsi_task_copy_status(&primary->scsi, &task->scsi);
    1085                 :          0 :                 }
    1086   [ +  +  #  #  :   12568867 :         } else if (primary->scsi.status != SPDK_SCSI_STATUS_GOOD) {
             #  #  #  # ]
    1087                 :            :                 /* Even if the status of the completed subtask is success,
    1088                 :            :                  * if there are any failed subtask ever, copy the first failed
    1089                 :            :                  * status to it.
    1090                 :            :                  */
    1091   [ #  #  #  # ]:          9 :                 spdk_scsi_task_copy_status(&task->scsi, &primary->scsi);
    1092                 :          0 :         }
    1093                 :            : 
    1094         [ +  + ]:   12571477 :         if (task == primary) {
    1095                 :            :                 /* If read I/O size is not larger than SPDK_BDEV_LARGE_BUF_MAX_SIZE,
    1096                 :            :                  * the primary task which processes the SCSI Read Command PDU is
    1097                 :            :                  * submitted directly. Hence send SCSI Response PDU for the primary
    1098                 :            :                  * task simply.
    1099                 :            :                  */
    1100   [ #  #  #  #  :   12160287 :                 primary->bytes_completed = task->scsi.length;
          #  #  #  #  #  
                      # ]
    1101   [ -  +  #  #  :   12160287 :                 assert(primary->bytes_completed == task->scsi.transfer_len);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1102                 :   12160287 :                 iscsi_task_response(conn, task);
    1103                 :   12160287 :                 iscsi_task_put(task);
    1104   [ -  +  -  +  :     411190 :         } else if (!conn->sess->DataSequenceInOrder) {
          #  #  #  #  #  
                #  #  # ]
    1105                 :            :                 /* If DataSequenceInOrder is No, send SCSI Response PDU for the completed
    1106                 :            :                  * subtask without any deferral.
    1107                 :            :                  */
    1108   [ #  #  #  #  :          0 :                 primary->bytes_completed += task->scsi.length;
          #  #  #  #  #  
                      # ]
    1109   [ #  #  #  #  :          0 :                 if (primary->bytes_completed == primary->scsi.transfer_len) {
          #  #  #  #  #  
                #  #  # ]
    1110                 :          0 :                         iscsi_task_put(primary);
    1111                 :          0 :                 }
    1112                 :          0 :                 iscsi_task_response(conn, task);
    1113                 :          0 :                 iscsi_task_put(task);
    1114                 :          0 :         } else {
    1115                 :            :                 /* If DataSequenceInOrder is Yes, if the completed subtask is out-of-order,
    1116                 :            :                  * it is deferred until all preceding subtasks send SCSI Response PDU.
    1117                 :            :                  */
    1118   [ +  +  #  #  :     411190 :                 if (task->scsi.offset != primary->bytes_completed) {
          #  #  #  #  #  
                #  #  # ]
    1119   [ +  +  #  #  :      25632 :                         TAILQ_FOREACH(tmp, &primary->subtask_list, subtask_link) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1120   [ +  +  #  #  :        554 :                                 if (task->scsi.offset < tmp->scsi.offset) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1121   [ #  #  #  #  :        459 :                                         TAILQ_INSERT_BEFORE(tmp, task, subtask_link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1122                 :        459 :                                         return;
    1123                 :            :                                 }
    1124                 :          0 :                         }
    1125                 :            : 
    1126   [ #  #  #  #  :      25078 :                         TAILQ_INSERT_TAIL(&primary->subtask_list, task, subtask_link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1127                 :          0 :                 } else {
    1128   [ +  +  #  #  :     385653 :                         TAILQ_INSERT_HEAD(&primary->subtask_list, task, subtask_link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1129                 :     385653 :                         process_completed_read_subtask_list_in_order(conn, primary);
    1130                 :            :                 }
    1131                 :            :         }
    1132                 :          0 : }
    1133                 :            : 
    1134                 :            : static void
    1135                 :   11097684 : process_non_read_task_completion(struct spdk_iscsi_conn *conn,
    1136                 :            :                                  struct spdk_iscsi_task *task,
    1137                 :            :                                  struct spdk_iscsi_task *primary)
    1138                 :            : {
    1139   [ #  #  #  #  :   11097684 :         primary->bytes_completed += task->scsi.length;
          #  #  #  #  #  
                      # ]
    1140                 :            : 
    1141         [ +  + ]:   11097684 :         if (task == primary) {
    1142                 :            :                 /* This was a small write with no R2T. */
    1143                 :   10197366 :                 iscsi_task_response(conn, task);
    1144                 :   10197366 :                 iscsi_task_put(task);
    1145                 :   10197366 :                 return;
    1146                 :            :         }
    1147                 :            : 
    1148   [ +  +  #  #  :     900318 :         if (task->scsi.status == SPDK_SCSI_STATUS_GOOD) {
             #  #  #  # ]
    1149   [ #  #  #  #  :     900315 :                 primary->scsi.data_transferred += task->scsi.data_transferred;
          #  #  #  #  #  
                #  #  # ]
    1150   [ +  -  #  #  :          3 :         } else if (primary->scsi.status == SPDK_SCSI_STATUS_GOOD) {
             #  #  #  # ]
    1151                 :            :                 /* If the status of this subtask is the first failure, copy it to
    1152                 :            :                  * the primary task.
    1153                 :            :                  */
    1154   [ #  #  #  # ]:          3 :                 spdk_scsi_task_copy_status(&primary->scsi, &task->scsi);
    1155                 :          0 :         }
    1156                 :            : 
    1157   [ +  +  #  #  :     900318 :         if (primary->bytes_completed == primary->scsi.transfer_len) {
          #  #  #  #  #  
                #  #  # ]
    1158                 :            :                 /* If LUN is removed in the middle of the iSCSI write sequence,
    1159                 :            :                  *  primary might complete the write to the initiator because it is not
    1160                 :            :                  *  ensured that the initiator will send all data requested by R2Ts.
    1161                 :            :                  *
    1162                 :            :                  * We check it and skip the following if primary is completed. (see
    1163                 :            :                  *  iscsi_clear_all_transfer_task() in iscsi.c.)
    1164                 :            :                  */
    1165   [ +  +  +  +  :     507424 :                 if (primary->is_r2t_active) {
             #  #  #  # ]
    1166                 :     507421 :                         iscsi_task_response(conn, primary);
    1167   [ #  #  #  # ]:     507421 :                         iscsi_del_transfer_task(conn, primary->tag);
    1168                 :          0 :                 } else {
    1169                 :          3 :                         iscsi_task_response(conn, task);
    1170                 :            :                 }
    1171                 :          0 :         }
    1172                 :     900318 :         iscsi_task_put(task);
    1173                 :          0 : }
    1174                 :            : 
    1175                 :            : void
    1176                 :   23669083 : iscsi_task_cpl(struct spdk_scsi_task *scsi_task)
    1177                 :            : {
    1178                 :            :         struct spdk_iscsi_task *primary;
    1179                 :   23669083 :         struct spdk_iscsi_task *task = iscsi_task_from_scsi_task(scsi_task);
    1180   [ #  #  #  # ]:   23669083 :         struct spdk_iscsi_conn *conn = task->conn;
    1181   [ #  #  #  # ]:   23669083 :         struct spdk_iscsi_pdu *pdu = task->pdu;
    1182                 :            : 
    1183   [ +  +  +  +  :   23669083 :         spdk_trace_record(TRACE_ISCSI_TASK_DONE, conn->id, 0, (uintptr_t)task);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1184                 :            : 
    1185   [ #  #  #  # ]:   23669083 :         task->is_queued = false;
    1186                 :   23669083 :         primary = iscsi_task_get_primary(task);
    1187                 :            : 
    1188         [ +  + ]:   23669083 :         if (iscsi_task_is_read(primary)) {
    1189                 :   12571411 :                 process_read_task_completion(conn, task, primary);
    1190                 :          0 :         } else {
    1191                 :   11097672 :                 process_non_read_task_completion(conn, task, primary);
    1192                 :            :         }
    1193   [ +  +  #  #  :   23669083 :         if (!task->parent) {
                   #  # ]
    1194   [ +  -  +  +  :   23257959 :                 spdk_trace_record(TRACE_ISCSI_PDU_COMPLETED, 0, 0, (uintptr_t)pdu);
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    1195                 :          0 :         }
    1196                 :   23669083 : }
    1197                 :            : 
    1198                 :            : static void
    1199                 :         66 : iscsi_conn_send_nopin(struct spdk_iscsi_conn *conn)
    1200                 :            : {
    1201                 :            :         struct spdk_iscsi_pdu *rsp_pdu;
    1202                 :            :         struct iscsi_bhs_nop_in *rsp;
    1203                 :            :         /* Only send nopin if we have logged in and are in a normal session. */
    1204   [ +  -  #  #  :         66 :         if (conn->sess == NULL ||
             #  #  #  # ]
    1205   [ +  -  -  +  :        132 :             !conn->full_feature ||
                   #  # ]
    1206   [ #  #  #  #  :         66 :             !iscsi_param_eq_val(conn->sess->params, "SessionType", "Normal")) {
             #  #  #  # ]
    1207                 :          0 :                 return;
    1208                 :            :         }
    1209   [ -  +  -  +  :         66 :         SPDK_DEBUGLOG(iscsi, "send NOPIN isid=%"PRIx64", tsih=%u, cid=%u\n",
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1210                 :            :                       conn->sess->isid, conn->sess->tsih, conn->cid);
    1211   [ -  +  -  +  :         66 :         SPDK_DEBUGLOG(iscsi, "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1212                 :            :                       conn->StatSN, conn->sess->ExpCmdSN,
    1213                 :            :                       conn->sess->MaxCmdSN);
    1214                 :         66 :         rsp_pdu = iscsi_get_pdu(conn);
    1215         [ #  # ]:         66 :         rsp = (struct iscsi_bhs_nop_in *) &rsp_pdu->bhs;
    1216   [ #  #  #  # ]:         66 :         rsp_pdu->data = NULL;
    1217                 :            :         /*
    1218                 :            :          * iscsi_get_pdu() memset's the PDU for us, so only fill out the needed
    1219                 :            :          *  fields.
    1220                 :            :          */
    1221         [ #  # ]:         66 :         rsp->opcode = ISCSI_OP_NOPIN;
    1222   [ #  #  #  # ]:         66 :         rsp->flags = 0x80;
    1223                 :            :         /*
    1224                 :            :          * Technically the to_be32() is not needed here, since
    1225                 :            :          *  to_be32(0xFFFFFFFU) returns 0xFFFFFFFFU.
    1226                 :            :          */
    1227         [ #  # ]:         66 :         to_be32(&rsp->itt, 0xFFFFFFFFU);
    1228   [ #  #  #  #  :         66 :         to_be32(&rsp->ttt, conn->id);
                   #  # ]
    1229   [ #  #  #  #  :         66 :         to_be32(&rsp->stat_sn, conn->StatSN);
                   #  # ]
    1230   [ #  #  #  #  :         66 :         to_be32(&rsp->exp_cmd_sn, conn->sess->ExpCmdSN);
          #  #  #  #  #  
                      # ]
    1231   [ #  #  #  #  :         66 :         to_be32(&rsp->max_cmd_sn, conn->sess->MaxCmdSN);
          #  #  #  #  #  
                      # ]
    1232                 :         66 :         iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
    1233   [ #  #  #  # ]:         66 :         conn->last_nopin = spdk_get_ticks();
    1234   [ #  #  #  # ]:         66 :         conn->nop_outstanding = true;
    1235                 :          0 : }
    1236                 :            : 
    1237                 :            : void
    1238                 :       3849 : iscsi_conn_handle_nop(struct spdk_iscsi_conn *conn)
    1239                 :            : {
    1240                 :            :         uint64_t        tsc;
    1241                 :            : 
    1242                 :            :         /**
    1243                 :            :           * This function will be executed by nop_poller of iSCSI polling group, so
    1244                 :            :           * we need to check the connection state first, then do the nop interval
    1245                 :            :           * expiration check work.
    1246                 :            :           */
    1247   [ +  -  #  #  :       3849 :         if ((conn->state == ISCSI_CONN_STATE_EXITED) ||
             #  #  #  # ]
    1248   [ -  +  #  # ]:       3849 :             (conn->state == ISCSI_CONN_STATE_EXITING)) {
    1249                 :          0 :                 return;
    1250                 :            :         }
    1251                 :            : 
    1252                 :            :         /* Check for nop interval expiration */
    1253                 :       3849 :         tsc = spdk_get_ticks();
    1254   [ -  +  +  +  :       3849 :         if (conn->nop_outstanding) {
             #  #  #  # ]
    1255   [ -  +  #  #  :         80 :                 if ((tsc - conn->last_nopin) > conn->timeout) {
          #  #  #  #  #  
                      # ]
    1256                 :          0 :                         SPDK_ERRLOG("Timed out waiting for NOP-Out response from initiator\n");
    1257   [ #  #  #  # ]:          0 :                         SPDK_ERRLOG("  tsc=0x%" PRIx64 ", last_nopin=0x%" PRIx64 "\n", tsc, conn->last_nopin);
    1258   [ #  #  #  # ]:          0 :                         SPDK_ERRLOG("  initiator=%s, target=%s\n", conn->initiator_name,
    1259                 :            :                                     conn->target_short_name);
    1260   [ #  #  #  # ]:          0 :                         conn->state = ISCSI_CONN_STATE_EXITING;
    1261                 :          0 :                 }
    1262   [ +  +  #  #  :       3769 :         } else if (tsc - conn->last_nopin > conn->nopininterval) {
          #  #  #  #  #  
                      # ]
    1263                 :         66 :                 iscsi_conn_send_nopin(conn);
    1264                 :          0 :         }
    1265                 :          0 : }
    1266                 :            : 
    1267                 :            : /**
    1268                 :            :  * \brief Reads data for the specified iSCSI connection from its TCP socket.
    1269                 :            :  *
    1270                 :            :  * The TCP socket is marked as non-blocking, so this function may not read
    1271                 :            :  * all data requested.
    1272                 :            :  *
    1273                 :            :  * Returns SPDK_ISCSI_CONNECTION_FATAL if the recv() operation indicates a fatal
    1274                 :            :  * error with the TCP connection (including if the TCP connection was closed
    1275                 :            :  * unexpectedly.
    1276                 :            :  *
    1277                 :            :  * Otherwise returns the number of bytes successfully read.
    1278                 :            :  */
    1279                 :            : int
    1280                 :  103395660 : iscsi_conn_read_data(struct spdk_iscsi_conn *conn, int bytes,
    1281                 :            :                      void *buf)
    1282                 :            : {
    1283                 :            :         int ret;
    1284                 :            : 
    1285         [ -  + ]:  103395660 :         if (bytes == 0) {
    1286                 :          0 :                 return 0;
    1287                 :            :         }
    1288                 :            : 
    1289   [ #  #  #  # ]:  103395660 :         ret = spdk_sock_recv(conn->sock, buf, bytes);
    1290                 :            : 
    1291         [ +  + ]:  103395660 :         if (ret > 0) {
    1292   [ +  -  +  +  :   38270955 :                 spdk_trace_record(TRACE_ISCSI_READ_FROM_SOCKET_DONE, conn->id, ret, 0);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1293                 :   38270955 :                 return ret;
    1294                 :            :         }
    1295                 :            : 
    1296         [ +  + ]:   65124705 :         if (ret < 0) {
    1297   [ +  +  -  +  :   65124196 :                 if (errno == EAGAIN || errno == EWOULDBLOCK) {
             #  #  #  # ]
    1298                 :   65124152 :                         return 0;
    1299                 :            :                 }
    1300                 :            : 
    1301                 :            :                 /* For connect reset issue, do not output error log */
    1302   [ +  -  #  # ]:         44 :                 if (errno == ECONNRESET) {
    1303   [ -  +  -  +  :         44 :                         SPDK_DEBUGLOG(iscsi, "spdk_sock_recv() failed, errno %d: %s\n",
          #  #  #  #  #  
                      # ]
    1304                 :            :                                       errno, spdk_strerror(errno));
    1305                 :          0 :                 } else {
    1306   [ #  #  #  # ]:          0 :                         SPDK_ERRLOG("spdk_sock_recv() failed, errno %d: %s\n",
    1307                 :            :                                     errno, spdk_strerror(errno));
    1308                 :            :                 }
    1309                 :          0 :         }
    1310                 :            : 
    1311                 :            :         /* connection closed */
    1312                 :        553 :         return SPDK_ISCSI_CONNECTION_FATAL;
    1313                 :          0 : }
    1314                 :            : 
    1315                 :            : int
    1316                 :          0 : iscsi_conn_readv_data(struct spdk_iscsi_conn *conn,
    1317                 :            :                       struct iovec *iov, int iovcnt)
    1318                 :            : {
    1319                 :            :         int ret;
    1320                 :            : 
    1321   [ #  #  #  # ]:          0 :         if (iov == NULL || iovcnt == 0) {
    1322                 :          0 :                 return 0;
    1323                 :            :         }
    1324                 :            : 
    1325         [ #  # ]:          0 :         if (iovcnt == 1) {
    1326   [ #  #  #  #  :          0 :                 return iscsi_conn_read_data(conn, iov[0].iov_len,
                   #  # ]
    1327   [ #  #  #  #  :          0 :                                             iov[0].iov_base);
                   #  # ]
    1328                 :            :         }
    1329                 :            : 
    1330   [ #  #  #  # ]:          0 :         ret = spdk_sock_readv(conn->sock, iov, iovcnt);
    1331                 :            : 
    1332         [ #  # ]:          0 :         if (ret > 0) {
    1333   [ #  #  #  #  :          0 :                 spdk_trace_record(TRACE_ISCSI_READ_FROM_SOCKET_DONE, conn->id, ret, 0);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1334                 :          0 :                 return ret;
    1335                 :            :         }
    1336                 :            : 
    1337         [ #  # ]:          0 :         if (ret < 0) {
    1338   [ #  #  #  #  :          0 :                 if (errno == EAGAIN || errno == EWOULDBLOCK) {
             #  #  #  # ]
    1339                 :          0 :                         return 0;
    1340                 :            :                 }
    1341                 :            : 
    1342                 :            :                 /* For connect reset issue, do not output error log */
    1343   [ #  #  #  # ]:          0 :                 if (errno == ECONNRESET) {
    1344   [ #  #  #  #  :          0 :                         SPDK_DEBUGLOG(iscsi, "spdk_sock_readv() failed, errno %d: %s\n",
          #  #  #  #  #  
                      # ]
    1345                 :            :                                       errno, spdk_strerror(errno));
    1346                 :          0 :                 } else {
    1347   [ #  #  #  # ]:          0 :                         SPDK_ERRLOG("spdk_sock_readv() failed, errno %d: %s\n",
    1348                 :            :                                     errno, spdk_strerror(errno));
    1349                 :            :                 }
    1350                 :          0 :         }
    1351                 :            : 
    1352                 :            :         /* connection closed */
    1353                 :          0 :         return SPDK_ISCSI_CONNECTION_FATAL;
    1354                 :          0 : }
    1355                 :            : 
    1356                 :            : static bool
    1357                 :       2354 : iscsi_is_free_pdu_deferred(struct spdk_iscsi_pdu *pdu)
    1358                 :            : {
    1359         [ -  + ]:       2354 :         if (pdu == NULL) {
    1360                 :          0 :                 return false;
    1361                 :            :         }
    1362                 :            : 
    1363   [ +  +  #  #  :       2354 :         if (pdu->bhs.opcode == ISCSI_OP_R2T ||
             #  #  #  # ]
    1364   [ +  +  #  # ]:       2172 :             pdu->bhs.opcode == ISCSI_OP_SCSI_DATAIN) {
    1365                 :       1474 :                 return true;
    1366                 :            :         }
    1367                 :            : 
    1368                 :        880 :         return false;
    1369                 :          0 : }
    1370                 :            : 
    1371                 :            : static int
    1372                 :          0 : iscsi_dif_verify(struct spdk_iscsi_pdu *pdu, struct spdk_dif_ctx *dif_ctx)
    1373                 :            : {
    1374                 :          0 :         struct iovec iov;
    1375                 :          0 :         struct spdk_dif_error err_blk = {};
    1376                 :            :         uint32_t num_blocks;
    1377                 :            :         int rc;
    1378                 :            : 
    1379   [ #  #  #  # ]:          0 :         iov.iov_base = pdu->data;
    1380   [ #  #  #  #  :          0 :         iov.iov_len = pdu->data_buf_len;
                   #  # ]
    1381   [ #  #  #  #  :          0 :         num_blocks = pdu->data_buf_len / dif_ctx->block_size;
          #  #  #  #  #  
                      # ]
    1382                 :            : 
    1383                 :          0 :         rc = spdk_dif_verify(&iov, 1, num_blocks, dif_ctx, &err_blk);
    1384         [ #  # ]:          0 :         if (rc != 0) {
    1385         [ #  # ]:          0 :                 SPDK_ERRLOG("DIF error detected. type=%d, offset=%" PRIu32 "\n",
    1386                 :            :                             err_blk.err_type, err_blk.err_offset);
    1387                 :          0 :         }
    1388                 :            : 
    1389                 :          0 :         return rc;
    1390                 :            : }
    1391                 :            : 
    1392                 :            : static void
    1393                 :   24206129 : _iscsi_conn_pdu_write_done(void *cb_arg, int err)
    1394                 :            : {
    1395                 :   24206129 :         struct spdk_iscsi_pdu *pdu = cb_arg;
    1396   [ #  #  #  # ]:   24206129 :         struct spdk_iscsi_conn *conn = pdu->conn;
    1397                 :            : 
    1398   [ -  +  #  # ]:   24206129 :         assert(conn != NULL);
    1399                 :            : 
    1400   [ -  +  #  #  :   24206129 :         if (spdk_unlikely(conn->state >= ISCSI_CONN_STATE_EXITING)) {
                   #  # ]
    1401                 :            :                 /* The other policy will recycle the resource */
    1402                 :          0 :                 return;
    1403                 :            :         }
    1404                 :            : 
    1405   [ +  +  #  #  :   24206129 :         TAILQ_REMOVE(&conn->write_pdu_list, pdu, tailq);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1406                 :            : 
    1407         [ +  + ]:   24206129 :         if (err != 0) {
    1408   [ #  #  #  # ]:          2 :                 conn->state = ISCSI_CONN_STATE_EXITING;
    1409                 :          0 :         } else {
    1410   [ +  -  +  +  :   24206127 :                 spdk_trace_record(TRACE_ISCSI_FLUSH_WRITEBUF_DONE, conn->id, pdu->mapped_length, (uintptr_t)pdu);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1411                 :            :         }
    1412                 :            : 
    1413   [ +  +  #  #  :   24206129 :         if ((conn->full_feature) &&
             #  #  #  # ]
    1414   [ +  +  +  +  :   24207387 :             (conn->sess->ErrorRecoveryLevel >= 1) &&
          #  #  #  #  #  
                      # ]
    1415                 :       2354 :             iscsi_is_free_pdu_deferred(pdu)) {
    1416   [ -  +  -  +  :       1474 :                 SPDK_DEBUGLOG(iscsi, "stat_sn=%d\n",
          #  #  #  #  #  
                      # ]
    1417                 :            :                               from_be32(&pdu->bhs.stat_sn));
    1418   [ #  #  #  #  :       1474 :                 TAILQ_INSERT_TAIL(&conn->snack_pdu_list, pdu,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1419                 :            :                                   tailq);
    1420                 :          0 :         } else {
    1421                 :   24204655 :                 iscsi_conn_free_pdu(conn, pdu);
    1422                 :            :         }
    1423                 :          0 : }
    1424                 :            : 
    1425                 :            : void
    1426                 :   11631694 : iscsi_conn_pdu_generic_complete(void *cb_arg)
    1427                 :            : {
    1428                 :   11631694 : }
    1429                 :            : 
    1430                 :            : void
    1431                 :   24206129 : iscsi_conn_write_pdu(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu,
    1432                 :            :                      iscsi_conn_xfer_complete_cb cb_fn,
    1433                 :            :                      void *cb_arg)
    1434                 :            : {
    1435                 :            :         uint32_t crc32c;
    1436                 :            :         ssize_t rc;
    1437                 :            : 
    1438   [ -  +  -  +  :   24206129 :         if (spdk_unlikely(pdu->dif_insert_or_strip)) {
             #  #  #  # ]
    1439         [ #  # ]:          0 :                 rc = iscsi_dif_verify(pdu, &pdu->dif_ctx);
    1440         [ #  # ]:          0 :                 if (rc != 0) {
    1441                 :          0 :                         iscsi_conn_free_pdu(conn, pdu);
    1442   [ #  #  #  # ]:          0 :                         conn->state = ISCSI_CONN_STATE_EXITING;
    1443                 :          0 :                         return;
    1444                 :            :                 }
    1445                 :          0 :         }
    1446                 :            : 
    1447   [ +  +  #  #  :   24206129 :         if (pdu->bhs.opcode != ISCSI_OP_LOGIN_RSP) {
                   #  # ]
    1448                 :            :                 /* Header Digest */
    1449   [ +  +  #  #  :   24201055 :                 if (conn->header_digest) {
                   #  # ]
    1450                 :     187718 :                         crc32c = iscsi_pdu_calc_header_digest(pdu);
    1451   [ #  #  #  #  :     187718 :                         MAKE_DIGEST_WORD(pdu->header_digest, crc32c);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1452                 :          0 :                 }
    1453                 :            : 
    1454                 :            :                 /* Data Digest */
    1455   [ -  +  -  -  :   24201055 :                 if (conn->data_digest && DGET24(pdu->bhs.data_segment_len) != 0) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    1456                 :          0 :                         crc32c = iscsi_pdu_calc_data_digest(pdu);
    1457   [ #  #  #  #  :          0 :                         MAKE_DIGEST_WORD(pdu->data_digest, crc32c);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1458                 :          0 :                 }
    1459                 :          0 :         }
    1460                 :            : 
    1461   [ #  #  #  # ]:   24206129 :         pdu->cb_fn = cb_fn;
    1462   [ #  #  #  # ]:   24206129 :         pdu->cb_arg = cb_arg;
    1463   [ #  #  #  #  :   24206129 :         TAILQ_INSERT_TAIL(&conn->write_pdu_list, pdu, tailq);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1464                 :            : 
    1465   [ -  +  #  #  :   24206129 :         if (spdk_unlikely(conn->state >= ISCSI_CONN_STATE_EXITING)) {
                   #  # ]
    1466                 :          0 :                 return;
    1467                 :            :         }
    1468   [ #  #  #  #  :   24206129 :         pdu->sock_req.iovcnt = iscsi_build_iovs(conn, pdu->iov, SPDK_COUNTOF(pdu->iov), pdu,
             #  #  #  # ]
    1469         [ #  # ]:   24206129 :                                                 &pdu->mapped_length);
    1470   [ #  #  #  #  :   24206129 :         pdu->sock_req.cb_fn = _iscsi_conn_pdu_write_done;
                   #  # ]
    1471   [ #  #  #  #  :   24206129 :         pdu->sock_req.cb_arg = pdu;
                   #  # ]
    1472                 :            : 
    1473   [ +  -  +  +  :   24206129 :         spdk_trace_record(TRACE_ISCSI_FLUSH_WRITEBUF_START, conn->id, pdu->mapped_length, (uintptr_t)pdu,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1474                 :            :                           pdu->sock_req.iovcnt);
    1475   [ #  #  #  #  :   24206129 :         spdk_sock_writev_async(conn->sock, &pdu->sock_req);
                   #  # ]
    1476                 :          0 : }
    1477                 :            : 
    1478                 :            : static void
    1479                 :   68241352 : iscsi_conn_sock_cb(void *arg, struct spdk_sock_group *group, struct spdk_sock *sock)
    1480                 :            : {
    1481                 :   68241352 :         struct spdk_iscsi_conn *conn = arg;
    1482                 :            :         int rc;
    1483                 :            : 
    1484   [ -  +  #  # ]:   68241352 :         assert(conn != NULL);
    1485                 :            : 
    1486   [ +  -  #  #  :   68241352 :         if ((conn->state == ISCSI_CONN_STATE_EXITED) ||
             #  #  #  # ]
    1487   [ -  +  #  # ]:   68241352 :             (conn->state == ISCSI_CONN_STATE_EXITING)) {
    1488                 :          0 :                 return;
    1489                 :            :         }
    1490                 :            : 
    1491                 :            :         /* Handle incoming PDUs */
    1492                 :   68241352 :         rc = iscsi_handle_incoming_pdus(conn);
    1493         [ +  + ]:   68241352 :         if (rc < 0) {
    1494   [ #  #  #  # ]:        565 :                 conn->state = ISCSI_CONN_STATE_EXITING;
    1495                 :          0 :         }
    1496                 :          0 : }
    1497                 :            : 
    1498                 :            : static void
    1499                 :        478 : iscsi_conn_full_feature_migrate(void *arg)
    1500                 :            : {
    1501                 :        478 :         struct spdk_iscsi_conn *conn = arg;
    1502                 :            :         int rc;
    1503                 :            : 
    1504   [ -  +  #  #  :        478 :         assert(conn->state != ISCSI_CONN_STATE_EXITED);
             #  #  #  # ]
    1505                 :            : 
    1506                 :            :         /* Note: it is possible that connection could have moved to EXITING
    1507                 :            :          * state after this message was sent. We will still add it to the
    1508                 :            :          * poll group in this case.  When the poll group is polled
    1509                 :            :          * again, it will call iscsi_conn_destruct() on it.
    1510                 :            :          */
    1511                 :            : 
    1512   [ +  -  #  #  :        478 :         if (conn->sess->session_type == SESSION_TYPE_NORMAL) {
          #  #  #  #  #  
                      # ]
    1513                 :        478 :                 rc = iscsi_conn_open_luns(conn);
    1514         [ -  + ]:        478 :                 if (rc != 0) {
    1515                 :            :                         /* If opening LUNs failed, it is a fatal error. At the first poll in the
    1516                 :            :                          * assigned poll group, this connection will be destructed.
    1517                 :            :                          */
    1518   [ #  #  #  # ]:          0 :                         conn->state = ISCSI_CONN_STATE_EXITING;
    1519                 :          0 :                 }
    1520                 :          0 :         }
    1521                 :            : 
    1522                 :            :         /* Add this connection to the assigned poll group. */
    1523   [ #  #  #  # ]:        478 :         iscsi_poll_group_add_conn(conn->pg, conn);
    1524                 :        478 : }
    1525                 :            : 
    1526                 :            : static struct spdk_iscsi_poll_group *g_next_pg = NULL;
    1527                 :            : 
    1528                 :            : void
    1529                 :        507 : iscsi_conn_schedule(struct spdk_iscsi_conn *conn)
    1530                 :            : {
    1531                 :            :         struct spdk_iscsi_poll_group    *pg;
    1532                 :            :         struct spdk_iscsi_tgt_node      *target;
    1533                 :            : 
    1534   [ +  +  #  #  :        507 :         if (conn->sess->session_type != SESSION_TYPE_NORMAL) {
          #  #  #  #  #  
                      # ]
    1535                 :            :                 /* Leave all non-normal sessions on the acceptor
    1536                 :            :                  * thread. */
    1537                 :         29 :                 return;
    1538                 :            :         }
    1539         [ -  + ]:        478 :         pthread_mutex_lock(&g_iscsi.mutex);
    1540                 :            : 
    1541   [ #  #  #  #  :        478 :         target = conn->sess->target;
             #  #  #  # ]
    1542   [ -  +  #  # ]:        478 :         pthread_mutex_lock(&target->mutex);
    1543         [ #  # ]:        478 :         target->num_active_conns++;
    1544   [ +  +  #  #  :        478 :         if (target->num_active_conns == 1) {
                   #  # ]
    1545                 :            :                 /**
    1546                 :            :                  * This is the only active connection for this target node.
    1547                 :            :                  *  Pick a poll group using round-robin.
    1548                 :            :                  */
    1549         [ +  + ]:        456 :                 if (g_next_pg == NULL) {
    1550   [ #  #  #  # ]:        410 :                         g_next_pg = TAILQ_FIRST(&g_iscsi.poll_group_head);
    1551   [ -  +  #  # ]:        410 :                         assert(g_next_pg != NULL);
    1552                 :          0 :                 }
    1553                 :            : 
    1554                 :        456 :                 pg = g_next_pg;
    1555   [ #  #  #  #  :        456 :                 g_next_pg = TAILQ_NEXT(g_next_pg, link);
                   #  # ]
    1556                 :            : 
    1557                 :            :                 /* Save the pg in the target node so it can be used for any other connections to this target node. */
    1558   [ #  #  #  # ]:        456 :                 target->pg = pg;
    1559                 :          0 :         } else {
    1560                 :            :                 /**
    1561                 :            :                  * There are other active connections for this target node.
    1562                 :            :                  */
    1563   [ #  #  #  # ]:         22 :                 pg = target->pg;
    1564                 :            :         }
    1565                 :            : 
    1566   [ -  +  #  # ]:        478 :         pthread_mutex_unlock(&target->mutex);
    1567         [ -  + ]:        478 :         pthread_mutex_unlock(&g_iscsi.mutex);
    1568                 :            : 
    1569   [ -  +  #  #  :        478 :         assert(spdk_io_channel_get_thread(spdk_io_channel_from_ctx(conn->pg)) ==
             #  #  #  # ]
    1570                 :            :                spdk_get_thread());
    1571                 :            : 
    1572                 :            :         /* Remove this connection from the previous poll group */
    1573   [ #  #  #  # ]:        478 :         iscsi_poll_group_remove_conn(conn->pg, conn);
    1574                 :            : 
    1575   [ #  #  #  # ]:        478 :         conn->pg = pg;
    1576                 :            : 
    1577                 :        478 :         spdk_thread_send_msg(spdk_io_channel_get_thread(spdk_io_channel_from_ctx(pg)),
    1578                 :          0 :                              iscsi_conn_full_feature_migrate, conn);
    1579                 :          0 : }
    1580                 :            : 
    1581                 :            : static int
    1582                 :          0 : logout_timeout(void *arg)
    1583                 :            : {
    1584                 :          0 :         struct spdk_iscsi_conn *conn = arg;
    1585                 :            : 
    1586   [ #  #  #  #  :          0 :         if (conn->state < ISCSI_CONN_STATE_EXITING) {
                   #  # ]
    1587   [ #  #  #  # ]:          0 :                 conn->state = ISCSI_CONN_STATE_EXITING;
    1588                 :          0 :         }
    1589                 :            : 
    1590                 :          0 :         return SPDK_POLLER_BUSY;
    1591                 :            : }
    1592                 :            : 
    1593                 :            : void
    1594                 :        357 : iscsi_conn_logout(struct spdk_iscsi_conn *conn)
    1595                 :            : {
    1596   [ #  #  #  # ]:        357 :         conn->is_logged_out = true;
    1597   [ #  #  #  # ]:        357 :         conn->logout_timer = SPDK_POLLER_REGISTER(logout_timeout, conn, ISCSI_LOGOUT_TIMEOUT * 1000000);
    1598                 :        357 : }
    1599                 :            : 
    1600                 :            : static const char *
    1601                 :          8 : iscsi_conn_get_state(struct spdk_iscsi_conn *conn)
    1602                 :            : {
    1603   [ -  +  -  -  :          8 :         switch (conn->state) {
             -  #  #  #  
                      # ]
    1604                 :          0 :                 SPDK_ISCSI_CONNECTION_STATUS(ISCSI_CONN_STATE_INVALID, "invalid");
    1605                 :          8 :                 SPDK_ISCSI_CONNECTION_STATUS(ISCSI_CONN_STATE_RUNNING, "running");
    1606                 :          0 :                 SPDK_ISCSI_CONNECTION_STATUS(ISCSI_CONN_STATE_EXITING, "exiting");
    1607                 :          0 :                 SPDK_ISCSI_CONNECTION_STATUS(ISCSI_CONN_STATE_EXITED, "exited");
    1608                 :            :         }
    1609                 :          0 :         return "unknown";
    1610                 :          0 : }
    1611                 :            : 
    1612                 :            : static const char *
    1613                 :          8 : iscsi_conn_get_login_phase(struct spdk_iscsi_conn *conn)
    1614                 :            : {
    1615   [ -  -  +  -  :          8 :         switch (conn->login_phase) {
             #  #  #  # ]
    1616                 :          0 :                 SPDK_ISCSI_CONNECTION_STATUS(ISCSI_SECURITY_NEGOTIATION_PHASE, "security_negotiation_phase");
    1617                 :          0 :                 SPDK_ISCSI_CONNECTION_STATUS(ISCSI_OPERATIONAL_NEGOTIATION_PHASE, "operational_negotiation_phase");
    1618                 :          8 :                 SPDK_ISCSI_CONNECTION_STATUS(ISCSI_FULL_FEATURE_PHASE, "full_feature_phase");
    1619                 :            :         }
    1620                 :          0 :         return "not_started";
    1621                 :          0 : }
    1622                 :            : 
    1623                 :            : static void
    1624                 :        550 : iscsi_conn_trace(void)
    1625                 :            : {
    1626                 :        550 :         spdk_trace_register_owner(OWNER_ISCSI_CONN, 'c');
    1627                 :        550 :         spdk_trace_register_object(OBJECT_ISCSI_PDU, 'p');
    1628                 :        550 :         spdk_trace_register_description("ISCSI_READ_DONE", TRACE_ISCSI_READ_FROM_SOCKET_DONE,
    1629                 :            :                                         OWNER_ISCSI_CONN, OBJECT_NONE, 0,
    1630                 :            :                                         SPDK_TRACE_ARG_TYPE_INT, "");
    1631                 :        550 :         spdk_trace_register_description("ISCSI_WRITE_START", TRACE_ISCSI_FLUSH_WRITEBUF_START,
    1632                 :            :                                         OWNER_ISCSI_CONN, OBJECT_ISCSI_PDU, 1,
    1633                 :            :                                         SPDK_TRACE_ARG_TYPE_INT, "iovec");
    1634                 :        550 :         spdk_trace_register_description("ISCSI_WRITE_DONE", TRACE_ISCSI_FLUSH_WRITEBUF_DONE,
    1635                 :            :                                         OWNER_ISCSI_CONN, OBJECT_ISCSI_PDU, 0,
    1636                 :            :                                         SPDK_TRACE_ARG_TYPE_INT, "");
    1637                 :        550 :         spdk_trace_register_description("ISCSI_READ_PDU", TRACE_ISCSI_READ_PDU,
    1638                 :            :                                         OWNER_ISCSI_CONN, OBJECT_ISCSI_PDU, 1,
    1639                 :            :                                         SPDK_TRACE_ARG_TYPE_INT, "opc");
    1640                 :        550 :         spdk_trace_register_description("ISCSI_TASK_DONE", TRACE_ISCSI_TASK_DONE,
    1641                 :            :                                         OWNER_ISCSI_CONN, OBJECT_SCSI_TASK, 0,
    1642                 :            :                                         SPDK_TRACE_ARG_TYPE_INT, "");
    1643                 :        550 :         spdk_trace_register_description("ISCSI_TASK_QUEUE", TRACE_ISCSI_TASK_QUEUE,
    1644                 :            :                                         OWNER_ISCSI_CONN, OBJECT_SCSI_TASK, 1,
    1645                 :            :                                         SPDK_TRACE_ARG_TYPE_PTR, "pdu");
    1646                 :        550 :         spdk_trace_register_description("ISCSI_TASK_EXECUTED", TRACE_ISCSI_TASK_EXECUTED,
    1647                 :            :                                         OWNER_ISCSI_CONN, OBJECT_ISCSI_PDU, 0,
    1648                 :            :                                         SPDK_TRACE_ARG_TYPE_INT, "");
    1649                 :        550 :         spdk_trace_register_description("ISCSI_PDU_COMPLETED", TRACE_ISCSI_PDU_COMPLETED,
    1650                 :            :                                         OWNER_ISCSI_CONN, OBJECT_ISCSI_PDU, 0,
    1651                 :            :                                         SPDK_TRACE_ARG_TYPE_INT, "");
    1652                 :        550 : }
    1653                 :        593 : SPDK_TRACE_REGISTER_FN(iscsi_conn_trace, "iscsi_conn", TRACE_GROUP_ISCSI)
    1654                 :            : 
    1655                 :            : void
    1656                 :          8 : iscsi_conn_info_json(struct spdk_json_write_ctx *w, struct spdk_iscsi_conn *conn)
    1657                 :            : {
    1658                 :            :         uint16_t tsih;
    1659                 :            : 
    1660   [ -  +  #  #  :          8 :         if (!conn->is_valid) {
                   #  # ]
    1661                 :          0 :                 return;
    1662                 :            :         }
    1663                 :            : 
    1664                 :          8 :         spdk_json_write_object_begin(w);
    1665                 :            : 
    1666   [ #  #  #  # ]:          8 :         spdk_json_write_named_int32(w, "id", conn->id);
    1667                 :            : 
    1668   [ #  #  #  # ]:          8 :         spdk_json_write_named_int32(w, "cid", conn->cid);
    1669                 :            : 
    1670                 :            :         /*
    1671                 :            :          * If we try to return data for a connection that has not
    1672                 :            :          *  logged in yet, the session will not be set.  So in this
    1673                 :            :          *  case, return -1 for the tsih rather than segfaulting
    1674                 :            :          *  on the null conn->sess.
    1675                 :            :          */
    1676   [ -  +  #  #  :          8 :         if (conn->sess == NULL) {
                   #  # ]
    1677                 :          0 :                 tsih = -1;
    1678                 :          0 :         } else {
    1679   [ #  #  #  #  :          8 :                 tsih = conn->sess->tsih;
             #  #  #  # ]
    1680                 :            :         }
    1681                 :          8 :         spdk_json_write_named_int32(w, "tsih", tsih);
    1682                 :            : 
    1683                 :          8 :         spdk_json_write_named_string(w, "state", iscsi_conn_get_state(conn));
    1684                 :            : 
    1685                 :          8 :         spdk_json_write_named_string(w, "login_phase", iscsi_conn_get_login_phase(conn));
    1686                 :            : 
    1687         [ #  # ]:          8 :         spdk_json_write_named_string(w, "initiator_addr", conn->initiator_addr);
    1688                 :            : 
    1689         [ #  # ]:          8 :         spdk_json_write_named_string(w, "target_addr", conn->target_addr);
    1690                 :            : 
    1691         [ #  # ]:          8 :         spdk_json_write_named_string(w, "target_node_name", conn->target_short_name);
    1692                 :            : 
    1693                 :          8 :         spdk_json_write_named_string(w, "thread_name",
    1694                 :          8 :                                      spdk_thread_get_name(spdk_get_thread()));
    1695                 :            : 
    1696                 :          8 :         spdk_json_write_object_end(w);
    1697                 :          0 : }

Generated by: LCOV version 1.15