1/* @title: AHCI */
2#pragma once
3#include <block/block.h>
4#include <block/sched.h>
5#include <compiler/core.h>
6#include <log.h>
7#include <math/bit.h>
8#include <stdbool.h>
9#include <stdint.h>
10#include <sync/event.h>
11#include <thread/thread.h>
12
13#define AHCI_CMD_TIMEOUT_MS 5000 // Data commands (read/write)
14#define AHCI_IDENT_TIMEOUT_MS 10000 // Identify, flush cache, etc.
15#define AHCI_RESET_TIMEOUT_MS 30000 // Full controller reset or COMRESET
16
17#define AHCI_CAP 0x00 // Host Capabilities
18#define AHCI_GHC 0x04 // Global Host Control
19#define AHCI_IS 0x08 // Interrupt Status
20#define AHCI_PI 0x0C // Ports Implemented
21#define AHCI_VS 0x10 // AHCI Version
22#define AHCI_CCC_CTL 0x14 // Command Completion Coalescing Control
23#define AHCI_CCC_PORTS 0x18 // CCC Ports
24#define AHCI_EM_LOC 0x1C // Enclosure Management Location
25#define AHCI_EM_CTL 0x20 // Enclosure Management Control
26#define AHCI_CAP2 0x24 // Host Capabilities Extended
27#define AHCI_BOHC 0x28 // BIOS/OS Handoff Control and Status
28
29#define AHCI_PORT_BASE 0x100 // Base offset for port registers
30#define AHCI_PORT_SIZE 0x80 // Size of each port register set
31
32#define AHCI_MAX_PORTS 32
33#define AHCI_MAX_SLOTS 32
34
35#define AHCI_PORT_CLB 0x00 // Command List Base Address
36#define AHCI_PORT_CLBU 0x04 // Command List Base Address Upper
37#define AHCI_PORT_FB 0x08 // FIS Base Address
38#define AHCI_PORT_FBU 0x0C // FIS Base Address Upper
39#define AHCI_PORT_IS 0x10 // Interrupt Status
40#define AHCI_PORT_IE 0x14 // Interrupt Enable
41#define AHCI_PORT_CMD 0x18 // Command and Status
42#define AHCI_PORT_TFD 0x20 // Task File Data
43#define AHCI_PORT_SIG 0x24 // Signature
44#define AHCI_PORT_SSTS 0x28 // SATA Status
45#define AHCI_PORT_SCTL 0x2C // SATA Control
46#define AHCI_PORT_SERR 0x30 // SATA Error
47#define AHCI_PORT_SACT 0x34 // SATA Active
48#define AHCI_PORT_CI 0x38 // Command Issue
49#define AHCI_PORT_SNTF 0x3C // SATA Notification
50
51#define AHCI_DEV_NULL 0
52#define AHCI_DEV_SATA 1
53#define AHCI_DEV_BUSY BIT(30)
54#define AHCI_DEV_DRDY 0x40
55#define AHCI_DEV_SATAPI 2
56#define AHCI_DEV_SEMB 3
57#define AHCI_DEV_PM 4
58
59#define AHCI_CMD_TABLE_FIS_SIZE 64
60#define AHCI_CMD_TABLE_ATAPI_SIZE 16
61#define AHCI_MAX_PRDT_ENTRIES 65535
62
63#define AHCI_GHC_HR BIT(0)
64#define AHCI_GHC_AE BIT(31)
65
66#define AHCI_DET_NO_DEVICE 0x0
67#define AHCI_DET_PRESENT 0x3
68
69#define AHCI_IPM_NO_INTERFACE 0x0
70#define AHCI_IPM_ACTIVE 0x1
71
72#define AHCI_CMD_READ_DMA_EXT 0x25
73#define AHCI_CMD_WRITE_DMA_EXT 0x35
74
75#define AHCI_CMD_IDENTIFY 0xEC
76#define AHCI_CMD_ST BIT(0) // Start
77#define AHCI_CMD_SUD BIT(1) // Spin-Up Device
78#define AHCI_CMD_FRE BIT(4) // FIS Receive Enable
79#define AHCI_CMD_FR BIT(14) // FIS Receive Running
80#define AHCI_CMD_CR BIT(15) // Command List Running
81#define AHCI_CMD_CLO BIT(3) // Command List Override
82
83#define AHCI_PORT_IPM_ACTIVE 1
84#define AHCI_PORT_DET_PRESENT 3
85
86#define AHCI_CMD_FLAGS_WRITE BIT(6)
87#define AHCI_CMD_FLAGS_PRDTL 1
88
89#define FIS_TYPE_REG_H2D 0x27
90#define FIS_REG_CMD 0x80
91#define LBA_MODE 0x40
92#define CONTROL_BIT 0x80
93
94#define AHCI_CMD_FLAGS_CFL_MASK 0x1F
95#define AHCI_CMD_FLAGS_W_BIT 0x40
96
97/* NOTE: offsets and sizes in kernel/drivers/ahci/layout.c */
98struct ahci_fis_reg_h2d {
99 uint8_t fis_type; // 0x27
100 uint8_t pmport : 4;
101 uint8_t reserved1 : 3;
102 uint8_t c : 1;
103 uint8_t command;
104 uint8_t featurel;
105
106 uint8_t lba0;
107 uint8_t lba1;
108 uint8_t lba2;
109 uint8_t device;
110
111 uint8_t lba3;
112 uint8_t lba4;
113 uint8_t lba5;
114 uint8_t featureh;
115
116 uint8_t countl;
117 uint8_t counth;
118 uint8_t icc;
119 uint8_t control;
120 uint8_t reserved2[4];
121};
122
123struct ahci_fis_reg_d2h {
124 uint8_t fis_type; // FIS_TYPE_REG_D2H
125
126 uint8_t pmport : 4; // Port multiplier
127 uint8_t rsv0 : 2; // Reserved
128 uint8_t i : 1; // Interrupt bit
129 uint8_t rsv1 : 1; // Reserved
130
131 uint8_t status; // Status register
132 uint8_t error; // Error register
133
134 uint8_t lba0; // LBA low register, 7:0
135 uint8_t lba1; // LBA mid register, 15:8
136 uint8_t lba2; // LBA high register, 23:16
137 uint8_t device; // Device register
138
139 uint8_t lba3; // LBA register, 31:24
140 uint8_t lba4; // LBA register, 39:32
141 uint8_t lba5; // LBA register, 47:40
142 uint8_t rsv2; // Reserved
143
144 uint8_t countl; // Count register, 7:0
145 uint8_t counth; // Count register, 15:8
146 uint8_t rsv3[2]; // Reserved
147
148 uint8_t rsv4[4]; // Reserved
149};
150
151struct ahci_prdt_entry {
152 uint32_t dba; // Data base address
153 uint32_t dbau; // Upper 32-bits of DBA
154 uint32_t reserved;
155 uint32_t dbc : 22; // Byte count (0-based)
156 uint32_t reserved2 : 9;
157 uint32_t i : 1; // Interrupt on completion
158} cc_packed;
159
160struct ahci_cmd_table {
161 uint8_t cfis[AHCI_CMD_TABLE_FIS_SIZE]; // Command FIS (host to device)
162 uint8_t acmd[AHCI_CMD_TABLE_ATAPI_SIZE]; // ATAPI command
163 uint8_t reserved[48];
164 struct ahci_prdt_entry prdt_entry[]; // up to 65535
165} cc_packed;
166
167struct ahci_full_port {
168 struct ahci_port cc_mem_io *port;
169 void *cmd_list_base;
170 void *fis;
171 struct ahci_cmd_table **cmd_tables;
172 struct ahci_cmd_header **cmd_hdrs;
173
174 volatile atomic_uint32_t slot_bitmap;
175};
176
177struct ahci_port {
178 uint32_t clb; // Command List Base (lower 32 bits)
179 uint32_t clbu; // Command List Base (upper 32 bits)
180 uint32_t fb; // FIS Base (lower 32 bits)
181 uint32_t fbu; // FIS Base (upper 32 bits)
182 uint32_t is; // Interrupt Status
183 uint32_t ie; // Interrupt Enable
184 uint32_t cmd; // Command and Status
185 uint32_t rsv0; // Reserved
186 uint32_t tfd; // Task File Data
187 uint32_t sig; // Signature
188 uint32_t ssts; // SATA Status
189 uint32_t sctl; // SATA Control
190 uint32_t serr; // SATA Error
191 uint32_t sact; // SATA Active
192 uint32_t ci; // Command Issue
193 uint32_t sntf; // SATA Notification
194 uint32_t fbs; // FIS-based Switching
195 uint32_t rsv1[11]; // Reserved
196 uint32_t vendor[4]; // vendor specific
197};
198
199// one controller
200struct ahci_device {
201 uint8_t type; // Device type
202 uint32_t signature; // Device signature
203 uint32_t sectors; // Total sectors (for disks)
204 uint16_t sector_size; // Sector size in bytes
205 struct ahci_controller cc_mem_io *ctrl;
206 uint64_t port_count;
207
208 uint16_t io_statuses[AHCI_MAX_PORTS][32];
209
210 struct ahci_request *io_requests[AHCI_MAX_PORTS][32];
211
212 irq_t irq_num;
213 struct spinlock lock;
214 struct ahci_full_port regs[32]; // Pointer to port registers
215};
216
217// one disk
218struct ahci_disk {
219 struct ahci_device *device;
220 uint32_t port;
221 uint16_t sector_size; // Sector size in bytes
222};
223
224struct ahci_controller {
225 uint32_t cap; // Host Capabilities
226 uint32_t ghc; // Global Host Control
227 uint32_t is; // Interrupt Status
228 uint32_t pi; // Ports Implemented
229 uint32_t vs; // Version
230 uint32_t ccc_ctl; // Command Completion Coalescing Control
231 uint32_t ccc_ports; // CCC Ports
232 uint32_t em_loc; // Enclosure Management Location
233 uint32_t em_ctl; // Enclosure Management Control
234 uint32_t cap2; // Extended Host Capabilities
235 uint32_t bohc; // BIOS/OS Handoff Control
236 uint8_t rsv[0xA0 - 0x2C];
237 uint8_t vendor[0x100 - 0xA0];
238};
239
240struct ahci_cmd_header {
241 uint8_t cfl : 5; // Command FIS length in DWORDS, 2 ~ 16
242 uint8_t a : 1; // ATAPI
243 uint8_t w : 1; // Write, 1: H2D, 0: D2H
244 uint8_t p : 1; // Prefetchable
245
246 uint8_t r : 1; // Reset
247 uint8_t b : 1; // BIST
248 uint8_t c : 1; // Clear busy upon R_OK
249 uint8_t rsv0 : 1; // Reserved
250 uint8_t pmp : 4; // Port multiplier port
251
252 uint16_t prdtl; // Physical region descriptor table length in entries
253
254 uint32_t prdbc; // Physical region descriptor byte count transferred
255
256 uint32_t ctba; // Command table descriptor base address
257 uint32_t ctbau; // Command table descriptor base address upper 32 bits
258
259 uint32_t rsv1[4]; // Reserved
260} cc_packed;
261
262LOG_HANDLE_EXTERN(ahci);
263LOG_SITE_EXTERN(ahci);
264
265#define ahci_log(log_level, fmt, ...) \
266 log(LOG_SITE(ahci), LOG_HANDLE(ahci), log_level, fmt, ##__VA_ARGS__)
267
268struct ahci_request {
269 struct event evt;
270 bool has_waiter;
271 uint32_t port;
272 uint32_t slot;
273 uint64_t lba;
274 void *buffer;
275 uint64_t size;
276 uint64_t sector_count;
277 bool write;
278 bool trigger_completion;
279
280 volatile bool done;
281 int status;
282
283 void (*on_complete)(struct ahci_request *);
284 void *user_data;
285};
286
287void ahci_discover(struct ahci_controller cc_mem_io *ctrl);
288uint32_t ahci_find_slot(struct ahci_full_port *port);
289struct ahci_disk *ahci_setup_controller(struct ahci_controller cc_mem_io *ctrl,
290 uint32_t *d_cnt);
291void ahci_identify(struct ahci_disk *disk);
292void ahci_prepare_command(struct ahci_full_port *port, uint32_t slot,
293 bool write, uint8_t *buf, uint64_t size);
294void ahci_setup_fis(struct ahci_cmd_table *cmd_tbl, uint8_t command,
295 bool is_atapi);
296
297void ahci_send_command(struct ahci_disk *disk, struct ahci_full_port *port,
298 struct ahci_request *req);
299
300struct ahci_disk *ahci_discover_device(uint8_t bus, uint8_t device,
301 uint8_t function,
302 uint32_t *out_disk_count);
303
304bool ahci_write_sector(struct block_device *disk, uint64_t lba,
305 const uint8_t *in_buf, uint16_t cnt);
306bool ahci_write_sector_async(struct block_device *disk, uint64_t lba,
307 uint8_t *in_buf, uint16_t count,
308 struct ahci_request *req);
309
310bool ahci_read_sector(struct block_device *disk, uint64_t lba, uint8_t *out_buf,
311 uint16_t cnt);
312bool ahci_read_sector_async(struct block_device *disk, uint64_t lba,
313 uint8_t *buf, uint16_t count,
314 struct ahci_request *req);
315
316bool ahci_read_sector_wrapper(struct block_device *disk, uint64_t lba,
317 uint8_t *buf, uint64_t cnt);
318
319bool ahci_read_sector_async_wrapper(struct block_device *disk, uint64_t lba,
320 uint8_t *buf, uint64_t cnt,
321 struct ahci_request *req);
322
323bool ahci_write_sector_wrapper(struct block_device *disk, uint64_t lba,
324 const uint8_t *buf, uint64_t cnt);
325
326bool ahci_write_sector_async_wrapper(struct block_device *disk, uint64_t lba,
327 const uint8_t *buf, uint64_t cnt,
328 struct ahci_request *req);
329
330bool ahci_submit_bio_request(struct block_device *disk,
331 struct bio_request *bio);
332
333void ahci_do_coalesce(struct block_device *disk, struct bio_request *into,
334 struct bio_request *from);
335
336bool ahci_should_coalesce(struct block_device *disk,
337 const struct bio_request *a,
338 const struct bio_request *b);
339
340void ahci_reorder(struct block_device *disk);
341
342struct block_device *ahci_create_generic(struct ahci_disk *disk);
343enum irq_result ahci_isr_handler(struct irq_context *ictx, void *ctx);
344
345#define AHCI_PORT_OFFSET(n) (0x100 + (n) * 0x80)
346
347static inline struct ahci_port cc_mem_io *ahci_get_port(struct ahci_device *dev,
348 int n) {
349 return (struct ahci_port cc_mem_io *) ((uintptr_t) dev->ctrl +
350 AHCI_PORT_OFFSET(n));
351}
352
353void ahci_print_wrapper(struct block_device *d);
354