1*004e86ffSlogin use alloc::vec::Vec; 2*004e86ffSlogin use core::{intrinsics::size_of, ptr}; 3*004e86ffSlogin 4*004e86ffSlogin use core::sync::atomic::compiler_fence; 5*004e86ffSlogin 6*004e86ffSlogin use crate::mm::phys_2_virt; 7*004e86ffSlogin 8*004e86ffSlogin /// 文件说明: 实现了 AHCI 中的控制器 HBA 的相关行为 9*004e86ffSlogin 10*004e86ffSlogin /// 根据 AHCI 写出 HBA 的 Command 11*004e86ffSlogin pub const ATA_CMD_READ_DMA_EXT: u8 = 0x25; // 读操作,并且退出 12*004e86ffSlogin pub const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; // 写操作,并且退出 13*004e86ffSlogin #[allow(dead_code)] 14*004e86ffSlogin pub const ATA_CMD_IDENTIFY: u8 = 0xEC; 15*004e86ffSlogin #[allow(dead_code)] 16*004e86ffSlogin pub const ATA_CMD_IDENTIFY_PACKET: u8 = 0xA1; 17*004e86ffSlogin #[allow(dead_code)] 18*004e86ffSlogin pub const ATA_CMD_PACKET: u8 = 0xA0; 19*004e86ffSlogin pub const ATA_DEV_BUSY: u8 = 0x80; 20*004e86ffSlogin pub const ATA_DEV_DRQ: u8 = 0x08; 21*004e86ffSlogin 22*004e86ffSlogin pub const HBA_PORT_CMD_CR: u32 = 1 << 15; 23*004e86ffSlogin pub const HBA_PORT_CMD_FR: u32 = 1 << 14; 24*004e86ffSlogin pub const HBA_PORT_CMD_FRE: u32 = 1 << 4; 25*004e86ffSlogin pub const HBA_PORT_CMD_ST: u32 = 1; 26*004e86ffSlogin #[allow(dead_code)] 27*004e86ffSlogin pub const HBA_PORT_IS_ERR: u32 = 1 << 30 | 1 << 29 | 1 << 28 | 1 << 27; 28*004e86ffSlogin pub const HBA_SSTS_PRESENT: u32 = 0x3; 29*004e86ffSlogin pub const HBA_SIG_ATA: u32 = 0x00000101; 30*004e86ffSlogin pub const HBA_SIG_ATAPI: u32 = 0xEB140101; 31*004e86ffSlogin pub const HBA_SIG_PM: u32 = 0x96690101; 32*004e86ffSlogin pub const HBA_SIG_SEMB: u32 = 0xC33C0101; 33*004e86ffSlogin 34*004e86ffSlogin /// 接入 Port 的 不同设备类型 35*004e86ffSlogin #[derive(Debug)] 36*004e86ffSlogin pub enum HbaPortType { 37*004e86ffSlogin None, 38*004e86ffSlogin Unknown(u32), 39*004e86ffSlogin SATA, 40*004e86ffSlogin SATAPI, 41*004e86ffSlogin PM, 42*004e86ffSlogin SEMB, 43*004e86ffSlogin } 44*004e86ffSlogin 45*004e86ffSlogin /// 声明了 HBA 的所有属性 46*004e86ffSlogin #[repr(packed)] 47*004e86ffSlogin pub struct HbaPort { 48*004e86ffSlogin pub clb: u64, // 0x00, command list base address, 1K-byte aligned 49*004e86ffSlogin pub fb: u64, // 0x08, FIS base address, 256-byte aligned 50*004e86ffSlogin pub is: u32, // 0x10, interrupt status 51*004e86ffSlogin pub ie: u32, // 0x14, interrupt enable 52*004e86ffSlogin pub cmd: u32, // 0x18, command and status 53*004e86ffSlogin pub _rsv0: u32, // 0x1C, Reserved 54*004e86ffSlogin pub tfd: u32, // 0x20, task file data 55*004e86ffSlogin pub sig: u32, // 0x24, signature 56*004e86ffSlogin pub ssts: u32, // 0x28, SATA status (SCR0:SStatus) 57*004e86ffSlogin pub sctl: u32, // 0x2C, SATA control (SCR2:SControl) 58*004e86ffSlogin pub serr: u32, // 0x30, SATA error (SCR1:SError) 59*004e86ffSlogin pub sact: u32, // 0x34, SATA active (SCR3:SActive) 60*004e86ffSlogin pub ci: u32, // 0x38, command issue 61*004e86ffSlogin pub sntf: u32, // 0x3C, SATA notification (SCR4:SNotification) 62*004e86ffSlogin pub fbs: u32, // 0x40, FIS-based switch control 63*004e86ffSlogin pub _rsv1: [u32; 11], // 0x44 ~ 0x6F, Reserved 64*004e86ffSlogin pub vendor: [u32; 4], // 0x70 ~ 0x7F, vendor specific 65*004e86ffSlogin } 66*004e86ffSlogin 67*004e86ffSlogin /// 全称 HBA Memory Register,是HBA的寄存器在内存中的映射 68*004e86ffSlogin #[repr(packed)] 69*004e86ffSlogin pub struct HbaMem { 70*004e86ffSlogin pub cap: u32, // 0x00, Host capability 71*004e86ffSlogin pub ghc: u32, // 0x04, Global host control 72*004e86ffSlogin pub is: u32, // 0x08, Interrupt status 73*004e86ffSlogin pub pi: u32, // 0x0C, Port implemented 74*004e86ffSlogin pub vs: u32, // 0x10, Version 75*004e86ffSlogin pub ccc_ctl: u32, // 0x14, Command completion coalescing control 76*004e86ffSlogin pub ccc_pts: u32, // 0x18, Command completion coalescing ports 77*004e86ffSlogin pub em_loc: u32, // 0x1C, Enclosure management location 78*004e86ffSlogin pub em_ctl: u32, // 0x20, Enclosure management control 79*004e86ffSlogin pub cap2: u32, // 0x24, Host capabilities extended 80*004e86ffSlogin pub bohc: u32, // 0x28, BIOS/OS handoff control and status 81*004e86ffSlogin pub _rsv: [u8; 116], // 0x2C - 0x9F, Reserved 82*004e86ffSlogin pub vendor: [u8; 96], // 0xA0 - 0xFF, Vendor specific registers 83*004e86ffSlogin pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers 84*004e86ffSlogin } 85*004e86ffSlogin 86*004e86ffSlogin /// HBA Command Table 里面的 PRDT 项 87*004e86ffSlogin /// 作用: 记录了内存中读/写数据的位置,以及长度。你可以把他类比成一个指针? 88*004e86ffSlogin #[repr(packed)] 89*004e86ffSlogin pub struct HbaPrdtEntry { 90*004e86ffSlogin pub dba: u64, // Data base address 91*004e86ffSlogin _rsv0: u32, // Reserved 92*004e86ffSlogin pub dbc: u32, // Byte count, 4M max, interrupt = 1 93*004e86ffSlogin } 94*004e86ffSlogin 95*004e86ffSlogin /// HAB Command Table 96*004e86ffSlogin /// 每个 Port 一个 Table,主机和设备的交互都靠这个数据结构 97*004e86ffSlogin #[repr(packed)] 98*004e86ffSlogin pub struct HbaCmdTable { 99*004e86ffSlogin // 0x00 100*004e86ffSlogin pub cfis: [u8; 64], // Command FIS 101*004e86ffSlogin // 0x40 102*004e86ffSlogin pub acmd: [u8; 16], // ATAPI command, 12 or 16 bytes 103*004e86ffSlogin // 0x50 104*004e86ffSlogin _rsv: [u8; 48], // Reserved 105*004e86ffSlogin // 0x80 106*004e86ffSlogin pub prdt_entry: [HbaPrdtEntry; 65535], // Physical region descriptor table entries, 0 ~ 65535, 需要注意不要越界 107*004e86ffSlogin } 108*004e86ffSlogin 109*004e86ffSlogin /// HBA Command Header 110*004e86ffSlogin /// 作用: 你可以把他类比成 Command Table 的指针。 111*004e86ffSlogin /// 猜测: 这里多了一层 Header,而不是直接在 HbaMem 结构体指向 CmdTable,可能是为了兼容和可移植性? 112*004e86ffSlogin #[repr(packed)] 113*004e86ffSlogin pub struct HbaCmdHeader { 114*004e86ffSlogin // DW0 115*004e86ffSlogin pub cfl: u8, 116*004e86ffSlogin // Command FIS length in DWORDS: 5(len in [2, 16]), atapi: 1, write - host to device: 1, prefetchable: 1 117*004e86ffSlogin pub _pm: u8, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier 118*004e86ffSlogin pub prdtl: u16, // Physical region descriptor table length in entries 119*004e86ffSlogin // DW1 120*004e86ffSlogin pub _prdbc: u32, // Physical region descriptor byte count transferred 121*004e86ffSlogin // DW2, 3 122*004e86ffSlogin pub ctba: u64, // Command table descriptor base address 123*004e86ffSlogin // DW4 - 7 124*004e86ffSlogin pub _rsv1: [u32; 4], // Reserved 125*004e86ffSlogin } 126*004e86ffSlogin 127*004e86ffSlogin /// Port 的函数实现 128*004e86ffSlogin impl HbaPort { 129*004e86ffSlogin /// 获取设备类型 130*004e86ffSlogin pub fn check_type(&mut self) -> HbaPortType { 131*004e86ffSlogin if volatile_read!(self.ssts) & HBA_SSTS_PRESENT > 0 { 132*004e86ffSlogin let sig = volatile_read!(self.sig); 133*004e86ffSlogin match sig { 134*004e86ffSlogin HBA_SIG_ATA => HbaPortType::SATA, 135*004e86ffSlogin HBA_SIG_ATAPI => HbaPortType::SATAPI, 136*004e86ffSlogin HBA_SIG_PM => HbaPortType::PM, 137*004e86ffSlogin HBA_SIG_SEMB => HbaPortType::SEMB, 138*004e86ffSlogin _ => HbaPortType::Unknown(sig), 139*004e86ffSlogin } 140*004e86ffSlogin } else { 141*004e86ffSlogin HbaPortType::None 142*004e86ffSlogin } 143*004e86ffSlogin } 144*004e86ffSlogin 145*004e86ffSlogin /// 启动该端口的命令引擎 146*004e86ffSlogin pub fn start(&mut self) { 147*004e86ffSlogin while volatile_read!(self.cmd) & HBA_PORT_CMD_CR > 0 { 148*004e86ffSlogin core::hint::spin_loop(); 149*004e86ffSlogin } 150*004e86ffSlogin let val: u32 = volatile_read!(self.cmd) | HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST; 151*004e86ffSlogin volatile_write!(self.cmd, val); 152*004e86ffSlogin } 153*004e86ffSlogin 154*004e86ffSlogin /// 关闭该端口的命令引擎 155*004e86ffSlogin pub fn stop(&mut self) { 156*004e86ffSlogin #[allow(unused_unsafe)] 157*004e86ffSlogin { 158*004e86ffSlogin volatile_write!( 159*004e86ffSlogin self.cmd, 160*004e86ffSlogin (u32::MAX ^ HBA_PORT_CMD_ST) & volatile_read!(self.cmd) 161*004e86ffSlogin ); 162*004e86ffSlogin } 163*004e86ffSlogin 164*004e86ffSlogin while volatile_read!(self.cmd) & (HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) 165*004e86ffSlogin == (HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) 166*004e86ffSlogin { 167*004e86ffSlogin core::hint::spin_loop(); 168*004e86ffSlogin } 169*004e86ffSlogin 170*004e86ffSlogin #[allow(unused_unsafe)] 171*004e86ffSlogin { 172*004e86ffSlogin volatile_write!( 173*004e86ffSlogin self.cmd, 174*004e86ffSlogin (u32::MAX ^ HBA_PORT_CMD_FRE) & volatile_read!(self.cmd) 175*004e86ffSlogin ); 176*004e86ffSlogin } 177*004e86ffSlogin } 178*004e86ffSlogin 179*004e86ffSlogin /// @return: 返回一个空闲 cmd table 的 id; 如果没有,则返回 Option::None 180*004e86ffSlogin pub fn find_cmdslot(&self) -> Option<u32> { 181*004e86ffSlogin let slots = volatile_read!(self.sact) | volatile_read!(self.ci); 182*004e86ffSlogin for i in 0..32 { 183*004e86ffSlogin if slots & 1 << i == 0 { 184*004e86ffSlogin return Some(i); 185*004e86ffSlogin } 186*004e86ffSlogin } 187*004e86ffSlogin return None; 188*004e86ffSlogin } 189*004e86ffSlogin 190*004e86ffSlogin /// 初始化, 把 CmdList 等变量的地址赋值到 HbaPort 上 - 这些空间由操作系统分配且固定 191*004e86ffSlogin /// 等价于原C版本的 port_rebase 函数 192*004e86ffSlogin pub fn init(&mut self, clb: u64, fb: u64, ctbas: &Vec<u64>) { 193*004e86ffSlogin self.stop(); // 先暂停端口 194*004e86ffSlogin 195*004e86ffSlogin // 赋值 command list base address 196*004e86ffSlogin // Command list offset: 1K*portno 197*004e86ffSlogin // Command list entry size = 32 198*004e86ffSlogin // Command list entry maxim count = 32 199*004e86ffSlogin // Command list maxim size = 32*32 = 1K per port 200*004e86ffSlogin volatile_write!(self.clb, clb); 201*004e86ffSlogin 202*004e86ffSlogin unsafe { 203*004e86ffSlogin compiler_fence(core::sync::atomic::Ordering::SeqCst); 204*004e86ffSlogin ptr::write_bytes(phys_2_virt(clb as usize) as *mut u64, 0, 1024); 205*004e86ffSlogin } 206*004e86ffSlogin 207*004e86ffSlogin // 赋值 fis base address 208*004e86ffSlogin // FIS offset: 32K+256*portno 209*004e86ffSlogin // FIS entry size = 256 bytes per port 210*004e86ffSlogin volatile_write!(self.fb, fb); 211*004e86ffSlogin unsafe { 212*004e86ffSlogin compiler_fence(core::sync::atomic::Ordering::SeqCst); 213*004e86ffSlogin ptr::write_bytes(phys_2_virt(fb as usize) as *mut u64, 0, 256); 214*004e86ffSlogin } 215*004e86ffSlogin 216*004e86ffSlogin // 赋值 command table base address 217*004e86ffSlogin // Command table offset: 40K + 8K*portno 218*004e86ffSlogin // Command table size = 256*32 = 8K per port 219*004e86ffSlogin let mut cmdheaders = phys_2_virt(clb as usize) as *mut u64 as *mut HbaCmdHeader; 220*004e86ffSlogin for i in 0..32 as usize { 221*004e86ffSlogin volatile_write!((*cmdheaders).prdtl, 0); // 一开始没有询问,prdtl = 0 222*004e86ffSlogin volatile_write!((*cmdheaders).ctba, ctbas[i]); 223*004e86ffSlogin // 这里限制了 prdtl <= 8, 所以一共用了256bytes,如果需要修改,可以修改这里 224*004e86ffSlogin compiler_fence(core::sync::atomic::Ordering::SeqCst); 225*004e86ffSlogin unsafe { 226*004e86ffSlogin ptr::write_bytes(phys_2_virt(ctbas[i] as usize) as *mut u64, 0, 256); 227*004e86ffSlogin } 228*004e86ffSlogin cmdheaders = (cmdheaders as usize + size_of::<HbaCmdHeader>()) as *mut HbaCmdHeader; 229*004e86ffSlogin } 230*004e86ffSlogin 231*004e86ffSlogin #[allow(unused_unsafe)] 232*004e86ffSlogin { 233*004e86ffSlogin // 启动中断 234*004e86ffSlogin volatile_write!(self.ie, 0 /*TODO: Enable interrupts: 0b10111*/); 235*004e86ffSlogin 236*004e86ffSlogin // 错误码 237*004e86ffSlogin volatile_write!(self.serr, volatile_read!(self.serr)); 238*004e86ffSlogin 239*004e86ffSlogin // Disable power management 240*004e86ffSlogin volatile_write!(self.sctl, volatile_read!(self.sctl) | 7 << 8); 241*004e86ffSlogin 242*004e86ffSlogin // Power on and spin up device 243*004e86ffSlogin volatile_write!(self.cmd, volatile_read!(self.cmd) | 1 << 2 | 1 << 1); 244*004e86ffSlogin } 245*004e86ffSlogin self.start(); // 重新开启端口 246*004e86ffSlogin } 247*004e86ffSlogin } 248*004e86ffSlogin 249*004e86ffSlogin #[repr(u8)] 250*004e86ffSlogin #[allow(dead_code)] 251*004e86ffSlogin pub enum FisType { 252*004e86ffSlogin /// Register FIS - host to device 253*004e86ffSlogin RegH2D = 0x27, 254*004e86ffSlogin /// Register FIS - device to host 255*004e86ffSlogin RegD2H = 0x34, 256*004e86ffSlogin /// DMA activate FIS - device to host 257*004e86ffSlogin DmaAct = 0x39, 258*004e86ffSlogin /// DMA setup FIS - bidirectional 259*004e86ffSlogin DmaSetup = 0x41, 260*004e86ffSlogin /// Data FIS - bidirectional 261*004e86ffSlogin Data = 0x46, 262*004e86ffSlogin /// BIST activate FIS - bidirectional 263*004e86ffSlogin Bist = 0x58, 264*004e86ffSlogin /// PIO setup FIS - device to host 265*004e86ffSlogin PioSetup = 0x5F, 266*004e86ffSlogin /// Set device bits FIS - device to host 267*004e86ffSlogin DevBits = 0xA1, 268*004e86ffSlogin } 269*004e86ffSlogin 270*004e86ffSlogin #[repr(packed)] 271*004e86ffSlogin pub struct FisRegH2D { 272*004e86ffSlogin // DWORD 0 273*004e86ffSlogin pub fis_type: u8, // FIS_TYPE_REG_H2D 274*004e86ffSlogin 275*004e86ffSlogin pub pm: u8, // Port multiplier, 1: Command, 0: Control 276*004e86ffSlogin // uint8_t pmport : 4; // Port multiplier 低4位 277*004e86ffSlogin // uint8_t rsv0 : 3; // Reserved 278*004e86ffSlogin // uint8_t c : 1; // 1: Command, 0: Control 279*004e86ffSlogin pub command: u8, // Command register 280*004e86ffSlogin pub featurel: u8, // Feature register, 7:0 281*004e86ffSlogin 282*004e86ffSlogin // DWORD 1 283*004e86ffSlogin pub lba0: u8, // LBA low register, 7:0 284*004e86ffSlogin pub lba1: u8, // LBA mid register, 15:8 285*004e86ffSlogin pub lba2: u8, // LBA high register, 23:16 286*004e86ffSlogin pub device: u8, // Device register 287*004e86ffSlogin 288*004e86ffSlogin // DWORD 2 289*004e86ffSlogin pub lba3: u8, // LBA register, 31:24 290*004e86ffSlogin pub lba4: u8, // LBA register, 39:32 291*004e86ffSlogin pub lba5: u8, // LBA register, 47:40 292*004e86ffSlogin pub featureh: u8, // Feature register, 15:8 293*004e86ffSlogin 294*004e86ffSlogin // DWORD 3 295*004e86ffSlogin pub countl: u8, // Count register, 7:0 296*004e86ffSlogin pub counth: u8, // Count register, 15:8 297*004e86ffSlogin pub icc: u8, // Isochronous command completion 298*004e86ffSlogin pub control: u8, // Control register 299*004e86ffSlogin 300*004e86ffSlogin // DWORD 4 301*004e86ffSlogin pub rsv1: [u8; 4], // Reserved 302*004e86ffSlogin } 303*004e86ffSlogin 304*004e86ffSlogin #[repr(packed)] 305*004e86ffSlogin #[allow(dead_code)] 306*004e86ffSlogin pub struct FisRegD2H { 307*004e86ffSlogin // DWORD 0 308*004e86ffSlogin pub fis_type: u8, // FIS_TYPE_REG_D2H 309*004e86ffSlogin 310*004e86ffSlogin pub pm: u8, // Port multiplier, Interrupt bit: 2 311*004e86ffSlogin 312*004e86ffSlogin pub status: u8, // Status register 313*004e86ffSlogin pub error: u8, // Error register 314*004e86ffSlogin 315*004e86ffSlogin // DWORD 1 316*004e86ffSlogin pub lba0: u8, // LBA low register, 7:0 317*004e86ffSlogin pub lba1: u8, // LBA mid register, 15:8 318*004e86ffSlogin pub lba2: u8, // LBA high register, 23:16 319*004e86ffSlogin pub device: u8, // Device register 320*004e86ffSlogin 321*004e86ffSlogin // DWORD 2 322*004e86ffSlogin pub lba3: u8, // LBA register, 31:24 323*004e86ffSlogin pub lba4: u8, // LBA register, 39:32 324*004e86ffSlogin pub lba5: u8, // LBA register, 47:40 325*004e86ffSlogin pub rsv2: u8, // Reserved 326*004e86ffSlogin 327*004e86ffSlogin // DWORD 3 328*004e86ffSlogin pub countl: u8, // Count register, 7:0 329*004e86ffSlogin pub counth: u8, // Count register, 15:8 330*004e86ffSlogin pub rsv3: [u8; 2], // Reserved 331*004e86ffSlogin 332*004e86ffSlogin // DWORD 4 333*004e86ffSlogin pub rsv4: [u8; 4], // Reserved 334*004e86ffSlogin } 335*004e86ffSlogin 336*004e86ffSlogin #[repr(packed)] 337*004e86ffSlogin #[allow(dead_code)] 338*004e86ffSlogin pub struct FisData { 339*004e86ffSlogin // DWORD 0 340*004e86ffSlogin pub fis_type: u8, // FIS_TYPE_DATA 341*004e86ffSlogin 342*004e86ffSlogin pub pm: u8, // Port multiplier 343*004e86ffSlogin 344*004e86ffSlogin pub rsv1: [u8; 2], // Reserved 345*004e86ffSlogin 346*004e86ffSlogin // DWORD 1 ~ N 347*004e86ffSlogin pub data: [u8; 252], // Payload 348*004e86ffSlogin } 349*004e86ffSlogin 350*004e86ffSlogin #[repr(packed)] 351*004e86ffSlogin #[allow(dead_code)] 352*004e86ffSlogin pub struct FisPioSetup { 353*004e86ffSlogin // DWORD 0 354*004e86ffSlogin pub fis_type: u8, // FIS_TYPE_PIO_SETUP 355*004e86ffSlogin 356*004e86ffSlogin pub pm: u8, // Port multiplier, direction: 4 - device to host, interrupt: 2 357*004e86ffSlogin 358*004e86ffSlogin pub status: u8, // Status register 359*004e86ffSlogin pub error: u8, // Error register 360*004e86ffSlogin 361*004e86ffSlogin // DWORD 1 362*004e86ffSlogin pub lba0: u8, // LBA low register, 7:0 363*004e86ffSlogin pub lba1: u8, // LBA mid register, 15:8 364*004e86ffSlogin pub lba2: u8, // LBA high register, 23:16 365*004e86ffSlogin pub device: u8, // Device register 366*004e86ffSlogin 367*004e86ffSlogin // DWORD 2 368*004e86ffSlogin pub lba3: u8, // LBA register, 31:24 369*004e86ffSlogin pub lba4: u8, // LBA register, 39:32 370*004e86ffSlogin pub lba5: u8, // LBA register, 47:40 371*004e86ffSlogin pub rsv2: u8, // Reserved 372*004e86ffSlogin 373*004e86ffSlogin // DWORD 3 374*004e86ffSlogin pub countl: u8, // Count register, 7:0 375*004e86ffSlogin pub counth: u8, // Count register, 15:8 376*004e86ffSlogin pub rsv3: u8, // Reserved 377*004e86ffSlogin pub e_status: u8, // New value of status register 378*004e86ffSlogin 379*004e86ffSlogin // DWORD 4 380*004e86ffSlogin pub tc: u16, // Transfer count 381*004e86ffSlogin pub rsv4: [u8; 2], // Reserved 382*004e86ffSlogin } 383*004e86ffSlogin 384*004e86ffSlogin #[repr(packed)] 385*004e86ffSlogin #[allow(dead_code)] 386*004e86ffSlogin pub struct FisDmaSetup { 387*004e86ffSlogin // DWORD 0 388*004e86ffSlogin pub fis_type: u8, // FIS_TYPE_DMA_SETUP 389*004e86ffSlogin 390*004e86ffSlogin pub pm: u8, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1 391*004e86ffSlogin 392*004e86ffSlogin pub rsv1: [u8; 2], // Reserved 393*004e86ffSlogin 394*004e86ffSlogin // DWORD 1&2 395*004e86ffSlogin 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. */ 396*004e86ffSlogin 397*004e86ffSlogin // DWORD 3 398*004e86ffSlogin pub rsv3: u32, // More reserved 399*004e86ffSlogin 400*004e86ffSlogin // DWORD 4 401*004e86ffSlogin pub dma_buffer_offset: u32, // Byte offset into buffer. First 2 bits must be 0 402*004e86ffSlogin 403*004e86ffSlogin // DWORD 5 404*004e86ffSlogin pub transfer_count: u32, // Number of bytes to transfer. Bit 0 must be 0 405*004e86ffSlogin 406*004e86ffSlogin // DWORD 6 407*004e86ffSlogin pub rsv6: u32, // Reserved 408*004e86ffSlogin } 409