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 #include "logical-to-physical-map.h"
6
7 #include <fbl/algorithm.h>
8
9 #include <utility>
10
11 namespace nand {
12
LogicalToPhysicalMap(uint32_t copies,uint32_t block_count,fbl::Array<uint32_t> bad_blocks)13 LogicalToPhysicalMap::LogicalToPhysicalMap(uint32_t copies, uint32_t block_count,
14 fbl::Array<uint32_t> bad_blocks)
15 : copies_(copies), block_count_(block_count), bad_blocks_(std::move(bad_blocks)) {
16 ZX_ASSERT(block_count_ > 0);
17 ZX_ASSERT(block_count_ >= bad_blocks_.size());
18 ZX_ASSERT(block_count_ % copies_ == 0);
19
20 qsort(bad_blocks_.get(), bad_blocks_.size(), sizeof(uint32_t),
21 [](const void* l, const void* r) {
22 const auto* left = static_cast<const uint32_t*>(l);
23 const auto* right = static_cast<const uint32_t*>(r);
24 if (*left < *right) {
25 return -1;
26 } else if (*left > *right) {
27 return 1;
28 }
29 return 0;
30 });
31 }
32
GetPhysical(uint32_t copy,uint32_t block,uint32_t * physical_block) const33 zx_status_t LogicalToPhysicalMap::GetPhysical(uint32_t copy, uint32_t block,
34 uint32_t* physical_block) const {
35 ZX_ASSERT(copy < copies_);
36
37 const uint32_t blocks_per_copy = block_count_ / copies_;
38 const uint32_t first = copy * blocks_per_copy;
39 const uint32_t last = first + blocks_per_copy - 1;
40 block += first;
41 uint32_t skipped_blocks = 0;
42 for (const auto& bad_block : bad_blocks_) {
43 if (bad_block != fbl::clamp(bad_block, first, last)) {
44 continue;
45 }
46
47 if (block + skipped_blocks < bad_block) {
48 *physical_block = block + skipped_blocks;
49 return ZX_OK;
50 }
51 skipped_blocks++;
52 }
53 if (block + skipped_blocks <= last) {
54 *physical_block = block + skipped_blocks;
55 return ZX_OK;
56 }
57
58 return ZX_ERR_OUT_OF_RANGE;
59 }
60
LogicalBlockCount(uint32_t copy) const61 uint32_t LogicalToPhysicalMap::LogicalBlockCount(uint32_t copy) const {
62 ZX_ASSERT(copy < copies_);
63 const uint32_t blocks_per_copy = block_count_ / copies_;
64 const uint32_t first = copy * blocks_per_copy;
65 const uint32_t last = first + blocks_per_copy - 1;
66
67 uint32_t bad_block_count = 0;
68 for (const auto& bad_block : bad_blocks_) {
69 if (bad_block == fbl::clamp(bad_block, first, last)) {
70 bad_block_count++;
71 }
72 }
73 return blocks_per_copy - bad_block_count;
74 }
75
76 } // namespace nand
77