Compare commits
3 Commits
440de700f9
...
e34540b77e
Author | SHA1 | Date |
---|---|---|
|
e34540b77e | |
|
4efeca661e | |
|
15a5e210ef |
|
@ -0,0 +1,264 @@
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct CommandHeader {
|
||||||
|
pub command: u16,
|
||||||
|
pub prd_table_length: u16,
|
||||||
|
pub prd_byte_count: u32,
|
||||||
|
pub command_table_base_addr: u64,
|
||||||
|
__: u64,
|
||||||
|
___: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CommandList = [CommandHeader; 32];
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum FisType {
|
||||||
|
RegisterHostToDevice = 0x27, // Register FIS - host to device
|
||||||
|
RegisterDeviceToHost = 0x34, // Register FIS - device to host
|
||||||
|
DmaActivate = 0x39, // DMA activate FIS - device to host
|
||||||
|
DmaSetup = 0x41, // DMA setup FIS - bidirectional
|
||||||
|
Data = 0x46, // Data FIS - bidirectional
|
||||||
|
BistActivate = 0x58, // BIST activate FIS - bidirectional
|
||||||
|
PioSetup = 0x5F, // PIO setup FIS - device to host
|
||||||
|
SetDeviceBits = 0xA1, // Set device bits FIS - device to host
|
||||||
|
Unknown = 0x0,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct DmaFis {
|
||||||
|
// DWORD 0
|
||||||
|
fis_type: u8, // FIS_TYPE_DMA_SETUP
|
||||||
|
pmport_dia: u8, // Port multiplier
|
||||||
|
|
||||||
|
__: u16, // Reserved
|
||||||
|
|
||||||
|
// DWORD 1&2
|
||||||
|
dma_buffer_id: u64, // DMA Buffer Identifier. Used to Identify DMA buffer
|
||||||
|
// in host memory. SATA Spec says host specific and not
|
||||||
|
// in Spec. Trying AHCI spec might work.
|
||||||
|
|
||||||
|
// DWORD 3
|
||||||
|
___: u32,
|
||||||
|
|
||||||
|
// DWORD 4
|
||||||
|
dma_buffer_offest: u32, // Byte offset into buffer. First 2 bits must be 0
|
||||||
|
|
||||||
|
// DWORD 5
|
||||||
|
transfer_count: u32, // Number of bytes to transfer. Bit 0 must be 0
|
||||||
|
|
||||||
|
// DWORD 6
|
||||||
|
____: u32, // Reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<DmaFis>() == 28);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct PioSetupFis {
|
||||||
|
// DWORD 0
|
||||||
|
fis_type: FisType, // FIS_TYPE_PIO_SETUP
|
||||||
|
|
||||||
|
pmport_di: u8, // Port multiplier
|
||||||
|
|
||||||
|
status: u8, // Status register
|
||||||
|
error: u8, // Error register
|
||||||
|
|
||||||
|
// DWORD 1
|
||||||
|
lba0: u8, // LBA low register, 7:0
|
||||||
|
lba1: u8, // LBA mid register, 15:8
|
||||||
|
lba2: u8, // LBA high register, 23:16
|
||||||
|
device: u8, // Device register
|
||||||
|
|
||||||
|
// DWORD 2
|
||||||
|
lba3: u8, // LBA register, 31:24
|
||||||
|
lba4: u8, // LBA register, 39:32
|
||||||
|
lba5: u8, // LBA register, 47:40
|
||||||
|
__: u8, // Reserved
|
||||||
|
|
||||||
|
// DWORD 3
|
||||||
|
countl: u8, // Count register, 7:0
|
||||||
|
counth: u8, // Count register, 15:8
|
||||||
|
___: u8, // Reserved
|
||||||
|
e_status: u8, // New value of status register
|
||||||
|
|
||||||
|
// DWORD 4
|
||||||
|
tc: u16, // Transfer count
|
||||||
|
____: u16, // Reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<PioSetupFis>() == 20);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum SataCommand {
|
||||||
|
IdentifyDevice = 0xEC,
|
||||||
|
DmaReadExt = 0x25,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // Read by memory.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct HostToDeviceRegisterFis {
|
||||||
|
fis_type: FisType, // FIS_TYPE_REG_H2D
|
||||||
|
pmp_and_c: u8,
|
||||||
|
command: SataCommand, // Command register
|
||||||
|
featurel: u8, // Feature register, 7:0
|
||||||
|
|
||||||
|
// DWORD 1
|
||||||
|
lba0: u8, // LBA low register, 7:0
|
||||||
|
lba1: u8, // LBA mid register, 15:8
|
||||||
|
lba2: u8, // LBA high register, 23:16
|
||||||
|
device: u8, // Device register
|
||||||
|
|
||||||
|
// DWORD 2
|
||||||
|
lba3: u8, // LBA register, 31:24
|
||||||
|
lba4: u8, // LBA register, 39:32
|
||||||
|
lba5: u8, // LBA register, 47:40
|
||||||
|
featureh: u8, // Feature register, 15:8
|
||||||
|
|
||||||
|
// DWORD 3
|
||||||
|
count: u16,
|
||||||
|
icc: u8, // Isochronous command completion
|
||||||
|
control: u8, // Control register
|
||||||
|
|
||||||
|
// DWORD 4
|
||||||
|
reserved: u32, // Reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<HostToDeviceRegisterFis>() == 20);
|
||||||
|
|
||||||
|
impl HostToDeviceRegisterFis {
|
||||||
|
pub fn new_command(command: SataCommand, lba: u64, sectors: u16) -> Self {
|
||||||
|
Self {
|
||||||
|
fis_type: FisType::RegisterHostToDevice,
|
||||||
|
pmp_and_c: 0x80, // Set command bit
|
||||||
|
command,
|
||||||
|
featurel: 0,
|
||||||
|
|
||||||
|
lba0: (lba & 0xFF) as u8,
|
||||||
|
lba1: ((lba >> 8) & 0xFF) as u8,
|
||||||
|
lba2: ((lba >> 16) & 0xFF) as u8,
|
||||||
|
device: (1 << 6), // ATA LBA Mode
|
||||||
|
|
||||||
|
lba3: ((lba >> 24) & 0xFF) as u8,
|
||||||
|
lba4: ((lba >> 32) & 0xFF) as u8,
|
||||||
|
lba5: ((lba >> 40) & 0xFF) as u8,
|
||||||
|
featureh: 0,
|
||||||
|
|
||||||
|
count: sectors,
|
||||||
|
icc: 0,
|
||||||
|
control: 0,
|
||||||
|
|
||||||
|
reserved: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct DeviceToHostRegisterFis {
|
||||||
|
// DWORD 0
|
||||||
|
pub fis_type: FisType, // FIS_TYPE_REG_D2H
|
||||||
|
|
||||||
|
pub pmport_and_i: u8,
|
||||||
|
|
||||||
|
pub status: u8, // Status register
|
||||||
|
pub error: u8, // Error register
|
||||||
|
|
||||||
|
// DWORD 1
|
||||||
|
pub lba0: u8, // LBA low register, 7:0
|
||||||
|
pub lba1: u8, // LBA mid register, 15:8
|
||||||
|
pub lba2: u8, // LBA high register, 23:16
|
||||||
|
pub device: u8, // Device register
|
||||||
|
|
||||||
|
// DWORD 2
|
||||||
|
pub lba3: u8, // LBA register, 31:24
|
||||||
|
pub lba4: u8, // LBA register, 39:32
|
||||||
|
pub lba5: u8, // LBA register, 47:40
|
||||||
|
__: u8,
|
||||||
|
|
||||||
|
// DWORD 3
|
||||||
|
pub count: u16,
|
||||||
|
___: u16,
|
||||||
|
|
||||||
|
____: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<DeviceToHostRegisterFis>() == 20);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct SetDeviceBitsFis {
|
||||||
|
fis_type: FisType,
|
||||||
|
pmport_and_i: u8,
|
||||||
|
status: u8,
|
||||||
|
error: u8,
|
||||||
|
reserved: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<SetDeviceBitsFis>() == 8);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct ReceivedFis {
|
||||||
|
pub dma_fis: DmaFis,
|
||||||
|
__: u32,
|
||||||
|
|
||||||
|
pub pio_set_fis: PioSetupFis,
|
||||||
|
___: [u8; 12],
|
||||||
|
|
||||||
|
pub device_to_host_register_fis: DeviceToHostRegisterFis,
|
||||||
|
____: u32,
|
||||||
|
|
||||||
|
pub set_device_bits_fis: SetDeviceBitsFis,
|
||||||
|
|
||||||
|
pub unknown_fis: [u8; 64],
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<ReceivedFis>() == 0xA0);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub union CommandFis {
|
||||||
|
pub host_to_device: HostToDeviceRegisterFis,
|
||||||
|
|
||||||
|
// Used to ensure the repr is
|
||||||
|
pub __: [u8; 64],
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<CommandFis>() == 0x40);
|
||||||
|
|
||||||
|
impl core::fmt::Debug for CommandFis {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("{:?}", unsafe { self.host_to_device }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct PhysicalRegionDescriptor {
|
||||||
|
pub region_address: u64,
|
||||||
|
__: u32,
|
||||||
|
// bit 0 must be one.
|
||||||
|
// 21:0 is byte count
|
||||||
|
// 31 is Interrupt on Completion
|
||||||
|
pub byte_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<PhysicalRegionDescriptor>() == 0x10);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct CommandTable {
|
||||||
|
pub command_fis: CommandFis,
|
||||||
|
pub atapi_command: [u8; 0x10],
|
||||||
|
__: [u8; 0x30],
|
||||||
|
pub prdt: [PhysicalRegionDescriptor; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<CommandTable>() == 0x100);
|
|
@ -1,264 +1,112 @@
|
||||||
#[derive(Debug)]
|
use core::{
|
||||||
#[repr(C, packed)]
|
future::Future,
|
||||||
pub struct CommandHeader {
|
ops::Deref,
|
||||||
pub command: u16,
|
ops::DerefMut,
|
||||||
pub prd_table_length: u16,
|
pin::Pin,
|
||||||
pub prd_byte_count: u32,
|
task::{Context, Poll, Waker},
|
||||||
pub command_table_base_addr: u64,
|
};
|
||||||
__: u64,
|
|
||||||
___: u64,
|
use alloc::boxed::Box;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use mammoth::{cap::Capability, sync::Mutex, syscall, zion::ZError};
|
||||||
|
|
||||||
|
use super::ahci_command::{HostToDeviceRegisterFis, SataCommand};
|
||||||
|
|
||||||
|
pub enum CommandStatus {
|
||||||
|
Empty,
|
||||||
|
NotSent,
|
||||||
|
Pending(Waker),
|
||||||
|
Complete,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type CommandList = [CommandHeader; 32];
|
pub struct CommandFuture {
|
||||||
|
status: Arc<Mutex<CommandStatus>>,
|
||||||
#[allow(dead_code)]
|
trigger: Box<dyn Fn() + Sync + Send>,
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum FisType {
|
|
||||||
RegisterHostToDevice = 0x27, // Register FIS - host to device
|
|
||||||
RegisterDeviceToHost = 0x34, // Register FIS - device to host
|
|
||||||
DmaActivate = 0x39, // DMA activate FIS - device to host
|
|
||||||
DmaSetup = 0x41, // DMA setup FIS - bidirectional
|
|
||||||
Data = 0x46, // Data FIS - bidirectional
|
|
||||||
BistActivate = 0x58, // BIST activate FIS - bidirectional
|
|
||||||
PioSetup = 0x5F, // PIO setup FIS - device to host
|
|
||||||
SetDeviceBits = 0xA1, // Set device bits FIS - device to host
|
|
||||||
Unknown = 0x0,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
impl CommandFuture {
|
||||||
#[derive(Copy, Clone, Debug)]
|
pub fn new(status: Arc<Mutex<CommandStatus>>, trigger: Box<dyn Fn() + Sync + Send>) -> Self {
|
||||||
#[repr(C, packed)]
|
Self { status, trigger }
|
||||||
pub struct DmaFis {
|
}
|
||||||
// DWORD 0
|
|
||||||
fis_type: u8, // FIS_TYPE_DMA_SETUP
|
|
||||||
pmport_dia: u8, // Port multiplier
|
|
||||||
|
|
||||||
__: u16, // Reserved
|
|
||||||
|
|
||||||
// DWORD 1&2
|
|
||||||
dma_buffer_id: u64, // DMA Buffer Identifier. Used to Identify DMA buffer
|
|
||||||
// in host memory. SATA Spec says host specific and not
|
|
||||||
// in Spec. Trying AHCI spec might work.
|
|
||||||
|
|
||||||
// DWORD 3
|
|
||||||
___: u32,
|
|
||||||
|
|
||||||
// DWORD 4
|
|
||||||
dma_buffer_offest: u32, // Byte offset into buffer. First 2 bits must be 0
|
|
||||||
|
|
||||||
// DWORD 5
|
|
||||||
transfer_count: u32, // Number of bytes to transfer. Bit 0 must be 0
|
|
||||||
|
|
||||||
// DWORD 6
|
|
||||||
____: u32, // Reserved
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _: () = assert!(size_of::<DmaFis>() == 28);
|
impl Drop for CommandFuture {
|
||||||
|
fn drop(&mut self) {
|
||||||
#[allow(dead_code)]
|
*self.status.lock() = CommandStatus::Empty;
|
||||||
#[derive(Copy, Clone, Debug)]
|
}
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct PioSetupFis {
|
|
||||||
// DWORD 0
|
|
||||||
fis_type: FisType, // FIS_TYPE_PIO_SETUP
|
|
||||||
|
|
||||||
pmport_di: u8, // Port multiplier
|
|
||||||
|
|
||||||
status: u8, // Status register
|
|
||||||
error: u8, // Error register
|
|
||||||
|
|
||||||
// DWORD 1
|
|
||||||
lba0: u8, // LBA low register, 7:0
|
|
||||||
lba1: u8, // LBA mid register, 15:8
|
|
||||||
lba2: u8, // LBA high register, 23:16
|
|
||||||
device: u8, // Device register
|
|
||||||
|
|
||||||
// DWORD 2
|
|
||||||
lba3: u8, // LBA register, 31:24
|
|
||||||
lba4: u8, // LBA register, 39:32
|
|
||||||
lba5: u8, // LBA register, 47:40
|
|
||||||
__: u8, // Reserved
|
|
||||||
|
|
||||||
// DWORD 3
|
|
||||||
countl: u8, // Count register, 7:0
|
|
||||||
counth: u8, // Count register, 15:8
|
|
||||||
___: u8, // Reserved
|
|
||||||
e_status: u8, // New value of status register
|
|
||||||
|
|
||||||
// DWORD 4
|
|
||||||
tc: u16, // Transfer count
|
|
||||||
____: u16, // Reserved
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _: () = assert!(size_of::<PioSetupFis>() == 20);
|
impl Future for CommandFuture {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
#[repr(u8)]
|
let s = self.deref_mut();
|
||||||
pub enum SataCommand {
|
let mut status = s.status.lock();
|
||||||
IdentifyDevice = 0xEC,
|
match status.deref() {
|
||||||
DmaReadExt = 0x25,
|
CommandStatus::NotSent => {
|
||||||
|
*status = CommandStatus::Pending(cx.waker().clone());
|
||||||
|
(s.trigger)();
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
CommandStatus::Pending(_) => Poll::Pending,
|
||||||
|
CommandStatus::Complete => Poll::Ready(()),
|
||||||
|
CommandStatus::Empty => panic!("Polling empty command slot"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)] // Read by memory.
|
pub struct Command {
|
||||||
#[derive(Clone, Copy, Debug)]
|
pub command: SataCommand,
|
||||||
#[repr(C)]
|
pub lba: u64,
|
||||||
pub struct HostToDeviceRegisterFis {
|
pub sector_cnt: u16,
|
||||||
fis_type: FisType, // FIS_TYPE_REG_H2D
|
pub paddr: u64,
|
||||||
pmp_and_c: u8,
|
|
||||||
command: SataCommand, // Command register
|
|
||||||
featurel: u8, // Feature register, 7:0
|
|
||||||
|
|
||||||
// DWORD 1
|
memory_region: Option<Capability>,
|
||||||
lba0: u8, // LBA low register, 7:0
|
|
||||||
lba1: u8, // LBA mid register, 15:8
|
|
||||||
lba2: u8, // LBA high register, 23:16
|
|
||||||
device: u8, // Device register
|
|
||||||
|
|
||||||
// DWORD 2
|
|
||||||
lba3: u8, // LBA register, 31:24
|
|
||||||
lba4: u8, // LBA register, 39:32
|
|
||||||
lba5: u8, // LBA register, 47:40
|
|
||||||
featureh: u8, // Feature register, 15:8
|
|
||||||
|
|
||||||
// DWORD 3
|
|
||||||
count: u16,
|
|
||||||
icc: u8, // Isochronous command completion
|
|
||||||
control: u8, // Control register
|
|
||||||
|
|
||||||
// DWORD 4
|
|
||||||
reserved: u32, // Reserved
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _: () = assert!(size_of::<HostToDeviceRegisterFis>() == 20);
|
impl Command {
|
||||||
|
pub fn identify() -> Result<Self, ZError> {
|
||||||
|
let (memory_region, paddr) = syscall::memory_object_contiguous_physical(512)?;
|
||||||
|
|
||||||
impl HostToDeviceRegisterFis {
|
Ok(Self {
|
||||||
pub fn new_command(command: SataCommand, lba: u64, sectors: u16) -> Self {
|
command: SataCommand::IdentifyDevice,
|
||||||
|
lba: 0,
|
||||||
|
sector_cnt: 1,
|
||||||
|
paddr,
|
||||||
|
memory_region: Some(memory_region),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(lba: u64, lba_count: u16) -> Result<Self, ZError> {
|
||||||
|
let (memory_region, paddr) =
|
||||||
|
syscall::memory_object_contiguous_physical(512 * (lba_count as u64))?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
command: SataCommand::DmaReadExt,
|
||||||
|
lba,
|
||||||
|
sector_cnt: lba_count,
|
||||||
|
paddr,
|
||||||
|
memory_region: Some(memory_region),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_manual(lba: u64, lba_count: u16, paddr: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
fis_type: FisType::RegisterHostToDevice,
|
command: SataCommand::DmaReadExt,
|
||||||
pmp_and_c: 0x80, // Set command bit
|
lba,
|
||||||
command,
|
sector_cnt: lba_count,
|
||||||
featurel: 0,
|
paddr: paddr,
|
||||||
|
memory_region: None,
|
||||||
lba0: (lba & 0xFF) as u8,
|
|
||||||
lba1: ((lba >> 8) & 0xFF) as u8,
|
|
||||||
lba2: ((lba >> 16) & 0xFF) as u8,
|
|
||||||
device: (1 << 6), // ATA LBA Mode
|
|
||||||
|
|
||||||
lba3: ((lba >> 24) & 0xFF) as u8,
|
|
||||||
lba4: ((lba >> 32) & 0xFF) as u8,
|
|
||||||
lba5: ((lba >> 40) & 0xFF) as u8,
|
|
||||||
featureh: 0,
|
|
||||||
|
|
||||||
count: sectors,
|
|
||||||
icc: 0,
|
|
||||||
control: 0,
|
|
||||||
|
|
||||||
reserved: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn release_mem_cap(&mut self) -> u64 {
|
||||||
|
self.memory_region.take().unwrap().release()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
impl From<&Command> for HostToDeviceRegisterFis {
|
||||||
#[repr(C, packed)]
|
fn from(val: &Command) -> Self {
|
||||||
pub struct DeviceToHostRegisterFis {
|
HostToDeviceRegisterFis::new_command(val.command, val.lba, val.sector_cnt)
|
||||||
// DWORD 0
|
|
||||||
pub fis_type: FisType, // FIS_TYPE_REG_D2H
|
|
||||||
|
|
||||||
pub pmport_and_i: u8,
|
|
||||||
|
|
||||||
pub status: u8, // Status register
|
|
||||||
pub error: u8, // Error register
|
|
||||||
|
|
||||||
// DWORD 1
|
|
||||||
pub lba0: u8, // LBA low register, 7:0
|
|
||||||
pub lba1: u8, // LBA mid register, 15:8
|
|
||||||
pub lba2: u8, // LBA high register, 23:16
|
|
||||||
pub device: u8, // Device register
|
|
||||||
|
|
||||||
// DWORD 2
|
|
||||||
pub lba3: u8, // LBA register, 31:24
|
|
||||||
pub lba4: u8, // LBA register, 39:32
|
|
||||||
pub lba5: u8, // LBA register, 47:40
|
|
||||||
__: u8,
|
|
||||||
|
|
||||||
// DWORD 3
|
|
||||||
pub count: u16,
|
|
||||||
___: u16,
|
|
||||||
|
|
||||||
____: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
const _: () = assert!(size_of::<DeviceToHostRegisterFis>() == 20);
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct SetDeviceBitsFis {
|
|
||||||
fis_type: FisType,
|
|
||||||
pmport_and_i: u8,
|
|
||||||
status: u8,
|
|
||||||
error: u8,
|
|
||||||
reserved: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
const _: () = assert!(size_of::<SetDeviceBitsFis>() == 8);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct ReceivedFis {
|
|
||||||
pub dma_fis: DmaFis,
|
|
||||||
__: u32,
|
|
||||||
|
|
||||||
pub pio_set_fis: PioSetupFis,
|
|
||||||
___: [u8; 12],
|
|
||||||
|
|
||||||
pub device_to_host_register_fis: DeviceToHostRegisterFis,
|
|
||||||
____: u32,
|
|
||||||
|
|
||||||
pub set_device_bits_fis: SetDeviceBitsFis,
|
|
||||||
|
|
||||||
pub unknown_fis: [u8; 64],
|
|
||||||
}
|
|
||||||
|
|
||||||
const _: () = assert!(size_of::<ReceivedFis>() == 0xA0);
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub union CommandFis {
|
|
||||||
pub host_to_device: HostToDeviceRegisterFis,
|
|
||||||
|
|
||||||
// Used to ensure the repr is
|
|
||||||
pub __: [u8; 64],
|
|
||||||
}
|
|
||||||
|
|
||||||
const _: () = assert!(size_of::<CommandFis>() == 0x40);
|
|
||||||
|
|
||||||
impl core::fmt::Debug for CommandFis {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
f.write_fmt(format_args!("{:?}", unsafe { self.host_to_device }))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct PhysicalRegionDescriptor {
|
|
||||||
pub region_address: u64,
|
|
||||||
__: u32,
|
|
||||||
// bit 0 must be one.
|
|
||||||
// 21:0 is byte count
|
|
||||||
// 31 is Interrupt on Completion
|
|
||||||
pub byte_count: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
const _: () = assert!(size_of::<PhysicalRegionDescriptor>() == 0x10);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct CommandTable {
|
|
||||||
pub command_fis: CommandFis,
|
|
||||||
pub atapi_command: [u8; 0x10],
|
|
||||||
__: [u8; 0x30],
|
|
||||||
pub prdt: [PhysicalRegionDescriptor; 8],
|
|
||||||
}
|
|
||||||
|
|
||||||
const _: () = assert!(size_of::<CommandTable>() == 0x100);
|
|
||||||
|
|
|
@ -1,28 +1,18 @@
|
||||||
use core::array;
|
|
||||||
use core::future::Future;
|
|
||||||
use core::ops::Deref;
|
|
||||||
use core::ops::DerefMut;
|
|
||||||
use core::pin::Pin;
|
|
||||||
use core::task::{Context, Poll, Waker};
|
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use mammoth::cap::Capability;
|
use mammoth::{
|
||||||
use mammoth::sync::Mutex;
|
cap::Capability,
|
||||||
use mammoth::syscall;
|
mem::{self, MemoryRegion},
|
||||||
use mammoth::{mem, thread};
|
sync::Mutex,
|
||||||
|
thread,
|
||||||
use mammoth::{mem::MemoryRegion, zion::ZError};
|
zion::ZError,
|
||||||
|
|
||||||
use crate::ahci::command::FisType;
|
|
||||||
use crate::ahci::port::{
|
|
||||||
AhciDeviceDetection, AhciInterfacePowerManagement, AhciPortInterruptStatus,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::command::{
|
use crate::ahci::{
|
||||||
CommandList, CommandTable, HostToDeviceRegisterFis, ReceivedFis, SataCommand,
|
port::{AhciDeviceDetection, AhciInterfacePowerManagement},
|
||||||
|
Command,
|
||||||
};
|
};
|
||||||
use super::{hba::AhciHba, port::AhciPortHba};
|
|
||||||
|
use super::{hba::AhciHba, port::AhciPortHba, port_controller::PortController};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
|
@ -206,248 +196,3 @@ pub fn spawn_irq_thread(controller: Arc<AhciController>) -> thread::JoinHandle {
|
||||||
pub async fn identify_ports(controller: Arc<AhciController>) {
|
pub async fn identify_ports(controller: Arc<AhciController>) {
|
||||||
controller.identify_ports().await.unwrap();
|
controller.identify_ports().await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CommandStatus {
|
|
||||||
Empty,
|
|
||||||
NotSent,
|
|
||||||
Pending(Waker),
|
|
||||||
Complete,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CommandFuture {
|
|
||||||
status: Arc<Mutex<CommandStatus>>,
|
|
||||||
trigger: Box<dyn Fn() + Sync + Send>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandFuture {
|
|
||||||
fn new(status: Arc<Mutex<CommandStatus>>, trigger: Box<dyn Fn() + Sync + Send>) -> Self {
|
|
||||||
Self { status, trigger }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for CommandFuture {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
*self.status.lock() = CommandStatus::Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Future for CommandFuture {
|
|
||||||
type Output = ();
|
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
let s = self.deref_mut();
|
|
||||||
let mut status = s.status.lock();
|
|
||||||
match status.deref() {
|
|
||||||
CommandStatus::NotSent => {
|
|
||||||
*status = CommandStatus::Pending(cx.waker().clone());
|
|
||||||
(s.trigger)();
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
CommandStatus::Pending(_) => Poll::Pending,
|
|
||||||
CommandStatus::Complete => Poll::Ready(()),
|
|
||||||
CommandStatus::Empty => panic!("Polling empty command slot"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Command {
|
|
||||||
command: SataCommand,
|
|
||||||
lba: u64,
|
|
||||||
sector_cnt: u16,
|
|
||||||
paddr: u64,
|
|
||||||
|
|
||||||
memory_region: Option<Capability>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command {
|
|
||||||
pub fn identify() -> Result<Self, ZError> {
|
|
||||||
let (memory_region, paddr) = syscall::memory_object_contiguous_physical(512)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
command: SataCommand::IdentifyDevice,
|
|
||||||
lba: 0,
|
|
||||||
sector_cnt: 1,
|
|
||||||
paddr,
|
|
||||||
memory_region: Some(memory_region),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(lba: u64, lba_count: u16) -> Result<Self, ZError> {
|
|
||||||
let (memory_region, paddr) =
|
|
||||||
syscall::memory_object_contiguous_physical(512 * (lba_count as u64))?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
command: SataCommand::DmaReadExt,
|
|
||||||
lba,
|
|
||||||
sector_cnt: lba_count,
|
|
||||||
paddr,
|
|
||||||
memory_region: Some(memory_region),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_manual(lba: u64, lba_count: u16, paddr: u64) -> Self {
|
|
||||||
Self {
|
|
||||||
command: SataCommand::DmaReadExt,
|
|
||||||
lba,
|
|
||||||
sector_cnt: lba_count,
|
|
||||||
paddr: paddr,
|
|
||||||
memory_region: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn release_mem_cap(&mut self) -> u64 {
|
|
||||||
self.memory_region.take().unwrap().release()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Command> for HostToDeviceRegisterFis {
|
|
||||||
fn from(val: &Command) -> Self {
|
|
||||||
HostToDeviceRegisterFis::new_command(val.command, val.lba, val.sector_cnt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CommandStructures {
|
|
||||||
command_list: &'static mut CommandList,
|
|
||||||
received_fis: &'static mut ReceivedFis,
|
|
||||||
command_tables: &'static mut [CommandTable; 32],
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PortController {
|
|
||||||
ahci_port_hba: Arc<Mutex<&'static mut AhciPortHba>>,
|
|
||||||
command_structures: Mutex<CommandStructures>,
|
|
||||||
|
|
||||||
command_slots: [Arc<Mutex<CommandStatus>>; 32],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PortController {
|
|
||||||
fn new(ahci_port_hba: &'static mut AhciPortHba) -> Self {
|
|
||||||
let (command_vaddr, command_paddr) = mem::map_physical_and_leak(0x2500);
|
|
||||||
ahci_port_hba.init(command_paddr, command_paddr + 0x400);
|
|
||||||
|
|
||||||
let command_list = unsafe { (command_vaddr as *mut CommandList).as_mut().unwrap() };
|
|
||||||
let received_fis = unsafe {
|
|
||||||
((command_vaddr + 0x400) as *mut ReceivedFis)
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
let command_tables = unsafe {
|
|
||||||
((command_vaddr + 0x500) as *mut [CommandTable; 32])
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
// This leaves space for 8 prdt entries.
|
|
||||||
for i in 0..32 {
|
|
||||||
command_list[i].command_table_base_addr =
|
|
||||||
(command_paddr + 0x500) + (0x100 * (i as u64));
|
|
||||||
}
|
|
||||||
|
|
||||||
let command_slots = array::from_fn(|_| Arc::new(Mutex::new(CommandStatus::Empty)));
|
|
||||||
|
|
||||||
Self {
|
|
||||||
ahci_port_hba: Arc::new(Mutex::new(ahci_port_hba)),
|
|
||||||
command_structures: Mutex::new(CommandStructures {
|
|
||||||
command_list,
|
|
||||||
received_fis,
|
|
||||||
command_tables,
|
|
||||||
}),
|
|
||||||
command_slots,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_signature(&self) -> u32 {
|
|
||||||
self.ahci_port_hba.lock().signature.read()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn issue_command(&self, command: &Command) -> Result<CommandFuture, ZError> {
|
|
||||||
let slot = self.select_slot()?;
|
|
||||||
let command_slot = self.command_slots[slot].clone();
|
|
||||||
|
|
||||||
let ahci_port_hba_clone = self.ahci_port_hba.clone();
|
|
||||||
let slot_clone = slot;
|
|
||||||
let future = CommandFuture::new(
|
|
||||||
command_slot,
|
|
||||||
Box::new(move || {
|
|
||||||
ahci_port_hba_clone.lock().issue_command(slot_clone);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut command_structures = self.command_structures.lock();
|
|
||||||
|
|
||||||
command_structures.command_tables[slot]
|
|
||||||
.command_fis
|
|
||||||
.host_to_device = command.into();
|
|
||||||
|
|
||||||
command_structures.command_tables[slot].prdt[0].region_address = command.paddr;
|
|
||||||
command_structures.command_tables[slot].prdt[0].byte_count =
|
|
||||||
512 * (command.sector_cnt as u32);
|
|
||||||
|
|
||||||
command_structures.command_list[slot].prd_table_length = 1;
|
|
||||||
|
|
||||||
command_structures.command_list[slot].command =
|
|
||||||
(size_of::<HostToDeviceRegisterFis>() as u16 / 4) & 0x1F;
|
|
||||||
command_structures.command_list[slot].command |= 1 << 7;
|
|
||||||
|
|
||||||
Ok(future)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn select_slot(&self) -> Result<usize, ZError> {
|
|
||||||
// TODO: We have a race condition here.
|
|
||||||
for i in 0..self.command_slots.len() {
|
|
||||||
let mut slot = self.command_slots[i].lock();
|
|
||||||
if matches!(*slot, CommandStatus::Empty) {
|
|
||||||
*slot = CommandStatus::NotSent;
|
|
||||||
return Ok(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(ZError::EXHAUSTED)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_interrupt(&self) {
|
|
||||||
let int_status = self.ahci_port_hba.lock().interrupt_status.read();
|
|
||||||
if int_status.device_to_host_register_fis_interrupt() {
|
|
||||||
let received_fis = self
|
|
||||||
.command_structures
|
|
||||||
.lock()
|
|
||||||
.received_fis
|
|
||||||
.device_to_host_register_fis;
|
|
||||||
assert_eq!(
|
|
||||||
received_fis.fis_type as u8,
|
|
||||||
FisType::RegisterDeviceToHost as u8
|
|
||||||
);
|
|
||||||
if received_fis.error != 0 {
|
|
||||||
mammoth::debug!("D2H err: {:#0x}", received_fis.error);
|
|
||||||
mammoth::debug!("Status: {:#0x}", received_fis.status);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ahci_port_hba.lock().interrupt_status.write(
|
|
||||||
AhciPortInterruptStatus::new().with_device_to_host_register_fis_interrupt(true),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if int_status.pio_setup_fis_interrupt() {
|
|
||||||
self.ahci_port_hba
|
|
||||||
.lock()
|
|
||||||
.interrupt_status
|
|
||||||
.write(AhciPortInterruptStatus::new().with_pio_setup_fis_interrupt(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..32 {
|
|
||||||
let int_offset = 1 << i;
|
|
||||||
|
|
||||||
// If there is no longer a command issued on a slot and we have something in
|
|
||||||
// the command list that is pending we know that this is the command that finished.
|
|
||||||
if (self.ahci_port_hba.lock().command_issue.read() & int_offset) != int_offset {
|
|
||||||
let mut command_status = self.command_slots[i].lock();
|
|
||||||
let mut did_complete = false;
|
|
||||||
if let CommandStatus::Pending(ref waker) = command_status.deref() {
|
|
||||||
waker.wake_by_ref();
|
|
||||||
did_complete = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if did_complete {
|
|
||||||
*command_status = CommandStatus::Complete;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
mod ahci_command;
|
||||||
mod command;
|
mod command;
|
||||||
mod controller;
|
mod controller;
|
||||||
mod hba;
|
mod hba;
|
||||||
mod port;
|
mod port;
|
||||||
|
mod port_controller;
|
||||||
|
|
||||||
|
pub use command::Command;
|
||||||
pub use controller::identify_ports;
|
pub use controller::identify_ports;
|
||||||
pub use controller::spawn_irq_thread;
|
pub use controller::spawn_irq_thread;
|
||||||
pub use controller::AhciController;
|
pub use controller::AhciController;
|
||||||
pub use controller::Command;
|
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
use core::array;
|
||||||
|
use core::ops::Deref;
|
||||||
|
|
||||||
|
use alloc::{boxed::Box, sync::Arc};
|
||||||
|
use mammoth::{mem, sync::Mutex, zion::ZError};
|
||||||
|
|
||||||
|
use crate::ahci::port::AhciPortInterruptStatus;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
ahci_command::{CommandList, CommandTable, FisType, HostToDeviceRegisterFis, ReceivedFis},
|
||||||
|
command::{CommandFuture, CommandStatus},
|
||||||
|
port::AhciPortHba,
|
||||||
|
Command,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommandStructures {
|
||||||
|
command_list: &'static mut CommandList,
|
||||||
|
received_fis: &'static mut ReceivedFis,
|
||||||
|
command_tables: &'static mut [CommandTable; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PortController {
|
||||||
|
ahci_port_hba: Arc<Mutex<&'static mut AhciPortHba>>,
|
||||||
|
command_structures: Mutex<CommandStructures>,
|
||||||
|
|
||||||
|
command_slots: [Arc<Mutex<CommandStatus>>; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PortController {
|
||||||
|
pub fn new(ahci_port_hba: &'static mut AhciPortHba) -> Self {
|
||||||
|
let (command_vaddr, command_paddr) = mem::map_physical_and_leak(0x2500);
|
||||||
|
ahci_port_hba.init(command_paddr, command_paddr + 0x400);
|
||||||
|
|
||||||
|
let command_list = unsafe { (command_vaddr as *mut CommandList).as_mut().unwrap() };
|
||||||
|
let received_fis = unsafe {
|
||||||
|
((command_vaddr + 0x400) as *mut ReceivedFis)
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
let command_tables = unsafe {
|
||||||
|
((command_vaddr + 0x500) as *mut [CommandTable; 32])
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// This leaves space for 8 prdt entries.
|
||||||
|
for i in 0..32 {
|
||||||
|
command_list[i].command_table_base_addr =
|
||||||
|
(command_paddr + 0x500) + (0x100 * (i as u64));
|
||||||
|
}
|
||||||
|
|
||||||
|
let command_slots = array::from_fn(|_| Arc::new(Mutex::new(CommandStatus::Empty)));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
ahci_port_hba: Arc::new(Mutex::new(ahci_port_hba)),
|
||||||
|
command_structures: Mutex::new(CommandStructures {
|
||||||
|
command_list,
|
||||||
|
received_fis,
|
||||||
|
command_tables,
|
||||||
|
}),
|
||||||
|
command_slots,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_signature(&self) -> u32 {
|
||||||
|
self.ahci_port_hba.lock().signature.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn issue_command(&self, command: &Command) -> Result<CommandFuture, ZError> {
|
||||||
|
let slot = self.select_slot()?;
|
||||||
|
let command_slot = self.command_slots[slot].clone();
|
||||||
|
|
||||||
|
let ahci_port_hba_clone = self.ahci_port_hba.clone();
|
||||||
|
let slot_clone = slot;
|
||||||
|
let future = CommandFuture::new(
|
||||||
|
command_slot,
|
||||||
|
Box::new(move || {
|
||||||
|
ahci_port_hba_clone.lock().issue_command(slot_clone);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut command_structures = self.command_structures.lock();
|
||||||
|
|
||||||
|
command_structures.command_tables[slot]
|
||||||
|
.command_fis
|
||||||
|
.host_to_device = command.into();
|
||||||
|
|
||||||
|
command_structures.command_tables[slot].prdt[0].region_address = command.paddr;
|
||||||
|
command_structures.command_tables[slot].prdt[0].byte_count =
|
||||||
|
512 * (command.sector_cnt as u32);
|
||||||
|
|
||||||
|
command_structures.command_list[slot].prd_table_length = 1;
|
||||||
|
|
||||||
|
command_structures.command_list[slot].command =
|
||||||
|
(size_of::<HostToDeviceRegisterFis>() as u16 / 4) & 0x1F;
|
||||||
|
command_structures.command_list[slot].command |= 1 << 7;
|
||||||
|
|
||||||
|
Ok(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_slot(&self) -> Result<usize, ZError> {
|
||||||
|
// TODO: We have a race condition here.
|
||||||
|
for i in 0..self.command_slots.len() {
|
||||||
|
let mut slot = self.command_slots[i].lock();
|
||||||
|
if matches!(*slot, CommandStatus::Empty) {
|
||||||
|
*slot = CommandStatus::NotSent;
|
||||||
|
return Ok(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ZError::EXHAUSTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_interrupt(&self) {
|
||||||
|
let int_status = self.ahci_port_hba.lock().interrupt_status.read();
|
||||||
|
if int_status.device_to_host_register_fis_interrupt() {
|
||||||
|
let received_fis = self
|
||||||
|
.command_structures
|
||||||
|
.lock()
|
||||||
|
.received_fis
|
||||||
|
.device_to_host_register_fis;
|
||||||
|
assert_eq!(
|
||||||
|
received_fis.fis_type as u8,
|
||||||
|
FisType::RegisterDeviceToHost as u8
|
||||||
|
);
|
||||||
|
if received_fis.error != 0 {
|
||||||
|
mammoth::debug!("D2H err: {:#0x}", received_fis.error);
|
||||||
|
mammoth::debug!("Status: {:#0x}", received_fis.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ahci_port_hba.lock().interrupt_status.write(
|
||||||
|
AhciPortInterruptStatus::new().with_device_to_host_register_fis_interrupt(true),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if int_status.pio_setup_fis_interrupt() {
|
||||||
|
self.ahci_port_hba
|
||||||
|
.lock()
|
||||||
|
.interrupt_status
|
||||||
|
.write(AhciPortInterruptStatus::new().with_pio_setup_fis_interrupt(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..32 {
|
||||||
|
let int_offset = 1 << i;
|
||||||
|
|
||||||
|
// If there is no longer a command issued on a slot and we have something in
|
||||||
|
// the command list that is pending we know that this is the command that finished.
|
||||||
|
if (self.ahci_port_hba.lock().command_issue.read() & int_offset) != int_offset {
|
||||||
|
let mut command_status = self.command_slots[i].lock();
|
||||||
|
let mut did_complete = false;
|
||||||
|
if let CommandStatus::Pending(ref waker) = command_status.deref() {
|
||||||
|
waker.wake_by_ref();
|
||||||
|
did_complete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if did_complete {
|
||||||
|
*command_status = CommandStatus::Complete;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,7 +47,7 @@ impl AsyncDenaliServerHandler for DenaliServerImpl {
|
||||||
// TODO: We should actually be able to read all of these in parallel.
|
// TODO: We should actually be able to read all of these in parallel.
|
||||||
self.ahci_controller
|
self.ahci_controller
|
||||||
.issue_command(req.device_id as usize, &command)
|
.issue_command(req.device_id as usize, &command)
|
||||||
.await;
|
.await?;
|
||||||
|
|
||||||
paddr += block.size * sector_size;
|
paddr += block.size * sector_size;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue