xref: /spdk/lib/ftl/ftl_band_ops.c (revision 1f11e145b64777dffb9975caa3e19325720b03fa)
17c9d3ea5SArtur Paszkiewicz /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2022 Intel Corporation.
3*1f11e145SMateusz Kozlowski  *   Copyright 2023 Solidigm All Rights Reserved
47c9d3ea5SArtur Paszkiewicz  *   All rights reserved.
57c9d3ea5SArtur Paszkiewicz  */
67c9d3ea5SArtur Paszkiewicz 
77c9d3ea5SArtur Paszkiewicz #include "spdk/stdinc.h"
87c9d3ea5SArtur Paszkiewicz #include "spdk/queue.h"
97c9d3ea5SArtur Paszkiewicz #include "spdk/bdev_module.h"
107c9d3ea5SArtur Paszkiewicz 
117c9d3ea5SArtur Paszkiewicz #include "ftl_core.h"
127c9d3ea5SArtur Paszkiewicz #include "ftl_band.h"
137c9d3ea5SArtur Paszkiewicz #include "ftl_internal.h"
147c9d3ea5SArtur Paszkiewicz 
157c9d3ea5SArtur Paszkiewicz static void
write_rq_end(struct spdk_bdev_io * bdev_io,bool success,void * arg)167c9d3ea5SArtur Paszkiewicz write_rq_end(struct spdk_bdev_io *bdev_io, bool success, void *arg)
177c9d3ea5SArtur Paszkiewicz {
187c9d3ea5SArtur Paszkiewicz 	struct ftl_rq *rq = arg;
191790ee8aSArtur Paszkiewicz 	struct spdk_ftl_dev *dev = rq->dev;
201790ee8aSArtur Paszkiewicz 
211790ee8aSArtur Paszkiewicz 	ftl_stats_bdev_io_completed(dev, rq->owner.compaction ? FTL_STATS_TYPE_CMP : FTL_STATS_TYPE_GC,
221790ee8aSArtur Paszkiewicz 				    bdev_io);
23e1fa7e3cSMateusz Kozlowski 	spdk_bdev_free_io(bdev_io);
247c9d3ea5SArtur Paszkiewicz 
257c9d3ea5SArtur Paszkiewicz 	rq->success = success;
26e1fa7e3cSMateusz Kozlowski 	if (spdk_likely(rq->success)) {
271738488eSArtur Paszkiewicz 		ftl_p2l_ckpt_issue(rq);
28e1fa7e3cSMateusz Kozlowski 	} else {
29e1fa7e3cSMateusz Kozlowski #ifdef SPDK_FTL_RETRY_ON_ERROR
30e1fa7e3cSMateusz Kozlowski 		assert(rq->io.band->queue_depth > 0);
31e1fa7e3cSMateusz Kozlowski 		rq->io.band->queue_depth--;
32e1fa7e3cSMateusz Kozlowski 		rq->owner.cb(rq);
337c9d3ea5SArtur Paszkiewicz 
34e1fa7e3cSMateusz Kozlowski #else
35e1fa7e3cSMateusz Kozlowski 		ftl_abort();
36e1fa7e3cSMateusz Kozlowski #endif
37e1fa7e3cSMateusz Kozlowski 	}
387c9d3ea5SArtur Paszkiewicz }
397c9d3ea5SArtur Paszkiewicz 
407c9d3ea5SArtur Paszkiewicz static void
ftl_band_rq_bdev_write(void * _rq)417c9d3ea5SArtur Paszkiewicz ftl_band_rq_bdev_write(void *_rq)
427c9d3ea5SArtur Paszkiewicz {
437c9d3ea5SArtur Paszkiewicz 	struct ftl_rq *rq = _rq;
447c9d3ea5SArtur Paszkiewicz 	struct ftl_band *band = rq->io.band;
457c9d3ea5SArtur Paszkiewicz 	struct spdk_ftl_dev *dev = band->dev;
467c9d3ea5SArtur Paszkiewicz 	int rc;
477c9d3ea5SArtur Paszkiewicz 
4822e97fd5SMateusz Kozlowski 	rc = spdk_bdev_write_blocks(dev->base_bdev_desc, dev->base_ioch,
4922e97fd5SMateusz Kozlowski 				    rq->io_payload, rq->io.addr, rq->num_blocks,
507c9d3ea5SArtur Paszkiewicz 				    write_rq_end, rq);
517c9d3ea5SArtur Paszkiewicz 
527c9d3ea5SArtur Paszkiewicz 	if (spdk_unlikely(rc)) {
537c9d3ea5SArtur Paszkiewicz 		if (rc == -ENOMEM) {
547c9d3ea5SArtur Paszkiewicz 			struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
557c9d3ea5SArtur Paszkiewicz 			rq->io.bdev_io_wait.bdev = bdev;
567c9d3ea5SArtur Paszkiewicz 			rq->io.bdev_io_wait.cb_fn = ftl_band_rq_bdev_write;
577c9d3ea5SArtur Paszkiewicz 			rq->io.bdev_io_wait.cb_arg = rq;
587c9d3ea5SArtur Paszkiewicz 			spdk_bdev_queue_io_wait(bdev, dev->base_ioch, &rq->io.bdev_io_wait);
597c9d3ea5SArtur Paszkiewicz 		} else {
607c9d3ea5SArtur Paszkiewicz 			ftl_abort();
617c9d3ea5SArtur Paszkiewicz 		}
627c9d3ea5SArtur Paszkiewicz 	}
637c9d3ea5SArtur Paszkiewicz }
647c9d3ea5SArtur Paszkiewicz 
657c9d3ea5SArtur Paszkiewicz void
ftl_band_rq_write(struct ftl_band * band,struct ftl_rq * rq)667c9d3ea5SArtur Paszkiewicz ftl_band_rq_write(struct ftl_band *band, struct ftl_rq *rq)
677c9d3ea5SArtur Paszkiewicz {
687c9d3ea5SArtur Paszkiewicz 	struct spdk_ftl_dev *dev = band->dev;
697c9d3ea5SArtur Paszkiewicz 
707c9d3ea5SArtur Paszkiewicz 	rq->success = false;
717c9d3ea5SArtur Paszkiewicz 	rq->io.band = band;
727c9d3ea5SArtur Paszkiewicz 	rq->io.addr = band->md->iter.addr;
737c9d3ea5SArtur Paszkiewicz 
747c9d3ea5SArtur Paszkiewicz 	ftl_band_rq_bdev_write(rq);
757c9d3ea5SArtur Paszkiewicz 
767c9d3ea5SArtur Paszkiewicz 	band->queue_depth++;
771790ee8aSArtur Paszkiewicz 	dev->stats.io_activity_total += rq->num_blocks;
787c9d3ea5SArtur Paszkiewicz 
797c9d3ea5SArtur Paszkiewicz 	ftl_band_iter_advance(band, rq->num_blocks);
807c9d3ea5SArtur Paszkiewicz 	if (ftl_band_filled(band, band->md->iter.offset)) {
817c9d3ea5SArtur Paszkiewicz 		ftl_band_set_state(band, FTL_BAND_STATE_FULL);
827c9d3ea5SArtur Paszkiewicz 		band->owner.state_change_fn(band);
837c9d3ea5SArtur Paszkiewicz 	}
847c9d3ea5SArtur Paszkiewicz }
857c9d3ea5SArtur Paszkiewicz 
867c9d3ea5SArtur Paszkiewicz static void ftl_band_rq_bdev_read(void *_entry);
877c9d3ea5SArtur Paszkiewicz 
887c9d3ea5SArtur Paszkiewicz static void
read_rq_end(struct spdk_bdev_io * bdev_io,bool success,void * arg)897c9d3ea5SArtur Paszkiewicz read_rq_end(struct spdk_bdev_io *bdev_io, bool success, void *arg)
907c9d3ea5SArtur Paszkiewicz {
917c9d3ea5SArtur Paszkiewicz 	struct ftl_rq_entry *entry = arg;
927c9d3ea5SArtur Paszkiewicz 	struct ftl_band *band = entry->io.band;
937c9d3ea5SArtur Paszkiewicz 	struct ftl_rq *rq = ftl_rq_from_entry(entry);
947c9d3ea5SArtur Paszkiewicz 
951790ee8aSArtur Paszkiewicz 	ftl_stats_bdev_io_completed(band->dev, FTL_STATS_TYPE_GC, bdev_io);
961790ee8aSArtur Paszkiewicz 
977c9d3ea5SArtur Paszkiewicz 	rq->success = success;
987c9d3ea5SArtur Paszkiewicz 	if (spdk_unlikely(!success)) {
997c9d3ea5SArtur Paszkiewicz 		ftl_band_rq_bdev_read(entry);
1007c9d3ea5SArtur Paszkiewicz 		spdk_bdev_free_io(bdev_io);
1017c9d3ea5SArtur Paszkiewicz 		return;
1027c9d3ea5SArtur Paszkiewicz 	}
1037c9d3ea5SArtur Paszkiewicz 
1047c9d3ea5SArtur Paszkiewicz 	assert(band->queue_depth > 0);
1057c9d3ea5SArtur Paszkiewicz 	band->queue_depth--;
1067c9d3ea5SArtur Paszkiewicz 
1077c9d3ea5SArtur Paszkiewicz 	rq->owner.cb(rq);
1087c9d3ea5SArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
1097c9d3ea5SArtur Paszkiewicz }
1107c9d3ea5SArtur Paszkiewicz 
1117c9d3ea5SArtur Paszkiewicz static void
ftl_band_rq_bdev_read(void * _entry)1127c9d3ea5SArtur Paszkiewicz ftl_band_rq_bdev_read(void *_entry)
1137c9d3ea5SArtur Paszkiewicz {
1147c9d3ea5SArtur Paszkiewicz 	struct ftl_rq_entry *entry = _entry;
1157c9d3ea5SArtur Paszkiewicz 	struct ftl_rq *rq = ftl_rq_from_entry(entry);
1167c9d3ea5SArtur Paszkiewicz 	struct spdk_ftl_dev *dev = rq->dev;
1177c9d3ea5SArtur Paszkiewicz 	int rc;
1187c9d3ea5SArtur Paszkiewicz 
1197c9d3ea5SArtur Paszkiewicz 	rc = spdk_bdev_read_blocks(dev->base_bdev_desc, dev->base_ioch, entry->io_payload,
1207c9d3ea5SArtur Paszkiewicz 				   entry->bdev_io.offset_blocks, entry->bdev_io.num_blocks,
1217c9d3ea5SArtur Paszkiewicz 				   read_rq_end, entry);
1227c9d3ea5SArtur Paszkiewicz 	if (spdk_unlikely(rc)) {
1237c9d3ea5SArtur Paszkiewicz 		if (rc == -ENOMEM) {
1247c9d3ea5SArtur Paszkiewicz 			struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
1257c9d3ea5SArtur Paszkiewicz 			entry->bdev_io.wait_entry.bdev = bdev;
1267c9d3ea5SArtur Paszkiewicz 			entry->bdev_io.wait_entry.cb_fn = ftl_band_rq_bdev_read;
1277c9d3ea5SArtur Paszkiewicz 			entry->bdev_io.wait_entry.cb_arg = entry;
1287c9d3ea5SArtur Paszkiewicz 			spdk_bdev_queue_io_wait(bdev, dev->base_ioch, &entry->bdev_io.wait_entry);
1297c9d3ea5SArtur Paszkiewicz 		} else {
1307c9d3ea5SArtur Paszkiewicz 			ftl_abort();
1317c9d3ea5SArtur Paszkiewicz 		}
1327c9d3ea5SArtur Paszkiewicz 	}
1337c9d3ea5SArtur Paszkiewicz }
1347c9d3ea5SArtur Paszkiewicz 
1357c9d3ea5SArtur Paszkiewicz void
ftl_band_rq_read(struct ftl_band * band,struct ftl_rq * rq)1367c9d3ea5SArtur Paszkiewicz ftl_band_rq_read(struct ftl_band *band, struct ftl_rq *rq)
1377c9d3ea5SArtur Paszkiewicz {
1387c9d3ea5SArtur Paszkiewicz 	struct spdk_ftl_dev *dev = band->dev;
1397c9d3ea5SArtur Paszkiewicz 	struct ftl_rq_entry *entry = &rq->entries[rq->iter.idx];
1407c9d3ea5SArtur Paszkiewicz 
1417c9d3ea5SArtur Paszkiewicz 	assert(rq->iter.idx + rq->iter.count <= rq->num_blocks);
1427c9d3ea5SArtur Paszkiewicz 
1437c9d3ea5SArtur Paszkiewicz 	rq->success = false;
1447c9d3ea5SArtur Paszkiewicz 	rq->io.band = band;
1457c9d3ea5SArtur Paszkiewicz 	rq->io.addr = band->md->iter.addr;
1467c9d3ea5SArtur Paszkiewicz 	entry->io.band = band;
1477c9d3ea5SArtur Paszkiewicz 	entry->bdev_io.offset_blocks = rq->io.addr;
1487c9d3ea5SArtur Paszkiewicz 	entry->bdev_io.num_blocks = rq->iter.count;
1497c9d3ea5SArtur Paszkiewicz 
1507c9d3ea5SArtur Paszkiewicz 	ftl_band_rq_bdev_read(entry);
1517c9d3ea5SArtur Paszkiewicz 
1521790ee8aSArtur Paszkiewicz 	dev->stats.io_activity_total += rq->num_blocks;
1537c9d3ea5SArtur Paszkiewicz 	band->queue_depth++;
1547c9d3ea5SArtur Paszkiewicz }
1557c9d3ea5SArtur Paszkiewicz 
1567c9d3ea5SArtur Paszkiewicz static void
write_brq_end(struct spdk_bdev_io * bdev_io,bool success,void * arg)1577c9d3ea5SArtur Paszkiewicz write_brq_end(struct spdk_bdev_io *bdev_io, bool success, void *arg)
1587c9d3ea5SArtur Paszkiewicz {
1597c9d3ea5SArtur Paszkiewicz 	struct ftl_basic_rq *brq = arg;
1607c9d3ea5SArtur Paszkiewicz 	struct ftl_band *band = brq->io.band;
1617c9d3ea5SArtur Paszkiewicz 
1621790ee8aSArtur Paszkiewicz 	ftl_stats_bdev_io_completed(band->dev, FTL_STATS_TYPE_MD_BASE, bdev_io);
1631790ee8aSArtur Paszkiewicz 
1647c9d3ea5SArtur Paszkiewicz 	brq->success = success;
1657c9d3ea5SArtur Paszkiewicz 
1667c9d3ea5SArtur Paszkiewicz 	assert(band->queue_depth > 0);
1677c9d3ea5SArtur Paszkiewicz 	band->queue_depth--;
1687c9d3ea5SArtur Paszkiewicz 
1697c9d3ea5SArtur Paszkiewicz 	brq->owner.cb(brq);
1707c9d3ea5SArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
1717c9d3ea5SArtur Paszkiewicz }
1727c9d3ea5SArtur Paszkiewicz 
1737c9d3ea5SArtur Paszkiewicz static void
ftl_band_brq_bdev_write(void * _brq)1747c9d3ea5SArtur Paszkiewicz ftl_band_brq_bdev_write(void *_brq)
1757c9d3ea5SArtur Paszkiewicz {
1767c9d3ea5SArtur Paszkiewicz 	struct ftl_basic_rq *brq = _brq;
1777c9d3ea5SArtur Paszkiewicz 	struct spdk_ftl_dev *dev = brq->dev;
1787c9d3ea5SArtur Paszkiewicz 	int rc;
1797c9d3ea5SArtur Paszkiewicz 
1807c9d3ea5SArtur Paszkiewicz 	rc = spdk_bdev_write_blocks(dev->base_bdev_desc, dev->base_ioch,
1817c9d3ea5SArtur Paszkiewicz 				    brq->io_payload, brq->io.addr,
1827c9d3ea5SArtur Paszkiewicz 				    brq->num_blocks, write_brq_end, brq);
1837c9d3ea5SArtur Paszkiewicz 
1847c9d3ea5SArtur Paszkiewicz 	if (spdk_unlikely(rc)) {
1857c9d3ea5SArtur Paszkiewicz 		if (rc == -ENOMEM) {
1867c9d3ea5SArtur Paszkiewicz 			struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
1877c9d3ea5SArtur Paszkiewicz 			brq->io.bdev_io_wait.bdev = bdev;
1887c9d3ea5SArtur Paszkiewicz 			brq->io.bdev_io_wait.cb_fn = ftl_band_brq_bdev_write;
1897c9d3ea5SArtur Paszkiewicz 			brq->io.bdev_io_wait.cb_arg = brq;
1907c9d3ea5SArtur Paszkiewicz 			spdk_bdev_queue_io_wait(bdev, dev->base_ioch, &brq->io.bdev_io_wait);
1917c9d3ea5SArtur Paszkiewicz 		} else {
1927c9d3ea5SArtur Paszkiewicz 			ftl_abort();
1937c9d3ea5SArtur Paszkiewicz 		}
1947c9d3ea5SArtur Paszkiewicz 	}
1957c9d3ea5SArtur Paszkiewicz }
1967c9d3ea5SArtur Paszkiewicz 
1977c9d3ea5SArtur Paszkiewicz void
ftl_band_basic_rq_write(struct ftl_band * band,struct ftl_basic_rq * brq)1987c9d3ea5SArtur Paszkiewicz ftl_band_basic_rq_write(struct ftl_band *band, struct ftl_basic_rq *brq)
1997c9d3ea5SArtur Paszkiewicz {
2007c9d3ea5SArtur Paszkiewicz 	struct spdk_ftl_dev *dev = band->dev;
2017c9d3ea5SArtur Paszkiewicz 
2027c9d3ea5SArtur Paszkiewicz 	brq->io.addr = band->md->iter.addr;
2037c9d3ea5SArtur Paszkiewicz 	brq->io.band = band;
2047c9d3ea5SArtur Paszkiewicz 	brq->success = false;
2057c9d3ea5SArtur Paszkiewicz 
2067c9d3ea5SArtur Paszkiewicz 	ftl_band_brq_bdev_write(brq);
2077c9d3ea5SArtur Paszkiewicz 
2081790ee8aSArtur Paszkiewicz 	dev->stats.io_activity_total += brq->num_blocks;
2097c9d3ea5SArtur Paszkiewicz 	band->queue_depth++;
2107c9d3ea5SArtur Paszkiewicz 	ftl_band_iter_advance(band, brq->num_blocks);
2117c9d3ea5SArtur Paszkiewicz 	if (ftl_band_filled(band, band->md->iter.offset)) {
2127c9d3ea5SArtur Paszkiewicz 		ftl_band_set_state(band, FTL_BAND_STATE_FULL);
2137c9d3ea5SArtur Paszkiewicz 		band->owner.state_change_fn(band);
2147c9d3ea5SArtur Paszkiewicz 	}
2157c9d3ea5SArtur Paszkiewicz }
2167c9d3ea5SArtur Paszkiewicz 
2177c9d3ea5SArtur Paszkiewicz static void
read_brq_end(struct spdk_bdev_io * bdev_io,bool success,void * arg)2187c9d3ea5SArtur Paszkiewicz read_brq_end(struct spdk_bdev_io *bdev_io, bool success, void *arg)
2197c9d3ea5SArtur Paszkiewicz {
2207c9d3ea5SArtur Paszkiewicz 	struct ftl_basic_rq *brq = arg;
2217c9d3ea5SArtur Paszkiewicz 	struct ftl_band *band = brq->io.band;
2227c9d3ea5SArtur Paszkiewicz 
2231790ee8aSArtur Paszkiewicz 	ftl_stats_bdev_io_completed(band->dev, FTL_STATS_TYPE_MD_BASE, bdev_io);
2241790ee8aSArtur Paszkiewicz 
2257c9d3ea5SArtur Paszkiewicz 	brq->success = success;
2267c9d3ea5SArtur Paszkiewicz 
2277c9d3ea5SArtur Paszkiewicz 	assert(band->queue_depth > 0);
2287c9d3ea5SArtur Paszkiewicz 	band->queue_depth--;
2297c9d3ea5SArtur Paszkiewicz 
2307c9d3ea5SArtur Paszkiewicz 	brq->owner.cb(brq);
2317c9d3ea5SArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
2327c9d3ea5SArtur Paszkiewicz }
2337c9d3ea5SArtur Paszkiewicz 
2347c9d3ea5SArtur Paszkiewicz static void
ftl_band_brq_bdev_read(void * _brq)2357c9d3ea5SArtur Paszkiewicz ftl_band_brq_bdev_read(void *_brq)
2367c9d3ea5SArtur Paszkiewicz {
2377c9d3ea5SArtur Paszkiewicz 	struct ftl_basic_rq *brq = _brq;
2387c9d3ea5SArtur Paszkiewicz 	struct spdk_ftl_dev *dev = brq->dev;
2397c9d3ea5SArtur Paszkiewicz 	int rc;
2407c9d3ea5SArtur Paszkiewicz 
2417c9d3ea5SArtur Paszkiewicz 	rc = spdk_bdev_read_blocks(dev->base_bdev_desc, dev->base_ioch,
2427c9d3ea5SArtur Paszkiewicz 				   brq->io_payload, brq->io.addr,
2437c9d3ea5SArtur Paszkiewicz 				   brq->num_blocks, read_brq_end, brq);
2447c9d3ea5SArtur Paszkiewicz 	if (spdk_unlikely(rc)) {
2457c9d3ea5SArtur Paszkiewicz 		if (rc == -ENOMEM) {
2467c9d3ea5SArtur Paszkiewicz 			struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
2477c9d3ea5SArtur Paszkiewicz 			brq->io.bdev_io_wait.bdev = bdev;
2487c9d3ea5SArtur Paszkiewicz 			brq->io.bdev_io_wait.cb_fn = ftl_band_brq_bdev_read;
2497c9d3ea5SArtur Paszkiewicz 			brq->io.bdev_io_wait.cb_arg = brq;
2507c9d3ea5SArtur Paszkiewicz 			spdk_bdev_queue_io_wait(bdev, dev->base_ioch, &brq->io.bdev_io_wait);
2517c9d3ea5SArtur Paszkiewicz 		} else {
2527c9d3ea5SArtur Paszkiewicz 			ftl_abort();
2537c9d3ea5SArtur Paszkiewicz 		}
2547c9d3ea5SArtur Paszkiewicz 	}
2557c9d3ea5SArtur Paszkiewicz }
2567c9d3ea5SArtur Paszkiewicz 
2577c9d3ea5SArtur Paszkiewicz void
ftl_band_basic_rq_read(struct ftl_band * band,struct ftl_basic_rq * brq)2587c9d3ea5SArtur Paszkiewicz ftl_band_basic_rq_read(struct ftl_band *band, struct ftl_basic_rq *brq)
2597c9d3ea5SArtur Paszkiewicz {
2607c9d3ea5SArtur Paszkiewicz 	struct spdk_ftl_dev *dev = brq->dev;
2617c9d3ea5SArtur Paszkiewicz 
2627c9d3ea5SArtur Paszkiewicz 	brq->io.band = band;
2637c9d3ea5SArtur Paszkiewicz 
2647c9d3ea5SArtur Paszkiewicz 	ftl_band_brq_bdev_read(brq);
2657c9d3ea5SArtur Paszkiewicz 
2667c9d3ea5SArtur Paszkiewicz 	brq->io.band->queue_depth++;
2671790ee8aSArtur Paszkiewicz 	dev->stats.io_activity_total += brq->num_blocks;
2687c9d3ea5SArtur Paszkiewicz }
2697c9d3ea5SArtur Paszkiewicz 
2707c9d3ea5SArtur Paszkiewicz static void
band_open_cb(int status,void * cb_arg)2715af491a2SKozlowski Mateusz band_open_cb(int status, void *cb_arg)
2725af491a2SKozlowski Mateusz {
2735af491a2SKozlowski Mateusz 	struct ftl_band *band = cb_arg;
2745af491a2SKozlowski Mateusz 
2755af491a2SKozlowski Mateusz 	if (spdk_unlikely(status)) {
276759e1769SKozlowski Mateusz #ifdef SPDK_FTL_RETRY_ON_ERROR
2775af491a2SKozlowski Mateusz 		ftl_md_persist_entry_retry(&band->md_persist_entry_ctx);
2785af491a2SKozlowski Mateusz 		return;
279759e1769SKozlowski Mateusz #else
280759e1769SKozlowski Mateusz 		ftl_abort();
281759e1769SKozlowski Mateusz #endif
2825af491a2SKozlowski Mateusz 	}
2835af491a2SKozlowski Mateusz 
2845af491a2SKozlowski Mateusz 	ftl_band_set_state(band, FTL_BAND_STATE_OPEN);
2855af491a2SKozlowski Mateusz }
2865af491a2SKozlowski Mateusz 
2875af491a2SKozlowski Mateusz void
ftl_band_open(struct ftl_band * band,enum ftl_band_type type)2885af491a2SKozlowski Mateusz ftl_band_open(struct ftl_band *band, enum ftl_band_type type)
2895af491a2SKozlowski Mateusz {
2905af491a2SKozlowski Mateusz 	struct spdk_ftl_dev *dev = band->dev;
2915af491a2SKozlowski Mateusz 	struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD];
29230ef80cdSMateusz Kozlowski 	struct ftl_layout_region *region = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD);
2935af491a2SKozlowski Mateusz 	struct ftl_p2l_map *p2l_map = &band->p2l_map;
2945af491a2SKozlowski Mateusz 
2955af491a2SKozlowski Mateusz 	ftl_band_set_type(band, type);
2965af491a2SKozlowski Mateusz 	ftl_band_set_state(band, FTL_BAND_STATE_OPENING);
2975af491a2SKozlowski Mateusz 
2985af491a2SKozlowski Mateusz 	memcpy(p2l_map->band_dma_md, band->md, region->entry_size * FTL_BLOCK_SIZE);
2995af491a2SKozlowski Mateusz 	p2l_map->band_dma_md->state = FTL_BAND_STATE_OPEN;
3005af491a2SKozlowski Mateusz 	p2l_map->band_dma_md->p2l_map_checksum = 0;
3015af491a2SKozlowski Mateusz 
3025af491a2SKozlowski Mateusz 	if (spdk_unlikely(0 != band->p2l_map.num_valid)) {
3035af491a2SKozlowski Mateusz 		/*
3045af491a2SKozlowski Mateusz 		 * This is inconsistent state, a band with valid block,
3055af491a2SKozlowski Mateusz 		 * it could be moved on the free list
3065af491a2SKozlowski Mateusz 		 */
3075af491a2SKozlowski Mateusz 		assert(false && 0 == band->p2l_map.num_valid);
3085af491a2SKozlowski Mateusz 		ftl_abort();
3095af491a2SKozlowski Mateusz 	}
3105af491a2SKozlowski Mateusz 
311*1f11e145SMateusz Kozlowski 	ftl_md_persist_entries(md, band->id, 1, p2l_map->band_dma_md, NULL,
3125af491a2SKozlowski Mateusz 			       band_open_cb, band, &band->md_persist_entry_ctx);
3135af491a2SKozlowski Mateusz }
3145af491a2SKozlowski Mateusz 
3155af491a2SKozlowski Mateusz static void
band_close_cb(int status,void * cb_arg)3165af491a2SKozlowski Mateusz band_close_cb(int status, void *cb_arg)
3175af491a2SKozlowski Mateusz {
3185af491a2SKozlowski Mateusz 	struct ftl_band *band = cb_arg;
3195af491a2SKozlowski Mateusz 
3205af491a2SKozlowski Mateusz 	if (spdk_unlikely(status)) {
321759e1769SKozlowski Mateusz #ifdef SPDK_FTL_RETRY_ON_ERROR
3225af491a2SKozlowski Mateusz 		ftl_md_persist_entry_retry(&band->md_persist_entry_ctx);
3235af491a2SKozlowski Mateusz 		return;
324759e1769SKozlowski Mateusz #else
325759e1769SKozlowski Mateusz 		ftl_abort();
326759e1769SKozlowski Mateusz #endif
3275af491a2SKozlowski Mateusz 	}
3285af491a2SKozlowski Mateusz 
3295af491a2SKozlowski Mateusz 	band->md->p2l_map_checksum = band->p2l_map.band_dma_md->p2l_map_checksum;
3305af491a2SKozlowski Mateusz 	ftl_band_set_state(band, FTL_BAND_STATE_CLOSED);
3315af491a2SKozlowski Mateusz }
3325af491a2SKozlowski Mateusz 
3335af491a2SKozlowski Mateusz static void
band_map_write_cb(struct ftl_basic_rq * brq)3345af491a2SKozlowski Mateusz band_map_write_cb(struct ftl_basic_rq *brq)
3355af491a2SKozlowski Mateusz {
3365af491a2SKozlowski Mateusz 	struct ftl_band *band = brq->io.band;
3375af491a2SKozlowski Mateusz 	struct ftl_p2l_map *p2l_map = &band->p2l_map;
3385af491a2SKozlowski Mateusz 	struct spdk_ftl_dev *dev = band->dev;
33930ef80cdSMateusz Kozlowski 	struct ftl_layout_region *region = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD);
3405af491a2SKozlowski Mateusz 	struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD];
3415af491a2SKozlowski Mateusz 	uint32_t band_map_crc;
3425af491a2SKozlowski Mateusz 
3435af491a2SKozlowski Mateusz 	if (spdk_likely(brq->success)) {
3445af491a2SKozlowski Mateusz 
3455af491a2SKozlowski Mateusz 		band_map_crc = spdk_crc32c_update(p2l_map->band_map,
3465af491a2SKozlowski Mateusz 						  ftl_tail_md_num_blocks(dev) * FTL_BLOCK_SIZE, 0);
3475af491a2SKozlowski Mateusz 		memcpy(p2l_map->band_dma_md, band->md, region->entry_size * FTL_BLOCK_SIZE);
3485af491a2SKozlowski Mateusz 		p2l_map->band_dma_md->state = FTL_BAND_STATE_CLOSED;
3495af491a2SKozlowski Mateusz 		p2l_map->band_dma_md->p2l_map_checksum = band_map_crc;
3505af491a2SKozlowski Mateusz 
351*1f11e145SMateusz Kozlowski 		ftl_md_persist_entries(md, band->id, 1, p2l_map->band_dma_md, NULL,
3525af491a2SKozlowski Mateusz 				       band_close_cb, band, &band->md_persist_entry_ctx);
3535af491a2SKozlowski Mateusz 	} else {
354759e1769SKozlowski Mateusz #ifdef SPDK_FTL_RETRY_ON_ERROR
3555af491a2SKozlowski Mateusz 		/* Try to retry in case of failure */
3565af491a2SKozlowski Mateusz 		ftl_band_brq_bdev_write(brq);
3575af491a2SKozlowski Mateusz 		band->queue_depth++;
358759e1769SKozlowski Mateusz #else
359759e1769SKozlowski Mateusz 		ftl_abort();
360759e1769SKozlowski Mateusz #endif
3615af491a2SKozlowski Mateusz 	}
3625af491a2SKozlowski Mateusz }
3635af491a2SKozlowski Mateusz 
3645af491a2SKozlowski Mateusz void
ftl_band_close(struct ftl_band * band)3655af491a2SKozlowski Mateusz ftl_band_close(struct ftl_band *band)
3665af491a2SKozlowski Mateusz {
3675af491a2SKozlowski Mateusz 	struct spdk_ftl_dev *dev = band->dev;
3685af491a2SKozlowski Mateusz 	void *metadata = band->p2l_map.band_map;
3695af491a2SKozlowski Mateusz 	uint64_t num_blocks = ftl_tail_md_num_blocks(dev);
3705af491a2SKozlowski Mateusz 
371711759a0SKozlowski Mateusz 	/* Write P2L map first, after completion, set the state to close on nvcache, then internally */
37236049672SArtur Paszkiewicz 	band->md->close_seq_id = ftl_get_next_seq_id(dev);
3735af491a2SKozlowski Mateusz 	ftl_band_set_state(band, FTL_BAND_STATE_CLOSING);
3745af491a2SKozlowski Mateusz 	ftl_basic_rq_init(dev, &band->metadata_rq, metadata, num_blocks);
3755af491a2SKozlowski Mateusz 	ftl_basic_rq_set_owner(&band->metadata_rq, band_map_write_cb, band);
3765af491a2SKozlowski Mateusz 
3775af491a2SKozlowski Mateusz 	ftl_band_basic_rq_write(band, &band->metadata_rq);
3785af491a2SKozlowski Mateusz }
3795af491a2SKozlowski Mateusz 
3805af491a2SKozlowski Mateusz static void
band_free_cb(int status,void * ctx)3815af491a2SKozlowski Mateusz band_free_cb(int status, void *ctx)
3825af491a2SKozlowski Mateusz {
3835af491a2SKozlowski Mateusz 	struct ftl_band *band = (struct ftl_band *)ctx;
3845af491a2SKozlowski Mateusz 
3855af491a2SKozlowski Mateusz 	if (spdk_unlikely(status)) {
386759e1769SKozlowski Mateusz #ifdef SPDK_FTL_RETRY_ON_ERROR
3875af491a2SKozlowski Mateusz 		ftl_md_persist_entry_retry(&band->md_persist_entry_ctx);
3885af491a2SKozlowski Mateusz 		return;
389759e1769SKozlowski Mateusz #else
390759e1769SKozlowski Mateusz 		ftl_abort();
391759e1769SKozlowski Mateusz #endif
3925af491a2SKozlowski Mateusz 	}
3935af491a2SKozlowski Mateusz 
3945af491a2SKozlowski Mateusz 	ftl_band_release_p2l_map(band);
3955af491a2SKozlowski Mateusz 	FTL_DEBUGLOG(band->dev, "Band is going to free state. Band id: %u\n", band->id);
3965af491a2SKozlowski Mateusz 	ftl_band_set_state(band, FTL_BAND_STATE_FREE);
3975af491a2SKozlowski Mateusz 	assert(0 == band->p2l_map.ref_cnt);
3985af491a2SKozlowski Mateusz }
3995af491a2SKozlowski Mateusz 
4005af491a2SKozlowski Mateusz void
ftl_band_free(struct ftl_band * band)4015af491a2SKozlowski Mateusz ftl_band_free(struct ftl_band *band)
4025af491a2SKozlowski Mateusz {
4035af491a2SKozlowski Mateusz 	struct spdk_ftl_dev *dev = band->dev;
4045af491a2SKozlowski Mateusz 	struct ftl_p2l_map *p2l_map = &band->p2l_map;
4055af491a2SKozlowski Mateusz 	struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_BAND_MD];
40630ef80cdSMateusz Kozlowski 	struct ftl_layout_region *region = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD);
4075af491a2SKozlowski Mateusz 
4085af491a2SKozlowski Mateusz 	memcpy(p2l_map->band_dma_md, band->md, region->entry_size * FTL_BLOCK_SIZE);
4095af491a2SKozlowski Mateusz 	p2l_map->band_dma_md->state = FTL_BAND_STATE_FREE;
41036049672SArtur Paszkiewicz 	p2l_map->band_dma_md->close_seq_id = 0;
4115af491a2SKozlowski Mateusz 	p2l_map->band_dma_md->p2l_map_checksum = 0;
4125af491a2SKozlowski Mateusz 
413*1f11e145SMateusz Kozlowski 	ftl_md_persist_entries(md, band->id, 1, p2l_map->band_dma_md, NULL,
4145af491a2SKozlowski Mateusz 			       band_free_cb, band, &band->md_persist_entry_ctx);
4155af491a2SKozlowski Mateusz 
4165af491a2SKozlowski Mateusz 	/* TODO: The whole band erase code should probably be done here instead */
4175af491a2SKozlowski Mateusz }
4185af491a2SKozlowski Mateusz 
4195af491a2SKozlowski Mateusz static void
read_md_cb(struct ftl_basic_rq * brq)420711759a0SKozlowski Mateusz read_md_cb(struct ftl_basic_rq *brq)
421711759a0SKozlowski Mateusz {
422711759a0SKozlowski Mateusz 	struct ftl_band *band = brq->owner.priv;
423711759a0SKozlowski Mateusz 	struct spdk_ftl_dev *dev = band->dev;
424711759a0SKozlowski Mateusz 	ftl_band_ops_cb cb;
425711759a0SKozlowski Mateusz 	uint32_t band_map_crc;
426711759a0SKozlowski Mateusz 	bool success = true;
427711759a0SKozlowski Mateusz 	void *priv;
428711759a0SKozlowski Mateusz 
429711759a0SKozlowski Mateusz 	cb = band->owner.ops_fn;
430711759a0SKozlowski Mateusz 	priv = band->owner.priv;
431711759a0SKozlowski Mateusz 
432711759a0SKozlowski Mateusz 	if (!brq->success) {
433711759a0SKozlowski Mateusz 		ftl_band_basic_rq_read(band, &band->metadata_rq);
434711759a0SKozlowski Mateusz 		return;
435711759a0SKozlowski Mateusz 	}
436711759a0SKozlowski Mateusz 
437711759a0SKozlowski Mateusz 	band_map_crc = spdk_crc32c_update(band->p2l_map.band_map,
438711759a0SKozlowski Mateusz 					  ftl_tail_md_num_blocks(band->dev) * FTL_BLOCK_SIZE, 0);
439711759a0SKozlowski Mateusz 	if (band->md->p2l_map_checksum && band->md->p2l_map_checksum != band_map_crc) {
440711759a0SKozlowski Mateusz 		FTL_ERRLOG(dev, "GC error, inconsistent P2L map CRC\n");
441711759a0SKozlowski Mateusz 		success = false;
4421790ee8aSArtur Paszkiewicz 
4431790ee8aSArtur Paszkiewicz 		ftl_stats_crc_error(band->dev, FTL_STATS_TYPE_GC);
444711759a0SKozlowski Mateusz 	}
445711759a0SKozlowski Mateusz 	band->owner.ops_fn = NULL;
446711759a0SKozlowski Mateusz 	band->owner.priv = NULL;
447711759a0SKozlowski Mateusz 	cb(band, priv, success);
448711759a0SKozlowski Mateusz }
449711759a0SKozlowski Mateusz 
450711759a0SKozlowski Mateusz static int
_read_md(struct ftl_band * band)451711759a0SKozlowski Mateusz _read_md(struct ftl_band *band)
452711759a0SKozlowski Mateusz {
453711759a0SKozlowski Mateusz 	struct spdk_ftl_dev *dev = band->dev;
454711759a0SKozlowski Mateusz 	struct ftl_basic_rq *rq = &band->metadata_rq;
455711759a0SKozlowski Mateusz 
456711759a0SKozlowski Mateusz 	if (ftl_band_alloc_p2l_map(band)) {
457711759a0SKozlowski Mateusz 		return -ENOMEM;
458711759a0SKozlowski Mateusz 	}
459711759a0SKozlowski Mateusz 
460711759a0SKozlowski Mateusz 	/* Read P2L map */
461711759a0SKozlowski Mateusz 	ftl_basic_rq_init(dev, rq, band->p2l_map.band_map, ftl_p2l_map_num_blocks(dev));
462711759a0SKozlowski Mateusz 	ftl_basic_rq_set_owner(rq, read_md_cb, band);
463711759a0SKozlowski Mateusz 
464711759a0SKozlowski Mateusz 	rq->io.band = band;
465711759a0SKozlowski Mateusz 	rq->io.addr = ftl_band_p2l_map_addr(band);
466711759a0SKozlowski Mateusz 
467711759a0SKozlowski Mateusz 	ftl_band_basic_rq_read(band, &band->metadata_rq);
468711759a0SKozlowski Mateusz 
469711759a0SKozlowski Mateusz 	return 0;
470711759a0SKozlowski Mateusz }
471711759a0SKozlowski Mateusz 
472711759a0SKozlowski Mateusz static void
read_md(void * band)473711759a0SKozlowski Mateusz read_md(void *band)
474711759a0SKozlowski Mateusz {
475711759a0SKozlowski Mateusz 	int rc;
476711759a0SKozlowski Mateusz 
477711759a0SKozlowski Mateusz 	rc = _read_md(band);
478711759a0SKozlowski Mateusz 	if (spdk_unlikely(rc)) {
479711759a0SKozlowski Mateusz 		spdk_thread_send_msg(spdk_get_thread(), read_md, band);
480711759a0SKozlowski Mateusz 	}
481711759a0SKozlowski Mateusz }
482711759a0SKozlowski Mateusz 
483711759a0SKozlowski Mateusz static void
read_tail_md_cb(struct ftl_basic_rq * brq)4847c9d3ea5SArtur Paszkiewicz read_tail_md_cb(struct ftl_basic_rq *brq)
4857c9d3ea5SArtur Paszkiewicz {
4867c9d3ea5SArtur Paszkiewicz 	struct ftl_band *band = brq->owner.priv;
4877c9d3ea5SArtur Paszkiewicz 	enum ftl_md_status status = FTL_MD_IO_FAILURE;
4887c9d3ea5SArtur Paszkiewicz 	ftl_band_md_cb cb;
4897c9d3ea5SArtur Paszkiewicz 	void *priv;
4907c9d3ea5SArtur Paszkiewicz 
4917c9d3ea5SArtur Paszkiewicz 	if (spdk_unlikely(!brq->success)) {
4927c9d3ea5SArtur Paszkiewicz 		/* Retries the read in case of error */
4937c9d3ea5SArtur Paszkiewicz 		ftl_band_basic_rq_read(band, &band->metadata_rq);
4947c9d3ea5SArtur Paszkiewicz 		return;
4957c9d3ea5SArtur Paszkiewicz 	}
4967c9d3ea5SArtur Paszkiewicz 
4977c9d3ea5SArtur Paszkiewicz 	cb = band->owner.md_fn;
4987c9d3ea5SArtur Paszkiewicz 	band->owner.md_fn = NULL;
4997c9d3ea5SArtur Paszkiewicz 
5007c9d3ea5SArtur Paszkiewicz 	priv = band->owner.priv;
5017c9d3ea5SArtur Paszkiewicz 	band->owner.priv = NULL;
5027c9d3ea5SArtur Paszkiewicz 
5037c9d3ea5SArtur Paszkiewicz 	status = FTL_MD_SUCCESS;
5047c9d3ea5SArtur Paszkiewicz 
5057c9d3ea5SArtur Paszkiewicz 	cb(band, priv, status);
5067c9d3ea5SArtur Paszkiewicz }
5077c9d3ea5SArtur Paszkiewicz 
5087c9d3ea5SArtur Paszkiewicz void
ftl_band_read_tail_brq_md(struct ftl_band * band,ftl_band_md_cb cb,void * cntx)5097c9d3ea5SArtur Paszkiewicz ftl_band_read_tail_brq_md(struct ftl_band *band, ftl_band_md_cb cb, void *cntx)
5107c9d3ea5SArtur Paszkiewicz {
5117c9d3ea5SArtur Paszkiewicz 	struct spdk_ftl_dev *dev = band->dev;
5127c9d3ea5SArtur Paszkiewicz 	struct ftl_basic_rq *rq = &band->metadata_rq;
5137c9d3ea5SArtur Paszkiewicz 
5147c9d3ea5SArtur Paszkiewicz 	ftl_basic_rq_init(dev, rq, band->p2l_map.band_map, ftl_tail_md_num_blocks(dev));
5157c9d3ea5SArtur Paszkiewicz 	ftl_basic_rq_set_owner(rq, read_tail_md_cb, band);
5167c9d3ea5SArtur Paszkiewicz 
5177c9d3ea5SArtur Paszkiewicz 	assert(!band->owner.md_fn);
5187c9d3ea5SArtur Paszkiewicz 	assert(!band->owner.priv);
5197c9d3ea5SArtur Paszkiewicz 	band->owner.md_fn = cb;
5207c9d3ea5SArtur Paszkiewicz 	band->owner.priv = cntx;
5217c9d3ea5SArtur Paszkiewicz 
5227c9d3ea5SArtur Paszkiewicz 	rq->io.band = band;
5237c9d3ea5SArtur Paszkiewicz 	rq->io.addr = band->tail_md_addr;
5247c9d3ea5SArtur Paszkiewicz 
5257c9d3ea5SArtur Paszkiewicz 	ftl_band_basic_rq_read(band, &band->metadata_rq);
5267c9d3ea5SArtur Paszkiewicz }
527711759a0SKozlowski Mateusz 
528711759a0SKozlowski Mateusz void
ftl_band_get_next_gc(struct spdk_ftl_dev * dev,ftl_band_ops_cb cb,void * cntx)529711759a0SKozlowski Mateusz ftl_band_get_next_gc(struct spdk_ftl_dev *dev, ftl_band_ops_cb cb, void *cntx)
530711759a0SKozlowski Mateusz {
531711759a0SKozlowski Mateusz 	struct ftl_band *band = ftl_band_search_next_to_reloc(dev);
532711759a0SKozlowski Mateusz 
533711759a0SKozlowski Mateusz 	/* if disk is very small, GC start very early that no band is ready for it */
534711759a0SKozlowski Mateusz 	if (spdk_unlikely(!band)) {
535711759a0SKozlowski Mateusz 		cb(NULL, cntx, false);
536711759a0SKozlowski Mateusz 		return;
537711759a0SKozlowski Mateusz 	}
538711759a0SKozlowski Mateusz 
539711759a0SKozlowski Mateusz 	/* Only one owner is allowed */
540711759a0SKozlowski Mateusz 	assert(!band->queue_depth);
541711759a0SKozlowski Mateusz 	assert(!band->owner.ops_fn);
542711759a0SKozlowski Mateusz 	assert(!band->owner.priv);
543711759a0SKozlowski Mateusz 	band->owner.ops_fn = cb;
544711759a0SKozlowski Mateusz 	band->owner.priv = cntx;
545711759a0SKozlowski Mateusz 
546711759a0SKozlowski Mateusz 	read_md(band);
547711759a0SKozlowski Mateusz }
548