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 <ddk/device.h>
8#include <ddk/protocol/nand.h>
9#include <ddktl/device.h>
10#include <ddktl/protocol/bad-block.h>
11#include <ddktl/protocol/nand.h>
12
13#include <fbl/array.h>
14#include <fbl/macros.h>
15#include <fbl/ref_ptr.h>
16#include <zircon/types.h>
17
18#include "bad-block.h"
19
20namespace nand {
21
22class NandPartDevice;
23using DeviceType = ddk::Device<NandPartDevice, ddk::GetSizable, ddk::GetProtocolable,
24                               ddk::Unbindable>;
25
26class NandPartDevice : public DeviceType,
27                       public ddk::NandProtocol<NandPartDevice>,
28                       public ddk::BadBlockable<NandPartDevice> {
29public:
30    // Spawns device nodes based on parent node.
31    static zx_status_t Create(zx_device_t* parent);
32
33    zx_status_t Bind(const char* name, uint32_t copy_count);
34
35    // Device protocol implementation.
36    zx_off_t DdkGetSize() {
37        //TODO: use query() results, *but* fvm returns different query and getsize
38        // results, and the latter are dynamic...
39        return device_get_size(parent());
40    }
41    zx_status_t DdkGetProtocol(uint32_t proto_id, void* protocol);
42    void DdkUnbind() { DdkRemove(); }
43    void DdkRelease() { delete this; }
44
45    // nand protocol implementation.
46    void Query(nand_info_t* info_out, size_t* nand_op_size_out);
47    void Queue(nand_op_t* op);
48    zx_status_t GetFactoryBadBlockList(uint32_t* bad_blocks, uint32_t bad_block_len,
49                                       uint32_t* num_bad_blocks);
50
51    // Bad block protocol implementation.
52    zx_status_t GetBadBlockList(uint32_t* bad_block_list, uint32_t bad_block_list_len,
53                                uint32_t* bad_block_count);
54    zx_status_t MarkBlockBad(uint32_t block);
55
56private:
57    explicit NandPartDevice(zx_device_t* parent, const nand_protocol_t& nand_proto,
58                            fbl::RefPtr<BadBlock> bad_block, size_t parent_op_size,
59                            const nand_info_t& nand_info, uint32_t erase_block_start)
60        : DeviceType(parent), nand_proto_(nand_proto), nand_(&nand_proto_),
61          parent_op_size_(parent_op_size), nand_info_(nand_info),
62          erase_block_start_(erase_block_start), bad_block_(fbl::move(bad_block)) {}
63
64    DISALLOW_COPY_ASSIGN_AND_MOVE(NandPartDevice);
65
66    nand_protocol_t nand_proto_;
67    ddk::NandProtocolProxy nand_;
68
69    // op_size for parent device.
70    size_t parent_op_size_;
71    // info about nand.
72    nand_info_t nand_info_;
73    // First erase block for the partition.
74    uint32_t erase_block_start_;
75    // Device specific bad block info. Shared between all devices for a given
76    // parent device.
77    fbl::RefPtr<BadBlock> bad_block_;
78    // Cached list of bad blocks for this partition. Lazily instantiated.
79    fbl::Array<uint32_t> bad_block_list_;
80};
81
82} // namespace nand
83