forked from Bananymous/banan-os
Kernel: Cleanup ATA device initialization
This commit is contained in:
parent
26d9a3e253
commit
3a4557d417
|
@ -8,43 +8,62 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
struct ATABus;
|
||||
class ATAController;
|
||||
|
||||
class ATADevice final : public StorageDevice
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<ATADevice*> create(ATAController*, uint16_t, uint16_t, uint8_t);
|
||||
|
||||
virtual BAN::ErrorOr<void> read_sectors(uint64_t, uint8_t, uint8_t*) override;
|
||||
virtual BAN::ErrorOr<void> write_sectors(uint64_t, uint8_t, const uint8_t*) override;
|
||||
virtual uint32_t sector_size() const override { return sector_words * 2; }
|
||||
virtual uint64_t total_size() const override { return lba_count * sector_size(); }
|
||||
virtual uint32_t sector_size() const override { return m_sector_words * 2; }
|
||||
virtual uint64_t total_size() const override { return m_lba_count * sector_size(); }
|
||||
|
||||
BAN::StringView model() const { return m_model; }
|
||||
|
||||
private:
|
||||
ATADevice(ATAController* controller, uint16_t base, uint16_t ctrl, uint8_t index)
|
||||
: m_controller(controller)
|
||||
, m_base(base)
|
||||
, m_ctrl(ctrl)
|
||||
, m_index(index)
|
||||
, m_slave_bit((index & 0x01) << 4)
|
||||
{ }
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
uint8_t io_read(uint16_t);
|
||||
void io_write(uint16_t, uint8_t);
|
||||
void read_buffer(uint16_t, uint16_t*, size_t);
|
||||
void write_buffer(uint16_t, const uint16_t*, size_t);
|
||||
BAN::ErrorOr<void> wait(bool);
|
||||
BAN::Error error();
|
||||
|
||||
private:
|
||||
enum class DeviceType
|
||||
{
|
||||
Unknown,
|
||||
ATA,
|
||||
ATAPI,
|
||||
};
|
||||
|
||||
DeviceType type;
|
||||
uint8_t slave_bit; // 0x00 for master, 0x10 for slave
|
||||
uint16_t signature;
|
||||
uint16_t capabilities;
|
||||
uint32_t command_set;
|
||||
uint32_t sector_words;
|
||||
uint64_t lba_count;
|
||||
char model[41];
|
||||
ATAController* m_controller;
|
||||
const uint16_t m_base;
|
||||
const uint16_t m_ctrl;
|
||||
const uint8_t m_index;
|
||||
const uint8_t m_slave_bit;
|
||||
|
||||
ATABus* bus;
|
||||
ATAController* controller;
|
||||
DeviceType m_type;
|
||||
uint16_t m_signature;
|
||||
uint16_t m_capabilities;
|
||||
uint32_t m_command_set;
|
||||
uint32_t m_sector_words;
|
||||
uint64_t m_lba_count;
|
||||
char m_model[41];
|
||||
|
||||
friend class ATAController;
|
||||
|
||||
char device_name[4] {};
|
||||
|
||||
public:
|
||||
virtual ino_t ino() const override { return !!slave_bit; }
|
||||
virtual ino_t ino() const override { return m_index; }
|
||||
virtual Mode mode() const override { return { Mode::IFBLK }; }
|
||||
virtual nlink_t nlink() const override { return 1; }
|
||||
virtual uid_t uid() const override { return 0; }
|
||||
|
@ -55,23 +74,12 @@ namespace Kernel
|
|||
virtual dev_t dev() const override;
|
||||
virtual dev_t rdev() const override { return 0x5429; }
|
||||
|
||||
virtual BAN::StringView name() const override { return BAN::StringView(device_name, sizeof(device_name) - 1); }
|
||||
virtual BAN::StringView name() const override { return BAN::StringView(m_device_name, sizeof(m_device_name) - 1); }
|
||||
|
||||
virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override;
|
||||
};
|
||||
|
||||
struct ATABus
|
||||
{
|
||||
uint16_t base;
|
||||
uint16_t ctrl;
|
||||
ATADevice devices[2];
|
||||
|
||||
uint8_t read(uint16_t);
|
||||
void read_buffer(uint16_t, uint16_t*, size_t);
|
||||
void write(uint16_t, uint8_t);
|
||||
void write_buffer(uint16_t, const uint16_t*, size_t);
|
||||
BAN::ErrorOr<void> wait(bool);
|
||||
BAN::Error error();
|
||||
public:
|
||||
char m_device_name[4] {};
|
||||
};
|
||||
|
||||
class ATAController final : public StorageController
|
||||
|
@ -80,15 +88,13 @@ namespace Kernel
|
|||
static BAN::ErrorOr<ATAController*> create(const PCIDevice&);
|
||||
|
||||
private:
|
||||
ATAController(const PCIDevice& device) : m_pci_device(device) {}
|
||||
BAN::ErrorOr<void> initialize();
|
||||
ATAController() = default;
|
||||
BAN::ErrorOr<void> initialize(const PCIDevice& device);
|
||||
|
||||
BAN::ErrorOr<void> read(ATADevice*, uint64_t, uint8_t, uint8_t*);
|
||||
BAN::ErrorOr<void> write(ATADevice*, uint64_t, uint8_t, const uint8_t*);
|
||||
|
||||
private:
|
||||
ATABus m_buses[2];
|
||||
const PCIDevice& m_pci_device;
|
||||
SpinLock m_lock;
|
||||
|
||||
friend class ATADevice;
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#include <BAN/ScopeGuard.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <kernel/Storage/ATAController.h>
|
||||
|
||||
#define ATA_PRIMARY 0
|
||||
#define ATA_SECONDARY 1
|
||||
|
||||
#define ATA_PORT_DATA 0x00
|
||||
#define ATA_PORT_ERROR 0x00
|
||||
#define ATA_PORT_SECTOR_COUNT 0x02
|
||||
|
@ -18,6 +16,8 @@
|
|||
#define ATA_PORT_CONTROL 0x10
|
||||
#define ATA_PORT_ALT_STATUS 0x10
|
||||
|
||||
#define ATA_CONTROL_nIEN 0x02
|
||||
|
||||
#define ATA_ERROR_AMNF 0x01
|
||||
#define ATA_ERROR_TKZNF 0x02
|
||||
#define ATA_ERROR_ABRT 0x04
|
||||
|
@ -34,9 +34,9 @@
|
|||
|
||||
#define ATA_COMMAND_READ_SECTORS 0x20
|
||||
#define ATA_COMMAND_WRITE_SECTORS 0x30
|
||||
#define ATA_COMMAND_IDENTIFY_PACKET 0xA1
|
||||
#define ATA_COMMAND_CACHE_FLUSH 0xE7
|
||||
#define ATA_COMMAND_IDENTIFY 0xEC
|
||||
#define ATA_COMMAND_IDENTIFY_PACKET 0xA1
|
||||
|
||||
#define ATA_IDENTIFY_SIGNATURE 0
|
||||
#define ATA_IDENTIFY_MODEL 27
|
||||
|
@ -52,148 +52,155 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<ATADevice*> ATADevice::create(ATAController* controller, uint16_t base, uint16_t ctrl, uint8_t index)
|
||||
{
|
||||
ATADevice* device = new ATADevice(controller, base, ctrl, index);
|
||||
if (device == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
BAN::ScopeGuard guard([device] { device->unref(); });
|
||||
TRY(device->initialize());
|
||||
guard.disable();
|
||||
return device;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<ATAController*> ATAController::create(const PCIDevice& device)
|
||||
{
|
||||
ATAController* controller = new ATAController(device);
|
||||
ATAController* controller = new ATAController();
|
||||
if (controller == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
TRY(controller->initialize());
|
||||
BAN::ScopeGuard guard([controller] { controller->unref(); });
|
||||
TRY(controller->initialize(device));
|
||||
guard.disable();
|
||||
return controller;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ATAController::initialize()
|
||||
BAN::ErrorOr<void> ATADevice::initialize()
|
||||
{
|
||||
m_buses[ATA_PRIMARY].base = 0x1F0;
|
||||
m_buses[ATA_PRIMARY].ctrl = 0x3F6;
|
||||
m_buses[ATA_PRIMARY].write(ATA_PORT_CONTROL, 2);
|
||||
io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN);
|
||||
|
||||
m_buses[ATA_SECONDARY].base = 0x170;
|
||||
m_buses[ATA_SECONDARY].ctrl = 0x376;
|
||||
m_buses[ATA_SECONDARY].write(ATA_PORT_CONTROL, 2);
|
||||
io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | m_slave_bit);
|
||||
PIT::sleep(1);
|
||||
|
||||
uint8_t prog_if = m_pci_device.read_byte(0x09);
|
||||
io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY);
|
||||
PIT::sleep(1);
|
||||
|
||||
if (io_read(ATA_PORT_STATUS) == 0)
|
||||
return BAN::Error::from_c_string("");
|
||||
|
||||
uint8_t status = 0;
|
||||
while (true)
|
||||
{
|
||||
status = io_read(ATA_PORT_STATUS);
|
||||
if (status & ATA_STATUS_ERR)
|
||||
break;
|
||||
if (!(status & ATA_STATUS_BSY) && (status && ATA_STATUS_DRQ))
|
||||
break;
|
||||
}
|
||||
|
||||
if (status & ATA_STATUS_ERR)
|
||||
{
|
||||
uint8_t lba1 = io_read(ATA_PORT_LBA1);
|
||||
uint8_t lba2 = io_read(ATA_PORT_LBA2);
|
||||
|
||||
if (lba1 == 0x14 && lba2 == 0xEB)
|
||||
m_type = ATADevice::DeviceType::ATAPI;
|
||||
else if (lba1 == 0x69 && lba2 == 0x96)
|
||||
m_type = ATADevice::DeviceType::ATAPI;
|
||||
else
|
||||
return BAN::Error::from_c_string("Not ATA/ATAPI device");
|
||||
|
||||
io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET);
|
||||
PIT::sleep(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = ATADevice::DeviceType::ATA;
|
||||
}
|
||||
|
||||
uint16_t buffer[256] {};
|
||||
read_buffer(ATA_PORT_DATA, buffer, 256);
|
||||
|
||||
m_signature = *(uint16_t*)(buffer + ATA_IDENTIFY_SIGNATURE);
|
||||
m_capabilities = *(uint16_t*)(buffer + ATA_IDENTIFY_CAPABILITIES);
|
||||
m_command_set = *(uint32_t*)(buffer + ATA_IDENTIFY_COMMAND_SET);
|
||||
|
||||
if ((buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 &&
|
||||
(buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 &&
|
||||
(buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0)
|
||||
{
|
||||
m_sector_words = *(uint32_t*)(buffer + 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*)(buffer + ATA_IDENTIFY_LBA_COUNT_EXT);
|
||||
if (m_lba_count < (1 << 28))
|
||||
m_lba_count = *(uint32_t*)(buffer + ATA_IDENTIFY_LBA_COUNT);
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
uint16_t word = buffer[ATA_IDENTIFY_MODEL + i];
|
||||
m_model[2 * i + 0] = word >> 8;
|
||||
m_model[2 * i + 1] = word & 0xFF;
|
||||
}
|
||||
m_model[40] = 0;
|
||||
|
||||
m_device_name[0] = 'h';
|
||||
m_device_name[1] = 'd';
|
||||
m_device_name[2] = 'a' + m_index;
|
||||
m_device_name[3] = '\0';
|
||||
|
||||
TRY(initialize_partitions());
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ATAController::initialize(const PCIDevice& pci_device)
|
||||
{
|
||||
struct Bus
|
||||
{
|
||||
uint16_t base;
|
||||
uint16_t ctrl;
|
||||
};
|
||||
|
||||
Bus buses[2];
|
||||
buses[0].base = 0x1F0;
|
||||
buses[0].ctrl = 0x3F6;
|
||||
|
||||
buses[1].base = 0x170;
|
||||
buses[1].ctrl = 0x376;
|
||||
|
||||
uint8_t prog_if = pci_device.read_byte(0x09);
|
||||
if (prog_if & 0x01)
|
||||
{
|
||||
m_buses[ATA_PRIMARY].base = m_pci_device.read_dword(0x10) & 0xFFFFFFFC;
|
||||
m_buses[ATA_PRIMARY].ctrl = m_pci_device.read_dword(0x14) & 0xFFFFFFFC;
|
||||
buses[0].base = pci_device.read_dword(0x10) & 0xFFFFFFFC;
|
||||
buses[0].ctrl = pci_device.read_dword(0x14) & 0xFFFFFFFC;
|
||||
}
|
||||
if (prog_if & 0x04)
|
||||
{
|
||||
m_buses[ATA_SECONDARY].base = m_pci_device.read_dword(0x18) & 0xFFFFFFFC;
|
||||
m_buses[ATA_SECONDARY].ctrl = m_pci_device.read_dword(0x1C) & 0xFFFFFFFC;
|
||||
buses[1].base = pci_device.read_dword(0x18) & 0xFFFFFFFC;
|
||||
buses[1].ctrl = pci_device.read_dword(0x1C) & 0xFFFFFFFC;
|
||||
}
|
||||
|
||||
for (uint8_t bus_index = 0; bus_index < 2; bus_index++)
|
||||
for (uint8_t drive = 0; drive < 4; drive++)
|
||||
{
|
||||
for (uint8_t device_index = 0; device_index < 2; device_index++)
|
||||
auto device = ATADevice::create(this, buses[drive / 2].base, buses[drive / 2].ctrl, drive);
|
||||
if (device.is_error())
|
||||
{
|
||||
ATABus& bus = m_buses[bus_index];
|
||||
ATADevice& device = bus.devices[device_index];
|
||||
|
||||
device.type = ATADevice::DeviceType::Unknown;
|
||||
device.slave_bit = device_index << 4;
|
||||
device.bus = &bus;
|
||||
device.controller = this;
|
||||
|
||||
device.device_name[0] = 'h';
|
||||
device.device_name[1] = 'd';
|
||||
device.device_name[2] = 'a' + bus_index * 2 + device_index;
|
||||
device.device_name[3] = '\0';
|
||||
|
||||
bus.write(ATA_PORT_DRIVE_SELECT, 0xA0 | device.slave_bit);
|
||||
PIT::sleep(1);
|
||||
|
||||
bus.write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY);
|
||||
PIT::sleep(1);
|
||||
|
||||
if (bus.read(ATA_PORT_STATUS) == 0)
|
||||
continue;
|
||||
|
||||
uint8_t status = 0;
|
||||
while (true)
|
||||
{
|
||||
status = bus.read(ATA_PORT_STATUS);
|
||||
if (status & ATA_STATUS_ERR)
|
||||
break;
|
||||
if (!(status & ATA_STATUS_BSY) && (status && ATA_STATUS_DRQ))
|
||||
break;
|
||||
}
|
||||
|
||||
auto type = ATADevice::DeviceType::ATA;
|
||||
|
||||
// Not a ATA device, maybe ATAPI
|
||||
if (status & ATA_STATUS_ERR)
|
||||
{
|
||||
uint8_t lba1 = bus.read(ATA_PORT_LBA1);
|
||||
uint8_t lba2 = bus.read(ATA_PORT_LBA2);
|
||||
|
||||
if (lba1 == 0x14 && lba2 == 0xEB)
|
||||
type = ATADevice::DeviceType::ATAPI;
|
||||
else if (lba1 == 0x69 && lba2 == 0x96)
|
||||
type = ATADevice::DeviceType::ATAPI;
|
||||
else
|
||||
continue;
|
||||
|
||||
bus.write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET);
|
||||
PIT::sleep(1);
|
||||
}
|
||||
|
||||
uint16_t buffer[256] {};
|
||||
bus.read_buffer(ATA_PORT_DATA, buffer, 256);
|
||||
|
||||
device.type = type;
|
||||
device.signature = *(uint16_t*)(buffer + ATA_IDENTIFY_SIGNATURE);
|
||||
device.capabilities = *(uint16_t*)(buffer + ATA_IDENTIFY_CAPABILITIES);
|
||||
device.command_set = *(uint32_t*)(buffer + ATA_IDENTIFY_COMMAND_SET);
|
||||
|
||||
device.sector_words = 256;
|
||||
if ((buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 &&
|
||||
(buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 &&
|
||||
(buffer[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0)
|
||||
{
|
||||
device.sector_words = *(uint32_t*)(buffer + ATA_IDENTIFY_SECTOR_WORDS);
|
||||
}
|
||||
|
||||
device.lba_count = 0;
|
||||
if (device.command_set & ATA_COMMANDSET_LBA48_SUPPORTED)
|
||||
device.lba_count = *(uint64_t*)(buffer + ATA_IDENTIFY_LBA_COUNT_EXT);
|
||||
if (device.lba_count < (1 << 28))
|
||||
device.lba_count = *(uint32_t*)(buffer + ATA_IDENTIFY_LBA_COUNT);
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
uint16_t word = buffer[ATA_IDENTIFY_MODEL + i];
|
||||
device.model[2 * i + 0] = word >> 8;
|
||||
device.model[2 * i + 1] = word & 0xFF;
|
||||
}
|
||||
device.model[40] = 0;
|
||||
|
||||
if (auto res = device.initialize_partitions(); res.is_error())
|
||||
{
|
||||
dprintln("could not initialize partitions on device {}", device.device_name);
|
||||
device.type = ATADevice::DeviceType::Unknown;
|
||||
}
|
||||
else
|
||||
{
|
||||
add_device(&device);
|
||||
}
|
||||
if (strlen(device.error().get_message()) > 0)
|
||||
dprintln("{}", device.error());
|
||||
continue;
|
||||
}
|
||||
add_device(device.value());
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 2; i++)
|
||||
for (StorageDevice* device_ : devices())
|
||||
{
|
||||
for (uint32_t j = 0; j < 2; j++)
|
||||
{
|
||||
ATADevice& device = m_buses[i].devices[j];
|
||||
if (device.type == ATADevice::DeviceType::Unknown)
|
||||
continue;
|
||||
constexpr uint32_t words_per_mib = 1024 * 1024 / 2;
|
||||
const char* device_type =
|
||||
device.type == ATADevice::DeviceType::ATA ? "ATA" :
|
||||
device.type == ATADevice::DeviceType::ATAPI ? "ATAPI" :
|
||||
"Unknown";
|
||||
dprintln("Found {} Drive ({} MiB) model {}", device_type, device.lba_count * device.sector_words / words_per_mib, device.model);
|
||||
}
|
||||
ATADevice& device = *(ATADevice*)device_;
|
||||
dprintln("Initialized drive {} ({} MiB) model {}", device.name(), device.total_size() / (1024 * 1024), device.model());
|
||||
}
|
||||
|
||||
return {};
|
||||
|
@ -201,7 +208,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> ATAController::read(ATADevice* device, uint64_t lba, uint8_t sector_count, uint8_t* buffer)
|
||||
{
|
||||
if (lba + sector_count > device->lba_count)
|
||||
if (lba + sector_count > device->m_lba_count)
|
||||
return BAN::Error::from_c_string("Attempted to read outside of the device boundaries");
|
||||
|
||||
LockGuard _(m_lock);
|
||||
|
@ -209,17 +216,17 @@ namespace Kernel
|
|||
if (lba < (1 << 28))
|
||||
{
|
||||
// LBA28
|
||||
device->bus->write(ATA_PORT_DRIVE_SELECT, 0xE0 | device->slave_bit | ((lba >> 24) & 0x0F));
|
||||
device->bus->write(ATA_PORT_SECTOR_COUNT, sector_count);
|
||||
device->bus->write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
|
||||
device->bus->write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
|
||||
device->bus->write(ATA_PORT_LBA2, (uint8_t)(lba >> 16));
|
||||
device->bus->write(ATA_PORT_COMMAND, ATA_COMMAND_READ_SECTORS);
|
||||
device->io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | device->m_slave_bit | ((lba >> 24) & 0x0F));
|
||||
device->io_write(ATA_PORT_SECTOR_COUNT, sector_count);
|
||||
device->io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
|
||||
device->io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
|
||||
device->io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16));
|
||||
device->io_write(ATA_PORT_COMMAND, ATA_COMMAND_READ_SECTORS);
|
||||
|
||||
for (uint32_t sector = 0; sector < sector_count; sector++)
|
||||
{
|
||||
TRY(device->bus->wait(true));
|
||||
device->bus->read_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device->sector_words, device->sector_words);
|
||||
TRY(device->wait(true));
|
||||
device->read_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device->m_sector_words, device->m_sector_words);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -233,7 +240,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> ATAController::write(ATADevice* device, uint64_t lba, uint8_t sector_count, const uint8_t* buffer)
|
||||
{
|
||||
if (lba + sector_count > device->lba_count)
|
||||
if (lba + sector_count > device->m_lba_count)
|
||||
return BAN::Error::from_c_string("Attempted to read outside of the device boundaries");
|
||||
|
||||
LockGuard _(m_lock);
|
||||
|
@ -241,17 +248,17 @@ namespace Kernel
|
|||
if (lba < (1 << 28))
|
||||
{
|
||||
// LBA28
|
||||
device->bus->write(ATA_PORT_DRIVE_SELECT, 0xE0 | device->slave_bit | ((lba >> 24) & 0x0F));
|
||||
device->bus->write(ATA_PORT_SECTOR_COUNT, sector_count);
|
||||
device->bus->write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
|
||||
device->bus->write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
|
||||
device->bus->write(ATA_PORT_LBA2, (uint8_t)(lba >> 16));
|
||||
device->bus->write(ATA_PORT_COMMAND, ATA_COMMAND_WRITE_SECTORS);
|
||||
device->io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | device->m_slave_bit | ((lba >> 24) & 0x0F));
|
||||
device->io_write(ATA_PORT_SECTOR_COUNT, sector_count);
|
||||
device->io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
|
||||
device->io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
|
||||
device->io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16));
|
||||
device->io_write(ATA_PORT_COMMAND, ATA_COMMAND_WRITE_SECTORS);
|
||||
|
||||
for (uint32_t sector = 0; sector < sector_count; sector++)
|
||||
{
|
||||
TRY(device->bus->wait(false));
|
||||
device->bus->write_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device->sector_words, device->sector_words);
|
||||
TRY(device->wait(false));
|
||||
device->write_buffer(ATA_PORT_DATA, (uint16_t*)buffer + sector * device->m_sector_words, device->m_sector_words);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -260,71 +267,71 @@ namespace Kernel
|
|||
ASSERT(false);
|
||||
}
|
||||
|
||||
TRY(device->bus->wait(false));
|
||||
device->bus->write(ATA_PORT_COMMAND, ATA_COMMAND_CACHE_FLUSH);
|
||||
TRY(device->wait(false));
|
||||
device->io_write(ATA_PORT_COMMAND, ATA_COMMAND_CACHE_FLUSH);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ATADevice::read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* buffer)
|
||||
{
|
||||
TRY(controller->read(this, lba, sector_count, buffer));
|
||||
TRY(m_controller->read(this, lba, sector_count, buffer));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ATADevice::write_sectors(uint64_t lba, uint8_t sector_count, const uint8_t* buffer)
|
||||
{
|
||||
TRY(controller->write(this, lba, sector_count, buffer));
|
||||
TRY(m_controller->write(this, lba, sector_count, buffer));
|
||||
return {};
|
||||
}
|
||||
|
||||
uint8_t ATABus::read(uint16_t port)
|
||||
uint8_t ATADevice::io_read(uint16_t port)
|
||||
{
|
||||
if (port <= 0x07)
|
||||
return IO::inb(base + port);
|
||||
return IO::inb(m_base + port);
|
||||
if (0x10 <= port && port <= 0x11)
|
||||
return IO::inb(ctrl + port - 0x10);
|
||||
return IO::inb(m_ctrl + port - 0x10);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void ATABus::read_buffer(uint16_t port, uint16_t* buffer, size_t words)
|
||||
void ATADevice::read_buffer(uint16_t port, uint16_t* buffer, size_t words)
|
||||
{
|
||||
if (port <= 0x07)
|
||||
return IO::insw(base + port - 0x00, buffer, words);
|
||||
return IO::insw(m_base + port - 0x00, buffer, words);
|
||||
if (0x10 <= port && port <= 0x11)
|
||||
return IO::insw(ctrl + port - 0x10, buffer, words);
|
||||
return IO::insw(m_ctrl + port - 0x10, buffer, words);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void ATABus::write(uint16_t port, uint8_t data)
|
||||
void ATADevice::io_write(uint16_t port, uint8_t data)
|
||||
{
|
||||
if (port <= 0x07)
|
||||
return IO::outb(base + port, data);
|
||||
return IO::outb(m_base + port, data);
|
||||
if (0x10 <= port && port <= 0x11)
|
||||
return IO::outb(ctrl + port - 0x10, data);
|
||||
return IO::outb(m_ctrl + port - 0x10, data);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void ATABus::write_buffer(uint16_t port, const uint16_t* buffer, size_t words)
|
||||
void ATADevice::write_buffer(uint16_t port, const uint16_t* buffer, size_t words)
|
||||
{
|
||||
uint16_t io_port = 0;
|
||||
if (port <= 0x07)
|
||||
io_port = base + port;
|
||||
io_port = m_base + port;
|
||||
if (0x10 <= port && port <= 0x11)
|
||||
io_port = ctrl + port - 0x10;
|
||||
io_port = m_ctrl + port - 0x10;
|
||||
ASSERT(io_port);
|
||||
for (size_t i = 0; i < words; i++)
|
||||
IO::outw(io_port, buffer[i]);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ATABus::wait(bool wait_drq)
|
||||
BAN::ErrorOr<void> ATADevice::wait(bool wait_drq)
|
||||
{
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
read(ATA_PORT_ALT_STATUS);
|
||||
io_read(ATA_PORT_ALT_STATUS);
|
||||
|
||||
uint8_t status = ATA_STATUS_BSY;
|
||||
while (status & ATA_STATUS_BSY)
|
||||
status = read(ATA_PORT_STATUS);
|
||||
status = io_read(ATA_PORT_STATUS);
|
||||
|
||||
while (wait_drq && !(status & ATA_STATUS_DRQ))
|
||||
{
|
||||
|
@ -332,15 +339,15 @@ namespace Kernel
|
|||
return error();
|
||||
if (status & ATA_STATUS_DF)
|
||||
return BAN::Error::from_errno(EIO);
|
||||
status = read(ATA_PORT_STATUS);
|
||||
status = io_read(ATA_PORT_STATUS);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::Error ATABus::error()
|
||||
BAN::Error ATADevice::error()
|
||||
{
|
||||
uint8_t err = read(ATA_PORT_ERROR);
|
||||
uint8_t err = io_read(ATA_PORT_ERROR);
|
||||
if (err & ATA_ERROR_AMNF)
|
||||
return BAN::Error::from_c_string("Address mark not found.");
|
||||
if (err & ATA_ERROR_TKZNF)
|
||||
|
@ -362,8 +369,8 @@ namespace Kernel
|
|||
|
||||
dev_t ATADevice::dev() const
|
||||
{
|
||||
ASSERT(controller);
|
||||
return controller->dev();
|
||||
ASSERT(m_controller);
|
||||
return m_controller->dev();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> ATADevice::read(size_t offset, void* buffer, size_t bytes)
|
||||
|
|
Loading…
Reference in New Issue