Spdk/lib/ftl/ftl_band.c

148 lines
3.3 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation.
* All rights reserved.
*/
#include "spdk/stdinc.h"
#include "spdk/crc32.h"
#include "spdk/likely.h"
#include "spdk/util.h"
#include "spdk/ftl.h"
#include "ftl_band.h"
#include "ftl_io.h"
#include "ftl_core.h"
#include "ftl_internal.h"
#include "utils/ftl_md.h"
#include "utils/ftl_defs.h"
static uint64_t
ftl_band_tail_md_offset(const struct ftl_band *band)
{
return ftl_get_num_blocks_in_band(band->dev) -
ftl_tail_md_num_blocks(band->dev);
}
int
ftl_band_filled(struct ftl_band *band, size_t offset)
{
return offset == ftl_band_tail_md_offset(band);
}
ftl_addr
ftl_band_tail_md_addr(struct ftl_band *band)
{
ftl_addr addr;
/* Metadata should be aligned to xfer size */
assert(ftl_band_tail_md_offset(band) % band->dev->xfer_size == 0);
addr = ftl_band_tail_md_offset(band) + band->start_addr;
return addr;
}
void
ftl_band_set_type(struct ftl_band *band, enum ftl_band_type type)
{
switch (type) {
case FTL_BAND_TYPE_COMPACTION:
case FTL_BAND_TYPE_GC:
band->md->type = type;
break;
default:
assert(false);
break;
}
}
size_t
ftl_band_user_blocks_left(const struct ftl_band *band, size_t offset)
{
size_t tail_md_offset = ftl_band_tail_md_offset(band);
if (spdk_unlikely(offset > tail_md_offset)) {
return 0;
}
return tail_md_offset - offset;
}
struct ftl_band *
ftl_band_from_addr(struct spdk_ftl_dev *dev, ftl_addr addr)
{
size_t band_id = ftl_addr_get_band(dev, addr);
assert(band_id < ftl_get_num_bands(dev));
return &dev->bands[band_id];
}
uint64_t
ftl_band_block_offset_from_addr(struct ftl_band *band, ftl_addr addr)
{
assert(ftl_addr_get_band(band->dev, addr) == band->id);
return addr % ftl_get_num_blocks_in_band(band->dev);
}
ftl_addr
ftl_band_next_xfer_addr(struct ftl_band *band, ftl_addr addr, size_t num_blocks)
{
struct spdk_ftl_dev *dev = band->dev;
size_t num_xfers;
uint64_t offset;
assert(ftl_addr_get_band(dev, addr) == band->id);
offset = addr - band->start_addr;
/* In case starting address wasn't aligned to xfer_size, we'll align for consistent calculation
* purposes - the unaligned value will be preserved at the end however.
*/
num_blocks += (offset % dev->xfer_size);
offset -= (offset % dev->xfer_size);
/* Calculate offset based on xfer_size aligned writes */
num_xfers = (num_blocks / dev->xfer_size);
offset += num_xfers * dev->xfer_size;
num_blocks -= num_xfers * dev->xfer_size;
if (offset > ftl_get_num_blocks_in_band(dev)) {
return FTL_ADDR_INVALID;
}
/* If there's any unalignment (either starting addr value or num_blocks), reintroduce it to the final address
*/
if (num_blocks) {
offset += num_blocks;
if (offset > ftl_get_num_blocks_in_band(dev)) {
return FTL_ADDR_INVALID;
}
}
addr = band->start_addr + offset;
return addr;
}
ftl_addr
ftl_band_addr_from_block_offset(struct ftl_band *band, uint64_t block_off)
{
ftl_addr addr;
addr = block_off + band->id * ftl_get_num_blocks_in_band(band->dev);
return addr;
}
ftl_addr
ftl_band_next_addr(struct ftl_band *band, ftl_addr addr, size_t offset)
{
uint64_t block_off = ftl_band_block_offset_from_addr(band, addr);
return ftl_band_addr_from_block_offset(band, block_off + offset);
}
ftl_addr
ftl_band_p2l_map_addr(struct ftl_band *band)
{
return band->tail_md_addr;
}