]>
Commit | Line | Data |
---|---|---|
2a6a4076 MA |
1 | #ifndef LIBQOS_AHCI_H |
2 | #define LIBQOS_AHCI_H | |
90fc5e09 JS |
3 | |
4 | /* | |
5 | * AHCI qtest library functions and definitions | |
6 | * | |
7 | * Copyright (c) 2014 John Snow <[email protected]> | |
8 | * | |
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
10 | * of this software and associated documentation files (the "Software"), to deal | |
11 | * in the Software without restriction, including without limitation the rights | |
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
13 | * copies of the Software, and to permit persons to whom the Software is | |
14 | * furnished to do so, subject to the following conditions: | |
15 | * | |
16 | * The above copyright notice and this permission notice shall be included in | |
17 | * all copies or substantial portions of the Software. | |
18 | * | |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
25 | * THE SOFTWARE. | |
26 | */ | |
27 | ||
9a75b0a0 | 28 | #include "libqos/libqos.h" |
90fc5e09 JS |
29 | #include "libqos/pci.h" |
30 | #include "libqos/malloc-pc.h" | |
31 | ||
32 | /*** Supplementary PCI Config Space IDs & Masks ***/ | |
33 | #define PCI_DEVICE_ID_INTEL_Q35_AHCI (0x2922) | |
34 | #define PCI_MSI_FLAGS_RESERVED (0xFF00) | |
35 | #define PCI_PM_CTRL_RESERVED (0xFC) | |
36 | #define PCI_BCC(REG32) ((REG32) >> 24) | |
37 | #define PCI_PI(REG32) (((REG32) >> 8) & 0xFF) | |
38 | #define PCI_SCC(REG32) (((REG32) >> 16) & 0xFF) | |
39 | ||
40 | /*** Recognized AHCI Device Types ***/ | |
41 | #define AHCI_INTEL_ICH9 (PCI_DEVICE_ID_INTEL_Q35_AHCI << 16 | \ | |
42 | PCI_VENDOR_ID_INTEL) | |
43 | ||
44 | /*** AHCI/HBA Register Offsets and Bitmasks ***/ | |
45 | #define AHCI_CAP (0) | |
46 | #define AHCI_CAP_NP (0x1F) | |
47 | #define AHCI_CAP_SXS (0x20) | |
48 | #define AHCI_CAP_EMS (0x40) | |
49 | #define AHCI_CAP_CCCS (0x80) | |
50 | #define AHCI_CAP_NCS (0x1F00) | |
51 | #define AHCI_CAP_PSC (0x2000) | |
52 | #define AHCI_CAP_SSC (0x4000) | |
53 | #define AHCI_CAP_PMD (0x8000) | |
54 | #define AHCI_CAP_FBSS (0x10000) | |
55 | #define AHCI_CAP_SPM (0x20000) | |
56 | #define AHCI_CAP_SAM (0x40000) | |
57 | #define AHCI_CAP_RESERVED (0x80000) | |
58 | #define AHCI_CAP_ISS (0xF00000) | |
59 | #define AHCI_CAP_SCLO (0x1000000) | |
60 | #define AHCI_CAP_SAL (0x2000000) | |
61 | #define AHCI_CAP_SALP (0x4000000) | |
62 | #define AHCI_CAP_SSS (0x8000000) | |
63 | #define AHCI_CAP_SMPS (0x10000000) | |
64 | #define AHCI_CAP_SSNTF (0x20000000) | |
65 | #define AHCI_CAP_SNCQ (0x40000000) | |
66 | #define AHCI_CAP_S64A (0x80000000) | |
67 | ||
68 | #define AHCI_GHC (1) | |
69 | #define AHCI_GHC_HR (0x01) | |
70 | #define AHCI_GHC_IE (0x02) | |
71 | #define AHCI_GHC_MRSM (0x04) | |
72 | #define AHCI_GHC_RESERVED (0x7FFFFFF8) | |
73 | #define AHCI_GHC_AE (0x80000000) | |
74 | ||
75 | #define AHCI_IS (2) | |
76 | #define AHCI_PI (3) | |
77 | #define AHCI_VS (4) | |
78 | ||
79 | #define AHCI_CCCCTL (5) | |
80 | #define AHCI_CCCCTL_EN (0x01) | |
81 | #define AHCI_CCCCTL_RESERVED (0x06) | |
82 | #define AHCI_CCCCTL_CC (0xFF00) | |
83 | #define AHCI_CCCCTL_TV (0xFFFF0000) | |
84 | ||
85 | #define AHCI_CCCPORTS (6) | |
86 | #define AHCI_EMLOC (7) | |
87 | ||
88 | #define AHCI_EMCTL (8) | |
89 | #define AHCI_EMCTL_STSMR (0x01) | |
90 | #define AHCI_EMCTL_CTLTM (0x100) | |
91 | #define AHCI_EMCTL_CTLRST (0x200) | |
92 | #define AHCI_EMCTL_RESERVED (0xF0F0FCFE) | |
93 | ||
94 | #define AHCI_CAP2 (9) | |
95 | #define AHCI_CAP2_BOH (0x01) | |
96 | #define AHCI_CAP2_NVMP (0x02) | |
97 | #define AHCI_CAP2_APST (0x04) | |
98 | #define AHCI_CAP2_RESERVED (0xFFFFFFF8) | |
99 | ||
100 | #define AHCI_BOHC (10) | |
101 | #define AHCI_RESERVED (11) | |
102 | #define AHCI_NVMHCI (24) | |
103 | #define AHCI_VENDOR (40) | |
104 | #define AHCI_PORTS (64) | |
105 | ||
106 | /*** Port Memory Offsets & Bitmasks ***/ | |
107 | #define AHCI_PX_CLB (0) | |
108 | #define AHCI_PX_CLB_RESERVED (0x1FF) | |
109 | ||
110 | #define AHCI_PX_CLBU (1) | |
111 | ||
112 | #define AHCI_PX_FB (2) | |
113 | #define AHCI_PX_FB_RESERVED (0xFF) | |
114 | ||
115 | #define AHCI_PX_FBU (3) | |
116 | ||
117 | #define AHCI_PX_IS (4) | |
118 | #define AHCI_PX_IS_DHRS (0x1) | |
119 | #define AHCI_PX_IS_PSS (0x2) | |
120 | #define AHCI_PX_IS_DSS (0x4) | |
121 | #define AHCI_PX_IS_SDBS (0x8) | |
122 | #define AHCI_PX_IS_UFS (0x10) | |
123 | #define AHCI_PX_IS_DPS (0x20) | |
124 | #define AHCI_PX_IS_PCS (0x40) | |
125 | #define AHCI_PX_IS_DMPS (0x80) | |
126 | #define AHCI_PX_IS_RESERVED (0x23FFF00) | |
127 | #define AHCI_PX_IS_PRCS (0x400000) | |
128 | #define AHCI_PX_IS_IPMS (0x800000) | |
129 | #define AHCI_PX_IS_OFS (0x1000000) | |
130 | #define AHCI_PX_IS_INFS (0x4000000) | |
131 | #define AHCI_PX_IS_IFS (0x8000000) | |
132 | #define AHCI_PX_IS_HBDS (0x10000000) | |
133 | #define AHCI_PX_IS_HBFS (0x20000000) | |
134 | #define AHCI_PX_IS_TFES (0x40000000) | |
135 | #define AHCI_PX_IS_CPDS (0x80000000) | |
136 | ||
137 | #define AHCI_PX_IE (5) | |
138 | #define AHCI_PX_IE_DHRE (0x1) | |
139 | #define AHCI_PX_IE_PSE (0x2) | |
140 | #define AHCI_PX_IE_DSE (0x4) | |
141 | #define AHCI_PX_IE_SDBE (0x8) | |
142 | #define AHCI_PX_IE_UFE (0x10) | |
143 | #define AHCI_PX_IE_DPE (0x20) | |
144 | #define AHCI_PX_IE_PCE (0x40) | |
145 | #define AHCI_PX_IE_DMPE (0x80) | |
146 | #define AHCI_PX_IE_RESERVED (0x23FFF00) | |
147 | #define AHCI_PX_IE_PRCE (0x400000) | |
148 | #define AHCI_PX_IE_IPME (0x800000) | |
149 | #define AHCI_PX_IE_OFE (0x1000000) | |
150 | #define AHCI_PX_IE_INFE (0x4000000) | |
151 | #define AHCI_PX_IE_IFE (0x8000000) | |
152 | #define AHCI_PX_IE_HBDE (0x10000000) | |
153 | #define AHCI_PX_IE_HBFE (0x20000000) | |
154 | #define AHCI_PX_IE_TFEE (0x40000000) | |
155 | #define AHCI_PX_IE_CPDE (0x80000000) | |
156 | ||
157 | #define AHCI_PX_CMD (6) | |
158 | #define AHCI_PX_CMD_ST (0x1) | |
159 | #define AHCI_PX_CMD_SUD (0x2) | |
160 | #define AHCI_PX_CMD_POD (0x4) | |
161 | #define AHCI_PX_CMD_CLO (0x8) | |
162 | #define AHCI_PX_CMD_FRE (0x10) | |
163 | #define AHCI_PX_CMD_RESERVED (0xE0) | |
164 | #define AHCI_PX_CMD_CCS (0x1F00) | |
165 | #define AHCI_PX_CMD_MPSS (0x2000) | |
166 | #define AHCI_PX_CMD_FR (0x4000) | |
167 | #define AHCI_PX_CMD_CR (0x8000) | |
168 | #define AHCI_PX_CMD_CPS (0x10000) | |
169 | #define AHCI_PX_CMD_PMA (0x20000) | |
170 | #define AHCI_PX_CMD_HPCP (0x40000) | |
171 | #define AHCI_PX_CMD_MPSP (0x80000) | |
172 | #define AHCI_PX_CMD_CPD (0x100000) | |
173 | #define AHCI_PX_CMD_ESP (0x200000) | |
174 | #define AHCI_PX_CMD_FBSCP (0x400000) | |
175 | #define AHCI_PX_CMD_APSTE (0x800000) | |
176 | #define AHCI_PX_CMD_ATAPI (0x1000000) | |
177 | #define AHCI_PX_CMD_DLAE (0x2000000) | |
178 | #define AHCI_PX_CMD_ALPE (0x4000000) | |
179 | #define AHCI_PX_CMD_ASP (0x8000000) | |
180 | #define AHCI_PX_CMD_ICC (0xF0000000) | |
181 | ||
182 | #define AHCI_PX_RES1 (7) | |
183 | ||
184 | #define AHCI_PX_TFD (8) | |
185 | #define AHCI_PX_TFD_STS (0xFF) | |
186 | #define AHCI_PX_TFD_STS_ERR (0x01) | |
187 | #define AHCI_PX_TFD_STS_CS1 (0x06) | |
188 | #define AHCI_PX_TFD_STS_DRQ (0x08) | |
189 | #define AHCI_PX_TFD_STS_CS2 (0x70) | |
190 | #define AHCI_PX_TFD_STS_BSY (0x80) | |
191 | #define AHCI_PX_TFD_ERR (0xFF00) | |
192 | #define AHCI_PX_TFD_RESERVED (0xFFFF0000) | |
193 | ||
194 | #define AHCI_PX_SIG (9) | |
195 | #define AHCI_PX_SIG_SECTOR_COUNT (0xFF) | |
196 | #define AHCI_PX_SIG_LBA_LOW (0xFF00) | |
197 | #define AHCI_PX_SIG_LBA_MID (0xFF0000) | |
198 | #define AHCI_PX_SIG_LBA_HIGH (0xFF000000) | |
199 | ||
200 | #define AHCI_PX_SSTS (10) | |
201 | #define AHCI_PX_SSTS_DET (0x0F) | |
202 | #define AHCI_PX_SSTS_SPD (0xF0) | |
203 | #define AHCI_PX_SSTS_IPM (0xF00) | |
204 | #define AHCI_PX_SSTS_RESERVED (0xFFFFF000) | |
205 | #define SSTS_DET_NO_DEVICE (0x00) | |
206 | #define SSTS_DET_PRESENT (0x01) | |
207 | #define SSTS_DET_ESTABLISHED (0x03) | |
208 | #define SSTS_DET_OFFLINE (0x04) | |
209 | ||
210 | #define AHCI_PX_SCTL (11) | |
211 | ||
212 | #define AHCI_PX_SERR (12) | |
213 | #define AHCI_PX_SERR_ERR (0xFFFF) | |
214 | #define AHCI_PX_SERR_DIAG (0xFFFF0000) | |
215 | #define AHCI_PX_SERR_DIAG_X (0x04000000) | |
216 | ||
217 | #define AHCI_PX_SACT (13) | |
218 | #define AHCI_PX_CI (14) | |
219 | #define AHCI_PX_SNTF (15) | |
220 | ||
221 | #define AHCI_PX_FBS (16) | |
222 | #define AHCI_PX_FBS_EN (0x1) | |
223 | #define AHCI_PX_FBS_DEC (0x2) | |
224 | #define AHCI_PX_FBS_SDE (0x4) | |
225 | #define AHCI_PX_FBS_DEV (0xF00) | |
226 | #define AHCI_PX_FBS_ADO (0xF000) | |
227 | #define AHCI_PX_FBS_DWE (0xF0000) | |
228 | #define AHCI_PX_FBS_RESERVED (0xFFF000F8) | |
229 | ||
230 | #define AHCI_PX_RES2 (17) | |
231 | #define AHCI_PX_VS (28) | |
232 | ||
233 | #define HBA_DATA_REGION_SIZE (256) | |
234 | #define HBA_PORT_DATA_SIZE (128) | |
235 | #define HBA_PORT_NUM_REG (HBA_PORT_DATA_SIZE/4) | |
236 | ||
237 | #define AHCI_VERSION_0_95 (0x00000905) | |
238 | #define AHCI_VERSION_1_0 (0x00010000) | |
239 | #define AHCI_VERSION_1_1 (0x00010100) | |
240 | #define AHCI_VERSION_1_2 (0x00010200) | |
241 | #define AHCI_VERSION_1_3 (0x00010300) | |
242 | ||
36e36726 | 243 | #define AHCI_SECTOR_SIZE (512) |
54d268b2 JS |
244 | #define ATAPI_SECTOR_SIZE (2048) |
245 | ||
246 | #define AHCI_SIGNATURE_CDROM (0xeb140101) | |
247 | #define AHCI_SIGNATURE_DISK (0x00000101) | |
36e36726 JS |
248 | |
249 | /* FIS types */ | |
250 | enum { | |
251 | REG_H2D_FIS = 0x27, | |
252 | REG_D2H_FIS = 0x34, | |
253 | DMA_ACTIVATE_FIS = 0x39, | |
254 | DMA_SETUP_FIS = 0x41, | |
255 | DATA_FIS = 0x46, | |
256 | BIST_ACTIVATE_FIS = 0x58, | |
257 | PIO_SETUP_FIS = 0x5F, | |
258 | SDB_FIS = 0xA1 | |
259 | }; | |
260 | ||
261 | /* FIS flags */ | |
262 | #define REG_H2D_FIS_CMD 0x80 | |
263 | ||
264 | /* ATA Commands */ | |
265 | enum { | |
266 | /* DMA */ | |
26ad0045 JS |
267 | CMD_READ_DMA = 0xC8, |
268 | CMD_READ_DMA_EXT = 0x25, | |
269 | CMD_WRITE_DMA = 0xCA, | |
270 | CMD_WRITE_DMA_EXT = 0x35, | |
36e36726 | 271 | /* PIO */ |
26ad0045 JS |
272 | CMD_READ_PIO = 0x20, |
273 | CMD_READ_PIO_EXT = 0x24, | |
274 | CMD_WRITE_PIO = 0x30, | |
275 | CMD_WRITE_PIO_EXT = 0x34, | |
36e36726 | 276 | /* Misc */ |
26ad0045 JS |
277 | CMD_READ_MAX = 0xF8, |
278 | CMD_READ_MAX_EXT = 0x27, | |
279 | CMD_FLUSH_CACHE = 0xE7, | |
280 | CMD_IDENTIFY = 0xEC, | |
54d268b2 JS |
281 | CMD_PACKET = 0xA0, |
282 | CMD_PACKET_ID = 0xA1, | |
26ad0045 JS |
283 | /* NCQ */ |
284 | READ_FPDMA_QUEUED = 0x60, | |
285 | WRITE_FPDMA_QUEUED = 0x61, | |
36e36726 JS |
286 | }; |
287 | ||
54d268b2 JS |
288 | /* ATAPI Commands */ |
289 | enum { | |
290 | CMD_ATAPI_READ_10 = 0x28, | |
291 | }; | |
292 | ||
36e36726 JS |
293 | /* AHCI Command Header Flags & Masks*/ |
294 | #define CMDH_CFL (0x1F) | |
295 | #define CMDH_ATAPI (0x20) | |
296 | #define CMDH_WRITE (0x40) | |
297 | #define CMDH_PREFETCH (0x80) | |
298 | #define CMDH_RESET (0x100) | |
299 | #define CMDH_BIST (0x200) | |
300 | #define CMDH_CLR_BSY (0x400) | |
301 | #define CMDH_RES (0x800) | |
302 | #define CMDH_PMP (0xF000) | |
303 | ||
304 | /* ATA device register masks */ | |
cb453041 | 305 | #define ATA_DEVICE_MAGIC 0xA0 /* used in ata1-3 */ |
36e36726 | 306 | #define ATA_DEVICE_LBA 0x40 |
cb453041 | 307 | #define NCQ_DEVICE_MAGIC 0x40 /* for ncq device registers */ |
36e36726 JS |
308 | #define ATA_DEVICE_DRIVE 0x10 |
309 | #define ATA_DEVICE_HEAD 0x0F | |
310 | ||
90fc5e09 JS |
311 | /*** Structures ***/ |
312 | ||
f3dd2da4 JS |
313 | typedef struct AHCIPortQState { |
314 | uint64_t fb; | |
315 | uint64_t clb; | |
6cae27a6 JS |
316 | uint64_t ctba[32]; |
317 | uint16_t prdtl[32]; | |
318 | uint8_t next; /** Next Command Slot to Use **/ | |
f3dd2da4 JS |
319 | } AHCIPortQState; |
320 | ||
dd0029c0 JS |
321 | typedef struct AHCIQState { |
322 | QOSState *parent; | |
323 | QPCIDevice *dev; | |
b4ba67d9 | 324 | QPCIBar hba_bar; |
8d5eeced JS |
325 | uint64_t barsize; |
326 | uint32_t fingerprint; | |
327 | uint32_t cap; | |
328 | uint32_t cap2; | |
f3dd2da4 | 329 | AHCIPortQState port[32]; |
e7c8526b | 330 | bool enabled; |
dd0029c0 JS |
331 | } AHCIQState; |
332 | ||
90fc5e09 JS |
333 | /** |
334 | * Generic FIS structure. | |
335 | */ | |
336 | typedef struct FIS { | |
337 | uint8_t fis_type; | |
338 | uint8_t flags; | |
339 | char data[0]; | |
340 | } __attribute__((__packed__)) FIS; | |
341 | ||
342 | /** | |
343 | * Register device-to-host FIS structure. | |
344 | */ | |
345 | typedef struct RegD2HFIS { | |
346 | /* DW0 */ | |
347 | uint8_t fis_type; | |
348 | uint8_t flags; | |
349 | uint8_t status; | |
350 | uint8_t error; | |
351 | /* DW1 */ | |
d1ef8838 | 352 | uint8_t lba_lo[3]; |
90fc5e09 JS |
353 | uint8_t device; |
354 | /* DW2 */ | |
d1ef8838 JS |
355 | uint8_t lba_hi[3]; |
356 | uint8_t res0; | |
90fc5e09 JS |
357 | /* DW3 */ |
358 | uint16_t count; | |
d1ef8838 | 359 | uint16_t res1; |
90fc5e09 | 360 | /* DW4 */ |
d1ef8838 | 361 | uint32_t res2; |
90fc5e09 JS |
362 | } __attribute__((__packed__)) RegD2HFIS; |
363 | ||
d1ef8838 JS |
364 | /** |
365 | * Register device-to-host FIS structure; | |
366 | * PIO Setup variety. | |
367 | */ | |
368 | typedef struct PIOSetupFIS { | |
369 | /* DW0 */ | |
370 | uint8_t fis_type; | |
371 | uint8_t flags; | |
372 | uint8_t status; | |
373 | uint8_t error; | |
374 | /* DW1 */ | |
375 | uint8_t lba_lo[3]; | |
376 | uint8_t device; | |
377 | /* DW2 */ | |
378 | uint8_t lba_hi[3]; | |
379 | uint8_t res0; | |
380 | /* DW3 */ | |
381 | uint16_t count; | |
382 | uint8_t res1; | |
383 | uint8_t e_status; | |
384 | /* DW4 */ | |
385 | uint16_t tx_count; | |
386 | uint16_t res2; | |
387 | } __attribute__((__packed__)) PIOSetupFIS; | |
388 | ||
90fc5e09 JS |
389 | /** |
390 | * Register host-to-device FIS structure. | |
391 | */ | |
392 | typedef struct RegH2DFIS { | |
393 | /* DW0 */ | |
394 | uint8_t fis_type; | |
395 | uint8_t flags; | |
396 | uint8_t command; | |
397 | uint8_t feature_low; | |
398 | /* DW1 */ | |
d1ef8838 | 399 | uint8_t lba_lo[3]; |
90fc5e09 JS |
400 | uint8_t device; |
401 | /* DW2 */ | |
d1ef8838 | 402 | uint8_t lba_hi[3]; |
90fc5e09 JS |
403 | uint8_t feature_high; |
404 | /* DW3 */ | |
405 | uint16_t count; | |
406 | uint8_t icc; | |
407 | uint8_t control; | |
408 | /* DW4 */ | |
52515766 | 409 | uint8_t aux[4]; |
90fc5e09 JS |
410 | } __attribute__((__packed__)) RegH2DFIS; |
411 | ||
cb453041 JS |
412 | /** |
413 | * Register host-to-device FIS structure, for NCQ commands. | |
414 | * Actually just a RegH2DFIS, but with fields repurposed. | |
415 | * Repurposed fields are annotated below. | |
416 | */ | |
417 | typedef struct NCQFIS { | |
418 | /* DW0 */ | |
419 | uint8_t fis_type; | |
420 | uint8_t flags; | |
421 | uint8_t command; | |
422 | uint8_t sector_low; /* H2D: Feature 7:0 */ | |
423 | /* DW1 */ | |
424 | uint8_t lba_lo[3]; | |
425 | uint8_t device; | |
426 | /* DW2 */ | |
427 | uint8_t lba_hi[3]; | |
428 | uint8_t sector_hi; /* H2D: Feature 15:8 */ | |
429 | /* DW3 */ | |
430 | uint8_t tag; /* H2D: Count 0:7 */ | |
431 | uint8_t prio; /* H2D: Count 15:8 */ | |
432 | uint8_t icc; | |
433 | uint8_t control; | |
434 | /* DW4 */ | |
435 | uint8_t aux[4]; | |
436 | } __attribute__((__packed__)) NCQFIS; | |
437 | ||
90fc5e09 JS |
438 | /** |
439 | * Command List entry structure. | |
440 | * The command list contains between 1-32 of these structures. | |
441 | */ | |
c7f9c570 JS |
442 | typedef struct AHCICommandHeader { |
443 | uint16_t flags; /* Cmd-Fis-Len, PMP#, and flags. */ | |
90fc5e09 JS |
444 | uint16_t prdtl; /* Phys Region Desc. Table Length */ |
445 | uint32_t prdbc; /* Phys Region Desc. Byte Count */ | |
6cae27a6 | 446 | uint64_t ctba; /* Command Table Descriptor Base Address */ |
90fc5e09 | 447 | uint32_t res[4]; |
c7f9c570 | 448 | } __attribute__((__packed__)) AHCICommandHeader; |
90fc5e09 JS |
449 | |
450 | /** | |
451 | * Physical Region Descriptor; pointed to by the Command List Header, | |
452 | * struct ahci_command. | |
453 | */ | |
454 | typedef struct PRD { | |
6cae27a6 | 455 | uint64_t dba; /* Data Base Address */ |
90fc5e09 JS |
456 | uint32_t res; /* Reserved */ |
457 | uint32_t dbc; /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */ | |
6cae27a6 | 458 | } __attribute__((__packed__)) PRD; |
90fc5e09 | 459 | |
64a5a272 JS |
460 | /* Opaque, defined within ahci.c */ |
461 | typedef struct AHCICommand AHCICommand; | |
462 | ||
9350df7c JS |
463 | /* Options to ahci_exec */ |
464 | typedef struct AHCIOpts { | |
465 | size_t size; | |
466 | unsigned prd_size; | |
467 | uint64_t lba; | |
468 | uint64_t buffer; | |
469 | bool atapi; | |
470 | bool atapi_dma; | |
471 | bool error; | |
472 | int (*pre_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); | |
473 | int (*mid_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); | |
474 | int (*post_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); | |
475 | void *opaque; | |
476 | } AHCIOpts; | |
477 | ||
90fc5e09 JS |
478 | /*** Macro Utilities ***/ |
479 | #define BITANY(data, mask) (((data) & (mask)) != 0) | |
480 | #define BITSET(data, mask) (((data) & (mask)) == (mask)) | |
481 | #define BITCLR(data, mask) (((data) & (mask)) == 0) | |
482 | #define ASSERT_BIT_SET(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) | |
483 | #define ASSERT_BIT_CLEAR(data, mask) g_assert_cmphex((data) & (mask), ==, 0) | |
484 | ||
485 | /* For calculating how big the PRD table needs to be: */ | |
486 | #define CMD_TBL_SIZ(n) ((0x80 + ((n) * sizeof(PRD)) + 0x7F) & ~0x7F) | |
487 | ||
4882f359 JS |
488 | /* Helpers for reading/writing AHCI HBA register values */ |
489 | ||
490 | static inline uint32_t ahci_mread(AHCIQState *ahci, size_t offset) | |
491 | { | |
b4ba67d9 | 492 | return qpci_io_readl(ahci->dev, ahci->hba_bar, offset); |
4882f359 JS |
493 | } |
494 | ||
495 | static inline void ahci_mwrite(AHCIQState *ahci, size_t offset, uint32_t value) | |
496 | { | |
b4ba67d9 | 497 | qpci_io_writel(ahci->dev, ahci->hba_bar, offset, value); |
4882f359 JS |
498 | } |
499 | ||
500 | static inline uint32_t ahci_rreg(AHCIQState *ahci, uint32_t reg_num) | |
501 | { | |
502 | return ahci_mread(ahci, 4 * reg_num); | |
503 | } | |
504 | ||
505 | static inline void ahci_wreg(AHCIQState *ahci, uint32_t reg_num, uint32_t value) | |
506 | { | |
507 | ahci_mwrite(ahci, 4 * reg_num, value); | |
508 | } | |
509 | ||
510 | static inline void ahci_set(AHCIQState *ahci, uint32_t reg_num, uint32_t mask) | |
511 | { | |
512 | ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) | mask); | |
513 | } | |
514 | ||
515 | static inline void ahci_clr(AHCIQState *ahci, uint32_t reg_num, uint32_t mask) | |
516 | { | |
517 | ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) & ~mask); | |
518 | } | |
519 | ||
520 | static inline size_t ahci_px_offset(uint8_t port, uint32_t reg_num) | |
521 | { | |
522 | return AHCI_PORTS + (HBA_PORT_NUM_REG * port) + reg_num; | |
523 | } | |
524 | ||
525 | static inline uint32_t ahci_px_rreg(AHCIQState *ahci, uint8_t port, | |
526 | uint32_t reg_num) | |
527 | { | |
528 | return ahci_rreg(ahci, ahci_px_offset(port, reg_num)); | |
529 | } | |
530 | ||
531 | static inline void ahci_px_wreg(AHCIQState *ahci, uint8_t port, | |
532 | uint32_t reg_num, uint32_t value) | |
533 | { | |
534 | ahci_wreg(ahci, ahci_px_offset(port, reg_num), value); | |
535 | } | |
536 | ||
537 | static inline void ahci_px_set(AHCIQState *ahci, uint8_t port, | |
538 | uint32_t reg_num, uint32_t mask) | |
539 | { | |
540 | ahci_px_wreg(ahci, port, reg_num, | |
541 | ahci_px_rreg(ahci, port, reg_num) | mask); | |
542 | } | |
543 | ||
544 | static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port, | |
545 | uint32_t reg_num, uint32_t mask) | |
546 | { | |
547 | ahci_px_wreg(ahci, port, reg_num, | |
548 | ahci_px_rreg(ahci, port, reg_num) & ~mask); | |
549 | } | |
550 | ||
9a75b0a0 JS |
551 | /*** Prototypes ***/ |
552 | uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes); | |
553 | void ahci_free(AHCIQState *ahci, uint64_t addr); | |
c5620e65 JS |
554 | void ahci_clean_mem(AHCIQState *ahci); |
555 | ||
556 | /* Device management */ | |
9a75b0a0 JS |
557 | QPCIDevice *get_ahci_device(uint32_t *fingerprint); |
558 | void free_ahci_device(QPCIDevice *dev); | |
559 | void ahci_pci_enable(AHCIQState *ahci); | |
560 | void start_ahci_device(AHCIQState *ahci); | |
561 | void ahci_hba_enable(AHCIQState *ahci); | |
c5620e65 JS |
562 | |
563 | /* Port Management */ | |
e77448a3 | 564 | unsigned ahci_port_select(AHCIQState *ahci); |
e83fd96b | 565 | void ahci_port_clear(AHCIQState *ahci, uint8_t port); |
c5620e65 JS |
566 | |
567 | /* Command header / table management */ | |
568 | unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); | |
569 | void ahci_get_command_header(AHCIQState *ahci, uint8_t port, | |
570 | uint8_t slot, AHCICommandHeader *cmd); | |
571 | void ahci_set_command_header(AHCIQState *ahci, uint8_t port, | |
572 | uint8_t slot, AHCICommandHeader *cmd); | |
573 | void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot); | |
574 | ||
575 | /* AHCI sanity check routines */ | |
85c34e93 | 576 | void ahci_port_check_error(AHCIQState *ahci, uint8_t port); |
5bf99aa1 JS |
577 | void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, |
578 | uint32_t intr_mask); | |
89a46723 | 579 | void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot); |
d1ef8838 JS |
580 | void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot); |
581 | void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port, | |
582 | uint8_t slot, size_t buffsize); | |
40d29928 | 583 | void ahci_port_check_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd); |
c5620e65 JS |
584 | |
585 | /* Misc */ | |
586 | bool is_atapi(AHCIQState *ahci, uint8_t port); | |
64a5a272 | 587 | unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd); |
c5620e65 JS |
588 | |
589 | /* Command: Macro level execution */ | |
11322195 | 590 | void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, |
727be1a7 | 591 | uint64_t gbuffer, size_t size, uint64_t sector); |
008b6e12 JS |
592 | AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, |
593 | uint64_t gbuffer, size_t size, uint64_t sector); | |
594 | void ahci_guest_io_resume(AHCIQState *ahci, AHCICommand *cmd); | |
ae029620 | 595 | void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, |
727be1a7 | 596 | void *buffer, size_t bufsize, uint64_t sector); |
9350df7c JS |
597 | void ahci_exec(AHCIQState *ahci, uint8_t port, |
598 | uint8_t op, const AHCIOpts *opts); | |
64a5a272 | 599 | |
c5620e65 | 600 | /* Command: Fine-grained lifecycle */ |
64a5a272 | 601 | AHCICommand *ahci_command_create(uint8_t command_name); |
54d268b2 | 602 | AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd); |
64a5a272 JS |
603 | void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port); |
604 | void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd); | |
605 | void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd); | |
606 | void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd); | |
ea41deb6 | 607 | void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd); |
64a5a272 JS |
608 | void ahci_command_free(AHCICommand *cmd); |
609 | ||
c5620e65 | 610 | /* Command: adjustments */ |
f9f963e0 JS |
611 | void ahci_command_set_flags(AHCICommand *cmd, uint16_t cmdh_flags); |
612 | void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags); | |
613 | void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect); | |
64a5a272 | 614 | void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer); |
cbc97569 JS |
615 | void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes); |
616 | void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size); | |
617 | void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, | |
618 | unsigned prd_size); | |
54d268b2 JS |
619 | void ahci_command_set_acmd(AHCICommand *cmd, void *acmd); |
620 | void ahci_command_enable_atapi_dma(AHCICommand *cmd); | |
f9f963e0 JS |
621 | void ahci_command_adjust(AHCICommand *cmd, uint64_t lba_sect, uint64_t gbuffer, |
622 | uint64_t xbytes, unsigned prd_size); | |
64a5a272 | 623 | |
c5620e65 | 624 | /* Command: Misc */ |
64a5a272 | 625 | uint8_t ahci_command_slot(AHCICommand *cmd); |
c5620e65 | 626 | void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd); |
9a75b0a0 | 627 | |
90fc5e09 | 628 | #endif |