]>
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 { | |
e0a4cb2c JS |
290 | CMD_ATAPI_TEST_UNIT_READY = 0x00, |
291 | CMD_ATAPI_REQUEST_SENSE = 0x03, | |
48cde091 JS |
292 | CMD_ATAPI_START_STOP_UNIT = 0x1b, |
293 | CMD_ATAPI_READ_10 = 0x28, | |
294 | CMD_ATAPI_READ_CD = 0xbe, | |
54d268b2 JS |
295 | }; |
296 | ||
e0a4cb2c JS |
297 | enum { |
298 | SENSE_NO_SENSE = 0x00, | |
299 | SENSE_NOT_READY = 0x02, | |
300 | SENSE_UNIT_ATTENTION = 0x06, | |
301 | }; | |
302 | ||
303 | enum { | |
304 | ASC_MEDIUM_MAY_HAVE_CHANGED = 0x28, | |
305 | ASC_MEDIUM_NOT_PRESENT = 0x3a, | |
306 | }; | |
307 | ||
36e36726 JS |
308 | /* AHCI Command Header Flags & Masks*/ |
309 | #define CMDH_CFL (0x1F) | |
310 | #define CMDH_ATAPI (0x20) | |
311 | #define CMDH_WRITE (0x40) | |
312 | #define CMDH_PREFETCH (0x80) | |
313 | #define CMDH_RESET (0x100) | |
314 | #define CMDH_BIST (0x200) | |
315 | #define CMDH_CLR_BSY (0x400) | |
316 | #define CMDH_RES (0x800) | |
317 | #define CMDH_PMP (0xF000) | |
318 | ||
319 | /* ATA device register masks */ | |
cb453041 | 320 | #define ATA_DEVICE_MAGIC 0xA0 /* used in ata1-3 */ |
36e36726 | 321 | #define ATA_DEVICE_LBA 0x40 |
cb453041 | 322 | #define NCQ_DEVICE_MAGIC 0x40 /* for ncq device registers */ |
36e36726 JS |
323 | #define ATA_DEVICE_DRIVE 0x10 |
324 | #define ATA_DEVICE_HEAD 0x0F | |
325 | ||
90fc5e09 JS |
326 | /*** Structures ***/ |
327 | ||
f3dd2da4 JS |
328 | typedef struct AHCIPortQState { |
329 | uint64_t fb; | |
330 | uint64_t clb; | |
6cae27a6 JS |
331 | uint64_t ctba[32]; |
332 | uint16_t prdtl[32]; | |
333 | uint8_t next; /** Next Command Slot to Use **/ | |
f3dd2da4 JS |
334 | } AHCIPortQState; |
335 | ||
dd0029c0 JS |
336 | typedef struct AHCIQState { |
337 | QOSState *parent; | |
338 | QPCIDevice *dev; | |
b4ba67d9 | 339 | QPCIBar hba_bar; |
8d5eeced JS |
340 | uint64_t barsize; |
341 | uint32_t fingerprint; | |
342 | uint32_t cap; | |
343 | uint32_t cap2; | |
f3dd2da4 | 344 | AHCIPortQState port[32]; |
e7c8526b | 345 | bool enabled; |
dd0029c0 JS |
346 | } AHCIQState; |
347 | ||
90fc5e09 JS |
348 | /** |
349 | * Generic FIS structure. | |
350 | */ | |
351 | typedef struct FIS { | |
352 | uint8_t fis_type; | |
353 | uint8_t flags; | |
354 | char data[0]; | |
355 | } __attribute__((__packed__)) FIS; | |
356 | ||
357 | /** | |
358 | * Register device-to-host FIS structure. | |
359 | */ | |
360 | typedef struct RegD2HFIS { | |
361 | /* DW0 */ | |
362 | uint8_t fis_type; | |
363 | uint8_t flags; | |
364 | uint8_t status; | |
365 | uint8_t error; | |
366 | /* DW1 */ | |
d1ef8838 | 367 | uint8_t lba_lo[3]; |
90fc5e09 JS |
368 | uint8_t device; |
369 | /* DW2 */ | |
d1ef8838 JS |
370 | uint8_t lba_hi[3]; |
371 | uint8_t res0; | |
90fc5e09 JS |
372 | /* DW3 */ |
373 | uint16_t count; | |
d1ef8838 | 374 | uint16_t res1; |
90fc5e09 | 375 | /* DW4 */ |
d1ef8838 | 376 | uint32_t res2; |
90fc5e09 JS |
377 | } __attribute__((__packed__)) RegD2HFIS; |
378 | ||
d1ef8838 JS |
379 | /** |
380 | * Register device-to-host FIS structure; | |
381 | * PIO Setup variety. | |
382 | */ | |
383 | typedef struct PIOSetupFIS { | |
384 | /* DW0 */ | |
385 | uint8_t fis_type; | |
386 | uint8_t flags; | |
387 | uint8_t status; | |
388 | uint8_t error; | |
389 | /* DW1 */ | |
390 | uint8_t lba_lo[3]; | |
391 | uint8_t device; | |
392 | /* DW2 */ | |
393 | uint8_t lba_hi[3]; | |
394 | uint8_t res0; | |
395 | /* DW3 */ | |
396 | uint16_t count; | |
397 | uint8_t res1; | |
398 | uint8_t e_status; | |
399 | /* DW4 */ | |
400 | uint16_t tx_count; | |
401 | uint16_t res2; | |
402 | } __attribute__((__packed__)) PIOSetupFIS; | |
403 | ||
90fc5e09 JS |
404 | /** |
405 | * Register host-to-device FIS structure. | |
406 | */ | |
407 | typedef struct RegH2DFIS { | |
408 | /* DW0 */ | |
409 | uint8_t fis_type; | |
410 | uint8_t flags; | |
411 | uint8_t command; | |
412 | uint8_t feature_low; | |
413 | /* DW1 */ | |
d1ef8838 | 414 | uint8_t lba_lo[3]; |
90fc5e09 JS |
415 | uint8_t device; |
416 | /* DW2 */ | |
d1ef8838 | 417 | uint8_t lba_hi[3]; |
90fc5e09 JS |
418 | uint8_t feature_high; |
419 | /* DW3 */ | |
420 | uint16_t count; | |
421 | uint8_t icc; | |
422 | uint8_t control; | |
423 | /* DW4 */ | |
52515766 | 424 | uint8_t aux[4]; |
90fc5e09 JS |
425 | } __attribute__((__packed__)) RegH2DFIS; |
426 | ||
cb453041 JS |
427 | /** |
428 | * Register host-to-device FIS structure, for NCQ commands. | |
429 | * Actually just a RegH2DFIS, but with fields repurposed. | |
430 | * Repurposed fields are annotated below. | |
431 | */ | |
432 | typedef struct NCQFIS { | |
433 | /* DW0 */ | |
434 | uint8_t fis_type; | |
435 | uint8_t flags; | |
436 | uint8_t command; | |
437 | uint8_t sector_low; /* H2D: Feature 7:0 */ | |
438 | /* DW1 */ | |
439 | uint8_t lba_lo[3]; | |
440 | uint8_t device; | |
441 | /* DW2 */ | |
442 | uint8_t lba_hi[3]; | |
443 | uint8_t sector_hi; /* H2D: Feature 15:8 */ | |
444 | /* DW3 */ | |
445 | uint8_t tag; /* H2D: Count 0:7 */ | |
446 | uint8_t prio; /* H2D: Count 15:8 */ | |
447 | uint8_t icc; | |
448 | uint8_t control; | |
449 | /* DW4 */ | |
450 | uint8_t aux[4]; | |
451 | } __attribute__((__packed__)) NCQFIS; | |
452 | ||
90fc5e09 JS |
453 | /** |
454 | * Command List entry structure. | |
455 | * The command list contains between 1-32 of these structures. | |
456 | */ | |
c7f9c570 JS |
457 | typedef struct AHCICommandHeader { |
458 | uint16_t flags; /* Cmd-Fis-Len, PMP#, and flags. */ | |
90fc5e09 JS |
459 | uint16_t prdtl; /* Phys Region Desc. Table Length */ |
460 | uint32_t prdbc; /* Phys Region Desc. Byte Count */ | |
6cae27a6 | 461 | uint64_t ctba; /* Command Table Descriptor Base Address */ |
90fc5e09 | 462 | uint32_t res[4]; |
c7f9c570 | 463 | } __attribute__((__packed__)) AHCICommandHeader; |
90fc5e09 JS |
464 | |
465 | /** | |
466 | * Physical Region Descriptor; pointed to by the Command List Header, | |
467 | * struct ahci_command. | |
468 | */ | |
469 | typedef struct PRD { | |
6cae27a6 | 470 | uint64_t dba; /* Data Base Address */ |
90fc5e09 JS |
471 | uint32_t res; /* Reserved */ |
472 | uint32_t dbc; /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */ | |
6cae27a6 | 473 | } __attribute__((__packed__)) PRD; |
90fc5e09 | 474 | |
64a5a272 JS |
475 | /* Opaque, defined within ahci.c */ |
476 | typedef struct AHCICommand AHCICommand; | |
477 | ||
9350df7c JS |
478 | /* Options to ahci_exec */ |
479 | typedef struct AHCIOpts { | |
ebde93bf JS |
480 | size_t size; /* Size of transfer */ |
481 | unsigned prd_size; /* Size per-each PRD */ | |
482 | bool set_bcl; /* Override the default BCL of ATAPI_SECTOR_SIZE */ | |
483 | unsigned bcl; /* Byte Count Limit, for ATAPI PIO */ | |
484 | uint64_t lba; /* Starting LBA offset */ | |
485 | uint64_t buffer; /* Pointer to source or destination guest buffer */ | |
486 | bool atapi; /* ATAPI command? */ | |
487 | bool atapi_dma; /* Use DMA for ATAPI? */ | |
9350df7c JS |
488 | bool error; |
489 | int (*pre_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); | |
490 | int (*mid_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); | |
491 | int (*post_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); | |
492 | void *opaque; | |
493 | } AHCIOpts; | |
494 | ||
90fc5e09 JS |
495 | /*** Macro Utilities ***/ |
496 | #define BITANY(data, mask) (((data) & (mask)) != 0) | |
497 | #define BITSET(data, mask) (((data) & (mask)) == (mask)) | |
498 | #define BITCLR(data, mask) (((data) & (mask)) == 0) | |
499 | #define ASSERT_BIT_SET(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) | |
500 | #define ASSERT_BIT_CLEAR(data, mask) g_assert_cmphex((data) & (mask), ==, 0) | |
501 | ||
502 | /* For calculating how big the PRD table needs to be: */ | |
503 | #define CMD_TBL_SIZ(n) ((0x80 + ((n) * sizeof(PRD)) + 0x7F) & ~0x7F) | |
504 | ||
4882f359 JS |
505 | /* Helpers for reading/writing AHCI HBA register values */ |
506 | ||
507 | static inline uint32_t ahci_mread(AHCIQState *ahci, size_t offset) | |
508 | { | |
b4ba67d9 | 509 | return qpci_io_readl(ahci->dev, ahci->hba_bar, offset); |
4882f359 JS |
510 | } |
511 | ||
512 | static inline void ahci_mwrite(AHCIQState *ahci, size_t offset, uint32_t value) | |
513 | { | |
b4ba67d9 | 514 | qpci_io_writel(ahci->dev, ahci->hba_bar, offset, value); |
4882f359 JS |
515 | } |
516 | ||
517 | static inline uint32_t ahci_rreg(AHCIQState *ahci, uint32_t reg_num) | |
518 | { | |
519 | return ahci_mread(ahci, 4 * reg_num); | |
520 | } | |
521 | ||
522 | static inline void ahci_wreg(AHCIQState *ahci, uint32_t reg_num, uint32_t value) | |
523 | { | |
524 | ahci_mwrite(ahci, 4 * reg_num, value); | |
525 | } | |
526 | ||
527 | static inline void ahci_set(AHCIQState *ahci, uint32_t reg_num, uint32_t mask) | |
528 | { | |
529 | ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) | mask); | |
530 | } | |
531 | ||
532 | static inline void ahci_clr(AHCIQState *ahci, uint32_t reg_num, uint32_t mask) | |
533 | { | |
534 | ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) & ~mask); | |
535 | } | |
536 | ||
537 | static inline size_t ahci_px_offset(uint8_t port, uint32_t reg_num) | |
538 | { | |
539 | return AHCI_PORTS + (HBA_PORT_NUM_REG * port) + reg_num; | |
540 | } | |
541 | ||
542 | static inline uint32_t ahci_px_rreg(AHCIQState *ahci, uint8_t port, | |
543 | uint32_t reg_num) | |
544 | { | |
545 | return ahci_rreg(ahci, ahci_px_offset(port, reg_num)); | |
546 | } | |
547 | ||
548 | static inline void ahci_px_wreg(AHCIQState *ahci, uint8_t port, | |
549 | uint32_t reg_num, uint32_t value) | |
550 | { | |
551 | ahci_wreg(ahci, ahci_px_offset(port, reg_num), value); | |
552 | } | |
553 | ||
554 | static inline void ahci_px_set(AHCIQState *ahci, uint8_t port, | |
555 | uint32_t reg_num, uint32_t mask) | |
556 | { | |
557 | ahci_px_wreg(ahci, port, reg_num, | |
558 | ahci_px_rreg(ahci, port, reg_num) | mask); | |
559 | } | |
560 | ||
561 | static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port, | |
562 | uint32_t reg_num, uint32_t mask) | |
563 | { | |
564 | ahci_px_wreg(ahci, port, reg_num, | |
565 | ahci_px_rreg(ahci, port, reg_num) & ~mask); | |
566 | } | |
567 | ||
9a75b0a0 JS |
568 | /*** Prototypes ***/ |
569 | uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes); | |
570 | void ahci_free(AHCIQState *ahci, uint64_t addr); | |
c5620e65 JS |
571 | void ahci_clean_mem(AHCIQState *ahci); |
572 | ||
573 | /* Device management */ | |
e5d1730d | 574 | QPCIDevice *get_ahci_device(QTestState *qts, uint32_t *fingerprint); |
9a75b0a0 JS |
575 | void free_ahci_device(QPCIDevice *dev); |
576 | void ahci_pci_enable(AHCIQState *ahci); | |
577 | void start_ahci_device(AHCIQState *ahci); | |
578 | void ahci_hba_enable(AHCIQState *ahci); | |
c5620e65 JS |
579 | |
580 | /* Port Management */ | |
e77448a3 | 581 | unsigned ahci_port_select(AHCIQState *ahci); |
e83fd96b | 582 | void ahci_port_clear(AHCIQState *ahci, uint8_t port); |
c5620e65 JS |
583 | |
584 | /* Command header / table management */ | |
585 | unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); | |
586 | void ahci_get_command_header(AHCIQState *ahci, uint8_t port, | |
587 | uint8_t slot, AHCICommandHeader *cmd); | |
588 | void ahci_set_command_header(AHCIQState *ahci, uint8_t port, | |
589 | uint8_t slot, AHCICommandHeader *cmd); | |
590 | void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot); | |
591 | ||
592 | /* AHCI sanity check routines */ | |
f697b0ed JS |
593 | void ahci_port_check_error(AHCIQState *ahci, uint8_t port, |
594 | uint32_t imask, uint8_t emask); | |
5bf99aa1 JS |
595 | void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, |
596 | uint32_t intr_mask); | |
89a46723 | 597 | void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot); |
d1ef8838 | 598 | void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot); |
956556e1 | 599 | void ahci_port_check_pio_sanity(AHCIQState *ahci, AHCICommand *cmd); |
40d29928 | 600 | void ahci_port_check_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd); |
c5620e65 JS |
601 | |
602 | /* Misc */ | |
603 | bool is_atapi(AHCIQState *ahci, uint8_t port); | |
64a5a272 | 604 | unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd); |
c5620e65 JS |
605 | |
606 | /* Command: Macro level execution */ | |
11322195 | 607 | void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, |
727be1a7 | 608 | uint64_t gbuffer, size_t size, uint64_t sector); |
008b6e12 JS |
609 | AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, |
610 | uint64_t gbuffer, size_t size, uint64_t sector); | |
611 | void ahci_guest_io_resume(AHCIQState *ahci, AHCICommand *cmd); | |
ae029620 | 612 | void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, |
727be1a7 | 613 | void *buffer, size_t bufsize, uint64_t sector); |
9350df7c JS |
614 | void ahci_exec(AHCIQState *ahci, uint8_t port, |
615 | uint8_t op, const AHCIOpts *opts); | |
e0a4cb2c JS |
616 | void ahci_atapi_test_ready(AHCIQState *ahci, uint8_t port, bool ready, |
617 | uint8_t expected_sense); | |
618 | void ahci_atapi_get_sense(AHCIQState *ahci, uint8_t port, | |
619 | uint8_t *sense, uint8_t *asc); | |
48cde091 JS |
620 | void ahci_atapi_eject(AHCIQState *ahci, uint8_t port); |
621 | void ahci_atapi_load(AHCIQState *ahci, uint8_t port); | |
64a5a272 | 622 | |
c5620e65 | 623 | /* Command: Fine-grained lifecycle */ |
64a5a272 | 624 | AHCICommand *ahci_command_create(uint8_t command_name); |
ae79c2db | 625 | AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd, uint16_t bcl, bool dma); |
64a5a272 JS |
626 | void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port); |
627 | void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd); | |
628 | void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd); | |
629 | void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd); | |
ea41deb6 | 630 | void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd); |
64a5a272 JS |
631 | void ahci_command_free(AHCICommand *cmd); |
632 | ||
c5620e65 | 633 | /* Command: adjustments */ |
f9f963e0 JS |
634 | void ahci_command_set_flags(AHCICommand *cmd, uint16_t cmdh_flags); |
635 | void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags); | |
636 | void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect); | |
64a5a272 | 637 | void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer); |
cbc97569 JS |
638 | void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes); |
639 | void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size); | |
640 | void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, | |
641 | unsigned prd_size); | |
54d268b2 JS |
642 | void ahci_command_set_acmd(AHCICommand *cmd, void *acmd); |
643 | void ahci_command_enable_atapi_dma(AHCICommand *cmd); | |
f9f963e0 JS |
644 | void ahci_command_adjust(AHCICommand *cmd, uint64_t lba_sect, uint64_t gbuffer, |
645 | uint64_t xbytes, unsigned prd_size); | |
64a5a272 | 646 | |
c5620e65 | 647 | /* Command: Misc */ |
64a5a272 | 648 | uint8_t ahci_command_slot(AHCICommand *cmd); |
c5620e65 | 649 | void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd); |
9a75b0a0 | 650 | |
90fc5e09 | 651 | #endif |