148 lines
3.3 KiB
C
148 lines
3.3 KiB
C
|
/* 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;
|
||
|
}
|