1 #pragma once
2 
3 #include <common/blk_types.h>
4 #include <driver/pci/pci.h>
5 #include <mm/mm.h>
6 
7 /**
8  * @todo 加入io调度器(当操作系统实现了多进程之后要加入这个)
9  *
10  */
11 #define AHCI_MAPPING_BASE SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + AHCI_MAPPING_OFFSET
12 
13 #define MAX_AHCI_DEVICES 100
14 
15 #define HBA_PxCMD_ST 0x0001
16 #define HBA_PxCMD_FRE 0x0010
17 #define HBA_PxCMD_FR 0x4000
18 #define HBA_PxCMD_CR 0x8000
19 
20 #define AHCI_DEV_BUSY 0x80
21 #define AHCI_DEV_DRQ 0x08
22 
23 #define AHCI_CMD_READ_DMA_EXT 0x25
24 #define AHCI_CMD_WRITE_DMA_EXT 0x30
25 
26 #define HBA_PxIS_TFES (1 << 30) /* TFES - Task File Error Status */
27 
28 #define AHCI_SUCCESS 0      // 请求成功
29 #define E_NOEMPTYSLOT 1     // 没有空闲的slot
30 #define E_PORT_HUNG 2       // 端口被挂起
31 #define E_TASK_FILE_ERROR 3 // 任务文件错误
32 #define E_UNSUPPORTED_CMD 4 // 不支持的命令
33 
34 extern struct block_device_operation ahci_operation;
35 
36 /**
37  * @brief 在SATA3.0规范中定义的Frame Information Structure类型
38  *
39  */
40 typedef enum
41 {
42     FIS_TYPE_REG_H2D = 0x27,   // Register FIS - host to device
43     FIS_TYPE_REG_D2H = 0x34,   // Register FIS - device to host
44     FIS_TYPE_DMA_ACT = 0x39,   // DMA activate FIS - device to host
45     FIS_TYPE_DMA_SETUP = 0x41, // DMA setup FIS - bidirectional
46     FIS_TYPE_DATA = 0x46,      // Data FIS - bidirectional
47     FIS_TYPE_BIST = 0x58,      // BIST activate FIS - bidirectional
48     FIS_TYPE_PIO_SETUP = 0x5F, // PIO setup FIS - device to host
49     FIS_TYPE_DEV_BITS = 0xA1,  // Set device bits FIS - device to host
50 } FIS_TYPE;
51 
52 /**
53  * @brief FIS_REG_H2D 被用于从主机向设备发送控制命令
54  * 注意:reserved bit应当被清零
55  */
56 typedef struct tagFIS_REG_H2D
57 {
58     // DWORD 0
59     uint8_t fis_type; // FIS_TYPE_REG_H2D
60 
61     uint8_t pmport : 4; // Port multiplier
62     uint8_t rsv0 : 3;   // Reserved
63     uint8_t c : 1;      // 1: Command, 0: Control
64 
65     uint8_t command;  // Command register
66     uint8_t featurel; // Feature register, 7:0
67 
68     // DWORD 1
69     uint8_t lba0;   // LBA low register, 7:0
70     uint8_t lba1;   // LBA mid register, 15:8
71     uint8_t lba2;   // LBA high register, 23:16
72     uint8_t device; // Device register
73 
74     // DWORD 2
75     uint8_t lba3;     // LBA register, 31:24
76     uint8_t lba4;     // LBA register, 39:32
77     uint8_t lba5;     // LBA register, 47:40
78     uint8_t featureh; // Feature register, 15:8
79 
80     // DWORD 3
81     uint8_t countl;  // Count register, 7:0
82     uint8_t counth;  // Count register, 15:8
83     uint8_t icc;     // Isochronous command completion
84     uint8_t control; // Control register
85 
86     // DWORD 4
87     uint8_t rsv1[4]; // Reserved
88 } FIS_REG_H2D;
89 
90 // A device to host register FIS is used by the device to notify the host that some ATA register has changed.
91 // It contains the updated task files such as status, error and other registers.
92 typedef struct tagFIS_REG_D2H
93 {
94     // DWORD 0
95     uint8_t fis_type; // FIS_TYPE_REG_D2H
96 
97     uint8_t pmport : 4; // Port multiplier
98     uint8_t rsv0 : 2;   // Reserved
99     uint8_t i : 1;      // Interrupt bit
100     uint8_t rsv1 : 1;   // Reserved
101 
102     uint8_t status; // Status register
103     uint8_t error;  // Error register
104 
105     // DWORD 1
106     uint8_t lba0;   // LBA low register, 7:0
107     uint8_t lba1;   // LBA mid register, 15:8
108     uint8_t lba2;   // LBA high register, 23:16
109     uint8_t device; // Device register
110 
111     // DWORD 2
112     uint8_t lba3; // LBA register, 31:24
113     uint8_t lba4; // LBA register, 39:32
114     uint8_t lba5; // LBA register, 47:40
115     uint8_t rsv2; // Reserved
116 
117     // DWORD 3
118     uint8_t countl;  // Count register, 7:0
119     uint8_t counth;  // Count register, 15:8
120     uint8_t rsv3[2]; // Reserved
121 
122     // DWORD 4
123     uint8_t rsv4[4]; // Reserved
124 } FIS_REG_D2H;
125 
126 // This FIS is used by the host or device to send data payload. The data size can be varied.
127 typedef struct tagFIS_DATA
128 {
129     // DWORD 0
130     uint8_t fis_type; // FIS_TYPE_DATA
131 
132     uint8_t pmport : 4; // Port multiplier
133     uint8_t rsv0 : 4;   // Reserved
134 
135     uint8_t rsv1[2]; // Reserved
136 
137     // DWORD 1 ~ N
138     uint32_t data[1]; // Payload
139 } FIS_DATA;
140 
141 // This FIS is used by the device to tell the host that it’s about to send or ready to receive a PIO data payload.
142 typedef struct tagFIS_PIO_SETUP
143 {
144     // DWORD 0
145     uint8_t fis_type; // FIS_TYPE_PIO_SETUP
146 
147     uint8_t pmport : 4; // Port multiplier
148     uint8_t rsv0 : 1;   // Reserved
149     uint8_t d : 1;      // Data transfer direction, 1 - device to host
150     uint8_t i : 1;      // Interrupt bit
151     uint8_t rsv1 : 1;
152 
153     uint8_t status; // Status register
154     uint8_t error;  // Error register
155 
156     // DWORD 1
157     uint8_t lba0;   // LBA low register, 7:0
158     uint8_t lba1;   // LBA mid register, 15:8
159     uint8_t lba2;   // LBA high register, 23:16
160     uint8_t device; // Device register
161 
162     // DWORD 2
163     uint8_t lba3; // LBA register, 31:24
164     uint8_t lba4; // LBA register, 39:32
165     uint8_t lba5; // LBA register, 47:40
166     uint8_t rsv2; // Reserved
167 
168     // DWORD 3
169     uint8_t countl;   // Count register, 7:0
170     uint8_t counth;   // Count register, 15:8
171     uint8_t rsv3;     // Reserved
172     uint8_t e_status; // New value of status register
173 
174     // DWORD 4
175     uint16_t tc;     // Transfer count
176     uint8_t rsv4[2]; // Reserved
177 } FIS_PIO_SETUP;
178 
179 typedef struct tagFIS_DMA_SETUP
180 {
181     // DWORD 0
182     uint8_t fis_type; // FIS_TYPE_DMA_SETUP
183 
184     uint8_t pmport : 4; // Port multiplier
185     uint8_t rsv0 : 1;   // Reserved
186     uint8_t d : 1;      // Data transfer direction, 1 - device to host
187     uint8_t i : 1;      // Interrupt bit
188     uint8_t a : 1;      // Auto-activate. Specifies if DMA Activate FIS is needed
189 
190     uint8_t rsved[2]; // Reserved
191 
192     // DWORD 1&2
193 
194     uint64_t DMAbufferID; // DMA Buffer Identifier. Used to Identify DMA buffer in host memory.
195                           // SATA Spec says host specific and not in Spec. Trying AHCI spec might work.
196 
197     // DWORD 3
198     uint32_t rsvd; // More reserved
199 
200     // DWORD 4
201     uint32_t DMAbufOffset; // Byte offset into buffer. First 2 bits must be 0
202 
203     // DWORD 5
204     uint32_t TransferCount; // Number of bytes to transfer. Bit 0 must be 0
205 
206     // DWORD 6
207     uint32_t resvd; // Reserved
208 
209 } FIS_DMA_SETUP;
210 
211 typedef volatile struct tagHBA_PORT
212 {
213     uint64_t clb;       // 0x00, command list base address, 1K-byte aligned
214     uint64_t fb;        // 0x08, FIS base address, 256-byte aligned
215     uint32_t is;        // 0x10, interrupt status
216     uint32_t ie;        // 0x14, interrupt enable
217     uint32_t cmd;       // 0x18, command and status
218     uint32_t rsv0;      // 0x1C, Reserved
219     uint32_t tfd;       // 0x20, task file data
220     uint32_t sig;       // 0x24, signature
221     uint32_t ssts;      // 0x28, SATA status (SCR0:SStatus)
222     uint32_t sctl;      // 0x2C, SATA control (SCR2:SControl)
223     uint32_t serr;      // 0x30, SATA error (SCR1:SError)
224     uint32_t sact;      // 0x34, SATA active (SCR3:SActive)
225     uint32_t ci;        // 0x38, command issue
226     uint32_t sntf;      // 0x3C, SATA notification (SCR4:SNotification)
227     uint32_t fbs;       // 0x40, FIS-based switch control
228     uint32_t rsv1[11];  // 0x44 ~ 0x6F, Reserved
229     uint32_t vendor[4]; // 0x70 ~ 0x7F, vendor specific
230 } HBA_PORT;
231 typedef volatile struct tagHBA_MEM
232 {
233     // 0x00 - 0x2B, Generic Host Control
234     uint32_t cap;     // 0x00, Host capability
235     uint32_t ghc;     // 0x04, Global host control
236     uint32_t is;      // 0x08, Interrupt status
237     uint32_t pi;      // 0x0C, Port implemented
238     uint32_t vs;      // 0x10, Version
239     uint32_t ccc_ctl; // 0x14, Command completion coalescing control
240     uint32_t ccc_pts; // 0x18, Command completion coalescing ports
241     uint32_t em_loc;  // 0x1C, Enclosure management location
242     uint32_t em_ctl;  // 0x20, Enclosure management control
243     uint32_t cap2;    // 0x24, Host capabilities extended
244     uint32_t bohc;    // 0x28, BIOS/OS handoff control and status
245 
246     // 0x2C - 0x9F, Reserved
247     uint8_t rsv[0xA0 - 0x2C];
248 
249     // 0xA0 - 0xFF, Vendor specific registers
250     uint8_t vendor[0x100 - 0xA0];
251 
252     // 0x100 - 0x10FF, Port control registers
253     HBA_PORT ports[32]; // 1 ~ 32
254 } HBA_MEM;
255 
256 // There are four kinds of FIS which may be sent to the host by the device as indicated in the following structure declaration.
257 //
258 typedef volatile struct tagHBA_FIS
259 {
260     // 0x00
261     FIS_DMA_SETUP dsfis; // DMA Setup FIS
262     uint8_t pad0[4];
263 
264     // 0x20
265     FIS_PIO_SETUP psfis; // PIO Setup FIS
266     uint8_t pad1[12];
267 
268     // 0x40
269     FIS_REG_D2H rfis; // Register – Device to Host FIS
270     uint8_t pad2[4];
271 
272     // 0x58
273     // FIS_DEV_BITS	sdbfis;		// Set Device Bit FIS
274 
275     // 0x60
276     uint8_t ufis[64];
277 
278     // 0xA0
279     uint8_t rsv[0x100 - 0xA0];
280 } HBA_FIS;
281 
282 typedef struct tagHBA_CMD_HEADER
283 {
284     // DW0
285     uint8_t cfl : 5; // Command FIS length in DWORDS, 2 ~ 16
286     uint8_t a : 1;   // ATAPI
287     uint8_t w : 1;   // Write, 1: H2D, 0: D2H
288     uint8_t p : 1;   // Prefetchable
289 
290     uint8_t r : 1;    // Reset
291     uint8_t b : 1;    // BIST
292     uint8_t c : 1;    // Clear busy upon R_OK
293     uint8_t rsv0 : 1; // Reserved
294     uint8_t pmp : 4;  // Port multiplier port
295 
296     uint16_t prdtl; // Physical region descriptor table length in entries
297 
298     // DW1
299     volatile uint32_t prdbc; // Physical region descriptor byte count transferred
300 
301     // DW2, 3
302     uint64_t ctba; // Command table descriptor base address
303 
304     // DW4 - 7
305     uint32_t rsv1[4]; // Reserved
306 } HBA_CMD_HEADER;
307 
308 typedef struct tagHBA_PRDT_ENTRY
309 {
310     uint64_t dba;  // Data base address
311     uint32_t rsv0; // Reserved
312 
313     // DW3
314     uint32_t dbc : 22; // Byte count, 4M max
315     uint32_t rsv1 : 9; // Reserved
316     uint32_t i : 1;    // Interrupt on completion
317 } HBA_PRDT_ENTRY;
318 
319 typedef struct tagHBA_CMD_TBL
320 {
321     // 0x00
322     uint8_t cfis[64]; // Command FIS
323 
324     // 0x40
325     uint8_t acmd[16]; // ATAPI command, 12 or 16 bytes
326 
327     // 0x50
328     uint8_t rsv[48]; // Reserved
329 
330     // 0x80
331     HBA_PRDT_ENTRY prdt_entry[1]; // Physical region descriptor table entries, 0 ~ 65535
332 } HBA_CMD_TBL;
333 
334 struct ahci_device_t
335 {
336     uint32_t type; // 设备类型
337     struct pci_device_structure_header_t *dev_struct;
338     HBA_MEM *hba_mem;
339 } ahci_devices[MAX_AHCI_DEVICES];
340 
341 #define SATA_SIG_ATA 0x00000101   // SATA drive
342 #define SATA_SIG_ATAPI 0xEB140101 // SATAPI drive
343 #define SATA_SIG_SEMB 0xC33C0101  // Enclosure management bridge
344 #define SATA_SIG_PM 0x96690101    // Port multiplier
345 
346 #define AHCI_DEV_NULL 0
347 #define AHCI_DEV_SATA 1
348 #define AHCI_DEV_SEMB 2
349 #define AHCI_DEV_PM 3
350 #define AHCI_DEV_SATAPI 4
351 
352 #define HBA_PORT_IPM_ACTIVE 1
353 #define HBA_PORT_DET_PRESENT 3
354 
355 struct ahci_request_packet_t
356 {
357     struct block_device_request_packet blk_pak; // 块设备请求包
358     uint8_t ahci_ctrl_num;                      // ahci控制器号, 默认应为0
359     uint8_t port_num;                           // ahci的设备端口号
360 };
361 
362 /**
363  * @brief 初始化ahci模块
364  *
365  */
366 void ahci_init();
367 
368 /**
369  * @brief 检测端口连接的设备的类型
370  *
371  * @param device_num ahci设备号
372  */
373 static void ahci_probe_port(const uint32_t device_num);
374 
375 /**
376  * @brief read data from SATA device using 48bit LBA address
377  *
378  * @param port HBA PORT
379  * @param startl low 32bits of start addr
380  * @param starth high 32bits of start addr
381  * @param count total sectors to read
382  * @param buf buffer
383  * @return true done
384  * @return false failed
385  */
386 static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf);
387 
388 /**
389  * @brief write data to SATA device using 48bit LBA address
390  *
391  * @param port HBA PORT
392  * @param startl low 32bits of start addr
393  * @param starth high 32bits of start addr
394  * @param count total sectors to read
395  * @param buf buffer
396  * @return true done
397  * @return false failed
398  */
399 static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count,
400                        uint64_t buf);
401 
402 void ahci_end_request();