192b5ebe0SKozlowski Mateusz /* SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse * Copyright (C) 2018 Intel Corporation.
392b5ebe0SKozlowski Mateusz * All rights reserved.
492b5ebe0SKozlowski Mateusz */
592b5ebe0SKozlowski Mateusz
692b5ebe0SKozlowski Mateusz #include "spdk/ftl.h"
792b5ebe0SKozlowski Mateusz #include "ftl_debug.h"
888d1c3a6SKozlowski Mateusz #include "ftl_band.h"
988d1c3a6SKozlowski Mateusz
1088d1c3a6SKozlowski Mateusz /* TODO: Switch to INFOLOG instead, we can control the printing via spdk_log_get_flag */
1188d1c3a6SKozlowski Mateusz #if defined(DEBUG)
1288d1c3a6SKozlowski Mateusz
1388d1c3a6SKozlowski Mateusz static const char *ftl_band_state_str[] = {
1488d1c3a6SKozlowski Mateusz "free",
1588d1c3a6SKozlowski Mateusz "prep",
1688d1c3a6SKozlowski Mateusz "opening",
1788d1c3a6SKozlowski Mateusz "open",
1888d1c3a6SKozlowski Mateusz "full",
1988d1c3a6SKozlowski Mateusz "closing",
2088d1c3a6SKozlowski Mateusz "closed",
2188d1c3a6SKozlowski Mateusz "max"
2288d1c3a6SKozlowski Mateusz };
2388d1c3a6SKozlowski Mateusz
248fad5718SArtur Paszkiewicz struct ftl_band_validate_ctx {
258fad5718SArtur Paszkiewicz struct ftl_band *band;
268fad5718SArtur Paszkiewicz ftl_band_validate_md_cb cb;
278fad5718SArtur Paszkiewicz int remaining;
288fad5718SArtur Paszkiewicz uint64_t pin_cnt;
298fad5718SArtur Paszkiewicz uint64_t current_offset;
308fad5718SArtur Paszkiewicz struct ftl_l2p_pin_ctx l2p_pin_ctx[];
318fad5718SArtur Paszkiewicz };
328fad5718SArtur Paszkiewicz
338fad5718SArtur Paszkiewicz static void ftl_band_validate_md_l2p_pin_cb(struct spdk_ftl_dev *dev, int status,
348fad5718SArtur Paszkiewicz struct ftl_l2p_pin_ctx *pin_ctx);
358fad5718SArtur Paszkiewicz
368fad5718SArtur Paszkiewicz #define FTL_MD_VALIDATE_LBA_PER_ITERATION 128
378fad5718SArtur Paszkiewicz
388fad5718SArtur Paszkiewicz static void
ftl_band_validate_md_pin(struct ftl_band_validate_ctx * ctx)398fad5718SArtur Paszkiewicz ftl_band_validate_md_pin(struct ftl_band_validate_ctx *ctx)
408fad5718SArtur Paszkiewicz {
418fad5718SArtur Paszkiewicz struct ftl_band *band = ctx->band;
428fad5718SArtur Paszkiewicz struct spdk_ftl_dev *dev = band->dev;
438fad5718SArtur Paszkiewicz struct ftl_p2l_map *p2l_map = &band->p2l_map;
448fad5718SArtur Paszkiewicz size_t i, size;
458fad5718SArtur Paszkiewicz struct ftl_l2p_pin_ctx tmp_pin_ctx = {
468fad5718SArtur Paszkiewicz .cb_ctx = ctx
478fad5718SArtur Paszkiewicz };
488fad5718SArtur Paszkiewicz
498fad5718SArtur Paszkiewicz /* Since the first L2P page may already be pinned, the ftl_band_validate_md_l2p_pin_cb could be prematurely
508fad5718SArtur Paszkiewicz * triggered. Initializing to 1 and then triggering the callback again manually prevents the issue.
518fad5718SArtur Paszkiewicz */
528fad5718SArtur Paszkiewicz ctx->remaining = 1;
538fad5718SArtur Paszkiewicz size = spdk_min(FTL_MD_VALIDATE_LBA_PER_ITERATION,
548fad5718SArtur Paszkiewicz ftl_get_num_blocks_in_band(dev) - ctx->current_offset);
558fad5718SArtur Paszkiewicz
568fad5718SArtur Paszkiewicz for (i = ctx->current_offset; i < ctx->current_offset + size; ++i) {
578fad5718SArtur Paszkiewicz if (!ftl_bitmap_get(p2l_map->valid, i)) {
588fad5718SArtur Paszkiewicz ctx->l2p_pin_ctx[i].lba = FTL_LBA_INVALID;
598fad5718SArtur Paszkiewicz continue;
608fad5718SArtur Paszkiewicz }
618fad5718SArtur Paszkiewicz
6236049672SArtur Paszkiewicz assert(p2l_map->band_map[i].lba != FTL_LBA_INVALID);
638fad5718SArtur Paszkiewicz ctx->remaining++;
648fad5718SArtur Paszkiewicz ctx->pin_cnt++;
6536049672SArtur Paszkiewicz ftl_l2p_pin(dev, p2l_map->band_map[i].lba, 1, ftl_band_validate_md_l2p_pin_cb, ctx,
668fad5718SArtur Paszkiewicz &ctx->l2p_pin_ctx[i]);
678fad5718SArtur Paszkiewicz }
688fad5718SArtur Paszkiewicz
698fad5718SArtur Paszkiewicz ftl_band_validate_md_l2p_pin_cb(dev, 0, &tmp_pin_ctx);
708fad5718SArtur Paszkiewicz }
718fad5718SArtur Paszkiewicz
728fad5718SArtur Paszkiewicz static void
_ftl_band_validate_md(void * _ctx)738fad5718SArtur Paszkiewicz _ftl_band_validate_md(void *_ctx)
748fad5718SArtur Paszkiewicz {
758fad5718SArtur Paszkiewicz struct ftl_band_validate_ctx *ctx = _ctx;
768fad5718SArtur Paszkiewicz struct ftl_band *band = ctx->band;
778fad5718SArtur Paszkiewicz struct spdk_ftl_dev *dev = band->dev;
788fad5718SArtur Paszkiewicz ftl_addr addr_l2p;
798fad5718SArtur Paszkiewicz size_t i, size;
808fad5718SArtur Paszkiewicz bool valid = true;
818fad5718SArtur Paszkiewicz uint64_t lba;
828fad5718SArtur Paszkiewicz
838fad5718SArtur Paszkiewicz size = spdk_min(FTL_MD_VALIDATE_LBA_PER_ITERATION,
848fad5718SArtur Paszkiewicz ftl_get_num_blocks_in_band(dev) - ctx->current_offset);
858fad5718SArtur Paszkiewicz
868fad5718SArtur Paszkiewicz for (i = ctx->current_offset; i < ctx->current_offset + size; ++i) {
878fad5718SArtur Paszkiewicz lba = ctx->l2p_pin_ctx[i].lba;
888fad5718SArtur Paszkiewicz if (lba == FTL_LBA_INVALID) {
898fad5718SArtur Paszkiewicz continue;
908fad5718SArtur Paszkiewicz }
918fad5718SArtur Paszkiewicz
928fad5718SArtur Paszkiewicz if (ftl_bitmap_get(band->p2l_map.valid, i)) {
938fad5718SArtur Paszkiewicz addr_l2p = ftl_l2p_get(dev, lba);
948fad5718SArtur Paszkiewicz
958fad5718SArtur Paszkiewicz if (addr_l2p != FTL_ADDR_INVALID && !ftl_addr_in_nvc(dev, addr_l2p) &&
968fad5718SArtur Paszkiewicz addr_l2p != ftl_band_addr_from_block_offset(band, i)) {
978fad5718SArtur Paszkiewicz valid = false;
988fad5718SArtur Paszkiewicz }
998fad5718SArtur Paszkiewicz }
1008fad5718SArtur Paszkiewicz
1018fad5718SArtur Paszkiewicz ctx->pin_cnt--;
1028fad5718SArtur Paszkiewicz ftl_l2p_unpin(dev, lba, 1);
1038fad5718SArtur Paszkiewicz }
1048fad5718SArtur Paszkiewicz assert(ctx->pin_cnt == 0);
1058fad5718SArtur Paszkiewicz
1068fad5718SArtur Paszkiewicz ctx->current_offset += size;
1078fad5718SArtur Paszkiewicz
1088fad5718SArtur Paszkiewicz if (ctx->current_offset == ftl_get_num_blocks_in_band(dev)) {
1098fad5718SArtur Paszkiewicz ctx->cb(band, valid);
1108fad5718SArtur Paszkiewicz free(ctx);
1118fad5718SArtur Paszkiewicz return;
1128fad5718SArtur Paszkiewicz }
1138fad5718SArtur Paszkiewicz
1148fad5718SArtur Paszkiewicz ftl_band_validate_md_pin(ctx);
1158fad5718SArtur Paszkiewicz }
1168fad5718SArtur Paszkiewicz
1178fad5718SArtur Paszkiewicz static void
ftl_band_validate_md_l2p_pin_cb(struct spdk_ftl_dev * dev,int status,struct ftl_l2p_pin_ctx * pin_ctx)1188fad5718SArtur Paszkiewicz ftl_band_validate_md_l2p_pin_cb(struct spdk_ftl_dev *dev, int status,
1198fad5718SArtur Paszkiewicz struct ftl_l2p_pin_ctx *pin_ctx)
1208fad5718SArtur Paszkiewicz {
1218fad5718SArtur Paszkiewicz struct ftl_band_validate_ctx *ctx = pin_ctx->cb_ctx;
1228fad5718SArtur Paszkiewicz
1238fad5718SArtur Paszkiewicz assert(status == 0);
1248fad5718SArtur Paszkiewicz
1258fad5718SArtur Paszkiewicz if (--ctx->remaining == 0) {
1268fad5718SArtur Paszkiewicz spdk_thread_send_msg(dev->core_thread, _ftl_band_validate_md, ctx);
1278fad5718SArtur Paszkiewicz }
1288fad5718SArtur Paszkiewicz }
1298fad5718SArtur Paszkiewicz
1308fad5718SArtur Paszkiewicz void
ftl_band_validate_md(struct ftl_band * band,ftl_band_validate_md_cb cb)1318fad5718SArtur Paszkiewicz ftl_band_validate_md(struct ftl_band *band, ftl_band_validate_md_cb cb)
1328fad5718SArtur Paszkiewicz {
1338fad5718SArtur Paszkiewicz struct ftl_band_validate_ctx *ctx;
1348fad5718SArtur Paszkiewicz size_t size;
1358fad5718SArtur Paszkiewicz
1368fad5718SArtur Paszkiewicz assert(cb);
1378fad5718SArtur Paszkiewicz
1388fad5718SArtur Paszkiewicz size = ftl_get_num_blocks_in_band(band->dev);
1398fad5718SArtur Paszkiewicz
1408fad5718SArtur Paszkiewicz ctx = malloc(sizeof(*ctx) + size * sizeof(*ctx->l2p_pin_ctx));
1418fad5718SArtur Paszkiewicz
1428fad5718SArtur Paszkiewicz if (!ctx) {
1438fad5718SArtur Paszkiewicz FTL_ERRLOG(band->dev, "Failed to allocate memory for band validate context");
1448fad5718SArtur Paszkiewicz cb(band, false);
1458fad5718SArtur Paszkiewicz return;
1468fad5718SArtur Paszkiewicz }
1478fad5718SArtur Paszkiewicz
1488fad5718SArtur Paszkiewicz ctx->band = band;
1498fad5718SArtur Paszkiewicz ctx->cb = cb;
1508fad5718SArtur Paszkiewicz ctx->pin_cnt = 0;
1518fad5718SArtur Paszkiewicz ctx->current_offset = 0;
1528fad5718SArtur Paszkiewicz
1538fad5718SArtur Paszkiewicz ftl_band_validate_md_pin(ctx);
1548fad5718SArtur Paszkiewicz }
1558fad5718SArtur Paszkiewicz
15688d1c3a6SKozlowski Mateusz void
ftl_dev_dump_bands(struct spdk_ftl_dev * dev)15788d1c3a6SKozlowski Mateusz ftl_dev_dump_bands(struct spdk_ftl_dev *dev)
15888d1c3a6SKozlowski Mateusz {
15988d1c3a6SKozlowski Mateusz uint64_t i;
16088d1c3a6SKozlowski Mateusz
16188d1c3a6SKozlowski Mateusz if (!dev->bands) {
16288d1c3a6SKozlowski Mateusz return;
16388d1c3a6SKozlowski Mateusz }
16488d1c3a6SKozlowski Mateusz
16588d1c3a6SKozlowski Mateusz FTL_NOTICELOG(dev, "Bands validity:\n");
16688d1c3a6SKozlowski Mateusz for (i = 0; i < ftl_get_num_bands(dev); ++i) {
16788d1c3a6SKozlowski Mateusz FTL_NOTICELOG(dev, " Band %3zu: %8zu / %zu \twr_cnt: %"PRIu64
16888d1c3a6SKozlowski Mateusz "\tstate: %s\n",
16988d1c3a6SKozlowski Mateusz i + 1, dev->bands[i].p2l_map.num_valid,
17088d1c3a6SKozlowski Mateusz ftl_band_user_blocks(&dev->bands[i]),
17188d1c3a6SKozlowski Mateusz dev->bands[i].md->wr_cnt,
17288d1c3a6SKozlowski Mateusz ftl_band_state_str[dev->bands[i].md->state]);
17388d1c3a6SKozlowski Mateusz }
17488d1c3a6SKozlowski Mateusz }
17588d1c3a6SKozlowski Mateusz
17688d1c3a6SKozlowski Mateusz #endif /* defined(DEBUG) */
17792b5ebe0SKozlowski Mateusz
17892b5ebe0SKozlowski Mateusz void
ftl_dev_dump_stats(const struct spdk_ftl_dev * dev)17992b5ebe0SKozlowski Mateusz ftl_dev_dump_stats(const struct spdk_ftl_dev *dev)
18092b5ebe0SKozlowski Mateusz {
18188d1c3a6SKozlowski Mateusz uint64_t i, total = 0;
18292b5ebe0SKozlowski Mateusz char uuid[SPDK_UUID_STRING_LEN];
1831790ee8aSArtur Paszkiewicz double waf;
1841790ee8aSArtur Paszkiewicz uint64_t write_user, write_total;
1851790ee8aSArtur Paszkiewicz const char *limits[] = {
1861790ee8aSArtur Paszkiewicz [SPDK_FTL_LIMIT_CRIT] = "crit",
1871790ee8aSArtur Paszkiewicz [SPDK_FTL_LIMIT_HIGH] = "high",
1881790ee8aSArtur Paszkiewicz [SPDK_FTL_LIMIT_LOW] = "low",
1891790ee8aSArtur Paszkiewicz [SPDK_FTL_LIMIT_START] = "start"
1901790ee8aSArtur Paszkiewicz };
1911790ee8aSArtur Paszkiewicz
1921790ee8aSArtur Paszkiewicz (void)limits;
19392b5ebe0SKozlowski Mateusz
19488d1c3a6SKozlowski Mateusz if (!dev->bands) {
19588d1c3a6SKozlowski Mateusz return;
19688d1c3a6SKozlowski Mateusz }
19788d1c3a6SKozlowski Mateusz
19888d1c3a6SKozlowski Mateusz /* Count the number of valid LBAs */
19988d1c3a6SKozlowski Mateusz for (i = 0; i < ftl_get_num_bands(dev); ++i) {
20088d1c3a6SKozlowski Mateusz total += dev->bands[i].p2l_map.num_valid;
20188d1c3a6SKozlowski Mateusz }
20288d1c3a6SKozlowski Mateusz
2031790ee8aSArtur Paszkiewicz write_user = dev->stats.entries[FTL_STATS_TYPE_CMP].write.blocks;
2041790ee8aSArtur Paszkiewicz write_total = write_user +
2051790ee8aSArtur Paszkiewicz dev->stats.entries[FTL_STATS_TYPE_GC].write.blocks +
2061790ee8aSArtur Paszkiewicz dev->stats.entries[FTL_STATS_TYPE_MD_BASE].write.blocks;
2071790ee8aSArtur Paszkiewicz
2081790ee8aSArtur Paszkiewicz waf = (double)write_total / (double)write_user;
2091790ee8aSArtur Paszkiewicz
21092b5ebe0SKozlowski Mateusz spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
21192b5ebe0SKozlowski Mateusz FTL_NOTICELOG(dev, "\n");
21292b5ebe0SKozlowski Mateusz FTL_NOTICELOG(dev, "device UUID: %s\n", uuid);
21392b5ebe0SKozlowski Mateusz FTL_NOTICELOG(dev, "total valid LBAs: %zu\n", total);
2141790ee8aSArtur Paszkiewicz FTL_NOTICELOG(dev, "total writes: %"PRIu64"\n", write_total);
2151790ee8aSArtur Paszkiewicz FTL_NOTICELOG(dev, "user writes: %"PRIu64"\n", write_user);
2161790ee8aSArtur Paszkiewicz FTL_NOTICELOG(dev, "WAF: %.4lf\n", waf);
2171790ee8aSArtur Paszkiewicz #ifdef DEBUG
2181790ee8aSArtur Paszkiewicz FTL_NOTICELOG(dev, "limits:\n");
2191790ee8aSArtur Paszkiewicz for (i = 0; i < SPDK_FTL_LIMIT_MAX; ++i) {
2201790ee8aSArtur Paszkiewicz FTL_NOTICELOG(dev, " %5s: %"PRIu64"\n", limits[i], dev->stats.limits[i]);
2211790ee8aSArtur Paszkiewicz }
2221790ee8aSArtur Paszkiewicz #endif
22392b5ebe0SKozlowski Mateusz }
224