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