blob: 57ca3f007419a4ab0405bf2f3118e73986e52f2d [file] [log] [blame]
// Copyright 2018 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 "ndm-ram-driver.h"
#include <unittest/unittest.h>
namespace {
constexpr uint32_t kPageSize = 2048;
constexpr uint32_t kOobSize = 16;
// 20 blocks of 32 pages, 4 bad blocks max.
constexpr ftl::VolumeOptions kDefaultOptions = {20, 4, 32 * kPageSize, kPageSize, kOobSize, 0};
bool TrivialLifetimeTest() {
BEGIN_TEST;
NdmRamDriver driver({});
END_TEST;
}
// Basic smoke tests for NdmRamDriver:
bool ReadWriteTest() {
BEGIN_TEST;
ASSERT_TRUE(ftl::InitModules());
NdmRamDriver driver(kDefaultOptions);
ASSERT_EQ(nullptr, driver.Init());
fbl::Array<uint8_t> data(new uint8_t[kPageSize * 2], kPageSize * 2);
fbl::Array<uint8_t> oob(new uint8_t[kOobSize * 2], kOobSize * 2);
memset(data.get(), 0x55, data.size());
memset(oob.get(), 0x66, oob.size());
ASSERT_EQ(ftl::kNdmOk, driver.NandWrite(5, 2, data.get(), oob.get()));
memset(data.get(), 0, data.size());
memset(oob.get(), 0, oob.size());
ASSERT_EQ(ftl::kNdmOk, driver.NandRead(5, 2, data.get(), oob.get()));
for (uint32_t i = 0; i < data.size(); i++) {
ASSERT_EQ(0x55, data[i]);
}
for (uint32_t i = 0; i < oob.size(); i++) {
ASSERT_EQ(0x66, oob[i]);
}
END_TEST;
}
// Writes a fixed pattern to the desired page.
bool WritePage(NdmRamDriver* driver, uint32_t page_num) {
BEGIN_TEST;
fbl::Array<uint8_t> data(new uint8_t[kPageSize], kPageSize);
fbl::Array<uint8_t> oob(new uint8_t[kOobSize], kOobSize);
memset(data.get(), 0x55, data.size());
memset(oob.get(), 0, oob.size());
ASSERT_EQ(ftl::kNdmOk, driver->NandWrite(page_num, 1, data.get(), oob.get()));
END_TEST;
}
bool IsEmptyTest() {
BEGIN_TEST;
ASSERT_TRUE(ftl::InitModules());
NdmRamDriver driver(kDefaultOptions);
ASSERT_EQ(nullptr, driver.Init());
// Use internal driver meta-data.
ASSERT_TRUE(driver.IsEmptyPage(0, nullptr, nullptr));
fbl::Array<uint8_t> data(new uint8_t[kPageSize], kPageSize);
fbl::Array<uint8_t> oob(new uint8_t[kOobSize], kOobSize);
memset(data.get(), 0x55, data.size());
memset(oob.get(), 0, oob.size());
ASSERT_EQ(ftl::kNdmOk, driver.NandWrite(0, 1, data.get(), oob.get()));
// Look at both meta-data and buffers.
ASSERT_FALSE(driver.IsEmptyPage(0, data.get(), oob.get()));
memset(data.get(), 0xff, data.size());
memset(oob.get(), 0xff, oob.size());
ASSERT_TRUE(driver.IsEmptyPage(0, data.get(), oob.get()));
END_TEST;
}
bool EraseTest() {
BEGIN_TEST;
ASSERT_TRUE(ftl::InitModules());
NdmRamDriver driver(kDefaultOptions);
ASSERT_EQ(nullptr, driver.Init());
ASSERT_TRUE(WritePage(&driver, 0));
ASSERT_EQ(ftl::kNdmOk, driver.NandErase(0));
ASSERT_TRUE(driver.IsEmptyPage(0, nullptr, nullptr));
END_TEST;
}
bool IsBadBlockTest() {
BEGIN_TEST;
ASSERT_TRUE(ftl::InitModules());
NdmRamDriver driver(kDefaultOptions);
ASSERT_EQ(nullptr, driver.Init());
ASSERT_EQ(ftl::kFalse, driver.IsBadBlock(0));
ASSERT_TRUE(WritePage(&driver, 0));
ASSERT_EQ(ftl::kTrue, driver.IsBadBlock(0));
END_TEST;
}
bool CreateVolumeTest() {
BEGIN_TEST;
ASSERT_TRUE(ftl::InitModules());
NdmRamDriver driver(kDefaultOptions);
ASSERT_EQ(nullptr, driver.Init());
ASSERT_EQ(nullptr, driver.Attach(nullptr));
ASSERT_TRUE(driver.Detach());
END_TEST;
}
bool ReAttachTest() {
BEGIN_TEST;
ASSERT_TRUE(ftl::InitModules());
NdmRamDriver driver(kDefaultOptions);
ASSERT_EQ(nullptr, driver.Init());
ASSERT_EQ(nullptr, driver.Attach(nullptr));
ASSERT_TRUE(WritePage(&driver, 5));
ASSERT_TRUE(driver.Detach());
ASSERT_EQ(nullptr, driver.Attach(nullptr));
fbl::Array<uint8_t> data(new uint8_t[kPageSize], kPageSize);
fbl::Array<uint8_t> oob(new uint8_t[kOobSize], kOobSize);
ASSERT_EQ(ftl::kNdmOk, driver.NandRead(5, 1, data.get(), oob.get()));
ASSERT_FALSE(driver.IsEmptyPage(5, data.get(), oob.get()));
END_TEST;
}
// NdmRamDriver is supposed to inject failures periodically. This tests that it
// does.
bool WriteBadBlockTest() {
BEGIN_TEST;
ASSERT_TRUE(ftl::InitModules());
NdmRamDriver driver(kDefaultOptions);
ASSERT_EQ(nullptr, driver.Init());
fbl::Array<uint8_t> data(new uint8_t[kPageSize], kPageSize);
fbl::Array<uint8_t> oob(new uint8_t[kOobSize], kOobSize);
memset(data.get(), 0, data.size());
memset(oob.get(), 0, oob.size());
for (int i = 0; i < kBadBlockInterval; i++) {
ASSERT_EQ(ftl::kNdmOk, driver.NandErase(0));
}
ASSERT_EQ(ftl::kNdmError, driver.NandWrite(0, 1, data.get(), oob.get()));
END_TEST;
}
// NdmRamDriver is supposed to inject failures periodically. This tests that it
// does.
bool ReadUnsafeEccTest() {
BEGIN_TEST;
ASSERT_TRUE(ftl::InitModules());
NdmRamDriver driver(kDefaultOptions);
ASSERT_EQ(nullptr, driver.Init());
fbl::Array<uint8_t> data(new uint8_t[kPageSize], kPageSize);
fbl::Array<uint8_t> oob(new uint8_t[kOobSize], kOobSize);
memset(data.get(), 0, data.size());
memset(oob.get(), 0, oob.size());
ASSERT_EQ(ftl::kNdmOk, driver.NandWrite(0, 1, data.get(), oob.get()));
for (int i = 0; i < kEccErrorInterval; i++) {
ASSERT_EQ(ftl::kNdmOk, driver.NandRead(0, 1, data.get(), oob.get()));
}
ASSERT_EQ(ftl::kNdmUnsafeEcc, driver.NandRead(0, 1, data.get(), oob.get()));
ASSERT_EQ(ftl::kNdmOk, driver.NandRead(0, 1, data.get(), oob.get()));
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(DriverTests)
RUN_TEST_SMALL(TrivialLifetimeTest)
RUN_TEST_SMALL(ReadWriteTest)
RUN_TEST_SMALL(IsEmptyTest)
RUN_TEST_SMALL(EraseTest)
RUN_TEST_SMALL(IsBadBlockTest)
RUN_TEST_SMALL(CreateVolumeTest)
RUN_TEST_SMALL(ReAttachTest)
RUN_TEST_SMALL(WriteBadBlockTest)
RUN_TEST_SMALL(ReadUnsafeEccTest)
END_TEST_CASE(DriverTests)