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