xref: /DragonOS/kernel/src/driver/disk/ahci/hba.rs (revision 816ee5ae545b60612055c939351911d6cf601c2e)
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