1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#pragma once 6 7#include <inttypes.h> 8 9#include <ddk/protocol/nand.h> 10#include <ddktl/device.h> 11#include <ddktl/protocol/bad-block.h> 12#include <ddktl/protocol/nand.h> 13#include <ddktl/protocol/skip-block.h> 14 15#include <fbl/array.h> 16#include <fbl/auto_lock.h> 17#include <fbl/macros.h> 18#include <fbl/mutex.h> 19#include <zircon/device/skip-block.h> 20#include <zircon/thread_annotations.h> 21#include <zircon/types.h> 22 23#include "logical-to-physical-map.h" 24 25namespace nand { 26 27class SkipBlockDevice; 28using DeviceType = ddk::Device<SkipBlockDevice, ddk::GetSizable, ddk::Ioctlable, ddk::Unbindable>; 29 30class SkipBlockDevice : public DeviceType, 31 public ddk::SkipBlockProtocol { 32public: 33 // Spawns device node based on parent node. 34 static zx_status_t Create(zx_device_t* parent); 35 36 zx_status_t Bind(); 37 38 // Device protocol implementation. 39 zx_off_t DdkGetSize(); 40 zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, 41 void* out_buf, size_t out_len, size_t* out_actual); 42 void DdkUnbind() { DdkRemove(); } 43 void DdkRelease() { delete this; } 44 45private: 46 explicit SkipBlockDevice(zx_device_t* parent, nand_protocol_t nand_proto, 47 bad_block_protocol_t bad_block_proto, uint32_t copy_count) 48 : DeviceType(parent), nand_proto_(nand_proto), bad_block_proto_(bad_block_proto), 49 nand_(&nand_proto_), bad_block_(&bad_block_proto_), copy_count_(copy_count) { 50 nand_.Query(&nand_info_, &parent_op_size_); 51 } 52 53 DISALLOW_COPY_ASSIGN_AND_MOVE(SkipBlockDevice); 54 55 uint64_t GetBlockSize() const { return nand_info_.pages_per_block * nand_info_.page_size; } 56 57 // Helper to get bad block list in a more idiomatic container. 58 zx_status_t GetBadBlockList(fbl::Array<uint32_t>* bad_block_list) TA_REQ(lock_); 59 // Helper to validate VMO received through IOCTL. 60 zx_status_t ValidateVmo(const skip_block_rw_operation_t& op) const; 61 62 // skip-block IOCTL implementation. 63 zx_status_t GetPartitionInfo(skip_block_partition_info_t* info) const TA_REQ(lock_); 64 zx_status_t Read(const skip_block_rw_operation_t& info) TA_REQ(lock_); 65 zx_status_t Write(const skip_block_rw_operation_t& info, bool* bad_block_grown) TA_REQ(lock_); 66 67 nand_protocol_t nand_proto_; 68 bad_block_protocol_t bad_block_proto_; 69 ddk::NandProtocolProxy nand_ __TA_GUARDED(lock_); 70 ddk::BadBlockProtocolProxy bad_block_ __TA_GUARDED(lock_); 71 LogicalToPhysicalMap block_map_ __TA_GUARDED(lock_); 72 fbl::Mutex lock_; 73 nand_info_t nand_info_; 74 size_t parent_op_size_; 75 // Operation buffer of size parent_op_size_. 76 fbl::Array<uint8_t> nand_op_ __TA_GUARDED(lock_); 77 78 const uint32_t copy_count_; 79}; 80 81} // namespace nand 82