18#include "pedigree/kernel/Log.h"
19#include "pedigree/kernel/TargetInfo.h"
20#include "pedigree/kernel/utilities/utility.h"
22#include "AhciController.h"
26 m_Controller(controller),
31 m_ExtendedFlush(false),
34 m_pParent = controller;
35 setSpecificType(
String(
"ahci-disk"));
38AhciDisk::~AhciDisk() {
44bool AhciDisk::initialise() {
47 uint16_t words[256] = {};
48 if (!m_Controller || !m_Controller->identify(m_Port, words))
51 const auto* raw =
reinterpret_cast<const uint8_t*
>(words);
52 if (raw[510] == 0xa5) {
54 for (
size_t i = 0; i <
sizeof(words); ++i)
57 WARNING(
"AHCI: IDENTIFY checksum failed on port " << m_Port);
61 for (
size_t i = 0; i < 256; ++i)
62 words[i] = LITTLE_TO_HOST16(words[i]);
64 if ((words[0] & 0x8000) || (words[49] & 0x0300) != 0x0300 || (words[83] & 0xc000) != 0x4000 ||
65 !(words[83] & (1U << 10))) {
66 WARNING(
"AHCI: port " << m_Port <<
" requires an ATA disk with DMA and LBA48");
70 uint64_t sectorBytes = 512;
71 if ((words[106] & 0xc000) == 0x4000 && (words[106] & (1U << 12))) {
72 const uint32_t sectorWords =
73 static_cast<uint32_t
>(words[117]) | (
static_cast<uint32_t
>(words[118]) << 16);
74 if (sectorWords <= 256) {
75 WARNING(
"AHCI: invalid logical sector size on port " << m_Port);
78 sectorBytes =
static_cast<uint64_t
>(sectorWords) * 2;
80 if (sectorBytes < 512 || (sectorBytes & (sectorBytes - 1))) {
81 WARNING(
"AHCI: port " << m_Port <<
" has unsupported logical sector size " << sectorBytes);
85 if (!pageBytes || pageBytes > 65536 || (pageBytes % sectorBytes))
88 const uint64_t sectors =
89 static_cast<uint64_t
>(words[100]) | (
static_cast<uint64_t
>(words[101]) << 16) |
90 (
static_cast<uint64_t
>(words[102]) << 32) | (
static_cast<uint64_t
>(words[103]) << 48);
91 if (!sectors || sectors > (uint64_t{1} << 48) || sectors > (~
size_t{0} / sectorBytes)) {
92 WARNING(
"AHCI: invalid or unaddressable LBA48 capacity on port " << m_Port);
95 const bool supportsFlush = words[83] & (1U << 12);
96 m_ExtendedFlush = words[83] & (1U << 13);
97 if (!supportsFlush && !m_ExtendedFlush) {
98 WARNING(
"AHCI: port " << m_Port <<
" lacks a supported cache flush command");
102 for (
size_t i = 0; i < 40; ++i) {
103 const uint8_t ch = words[27 + i / 2] >> ((i & 1) ? 0 : 8);
104 m_Model[i] = ch >= 32 && ch <= 126 ? static_cast<char>(ch) :
' ';
107 while (length && m_Model[length - 1] ==
' ')
111 const bool cacheSupported = words[82] & (1U << 5);
112 const bool enabledValid = (words[87] & 0xc000) == 0x4000;
113 const bool cacheEnabled = words[85] & (1U << 5);
114 const char* cacheState = !cacheSupported ?
"unsupported"
115 : !enabledValid ?
"unknown"
116 : cacheEnabled ?
"enabled"
119 m_SectorBytes =
static_cast<size_t>(sectorBytes);
120 m_Controller->configureDisk(
121 m_Port, m_SectorBytes,
122 words[76] != 0xffff && (words[76] & (1U << 8)) ? (words[75] & 31U) + 1 : 0);
123 m_Sectors =
static_cast<size_t>(sectors);
124 m_Bytes = m_Sectors * sectorBytes;
125 m_Initialised =
true;
126 NOTICE(
"AHCI: disk port " << m_Port <<
" model '" << m_Model <<
"', " <<
Dec << m_Sectors
127 <<
" sectors of " << m_SectorBytes <<
" bytes, " << m_Bytes
128 <<
" bytes; write cache " << cacheState <<
", flush "
129 << (m_ExtendedFlush ?
"EXT" :
"legacy") <<
Hex);
134 name.assign(m_Model[0] ? m_Model :
"AHCI Disk");
141size_t AhciDisk::getBlockCount()
const {
150 return m_SectorBytes;
153size_t AhciDisk::validPageLength(uint64_t location)
const {
154 if (!m_Initialised || location >= m_Bytes || (location % m_SectorBytes))
156 const uint64_t remaining = m_Bytes - location;
158 return remaining < pageBytes ? static_cast<size_t>(remaining) : pageBytes;
161bool AhciDisk::transferReadBuffers(
Disk::ReadBuffer* buffers,
size_t count) {
162 if (count > Disk::MaxReadBuffers || (count && !buffers))
164 for (
size_t i = 0; i < count; ++i)
165 buffers[i].complete =
false;
170 for (
size_t i = 0; i < count; ++i) {
172 buffers[i].location >= m_Bytes || buffers[i].length > m_Bytes - buffers[i].location ||
173 buffers[i].location % m_SectorBytes || buffers[i].length % m_SectorBytes)
176 return m_Controller->readBatch(m_Port, buffers, count);
183 return m_Initialised && m_Controller->writeBatch(m_Port, buffers, count);
187uint64_t AhciDisk::doRead(uint64_t location) {
189 if (!m_Initialised || !bytes)
192 const uintptr_t existing = getCache().
lookup(location);
197 bool existed =
false;
198 const uintptr_t page = getCache().
insert(location, &existed);
206 if (!m_Controller->readWrite(m_Port, location / m_SectorBytes,
207 static_cast<uint16_t
>(bytes / m_SectorBytes),
208 reinterpret_cast<void*
>(page), bytes,
false)) {
209 if (!getCache().discardEditing(location))
210 FATAL(
"AHCI: failed to discard an incomplete cache fill");
217uint64_t AhciDisk::doWrite(uint64_t location) {
221 if (!validPageLength(location))
223 const uintptr_t page = getCache().
lookup(location);
232bool AhciDisk::transferBuffer(uint64_t location,
void* buffer,
size_t length,
bool writing) {
237 if (!m_Initialised || !buffer || !length || location >= m_Bytes || length > m_Bytes - location ||
239 length / m_SectorBytes > 0xffff)
241 return m_Controller->readWrite(m_Port, location / m_SectorBytes,
242 static_cast<uint16_t
>(length / m_SectorBytes), buffer, length,
250 const size_t bytes = validPageLength(location);
253 return m_Controller->readWrite(m_Port, location / m_SectorBytes,
254 static_cast<uint16_t
>(bytes / m_SectorBytes),
255 reinterpret_cast<void*
>(page), bytes,
true)
261uint64_t AhciDisk::doSync(uint64_t location) {
266 location == SyncWholeDevice ? (m_Initialised ? 1 : 0) : validPageLength(location);
269 return m_Controller->flush(m_Port, m_ExtendedFlush) ? bytes : 0;
size_t getNativeBlockSize() const override
size_t getBlockSize() const override
Gets the preferred I/O extent of the disk.
size_t getSize() const override
Gets the size of the disk.
uint64_t doWriteDirect(uint64_t location, uintptr_t page) override
void getName(String &name) override
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)
size_t getCacheFillLength(uint64_t location) const
static constexpr size_t getPageSize() noexcept