xref: /spdk/lib/ftl/ftl_reloc.c (revision d4a2d28da1c6bc02a50c28428defdc7a2a99058d)
143a4d47aSKozlowski Mateusz /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2018 Intel Corporation.
343a4d47aSKozlowski Mateusz  *   All rights reserved.
443a4d47aSKozlowski Mateusz  */
543a4d47aSKozlowski Mateusz 
643a4d47aSKozlowski Mateusz #include "ftl_band.h"
743a4d47aSKozlowski Mateusz #include "ftl_core.h"
843a4d47aSKozlowski Mateusz #include "ftl_debug.h"
943a4d47aSKozlowski Mateusz #include "ftl_io.h"
1043a4d47aSKozlowski Mateusz #include "ftl_internal.h"
1143a4d47aSKozlowski Mateusz #include "spdk/ftl.h"
1243a4d47aSKozlowski Mateusz #include "spdk/likely.h"
1343a4d47aSKozlowski Mateusz 
1443a4d47aSKozlowski Mateusz struct ftl_reloc;
1543a4d47aSKozlowski Mateusz struct ftl_band_reloc;
1643a4d47aSKozlowski Mateusz 
1743a4d47aSKozlowski Mateusz /* TODO: Should probably change the move naming nomenclature to something more descriptive */
1843a4d47aSKozlowski Mateusz enum ftl_reloc_move_state {
1943a4d47aSKozlowski Mateusz 	FTL_RELOC_STATE_READ = 0,
2043a4d47aSKozlowski Mateusz 	FTL_RELOC_STATE_PIN,
2143a4d47aSKozlowski Mateusz 	FTL_RELOC_STATE_WRITE,
2243a4d47aSKozlowski Mateusz 	FTL_RELOC_STATE_WAIT,
2343a4d47aSKozlowski Mateusz 	FTL_RELOC_STATE_HALT,
2443a4d47aSKozlowski Mateusz 
2543a4d47aSKozlowski Mateusz 	FTL_RELOC_STATE_MAX
2643a4d47aSKozlowski Mateusz };
2743a4d47aSKozlowski Mateusz 
2843a4d47aSKozlowski Mateusz struct ftl_reloc_move {
2943a4d47aSKozlowski Mateusz 	/* FTL device */
3043a4d47aSKozlowski Mateusz 	struct spdk_ftl_dev *dev;
3143a4d47aSKozlowski Mateusz 
3243a4d47aSKozlowski Mateusz 	struct ftl_reloc *reloc;
3343a4d47aSKozlowski Mateusz 
3443a4d47aSKozlowski Mateusz 	/* Request for doing IO */
3543a4d47aSKozlowski Mateusz 	struct ftl_rq *rq;
3643a4d47aSKozlowski Mateusz 
3743a4d47aSKozlowski Mateusz 	/* Move state (read, write) */
3843a4d47aSKozlowski Mateusz 	enum ftl_reloc_move_state state;
3943a4d47aSKozlowski Mateusz 
4043a4d47aSKozlowski Mateusz 	/* Entry of circular list */
4143a4d47aSKozlowski Mateusz 	TAILQ_ENTRY(ftl_reloc_move) qentry;
4243a4d47aSKozlowski Mateusz };
4343a4d47aSKozlowski Mateusz 
4443a4d47aSKozlowski Mateusz struct ftl_reloc {
4543a4d47aSKozlowski Mateusz 	/* Device associated with relocate */
4643a4d47aSKozlowski Mateusz 	struct spdk_ftl_dev *dev;
4743a4d47aSKozlowski Mateusz 
4843a4d47aSKozlowski Mateusz 	/* Indicates relocate is about to halt */
4943a4d47aSKozlowski Mateusz 	bool halt;
5043a4d47aSKozlowski Mateusz 
5143a4d47aSKozlowski Mateusz 	/* Band which are read to relocate */
5243a4d47aSKozlowski Mateusz 	struct ftl_band *band;
5343a4d47aSKozlowski Mateusz 
5443a4d47aSKozlowski Mateusz 	/* Bands already read, but waiting for finishing GC */
5543a4d47aSKozlowski Mateusz 	TAILQ_HEAD(, ftl_band) band_done;
5643a4d47aSKozlowski Mateusz 	size_t band_done_count;
5743a4d47aSKozlowski Mateusz 
5843a4d47aSKozlowski Mateusz 	/* Flags indicating reloc is waiting for a new band */
5943a4d47aSKozlowski Mateusz 	bool band_waiting;
6043a4d47aSKozlowski Mateusz 
6143a4d47aSKozlowski Mateusz 	/* Maximum number of IOs per band */
6243a4d47aSKozlowski Mateusz 	size_t max_qdepth;
6343a4d47aSKozlowski Mateusz 
6443a4d47aSKozlowski Mateusz 	/* Queue of free move objects */
6543a4d47aSKozlowski Mateusz 	struct ftl_reloc_move *move_buffer;
6643a4d47aSKozlowski Mateusz 
6743a4d47aSKozlowski Mateusz 	/* Array of movers queue for each state */
6843a4d47aSKozlowski Mateusz 	TAILQ_HEAD(, ftl_reloc_move) move_queue[FTL_RELOC_STATE_MAX];
6943a4d47aSKozlowski Mateusz 
7043a4d47aSKozlowski Mateusz };
7143a4d47aSKozlowski Mateusz 
7243a4d47aSKozlowski Mateusz static void move_read_cb(struct ftl_rq *rq);
7343a4d47aSKozlowski Mateusz static void move_write_cb(struct ftl_rq *rq);
7443a4d47aSKozlowski Mateusz static void move_set_state(struct ftl_reloc_move *mv, enum ftl_reloc_move_state state);
7543a4d47aSKozlowski Mateusz static void move_write(struct ftl_reloc *reloc, struct ftl_reloc_move *mv);
7643a4d47aSKozlowski Mateusz static void move_read_error_cb(struct ftl_rq *rq, struct ftl_band *band, uint64_t idx,
7743a4d47aSKozlowski Mateusz 			       uint64_t count);
7843a4d47aSKozlowski Mateusz 
7943a4d47aSKozlowski Mateusz static void
move_deinit(struct ftl_reloc_move * mv)8043a4d47aSKozlowski Mateusz move_deinit(struct ftl_reloc_move *mv)
8143a4d47aSKozlowski Mateusz {
8243a4d47aSKozlowski Mateusz 	assert(mv);
8343a4d47aSKozlowski Mateusz 	ftl_rq_del(mv->rq);
8443a4d47aSKozlowski Mateusz }
8543a4d47aSKozlowski Mateusz 
8643a4d47aSKozlowski Mateusz static int
move_init(struct ftl_reloc * reloc,struct ftl_reloc_move * mv)8743a4d47aSKozlowski Mateusz move_init(struct ftl_reloc *reloc, struct ftl_reloc_move *mv)
8843a4d47aSKozlowski Mateusz {
8943a4d47aSKozlowski Mateusz 	mv->state = FTL_RELOC_STATE_HALT;
9043a4d47aSKozlowski Mateusz 	TAILQ_INSERT_TAIL(&reloc->move_queue[FTL_RELOC_STATE_HALT], mv, qentry);
9143a4d47aSKozlowski Mateusz 
9243a4d47aSKozlowski Mateusz 	mv->reloc = reloc;
9343a4d47aSKozlowski Mateusz 	mv->dev = reloc->dev;
9443a4d47aSKozlowski Mateusz 	mv->rq = ftl_rq_new(mv->dev, mv->dev->md_size);
9543a4d47aSKozlowski Mateusz 
9643a4d47aSKozlowski Mateusz 	if (!mv->rq) {
9743a4d47aSKozlowski Mateusz 		return -ENOMEM;
9843a4d47aSKozlowski Mateusz 	}
9943a4d47aSKozlowski Mateusz 	mv->rq->owner.priv = mv;
10043a4d47aSKozlowski Mateusz 
10143a4d47aSKozlowski Mateusz 	return 0;
10243a4d47aSKozlowski Mateusz }
10343a4d47aSKozlowski Mateusz 
10443a4d47aSKozlowski Mateusz struct ftl_reloc *
ftl_reloc_init(struct spdk_ftl_dev * dev)10543a4d47aSKozlowski Mateusz ftl_reloc_init(struct spdk_ftl_dev *dev)
10643a4d47aSKozlowski Mateusz {
10743a4d47aSKozlowski Mateusz 	struct ftl_reloc *reloc;
10843a4d47aSKozlowski Mateusz 	struct ftl_reloc_move *move;
10943a4d47aSKozlowski Mateusz 	size_t i, count;
11043a4d47aSKozlowski Mateusz 
11143a4d47aSKozlowski Mateusz 	reloc = calloc(1, sizeof(*reloc));
11243a4d47aSKozlowski Mateusz 	if (!reloc) {
11343a4d47aSKozlowski Mateusz 		return NULL;
11443a4d47aSKozlowski Mateusz 	}
11543a4d47aSKozlowski Mateusz 
11643a4d47aSKozlowski Mateusz 	reloc->dev = dev;
11743a4d47aSKozlowski Mateusz 	reloc->halt = true;
11843a4d47aSKozlowski Mateusz 	reloc->max_qdepth = dev->sb->max_reloc_qdepth;
11943a4d47aSKozlowski Mateusz 
12043a4d47aSKozlowski Mateusz 	reloc->move_buffer = calloc(reloc->max_qdepth, sizeof(*reloc->move_buffer));
12143a4d47aSKozlowski Mateusz 	if (!reloc->move_buffer) {
12243a4d47aSKozlowski Mateusz 		FTL_ERRLOG(dev, "Failed to initialize reloc moves pool");
12343a4d47aSKozlowski Mateusz 		goto error;
12443a4d47aSKozlowski Mateusz 	}
12543a4d47aSKozlowski Mateusz 
12643a4d47aSKozlowski Mateusz 	/* Initialize movers queues */
12743a4d47aSKozlowski Mateusz 	count = SPDK_COUNTOF(reloc->move_queue);
12843a4d47aSKozlowski Mateusz 	for (i = 0; i < count; ++i) {
12943a4d47aSKozlowski Mateusz 		TAILQ_INIT(&reloc->move_queue[i]);
13043a4d47aSKozlowski Mateusz 	}
13143a4d47aSKozlowski Mateusz 
13243a4d47aSKozlowski Mateusz 	for (i = 0; i < reloc->max_qdepth; ++i) {
13343a4d47aSKozlowski Mateusz 		move = &reloc->move_buffer[i];
13443a4d47aSKozlowski Mateusz 
13543a4d47aSKozlowski Mateusz 		if (move_init(reloc, move)) {
13643a4d47aSKozlowski Mateusz 			goto error;
13743a4d47aSKozlowski Mateusz 		}
13843a4d47aSKozlowski Mateusz 	}
13943a4d47aSKozlowski Mateusz 
14043a4d47aSKozlowski Mateusz 	TAILQ_INIT(&reloc->band_done);
14143a4d47aSKozlowski Mateusz 
14243a4d47aSKozlowski Mateusz 	return reloc;
14343a4d47aSKozlowski Mateusz error:
14443a4d47aSKozlowski Mateusz 	ftl_reloc_free(reloc);
14543a4d47aSKozlowski Mateusz 	return NULL;
14643a4d47aSKozlowski Mateusz }
14743a4d47aSKozlowski Mateusz 
14843a4d47aSKozlowski Mateusz struct ftl_reloc_task_fini {
14943a4d47aSKozlowski Mateusz 	struct ftl_reloc_task *task;
15043a4d47aSKozlowski Mateusz 	spdk_msg_fn cb;
15143a4d47aSKozlowski Mateusz 	void *cb_arg;
15243a4d47aSKozlowski Mateusz };
15343a4d47aSKozlowski Mateusz 
15443a4d47aSKozlowski Mateusz void
ftl_reloc_free(struct ftl_reloc * reloc)15543a4d47aSKozlowski Mateusz ftl_reloc_free(struct ftl_reloc *reloc)
15643a4d47aSKozlowski Mateusz {
15743a4d47aSKozlowski Mateusz 	size_t i;
15843a4d47aSKozlowski Mateusz 
15943a4d47aSKozlowski Mateusz 	if (!reloc) {
16043a4d47aSKozlowski Mateusz 		return;
16143a4d47aSKozlowski Mateusz 	}
16243a4d47aSKozlowski Mateusz 
16343a4d47aSKozlowski Mateusz 	if (reloc->move_buffer) {
16443a4d47aSKozlowski Mateusz 		for (i = 0; i < reloc->max_qdepth; ++i) {
16543a4d47aSKozlowski Mateusz 			move_deinit(&reloc->move_buffer[i]);
16643a4d47aSKozlowski Mateusz 		}
16743a4d47aSKozlowski Mateusz 	}
16843a4d47aSKozlowski Mateusz 
16943a4d47aSKozlowski Mateusz 	free(reloc->move_buffer);
17043a4d47aSKozlowski Mateusz 	free(reloc);
17143a4d47aSKozlowski Mateusz }
17243a4d47aSKozlowski Mateusz 
17343a4d47aSKozlowski Mateusz void
ftl_reloc_halt(struct ftl_reloc * reloc)17443a4d47aSKozlowski Mateusz ftl_reloc_halt(struct ftl_reloc *reloc)
17543a4d47aSKozlowski Mateusz {
176*d4a2d28dSMateusz Kozlowski 	struct spdk_ftl_dev *dev = reloc->dev;
177*d4a2d28dSMateusz Kozlowski 
178*d4a2d28dSMateusz Kozlowski 	if (dev->conf.prep_upgrade_on_shutdown && 0 == dev->num_free) {
179*d4a2d28dSMateusz Kozlowski 		/*
180*d4a2d28dSMateusz Kozlowski 		 * In shutdown upgrade procedure, it is required to have
181*d4a2d28dSMateusz Kozlowski 		 * at least one free band. Keep reloc running to reclaim
182*d4a2d28dSMateusz Kozlowski 		 * the band.
183*d4a2d28dSMateusz Kozlowski 		 */
184*d4a2d28dSMateusz Kozlowski 		return;
185*d4a2d28dSMateusz Kozlowski 	}
186*d4a2d28dSMateusz Kozlowski 
18743a4d47aSKozlowski Mateusz 	reloc->halt = true;
18843a4d47aSKozlowski Mateusz }
18943a4d47aSKozlowski Mateusz 
19043a4d47aSKozlowski Mateusz void
ftl_reloc_resume(struct ftl_reloc * reloc)19143a4d47aSKozlowski Mateusz ftl_reloc_resume(struct ftl_reloc *reloc)
19243a4d47aSKozlowski Mateusz {
19343a4d47aSKozlowski Mateusz 	struct ftl_reloc_move *mv, *next;
19443a4d47aSKozlowski Mateusz 	reloc->halt = false;
19543a4d47aSKozlowski Mateusz 
19643a4d47aSKozlowski Mateusz 	TAILQ_FOREACH_SAFE(mv, &reloc->move_queue[FTL_RELOC_STATE_HALT], qentry,
19743a4d47aSKozlowski Mateusz 			   next) {
19843a4d47aSKozlowski Mateusz 		move_set_state(mv, FTL_RELOC_STATE_READ);
19943a4d47aSKozlowski Mateusz 	}
20043a4d47aSKozlowski Mateusz }
20143a4d47aSKozlowski Mateusz 
20243a4d47aSKozlowski Mateusz static void
move_set_state(struct ftl_reloc_move * mv,enum ftl_reloc_move_state state)20343a4d47aSKozlowski Mateusz move_set_state(struct ftl_reloc_move *mv, enum ftl_reloc_move_state state)
20443a4d47aSKozlowski Mateusz {
20543a4d47aSKozlowski Mateusz 	struct ftl_reloc *reloc = mv->reloc;
20643a4d47aSKozlowski Mateusz 
20743a4d47aSKozlowski Mateusz 	switch (state) {
20843a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_READ:
20943a4d47aSKozlowski Mateusz 		mv->rq->owner.cb = move_read_cb;
21043a4d47aSKozlowski Mateusz 		mv->rq->owner.error = move_read_error_cb;
21143a4d47aSKozlowski Mateusz 		mv->rq->iter.idx = 0;
21243a4d47aSKozlowski Mateusz 		mv->rq->iter.count = 0;
21343a4d47aSKozlowski Mateusz 		mv->rq->success = true;
21443a4d47aSKozlowski Mateusz 		break;
21543a4d47aSKozlowski Mateusz 
21643a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_WRITE:
21743a4d47aSKozlowski Mateusz 		mv->rq->owner.cb = move_write_cb;
21843a4d47aSKozlowski Mateusz 		mv->rq->owner.error = NULL;
21943a4d47aSKozlowski Mateusz 		break;
22043a4d47aSKozlowski Mateusz 
22143a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_PIN:
22243a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_WAIT:
22343a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_HALT:
22443a4d47aSKozlowski Mateusz 		break;
22543a4d47aSKozlowski Mateusz 
22643a4d47aSKozlowski Mateusz 	default:
22743a4d47aSKozlowski Mateusz 		ftl_abort();
22843a4d47aSKozlowski Mateusz 		break;
22943a4d47aSKozlowski Mateusz 	}
23043a4d47aSKozlowski Mateusz 
23143a4d47aSKozlowski Mateusz 	if (mv->state != state) {
23243a4d47aSKozlowski Mateusz 		/* Remove the mover from previous queue */
23343a4d47aSKozlowski Mateusz 		TAILQ_REMOVE(&reloc->move_queue[mv->state], mv, qentry);
23443a4d47aSKozlowski Mateusz 		/* Insert the mover to the new queue */
23543a4d47aSKozlowski Mateusz 		TAILQ_INSERT_TAIL(&reloc->move_queue[state], mv, qentry);
23643a4d47aSKozlowski Mateusz 		/* Update state */
23743a4d47aSKozlowski Mateusz 		mv->state = state;
23843a4d47aSKozlowski Mateusz 	}
23943a4d47aSKozlowski Mateusz }
24043a4d47aSKozlowski Mateusz 
24143a4d47aSKozlowski Mateusz static void
move_get_band_cb(struct ftl_band * band,void * cntx,bool status)24243a4d47aSKozlowski Mateusz move_get_band_cb(struct ftl_band *band, void *cntx, bool status)
24343a4d47aSKozlowski Mateusz {
24443a4d47aSKozlowski Mateusz 	struct ftl_reloc *reloc = cntx;
24543a4d47aSKozlowski Mateusz 
24643a4d47aSKozlowski Mateusz 	if (spdk_likely(status)) {
24743a4d47aSKozlowski Mateusz 		reloc->band = band;
24843a4d47aSKozlowski Mateusz 		ftl_band_iter_init(band);
24943a4d47aSKozlowski Mateusz 	}
25043a4d47aSKozlowski Mateusz 	reloc->band_waiting = false;
25143a4d47aSKozlowski Mateusz }
25243a4d47aSKozlowski Mateusz 
25343a4d47aSKozlowski Mateusz static void
move_grab_new_band(struct ftl_reloc * reloc)25443a4d47aSKozlowski Mateusz move_grab_new_band(struct ftl_reloc *reloc)
25543a4d47aSKozlowski Mateusz {
25643a4d47aSKozlowski Mateusz 	if (!reloc->band_waiting) {
25743a4d47aSKozlowski Mateusz 		if (!ftl_needs_reloc(reloc->dev)) {
25843a4d47aSKozlowski Mateusz 			return;
25943a4d47aSKozlowski Mateusz 		}
26043a4d47aSKozlowski Mateusz 
26143a4d47aSKozlowski Mateusz 		/* Limit number of simultaneously relocated bands */
26243a4d47aSKozlowski Mateusz 		if (reloc->band_done_count > 2) {
26343a4d47aSKozlowski Mateusz 			return;
26443a4d47aSKozlowski Mateusz 		}
26543a4d47aSKozlowski Mateusz 
26643a4d47aSKozlowski Mateusz 		reloc->band_waiting = true;
26743a4d47aSKozlowski Mateusz 		ftl_band_get_next_gc(reloc->dev, move_get_band_cb, reloc);
26843a4d47aSKozlowski Mateusz 	}
26943a4d47aSKozlowski Mateusz }
27043a4d47aSKozlowski Mateusz 
27143a4d47aSKozlowski Mateusz static struct ftl_band *
move_get_band(struct ftl_reloc * reloc)27243a4d47aSKozlowski Mateusz move_get_band(struct ftl_reloc *reloc)
27343a4d47aSKozlowski Mateusz {
27443a4d47aSKozlowski Mateusz 	struct ftl_band *band = reloc->band;
27543a4d47aSKozlowski Mateusz 
27643a4d47aSKozlowski Mateusz 	if (!band) {
27743a4d47aSKozlowski Mateusz 		move_grab_new_band(reloc);
27843a4d47aSKozlowski Mateusz 		return NULL;
27943a4d47aSKozlowski Mateusz 	}
28043a4d47aSKozlowski Mateusz 
28143a4d47aSKozlowski Mateusz 	if (!ftl_band_filled(band, band->md->iter.offset)) {
28243a4d47aSKozlowski Mateusz 		/* Band still not read, we can continue reading */
28343a4d47aSKozlowski Mateusz 		return band;
28443a4d47aSKozlowski Mateusz 	}
28543a4d47aSKozlowski Mateusz 
28643a4d47aSKozlowski Mateusz 	TAILQ_INSERT_TAIL(&reloc->band_done, band, queue_entry);
28743a4d47aSKozlowski Mateusz 	reloc->band_done_count++;
28843a4d47aSKozlowski Mateusz 	reloc->band = NULL;
28943a4d47aSKozlowski Mateusz 
29043a4d47aSKozlowski Mateusz 	return NULL;
29143a4d47aSKozlowski Mateusz }
29243a4d47aSKozlowski Mateusz 
29343a4d47aSKozlowski Mateusz static void
move_advance_rq(struct ftl_rq * rq)29443a4d47aSKozlowski Mateusz move_advance_rq(struct ftl_rq *rq)
29543a4d47aSKozlowski Mateusz {
29643a4d47aSKozlowski Mateusz 	struct ftl_band *band = rq->io.band;
29743a4d47aSKozlowski Mateusz 	uint64_t offset, i;
29843a4d47aSKozlowski Mateusz 	struct ftl_rq_entry *entry = &rq->entries[rq->iter.idx];
29943a4d47aSKozlowski Mateusz 
30043a4d47aSKozlowski Mateusz 	assert(rq->iter.idx + rq->iter.count <= rq->num_blocks);
30143a4d47aSKozlowski Mateusz 
30243a4d47aSKozlowski Mateusz 	for (i = 0; i < rq->iter.count; i++) {
30343a4d47aSKozlowski Mateusz 		offset = ftl_band_block_offset_from_addr(band, rq->io.addr);
30443a4d47aSKozlowski Mateusz 
30543a4d47aSKozlowski Mateusz 		assert(offset < ftl_get_num_blocks_in_band(band->dev));
306cea8dadeSArtur Paszkiewicz 		assert(ftl_band_block_offset_valid(band, offset));
30743a4d47aSKozlowski Mateusz 
30836049672SArtur Paszkiewicz 		entry->lba = band->p2l_map.band_map[offset].lba;
30943a4d47aSKozlowski Mateusz 		entry->addr = rq->io.addr;
31043a4d47aSKozlowski Mateusz 		entry->owner.priv = band;
31136049672SArtur Paszkiewicz 		entry->seq_id = band->p2l_map.band_map[offset].seq_id;
31243a4d47aSKozlowski Mateusz 
31343a4d47aSKozlowski Mateusz 		entry++;
31443a4d47aSKozlowski Mateusz 		rq->io.addr = ftl_band_next_addr(band, rq->io.addr, 1);
31543a4d47aSKozlowski Mateusz 		band->owner.cnt++;
31643a4d47aSKozlowski Mateusz 	}
31743a4d47aSKozlowski Mateusz 
31843a4d47aSKozlowski Mateusz 	/* Increase QD for the request */
31943a4d47aSKozlowski Mateusz 	rq->iter.qd++;
32043a4d47aSKozlowski Mateusz 
32143a4d47aSKozlowski Mateusz 	/* Advanced request iterator */
32243a4d47aSKozlowski Mateusz 	rq->iter.idx += rq->iter.count;
32343a4d47aSKozlowski Mateusz }
32443a4d47aSKozlowski Mateusz 
32543a4d47aSKozlowski Mateusz static void
move_init_entries(struct ftl_rq * rq,uint64_t idx,uint64_t count)32643a4d47aSKozlowski Mateusz move_init_entries(struct ftl_rq *rq, uint64_t idx, uint64_t count)
32743a4d47aSKozlowski Mateusz {
32843a4d47aSKozlowski Mateusz 	uint64_t i = 0;
32943a4d47aSKozlowski Mateusz 	struct ftl_rq_entry *iter = &rq->entries[idx];
33043a4d47aSKozlowski Mateusz 
33143a4d47aSKozlowski Mateusz 	assert(idx + count <= rq->num_blocks);
33243a4d47aSKozlowski Mateusz 
33343a4d47aSKozlowski Mateusz 	i = 0;
33443a4d47aSKozlowski Mateusz 	while (i < count) {
33543a4d47aSKozlowski Mateusz 		iter->addr = FTL_ADDR_INVALID;
33643a4d47aSKozlowski Mateusz 		iter->owner.priv = NULL;
33743a4d47aSKozlowski Mateusz 		iter->lba = FTL_LBA_INVALID;
33836049672SArtur Paszkiewicz 		iter->seq_id = 0;
33943a4d47aSKozlowski Mateusz 		iter++;
34043a4d47aSKozlowski Mateusz 		i++;
34143a4d47aSKozlowski Mateusz 	}
34243a4d47aSKozlowski Mateusz }
34343a4d47aSKozlowski Mateusz 
34443a4d47aSKozlowski Mateusz static void
move_read_error_cb(struct ftl_rq * rq,struct ftl_band * band,uint64_t idx,uint64_t count)34543a4d47aSKozlowski Mateusz move_read_error_cb(struct ftl_rq *rq, struct ftl_band *band, uint64_t idx, uint64_t count)
34643a4d47aSKozlowski Mateusz {
34743a4d47aSKozlowski Mateusz 	move_init_entries(rq, idx, count);
34843a4d47aSKozlowski Mateusz 	band->owner.cnt -= count;
34943a4d47aSKozlowski Mateusz }
35043a4d47aSKozlowski Mateusz 
35143a4d47aSKozlowski Mateusz static void
move_read_cb(struct ftl_rq * rq)35243a4d47aSKozlowski Mateusz move_read_cb(struct ftl_rq *rq)
35343a4d47aSKozlowski Mateusz {
35443a4d47aSKozlowski Mateusz 	struct ftl_reloc_move *mv = rq->owner.priv;
35543a4d47aSKozlowski Mateusz 
35643a4d47aSKozlowski Mateusz 	/* Decrease QD of the request */
35743a4d47aSKozlowski Mateusz 	assert(rq->iter.qd > 0);
35843a4d47aSKozlowski Mateusz 	rq->iter.qd--;
35943a4d47aSKozlowski Mateusz 
36043a4d47aSKozlowski Mateusz 	if (rq->iter.idx != rq->num_blocks || rq->iter.qd) {
36143a4d47aSKozlowski Mateusz 		return;
36243a4d47aSKozlowski Mateusz 	}
36343a4d47aSKozlowski Mateusz 
36443a4d47aSKozlowski Mateusz 	move_set_state(mv, FTL_RELOC_STATE_PIN);
36543a4d47aSKozlowski Mateusz }
36643a4d47aSKozlowski Mateusz 
36743a4d47aSKozlowski Mateusz static void
move_rq_pad(struct ftl_rq * rq,struct ftl_band * band)36843a4d47aSKozlowski Mateusz move_rq_pad(struct ftl_rq *rq, struct ftl_band *band)
36943a4d47aSKozlowski Mateusz {
37043a4d47aSKozlowski Mateusz 	struct ftl_rq_entry *entry = &rq->entries[rq->iter.idx];
37143a4d47aSKozlowski Mateusz 
37243a4d47aSKozlowski Mateusz 	for (; rq->iter.idx < rq->num_blocks; ++rq->iter.idx) {
37343a4d47aSKozlowski Mateusz 		entry->addr = rq->io.addr;
37443a4d47aSKozlowski Mateusz 		entry->owner.priv = band;
37543a4d47aSKozlowski Mateusz 		entry->lba = FTL_LBA_INVALID;
37636049672SArtur Paszkiewicz 		entry->seq_id = 0;
37743a4d47aSKozlowski Mateusz 		entry++;
37843a4d47aSKozlowski Mateusz 		rq->io.addr = ftl_band_next_addr(band, rq->io.addr, 1);
37943a4d47aSKozlowski Mateusz 		band->owner.cnt++;
38043a4d47aSKozlowski Mateusz 	}
38143a4d47aSKozlowski Mateusz 
38243a4d47aSKozlowski Mateusz 	assert(rq->iter.idx == rq->num_blocks);
38343a4d47aSKozlowski Mateusz }
38443a4d47aSKozlowski Mateusz 
38543a4d47aSKozlowski Mateusz static void
move_read(struct ftl_reloc * reloc,struct ftl_reloc_move * mv,struct ftl_band * band)38643a4d47aSKozlowski Mateusz move_read(struct ftl_reloc *reloc, struct ftl_reloc_move *mv, struct ftl_band *band)
38743a4d47aSKozlowski Mateusz {
38843a4d47aSKozlowski Mateusz 	struct ftl_rq *rq = mv->rq;
38957cfab68SArtur Paszkiewicz 	uint64_t blocks = ftl_get_num_blocks_in_band(band->dev);
39057cfab68SArtur Paszkiewicz 	uint64_t pos = band->md->iter.offset;
39157cfab68SArtur Paszkiewicz 	uint64_t begin = ftl_bitmap_find_first_set(band->p2l_map.valid, pos, UINT64_MAX);
39257cfab68SArtur Paszkiewicz 	uint64_t end, band_left, rq_left;
39357cfab68SArtur Paszkiewicz 
39457cfab68SArtur Paszkiewicz 	if (spdk_likely(begin < blocks)) {
39557cfab68SArtur Paszkiewicz 		if (begin > pos) {
39657cfab68SArtur Paszkiewicz 			ftl_band_iter_advance(band, begin - pos);
39757cfab68SArtur Paszkiewicz 		} else if (begin == pos) {
39857cfab68SArtur Paszkiewicz 			/* Valid block at the position of iterator */
39957cfab68SArtur Paszkiewicz 		} else {
40057cfab68SArtur Paszkiewicz 			/* Inconsistent state */
40157cfab68SArtur Paszkiewicz 			ftl_abort();
40257cfab68SArtur Paszkiewicz 		}
40357cfab68SArtur Paszkiewicz 	} else if (UINT64_MAX == begin) {
40457cfab68SArtur Paszkiewicz 		/* No more valid LBAs in the band */
40557cfab68SArtur Paszkiewicz 		band_left = ftl_band_user_blocks_left(band, pos);
40657cfab68SArtur Paszkiewicz 		ftl_band_iter_advance(band, band_left);
40757cfab68SArtur Paszkiewicz 
40857cfab68SArtur Paszkiewicz 		assert(ftl_band_filled(band, band->md->iter.offset));
40957cfab68SArtur Paszkiewicz 
41057cfab68SArtur Paszkiewicz 		if (rq->iter.idx) {
41157cfab68SArtur Paszkiewicz 			move_rq_pad(rq, band);
41257cfab68SArtur Paszkiewicz 			move_set_state(mv, FTL_RELOC_STATE_WAIT);
41357cfab68SArtur Paszkiewicz 			rq->iter.qd++;
41457cfab68SArtur Paszkiewicz 			rq->owner.cb(rq);
41557cfab68SArtur Paszkiewicz 		}
41657cfab68SArtur Paszkiewicz 
41757cfab68SArtur Paszkiewicz 		return;
41857cfab68SArtur Paszkiewicz 	} else {
41957cfab68SArtur Paszkiewicz 		/* Inconsistent state */
42057cfab68SArtur Paszkiewicz 		ftl_abort();
42157cfab68SArtur Paszkiewicz 	}
42243a4d47aSKozlowski Mateusz 
42343a4d47aSKozlowski Mateusz 	rq_left = rq->num_blocks - rq->iter.idx;
42443a4d47aSKozlowski Mateusz 	assert(rq_left > 0);
42543a4d47aSKozlowski Mateusz 
42657cfab68SArtur Paszkiewicz 	/* Find next clear bit, but no further than max request count */
42757cfab68SArtur Paszkiewicz 	end = ftl_bitmap_find_first_clear(band->p2l_map.valid, begin + 1, begin + rq_left);
42857cfab68SArtur Paszkiewicz 	if (end != UINT64_MAX) {
42957cfab68SArtur Paszkiewicz 		rq_left = end - begin;
43057cfab68SArtur Paszkiewicz 	}
43157cfab68SArtur Paszkiewicz 
43243a4d47aSKozlowski Mateusz 	band_left = ftl_band_user_blocks_left(band, band->md->iter.offset);
43343a4d47aSKozlowski Mateusz 	rq->iter.count = spdk_min(rq_left, band_left);
43443a4d47aSKozlowski Mateusz 
43543a4d47aSKozlowski Mateusz 	ftl_band_rq_read(band, rq);
43643a4d47aSKozlowski Mateusz 
43743a4d47aSKozlowski Mateusz 	move_advance_rq(rq);
43843a4d47aSKozlowski Mateusz 
43943a4d47aSKozlowski Mateusz 	/* Advance band iterator */
44043a4d47aSKozlowski Mateusz 	ftl_band_iter_advance(band, rq->iter.count);
44143a4d47aSKozlowski Mateusz 
44243a4d47aSKozlowski Mateusz 	/* If band is fully written pad rest of request */
44343a4d47aSKozlowski Mateusz 	if (ftl_band_filled(band, band->md->iter.offset)) {
44443a4d47aSKozlowski Mateusz 		move_rq_pad(rq, band);
44543a4d47aSKozlowski Mateusz 	}
44643a4d47aSKozlowski Mateusz 
44743a4d47aSKozlowski Mateusz 	if (rq->iter.idx == rq->num_blocks) {
44843a4d47aSKozlowski Mateusz 		/*
44943a4d47aSKozlowski Mateusz 		 * All request entries scheduled for reading,
45043a4d47aSKozlowski Mateusz 		 * We can change state to waiting
45143a4d47aSKozlowski Mateusz 		 */
45243a4d47aSKozlowski Mateusz 		move_set_state(mv, FTL_RELOC_STATE_WAIT);
45343a4d47aSKozlowski Mateusz 	}
45443a4d47aSKozlowski Mateusz }
45543a4d47aSKozlowski Mateusz 
45643a4d47aSKozlowski Mateusz static void
move_pin_cb(struct spdk_ftl_dev * dev,int status,struct ftl_l2p_pin_ctx * pin_ctx)45743a4d47aSKozlowski Mateusz move_pin_cb(struct spdk_ftl_dev *dev, int status, struct ftl_l2p_pin_ctx *pin_ctx)
45843a4d47aSKozlowski Mateusz {
45943a4d47aSKozlowski Mateusz 	struct ftl_reloc_move *mv = pin_ctx->cb_ctx;
46043a4d47aSKozlowski Mateusz 	struct ftl_rq *rq = mv->rq;
46143a4d47aSKozlowski Mateusz 
46243a4d47aSKozlowski Mateusz 	if (status) {
46343a4d47aSKozlowski Mateusz 		rq->iter.status = status;
46443a4d47aSKozlowski Mateusz 		pin_ctx->lba = FTL_LBA_INVALID;
46543a4d47aSKozlowski Mateusz 	}
46643a4d47aSKozlowski Mateusz 
46743a4d47aSKozlowski Mateusz 	if (--rq->iter.remaining == 0) {
46843a4d47aSKozlowski Mateusz 		if (rq->iter.status) {
46943a4d47aSKozlowski Mateusz 			/* unpin and try again */
47043a4d47aSKozlowski Mateusz 			ftl_rq_unpin(rq);
47143a4d47aSKozlowski Mateusz 			move_set_state(mv, FTL_RELOC_STATE_PIN);
47243a4d47aSKozlowski Mateusz 			return;
47343a4d47aSKozlowski Mateusz 		}
47443a4d47aSKozlowski Mateusz 
47543a4d47aSKozlowski Mateusz 		move_set_state(mv, FTL_RELOC_STATE_WRITE);
47643a4d47aSKozlowski Mateusz 	}
47743a4d47aSKozlowski Mateusz }
47843a4d47aSKozlowski Mateusz 
47943a4d47aSKozlowski Mateusz static void
move_pin(struct ftl_reloc_move * mv)48043a4d47aSKozlowski Mateusz move_pin(struct ftl_reloc_move *mv)
48143a4d47aSKozlowski Mateusz {
48243a4d47aSKozlowski Mateusz 	struct ftl_rq *rq = mv->rq;
48343a4d47aSKozlowski Mateusz 	struct ftl_rq_entry *entry = rq->entries;
48443a4d47aSKozlowski Mateusz 	uint64_t i;
48543a4d47aSKozlowski Mateusz 
48643a4d47aSKozlowski Mateusz 	move_set_state(mv, FTL_RELOC_STATE_WAIT);
48743a4d47aSKozlowski Mateusz 
48843a4d47aSKozlowski Mateusz 	rq->iter.remaining = rq->iter.count = rq->num_blocks;
48943a4d47aSKozlowski Mateusz 	rq->iter.status = 0;
49043a4d47aSKozlowski Mateusz 
49143a4d47aSKozlowski Mateusz 	for (i = 0; i < rq->num_blocks; i++) {
49243a4d47aSKozlowski Mateusz 		if (entry->lba != FTL_LBA_INVALID) {
49343a4d47aSKozlowski Mateusz 			ftl_l2p_pin(rq->dev, entry->lba, 1, move_pin_cb, mv, &entry->l2p_pin_ctx);
49443a4d47aSKozlowski Mateusz 		} else {
49543a4d47aSKozlowski Mateusz 			ftl_l2p_pin_skip(rq->dev, move_pin_cb, mv, &entry->l2p_pin_ctx);
49643a4d47aSKozlowski Mateusz 		}
49743a4d47aSKozlowski Mateusz 		entry++;
49843a4d47aSKozlowski Mateusz 	}
49943a4d47aSKozlowski Mateusz }
50043a4d47aSKozlowski Mateusz 
50143a4d47aSKozlowski Mateusz static void
move_finish_write(struct ftl_rq * rq)50243a4d47aSKozlowski Mateusz move_finish_write(struct ftl_rq *rq)
50343a4d47aSKozlowski Mateusz {
50443a4d47aSKozlowski Mateusz 	uint64_t i;
50543a4d47aSKozlowski Mateusz 	struct spdk_ftl_dev *dev = rq->dev;
50643a4d47aSKozlowski Mateusz 	struct ftl_rq_entry *iter = rq->entries;
50743a4d47aSKozlowski Mateusz 	ftl_addr addr = rq->io.addr;
50843a4d47aSKozlowski Mateusz 	struct ftl_band *rq_band = rq->io.band;
50943a4d47aSKozlowski Mateusz 	struct ftl_band *band;
51043a4d47aSKozlowski Mateusz 
51143a4d47aSKozlowski Mateusz 	for (i = 0; i < rq->num_blocks; ++i, ++iter) {
51243a4d47aSKozlowski Mateusz 		band = iter->owner.priv;
51343a4d47aSKozlowski Mateusz 
51443a4d47aSKozlowski Mateusz 		if (band) {
51543a4d47aSKozlowski Mateusz 			assert(band->owner.cnt > 0);
51643a4d47aSKozlowski Mateusz 			band->owner.cnt--;
51743a4d47aSKozlowski Mateusz 		}
51843a4d47aSKozlowski Mateusz 		if (iter->lba != FTL_LBA_INVALID) {
51943a4d47aSKozlowski Mateusz 			/* Update L2P table */
52043a4d47aSKozlowski Mateusz 			ftl_l2p_update_base(dev, iter->lba, addr, iter->addr);
52143a4d47aSKozlowski Mateusz 			ftl_l2p_unpin(dev, iter->lba, 1);
52243a4d47aSKozlowski Mateusz 		}
52343a4d47aSKozlowski Mateusz 		addr = ftl_band_next_addr(rq_band, addr, 1);
52443a4d47aSKozlowski Mateusz 	}
52543a4d47aSKozlowski Mateusz }
52643a4d47aSKozlowski Mateusz 
52743a4d47aSKozlowski Mateusz static void
move_write_cb(struct ftl_rq * rq)52843a4d47aSKozlowski Mateusz move_write_cb(struct ftl_rq *rq)
52943a4d47aSKozlowski Mateusz {
53043a4d47aSKozlowski Mateusz 	struct ftl_reloc_move *mv = rq->owner.priv;
53143a4d47aSKozlowski Mateusz 
53243a4d47aSKozlowski Mateusz 	assert(rq->iter.qd == 1);
53343a4d47aSKozlowski Mateusz 	rq->iter.qd--;
53443a4d47aSKozlowski Mateusz 
53543a4d47aSKozlowski Mateusz 	if (spdk_likely(rq->success)) {
53643a4d47aSKozlowski Mateusz 		move_finish_write(rq);
53743a4d47aSKozlowski Mateusz 		move_set_state(mv, FTL_RELOC_STATE_READ);
53843a4d47aSKozlowski Mateusz 	} else {
53943a4d47aSKozlowski Mateusz 		/* Write failed, repeat write */
54043a4d47aSKozlowski Mateusz 		move_set_state(mv, FTL_RELOC_STATE_WRITE);
54143a4d47aSKozlowski Mateusz 	}
54243a4d47aSKozlowski Mateusz }
54343a4d47aSKozlowski Mateusz 
54443a4d47aSKozlowski Mateusz static void
move_write(struct ftl_reloc * reloc,struct ftl_reloc_move * mv)54543a4d47aSKozlowski Mateusz move_write(struct ftl_reloc *reloc, struct ftl_reloc_move *mv)
54643a4d47aSKozlowski Mateusz {
54743a4d47aSKozlowski Mateusz 	struct spdk_ftl_dev *dev = mv->dev;
54843a4d47aSKozlowski Mateusz 	struct ftl_rq *rq = mv->rq;
54943a4d47aSKozlowski Mateusz 
55043a4d47aSKozlowski Mateusz 	assert(rq->iter.idx == rq->num_blocks);
55143a4d47aSKozlowski Mateusz 
55243a4d47aSKozlowski Mateusz 	/* Request contains data to be placed on a new location, submit it */
55343a4d47aSKozlowski Mateusz 	ftl_writer_queue_rq(&dev->writer_gc, rq);
55443a4d47aSKozlowski Mateusz 	rq->iter.qd++;
55543a4d47aSKozlowski Mateusz 
55643a4d47aSKozlowski Mateusz 	move_set_state(mv, FTL_RELOC_STATE_WAIT);
55743a4d47aSKozlowski Mateusz }
55843a4d47aSKozlowski Mateusz 
55943a4d47aSKozlowski Mateusz static void
move_run(struct ftl_reloc * reloc,struct ftl_reloc_move * mv)56043a4d47aSKozlowski Mateusz move_run(struct ftl_reloc *reloc, struct ftl_reloc_move *mv)
56143a4d47aSKozlowski Mateusz {
56243a4d47aSKozlowski Mateusz 	struct ftl_band *band;
56343a4d47aSKozlowski Mateusz 
56443a4d47aSKozlowski Mateusz 	switch (mv->state) {
56543a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_READ: {
56643a4d47aSKozlowski Mateusz 		if (spdk_unlikely(reloc->halt)) {
56743a4d47aSKozlowski Mateusz 			move_set_state(mv, FTL_RELOC_STATE_HALT);
56843a4d47aSKozlowski Mateusz 			break;
56943a4d47aSKozlowski Mateusz 		}
57043a4d47aSKozlowski Mateusz 
57143a4d47aSKozlowski Mateusz 		band = move_get_band(reloc);
57243a4d47aSKozlowski Mateusz 		if (!band) {
57343a4d47aSKozlowski Mateusz 			break;
57443a4d47aSKozlowski Mateusz 		}
57543a4d47aSKozlowski Mateusz 
57643a4d47aSKozlowski Mateusz 		move_read(reloc, mv, band);
57743a4d47aSKozlowski Mateusz 	}
57843a4d47aSKozlowski Mateusz 	break;
57943a4d47aSKozlowski Mateusz 
58043a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_PIN:
58143a4d47aSKozlowski Mateusz 		move_pin(mv);
582646b851eSKozlowski Mateusz 		ftl_add_io_activity(reloc->dev);
58343a4d47aSKozlowski Mateusz 		break;
58443a4d47aSKozlowski Mateusz 
58543a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_WRITE:
58643a4d47aSKozlowski Mateusz 		if (spdk_unlikely(reloc->halt)) {
58743a4d47aSKozlowski Mateusz 			ftl_rq_unpin(mv->rq);
58843a4d47aSKozlowski Mateusz 			move_set_state(mv, FTL_RELOC_STATE_HALT);
58943a4d47aSKozlowski Mateusz 			break;
59043a4d47aSKozlowski Mateusz 		}
59143a4d47aSKozlowski Mateusz 
592646b851eSKozlowski Mateusz 		ftl_add_io_activity(reloc->dev);
59343a4d47aSKozlowski Mateusz 		move_write(reloc, mv);
59443a4d47aSKozlowski Mateusz 		break;
59543a4d47aSKozlowski Mateusz 
59643a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_HALT:
59743a4d47aSKozlowski Mateusz 	case FTL_RELOC_STATE_WAIT:
59843a4d47aSKozlowski Mateusz 		break;
59943a4d47aSKozlowski Mateusz 
60043a4d47aSKozlowski Mateusz 	default:
60143a4d47aSKozlowski Mateusz 		assert(0);
60243a4d47aSKozlowski Mateusz 		ftl_abort();
60343a4d47aSKozlowski Mateusz 		break;
60443a4d47aSKozlowski Mateusz 	}
60543a4d47aSKozlowski Mateusz }
60643a4d47aSKozlowski Mateusz 
60743a4d47aSKozlowski Mateusz static void
move_handle_band_error(struct ftl_band * band)60843a4d47aSKozlowski Mateusz move_handle_band_error(struct ftl_band *band)
60943a4d47aSKozlowski Mateusz {
61043a4d47aSKozlowski Mateusz 	struct ftl_reloc *reloc = band->dev->reloc;
61143a4d47aSKozlowski Mateusz 	/*
61243a4d47aSKozlowski Mateusz 	 * Handle band error, it's because an error occurred during reading,
61343a4d47aSKozlowski Mateusz 	 * Add band to the close band list, will try reloc it in a moment
61443a4d47aSKozlowski Mateusz 	 */
61543a4d47aSKozlowski Mateusz 	TAILQ_REMOVE(&reloc->band_done, band, queue_entry);
61643a4d47aSKozlowski Mateusz 	reloc->band_done_count--;
61743a4d47aSKozlowski Mateusz 
61843a4d47aSKozlowski Mateusz 	band->md->state = FTL_BAND_STATE_CLOSING;
61943a4d47aSKozlowski Mateusz 	ftl_band_set_state(band, FTL_BAND_STATE_CLOSED);
62043a4d47aSKozlowski Mateusz }
62143a4d47aSKozlowski Mateusz 
62243a4d47aSKozlowski Mateusz static void
move_release_bands(struct ftl_reloc * reloc)62343a4d47aSKozlowski Mateusz move_release_bands(struct ftl_reloc *reloc)
62443a4d47aSKozlowski Mateusz {
62543a4d47aSKozlowski Mateusz 	struct ftl_band *band;
62643a4d47aSKozlowski Mateusz 
62743a4d47aSKozlowski Mateusz 	if (TAILQ_EMPTY(&reloc->band_done)) {
62843a4d47aSKozlowski Mateusz 		return;
62943a4d47aSKozlowski Mateusz 	}
63043a4d47aSKozlowski Mateusz 
63143a4d47aSKozlowski Mateusz 	band = TAILQ_FIRST(&reloc->band_done);
63243a4d47aSKozlowski Mateusz 
63343a4d47aSKozlowski Mateusz 	if (band->owner.cnt || ftl_band_qd(band)) {
63443a4d47aSKozlowski Mateusz 		/* Band still in use */
63543a4d47aSKozlowski Mateusz 		return;
63643a4d47aSKozlowski Mateusz 	}
63743a4d47aSKozlowski Mateusz 
63843a4d47aSKozlowski Mateusz 	if (ftl_band_empty(band)) {
63943a4d47aSKozlowski Mateusz 		assert(ftl_band_filled(band, band->md->iter.offset));
64043a4d47aSKozlowski Mateusz 		TAILQ_REMOVE(&reloc->band_done, band, queue_entry);
64143a4d47aSKozlowski Mateusz 		reloc->band_done_count--;
64243a4d47aSKozlowski Mateusz 		ftl_band_free(band);
64343a4d47aSKozlowski Mateusz 	} else {
64443a4d47aSKozlowski Mateusz 		move_handle_band_error(band);
64543a4d47aSKozlowski Mateusz 	}
64643a4d47aSKozlowski Mateusz }
64743a4d47aSKozlowski Mateusz 
64843a4d47aSKozlowski Mateusz bool
ftl_reloc_is_halted(const struct ftl_reloc * reloc)64943a4d47aSKozlowski Mateusz ftl_reloc_is_halted(const struct ftl_reloc *reloc)
65043a4d47aSKozlowski Mateusz {
65143a4d47aSKozlowski Mateusz 	size_t i, count;
65243a4d47aSKozlowski Mateusz 
65343a4d47aSKozlowski Mateusz 	count = SPDK_COUNTOF(reloc->move_queue);
65443a4d47aSKozlowski Mateusz 	for (i = 0; i < count; ++i) {
65543a4d47aSKozlowski Mateusz 		if (i == FTL_RELOC_STATE_HALT) {
65643a4d47aSKozlowski Mateusz 			continue;
65743a4d47aSKozlowski Mateusz 		}
65843a4d47aSKozlowski Mateusz 
65943a4d47aSKozlowski Mateusz 		if (!TAILQ_EMPTY(&reloc->move_queue[i])) {
66043a4d47aSKozlowski Mateusz 			return false;
66143a4d47aSKozlowski Mateusz 		}
66243a4d47aSKozlowski Mateusz 	}
66343a4d47aSKozlowski Mateusz 
66443a4d47aSKozlowski Mateusz 	return true;
66543a4d47aSKozlowski Mateusz }
66643a4d47aSKozlowski Mateusz 
66743a4d47aSKozlowski Mateusz void
ftl_reloc(struct ftl_reloc * reloc)66843a4d47aSKozlowski Mateusz ftl_reloc(struct ftl_reloc *reloc)
66943a4d47aSKozlowski Mateusz {
67043a4d47aSKozlowski Mateusz 	size_t i, count;
67143a4d47aSKozlowski Mateusz 
67243a4d47aSKozlowski Mateusz 	count = SPDK_COUNTOF(reloc->move_queue);
67343a4d47aSKozlowski Mateusz 	for (i = 0; i < count; ++i) {
67443a4d47aSKozlowski Mateusz 		if (TAILQ_EMPTY(&reloc->move_queue[i])) {
67543a4d47aSKozlowski Mateusz 			continue;
67643a4d47aSKozlowski Mateusz 		}
67743a4d47aSKozlowski Mateusz 
67843a4d47aSKozlowski Mateusz 		move_run(reloc, TAILQ_FIRST(&reloc->move_queue[i]));
67943a4d47aSKozlowski Mateusz 	}
68043a4d47aSKozlowski Mateusz 
68143a4d47aSKozlowski Mateusz 	move_release_bands(reloc);
68243a4d47aSKozlowski Mateusz }
683