3#include "pedigree/kernel/Log.h"
4#include "pedigree/kernel/TargetInfo.h"
5#include "pedigree/kernel/utilities/utility.h"
7#include "NvmeController.h"
10 : m_Controller(controller), m_Nsid(nsid), m_Blocks(0), m_Bytes(0), m_BlockBytes(0) {
11 m_pParent = controller;
12 setSpecificType(
String(
"nvme-disk"));
14NvmeDisk::~NvmeDisk() {
18bool NvmeDisk::initialise() {
19 uint8_t data[Nvme::PageSize]{};
20 if (!m_Controller || !m_Controller->identify(m_Nsid, 0, data))
22 uint64_t blocks = 0, capacity = 0;
23 for (
size_t i = 0; i < 8; ++i) {
24 blocks |= uint64_t{data[i]} << (8 * i);
25 capacity |= uint64_t{data[8 + i]} << (8 * i);
27 const uint8_t format = data[26] & 15U;
28 const size_t formatOffset = 128 + 4 * format;
29 const uint16_t metadata = data[formatOffset] | (uint16_t{data[formatOffset + 1]} << 8);
30 const uint8_t lbads = data[formatOffset + 2];
33 if ((data[26] & 0xe0U) || format > data[25] || metadata || (data[29] & 7U) || (data[30] & 1U) ||
34 (lbads != 9 && lbads != 12) || !blocks || !capacity || capacity > blocks) {
35 WARNING(
"NVMe: namespace " << m_Nsid <<
" unsupported format, protection, or sharing");
38 const size_t blockBytes =
size_t{1} << lbads;
43 m_BlockBytes = blockBytes;
44 m_Bytes = m_Blocks * m_BlockBytes;
45 NOTICE(
"NVMe: namespace " <<
Dec << m_Nsid <<
", " << m_Blocks <<
" blocks of " << m_BlockBytes
46 <<
" bytes, " << m_Bytes <<
" bytes" <<
Hex);
50 name.assign(m_Controller->model());
55size_t NvmeDisk::validPageLength(uint64_t location)
const {
56 if (!m_BlockBytes || location >= m_Bytes || location % m_BlockBytes)
58 const size_t remaining = m_Bytes - location;
61uint64_t NvmeDisk::doRead(uint64_t location) {
63 if (!m_BlockBytes || !bytes || bytes % m_BlockBytes)
65 const uintptr_t existing = getCache().
lookup(location);
71 const uintptr_t page = getCache().
insert(location, &existed);
77 if (!m_Controller->readWrite(m_Nsid, location / m_BlockBytes, bytes / m_BlockBytes,
78 reinterpret_cast<void*
>(page), bytes,
false)) {
79 if (!getCache().discardEditing(location))
80 FATAL(
"NVMe: failed to discard incomplete cache fill");
86uint64_t NvmeDisk::doWrite(uint64_t location) {
90 if (!validPageLength(location))
92 const uintptr_t page = getCache().
lookup(location);
103 const size_t bytes = validPageLength(location);
106 return m_Controller->readWrite(m_Nsid, location / m_BlockBytes, bytes / m_BlockBytes,
107 reinterpret_cast<void*
>(page), bytes,
true)
112uint64_t NvmeDisk::doSync(uint64_t location) {
116 const size_t bytes = location == SyncWholeDevice ? bool(m_BlockBytes) : validPageLength(location);
117 return bytes && m_Controller->flush(m_Nsid) ? bytes : 0;
void release(uintptr_t key)
uintptr_t insert(uintptr_t key, bool *alreadyExisted=nullptr)
void markNoLongerEditing(uintptr_t key, size_t length=0)
uintptr_t lookup(uintptr_t key)
void getName(String &name) override
size_t getBlockSize() const override
Gets the preferred I/O extent of the disk.
uint64_t doWriteDirect(uint64_t location, uintptr_t page) override
size_t getCacheFillLength(uint64_t location) const
static constexpr size_t getPageSize() noexcept