blob: de04dc4b039171d03425ff2a3e25e5921a2df2b7 [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 <inttypes.h>
#include <ddk/protocol/nand.h>
#include <ddktl/device.h>
#include <ddktl/protocol/badblock.h>
#include <ddktl/protocol/nand.h>
#include <ddktl/protocol/empty-protocol.h>
#include <fbl/array.h>
#include <fbl/auto_lock.h>
#include <fbl/macros.h>
#include <fbl/mutex.h>
#include <lib/operation/nand.h>
#include <fuchsia/hardware/skipblock/c/fidl.h>
#include <zircon/thread_annotations.h>
#include <zircon/types.h>
#include "logical-to-physical-map.h"
namespace nand {
using NandOperation = nand::Operation<>;
using PartitionInfo = fuchsia_hardware_skipblock_PartitionInfo;
using ReadWriteOperation = fuchsia_hardware_skipblock_ReadWriteOperation;
class SkipBlockDevice;
using DeviceType = ddk::Device<SkipBlockDevice, ddk::GetSizable, ddk::Unbindable,
ddk::Messageable>;
class SkipBlockDevice : public DeviceType,
public ddk::EmptyProtocol<ZX_PROTOCOL_SKIP_BLOCK> {
public:
// Spawns device node based on parent node.
static zx_status_t Create(zx_device_t* parent);
zx_status_t Bind();
// Device protocol implementation.
zx_off_t DdkGetSize();
zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
void DdkUnbind() { DdkRemove(); }
void DdkRelease() { delete this; }
// skip-block fidl implementation.
zx_status_t GetPartitionInfo(PartitionInfo* info);
zx_status_t Read(const ReadWriteOperation& info);
zx_status_t Write(const ReadWriteOperation& info, bool* bad_block_grown);
private:
explicit SkipBlockDevice(zx_device_t* parent, ddk::NandProtocolClient nand,
ddk::BadBlockProtocolClient bad_block, uint32_t copy_count)
: DeviceType(parent), nand_(nand), bad_block_(bad_block), copy_count_(copy_count) {
nand_.Query(&nand_info_, &parent_op_size_);
}
DISALLOW_COPY_ASSIGN_AND_MOVE(SkipBlockDevice);
uint64_t GetBlockSize() const { return nand_info_.pages_per_block * nand_info_.page_size; }
// Helper to get bad block list in a more idiomatic container.
zx_status_t GetBadBlockList(fbl::Array<uint32_t>* bad_block_list) TA_REQ(lock_);
// Helper to validate VMO received through IOCTL.
zx_status_t ValidateVmo(const ReadWriteOperation& op) const;
ddk::NandProtocolClient nand_ __TA_GUARDED(lock_);
ddk::BadBlockProtocolClient bad_block_ __TA_GUARDED(lock_);
LogicalToPhysicalMap block_map_ __TA_GUARDED(lock_);
fbl::Mutex lock_;
fuchsia_hardware_nand_Info nand_info_;
size_t parent_op_size_;
std::optional<NandOperation> nand_op_ __TA_GUARDED(lock_);
const uint32_t copy_count_;
};
} // namespace nand