blob: 48ac2019766986113998b234cba44242ccd88229 [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.
#pragma once
#include <threads.h>
#include <memory>
#include <ddk/protocol/badblock.h>
#include <ddk/protocol/block.h>
#include <ddk/protocol/nand.h>
#include <ddktl/device.h>
#include <ddktl/protocol/badblock.h>
#include <ddktl/protocol/block.h>
#include <ddktl/protocol/block/partition.h>
#include <fbl/macros.h>
#include <fbl/mutex.h>
#include <lib/ftl/volume.h>
#include <lib/sync/completion.h>
#include <zircon/boot/image.h>
#include <zircon/listnode.h>
#include <zircon/thread_annotations.h>
#include <zircon/types.h>
namespace ftl {
struct BlockParams {
uint64_t GetSize() const {
return static_cast<uint64_t>(page_size) * num_pages;
}
uint32_t page_size;
uint32_t num_pages;
};
// Ftl version of block_op_t.
// TODO(rvargas): Explore using c++ lists.
struct FtlOp {
block_op_t op;
list_node_t node;
block_impl_queue_callback completion_cb;
void* cookie;
};
class BlockDevice;
using DeviceType = ddk::Device<BlockDevice, ddk::GetSizable, ddk::Unbindable, ddk::Messageable,
ddk::Suspendable, ddk::Resumable, ddk::GetProtocolable>;
// Provides the bulk of the functionality for a FTL-backed block device.
class BlockDevice : public DeviceType,
public ddk::BlockImplProtocol<BlockDevice, ddk::base_protocol>,
public ddk::BlockPartitionProtocol<BlockDevice>, public ftl::FtlInstance {
public:
explicit BlockDevice(zx_device_t* parent = nullptr) : DeviceType(parent) {}
~BlockDevice();
zx_status_t Bind();
void DdkRelease() { delete this; }
void DdkUnbind();
// Performs the object initialization.
zx_status_t Init();
// Device protocol implementation.
zx_off_t DdkGetSize() { return params_.GetSize(); }
zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
zx_status_t DdkSuspend(uint32_t flags);
zx_status_t DdkResume(uint32_t flags) { return ZX_OK; }
zx_status_t DdkGetProtocol(uint32_t proto_id, void* out_protocol);
// Block protocol implementation.
void BlockImplQuery(block_info_t* info_out, size_t* block_op_size_out);
void BlockImplQueue(block_op_t* operation, block_impl_queue_callback completion_cb,
void* cookie);
// Partition protocol implementation.
zx_status_t BlockPartitionGetGuid(guidtype_t guid_type, guid_t* out_guid);
zx_status_t BlockPartitionGetName(char* out_name, size_t capacity);
// FtlInstance interface.
bool OnVolumeAdded(uint32_t page_size, uint32_t num_pages) final;
// Issues a command to format the FTL (aka, delete all data).
zx_status_t Format();
void SetVolumeForTest(std::unique_ptr<ftl::Volume> volume) {
volume_ = std::move(volume);
}
void SetNandParentForTest(const nand_protocol_t& nand) {
parent_ = nand;
}
DISALLOW_COPY_ASSIGN_AND_MOVE(BlockDevice);
private:
bool InitFtl();
void Kill();
bool AddToList(FtlOp* operation);
bool RemoveFromList(FtlOp** operation);
int WorkerThread();
static int WorkerThreadStub(void* arg);
// Implementation of the actual commands.
zx_status_t ReadWriteData(block_op_t* operation);
zx_status_t Flush();
BlockParams params_ = {};
fbl::Mutex lock_;
list_node_t txn_list_ TA_GUARDED(lock_) = {};
bool dead_ TA_GUARDED(lock_) = false;
bool thread_created_ = false;
bool pending_flush_ = false;
sync_completion_t wake_signal_;
thrd_t worker_;
nand_protocol_t parent_ = {};
bad_block_protocol_t bad_block_ = {};
std::unique_ptr<ftl::Volume> volume_;
uint8_t guid_[ZBI_PARTITION_GUID_LEN] = {};
};
} // namespace ftl.