131 lines
3.9 KiB
C++
131 lines
3.9 KiB
C++
#include <kernel/Device/DeviceNumbers.h>
|
|
#include <kernel/FS/DevFS/FileSystem.h>
|
|
#include <kernel/IO.h>
|
|
#include <kernel/Storage/ATA/ATABus.h>
|
|
#include <kernel/Storage/ATA/ATADefinitions.h>
|
|
#include <kernel/Storage/ATA/ATADevice.h>
|
|
|
|
#include <sys/sysmacros.h>
|
|
|
|
namespace Kernel
|
|
{
|
|
|
|
static dev_t get_ata_dev_minor()
|
|
{
|
|
static dev_t minor = 0;
|
|
return minor++;
|
|
}
|
|
|
|
detail::ATABaseDevice::ATABaseDevice()
|
|
: m_rdev(makedev(DeviceNumber::SCSI, get_ata_dev_minor()))
|
|
{
|
|
strcpy(m_name, "sda");
|
|
m_name[2] += minor(m_rdev);
|
|
}
|
|
|
|
BAN::ErrorOr<void> detail::ATABaseDevice::initialize(BAN::Span<const uint16_t> identify_data)
|
|
{
|
|
ASSERT(identify_data.size() >= 256);
|
|
|
|
m_signature = identify_data[ATA_IDENTIFY_SIGNATURE];
|
|
m_capabilities = identify_data[ATA_IDENTIFY_CAPABILITIES];
|
|
|
|
m_command_set = 0;
|
|
m_command_set |= (uint32_t)(identify_data[ATA_IDENTIFY_COMMAND_SET + 0] << 0);
|
|
m_command_set |= (uint32_t)(identify_data[ATA_IDENTIFY_COMMAND_SET + 1] << 16);
|
|
|
|
if (!(m_capabilities & ATA_CAPABILITIES_LBA))
|
|
return BAN::Error::from_error_code(ErrorCode::ATA_NoLBA);
|
|
|
|
if ((identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 &&
|
|
(identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 &&
|
|
(identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0)
|
|
{
|
|
m_sector_words = *(uint32_t*)(identify_data.data() + ATA_IDENTIFY_SECTOR_WORDS);
|
|
}
|
|
else
|
|
{
|
|
m_sector_words = 256;
|
|
}
|
|
|
|
m_lba_count = 0;
|
|
if (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED)
|
|
m_lba_count = *(uint64_t*)(identify_data.data() + ATA_IDENTIFY_LBA_COUNT_EXT);
|
|
if (m_lba_count < (1 << 28))
|
|
m_lba_count = *(uint32_t*)(identify_data.data() + ATA_IDENTIFY_LBA_COUNT);
|
|
|
|
for (int i = 0; i < 20; i++)
|
|
{
|
|
uint16_t word = identify_data[ATA_IDENTIFY_MODEL + i];
|
|
m_model[2 * i + 0] = word >> 8;
|
|
m_model[2 * i + 1] = word & 0xFF;
|
|
}
|
|
m_model[40] = 0;
|
|
|
|
size_t model_len = 40;
|
|
while (model_len > 0 && m_model[model_len - 1] == ' ')
|
|
model_len--;
|
|
|
|
dprintln("Initialized disk '{}' {} MiB", BAN::StringView(m_model, model_len), total_size() / 1024 / 1024);
|
|
|
|
add_disk_cache();
|
|
|
|
DevFileSystem::get().add_device(this);
|
|
if (auto res = initialize_partitions(name()); res.is_error())
|
|
dprintln("{}", res.error());
|
|
|
|
return {};
|
|
}
|
|
|
|
BAN::ErrorOr<size_t> detail::ATABaseDevice::read_impl(off_t offset, BAN::ByteSpan buffer)
|
|
{
|
|
if (offset % sector_size())
|
|
return BAN::Error::from_errno(EINVAL);
|
|
if (buffer.size() % sector_size())
|
|
return BAN::Error::from_errno(EINVAL);
|
|
TRY(read_sectors(offset / sector_size(), buffer.size() / sector_size(), buffer));
|
|
return buffer.size();
|
|
}
|
|
|
|
BAN::ErrorOr<size_t> detail::ATABaseDevice::write_impl(off_t offset, BAN::ConstByteSpan buffer)
|
|
{
|
|
if (offset % sector_size())
|
|
return BAN::Error::from_errno(EINVAL);
|
|
if (buffer.size() % sector_size())
|
|
return BAN::Error::from_errno(EINVAL);
|
|
TRY(write_sectors(offset / sector_size(), buffer.size() / sector_size(), buffer));
|
|
return buffer.size();
|
|
}
|
|
|
|
BAN::ErrorOr<BAN::RefPtr<ATADevice>> ATADevice::create(BAN::RefPtr<ATABus> bus, ATABus::DeviceType type, bool is_secondary, BAN::Span<const uint16_t> identify_data)
|
|
{
|
|
auto* device_ptr = new ATADevice(bus, type, is_secondary);
|
|
if (device_ptr == nullptr)
|
|
return BAN::Error::from_errno(ENOMEM);
|
|
auto device = BAN::RefPtr<ATADevice>::adopt(device_ptr);
|
|
TRY(device->initialize(identify_data));
|
|
return device;
|
|
}
|
|
|
|
ATADevice::ATADevice(BAN::RefPtr<ATABus> bus, ATABus::DeviceType type, bool is_secondary)
|
|
: m_bus(bus)
|
|
, m_type(type)
|
|
, m_is_secondary(is_secondary)
|
|
{ }
|
|
|
|
BAN::ErrorOr<void> ATADevice::read_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ByteSpan buffer)
|
|
{
|
|
ASSERT(buffer.size() >= sector_count * sector_size());
|
|
TRY(m_bus->read(*this, lba, sector_count, buffer));
|
|
return {};
|
|
}
|
|
|
|
BAN::ErrorOr<void> ATADevice::write_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ConstByteSpan buffer)
|
|
{
|
|
ASSERT(buffer.size() >= sector_count * sector_size());
|
|
TRY(m_bus->write(*this, lba, sector_count, buffer));
|
|
return {};
|
|
}
|
|
|
|
}
|