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