Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/bdev.h"
9 : : #include "spdk/env.h"
10 : : #include "spdk/fd.h"
11 : : #include "spdk/thread.h"
12 : : #include "spdk/json.h"
13 : : #include "spdk/util.h"
14 : : #include "spdk/rpc.h"
15 : : #include "spdk/string.h"
16 : : #include "spdk/iscsi_spec.h"
17 : :
18 : : #include "spdk/log.h"
19 : : #include "spdk/bdev_module.h"
20 : :
21 : : #include "iscsi/iscsi.h"
22 : : #include "iscsi/scsi-lowlevel.h"
23 : :
24 : : #include "bdev_iscsi.h"
25 : :
26 : : struct bdev_iscsi_lun;
27 : :
28 : : #define BDEV_ISCSI_CONNECTION_POLL_US 500 /* 0.5 ms */
29 : : #define BDEV_ISCSI_NO_MAIN_CH_POLL_US 10000 /* 10ms */
30 : :
31 : : #define BDEV_ISCSI_TIMEOUT_POLL_PERIOD_DEFAULT 1000000ULL /* 1 s */
32 : : #define BDEV_ISCSI_TIMEOUT_DEFAULT 30 /* 30 s */
33 : : #define BDEV_ISCSI_TIMEOUT_POLL_PERIOD_DIVISOR 30
34 : :
35 : : #define DEFAULT_INITIATOR_NAME "iqn.2016-06.io.spdk:init"
36 : :
37 : : /* MAXIMUM UNMAP LBA COUNT:
38 : : * indicates the maximum number of LBAs that may be unmapped
39 : : * by an UNMAP command.
40 : : */
41 : : #define BDEV_ISCSI_DEFAULT_MAX_UNMAP_LBA_COUNT (32768)
42 : :
43 : : /* MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT:
44 : : * indicates the maximum number of UNMAP block descriptors that
45 : : * shall be contained in the parameter data transferred to the
46 : : * device server for an UNMAP command.
47 : : */
48 : : #define BDEV_ISCSI_MAX_UNMAP_BLOCK_DESCS_COUNT (1)
49 : :
50 : : static int bdev_iscsi_initialize(void);
51 : : static void bdev_iscsi_readcapacity16(struct iscsi_context *context, struct bdev_iscsi_lun *lun);
52 : : static void _bdev_iscsi_submit_request(void *_bdev_io);
53 : :
54 : : static TAILQ_HEAD(, bdev_iscsi_conn_req) g_iscsi_conn_req = TAILQ_HEAD_INITIALIZER(
55 : : g_iscsi_conn_req);
56 : : static struct spdk_poller *g_conn_poller = NULL;
57 : :
58 : : struct bdev_iscsi_io {
59 : : struct spdk_thread *submit_td;
60 : : struct bdev_iscsi_lun *lun;
61 : : enum spdk_bdev_io_status status;
62 : : int scsi_status;
63 : : enum spdk_scsi_sense sk;
64 : : uint8_t asc;
65 : : uint8_t ascq;
66 : : };
67 : :
68 : : struct bdev_iscsi_lun {
69 : : struct spdk_bdev bdev;
70 : : struct iscsi_context *context;
71 : : char *initiator_iqn;
72 : : int lun_id;
73 : : char *url;
74 : : pthread_mutex_t mutex;
75 : : uint32_t ch_count;
76 : : struct spdk_thread *main_td;
77 : : struct spdk_poller *no_main_ch_poller;
78 : : struct spdk_thread *no_main_ch_poller_td;
79 : : bool unmap_supported;
80 : : uint32_t max_unmap;
81 : : struct spdk_poller *poller;
82 : : struct spdk_poller *timeout_poller;
83 : : };
84 : :
85 : : struct bdev_iscsi_io_channel {
86 : : struct bdev_iscsi_lun *lun;
87 : : };
88 : :
89 : : struct bdev_iscsi_conn_req {
90 : : char *url;
91 : : char *bdev_name;
92 : : char *initiator_iqn;
93 : : struct iscsi_context *context;
94 : : spdk_bdev_iscsi_create_cb create_cb;
95 : : void *create_cb_arg;
96 : : bool unmap_supported;
97 : : uint32_t max_unmap;
98 : : int lun;
99 : : int status;
100 : : TAILQ_ENTRY(bdev_iscsi_conn_req) link;
101 : : };
102 : :
103 : : static struct spdk_bdev_iscsi_opts g_opts = {
104 : : .timeout_sec = BDEV_ISCSI_TIMEOUT_DEFAULT,
105 : : .timeout_poller_period_us = BDEV_ISCSI_TIMEOUT_POLL_PERIOD_DEFAULT,
106 : : };
107 : :
108 : : void
109 : 243 : bdev_iscsi_get_opts(struct spdk_bdev_iscsi_opts *opts)
110 : : {
111 : 243 : *opts = g_opts;
112 : 243 : }
113 : :
114 : : int
115 : 243 : bdev_iscsi_set_opts(struct spdk_bdev_iscsi_opts *opts)
116 : : {
117 : : /* make the poller period equal to timeout / 30 */
118 : 243 : opts->timeout_poller_period_us = (opts->timeout_sec * 1000000ULL) /
119 : : BDEV_ISCSI_TIMEOUT_POLL_PERIOD_DIVISOR;
120 : :
121 : 243 : g_opts = *opts;
122 : :
123 : 243 : return 0;
124 : : }
125 : :
126 : : static void
127 : 9 : complete_conn_req(struct bdev_iscsi_conn_req *req, struct spdk_bdev *bdev,
128 : : int status)
129 : : {
130 [ - + ]: 9 : TAILQ_REMOVE(&g_iscsi_conn_req, req, link);
131 : 9 : req->create_cb(req->create_cb_arg, bdev, status);
132 : :
133 : : /*
134 : : * we are still running in the context of iscsi_service()
135 : : * so do not tear down its data structures here
136 : : */
137 : 9 : req->status = status;
138 : 9 : }
139 : :
140 : : static int
141 : 1962 : bdev_iscsi_get_ctx_size(void)
142 : : {
143 : 1962 : return sizeof(struct bdev_iscsi_io);
144 : : }
145 : :
146 : : static void
147 : 9 : _iscsi_free_lun(void *arg)
148 : : {
149 : 9 : struct bdev_iscsi_lun *lun = arg;
150 : :
151 [ - + ]: 9 : assert(lun != NULL);
152 : 9 : iscsi_destroy_context(lun->context);
153 [ - + ]: 9 : pthread_mutex_destroy(&lun->mutex);
154 : 9 : free(lun->bdev.name);
155 : 9 : free(lun->url);
156 : 9 : free(lun->initiator_iqn);
157 : :
158 : 9 : spdk_bdev_destruct_done(&lun->bdev, 0);
159 : 9 : free(lun);
160 : 9 : }
161 : :
162 : : static void
163 : 0 : _bdev_iscsi_conn_req_free(struct bdev_iscsi_conn_req *req)
164 : : {
165 : 0 : free(req->initiator_iqn);
166 : 0 : free(req->bdev_name);
167 : 0 : free(req->url);
168 : : /* destroy will call iscsi_disconnect() implicitly if connected */
169 : 0 : iscsi_destroy_context(req->context);
170 : 0 : free(req);
171 : 0 : }
172 : :
173 : : static void
174 : 1962 : bdev_iscsi_finish(void)
175 : : {
176 : : struct bdev_iscsi_conn_req *req, *tmp;
177 : :
178 : : /* clear out pending connection requests here. We cannot
179 : : * simply set the state to a non SCSI_STATUS_GOOD state as
180 : : * the connection poller won't run anymore
181 : : */
182 [ - + ]: 1962 : TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) {
183 : 0 : _bdev_iscsi_conn_req_free(req);
184 : : }
185 : :
186 [ - + ]: 1962 : if (g_conn_poller) {
187 : 0 : spdk_poller_unregister(&g_conn_poller);
188 : : }
189 : 1962 : }
190 : :
191 : : static void
192 : 162 : bdev_iscsi_opts_config_json(struct spdk_json_write_ctx *w)
193 : : {
194 : 162 : spdk_json_write_object_begin(w);
195 : :
196 : 162 : spdk_json_write_named_string(w, "method", "bdev_iscsi_set_options");
197 : :
198 : 162 : spdk_json_write_named_object_begin(w, "params");
199 : 162 : spdk_json_write_named_uint64(w, "timeout_sec", g_opts.timeout_sec);
200 : 162 : spdk_json_write_object_end(w);
201 : :
202 : 162 : spdk_json_write_object_end(w);
203 : 162 : }
204 : :
205 : : static int
206 : 162 : bdev_iscsi_config_json(struct spdk_json_write_ctx *w)
207 : : {
208 : 162 : bdev_iscsi_opts_config_json(w);
209 : 162 : return 0;
210 : : }
211 : :
212 : : static struct spdk_bdev_module g_iscsi_bdev_module = {
213 : : .name = "iscsi",
214 : : .module_init = bdev_iscsi_initialize,
215 : : .module_fini = bdev_iscsi_finish,
216 : : .config_json = bdev_iscsi_config_json,
217 : : .get_ctx_size = bdev_iscsi_get_ctx_size,
218 : : };
219 : :
220 : 2136 : SPDK_BDEV_MODULE_REGISTER(iscsi, &g_iscsi_bdev_module);
221 : :
222 : : static void
223 : 1476671 : _bdev_iscsi_io_complete(void *_iscsi_io)
224 : : {
225 : 1476671 : struct bdev_iscsi_io *iscsi_io = _iscsi_io;
226 : :
227 [ + - ]: 1476671 : if (iscsi_io->status == SPDK_BDEV_IO_STATUS_SUCCESS) {
228 : 1476671 : spdk_bdev_io_complete_scsi_status(spdk_bdev_io_from_ctx(iscsi_io), iscsi_io->scsi_status,
229 : 1476671 : iscsi_io->sk, iscsi_io->asc, iscsi_io->ascq);
230 : : } else {
231 : 0 : spdk_bdev_io_complete(spdk_bdev_io_from_ctx(iscsi_io), iscsi_io->status);
232 : : }
233 : 1476671 : }
234 : :
235 : : static void
236 : 1476671 : bdev_iscsi_io_complete(struct bdev_iscsi_io *iscsi_io, enum spdk_bdev_io_status status)
237 : : {
238 : 1476671 : iscsi_io->status = status;
239 [ - + ]: 1476671 : if (iscsi_io->submit_td != NULL) {
240 : 0 : spdk_thread_send_msg(iscsi_io->submit_td, _bdev_iscsi_io_complete, iscsi_io);
241 : : } else {
242 : 1476671 : _bdev_iscsi_io_complete(iscsi_io);
243 : : }
244 : 1476671 : }
245 : :
246 : : static bool
247 : 1476672 : _bdev_iscsi_is_size_change(int status, struct scsi_task *task)
248 : : {
249 [ + + ]: 1476672 : if (status == SPDK_SCSI_STATUS_CHECK_CONDITION &&
250 [ + - ]: 1 : (uint8_t)task->sense.key == SPDK_SCSI_SENSE_UNIT_ATTENTION &&
251 [ + - ]: 1 : task->sense.ascq == 0x2a09) {
252 : : /* ASCQ: SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED (0x2a09) */
253 : 1 : return true;
254 : : }
255 : :
256 : 1476671 : return false;
257 : : }
258 : :
259 : : /* Common call back function for read/write/flush command */
260 : : static void
261 : 1476672 : bdev_iscsi_command_cb(struct iscsi_context *context, int status, void *_task, void *_iscsi_io)
262 : : {
263 : 1476672 : struct scsi_task *task = _task;
264 : 1476672 : struct bdev_iscsi_io *iscsi_io = _iscsi_io;
265 : : struct spdk_bdev_io *bdev_io;
266 : :
267 : 1476672 : iscsi_io->scsi_status = status;
268 : 1476672 : iscsi_io->sk = (uint8_t)task->sense.key;
269 : 1476672 : iscsi_io->asc = (task->sense.ascq >> 8) & 0xFF;
270 : 1476672 : iscsi_io->ascq = task->sense.ascq & 0xFF;
271 : :
272 [ + + ]: 1476672 : if (_bdev_iscsi_is_size_change(status, task)) {
273 : 1 : bdev_iscsi_readcapacity16(context, iscsi_io->lun);
274 : :
275 : : /* Retry this failed IO immediately */
276 : 1 : bdev_io = spdk_bdev_io_from_ctx(iscsi_io);
277 [ - + ]: 1 : if (iscsi_io->submit_td != NULL) {
278 : 0 : spdk_thread_send_msg(iscsi_io->lun->main_td,
279 : : _bdev_iscsi_submit_request, bdev_io);
280 : : } else {
281 : 1 : _bdev_iscsi_submit_request(bdev_io);
282 : : }
283 : : } else {
284 : 1476671 : bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_SUCCESS);
285 : : }
286 : :
287 : 1476672 : scsi_free_scsi_task(task);
288 : 1476672 : }
289 : :
290 : : static int
291 : 1 : bdev_iscsi_resize(struct spdk_bdev *bdev, const uint64_t new_size_in_block)
292 : : {
293 : : int rc;
294 : :
295 [ - + ]: 1 : assert(bdev->module == &g_iscsi_bdev_module);
296 : :
297 [ - + ]: 1 : if (new_size_in_block <= bdev->blockcnt) {
298 : 0 : SPDK_ERRLOG("The new bdev size must be larger than current bdev size.\n");
299 : 0 : return -EINVAL;
300 : : }
301 : :
302 : 1 : rc = spdk_bdev_notify_blockcnt_change(bdev, new_size_in_block);
303 [ - + ]: 1 : if (rc != 0) {
304 : 0 : SPDK_ERRLOG("failed to notify block cnt change.\n");
305 : 0 : return rc;
306 : : }
307 : :
308 : 1 : return 0;
309 : : }
310 : :
311 : : static void
312 : 1 : bdev_iscsi_readcapacity16_cb(struct iscsi_context *context, int status, void *_task,
313 : : void *private_data)
314 : : {
315 : 1 : struct bdev_iscsi_lun *lun = private_data;
316 : : struct scsi_readcapacity16 *readcap16;
317 : 1 : struct scsi_task *task = _task;
318 : 1 : uint64_t size_in_block = 0;
319 : : int rc;
320 : :
321 [ - + ]: 1 : if (status != SPDK_SCSI_STATUS_GOOD) {
322 : 0 : SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(context));
323 : 0 : goto ret;
324 : : }
325 : :
326 : 1 : readcap16 = scsi_datain_unmarshall(task);
327 [ - + ]: 1 : if (!readcap16) {
328 : 0 : SPDK_ERRLOG("Read capacity error\n");
329 : 0 : goto ret;
330 : : }
331 : :
332 : 1 : size_in_block = readcap16->returned_lba + 1;
333 : :
334 : 1 : rc = bdev_iscsi_resize(&lun->bdev, size_in_block);
335 [ + - ]: 1 : if (rc != 0) {
336 : 0 : SPDK_ERRLOG("Bdev (%s) resize error: %d\n", lun->bdev.name, rc);
337 : : }
338 : :
339 : 1 : ret:
340 : 1 : scsi_free_scsi_task(task);
341 : 1 : }
342 : :
343 : : static void
344 : 1 : bdev_iscsi_readcapacity16(struct iscsi_context *context, struct bdev_iscsi_lun *lun)
345 : : {
346 : : struct scsi_task *task;
347 : :
348 : 1 : task = iscsi_readcapacity16_task(context, lun->lun_id,
349 : : bdev_iscsi_readcapacity16_cb, lun);
350 [ - + ]: 1 : if (task == NULL) {
351 : 0 : SPDK_ERRLOG("failed to get readcapacity16_task\n");
352 : : }
353 : 1 : }
354 : :
355 : : static void
356 : 568064 : bdev_iscsi_readv(struct bdev_iscsi_lun *lun, struct bdev_iscsi_io *iscsi_io,
357 : : struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t lba)
358 : : {
359 : : struct scsi_task *task;
360 : :
361 [ - + - + ]: 568064 : SPDK_DEBUGLOG(iscsi_init, "read %d iovs size %lu to lba: %#lx\n",
362 : : iovcnt, nbytes, lba);
363 : :
364 : 568064 : task = iscsi_read16_task(lun->context, lun->lun_id, lba, nbytes, lun->bdev.blocklen, 0, 0, 0, 0, 0,
365 : : bdev_iscsi_command_cb, iscsi_io);
366 [ - + ]: 568064 : if (task == NULL) {
367 : 0 : SPDK_ERRLOG("failed to get read16_task\n");
368 : 0 : bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
369 : 0 : return;
370 : : }
371 : :
372 : : #if defined(LIBISCSI_FEATURE_IOVECTOR)
373 : 568064 : scsi_task_set_iov_in(task, (struct scsi_iovec *)iov, iovcnt);
374 : : #else
375 : : int i;
376 : : for (i = 0; i < iovcnt; i++) {
377 : : scsi_task_add_data_in_buffer(task, iov[i].iov_len, iov[i].iov_base);
378 : : }
379 : : #endif
380 : : }
381 : :
382 : : static void
383 : 309417 : bdev_iscsi_writev(struct bdev_iscsi_lun *lun, struct bdev_iscsi_io *iscsi_io,
384 : : struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t lba)
385 : : {
386 : : struct scsi_task *task;
387 : :
388 [ - + - + ]: 309417 : SPDK_DEBUGLOG(iscsi_init, "write %d iovs size %lu to lba: %#lx\n",
389 : : iovcnt, nbytes, lba);
390 : :
391 : 309417 : task = iscsi_write16_task(lun->context, lun->lun_id, lba, NULL, nbytes, lun->bdev.blocklen, 0, 0, 0,
392 : : 0, 0,
393 : : bdev_iscsi_command_cb, iscsi_io);
394 [ - + ]: 309417 : if (task == NULL) {
395 : 0 : SPDK_ERRLOG("failed to get write16_task\n");
396 : 0 : bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
397 : 0 : return;
398 : : }
399 : :
400 : : #if defined(LIBISCSI_FEATURE_IOVECTOR)
401 : 309417 : scsi_task_set_iov_out(task, (struct scsi_iovec *)iov, iovcnt);
402 : : #else
403 : : int i;
404 : : for (i = 0; i < iovcnt; i++) {
405 : : scsi_task_add_data_in_buffer(task, iov[i].iov_len, iov[i].iov_base);
406 : : }
407 : : #endif
408 : : }
409 : :
410 : : static void
411 : 9 : bdev_iscsi_destruct_cb(void *ctx)
412 : : {
413 : 9 : struct bdev_iscsi_lun *lun = ctx;
414 : :
415 : 9 : spdk_poller_unregister(&lun->no_main_ch_poller);
416 : 9 : spdk_io_device_unregister(lun, _iscsi_free_lun);
417 : 9 : }
418 : :
419 : : static int
420 : 9 : bdev_iscsi_destruct(void *ctx)
421 : : {
422 : 9 : struct bdev_iscsi_lun *lun = ctx;
423 : :
424 [ - + ]: 9 : assert(lun->no_main_ch_poller_td);
425 : 9 : spdk_thread_send_msg(lun->no_main_ch_poller_td, bdev_iscsi_destruct_cb, lun);
426 : 9 : return 1;
427 : : }
428 : :
429 : : static void
430 : 345654 : bdev_iscsi_flush(struct bdev_iscsi_lun *lun, struct bdev_iscsi_io *iscsi_io, uint32_t num_blocks,
431 : : int immed, uint64_t lba)
432 : : {
433 : : struct scsi_task *task;
434 : :
435 : 345654 : task = iscsi_synchronizecache16_task(lun->context, lun->lun_id, lba,
436 : : num_blocks, 0, immed, bdev_iscsi_command_cb, iscsi_io);
437 [ - + ]: 345654 : if (task == NULL) {
438 : 0 : SPDK_ERRLOG("failed to get sync16_task\n");
439 : 0 : bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
440 : 0 : return;
441 : : }
442 : : }
443 : :
444 : : static void
445 : 253537 : bdev_iscsi_unmap(struct bdev_iscsi_lun *lun, struct bdev_iscsi_io *iscsi_io,
446 : : uint64_t lba, uint64_t num_blocks)
447 : : {
448 : : struct scsi_task *task;
449 : 253537 : struct unmap_list list[BDEV_ISCSI_MAX_UNMAP_BLOCK_DESCS_COUNT] = {};
450 : : struct unmap_list *entry;
451 : : uint32_t num_unmap_list;
452 : : uint64_t offset, remaining, unmap_blocks;
453 : :
454 : 253537 : num_unmap_list = spdk_divide_round_up(num_blocks, lun->max_unmap);
455 [ - + ]: 253537 : if (num_unmap_list > BDEV_ISCSI_MAX_UNMAP_BLOCK_DESCS_COUNT) {
456 : 0 : SPDK_ERRLOG("Too many unmap entries\n");
457 : 0 : goto failed;
458 : : }
459 : :
460 : 253537 : remaining = num_blocks;
461 : 253537 : offset = lba;
462 : 253537 : num_unmap_list = 0;
463 : 253537 : entry = &list[0];
464 : :
465 : : do {
466 : 253537 : unmap_blocks = spdk_min(remaining, lun->max_unmap);
467 : 253537 : entry->lba = offset;
468 : 253537 : entry->num = unmap_blocks;
469 : 253537 : num_unmap_list++;
470 : 253537 : remaining -= unmap_blocks;
471 : 253537 : offset += unmap_blocks;
472 : 253537 : entry++;
473 [ - + ]: 253537 : } while (remaining > 0);
474 : :
475 : 253537 : task = iscsi_unmap_task(lun->context, lun->lun_id, 0, 0, list, num_unmap_list,
476 : : bdev_iscsi_command_cb, iscsi_io);
477 [ + - ]: 253537 : if (task != NULL) {
478 : 253537 : return;
479 : : }
480 : 0 : SPDK_ERRLOG("failed to get unmap_task\n");
481 : :
482 : 0 : failed:
483 : 0 : bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
484 : : }
485 : :
486 : : static void
487 : 0 : bdev_iscsi_reset_cb(struct iscsi_context *context __attribute__((unused)), int status,
488 : : void *command_data, void *private_data)
489 : : {
490 : : uint32_t tmf_response;
491 : 0 : struct bdev_iscsi_io *iscsi_io = private_data;
492 : :
493 : 0 : tmf_response = *(uint32_t *)command_data;
494 [ # # ]: 0 : if (tmf_response == ISCSI_TASK_FUNC_RESP_COMPLETE) {
495 : 0 : bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_SUCCESS);
496 : : } else {
497 : 0 : bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
498 : : }
499 : 0 : }
500 : :
501 : : static void
502 : 0 : _bdev_iscsi_reset(void *_bdev_io)
503 : : {
504 : : int rc;
505 : 0 : struct spdk_bdev_io *bdev_io = _bdev_io;
506 : 0 : struct bdev_iscsi_lun *lun = (struct bdev_iscsi_lun *)bdev_io->bdev->ctxt;
507 : 0 : struct bdev_iscsi_io *iscsi_io = (struct bdev_iscsi_io *)bdev_io->driver_ctx;
508 : 0 : struct iscsi_context *context = lun->context;
509 : :
510 : 0 : rc = iscsi_task_mgmt_lun_reset_async(context, lun->lun_id,
511 : : bdev_iscsi_reset_cb, iscsi_io);
512 [ # # ]: 0 : if (rc != 0) {
513 : 0 : SPDK_ERRLOG("failed to do iscsi reset\n");
514 : 0 : bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
515 : 0 : return;
516 : : }
517 : : }
518 : :
519 : : static void
520 : 0 : bdev_iscsi_reset(struct spdk_bdev_io *bdev_io)
521 : : {
522 : 0 : struct bdev_iscsi_lun *lun = (struct bdev_iscsi_lun *)bdev_io->bdev->ctxt;
523 : 0 : spdk_thread_send_msg(lun->main_td, _bdev_iscsi_reset, bdev_io);
524 : 0 : }
525 : :
526 : : static int
527 : 2503744 : bdev_iscsi_poll_lun(void *_lun)
528 : : {
529 : 2503744 : struct bdev_iscsi_lun *lun = _lun;
530 : 2503744 : struct pollfd pfd = {};
531 : :
532 : 2503744 : pfd.fd = iscsi_get_fd(lun->context);
533 : 2503744 : pfd.events = iscsi_which_events(lun->context);
534 : :
535 [ - + ]: 2503744 : if (poll(&pfd, 1, 0) < 0) {
536 : 0 : SPDK_ERRLOG("poll failed\n");
537 : 0 : return SPDK_POLLER_IDLE;
538 : : }
539 : :
540 [ + + ]: 2503744 : if (pfd.revents != 0) {
541 [ - + ]: 226291 : if (iscsi_service(lun->context, pfd.revents) < 0) {
542 : 0 : SPDK_ERRLOG("iscsi_service failed: %s\n", iscsi_get_error(lun->context));
543 : : }
544 : :
545 : 226291 : return SPDK_POLLER_BUSY;
546 : : }
547 : :
548 : 2277453 : return SPDK_POLLER_IDLE;
549 : : }
550 : :
551 : : static int
552 : 34 : bdev_iscsi_poll_lun_timeout(void *_lun)
553 : : {
554 : 34 : struct bdev_iscsi_lun *lun = _lun;
555 : : /* passing 0 here to iscsi_service means do nothing except for timeout checks */
556 : 34 : iscsi_service(lun->context, 0);
557 : 34 : return SPDK_POLLER_BUSY;
558 : : }
559 : :
560 : : static int
561 : 3635 : bdev_iscsi_no_main_ch_poll(void *arg)
562 : : {
563 : 3635 : struct bdev_iscsi_lun *lun = arg;
564 : 3635 : enum spdk_thread_poller_rc rc = SPDK_POLLER_IDLE;
565 : :
566 [ - + - + ]: 3635 : if (pthread_mutex_trylock(&lun->mutex)) {
567 : : /* Don't care about the error code here. */
568 : 0 : return SPDK_POLLER_IDLE;
569 : : }
570 : :
571 [ + + ]: 3635 : if (lun->ch_count == 0) {
572 : 286 : rc = bdev_iscsi_poll_lun(arg);
573 : : }
574 : :
575 [ - + ]: 3635 : pthread_mutex_unlock(&lun->mutex);
576 : 3635 : return rc;
577 : : }
578 : :
579 : : static void
580 : 568064 : bdev_iscsi_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
581 : : bool success)
582 : : {
583 [ - + ]: 568064 : if (!success) {
584 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
585 : 0 : return;
586 : : }
587 : :
588 : 1704192 : bdev_iscsi_readv((struct bdev_iscsi_lun *)bdev_io->bdev->ctxt,
589 : 568064 : (struct bdev_iscsi_io *)bdev_io->driver_ctx,
590 : : bdev_io->u.bdev.iovs,
591 : : bdev_io->u.bdev.iovcnt,
592 : 568064 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
593 : : bdev_io->u.bdev.offset_blocks);
594 : : }
595 : :
596 : : static void
597 : 1476672 : _bdev_iscsi_submit_request(void *_bdev_io)
598 : : {
599 : 1476672 : struct spdk_bdev_io *bdev_io = _bdev_io;
600 : 1476672 : struct bdev_iscsi_io *iscsi_io = (struct bdev_iscsi_io *)bdev_io->driver_ctx;
601 : 1476672 : struct bdev_iscsi_lun *lun = (struct bdev_iscsi_lun *)bdev_io->bdev->ctxt;
602 : :
603 [ + + + - : 1476672 : switch (bdev_io->type) {
+ - ]
604 : 568064 : case SPDK_BDEV_IO_TYPE_READ:
605 : 568064 : spdk_bdev_io_get_buf(bdev_io, bdev_iscsi_get_buf_cb,
606 : 568064 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
607 : 568064 : break;
608 : :
609 : 309417 : case SPDK_BDEV_IO_TYPE_WRITE:
610 : 618834 : bdev_iscsi_writev(lun, iscsi_io,
611 : : bdev_io->u.bdev.iovs,
612 : : bdev_io->u.bdev.iovcnt,
613 : 309417 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
614 : : bdev_io->u.bdev.offset_blocks);
615 : 309417 : break;
616 : 345654 : case SPDK_BDEV_IO_TYPE_FLUSH:
617 : 345654 : bdev_iscsi_flush(lun, iscsi_io,
618 : 345654 : bdev_io->u.bdev.num_blocks,
619 : : ISCSI_IMMEDIATE_DATA_NO,
620 : : bdev_io->u.bdev.offset_blocks);
621 : 345654 : break;
622 : 0 : case SPDK_BDEV_IO_TYPE_RESET:
623 : 0 : bdev_iscsi_reset(bdev_io);
624 : 0 : break;
625 : 253537 : case SPDK_BDEV_IO_TYPE_UNMAP:
626 : 253537 : bdev_iscsi_unmap(lun, iscsi_io,
627 : : bdev_io->u.bdev.offset_blocks,
628 : : bdev_io->u.bdev.num_blocks);
629 : 253537 : break;
630 : 0 : default:
631 : 0 : bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
632 : 0 : break;
633 : : }
634 : 1476672 : }
635 : :
636 : : static void
637 : 1476671 : bdev_iscsi_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
638 : : {
639 : 1476671 : struct spdk_thread *submit_td = spdk_io_channel_get_thread(_ch);
640 : 1476671 : struct bdev_iscsi_io *iscsi_io = (struct bdev_iscsi_io *)bdev_io->driver_ctx;
641 : 1476671 : struct bdev_iscsi_lun *lun = (struct bdev_iscsi_lun *)bdev_io->bdev->ctxt;
642 : :
643 : 1476671 : iscsi_io->lun = lun;
644 : :
645 [ - + ]: 1476671 : if (lun->main_td != submit_td) {
646 : 0 : iscsi_io->submit_td = submit_td;
647 : 0 : spdk_thread_send_msg(lun->main_td, _bdev_iscsi_submit_request, bdev_io);
648 : 0 : return;
649 : : } else {
650 : 1476671 : iscsi_io->submit_td = NULL;
651 : : }
652 : :
653 : 1476671 : _bdev_iscsi_submit_request(bdev_io);
654 : : }
655 : :
656 : : static bool
657 : 71 : bdev_iscsi_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
658 : : {
659 : 71 : struct bdev_iscsi_lun *lun = ctx;
660 : :
661 [ + + + ]: 71 : switch (io_type) {
662 : 10 : case SPDK_BDEV_IO_TYPE_READ:
663 : : case SPDK_BDEV_IO_TYPE_WRITE:
664 : : case SPDK_BDEV_IO_TYPE_FLUSH:
665 : : case SPDK_BDEV_IO_TYPE_RESET:
666 : 10 : return true;
667 : :
668 : 4 : case SPDK_BDEV_IO_TYPE_UNMAP:
669 [ - + ]: 4 : return lun->unmap_supported;
670 : 57 : default:
671 : 57 : return false;
672 : : }
673 : : }
674 : :
675 : : static int
676 : 18 : bdev_iscsi_create_cb(void *io_device, void *ctx_buf)
677 : : {
678 : 18 : struct bdev_iscsi_io_channel *ch = ctx_buf;
679 : 18 : struct bdev_iscsi_lun *lun = io_device;
680 : :
681 [ - + ]: 18 : pthread_mutex_lock(&lun->mutex);
682 [ + - ]: 18 : if (lun->ch_count == 0) {
683 [ - + ]: 18 : assert(lun->main_td == NULL);
684 : 18 : lun->main_td = spdk_get_thread();
685 : 18 : lun->poller = SPDK_POLLER_REGISTER(bdev_iscsi_poll_lun, lun, 0);
686 [ + - ]: 18 : if (g_opts.timeout_sec > 0) {
687 : 18 : lun->timeout_poller = SPDK_POLLER_REGISTER(bdev_iscsi_poll_lun_timeout, lun,
688 : : g_opts.timeout_poller_period_us);
689 : : }
690 : 18 : ch->lun = lun;
691 : : }
692 : 18 : lun->ch_count++;
693 [ - + ]: 18 : pthread_mutex_unlock(&lun->mutex);
694 : :
695 : 18 : return 0;
696 : : }
697 : :
698 : : static void
699 : 0 : _iscsi_destroy_cb(void *ctx)
700 : : {
701 : 0 : struct bdev_iscsi_lun *lun = ctx;
702 : :
703 [ # # ]: 0 : pthread_mutex_lock(&lun->mutex);
704 : :
705 [ # # ]: 0 : assert(lun->main_td == spdk_get_thread());
706 [ # # ]: 0 : assert(lun->ch_count > 0);
707 : :
708 : 0 : lun->ch_count--;
709 [ # # ]: 0 : if (lun->ch_count > 0) {
710 [ # # ]: 0 : pthread_mutex_unlock(&lun->mutex);
711 : 0 : return;
712 : : }
713 : :
714 : 0 : lun->main_td = NULL;
715 : 0 : spdk_poller_unregister(&lun->poller);
716 : 0 : spdk_poller_unregister(&lun->timeout_poller);
717 : :
718 [ # # ]: 0 : pthread_mutex_unlock(&lun->mutex);
719 : : }
720 : :
721 : : static void
722 : 18 : bdev_iscsi_destroy_cb(void *io_device, void *ctx_buf)
723 : : {
724 : 18 : struct bdev_iscsi_lun *lun = io_device;
725 : : struct spdk_thread *thread;
726 : :
727 [ - + ]: 18 : pthread_mutex_lock(&lun->mutex);
728 : 18 : lun->ch_count--;
729 [ + - ]: 18 : if (lun->ch_count == 0) {
730 [ - + ]: 18 : assert(lun->main_td != NULL);
731 : :
732 [ - + ]: 18 : if (lun->main_td != spdk_get_thread()) {
733 : : /* The final channel was destroyed on a different thread
734 : : * than where the first channel was created. Pass a message
735 : : * to the main thread to unregister the poller. */
736 : 0 : lun->ch_count++;
737 : 0 : thread = lun->main_td;
738 [ # # ]: 0 : pthread_mutex_unlock(&lun->mutex);
739 : 0 : spdk_thread_send_msg(thread, _iscsi_destroy_cb, lun);
740 : 0 : return;
741 : : }
742 : :
743 : 18 : lun->main_td = NULL;
744 : 18 : spdk_poller_unregister(&lun->poller);
745 : 18 : spdk_poller_unregister(&lun->timeout_poller);
746 : : }
747 [ - + ]: 18 : pthread_mutex_unlock(&lun->mutex);
748 : : }
749 : :
750 : : static struct spdk_io_channel *
751 : 18 : bdev_iscsi_get_io_channel(void *ctx)
752 : : {
753 : 18 : struct bdev_iscsi_lun *lun = ctx;
754 : :
755 : 18 : return spdk_get_io_channel(lun);
756 : : }
757 : :
758 : : static int
759 : 2 : bdev_iscsi_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
760 : : {
761 : 2 : struct bdev_iscsi_lun *lun = ctx;
762 : :
763 : 2 : spdk_json_write_named_object_begin(w, "iscsi");
764 : 2 : spdk_json_write_named_string(w, "initiator_name", lun->initiator_iqn);
765 : 2 : spdk_json_write_named_string(w, "url", lun->url);
766 : 2 : spdk_json_write_object_end(w);
767 : :
768 : 2 : return 0;
769 : : }
770 : :
771 : : static void
772 : 0 : bdev_iscsi_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
773 : : {
774 : 0 : struct bdev_iscsi_lun *lun = bdev->ctxt;
775 : :
776 [ # # ]: 0 : pthread_mutex_lock(&lun->mutex);
777 : 0 : spdk_json_write_object_begin(w);
778 : :
779 : 0 : spdk_json_write_named_string(w, "method", "bdev_iscsi_create");
780 : :
781 : 0 : spdk_json_write_named_object_begin(w, "params");
782 : 0 : spdk_json_write_named_string(w, "name", bdev->name);
783 : 0 : spdk_json_write_named_string(w, "initiator_iqn", lun->initiator_iqn);
784 : 0 : spdk_json_write_named_string(w, "url", lun->url);
785 : 0 : spdk_json_write_object_end(w);
786 : :
787 : 0 : spdk_json_write_object_end(w);
788 [ # # ]: 0 : pthread_mutex_unlock(&lun->mutex);
789 : 0 : }
790 : :
791 : : static const struct spdk_bdev_fn_table iscsi_fn_table = {
792 : : .destruct = bdev_iscsi_destruct,
793 : : .submit_request = bdev_iscsi_submit_request,
794 : : .io_type_supported = bdev_iscsi_io_type_supported,
795 : : .get_io_channel = bdev_iscsi_get_io_channel,
796 : : .dump_info_json = bdev_iscsi_dump_info_json,
797 : : .write_config_json = bdev_iscsi_write_config_json,
798 : : };
799 : :
800 : : static int
801 : 9 : create_iscsi_lun(struct bdev_iscsi_conn_req *req, uint64_t num_blocks,
802 : : uint32_t block_size, struct spdk_bdev **bdev, uint8_t lbppbe)
803 : : {
804 : : struct bdev_iscsi_lun *lun;
805 : : int rc;
806 : :
807 : 9 : lun = calloc(1, sizeof(*lun));
808 [ - + ]: 9 : if (!lun) {
809 : 0 : SPDK_ERRLOG("Unable to allocate enough memory for iscsi backend\n");
810 : 0 : return -ENOMEM;
811 : : }
812 : :
813 : 9 : lun->context = req->context;
814 : 9 : lun->lun_id = req->lun;
815 : 9 : lun->url = req->url;
816 : 9 : lun->initiator_iqn = req->initiator_iqn;
817 : :
818 [ - + ]: 9 : pthread_mutex_init(&lun->mutex, NULL);
819 : :
820 : 9 : lun->bdev.name = req->bdev_name;
821 : 9 : lun->bdev.product_name = "iSCSI LUN";
822 : 9 : lun->bdev.module = &g_iscsi_bdev_module;
823 : 9 : lun->bdev.blocklen = block_size;
824 [ - + ]: 9 : lun->bdev.phys_blocklen = block_size * (1 << lbppbe);
825 : 9 : lun->bdev.blockcnt = num_blocks;
826 : 9 : lun->bdev.ctxt = lun;
827 [ - + ]: 9 : lun->unmap_supported = req->unmap_supported;
828 [ - + + + ]: 9 : if (lun->unmap_supported) {
829 : 8 : lun->max_unmap = req->max_unmap;
830 : 8 : lun->bdev.max_unmap = req->max_unmap;
831 : 8 : lun->bdev.max_unmap_segments = BDEV_ISCSI_MAX_UNMAP_BLOCK_DESCS_COUNT;
832 : : }
833 : :
834 : 9 : lun->bdev.fn_table = &iscsi_fn_table;
835 : :
836 : 9 : spdk_io_device_register(lun, bdev_iscsi_create_cb, bdev_iscsi_destroy_cb,
837 : : sizeof(struct bdev_iscsi_io_channel),
838 : 9 : req->bdev_name);
839 : 9 : rc = spdk_bdev_register(&lun->bdev);
840 [ - + ]: 9 : if (rc) {
841 : 0 : spdk_io_device_unregister(lun, NULL);
842 [ # # ]: 0 : pthread_mutex_destroy(&lun->mutex);
843 : 0 : free(lun);
844 : 0 : return rc;
845 : : }
846 : :
847 : 9 : lun->no_main_ch_poller_td = spdk_get_thread();
848 : 9 : lun->no_main_ch_poller = SPDK_POLLER_REGISTER(bdev_iscsi_no_main_ch_poll, lun,
849 : : BDEV_ISCSI_NO_MAIN_CH_POLL_US);
850 : :
851 : 9 : *bdev = &lun->bdev;
852 : 9 : return 0;
853 : : }
854 : :
855 : : static void
856 : 9 : iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
857 : : void *command_data, void *private_data)
858 : : {
859 : 9 : struct bdev_iscsi_conn_req *req = private_data;
860 : : struct scsi_readcapacity16 *readcap16;
861 : 9 : struct spdk_bdev *bdev = NULL;
862 : 9 : struct scsi_task *task = command_data;
863 : 9 : struct scsi_task *retry_task = NULL;
864 : :
865 [ - + ]: 9 : if (status != SPDK_SCSI_STATUS_GOOD) {
866 : 0 : SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(iscsi));
867 [ # # ]: 0 : if (_bdev_iscsi_is_size_change(status, task)) {
868 : 0 : scsi_free_scsi_task(task);
869 : 0 : retry_task = iscsi_readcapacity16_task(iscsi, req->lun,
870 : : iscsi_readcapacity16_cb, req);
871 [ # # ]: 0 : if (retry_task) {
872 : 0 : return;
873 : : }
874 : : }
875 : 0 : goto ret;
876 : : }
877 : :
878 : 9 : readcap16 = scsi_datain_unmarshall(task);
879 [ - + ]: 9 : if (!readcap16) {
880 : 0 : status = -ENOMEM;
881 : 0 : goto ret;
882 : : }
883 : :
884 : 9 : status = create_iscsi_lun(req, readcap16->returned_lba + 1, readcap16->block_length, &bdev,
885 : 9 : readcap16->lbppbe);
886 [ + - ]: 9 : if (status) {
887 : 0 : SPDK_ERRLOG("Unable to create iscsi bdev: %s (%d)\n", spdk_strerror(-status), status);
888 : : }
889 : :
890 : 9 : ret:
891 : 9 : scsi_free_scsi_task(task);
892 : 9 : complete_conn_req(req, bdev, status);
893 : : }
894 : :
895 : : static void
896 : 8 : bdev_iscsi_inquiry_bl_cb(struct iscsi_context *context, int status, void *_task, void *private_data)
897 : : {
898 : 8 : struct scsi_task *task = _task;
899 : 8 : struct scsi_inquiry_block_limits *bl_inq = NULL;
900 : 8 : struct bdev_iscsi_conn_req *req = private_data;
901 : :
902 [ + - ]: 8 : if (status == SPDK_SCSI_STATUS_GOOD) {
903 : 8 : bl_inq = scsi_datain_unmarshall(task);
904 [ + - ]: 8 : if (bl_inq != NULL) {
905 [ - + ]: 8 : if (!bl_inq->max_unmap) {
906 : 0 : SPDK_ERRLOG("Invalid max_unmap, use the default\n");
907 : 0 : req->max_unmap = BDEV_ISCSI_DEFAULT_MAX_UNMAP_LBA_COUNT;
908 : : } else {
909 : 8 : req->max_unmap = bl_inq->max_unmap;
910 : : }
911 : : }
912 : : }
913 : :
914 : 8 : scsi_free_scsi_task(task);
915 : 8 : task = iscsi_readcapacity16_task(context, req->lun, iscsi_readcapacity16_cb, req);
916 [ + - ]: 8 : if (task) {
917 : 8 : return;
918 : : }
919 : :
920 : 0 : SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(req->context));
921 : 0 : complete_conn_req(req, NULL, status);
922 : : }
923 : :
924 : : static void
925 : 9 : bdev_iscsi_inquiry_lbp_cb(struct iscsi_context *context, int status, void *_task,
926 : : void *private_data)
927 : : {
928 : 9 : struct scsi_task *task = _task;
929 : 9 : struct scsi_inquiry_logical_block_provisioning *lbp_inq = NULL;
930 : 9 : struct bdev_iscsi_conn_req *req = private_data;
931 : :
932 [ + + ]: 9 : if (status == SPDK_SCSI_STATUS_GOOD) {
933 : 8 : lbp_inq = scsi_datain_unmarshall(task);
934 [ + - + - ]: 8 : if (lbp_inq != NULL && lbp_inq->lbpu) {
935 : 8 : req->unmap_supported = true;
936 : 8 : scsi_free_scsi_task(task);
937 : :
938 : 8 : task = iscsi_inquiry_task(context, req->lun, 1,
939 : : SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS,
940 : : 255, bdev_iscsi_inquiry_bl_cb, req);
941 [ + - ]: 8 : if (task) {
942 : 8 : return;
943 : : }
944 : : }
945 : : } else {
946 : 1 : scsi_free_scsi_task(task);
947 : : }
948 : :
949 : 1 : task = iscsi_readcapacity16_task(context, req->lun, iscsi_readcapacity16_cb, req);
950 [ + - ]: 1 : if (task) {
951 : 1 : return;
952 : : }
953 : :
954 : 0 : SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(req->context));
955 : 0 : complete_conn_req(req, NULL, status);
956 : : }
957 : :
958 : : static void
959 : 9 : iscsi_connect_cb(struct iscsi_context *iscsi, int status,
960 : : void *command_data, void *private_data)
961 : : {
962 : 9 : struct bdev_iscsi_conn_req *req = private_data;
963 : : struct scsi_task *task;
964 : :
965 [ - + ]: 9 : if (status != SPDK_SCSI_STATUS_GOOD) {
966 : 0 : goto ret;
967 : : }
968 : :
969 : 9 : task = iscsi_inquiry_task(iscsi, req->lun, 1,
970 : : SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
971 : : 255, bdev_iscsi_inquiry_lbp_cb, req);
972 [ + - ]: 9 : if (task) {
973 : 9 : return;
974 : : }
975 : :
976 : 0 : ret:
977 : 0 : SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(req->context));
978 : 0 : complete_conn_req(req, NULL, status);
979 : : }
980 : :
981 : : static int
982 : 114 : iscsi_bdev_conn_poll(void *arg)
983 : : {
984 : : struct bdev_iscsi_conn_req *req, *tmp;
985 : 0 : struct pollfd pfd;
986 : : struct iscsi_context *context;
987 : :
988 [ + + ]: 114 : if (TAILQ_EMPTY(&g_iscsi_conn_req)) {
989 : 9 : spdk_poller_unregister(&g_conn_poller);
990 : 9 : return SPDK_POLLER_IDLE;
991 : : }
992 : :
993 [ + + ]: 210 : TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) {
994 : 105 : context = req->context;
995 : 105 : pfd.fd = iscsi_get_fd(context);
996 : 105 : pfd.events = iscsi_which_events(context);
997 : 105 : pfd.revents = 0;
998 [ - + ]: 105 : if (poll(&pfd, 1, 0) < 0) {
999 : 0 : SPDK_ERRLOG("poll failed\n");
1000 : 0 : return SPDK_POLLER_BUSY;
1001 : : }
1002 : :
1003 [ + + ]: 105 : if (pfd.revents != 0) {
1004 [ - + ]: 97 : if (iscsi_service(context, pfd.revents) < 0) {
1005 : 0 : SPDK_ERRLOG("iscsi_service failed: %s\n", iscsi_get_error(context));
1006 : : }
1007 : : }
1008 : :
1009 [ + + ]: 105 : if (req->status == 0) {
1010 : : /*
1011 : : * The request completed successfully.
1012 : : */
1013 : 9 : free(req);
1014 [ - + ]: 96 : } else if (req->status > 0) {
1015 : : /*
1016 : : * An error has occurred during connecting. This req has already
1017 : : * been removed from the g_iscsi_conn_req list, but we needed to
1018 : : * wait until iscsi_service unwound before we could free the req.
1019 : : */
1020 : 0 : _bdev_iscsi_conn_req_free(req);
1021 : : }
1022 : : }
1023 : 105 : return SPDK_POLLER_BUSY;
1024 : : }
1025 : :
1026 : : int
1027 : 9 : create_iscsi_disk(const char *bdev_name, const char *url, const char *initiator_iqn,
1028 : : spdk_bdev_iscsi_create_cb cb_fn, void *cb_arg)
1029 : : {
1030 : : struct bdev_iscsi_conn_req *req;
1031 : 9 : struct iscsi_url *iscsi_url = NULL;
1032 : : int rc;
1033 : :
1034 [ + - + - : 9 : if (!bdev_name || !url || !initiator_iqn || strlen(initiator_iqn) == 0 || !cb_fn) {
+ - + - -
+ ]
1035 : 0 : return -EINVAL;
1036 : : }
1037 : :
1038 : 9 : req = calloc(1, sizeof(struct bdev_iscsi_conn_req));
1039 [ - + ]: 9 : if (!req) {
1040 : 0 : SPDK_ERRLOG("Cannot allocate pointer of struct bdev_iscsi_conn_req\n");
1041 : 0 : return -ENOMEM;
1042 : : }
1043 : :
1044 : 9 : req->status = SCSI_STATUS_GOOD;
1045 [ - + ]: 9 : req->bdev_name = strdup(bdev_name);
1046 [ - + ]: 9 : req->url = strdup(url);
1047 [ - + ]: 9 : req->initiator_iqn = strdup(initiator_iqn);
1048 : 9 : req->context = iscsi_create_context(initiator_iqn);
1049 [ + - + - : 9 : if (!req->bdev_name || !req->url || !req->initiator_iqn || !req->context) {
+ - - + ]
1050 : 0 : SPDK_ERRLOG("Out of memory\n");
1051 : 0 : rc = -ENOMEM;
1052 : 0 : goto err;
1053 : : }
1054 : :
1055 : 9 : req->create_cb = cb_fn;
1056 : 9 : req->create_cb_arg = cb_arg;
1057 : :
1058 : 9 : iscsi_url = iscsi_parse_full_url(req->context, url);
1059 [ - + ]: 9 : if (iscsi_url == NULL) {
1060 : 0 : SPDK_ERRLOG("could not parse URL: %s\n", iscsi_get_error(req->context));
1061 : 0 : rc = -EINVAL;
1062 : 0 : goto err;
1063 : : }
1064 : :
1065 : 9 : req->lun = iscsi_url->lun;
1066 : 9 : rc = iscsi_set_session_type(req->context, ISCSI_SESSION_NORMAL);
1067 [ + - ]: 9 : rc = rc ? rc : iscsi_set_header_digest(req->context, ISCSI_HEADER_DIGEST_NONE);
1068 [ + - ]: 9 : rc = rc ? rc : iscsi_set_targetname(req->context, iscsi_url->target);
1069 [ + - ]: 9 : rc = rc ? rc : iscsi_set_timeout(req->context, g_opts.timeout_sec);
1070 [ + - ]: 9 : rc = rc ? rc : iscsi_full_connect_async(req->context, iscsi_url->portal, iscsi_url->lun,
1071 : : iscsi_connect_cb, req);
1072 [ + - - + ]: 9 : if (rc == 0 && iscsi_url->user[0] != '\0') {
1073 : 0 : rc = iscsi_set_initiator_username_pwd(req->context, iscsi_url->user, iscsi_url->passwd);
1074 : : }
1075 : :
1076 [ - + ]: 9 : if (rc < 0) {
1077 : 0 : SPDK_ERRLOG("Failed to connect provided URL=%s: %s\n", url, iscsi_get_error(req->context));
1078 : 0 : goto err;
1079 : : }
1080 : :
1081 : 9 : iscsi_destroy_url(iscsi_url);
1082 : 9 : req->status = -1;
1083 : 9 : TAILQ_INSERT_TAIL(&g_iscsi_conn_req, req, link);
1084 [ + - ]: 9 : if (!g_conn_poller) {
1085 : 9 : g_conn_poller = SPDK_POLLER_REGISTER(iscsi_bdev_conn_poll, NULL, BDEV_ISCSI_CONNECTION_POLL_US);
1086 : : }
1087 : :
1088 : 9 : return 0;
1089 : :
1090 : 0 : err:
1091 : : /* iscsi_destroy_url() is not NULL-proof */
1092 [ # # ]: 0 : if (iscsi_url) {
1093 : 0 : iscsi_destroy_url(iscsi_url);
1094 : : }
1095 : :
1096 [ # # ]: 0 : if (req->context) {
1097 : 0 : iscsi_destroy_context(req->context);
1098 : : }
1099 : :
1100 : 0 : free(req->initiator_iqn);
1101 : 0 : free(req->bdev_name);
1102 : 0 : free(req->url);
1103 : 0 : free(req);
1104 : 0 : return rc;
1105 : : }
1106 : :
1107 : : void
1108 : 0 : delete_iscsi_disk(const char *bdev_name, spdk_delete_iscsi_complete cb_fn, void *cb_arg)
1109 : : {
1110 : : int rc;
1111 : :
1112 : 0 : rc = spdk_bdev_unregister_by_name(bdev_name, &g_iscsi_bdev_module, cb_fn, cb_arg);
1113 [ # # ]: 0 : if (rc != 0) {
1114 : 0 : cb_fn(cb_arg, rc);
1115 : : }
1116 : 0 : }
1117 : :
1118 : : static int
1119 : 1962 : bdev_iscsi_initialize(void)
1120 : : {
1121 : 1962 : return 0;
1122 : : }
1123 : :
1124 : 2136 : SPDK_LOG_REGISTER_COMPONENT(iscsi_init)
|