forked from Bananymous/banan-os
Kernel: Move ATADevice to its own file from ATAController
The API is kinda weird since device reads/writes go from ATADevice -> ATAController -> ATADevice but this is for now atleast necessary since ATAController has(?) to keep all devices from using the disks at the same time
This commit is contained in:
parent
f2362b2b78
commit
762d22ed28
|
@ -39,6 +39,7 @@ set(KERNEL_SOURCES
|
||||||
kernel/SpinLock.cpp
|
kernel/SpinLock.cpp
|
||||||
kernel/SSP.cpp
|
kernel/SSP.cpp
|
||||||
kernel/Storage/ATAController.cpp
|
kernel/Storage/ATAController.cpp
|
||||||
|
kernel/Storage/ATADevice.cpp
|
||||||
kernel/Storage/StorageDevice.cpp
|
kernel/Storage/StorageDevice.cpp
|
||||||
kernel/Syscall.cpp
|
kernel/Syscall.cpp
|
||||||
kernel/Thread.cpp
|
kernel/Thread.cpp
|
||||||
|
|
|
@ -8,79 +8,7 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
class ATAController;
|
class ATADevice;
|
||||||
|
|
||||||
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 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
|
|
||||||
{
|
|
||||||
ATA,
|
|
||||||
ATAPI,
|
|
||||||
};
|
|
||||||
|
|
||||||
ATAController* m_controller;
|
|
||||||
const uint16_t m_base;
|
|
||||||
const uint16_t m_ctrl;
|
|
||||||
const uint8_t m_index;
|
|
||||||
const uint8_t m_slave_bit;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
public:
|
|
||||||
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; }
|
|
||||||
virtual gid_t gid() const override { return 0; }
|
|
||||||
virtual off_t size() const override { return 0; }
|
|
||||||
virtual blksize_t blksize() const override { return sector_size(); }
|
|
||||||
virtual blkcnt_t blocks() const override { return 0; }
|
|
||||||
virtual dev_t dev() const override;
|
|
||||||
virtual dev_t rdev() const override { return 0x5429; }
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
public:
|
|
||||||
char m_device_name[4] {};
|
|
||||||
};
|
|
||||||
|
|
||||||
class ATAController final : public StorageController
|
class ATAController final : public StorageController
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define ATA_PORT_DATA 0x00
|
||||||
|
#define ATA_PORT_ERROR 0x00
|
||||||
|
#define ATA_PORT_SECTOR_COUNT 0x02
|
||||||
|
#define ATA_PORT_LBA0 0x03
|
||||||
|
#define ATA_PORT_LBA1 0x04
|
||||||
|
#define ATA_PORT_LBA2 0x05
|
||||||
|
#define ATA_PORT_DRIVE_SELECT 0x06
|
||||||
|
#define ATA_PORT_COMMAND 0x07
|
||||||
|
#define ATA_PORT_STATUS 0x07
|
||||||
|
|
||||||
|
#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
|
||||||
|
#define ATA_ERROR_MCR 0x08
|
||||||
|
#define ATA_ERROR_IDNF 0x10
|
||||||
|
#define ATA_ERROR_MC 0x20
|
||||||
|
#define ATA_ERROR_UNC 0x40
|
||||||
|
#define ATA_ERROR_BBK 0x80
|
||||||
|
|
||||||
|
#define ATA_STATUS_ERR 0x01
|
||||||
|
#define ATA_STATUS_DF 0x02
|
||||||
|
#define ATA_STATUS_DRQ 0x08
|
||||||
|
#define ATA_STATUS_BSY 0x80
|
||||||
|
|
||||||
|
#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_IDENTIFY_SIGNATURE 0
|
||||||
|
#define ATA_IDENTIFY_MODEL 27
|
||||||
|
#define ATA_IDENTIFY_CAPABILITIES 49
|
||||||
|
#define ATA_IDENTIFY_LBA_COUNT 60
|
||||||
|
#define ATA_IDENTIFY_COMMAND_SET 82
|
||||||
|
#define ATA_IDENTIFY_LBA_COUNT_EXT 100
|
||||||
|
#define ATA_IDENTIFY_SECTOR_INFO 106
|
||||||
|
#define ATA_IDENTIFY_SECTOR_WORDS 117
|
||||||
|
|
||||||
|
#define ATA_COMMANDSET_LBA48_SUPPORTED (1 << 26)
|
||||||
|
|
||||||
|
#define ATA_CAPABILITIES_LBA (1 << 9)
|
||||||
|
#define ATA_CAPABILITIES_DMA (1 << 8)
|
|
@ -0,0 +1,82 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/Storage/StorageDevice.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
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 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
|
||||||
|
{
|
||||||
|
ATA,
|
||||||
|
ATAPI,
|
||||||
|
};
|
||||||
|
|
||||||
|
ATAController* m_controller;
|
||||||
|
const uint16_t m_base;
|
||||||
|
const uint16_t m_ctrl;
|
||||||
|
const uint8_t m_index;
|
||||||
|
const uint8_t m_slave_bit;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public:
|
||||||
|
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; }
|
||||||
|
virtual gid_t gid() const override { return 0; }
|
||||||
|
virtual off_t size() const override { return 0; }
|
||||||
|
virtual blksize_t blksize() const override { return sector_size(); }
|
||||||
|
virtual blkcnt_t blocks() const override { return 0; }
|
||||||
|
virtual dev_t dev() const override;
|
||||||
|
virtual dev_t rdev() const override { return 0x5429; }
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public:
|
||||||
|
char m_device_name[4] {};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,68 +1,12 @@
|
||||||
#include <BAN/ScopeGuard.h>
|
#include <BAN/ScopeGuard.h>
|
||||||
#include <kernel/IO.h>
|
|
||||||
#include <kernel/LockGuard.h>
|
#include <kernel/LockGuard.h>
|
||||||
#include <kernel/Storage/ATAController.h>
|
#include <kernel/Storage/ATAController.h>
|
||||||
|
#include <kernel/Storage/ATADefinitions.h>
|
||||||
#define ATA_PORT_DATA 0x00
|
#include <kernel/Storage/ATADevice.h>
|
||||||
#define ATA_PORT_ERROR 0x00
|
|
||||||
#define ATA_PORT_SECTOR_COUNT 0x02
|
|
||||||
#define ATA_PORT_LBA0 0x03
|
|
||||||
#define ATA_PORT_LBA1 0x04
|
|
||||||
#define ATA_PORT_LBA2 0x05
|
|
||||||
#define ATA_PORT_DRIVE_SELECT 0x06
|
|
||||||
#define ATA_PORT_COMMAND 0x07
|
|
||||||
#define ATA_PORT_STATUS 0x07
|
|
||||||
|
|
||||||
#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
|
|
||||||
#define ATA_ERROR_MCR 0x08
|
|
||||||
#define ATA_ERROR_IDNF 0x10
|
|
||||||
#define ATA_ERROR_MC 0x20
|
|
||||||
#define ATA_ERROR_UNC 0x40
|
|
||||||
#define ATA_ERROR_BBK 0x80
|
|
||||||
|
|
||||||
#define ATA_STATUS_ERR 0x01
|
|
||||||
#define ATA_STATUS_DF 0x02
|
|
||||||
#define ATA_STATUS_DRQ 0x08
|
|
||||||
#define ATA_STATUS_BSY 0x80
|
|
||||||
|
|
||||||
#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_IDENTIFY_SIGNATURE 0
|
|
||||||
#define ATA_IDENTIFY_MODEL 27
|
|
||||||
#define ATA_IDENTIFY_CAPABILITIES 49
|
|
||||||
#define ATA_IDENTIFY_LBA_COUNT 60
|
|
||||||
#define ATA_IDENTIFY_COMMAND_SET 82
|
|
||||||
#define ATA_IDENTIFY_LBA_COUNT_EXT 100
|
|
||||||
#define ATA_IDENTIFY_SECTOR_INFO 106
|
|
||||||
#define ATA_IDENTIFY_SECTOR_WORDS 117
|
|
||||||
|
|
||||||
#define ATA_COMMANDSET_LBA48_SUPPORTED (1 << 26)
|
|
||||||
|
|
||||||
namespace Kernel
|
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)
|
BAN::ErrorOr<ATAController*> ATAController::create(const PCIDevice& device)
|
||||||
{
|
{
|
||||||
ATAController* controller = new ATAController();
|
ATAController* controller = new ATAController();
|
||||||
|
@ -74,90 +18,6 @@ namespace Kernel
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> ATADevice::initialize()
|
|
||||||
{
|
|
||||||
io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN);
|
|
||||||
|
|
||||||
io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | m_slave_bit);
|
|
||||||
PIT::sleep(1);
|
|
||||||
|
|
||||||
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)
|
BAN::ErrorOr<void> ATAController::initialize(const PCIDevice& pci_device)
|
||||||
{
|
{
|
||||||
struct Bus
|
struct Bus
|
||||||
|
@ -275,114 +135,4 @@ namespace Kernel
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> ATADevice::read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* 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(m_controller->write(this, lba, sector_count, buffer));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ATADevice::io_read(uint16_t port)
|
|
||||||
{
|
|
||||||
if (port <= 0x07)
|
|
||||||
return IO::inb(m_base + port);
|
|
||||||
if (0x10 <= port && port <= 0x11)
|
|
||||||
return IO::inb(m_ctrl + port - 0x10);
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATADevice::read_buffer(uint16_t port, uint16_t* buffer, size_t words)
|
|
||||||
{
|
|
||||||
if (port <= 0x07)
|
|
||||||
return IO::insw(m_base + port - 0x00, buffer, words);
|
|
||||||
if (0x10 <= port && port <= 0x11)
|
|
||||||
return IO::insw(m_ctrl + port - 0x10, buffer, words);
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATADevice::io_write(uint16_t port, uint8_t data)
|
|
||||||
{
|
|
||||||
if (port <= 0x07)
|
|
||||||
return IO::outb(m_base + port, data);
|
|
||||||
if (0x10 <= port && port <= 0x11)
|
|
||||||
return IO::outb(m_ctrl + port - 0x10, data);
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATADevice::write_buffer(uint16_t port, const uint16_t* buffer, size_t words)
|
|
||||||
{
|
|
||||||
uint16_t io_port = 0;
|
|
||||||
if (port <= 0x07)
|
|
||||||
io_port = m_base + port;
|
|
||||||
if (0x10 <= port && port <= 0x11)
|
|
||||||
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> ATADevice::wait(bool wait_drq)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < 4; i++)
|
|
||||||
io_read(ATA_PORT_ALT_STATUS);
|
|
||||||
|
|
||||||
uint8_t status = ATA_STATUS_BSY;
|
|
||||||
while (status & ATA_STATUS_BSY)
|
|
||||||
status = io_read(ATA_PORT_STATUS);
|
|
||||||
|
|
||||||
while (wait_drq && !(status & ATA_STATUS_DRQ))
|
|
||||||
{
|
|
||||||
if (status & ATA_STATUS_ERR)
|
|
||||||
return error();
|
|
||||||
if (status & ATA_STATUS_DF)
|
|
||||||
return BAN::Error::from_errno(EIO);
|
|
||||||
status = io_read(ATA_PORT_STATUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Error ATADevice::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)
|
|
||||||
return BAN::Error::from_c_string("Track zero not found.");
|
|
||||||
if (err & ATA_ERROR_ABRT)
|
|
||||||
return BAN::Error::from_c_string("Aborted command.");
|
|
||||||
if (err & ATA_ERROR_MCR)
|
|
||||||
return BAN::Error::from_c_string("Media change request.");
|
|
||||||
if (err & ATA_ERROR_IDNF)
|
|
||||||
return BAN::Error::from_c_string("ID not found.");
|
|
||||||
if (err & ATA_ERROR_MC)
|
|
||||||
return BAN::Error::from_c_string("Media changed.");
|
|
||||||
if (err & ATA_ERROR_UNC)
|
|
||||||
return BAN::Error::from_c_string("Uncorrectable data error.");
|
|
||||||
if (err & ATA_ERROR_BBK)
|
|
||||||
return BAN::Error::from_c_string("Bad Block detected.");
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_t ATADevice::dev() const
|
|
||||||
{
|
|
||||||
ASSERT(m_controller);
|
|
||||||
return m_controller->dev();
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> ATADevice::read(size_t offset, void* buffer, size_t bytes)
|
|
||||||
{
|
|
||||||
if (offset % sector_size() || bytes % sector_size())
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
if (offset == total_size())
|
|
||||||
return 0;
|
|
||||||
TRY(read_sectors(offset / sector_size(), bytes / sector_size(), (uint8_t*)buffer));
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
#include <BAN/ScopeGuard.h>
|
||||||
|
#include <kernel/IO.h>
|
||||||
|
#include <kernel/Storage/ATAController.h>
|
||||||
|
#include <kernel/Storage/ATADefinitions.h>
|
||||||
|
#include <kernel/Storage/ATADevice.h>
|
||||||
|
|
||||||
|
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<void> ATADevice::initialize()
|
||||||
|
{
|
||||||
|
io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN);
|
||||||
|
|
||||||
|
io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | m_slave_bit);
|
||||||
|
PIT::sleep(1);
|
||||||
|
|
||||||
|
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 (!(m_capabilities & ATA_CAPABILITIES_LBA))
|
||||||
|
return BAN::Error::from_c_string("Device does not support LBA addressing");
|
||||||
|
|
||||||
|
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> ATADevice::read_sectors(uint64_t lba, uint8_t sector_count, uint8_t* 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(m_controller->write(this, lba, sector_count, buffer));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ATADevice::io_read(uint16_t port)
|
||||||
|
{
|
||||||
|
if (port <= 0x07)
|
||||||
|
return IO::inb(m_base + port);
|
||||||
|
if (0x10 <= port && port <= 0x11)
|
||||||
|
return IO::inb(m_ctrl + port - 0x10);
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATADevice::read_buffer(uint16_t port, uint16_t* buffer, size_t words)
|
||||||
|
{
|
||||||
|
if (port <= 0x07)
|
||||||
|
return IO::insw(m_base + port - 0x00, buffer, words);
|
||||||
|
if (0x10 <= port && port <= 0x11)
|
||||||
|
return IO::insw(m_ctrl + port - 0x10, buffer, words);
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATADevice::io_write(uint16_t port, uint8_t data)
|
||||||
|
{
|
||||||
|
if (port <= 0x07)
|
||||||
|
return IO::outb(m_base + port, data);
|
||||||
|
if (0x10 <= port && port <= 0x11)
|
||||||
|
return IO::outb(m_ctrl + port - 0x10, data);
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATADevice::write_buffer(uint16_t port, const uint16_t* buffer, size_t words)
|
||||||
|
{
|
||||||
|
uint16_t io_port = 0;
|
||||||
|
if (port <= 0x07)
|
||||||
|
io_port = m_base + port;
|
||||||
|
if (0x10 <= port && port <= 0x11)
|
||||||
|
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> ATADevice::wait(bool wait_drq)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < 4; i++)
|
||||||
|
io_read(ATA_PORT_ALT_STATUS);
|
||||||
|
|
||||||
|
uint8_t status = ATA_STATUS_BSY;
|
||||||
|
while (status & ATA_STATUS_BSY)
|
||||||
|
status = io_read(ATA_PORT_STATUS);
|
||||||
|
|
||||||
|
while (wait_drq && !(status & ATA_STATUS_DRQ))
|
||||||
|
{
|
||||||
|
if (status & ATA_STATUS_ERR)
|
||||||
|
return error();
|
||||||
|
if (status & ATA_STATUS_DF)
|
||||||
|
return BAN::Error::from_errno(EIO);
|
||||||
|
status = io_read(ATA_PORT_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Error ATADevice::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)
|
||||||
|
return BAN::Error::from_c_string("Track zero not found.");
|
||||||
|
if (err & ATA_ERROR_ABRT)
|
||||||
|
return BAN::Error::from_c_string("Aborted command.");
|
||||||
|
if (err & ATA_ERROR_MCR)
|
||||||
|
return BAN::Error::from_c_string("Media change request.");
|
||||||
|
if (err & ATA_ERROR_IDNF)
|
||||||
|
return BAN::Error::from_c_string("ID not found.");
|
||||||
|
if (err & ATA_ERROR_MC)
|
||||||
|
return BAN::Error::from_c_string("Media changed.");
|
||||||
|
if (err & ATA_ERROR_UNC)
|
||||||
|
return BAN::Error::from_c_string("Uncorrectable data error.");
|
||||||
|
if (err & ATA_ERROR_BBK)
|
||||||
|
return BAN::Error::from_c_string("Bad Block detected.");
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_t ATADevice::dev() const
|
||||||
|
{
|
||||||
|
ASSERT(m_controller);
|
||||||
|
return m_controller->dev();
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<size_t> ATADevice::read(size_t offset, void* buffer, size_t bytes)
|
||||||
|
{
|
||||||
|
if (offset % sector_size() || bytes % sector_size())
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
if (offset == total_size())
|
||||||
|
return 0;
|
||||||
|
TRY(read_sectors(offset / sector_size(), bytes / sector_size(), (uint8_t*)buffer));
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue