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