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