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 : 0 : 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 : 0 : }
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 : 544 : _iscsi_conns_cleanup(void)
91 : : {
92 : 544 : free(g_conns_array);
93 : 544 : }
94 : :
95 : : int
96 : 544 : initialize_iscsi_conns(void)
97 : : {
98 : 0 : uint32_t i;
99 : :
100 [ + + + + : 544 : SPDK_DEBUGLOG(iscsi, "spdk_iscsi_init\n");
+ - ]
101 : :
102 : 544 : g_conns_array = calloc(MAX_ISCSI_CONNECTIONS, sizeof(struct spdk_iscsi_conn));
103 [ + + ]: 544 : if (g_conns_array == NULL) {
104 : 0 : return -ENOMEM;
105 : : }
106 : :
107 [ + + ]: 557600 : for (i = 0; i < MAX_ISCSI_CONNECTIONS; i++) {
108 [ + - + - : 557056 : g_conns_array[i].id = i;
+ - ]
109 [ + - + - : 557056 : TAILQ_INSERT_TAIL(&g_free_conns, &g_conns_array[i], conn_link);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
110 : 19456 : }
111 : :
112 : 544 : 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 : 0 : 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 : 0 : 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 [ + + + + : 2060 : 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 : 0 : }
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 : 0 : struct spdk_iscsi_poll_group *pg;
173 : 0 : struct spdk_iscsi_conn *conn;
174 : 0 : 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 : 30404453 : iscsi_conn_free_pdu(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
273 : : {
274 : 10 : iscsi_conn_xfer_complete_cb cb_fn;
275 : 10 : void *cb_arg;
276 : :
277 [ + - + - ]: 30404453 : cb_fn = pdu->cb_fn;
278 [ + - + - ]: 30404453 : cb_arg = pdu->cb_arg;
279 : :
280 [ + + # # ]: 30404453 : assert(cb_fn != NULL);
281 [ + - + - ]: 30404453 : pdu->cb_fn = NULL;
282 : :
283 [ + + + - : 30404453 : if (pdu->task) {
+ + ]
284 [ + - + - ]: 29918085 : iscsi_task_put(pdu->task);
285 : 9 : }
286 : 30404453 : iscsi_put_pdu(pdu);
287 : :
288 [ - + + - ]: 30404453 : cb_fn(cb_arg);
289 : 30404453 : }
290 : :
291 : : static int
292 : 589 : iscsi_conn_free_tasks(struct spdk_iscsi_conn *conn)
293 : : {
294 : 4 : struct spdk_iscsi_pdu *pdu, *tmp_pdu;
295 : 4 : struct spdk_iscsi_task *iscsi_task, *tmp_iscsi_task;
296 : :
297 [ + + + - : 825 : TAILQ_FOREACH_SAFE(pdu, &conn->snack_pdu_list, tailq, tmp_pdu) {
+ - + + +
- + - + -
+ + ]
298 [ + + + - : 236 : TAILQ_REMOVE(&conn->snack_pdu_list, pdu, tailq);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
299 : 236 : iscsi_conn_free_pdu(conn, pdu);
300 : 3 : }
301 : :
302 [ + + + - : 625 : TAILQ_FOREACH_SAFE(iscsi_task, &conn->queued_datain_tasks, link, tmp_iscsi_task) {
+ - + + +
- + - + -
+ + ]
303 [ + + + + : 36 : if (!iscsi_task->is_queued) {
+ - + + ]
304 [ + + + - : 30 : TAILQ_REMOVE(&conn->queued_datain_tasks, iscsi_task, link);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
305 : 30 : iscsi_task_put(iscsi_task);
306 : 5 : }
307 : 6 : }
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 [ + + + - : 632 : TAILQ_FOREACH_SAFE(pdu, &conn->write_pdu_list, tailq, tmp_pdu) {
+ - + + +
- + - + -
+ + ]
316 [ + + + - : 43 : TAILQ_REMOVE(&conn->write_pdu_list, pdu, tailq);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
317 : 43 : iscsi_conn_free_pdu(conn, pdu);
318 : 7 : }
319 : :
320 [ + + + - : 589 : if (conn->pending_task_cnt) {
- + ]
321 : 0 : return -1;
322 : : }
323 : :
324 : 589 : return 0;
325 : 4 : }
326 : :
327 : : static void
328 : 148 : iscsi_conn_cleanup_backend(struct spdk_iscsi_conn *conn)
329 : : {
330 : 0 : int rc;
331 : 0 : 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 : 0 : struct spdk_iscsi_sess *sess;
358 : 0 : int idx;
359 : 0 : 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 : 0 : 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 : 8 : iscsi_conn_check_tasks_for_lun(struct spdk_iscsi_conn *conn,
436 : : struct spdk_scsi_lun *lun)
437 : : {
438 : 0 : struct spdk_iscsi_pdu *pdu, *tmp_pdu;
439 : 0 : struct spdk_iscsi_task *task;
440 : :
441 [ - + # # ]: 8 : assert(lun != NULL);
442 : :
443 : : /* We can remove deferred PDUs safely because they are already flushed. */
444 [ - + # # : 8 : 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 [ - + # # : 8 : 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 [ + + # # : 23 : TAILQ_FOREACH(pdu, &conn->write_pdu_list, tailq) {
# # # # #
# # # #
# ]
461 [ + + + + : 17 : if (pdu->task && lun == pdu->task->scsi.lun) {
# # # # #
# # # # #
# # # # ]
462 : 2 : return false;
463 : : }
464 : 0 : }
465 : :
466 : 6 : return true;
467 : 0 : }
468 : :
469 : : static int
470 : 8 : iscsi_conn_remove_lun(void *ctx)
471 : : {
472 : 8 : struct spdk_iscsi_lun *iscsi_lun = ctx;
473 [ # # # # ]: 8 : struct spdk_iscsi_conn *conn = iscsi_lun->conn;
474 [ # # # # ]: 8 : struct spdk_scsi_lun *lun = iscsi_lun->lun;
475 : :
476 [ + + ]: 8 : if (!iscsi_conn_check_tasks_for_lun(conn, lun)) {
477 : 2 : 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 : 0 : int rc;
518 : 0 : 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 : 0 : int rc;
550 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : struct spdk_iscsi_pdu *pdu;
656 : 0 : struct spdk_iscsi_task *task;
657 : 0 : 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 : 702 : iscsi_get_active_conns(struct spdk_iscsi_tgt_node *target)
706 : : {
707 : 0 : struct spdk_iscsi_conn *conn;
708 : 702 : int num = 0;
709 : :
710 [ + + ]: 702 : if (g_conns_array == MAP_FAILED) {
711 : 0 : return 0;
712 : : }
713 : :
714 [ + + ]: 702 : pthread_mutex_lock(&g_conns_mutex);
715 [ - + # # : 702 : TAILQ_FOREACH(conn, &g_active_conns, conn_link) {
# # # # ]
716 [ # # # # : 0 : if (target == NULL || conn->target == target) {
# # # # ]
717 [ # # ]: 0 : num++;
718 : 0 : }
719 : 0 : }
720 [ + + ]: 702 : pthread_mutex_unlock(&g_conns_mutex);
721 : 702 : return num;
722 : 19 : }
723 : :
724 : : static void
725 : 544 : iscsi_conn_check_shutdown_cb(void *arg1)
726 : : {
727 : 544 : _iscsi_conns_cleanup();
728 : 544 : shutdown_iscsi_conns_done();
729 : 544 : }
730 : :
731 : : static int
732 : 544 : iscsi_conn_check_shutdown(void *arg)
733 : : {
734 [ - + ]: 544 : if (iscsi_get_active_conns(NULL) != 0) {
735 : 0 : return SPDK_POLLER_BUSY;
736 : : }
737 : :
738 : 544 : spdk_poller_unregister(&g_shutdown_timer);
739 : :
740 : 544 : spdk_thread_send_msg(spdk_get_thread(), iscsi_conn_check_shutdown_cb, NULL);
741 : :
742 : 544 : return SPDK_POLLER_BUSY;
743 : 19 : }
744 : :
745 : : static void
746 : 8 : iscsi_send_logout_request(struct spdk_iscsi_conn *conn)
747 : : {
748 : 0 : struct spdk_iscsi_pdu *rsp_pdu;
749 : 0 : 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 : 0 : }
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 : 0 : 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 : 706 : iscsi_conns_request_logout(struct spdk_iscsi_tgt_node *target, int pg_tag)
818 : : {
819 : 0 : struct spdk_iscsi_conn *conn;
820 : :
821 [ + + ]: 706 : if (g_conns_array == MAP_FAILED) {
822 : 0 : return;
823 : : }
824 : :
825 [ + + ]: 706 : pthread_mutex_lock(&g_conns_mutex);
826 [ + + # # : 714 : 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 [ + + ]: 706 : pthread_mutex_unlock(&g_conns_mutex);
833 [ # # ]: 19 : }
834 : :
835 : : void
836 : 544 : shutdown_iscsi_conns(void)
837 : : {
838 : 544 : iscsi_conns_request_logout(NULL, -1);
839 : :
840 : 544 : g_shutdown_timer = SPDK_POLLER_REGISTER(iscsi_conn_check_shutdown, NULL, 1000);
841 : 544 : }
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 : 0 : struct spdk_iscsi_conn *xconn;
861 : 0 : const char *xconn_match;
862 : 0 : struct spdk_thread *thread;
863 : 0 : 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 [ + + # # : 1521 : TAILQ_FOREACH(xconn, &g_active_conns, conn_link) {
# # # # ]
874 [ + + ]: 1361 : if (xconn == conn) {
875 : 160 : continue;
876 : : }
877 : :
878 [ + - + + : 1201 : if (!drop_all && xconn->initiator_port == NULL) {
# # # # ]
879 : 1 : 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 : 0 : }
923 : :
924 : : static int
925 : 42 : _iscsi_conn_abort_queued_datain_task(struct spdk_iscsi_conn *conn,
926 : : struct spdk_iscsi_task *task)
927 : : {
928 : 7 : struct spdk_iscsi_task *subtask;
929 : 7 : uint32_t remaining_size;
930 : :
931 [ + + + - : 42 : if (conn->data_in_cnt >= g_iscsi.MaxLargeDataInPerConnection) {
+ - + + ]
932 : 12 : return -1;
933 : : }
934 : :
935 [ + + + - : 30 : assert(task->current_data_offset <= task->scsi.transfer_len);
+ - + - +
- + - #
# ]
936 : : /* Stop split and abort read I/O for remaining data. */
937 [ + - + - : 30 : if (task->current_data_offset < task->scsi.transfer_len) {
+ - + - +
- - + ]
938 [ - + - + : 30 : remaining_size = task->scsi.transfer_len - task->current_data_offset;
- + - + -
+ ]
939 : 30 : subtask = iscsi_task_get(conn, task, iscsi_task_cpl);
940 [ + + # # ]: 30 : assert(subtask != NULL);
941 [ + - + - : 30 : subtask->scsi.offset = task->current_data_offset;
+ - + - +
- ]
942 [ + - + - : 30 : subtask->scsi.length = remaining_size;
+ - ]
943 [ + - ]: 30 : spdk_scsi_task_set_data(&subtask->scsi, NULL, 0);
944 [ + - + - : 30 : task->current_data_offset += subtask->scsi.length;
+ - + - +
- ]
945 : :
946 [ + - + - : 30 : subtask->scsi.transfer_len = subtask->scsi.length;
+ - + - +
- + - ]
947 [ + - ]: 30 : spdk_scsi_task_process_abort(&subtask->scsi);
948 [ + - ]: 30 : iscsi_task_cpl(&subtask->scsi);
949 : 5 : }
950 : :
951 : : /* Remove the primary task from the list because all subtasks are submitted
952 : : * or aborted.
953 : : */
954 [ + + + - : 30 : assert(task->current_data_offset == task->scsi.transfer_len);
+ - + - +
- + - #
# ]
955 [ + + + - : 30 : TAILQ_REMOVE(&conn->queued_datain_tasks, task, link);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
956 : 30 : return 0;
957 : 7 : }
958 : :
959 : : int
960 : 0 : iscsi_conn_abort_queued_datain_task(struct spdk_iscsi_conn *conn,
961 : : uint32_t ref_task_tag)
962 : : {
963 : 0 : 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 : 24 : 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 : 8 : struct spdk_iscsi_task *task, *task_tmp;
980 : 8 : struct spdk_iscsi_pdu *pdu_tmp;
981 : 8 : int rc;
982 : :
983 [ + + + - : 90 : TAILQ_FOREACH_SAFE(task, &conn->queued_datain_tasks, link, task_tmp) {
+ - + + +
- + - + -
+ + ]
984 : 72 : pdu_tmp = iscsi_task_get_pdu(task);
985 [ + + + + : 78 : if ((lun == NULL || lun == task->scsi.lun) &&
+ - + - +
+ ]
986 [ + + + - : 39 : (pdu == NULL || (spdk_sn32_lt(pdu_tmp->cmd_sn, pdu->cmd_sn)))) {
+ - + - +
- ]
987 : 24 : rc = _iscsi_conn_abort_queued_datain_task(conn, task);
988 [ + + ]: 24 : if (rc != 0) {
989 : 0 : return rc;
990 : : }
991 : 3 : }
992 : 11 : }
993 : :
994 : 18 : return 0;
995 : 2 : }
996 : :
997 : : int
998 : 16434057 : iscsi_conn_handle_queued_datain_tasks(struct spdk_iscsi_conn *conn)
999 : : {
1000 : 0 : struct spdk_iscsi_task *task;
1001 : :
1002 [ + + # # : 33517138 : while (!TAILQ_EMPTY(&conn->queued_datain_tasks) &&
# # # # #
# ]
1003 [ + + # # : 705764 : conn->data_in_cnt < g_iscsi.MaxLargeDataInPerConnection) {
# # ]
1004 [ # # # # : 649047 : task = TAILQ_FIRST(&conn->queued_datain_tasks);
# # ]
1005 [ - + # # : 649047 : assert(task->current_data_offset <= task->scsi.transfer_len);
# # # # #
# # # #
# ]
1006 [ + - # # : 649047 : if (task->current_data_offset < task->scsi.transfer_len) {
# # # # #
# # # ]
1007 : 0 : struct spdk_iscsi_task *subtask;
1008 : 649047 : uint32_t remaining_size = 0;
1009 : :
1010 [ # # # # : 649047 : remaining_size = task->scsi.transfer_len - task->current_data_offset;
# # # # #
# ]
1011 : 649047 : subtask = iscsi_task_get(conn, task, iscsi_task_cpl);
1012 [ - + # # ]: 649047 : assert(subtask != NULL);
1013 [ # # # # : 649047 : subtask->scsi.offset = task->current_data_offset;
# # # # #
# ]
1014 [ # # ]: 649047 : spdk_scsi_task_set_data(&subtask->scsi, NULL, 0);
1015 : :
1016 [ + + # # : 649047 : if (spdk_scsi_dev_get_lun(conn->dev, task->lun_id) == NULL) {
# # # # #
# ]
1017 : : /* Stop submitting split read I/Os for remaining data. */
1018 [ + + # # : 23 : TAILQ_REMOVE(&conn->queued_datain_tasks, task, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1019 [ # # # # ]: 23 : task->current_data_offset += remaining_size;
1020 [ - + # # : 23 : assert(task->current_data_offset == task->scsi.transfer_len);
# # # # #
# # # #
# ]
1021 [ # # # # : 23 : subtask->scsi.transfer_len = remaining_size;
# # ]
1022 [ # # ]: 23 : spdk_scsi_task_process_null_lun(&subtask->scsi);
1023 [ # # ]: 23 : iscsi_task_cpl(&subtask->scsi);
1024 : 23 : return 0;
1025 : : }
1026 : :
1027 [ # # # # : 649024 : subtask->scsi.length = spdk_min(SPDK_BDEV_LARGE_BUF_MAX_SIZE, remaining_size);
# # # # ]
1028 [ # # # # : 649024 : task->current_data_offset += subtask->scsi.length;
# # # # #
# ]
1029 : 649024 : iscsi_queue_task(conn, subtask);
1030 [ # # ]: 0 : }
1031 [ + + # # : 649024 : if (task->current_data_offset == task->scsi.transfer_len) {
# # # # #
# # # ]
1032 [ + + # # : 295710 : TAILQ_REMOVE(&conn->queued_datain_tasks, task, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1033 : 0 : }
1034 : : }
1035 : 16434034 : return 0;
1036 : 0 : }
1037 : :
1038 : : void
1039 : 6 : iscsi_task_mgmt_cpl(struct spdk_scsi_task *scsi_task)
1040 : : {
1041 : 6 : struct spdk_iscsi_task *task = iscsi_task_from_scsi_task(scsi_task);
1042 : :
1043 [ # # # # ]: 6 : iscsi_task_mgmt_response(task->conn, task);
1044 : 6 : iscsi_task_put(task);
1045 : 6 : }
1046 : :
1047 : : static void
1048 : 619279 : process_completed_read_subtask_list_in_order(struct spdk_iscsi_conn *conn,
1049 : : struct spdk_iscsi_task *primary)
1050 : : {
1051 : 16 : struct spdk_iscsi_task *subtask, *tmp;
1052 : :
1053 [ + + + - : 1268482 : TAILQ_FOREACH_SAFE(subtask, &primary->subtask_list, subtask_link, tmp) {
+ - + + +
- + - + -
+ + ]
1054 [ + + + - : 649225 : if (subtask->scsi.offset == primary->bytes_completed) {
+ - + - +
- + - ]
1055 [ + + + - : 649203 : TAILQ_REMOVE(&primary->subtask_list, subtask, subtask_link);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - ]
1056 [ + - + - : 649203 : primary->bytes_completed += subtask->scsi.length;
+ - + - +
- ]
1057 [ + + + - : 649203 : if (primary->bytes_completed == primary->scsi.transfer_len) {
+ - + - +
- + + ]
1058 : 295775 : iscsi_task_put(primary);
1059 : 7 : }
1060 : 649203 : iscsi_task_response(conn, subtask);
1061 : 649203 : iscsi_task_put(subtask);
1062 : 26 : } else {
1063 : 22 : break;
1064 : : }
1065 : 26 : }
1066 : 619279 : }
1067 : :
1068 : : static void
1069 : 16141010 : process_read_task_completion(struct spdk_iscsi_conn *conn,
1070 : : struct spdk_iscsi_task *task,
1071 : : struct spdk_iscsi_task *primary)
1072 : : {
1073 : 27 : struct spdk_iscsi_task *tmp;
1074 : :
1075 [ + + + - : 16141010 : if (task->scsi.status != SPDK_SCSI_STATUS_GOOD) {
+ - + + ]
1076 [ + + + - : 2618 : 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 [ + + + - : 41 : TAILQ_FOREACH(tmp, &primary->subtask_list, subtask_link) {
+ - + + +
- + - +
- ]
1082 [ + - + - ]: 12 : spdk_scsi_task_copy_status(&tmp->scsi, &task->scsi);
1083 : 2 : }
1084 [ + - + - ]: 29 : spdk_scsi_task_copy_status(&primary->scsi, &task->scsi);
1085 : 1 : }
1086 [ + + + - : 16138393 : } 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 [ + - + - ]: 18 : spdk_scsi_task_copy_status(&task->scsi, &primary->scsi);
1092 : 3 : }
1093 : :
1094 [ + + ]: 16141010 : 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 [ # # # # : 15491801 : primary->bytes_completed = task->scsi.length;
# # # # #
# ]
1101 [ - + # # : 15491801 : assert(primary->bytes_completed == task->scsi.transfer_len);
# # # # #
# # # #
# ]
1102 : 15491801 : iscsi_task_response(conn, task);
1103 : 15491801 : iscsi_task_put(task);
1104 [ + + + + : 649209 : } 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 [ + + + - : 649209 : if (task->scsi.offset != primary->bytes_completed) {
+ - + - +
- + + ]
1119 [ + + + - : 30024 : TAILQ_FOREACH(tmp, &primary->subtask_list, subtask_link) {
+ - + + #
# # # #
# ]
1120 [ + + + - : 604 : if (task->scsi.offset < tmp->scsi.offset) {
+ - + - +
- + - +
- ]
1121 [ + - + - : 510 : TAILQ_INSERT_BEFORE(tmp, task, subtask_link);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
1122 : 510 : return;
1123 : : }
1124 : 0 : }
1125 : :
1126 [ + - + - : 29420 : TAILQ_INSERT_TAIL(&primary->subtask_list, task, subtask_link);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
1127 : 3 : } else {
1128 [ + + + - : 619279 : TAILQ_INSERT_HEAD(&primary->subtask_list, task, subtask_link);
+ - + - +
- + - + +
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
1129 : 619279 : process_completed_read_subtask_list_in_order(conn, primary);
1130 : : }
1131 : : }
1132 [ - + ]: 27 : }
1133 : :
1134 : : static void
1135 : 13699038 : process_non_read_task_completion(struct spdk_iscsi_conn *conn,
1136 : : struct spdk_iscsi_task *task,
1137 : : struct spdk_iscsi_task *primary)
1138 : : {
1139 [ + - + - : 13699038 : primary->bytes_completed += task->scsi.length;
+ - + - +
- ]
1140 : :
1141 [ + + ]: 13699038 : if (task == primary) {
1142 : : /* This was a small write with no R2T. */
1143 : 12525790 : iscsi_task_response(conn, task);
1144 : 12525790 : iscsi_task_put(task);
1145 : 12525790 : return;
1146 : : }
1147 : :
1148 [ + + + - : 1173248 : if (task->scsi.status == SPDK_SCSI_STATUS_GOOD) {
+ - + + ]
1149 [ + - + - : 1173242 : primary->scsi.data_transferred += task->scsi.data_transferred;
+ - + - +
- + - ]
1150 [ + - + - : 9 : } 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 [ + - + - ]: 6 : spdk_scsi_task_copy_status(&primary->scsi, &task->scsi);
1155 : 1 : }
1156 : :
1157 [ + + + - : 1173248 : 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 [ + + + + : 625582 : if (primary->is_r2t_active) {
+ - + + ]
1166 : 625576 : iscsi_task_response(conn, primary);
1167 [ + - + - ]: 625576 : iscsi_del_transfer_task(conn, primary->tag);
1168 : 1 : } else {
1169 : 6 : iscsi_task_response(conn, task);
1170 : : }
1171 : 2 : }
1172 : 1173248 : iscsi_task_put(task);
1173 : 4 : }
1174 : :
1175 : : void
1176 : 29839892 : iscsi_task_cpl(struct spdk_scsi_task *scsi_task)
1177 : : {
1178 : 5 : struct spdk_iscsi_task *primary;
1179 : 29839892 : struct spdk_iscsi_task *task = iscsi_task_from_scsi_task(scsi_task);
1180 [ + - + - ]: 29839892 : struct spdk_iscsi_conn *conn = task->conn;
1181 [ + - + - ]: 29839892 : struct spdk_iscsi_pdu *pdu = task->pdu;
1182 : :
1183 [ + + + + : 29839892 : spdk_trace_record(TRACE_ISCSI_TASK_DONE, conn->id, 0, (uintptr_t)task);
# # # # #
# # # # #
# # # # #
# # # ]
1184 : :
1185 [ + - + - ]: 29839892 : task->is_queued = false;
1186 : 29839892 : primary = iscsi_task_get_primary(task);
1187 : :
1188 [ + + ]: 29839892 : if (iscsi_task_is_read(primary)) {
1189 : 16140878 : process_read_task_completion(conn, task, primary);
1190 : 5 : } else {
1191 : 13699014 : process_non_read_task_completion(conn, task, primary);
1192 : : }
1193 [ + + + - : 29839892 : if (!task->parent) {
+ - ]
1194 [ + - + + : 29190815 : spdk_trace_record(TRACE_ISCSI_PDU_COMPLETED, 0, 0, (uintptr_t)pdu);
# # # # #
# # # # #
# # # # ]
1195 : 0 : }
1196 : 29839892 : }
1197 : :
1198 : : static void
1199 : 62 : iscsi_conn_send_nopin(struct spdk_iscsi_conn *conn)
1200 : : {
1201 : 0 : struct spdk_iscsi_pdu *rsp_pdu;
1202 : 0 : struct iscsi_bhs_nop_in *rsp;
1203 : : /* Only send nopin if we have logged in and are in a normal session. */
1204 [ + - # # : 62 : if (conn->sess == NULL ||
# # # # ]
1205 [ + - - + : 124 : !conn->full_feature ||
# # ]
1206 [ # # # # : 62 : !iscsi_param_eq_val(conn->sess->params, "SessionType", "Normal")) {
# # # # ]
1207 : 0 : return;
1208 : : }
1209 [ - + - + : 62 : SPDK_DEBUGLOG(iscsi, "send NOPIN isid=%"PRIx64", tsih=%u, cid=%u\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1210 : : conn->sess->isid, conn->sess->tsih, conn->cid);
1211 [ - + - + : 62 : SPDK_DEBUGLOG(iscsi, "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1212 : : conn->StatSN, conn->sess->ExpCmdSN,
1213 : : conn->sess->MaxCmdSN);
1214 : 62 : rsp_pdu = iscsi_get_pdu(conn);
1215 [ # # ]: 62 : rsp = (struct iscsi_bhs_nop_in *) &rsp_pdu->bhs;
1216 [ # # # # ]: 62 : 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 [ # # ]: 62 : rsp->opcode = ISCSI_OP_NOPIN;
1222 [ # # # # ]: 62 : rsp->flags = 0x80;
1223 : : /*
1224 : : * Technically the to_be32() is not needed here, since
1225 : : * to_be32(0xFFFFFFFU) returns 0xFFFFFFFFU.
1226 : : */
1227 [ # # ]: 62 : to_be32(&rsp->itt, 0xFFFFFFFFU);
1228 [ # # # # : 62 : to_be32(&rsp->ttt, conn->id);
# # ]
1229 [ # # # # : 62 : to_be32(&rsp->stat_sn, conn->StatSN);
# # ]
1230 [ # # # # : 62 : to_be32(&rsp->exp_cmd_sn, conn->sess->ExpCmdSN);
# # # # #
# ]
1231 [ # # # # : 62 : to_be32(&rsp->max_cmd_sn, conn->sess->MaxCmdSN);
# # # # #
# ]
1232 : 62 : iscsi_conn_write_pdu(conn, rsp_pdu, iscsi_conn_pdu_generic_complete, NULL);
1233 [ # # # # ]: 62 : conn->last_nopin = spdk_get_ticks();
1234 [ # # # # ]: 62 : conn->nop_outstanding = true;
1235 [ # # ]: 0 : }
1236 : :
1237 : : void
1238 : 3641 : iscsi_conn_handle_nop(struct spdk_iscsi_conn *conn)
1239 : : {
1240 : 0 : 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 [ + - # # : 3641 : if ((conn->state == ISCSI_CONN_STATE_EXITED) ||
# # # # ]
1248 [ - + # # ]: 3641 : (conn->state == ISCSI_CONN_STATE_EXITING)) {
1249 : 0 : return;
1250 : : }
1251 : :
1252 : : /* Check for nop interval expiration */
1253 : 3641 : tsc = spdk_get_ticks();
1254 [ - + + + : 3641 : 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 [ + + # # : 3561 : } else if (tsc - conn->last_nopin > conn->nopininterval) {
# # # # #
# ]
1263 : 62 : 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 : 119948722 : iscsi_conn_read_data(struct spdk_iscsi_conn *conn, int bytes,
1281 : : void *buf)
1282 : : {
1283 : 0 : int ret;
1284 : :
1285 [ - + ]: 119948722 : if (bytes == 0) {
1286 : 0 : return 0;
1287 : : }
1288 : :
1289 [ # # # # ]: 119948722 : ret = spdk_sock_recv(conn->sock, buf, bytes);
1290 : :
1291 [ + + ]: 119948722 : if (ret > 0) {
1292 [ + - + + : 47771569 : spdk_trace_record(TRACE_ISCSI_READ_FROM_SOCKET_DONE, conn->id, ret, 0);
# # # # #
# # # # #
# # # # #
# # # ]
1293 : 47771569 : return ret;
1294 : : }
1295 : :
1296 [ + + ]: 72177153 : if (ret < 0) {
1297 [ + + - + : 72176643 : if (errno == EAGAIN || errno == EWOULDBLOCK) {
# # # # ]
1298 : 72176600 : return 0;
1299 : : }
1300 : :
1301 : : /* For connect reset issue, do not output error log */
1302 [ + - # # ]: 43 : if (errno == ECONNRESET) {
1303 [ - + - + : 43 : 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 : 0 : 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 : 2353 : iscsi_is_free_pdu_deferred(struct spdk_iscsi_pdu *pdu)
1358 : : {
1359 [ - + ]: 2353 : if (pdu == NULL) {
1360 : 0 : return false;
1361 : : }
1362 : :
1363 [ + + # # : 2353 : if (pdu->bhs.opcode == ISCSI_OP_R2T ||
# # # # ]
1364 [ + + # # ]: 2171 : pdu->bhs.opcode == ISCSI_OP_SCSI_DATAIN) {
1365 : 1474 : return true;
1366 : : }
1367 : :
1368 : 879 : 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 : 0 : uint32_t num_blocks;
1377 : 0 : 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 : 0 : }
1391 : :
1392 : : static void
1393 : 30404467 : _iscsi_conn_pdu_write_done(void *cb_arg, int err)
1394 : : {
1395 : 30404467 : struct spdk_iscsi_pdu *pdu = cb_arg;
1396 [ # # # # ]: 30404467 : struct spdk_iscsi_conn *conn = pdu->conn;
1397 : :
1398 [ - + # # ]: 30404467 : assert(conn != NULL);
1399 : :
1400 [ + + # # : 30404467 : if (spdk_unlikely(conn->state >= ISCSI_CONN_STATE_EXITING)) {
# # ]
1401 : : /* The other policy will recycle the resource */
1402 : 1 : return;
1403 : : }
1404 : :
1405 [ + + # # : 30404466 : TAILQ_REMOVE(&conn->write_pdu_list, pdu, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1406 : :
1407 [ + + ]: 30404466 : if (err != 0) {
1408 [ # # # # ]: 2 : conn->state = ISCSI_CONN_STATE_EXITING;
1409 : 0 : } else {
1410 [ + - + + : 30404464 : spdk_trace_record(TRACE_ISCSI_FLUSH_WRITEBUF_DONE, conn->id, pdu->mapped_length, (uintptr_t)pdu);
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1411 : : }
1412 : :
1413 [ + + # # : 30404466 : if ((conn->full_feature) &&
# # # # ]
1414 [ + + + + : 30405723 : (conn->sess->ErrorRecoveryLevel >= 1) &&
# # # # #
# ]
1415 : 2353 : 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 : 30402992 : iscsi_conn_free_pdu(conn, pdu);
1422 : : }
1423 [ # # ]: 0 : }
1424 : :
1425 : : void
1426 : 14260071 : iscsi_conn_pdu_generic_complete(void *cb_arg)
1427 : : {
1428 : 14260071 : }
1429 : :
1430 : : void
1431 : 30404467 : 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 : 0 : uint32_t crc32c;
1436 : 0 : ssize_t rc;
1437 : :
1438 [ - + - + : 30404467 : 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 [ + + # # : 30404467 : if (pdu->bhs.opcode != ISCSI_OP_LOGIN_RSP) {
# # ]
1448 : : /* Header Digest */
1449 [ + + # # : 30398945 : if (conn->header_digest) {
# # ]
1450 : 264745 : crc32c = iscsi_pdu_calc_header_digest(pdu);
1451 [ # # # # : 264745 : MAKE_DIGEST_WORD(pdu->header_digest, crc32c);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1452 : 0 : }
1453 : :
1454 : : /* Data Digest */
1455 [ - + - - : 30398945 : 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 [ # # # # ]: 30404467 : pdu->cb_fn = cb_fn;
1462 [ # # # # ]: 30404467 : pdu->cb_arg = cb_arg;
1463 [ # # # # : 30404467 : TAILQ_INSERT_TAIL(&conn->write_pdu_list, pdu, tailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1464 : :
1465 [ - + # # : 30404467 : if (spdk_unlikely(conn->state >= ISCSI_CONN_STATE_EXITING)) {
# # ]
1466 : 0 : return;
1467 : : }
1468 [ # # # # : 30404467 : pdu->sock_req.iovcnt = iscsi_build_iovs(conn, pdu->iov, SPDK_COUNTOF(pdu->iov), pdu,
# # # # ]
1469 [ # # ]: 30404467 : &pdu->mapped_length);
1470 [ # # # # : 30404467 : pdu->sock_req.cb_fn = _iscsi_conn_pdu_write_done;
# # ]
1471 [ # # # # : 30404467 : pdu->sock_req.cb_arg = pdu;
# # ]
1472 : :
1473 [ + - + + : 30404467 : spdk_trace_record(TRACE_ISCSI_FLUSH_WRITEBUF_START, conn->id, pdu->mapped_length, (uintptr_t)pdu,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1474 : : pdu->sock_req.iovcnt);
1475 [ # # # # : 30404467 : spdk_sock_writev_async(conn->sock, &pdu->sock_req);
# # ]
1476 [ # # ]: 0 : }
1477 : :
1478 : : static void
1479 : 75812397 : iscsi_conn_sock_cb(void *arg, struct spdk_sock_group *group, struct spdk_sock *sock)
1480 : : {
1481 : 75812397 : struct spdk_iscsi_conn *conn = arg;
1482 : 0 : int rc;
1483 : :
1484 [ - + # # ]: 75812397 : assert(conn != NULL);
1485 : :
1486 [ + - # # : 75812397 : if ((conn->state == ISCSI_CONN_STATE_EXITED) ||
# # # # ]
1487 [ - + # # ]: 75812397 : (conn->state == ISCSI_CONN_STATE_EXITING)) {
1488 : 0 : return;
1489 : : }
1490 : :
1491 : : /* Handle incoming PDUs */
1492 : 75812397 : rc = iscsi_handle_incoming_pdus(conn);
1493 [ + + ]: 75812397 : 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 : 0 : 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 : 0 : struct spdk_iscsi_poll_group *pg;
1532 : 0 : 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 : 0 : }
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 : 546 : iscsi_conn_trace(void)
1625 : : {
1626 : 546 : spdk_trace_register_owner(OWNER_ISCSI_CONN, 'c');
1627 : 546 : spdk_trace_register_object(OBJECT_ISCSI_PDU, 'p');
1628 : 546 : 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 : 546 : 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 : 546 : 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 : 546 : 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 : 546 : 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 : 546 : 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 : 546 : 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 : 546 : 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 : 546 : }
1653 : 592 : 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 : 0 : 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 : }
|