[Denali] Add identify device command.
This commit is contained in:
parent
81469496d1
commit
d90c8eb1ef
|
@ -1,6 +1,6 @@
|
||||||
add_executable(denali
|
add_executable(denali
|
||||||
ahci/ahci_device.cpp
|
|
||||||
ahci/ahci_controller.cpp
|
ahci/ahci_controller.cpp
|
||||||
|
ahci/ahci_port.cpp
|
||||||
ahci/command.cpp
|
ahci/command.cpp
|
||||||
denali.cpp
|
denali.cpp
|
||||||
denali_server.cpp
|
denali_server.cpp
|
||||||
|
|
|
@ -64,7 +64,7 @@ const uint32_t kInterrupt_DMA_FIS = (1 << 2);
|
||||||
const uint32_t kInterrupt_DeviceBits_FIS = (1 << 3);
|
const uint32_t kInterrupt_DeviceBits_FIS = (1 << 3);
|
||||||
const uint32_t kInterrupt_Unknown_FIS = (1 << 4);
|
const uint32_t kInterrupt_Unknown_FIS = (1 << 4);
|
||||||
|
|
||||||
struct AhciPort {
|
struct AhciPortHba {
|
||||||
uint64_t command_list_base;
|
uint64_t command_list_base;
|
||||||
uint64_t fis_base;
|
uint64_t fis_base;
|
||||||
uint32_t interrupt_status;
|
uint32_t interrupt_status;
|
||||||
|
@ -190,6 +190,9 @@ struct PioSetupFis {
|
||||||
uint8_t rsv4[2]; // Reserved
|
uint8_t rsv4[2]; // Reserved
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
const uint8_t kIdentifyDevice = 0xEC;
|
||||||
|
const uint8_t kDmaReadExt = 0x25;
|
||||||
|
|
||||||
struct HostToDeviceRegisterFis {
|
struct HostToDeviceRegisterFis {
|
||||||
uint8_t fis_type; // FIS_TYPE_REG_H2D
|
uint8_t fis_type; // FIS_TYPE_REG_H2D
|
||||||
uint8_t pmp_and_c;
|
uint8_t pmp_and_c;
|
||||||
|
@ -216,6 +219,7 @@ struct HostToDeviceRegisterFis {
|
||||||
// DWORD 4
|
// DWORD 4
|
||||||
uint32_t reserved; // Reserved
|
uint32_t reserved; // Reserved
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct DeviceToHostRegisterFis {
|
struct DeviceToHostRegisterFis {
|
||||||
// DWORD 0
|
// DWORD 0
|
||||||
uint8_t fis_type; // FIS_TYPE_REG_D2H
|
uint8_t fis_type; // FIS_TYPE_REG_D2H
|
||||||
|
|
|
@ -33,7 +33,7 @@ glcr::ErrorOr<glcr::UniquePtr<AhciController>> AhciController::Init(
|
||||||
return driver;
|
return driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
glcr::ErrorOr<AhciDevice*> AhciController::GetDevice(uint64_t id) {
|
glcr::ErrorOr<AhciPort*> AhciController::GetDevice(uint64_t id) {
|
||||||
if (id >= num_ports_) {
|
if (id >= num_ports_) {
|
||||||
return glcr::INVALID_ARGUMENT;
|
return glcr::INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
@ -237,13 +237,18 @@ glcr::ErrorCode AhciController::LoadDevices() {
|
||||||
|
|
||||||
uint64_t port_addr =
|
uint64_t port_addr =
|
||||||
reinterpret_cast<uint64_t>(ahci_hba_) + 0x100 + (0x80 * i);
|
reinterpret_cast<uint64_t>(ahci_hba_) + 0x100 + (0x80 * i);
|
||||||
AhciPort* port = reinterpret_cast<AhciPort*>(port_addr);
|
AhciPortHba* port = reinterpret_cast<AhciPortHba*>(port_addr);
|
||||||
if ((port->sata_status & 0x103) != 0x103) {
|
if ((port->sata_status & 0x103) != 0x103) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
devices_[i] = new AhciDevice(reinterpret_cast<AhciPort*>(port_addr));
|
devices_[i] = new AhciPort(reinterpret_cast<AhciPortHba*>(port_addr));
|
||||||
devices_[i]->DumpInfo();
|
|
||||||
|
if (devices_[i]->IsSata()) {
|
||||||
|
IdentifyDeviceCommand identify(devices_[i].get());
|
||||||
|
devices_[i]->IssueCommand(&identify);
|
||||||
|
identify.WaitComplete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return glcr::OK;
|
return glcr::OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <ztypes.h>
|
#include <ztypes.h>
|
||||||
|
|
||||||
#include "ahci/ahci.h"
|
#include "ahci/ahci.h"
|
||||||
#include "ahci/ahci_device.h"
|
#include "ahci/ahci_port.h"
|
||||||
|
|
||||||
class AhciController {
|
class AhciController {
|
||||||
public:
|
public:
|
||||||
|
@ -16,7 +16,7 @@ class AhciController {
|
||||||
|
|
||||||
void InterruptLoop();
|
void InterruptLoop();
|
||||||
|
|
||||||
glcr::ErrorOr<AhciDevice*> GetDevice(uint64_t id);
|
glcr::ErrorOr<AhciPort*> GetDevice(uint64_t id);
|
||||||
|
|
||||||
void DumpCapabilities();
|
void DumpCapabilities();
|
||||||
void DumpPorts();
|
void DumpPorts();
|
||||||
|
@ -27,7 +27,7 @@ class AhciController {
|
||||||
mmth::OwnedMemoryRegion ahci_region_;
|
mmth::OwnedMemoryRegion ahci_region_;
|
||||||
volatile AhciHba* ahci_hba_ = nullptr;
|
volatile AhciHba* ahci_hba_ = nullptr;
|
||||||
|
|
||||||
glcr::UniquePtr<AhciDevice> devices_[32];
|
glcr::UniquePtr<AhciPort> devices_[32];
|
||||||
|
|
||||||
Thread irq_thread_;
|
Thread irq_thread_;
|
||||||
uint64_t irq_port_cap_ = 0;
|
uint64_t irq_port_cap_ = 0;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include "ahci/ahci_device.h"
|
#include "ahci/ahci_port.h"
|
||||||
|
|
||||||
#include <glacier/status/error.h>
|
#include <glacier/status/error.h>
|
||||||
#include <mammoth/util/debug.h>
|
#include <mammoth/util/debug.h>
|
||||||
#include <zcall.h>
|
#include <zcall.h>
|
||||||
|
|
||||||
AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) {
|
AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) {
|
||||||
if ((port_struct_->sata_status & 0x103) != 0x103) {
|
if ((port_struct_->sata_status & 0x103) != 0x103) {
|
||||||
crash("Creating device on port without a device",
|
crash("Creating device on port without a device",
|
||||||
glcr::FAILED_PRECONDITION);
|
glcr::FAILED_PRECONDITION);
|
||||||
|
@ -34,14 +34,14 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) {
|
||||||
(paddr + 0x500) + (0x100 * i);
|
(paddr + 0x500) + (0x100 * i);
|
||||||
commands_[i] = nullptr;
|
commands_[i] = nullptr;
|
||||||
}
|
}
|
||||||
port_struct_->interrupt_enable =
|
port_struct_->interrupt_enable = 0xFFFFFFFF;
|
||||||
kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS |
|
// kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS |
|
||||||
kInterrupt_DeviceBits_FIS | kInterrupt_Unknown_FIS;
|
// kInterrupt_DeviceBits_FIS | kInterrupt_Unknown_FIS;
|
||||||
port_struct_->sata_error = -1;
|
port_struct_->sata_error = -1;
|
||||||
port_struct_->command |= kCommand_Start;
|
port_struct_->command |= kCommand_Start;
|
||||||
}
|
}
|
||||||
|
|
||||||
glcr::ErrorCode AhciDevice::IssueCommand(Command* command) {
|
glcr::ErrorCode AhciPort::IssueCommand(Command* command) {
|
||||||
uint64_t slot;
|
uint64_t slot;
|
||||||
for (slot = 0; slot < 32; slot++) {
|
for (slot = 0; slot < 32; slot++) {
|
||||||
if (commands_[slot] == nullptr) {
|
if (commands_[slot] == nullptr) {
|
||||||
|
@ -56,7 +56,7 @@ glcr::ErrorCode AhciDevice::IssueCommand(Command* command) {
|
||||||
command->PopulatePrdt(command_tables_[slot].prdt);
|
command->PopulatePrdt(command_tables_[slot].prdt);
|
||||||
|
|
||||||
command_list_->command_headers[slot].command =
|
command_list_->command_headers[slot].command =
|
||||||
(sizeof(HostToDeviceRegisterFis) / 2) & 0x1F;
|
(sizeof(HostToDeviceRegisterFis) / 2) & 0x1F | (1 << 7);
|
||||||
command_list_->command_headers[slot].prd_table_length = 1;
|
command_list_->command_headers[slot].prd_table_length = 1;
|
||||||
command_list_->command_headers[slot].prd_byte_count = 0;
|
command_list_->command_headers[slot].prd_byte_count = 0;
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ glcr::ErrorCode AhciDevice::IssueCommand(Command* command) {
|
||||||
return glcr::OK;
|
return glcr::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AhciDevice::DumpInfo() {
|
void AhciPort::DumpInfo() {
|
||||||
dbgln("Comlist: {x}", port_struct_->command_list_base);
|
dbgln("Comlist: {x}", port_struct_->command_list_base);
|
||||||
dbgln("FIS: {x}", port_struct_->fis_base);
|
dbgln("FIS: {x}", port_struct_->fis_base);
|
||||||
dbgln("Command: {x}", port_struct_->command);
|
dbgln("Command: {x}", port_struct_->command);
|
||||||
|
@ -88,7 +88,7 @@ bool CheckFisType(FIS_TYPE expected, uint8_t actual) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AhciDevice::HandleIrq() {
|
void AhciPort::HandleIrq() {
|
||||||
uint32_t int_status = port_struct_->interrupt_status;
|
uint32_t int_status = port_struct_->interrupt_status;
|
||||||
port_struct_->interrupt_status = int_status;
|
port_struct_->interrupt_status = int_status;
|
||||||
|
|
||||||
|
@ -103,7 +103,9 @@ void AhciDevice::HandleIrq() {
|
||||||
}
|
}
|
||||||
if (fis.error) {
|
if (fis.error) {
|
||||||
dbgln("D2H err: {x}", fis.error);
|
dbgln("D2H err: {x}", fis.error);
|
||||||
|
|
||||||
dbgln("status: {x}", fis.status);
|
dbgln("status: {x}", fis.status);
|
||||||
|
dbgln("Error: {x}", port_struct_->sata_error);
|
||||||
has_error = true;
|
has_error = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,6 +116,7 @@ void AhciDevice::HandleIrq() {
|
||||||
if (!CheckFisType(FIS_TYPE_PIO_SETUP, fis.fis_type)) {
|
if (!CheckFisType(FIS_TYPE_PIO_SETUP, fis.fis_type)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
dbgln("Count: {x} {x} {x}", fis.counth, fis.countl, fis.e_status);
|
||||||
if (fis.error) {
|
if (fis.error) {
|
||||||
dbgln("PIO err: {x}", fis.error);
|
dbgln("PIO err: {x}", fis.error);
|
||||||
dbgln("status: {x}", fis.status);
|
dbgln("status: {x}", fis.status);
|
|
@ -8,25 +8,26 @@
|
||||||
#include "ahci/ahci.h"
|
#include "ahci/ahci.h"
|
||||||
#include "ahci/command.h"
|
#include "ahci/command.h"
|
||||||
|
|
||||||
class AhciDevice {
|
class AhciPort {
|
||||||
public:
|
public:
|
||||||
AhciDevice() {}
|
AhciPort() {}
|
||||||
// Caller retains ownership of the pointer.
|
// Caller retains ownership of the pointer.
|
||||||
AhciDevice(AhciPort* port_struct);
|
AhciPort(AhciPortHba* port_struct);
|
||||||
|
|
||||||
void DumpInfo();
|
void DumpInfo();
|
||||||
|
|
||||||
|
bool IsSata() { return port_struct_->signature == 0x101; }
|
||||||
bool IsInit() { return port_struct_ != nullptr && command_structures_; }
|
bool IsInit() { return port_struct_ != nullptr && command_structures_; }
|
||||||
|
|
||||||
glcr::ErrorCode IssueCommand(Command* command);
|
glcr::ErrorCode IssueCommand(Command* command);
|
||||||
|
|
||||||
void HandleIrq();
|
void HandleIrq();
|
||||||
|
|
||||||
AhciDevice(const AhciDevice&) = delete;
|
AhciPort(const AhciPort&) = delete;
|
||||||
AhciDevice& operator=(const AhciDevice&) = delete;
|
AhciPort& operator=(const AhciPort&) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
volatile AhciPort* port_struct_ = nullptr;
|
volatile AhciPortHba* port_struct_ = nullptr;
|
||||||
mmth::OwnedMemoryRegion command_structures_;
|
mmth::OwnedMemoryRegion command_structures_;
|
||||||
|
|
||||||
volatile CommandList* command_list_ = nullptr;
|
volatile CommandList* command_list_ = nullptr;
|
|
@ -1,5 +1,7 @@
|
||||||
#include "ahci/command.h"
|
#include "ahci/command.h"
|
||||||
|
|
||||||
|
#include <mammoth/util/debug.h>
|
||||||
|
|
||||||
#include "ahci/ahci.h"
|
#include "ahci/ahci.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -17,12 +19,46 @@ void* memcpy(void* dest, const void* src, uint64_t count) {
|
||||||
|
|
||||||
Command::~Command() {}
|
Command::~Command() {}
|
||||||
|
|
||||||
|
void Command::SignalComplete() {
|
||||||
|
OnComplete();
|
||||||
|
callback_semaphore_.Signal();
|
||||||
|
}
|
||||||
|
void Command::WaitComplete() { callback_semaphore_.Wait(); }
|
||||||
|
|
||||||
|
void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) {
|
||||||
|
HostToDeviceRegisterFis fis __attribute__((aligned(16))){
|
||||||
|
.fis_type = FIS_TYPE_REG_H2D,
|
||||||
|
.pmp_and_c = 0x80,
|
||||||
|
.command = kIdentifyDevice,
|
||||||
|
.device = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(command_fis, &fis, sizeof(fis));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdentifyDeviceCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) {
|
||||||
|
prdt[0].region_address = paddr_;
|
||||||
|
prdt[0].byte_count = 0x200 - 1;
|
||||||
|
dbgln("paddr: {x}", paddr_);
|
||||||
|
uint16_t* ident = reinterpret_cast<uint16_t*>(identify_.vaddr());
|
||||||
|
dbgln("vaddr: {x}", identify_.vaddr());
|
||||||
|
for (uint32_t i = 0; i < 256; i++) {
|
||||||
|
ident[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdentifyDeviceCommand::OnComplete() {
|
||||||
|
uint16_t* ident = reinterpret_cast<uint16_t*>(identify_.vaddr());
|
||||||
|
uint32_t* sector_size = reinterpret_cast<uint32_t*>(ident + 117);
|
||||||
|
dbgln("Sector size: {}", *sector_size);
|
||||||
|
uint64_t* lbas = reinterpret_cast<uint64_t*>(ident + 100);
|
||||||
|
dbgln("LBA Count: {}", *lbas);
|
||||||
|
// TODO tell the port its sector size.
|
||||||
|
}
|
||||||
|
|
||||||
DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt,
|
DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt,
|
||||||
uint64_t paddr)
|
uint64_t paddr)
|
||||||
: lba_(lba),
|
: lba_(lba), sector_cnt_(sector_cnt), paddr_(paddr) {}
|
||||||
sector_cnt_(sector_cnt),
|
|
||||||
paddr_(paddr),
|
|
||||||
callback_semaphore_() {}
|
|
||||||
|
|
||||||
DmaReadCommand::~DmaReadCommand() {}
|
DmaReadCommand::~DmaReadCommand() {}
|
||||||
|
|
||||||
|
@ -30,7 +66,7 @@ void DmaReadCommand::PopulateFis(uint8_t* command_fis) {
|
||||||
HostToDeviceRegisterFis fis{
|
HostToDeviceRegisterFis fis{
|
||||||
.fis_type = FIS_TYPE_REG_H2D,
|
.fis_type = FIS_TYPE_REG_H2D,
|
||||||
.pmp_and_c = 0x80,
|
.pmp_and_c = 0x80,
|
||||||
.command = 0x25,
|
.command = kDmaReadExt,
|
||||||
.featurel = 0,
|
.featurel = 0,
|
||||||
|
|
||||||
.lba0 = static_cast<uint8_t>(lba_ & 0xFF),
|
.lba0 = static_cast<uint8_t>(lba_ & 0xFF),
|
||||||
|
@ -50,14 +86,10 @@ void DmaReadCommand::PopulateFis(uint8_t* command_fis) {
|
||||||
.reserved = 0,
|
.reserved = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t bytes = sector_cnt_ * 512;
|
|
||||||
|
|
||||||
memcpy(command_fis, &fis, sizeof(fis));
|
memcpy(command_fis, &fis, sizeof(fis));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmaReadCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) {
|
void DmaReadCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) {
|
||||||
prdt[0].region_address = paddr_;
|
prdt[0].region_address = paddr_;
|
||||||
prdt[0].byte_count = sector_cnt_ * 512;
|
prdt[0].byte_count = sector_cnt_ * 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmaReadCommand::SignalComplete() { callback_semaphore_.Signal(); }
|
|
||||||
void DmaReadCommand::WaitComplete() { callback_semaphore_.Wait(); }
|
|
||||||
|
|
|
@ -1,17 +1,43 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mammoth/sync/semaphore.h>
|
#include <mammoth/sync/semaphore.h>
|
||||||
|
#include <mammoth/util/memory_region.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "ahci/ahci.h"
|
#include "ahci/ahci.h"
|
||||||
|
|
||||||
|
class AhciPort;
|
||||||
|
|
||||||
class Command {
|
class Command {
|
||||||
public:
|
public:
|
||||||
|
Command() = default;
|
||||||
virtual ~Command();
|
virtual ~Command();
|
||||||
virtual void PopulateFis(uint8_t* command_fis) = 0;
|
virtual void PopulateFis(uint8_t* command_fis) = 0;
|
||||||
virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) = 0;
|
virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) = 0;
|
||||||
virtual void WaitComplete() = 0;
|
void WaitComplete();
|
||||||
virtual void SignalComplete() = 0;
|
void SignalComplete();
|
||||||
|
|
||||||
|
virtual void OnComplete() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// TODO: Make this owned by the device so that we don't have to create a new
|
||||||
|
// one with the kernel every time a command is issued.
|
||||||
|
mmth::Semaphore callback_semaphore_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IdentifyDeviceCommand : public Command {
|
||||||
|
public:
|
||||||
|
IdentifyDeviceCommand(AhciPort* port) : port_(port) {}
|
||||||
|
virtual void PopulateFis(uint8_t* command_fis) override;
|
||||||
|
virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) override;
|
||||||
|
|
||||||
|
virtual void OnComplete() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AhciPort* port_;
|
||||||
|
uint64_t paddr_;
|
||||||
|
mmth::OwnedMemoryRegion identify_ =
|
||||||
|
mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &paddr_);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DmaReadCommand : public Command {
|
class DmaReadCommand : public Command {
|
||||||
|
@ -23,14 +49,8 @@ class DmaReadCommand : public Command {
|
||||||
void PopulateFis(uint8_t* command_fis) override;
|
void PopulateFis(uint8_t* command_fis) override;
|
||||||
void PopulatePrdt(PhysicalRegionDescriptor* prdt) override;
|
void PopulatePrdt(PhysicalRegionDescriptor* prdt) override;
|
||||||
|
|
||||||
void WaitComplete() override;
|
|
||||||
void SignalComplete() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t lba_;
|
uint64_t lba_;
|
||||||
uint64_t sector_cnt_;
|
uint64_t sector_cnt_;
|
||||||
uint64_t paddr_;
|
uint64_t paddr_;
|
||||||
// TODO: Make this owned by the device so that we don't have to create a new
|
|
||||||
// one with the kernel every time a command is issued.
|
|
||||||
mmth::Semaphore callback_semaphore_;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@ glcr::ErrorOr<glcr::UniquePtr<DenaliServer>> DenaliServer::Create(
|
||||||
|
|
||||||
glcr::Status DenaliServer::HandleRead(const ReadRequest& req,
|
glcr::Status DenaliServer::HandleRead(const ReadRequest& req,
|
||||||
ReadResponse& resp) {
|
ReadResponse& resp) {
|
||||||
ASSIGN_OR_RETURN(AhciDevice * device, driver_.GetDevice(req.device_id()));
|
ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id()));
|
||||||
|
|
||||||
uint64_t paddr;
|
uint64_t paddr;
|
||||||
mmth::OwnedMemoryRegion region =
|
mmth::OwnedMemoryRegion region =
|
||||||
|
@ -33,7 +33,7 @@ glcr::Status DenaliServer::HandleRead(const ReadRequest& req,
|
||||||
|
|
||||||
glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req,
|
glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req,
|
||||||
ReadResponse& resp) {
|
ReadResponse& resp) {
|
||||||
ASSIGN_OR_RETURN(AhciDevice * device, driver_.GetDevice(req.device_id()));
|
ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id()));
|
||||||
|
|
||||||
if (req.lba().size() != req.sector_cnt().size()) {
|
if (req.lba().size() != req.sector_cnt().size()) {
|
||||||
return glcr::InvalidArgument("LBA and Sector Cnt must be the same length.");
|
return glcr::InvalidArgument("LBA and Sector Cnt must be the same length.");
|
||||||
|
|
Loading…
Reference in New Issue