blob: eb89f2dfc53173af1b8d667eef8d9265e0d61928 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <string.h>
#include "fake-nand-interface.h"
namespace ftl_mtd {
FakeNandInterface::FakeNandInterface(uint32_t page_size, uint32_t oob_size, uint32_t block_size,
uint32_t size)
: read_actual_(page_size), fail_read_(false), fail_write_(false), fail_erase_(false),
fail_is_bad_block_(false), page_size_(page_size), oob_size_(oob_size),
block_size_(block_size), size_(size) {
size_t num_blocks = size_ / block_size_;
bad_blocks_ = std::make_unique<bool[]>(num_blocks);
size_t data_size = (size_ / page_size_) * (page_size_ + oob_size_);
data_ = std::make_unique<uint8_t[]>(data_size);
}
uint32_t FakeNandInterface::PageSize() {
return page_size_;
}
uint32_t FakeNandInterface::BlockSize() {
return block_size_;
}
uint32_t FakeNandInterface::OobSize() {
return oob_size_;
}
uint32_t FakeNandInterface::Size() {
return size_;
}
zx_status_t FakeNandInterface::ReadOob(uint32_t byte_offset, void* bytes) {
if (fail_read_) {
return ZX_ERR_IO;
}
void* oob_src;
zx_status_t status = GetPagePointers(byte_offset, nullptr, &oob_src);
if (status != ZX_OK) {
return status;
}
memcpy(bytes, oob_src, oob_size_);
return ZX_OK;
}
zx_status_t FakeNandInterface::ReadPage(uint32_t byte_offset, void* bytes, uint32_t* actual) {
if (fail_read_) {
return ZX_ERR_IO;
}
void* data_src;
zx_status_t status = GetPagePointers(byte_offset, &data_src, nullptr);
if (status != ZX_OK) {
return status;
}
memcpy(bytes, data_src, page_size_);
*actual = read_actual_;
return ZX_OK;
}
zx_status_t FakeNandInterface::WritePage(uint32_t byte_offset, const void* data, const void* oob) {
if (fail_write_) {
return ZX_ERR_IO;
}
void* data_dest;
void* oob_dest;
zx_status_t status = GetPagePointers(byte_offset, &data_dest, &oob_dest);
if (status != ZX_OK) {
return status;
}
memcpy(data_dest, data, page_size_);
memcpy(oob_dest, oob, oob_size_);
return ZX_OK;
}
zx_status_t FakeNandInterface::EraseBlock(uint32_t byte_offset) {
if (fail_erase_ || byte_offset % block_size_ != 0) {
return ZX_ERR_IO;
}
void* data_dest;
void* oob_dest;
zx_status_t status = GetPagePointers(byte_offset, &data_dest, &oob_dest);
if (status != ZX_OK) {
return status;
}
size_t data_size = block_size_ / page_size_ * (page_size_ + oob_size_);
memset(data_dest, 0xFF, data_size);
return ZX_OK;
}
zx_status_t FakeNandInterface::IsBadBlock(uint32_t byte_offset, bool* is_bad_block) {
if (fail_is_bad_block_ || byte_offset % block_size_ != 0) {
return ZX_ERR_IO;
}
uint32_t block_num = byte_offset / block_size_;
*is_bad_block = bad_blocks_[block_num];
return ZX_OK;
}
zx_status_t FakeNandInterface::GetPagePointers(uint32_t byte_offset, void** data, void** oob) {
if (byte_offset % page_size_ != 0) {
return ZX_ERR_INVALID_ARGS;
}
uint32_t page_index = byte_offset / page_size_;
uint32_t page_offset = page_index * (page_size_ + oob_size_);
uint32_t oob_offset = page_offset + page_size_;
if (data) {
*data = &data_[page_offset];
}
if (oob) {
*oob = &data_[oob_offset];
}
return ZX_OK;
}
void FakeNandInterface::SetBadBlock(uint32_t block_num, bool is_bad) {
bad_blocks_[block_num] = is_bad;
}
} // namespace ftl_mtd