1004e86ffSlogin use core::{intrinsics::size_of, ptr}; 2004e86ffSlogin 3004e86ffSlogin use core::sync::atomic::compiler_fence; 4004e86ffSlogin 5*816ee5aeSLoGin use crate::arch::MMArch; 6*816ee5aeSLoGin use crate::mm::{MemoryManagementArch, PhysAddr}; 7004e86ffSlogin 8004e86ffSlogin /// 文件说明: 实现了 AHCI 中的控制器 HBA 的相关行为 9004e86ffSlogin 10004e86ffSlogin /// 根据 AHCI 写出 HBA 的 Command 11004e86ffSlogin pub const ATA_CMD_READ_DMA_EXT: u8 = 0x25; // 读操作,并且退出 12004e86ffSlogin pub const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; // 写操作,并且退出 13004e86ffSlogin #[allow(dead_code)] 14004e86ffSlogin pub const ATA_CMD_IDENTIFY: u8 = 0xEC; 15004e86ffSlogin #[allow(dead_code)] 16004e86ffSlogin pub const ATA_CMD_IDENTIFY_PACKET: u8 = 0xA1; 17004e86ffSlogin #[allow(dead_code)] 18004e86ffSlogin pub const ATA_CMD_PACKET: u8 = 0xA0; 19004e86ffSlogin pub const ATA_DEV_BUSY: u8 = 0x80; 20004e86ffSlogin pub const ATA_DEV_DRQ: u8 = 0x08; 21004e86ffSlogin 22004e86ffSlogin pub const HBA_PORT_CMD_CR: u32 = 1 << 15; 23004e86ffSlogin pub const HBA_PORT_CMD_FR: u32 = 1 << 14; 24004e86ffSlogin pub const HBA_PORT_CMD_FRE: u32 = 1 << 4; 25004e86ffSlogin pub const HBA_PORT_CMD_ST: u32 = 1; 26004e86ffSlogin #[allow(dead_code)] 27004e86ffSlogin pub const HBA_PORT_IS_ERR: u32 = 1 << 30 | 1 << 29 | 1 << 28 | 1 << 27; 28004e86ffSlogin pub const HBA_SSTS_PRESENT: u32 = 0x3; 29004e86ffSlogin pub const HBA_SIG_ATA: u32 = 0x00000101; 30004e86ffSlogin pub const HBA_SIG_ATAPI: u32 = 0xEB140101; 31004e86ffSlogin pub const HBA_SIG_PM: u32 = 0x96690101; 32004e86ffSlogin pub const HBA_SIG_SEMB: u32 = 0xC33C0101; 33004e86ffSlogin 34004e86ffSlogin /// 接入 Port 的 不同设备类型 35004e86ffSlogin #[derive(Debug)] 36004e86ffSlogin pub enum HbaPortType { 37004e86ffSlogin None, 38004e86ffSlogin Unknown(u32), 39004e86ffSlogin SATA, 40004e86ffSlogin SATAPI, 41004e86ffSlogin PM, 42004e86ffSlogin SEMB, 43004e86ffSlogin } 44004e86ffSlogin 45004e86ffSlogin /// 声明了 HBA 的所有属性 46004e86ffSlogin #[repr(packed)] 47bd70d2d1SLoGin #[allow(dead_code)] 48004e86ffSlogin pub struct HbaPort { 49004e86ffSlogin pub clb: u64, // 0x00, command list base address, 1K-byte aligned 50004e86ffSlogin pub fb: u64, // 0x08, FIS base address, 256-byte aligned 51004e86ffSlogin pub is: u32, // 0x10, interrupt status 52004e86ffSlogin pub ie: u32, // 0x14, interrupt enable 53004e86ffSlogin pub cmd: u32, // 0x18, command and status 54004e86ffSlogin pub _rsv0: u32, // 0x1C, Reserved 55004e86ffSlogin pub tfd: u32, // 0x20, task file data 56004e86ffSlogin pub sig: u32, // 0x24, signature 57004e86ffSlogin pub ssts: u32, // 0x28, SATA status (SCR0:SStatus) 58004e86ffSlogin pub sctl: u32, // 0x2C, SATA control (SCR2:SControl) 59004e86ffSlogin pub serr: u32, // 0x30, SATA error (SCR1:SError) 60004e86ffSlogin pub sact: u32, // 0x34, SATA active (SCR3:SActive) 61004e86ffSlogin pub ci: u32, // 0x38, command issue 62004e86ffSlogin pub sntf: u32, // 0x3C, SATA notification (SCR4:SNotification) 63004e86ffSlogin pub fbs: u32, // 0x40, FIS-based switch control 64004e86ffSlogin pub _rsv1: [u32; 11], // 0x44 ~ 0x6F, Reserved 65004e86ffSlogin pub vendor: [u32; 4], // 0x70 ~ 0x7F, vendor specific 66004e86ffSlogin } 67004e86ffSlogin 68004e86ffSlogin /// 全称 HBA Memory Register,是HBA的寄存器在内存中的映射 69004e86ffSlogin #[repr(packed)] 70bd70d2d1SLoGin #[allow(dead_code)] 71004e86ffSlogin pub struct HbaMem { 72004e86ffSlogin pub cap: u32, // 0x00, Host capability 73004e86ffSlogin pub ghc: u32, // 0x04, Global host control 74004e86ffSlogin pub is: u32, // 0x08, Interrupt status 75004e86ffSlogin pub pi: u32, // 0x0C, Port implemented 76004e86ffSlogin pub vs: u32, // 0x10, Version 77004e86ffSlogin pub ccc_ctl: u32, // 0x14, Command completion coalescing control 78004e86ffSlogin pub ccc_pts: u32, // 0x18, Command completion coalescing ports 79004e86ffSlogin pub em_loc: u32, // 0x1C, Enclosure management location 80004e86ffSlogin pub em_ctl: u32, // 0x20, Enclosure management control 81004e86ffSlogin pub cap2: u32, // 0x24, Host capabilities extended 82004e86ffSlogin pub bohc: u32, // 0x28, BIOS/OS handoff control and status 83004e86ffSlogin pub _rsv: [u8; 116], // 0x2C - 0x9F, Reserved 84004e86ffSlogin pub vendor: [u8; 96], // 0xA0 - 0xFF, Vendor specific registers 85004e86ffSlogin pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers 86004e86ffSlogin } 87004e86ffSlogin 88004e86ffSlogin /// HBA Command Table 里面的 PRDT 项 89004e86ffSlogin /// 作用: 记录了内存中读/写数据的位置,以及长度。你可以把他类比成一个指针? 90004e86ffSlogin #[repr(packed)] 91004e86ffSlogin pub struct HbaPrdtEntry { 92004e86ffSlogin pub dba: u64, // Data base address 93004e86ffSlogin _rsv0: u32, // Reserved 94004e86ffSlogin pub dbc: u32, // Byte count, 4M max, interrupt = 1 95004e86ffSlogin } 96004e86ffSlogin 97004e86ffSlogin /// HAB Command Table 98004e86ffSlogin /// 每个 Port 一个 Table,主机和设备的交互都靠这个数据结构 99004e86ffSlogin #[repr(packed)] 100bd70d2d1SLoGin #[allow(dead_code)] 101004e86ffSlogin pub struct HbaCmdTable { 102004e86ffSlogin // 0x00 103004e86ffSlogin pub cfis: [u8; 64], // Command FIS 104004e86ffSlogin // 0x40 105004e86ffSlogin pub acmd: [u8; 16], // ATAPI command, 12 or 16 bytes 106004e86ffSlogin // 0x50 107004e86ffSlogin _rsv: [u8; 48], // Reserved 108004e86ffSlogin // 0x80 1097ae679ddSLoGin pub prdt_entry: [HbaPrdtEntry; 8], // Physical region descriptor table entries, 0 ~ 65535, 需要注意不要越界 这里设置8的原因是,目前CmdTable只预留了8个PRDT项的空间 110004e86ffSlogin } 111004e86ffSlogin 112004e86ffSlogin /// HBA Command Header 113004e86ffSlogin /// 作用: 你可以把他类比成 Command Table 的指针。 114004e86ffSlogin /// 猜测: 这里多了一层 Header,而不是直接在 HbaMem 结构体指向 CmdTable,可能是为了兼容和可移植性? 115004e86ffSlogin #[repr(packed)] 116004e86ffSlogin pub struct HbaCmdHeader { 117004e86ffSlogin // DW0 118004e86ffSlogin pub cfl: u8, 119004e86ffSlogin // Command FIS length in DWORDS: 5(len in [2, 16]), atapi: 1, write - host to device: 1, prefetchable: 1 120004e86ffSlogin pub _pm: u8, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier 121004e86ffSlogin pub prdtl: u16, // Physical region descriptor table length in entries 122004e86ffSlogin // DW1 123004e86ffSlogin pub _prdbc: u32, // Physical region descriptor byte count transferred 124004e86ffSlogin // DW2, 3 125004e86ffSlogin pub ctba: u64, // Command table descriptor base address 126004e86ffSlogin // DW4 - 7 127004e86ffSlogin pub _rsv1: [u32; 4], // Reserved 128004e86ffSlogin } 129004e86ffSlogin 130004e86ffSlogin /// Port 的函数实现 131004e86ffSlogin impl HbaPort { 132004e86ffSlogin /// 获取设备类型 check_type(&mut self) -> HbaPortType133004e86ffSlogin pub fn check_type(&mut self) -> HbaPortType { 134004e86ffSlogin if volatile_read!(self.ssts) & HBA_SSTS_PRESENT > 0 { 135004e86ffSlogin let sig = volatile_read!(self.sig); 136004e86ffSlogin match sig { 137004e86ffSlogin HBA_SIG_ATA => HbaPortType::SATA, 138004e86ffSlogin HBA_SIG_ATAPI => HbaPortType::SATAPI, 139004e86ffSlogin HBA_SIG_PM => HbaPortType::PM, 140004e86ffSlogin HBA_SIG_SEMB => HbaPortType::SEMB, 141004e86ffSlogin _ => HbaPortType::Unknown(sig), 142004e86ffSlogin } 143004e86ffSlogin } else { 144004e86ffSlogin HbaPortType::None 145004e86ffSlogin } 146004e86ffSlogin } 147004e86ffSlogin 148004e86ffSlogin /// 启动该端口的命令引擎 start(&mut self)149004e86ffSlogin pub fn start(&mut self) { 150004e86ffSlogin while volatile_read!(self.cmd) & HBA_PORT_CMD_CR > 0 { 151004e86ffSlogin core::hint::spin_loop(); 152004e86ffSlogin } 153004e86ffSlogin let val: u32 = volatile_read!(self.cmd) | HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST; 154004e86ffSlogin volatile_write!(self.cmd, val); 155004e86ffSlogin } 156004e86ffSlogin 157004e86ffSlogin /// 关闭该端口的命令引擎 stop(&mut self)158004e86ffSlogin pub fn stop(&mut self) { 159004e86ffSlogin #[allow(unused_unsafe)] 160004e86ffSlogin { 161004e86ffSlogin volatile_write!( 162004e86ffSlogin self.cmd, 163004e86ffSlogin (u32::MAX ^ HBA_PORT_CMD_ST) & volatile_read!(self.cmd) 164004e86ffSlogin ); 165004e86ffSlogin } 166004e86ffSlogin 167004e86ffSlogin while volatile_read!(self.cmd) & (HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) 168004e86ffSlogin == (HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) 169004e86ffSlogin { 170004e86ffSlogin core::hint::spin_loop(); 171004e86ffSlogin } 172004e86ffSlogin 173004e86ffSlogin #[allow(unused_unsafe)] 174004e86ffSlogin { 175004e86ffSlogin volatile_write!( 176004e86ffSlogin self.cmd, 177004e86ffSlogin (u32::MAX ^ HBA_PORT_CMD_FRE) & volatile_read!(self.cmd) 178004e86ffSlogin ); 179004e86ffSlogin } 180004e86ffSlogin } 181004e86ffSlogin 182004e86ffSlogin /// @return: 返回一个空闲 cmd table 的 id; 如果没有,则返回 Option::None find_cmdslot(&self) -> Option<u32>183004e86ffSlogin pub fn find_cmdslot(&self) -> Option<u32> { 184004e86ffSlogin let slots = volatile_read!(self.sact) | volatile_read!(self.ci); 185b5b571e0SLoGin (0..32).find(|&i| slots & 1 << i == 0) 186004e86ffSlogin } 187004e86ffSlogin 188004e86ffSlogin /// 初始化, 把 CmdList 等变量的地址赋值到 HbaPort 上 - 这些空间由操作系统分配且固定 189004e86ffSlogin /// 等价于原C版本的 port_rebase 函数 init(&mut self, clb: u64, fb: u64, ctbas: &[u64])190b5b571e0SLoGin pub fn init(&mut self, clb: u64, fb: u64, ctbas: &[u64]) { 191004e86ffSlogin self.stop(); // 先暂停端口 192004e86ffSlogin 193004e86ffSlogin // 赋值 command list base address 194004e86ffSlogin // Command list offset: 1K*portno 195004e86ffSlogin // Command list entry size = 32 196004e86ffSlogin // Command list entry maxim count = 32 197004e86ffSlogin // Command list maxim size = 32*32 = 1K per port 198004e86ffSlogin volatile_write!(self.clb, clb); 199004e86ffSlogin 200004e86ffSlogin unsafe { 201004e86ffSlogin compiler_fence(core::sync::atomic::Ordering::SeqCst); 202*816ee5aeSLoGin ptr::write_bytes( 203*816ee5aeSLoGin MMArch::phys_2_virt(PhysAddr::new(clb as usize)) 204*816ee5aeSLoGin .unwrap() 205*816ee5aeSLoGin .data() as *mut u64, 206*816ee5aeSLoGin 0, 207*816ee5aeSLoGin 1024, 208*816ee5aeSLoGin ); 209004e86ffSlogin } 210004e86ffSlogin 211004e86ffSlogin // 赋值 fis base address 212004e86ffSlogin // FIS offset: 32K+256*portno 213004e86ffSlogin // FIS entry size = 256 bytes per port 214004e86ffSlogin volatile_write!(self.fb, fb); 215004e86ffSlogin unsafe { 216004e86ffSlogin compiler_fence(core::sync::atomic::Ordering::SeqCst); 217*816ee5aeSLoGin ptr::write_bytes( 218*816ee5aeSLoGin MMArch::phys_2_virt(PhysAddr::new(fb as usize)) 219*816ee5aeSLoGin .unwrap() 220*816ee5aeSLoGin .data() as *mut u64, 221*816ee5aeSLoGin 0, 222*816ee5aeSLoGin 256, 223*816ee5aeSLoGin ); 224004e86ffSlogin } 225004e86ffSlogin 226004e86ffSlogin // 赋值 command table base address 227004e86ffSlogin // Command table offset: 40K + 8K*portno 228004e86ffSlogin // Command table size = 256*32 = 8K per port 229*816ee5aeSLoGin let mut cmdheaders = unsafe { 230*816ee5aeSLoGin MMArch::phys_2_virt(PhysAddr::new(clb as usize)) 231*816ee5aeSLoGin .unwrap() 232*816ee5aeSLoGin .data() 233*816ee5aeSLoGin } as *mut u64 as *mut HbaCmdHeader; 234b5b571e0SLoGin for ctbas_value in ctbas.iter().take(32) { 2357ae679ddSLoGin volatile_write!((*cmdheaders).prdtl, 0); // 一开始没有询问,prdtl = 0(预留了8个PRDT项的空间) 236b5b571e0SLoGin volatile_write!((*cmdheaders).ctba, *ctbas_value); 237004e86ffSlogin // 这里限制了 prdtl <= 8, 所以一共用了256bytes,如果需要修改,可以修改这里 238004e86ffSlogin compiler_fence(core::sync::atomic::Ordering::SeqCst); 239004e86ffSlogin unsafe { 240*816ee5aeSLoGin ptr::write_bytes( 241*816ee5aeSLoGin MMArch::phys_2_virt(PhysAddr::new(*ctbas_value as usize)) 242*816ee5aeSLoGin .unwrap() 243*816ee5aeSLoGin .data() as *mut u64, 244*816ee5aeSLoGin 0, 245*816ee5aeSLoGin 256, 246*816ee5aeSLoGin ); 247004e86ffSlogin } 248004e86ffSlogin cmdheaders = (cmdheaders as usize + size_of::<HbaCmdHeader>()) as *mut HbaCmdHeader; 249004e86ffSlogin } 250004e86ffSlogin 251004e86ffSlogin #[allow(unused_unsafe)] 252004e86ffSlogin { 253004e86ffSlogin // 启动中断 254004e86ffSlogin volatile_write!(self.ie, 0 /*TODO: Enable interrupts: 0b10111*/); 255004e86ffSlogin 256004e86ffSlogin // 错误码 257004e86ffSlogin volatile_write!(self.serr, volatile_read!(self.serr)); 258004e86ffSlogin 259004e86ffSlogin // Disable power management 260004e86ffSlogin volatile_write!(self.sctl, volatile_read!(self.sctl) | 7 << 8); 261004e86ffSlogin 262004e86ffSlogin // Power on and spin up device 263004e86ffSlogin volatile_write!(self.cmd, volatile_read!(self.cmd) | 1 << 2 | 1 << 1); 264004e86ffSlogin } 265004e86ffSlogin self.start(); // 重新开启端口 266004e86ffSlogin } 267004e86ffSlogin } 268004e86ffSlogin 269004e86ffSlogin #[repr(u8)] 270004e86ffSlogin #[allow(dead_code)] 271004e86ffSlogin pub enum FisType { 272004e86ffSlogin /// Register FIS - host to device 273004e86ffSlogin RegH2D = 0x27, 274004e86ffSlogin /// Register FIS - device to host 275004e86ffSlogin RegD2H = 0x34, 276004e86ffSlogin /// DMA activate FIS - device to host 277004e86ffSlogin DmaAct = 0x39, 278004e86ffSlogin /// DMA setup FIS - bidirectional 279004e86ffSlogin DmaSetup = 0x41, 280004e86ffSlogin /// Data FIS - bidirectional 281004e86ffSlogin Data = 0x46, 282004e86ffSlogin /// BIST activate FIS - bidirectional 283004e86ffSlogin Bist = 0x58, 284004e86ffSlogin /// PIO setup FIS - device to host 285004e86ffSlogin PioSetup = 0x5F, 286004e86ffSlogin /// Set device bits FIS - device to host 287004e86ffSlogin DevBits = 0xA1, 288004e86ffSlogin } 289004e86ffSlogin 290004e86ffSlogin #[repr(packed)] 291bd70d2d1SLoGin #[allow(dead_code)] 292004e86ffSlogin pub struct FisRegH2D { 293004e86ffSlogin // DWORD 0 294004e86ffSlogin pub fis_type: u8, // FIS_TYPE_REG_H2D 295004e86ffSlogin 296004e86ffSlogin pub pm: u8, // Port multiplier, 1: Command, 0: Control 297004e86ffSlogin // uint8_t pmport : 4; // Port multiplier 低4位 298004e86ffSlogin // uint8_t rsv0 : 3; // Reserved 299004e86ffSlogin // uint8_t c : 1; // 1: Command, 0: Control 300004e86ffSlogin pub command: u8, // Command register 301004e86ffSlogin pub featurel: u8, // Feature register, 7:0 302004e86ffSlogin 303004e86ffSlogin // DWORD 1 304004e86ffSlogin pub lba0: u8, // LBA low register, 7:0 305004e86ffSlogin pub lba1: u8, // LBA mid register, 15:8 306004e86ffSlogin pub lba2: u8, // LBA high register, 23:16 307004e86ffSlogin pub device: u8, // Device register 308004e86ffSlogin 309004e86ffSlogin // DWORD 2 310004e86ffSlogin pub lba3: u8, // LBA register, 31:24 311004e86ffSlogin pub lba4: u8, // LBA register, 39:32 312004e86ffSlogin pub lba5: u8, // LBA register, 47:40 313004e86ffSlogin pub featureh: u8, // Feature register, 15:8 314004e86ffSlogin 315004e86ffSlogin // DWORD 3 316004e86ffSlogin pub countl: u8, // Count register, 7:0 317004e86ffSlogin pub counth: u8, // Count register, 15:8 318004e86ffSlogin pub icc: u8, // Isochronous command completion 319004e86ffSlogin pub control: u8, // Control register 320004e86ffSlogin 321004e86ffSlogin // DWORD 4 322004e86ffSlogin pub rsv1: [u8; 4], // Reserved 323004e86ffSlogin } 324004e86ffSlogin 325004e86ffSlogin #[repr(packed)] 326004e86ffSlogin #[allow(dead_code)] 327004e86ffSlogin pub struct FisRegD2H { 328004e86ffSlogin // DWORD 0 329004e86ffSlogin pub fis_type: u8, // FIS_TYPE_REG_D2H 330004e86ffSlogin 331004e86ffSlogin pub pm: u8, // Port multiplier, Interrupt bit: 2 332004e86ffSlogin 333004e86ffSlogin pub status: u8, // Status register 334004e86ffSlogin pub error: u8, // Error register 335004e86ffSlogin 336004e86ffSlogin // DWORD 1 337004e86ffSlogin pub lba0: u8, // LBA low register, 7:0 338004e86ffSlogin pub lba1: u8, // LBA mid register, 15:8 339004e86ffSlogin pub lba2: u8, // LBA high register, 23:16 340004e86ffSlogin pub device: u8, // Device register 341004e86ffSlogin 342004e86ffSlogin // DWORD 2 343004e86ffSlogin pub lba3: u8, // LBA register, 31:24 344004e86ffSlogin pub lba4: u8, // LBA register, 39:32 345004e86ffSlogin pub lba5: u8, // LBA register, 47:40 346004e86ffSlogin pub rsv2: u8, // Reserved 347004e86ffSlogin 348004e86ffSlogin // DWORD 3 349004e86ffSlogin pub countl: u8, // Count register, 7:0 350004e86ffSlogin pub counth: u8, // Count register, 15:8 351004e86ffSlogin pub rsv3: [u8; 2], // Reserved 352004e86ffSlogin 353004e86ffSlogin // DWORD 4 354004e86ffSlogin pub rsv4: [u8; 4], // Reserved 355004e86ffSlogin } 356004e86ffSlogin 357004e86ffSlogin #[repr(packed)] 358004e86ffSlogin #[allow(dead_code)] 359004e86ffSlogin pub struct FisData { 360004e86ffSlogin // DWORD 0 361004e86ffSlogin pub fis_type: u8, // FIS_TYPE_DATA 362004e86ffSlogin 363004e86ffSlogin pub pm: u8, // Port multiplier 364004e86ffSlogin 365004e86ffSlogin pub rsv1: [u8; 2], // Reserved 366004e86ffSlogin 367004e86ffSlogin // DWORD 1 ~ N 368004e86ffSlogin pub data: [u8; 252], // Payload 369004e86ffSlogin } 370004e86ffSlogin 371004e86ffSlogin #[repr(packed)] 372004e86ffSlogin #[allow(dead_code)] 373004e86ffSlogin pub struct FisPioSetup { 374004e86ffSlogin // DWORD 0 375004e86ffSlogin pub fis_type: u8, // FIS_TYPE_PIO_SETUP 376004e86ffSlogin 377004e86ffSlogin pub pm: u8, // Port multiplier, direction: 4 - device to host, interrupt: 2 378004e86ffSlogin 379004e86ffSlogin pub status: u8, // Status register 380004e86ffSlogin pub error: u8, // Error register 381004e86ffSlogin 382004e86ffSlogin // DWORD 1 383004e86ffSlogin pub lba0: u8, // LBA low register, 7:0 384004e86ffSlogin pub lba1: u8, // LBA mid register, 15:8 385004e86ffSlogin pub lba2: u8, // LBA high register, 23:16 386004e86ffSlogin pub device: u8, // Device register 387004e86ffSlogin 388004e86ffSlogin // DWORD 2 389004e86ffSlogin pub lba3: u8, // LBA register, 31:24 390004e86ffSlogin pub lba4: u8, // LBA register, 39:32 391004e86ffSlogin pub lba5: u8, // LBA register, 47:40 392004e86ffSlogin pub rsv2: u8, // Reserved 393004e86ffSlogin 394004e86ffSlogin // DWORD 3 395004e86ffSlogin pub countl: u8, // Count register, 7:0 396004e86ffSlogin pub counth: u8, // Count register, 15:8 397004e86ffSlogin pub rsv3: u8, // Reserved 398004e86ffSlogin pub e_status: u8, // New value of status register 399004e86ffSlogin 400004e86ffSlogin // DWORD 4 401004e86ffSlogin pub tc: u16, // Transfer count 402004e86ffSlogin pub rsv4: [u8; 2], // Reserved 403004e86ffSlogin } 404004e86ffSlogin 405004e86ffSlogin #[repr(packed)] 406004e86ffSlogin #[allow(dead_code)] 407004e86ffSlogin pub struct FisDmaSetup { 408004e86ffSlogin // DWORD 0 409004e86ffSlogin pub fis_type: u8, // FIS_TYPE_DMA_SETUP 410004e86ffSlogin 411004e86ffSlogin pub pm: u8, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1 412004e86ffSlogin 413004e86ffSlogin pub rsv1: [u8; 2], // Reserved 414004e86ffSlogin 415004e86ffSlogin // DWORD 1&2 416004e86ffSlogin pub 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. */ 417004e86ffSlogin 418004e86ffSlogin // DWORD 3 419004e86ffSlogin pub rsv3: u32, // More reserved 420004e86ffSlogin 421004e86ffSlogin // DWORD 4 422004e86ffSlogin pub dma_buffer_offset: u32, // Byte offset into buffer. First 2 bits must be 0 423004e86ffSlogin 424004e86ffSlogin // DWORD 5 425004e86ffSlogin pub transfer_count: u32, // Number of bytes to transfer. Bit 0 must be 0 426004e86ffSlogin 427004e86ffSlogin // DWORD 6 428004e86ffSlogin pub rsv6: u32, // Reserved 429004e86ffSlogin } 430