]>
Commit | Line | Data |
---|---|---|
f83a40dc AG |
1 | /* |
2 | * QEMU AHCI Emulation | |
3 | * | |
4 | * Copyright (c) 2010 [email protected] | |
5 | * Copyright (c) 2010 Roland Elek <[email protected]> | |
6 | * Copyright (c) 2010 Sebastian Herbszt <[email protected]> | |
7 | * Copyright (c) 2010 Alexander Graf <[email protected]> | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
21 | * | |
22 | */ | |
23 | ||
03c7a6a8 SH |
24 | #ifndef HW_IDE_AHCI_H |
25 | #define HW_IDE_AHCI_H | |
26 | ||
5ea8b9c5 AF |
27 | #include <hw/sysbus.h> |
28 | ||
465f1ab1 | 29 | #define AHCI_MEM_BAR_SIZE 0x1000 |
03c7a6a8 SH |
30 | #define AHCI_MAX_PORTS 32 |
31 | #define AHCI_MAX_SG 168 /* hardware max is 64K */ | |
32 | #define AHCI_DMA_BOUNDARY 0xffffffff | |
33 | #define AHCI_USE_CLUSTERING 0 | |
34 | #define AHCI_MAX_CMDS 32 | |
35 | #define AHCI_CMD_SZ 32 | |
36 | #define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ) | |
37 | #define AHCI_RX_FIS_SZ 256 | |
38 | #define AHCI_CMD_TBL_CDB 0x40 | |
39 | #define AHCI_CMD_TBL_HDR_SZ 0x80 | |
40 | #define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16)) | |
41 | #define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS) | |
42 | #define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \ | |
43 | AHCI_RX_FIS_SZ) | |
44 | ||
2c02f887 | 45 | #define AHCI_IRQ_ON_SG (1U << 31) |
03c7a6a8 SH |
46 | #define AHCI_CMD_ATAPI (1 << 5) |
47 | #define AHCI_CMD_WRITE (1 << 6) | |
48 | #define AHCI_CMD_PREFETCH (1 << 7) | |
49 | #define AHCI_CMD_RESET (1 << 8) | |
50 | #define AHCI_CMD_CLR_BUSY (1 << 10) | |
51 | ||
52 | #define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */ | |
53 | #define RX_FIS_SDB 0x58 /* offset of SDB FIS data */ | |
54 | #define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */ | |
55 | ||
56 | /* global controller registers */ | |
57 | #define HOST_CAP 0x00 /* host capabilities */ | |
58 | #define HOST_CTL 0x04 /* global host control */ | |
59 | #define HOST_IRQ_STAT 0x08 /* interrupt status */ | |
60 | #define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */ | |
61 | #define HOST_VERSION 0x10 /* AHCI spec. version compliancy */ | |
62 | ||
63 | /* HOST_CTL bits */ | |
64 | #define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */ | |
65 | #define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */ | |
2c02f887 | 66 | #define HOST_CTL_AHCI_EN (1U << 31) /* AHCI enabled */ |
03c7a6a8 SH |
67 | |
68 | /* HOST_CAP bits */ | |
69 | #define HOST_CAP_SSC (1 << 14) /* Slumber capable */ | |
70 | #define HOST_CAP_AHCI (1 << 18) /* AHCI only */ | |
71 | #define HOST_CAP_CLO (1 << 24) /* Command List Override support */ | |
72 | #define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */ | |
73 | #define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */ | |
2c02f887 | 74 | #define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */ |
03c7a6a8 SH |
75 | |
76 | /* registers for each SATA port */ | |
77 | #define PORT_LST_ADDR 0x00 /* command list DMA addr */ | |
78 | #define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */ | |
79 | #define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */ | |
80 | #define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */ | |
81 | #define PORT_IRQ_STAT 0x10 /* interrupt status */ | |
82 | #define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */ | |
83 | #define PORT_CMD 0x18 /* port command */ | |
84 | #define PORT_TFDATA 0x20 /* taskfile data */ | |
85 | #define PORT_SIG 0x24 /* device TF signature */ | |
86 | #define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */ | |
87 | #define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */ | |
88 | #define PORT_SCR_ERR 0x30 /* SATA phy register: SError */ | |
89 | #define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */ | |
90 | #define PORT_CMD_ISSUE 0x38 /* command issue */ | |
91 | #define PORT_RESERVED 0x3c /* reserved */ | |
92 | ||
93 | /* PORT_IRQ_{STAT,MASK} bits */ | |
2c02f887 | 94 | #define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */ |
03c7a6a8 SH |
95 | #define PORT_IRQ_TF_ERR (1 << 30) /* task file error */ |
96 | #define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */ | |
97 | #define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */ | |
98 | #define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */ | |
99 | #define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */ | |
100 | #define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */ | |
101 | #define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */ | |
102 | ||
103 | #define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */ | |
104 | #define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */ | |
105 | #define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */ | |
106 | #define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */ | |
107 | #define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */ | |
108 | #define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */ | |
109 | #define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */ | |
110 | #define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */ | |
111 | #define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */ | |
112 | ||
113 | #define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \ | |
114 | PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \ | |
115 | PORT_IRQ_UNK_FIS) | |
116 | #define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \ | |
117 | PORT_IRQ_HBUS_DATA_ERR) | |
118 | #define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \ | |
119 | PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \ | |
120 | PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS) | |
121 | ||
122 | /* PORT_CMD bits */ | |
123 | #define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */ | |
124 | #define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */ | |
125 | #define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */ | |
126 | #define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */ | |
127 | #define PORT_CMD_CLO (1 << 3) /* Command list override */ | |
128 | #define PORT_CMD_POWER_ON (1 << 2) /* Power up device */ | |
129 | #define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */ | |
130 | #define PORT_CMD_START (1 << 0) /* Enable port DMA engine */ | |
131 | ||
91ced514 | 132 | #define PORT_CMD_ICC_MASK (0xfU << 28) /* i/f ICC state mask */ |
03c7a6a8 SH |
133 | #define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */ |
134 | #define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */ | |
135 | #define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */ | |
136 | ||
fc3d8e11 JS |
137 | #define PORT_CMD_RO_MASK 0x007dffe0 /* Which CMD bits are read only? */ |
138 | ||
03c7a6a8 SH |
139 | /* ap->flags bits */ |
140 | #define AHCI_FLAG_NO_NCQ (1 << 24) | |
141 | #define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */ | |
142 | #define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */ | |
143 | #define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */ | |
144 | #define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */ | |
145 | ||
146 | #define ATA_SRST (1 << 2) /* software reset */ | |
147 | ||
148 | #define STATE_RUN 0 | |
149 | #define STATE_RESET 1 | |
150 | ||
151 | #define SATA_SCR_SSTATUS_DET_NODEV 0x0 | |
152 | #define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3 | |
153 | ||
154 | #define SATA_SCR_SSTATUS_SPD_NODEV 0x00 | |
155 | #define SATA_SCR_SSTATUS_SPD_GEN1 0x10 | |
156 | ||
157 | #define SATA_SCR_SSTATUS_IPM_NODEV 0x000 | |
158 | #define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100 | |
159 | ||
160 | #define AHCI_SCR_SCTL_DET 0xf | |
161 | ||
162 | #define SATA_FIS_TYPE_REGISTER_H2D 0x27 | |
17fcb74a SH |
163 | #define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80 |
164 | #define SATA_FIS_TYPE_REGISTER_D2H 0x34 | |
165 | #define SATA_FIS_TYPE_PIO_SETUP 0x5f | |
166 | #define SATA_FIS_TYPE_SDB 0xA1 | |
03c7a6a8 SH |
167 | |
168 | #define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f | |
169 | #define AHCI_CMD_HDR_PRDT_LEN 16 | |
170 | ||
702c8c8b | 171 | #define SATA_SIGNATURE_CDROM 0xeb140101 |
03c7a6a8 SH |
172 | #define SATA_SIGNATURE_DISK 0x00000101 |
173 | ||
174 | #define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20 | |
175 | /* Shouldn't this be 0x2c? */ | |
176 | ||
03c7a6a8 | 177 | #define AHCI_PORT_REGS_START_ADDR 0x100 |
03c7a6a8 | 178 | #define AHCI_PORT_ADDR_OFFSET_MASK 0x7f |
2c4b9d0e | 179 | #define AHCI_PORT_ADDR_OFFSET_LEN 0x80 |
03c7a6a8 SH |
180 | |
181 | #define AHCI_NUM_COMMAND_SLOTS 31 | |
182 | #define AHCI_SUPPORTED_SPEED 20 | |
183 | #define AHCI_SUPPORTED_SPEED_GEN1 1 | |
184 | #define AHCI_VERSION_1_0 0x10000 | |
185 | ||
186 | #define AHCI_PROGMODE_MAJOR_REV_1 1 | |
187 | ||
188 | #define AHCI_COMMAND_TABLE_ACMD 0x40 | |
189 | ||
d02f8adc RJ |
190 | #define AHCI_PRDT_SIZE_MASK 0x3fffff |
191 | ||
03c7a6a8 SH |
192 | #define IDE_FEATURE_DMA 1 |
193 | ||
194 | #define READ_FPDMA_QUEUED 0x60 | |
195 | #define WRITE_FPDMA_QUEUED 0x61 | |
72a065db JS |
196 | #define NCQ_NON_DATA 0x63 |
197 | #define RECEIVE_FPDMA_QUEUED 0x65 | |
198 | #define SEND_FPDMA_QUEUED 0x64 | |
03c7a6a8 | 199 | |
7763ed15 JS |
200 | #define NCQ_FIS_FUA_MASK 0x80 |
201 | #define NCQ_FIS_RARC_MASK 0x01 | |
202 | ||
03c7a6a8 SH |
203 | #define RES_FIS_DSFIS 0x00 |
204 | #define RES_FIS_PSFIS 0x20 | |
205 | #define RES_FIS_RFIS 0x40 | |
206 | #define RES_FIS_SDBFIS 0x58 | |
207 | #define RES_FIS_UFIS 0x60 | |
208 | ||
465f1ab1 DV |
209 | #define SATA_CAP_SIZE 0x8 |
210 | #define SATA_CAP_REV 0x2 | |
211 | #define SATA_CAP_BAR 0x4 | |
212 | ||
03c7a6a8 SH |
213 | typedef struct AHCIControlRegs { |
214 | uint32_t cap; | |
215 | uint32_t ghc; | |
216 | uint32_t irqstatus; | |
217 | uint32_t impl; | |
218 | uint32_t version; | |
219 | } AHCIControlRegs; | |
220 | ||
221 | typedef struct AHCIPortRegs { | |
222 | uint32_t lst_addr; | |
223 | uint32_t lst_addr_hi; | |
224 | uint32_t fis_addr; | |
225 | uint32_t fis_addr_hi; | |
226 | uint32_t irq_stat; | |
227 | uint32_t irq_mask; | |
228 | uint32_t cmd; | |
229 | uint32_t unused0; | |
230 | uint32_t tfdata; | |
231 | uint32_t sig; | |
232 | uint32_t scr_stat; | |
233 | uint32_t scr_ctl; | |
234 | uint32_t scr_err; | |
235 | uint32_t scr_act; | |
236 | uint32_t cmd_issue; | |
237 | uint32_t reserved; | |
238 | } AHCIPortRegs; | |
239 | ||
240 | typedef struct AHCICmdHdr { | |
d56f4d69 JS |
241 | uint16_t opts; |
242 | uint16_t prdtl; | |
03c7a6a8 SH |
243 | uint32_t status; |
244 | uint64_t tbl_addr; | |
245 | uint32_t reserved[4]; | |
541dc0d4 | 246 | } QEMU_PACKED AHCICmdHdr; |
03c7a6a8 SH |
247 | |
248 | typedef struct AHCI_SG { | |
249 | uint64_t addr; | |
250 | uint32_t reserved; | |
251 | uint32_t flags_size; | |
541dc0d4 | 252 | } QEMU_PACKED AHCI_SG; |
03c7a6a8 SH |
253 | |
254 | typedef struct AHCIDevice AHCIDevice; | |
255 | ||
256 | typedef struct NCQTransferState { | |
257 | AHCIDevice *drive; | |
7c84b1b8 | 258 | BlockAIOCB *aiocb; |
c82bd3c8 | 259 | AHCICmdHdr *cmdh; |
03c7a6a8 | 260 | QEMUSGList sglist; |
a597e79c | 261 | BlockAcctCookie acct; |
e08a9835 | 262 | uint32_t sector_count; |
03c7a6a8 SH |
263 | uint64_t lba; |
264 | uint8_t tag; | |
4614619e | 265 | uint8_t cmd; |
9364384d JS |
266 | uint8_t slot; |
267 | bool used; | |
7c03a691 | 268 | bool halt; |
03c7a6a8 SH |
269 | } NCQTransferState; |
270 | ||
271 | struct AHCIDevice { | |
272 | IDEDMA dma; | |
273 | IDEBus port; | |
274 | int port_no; | |
275 | uint32_t port_state; | |
276 | uint32_t finished; | |
277 | AHCIPortRegs port_regs; | |
278 | struct AHCIState *hba; | |
279 | QEMUBH *check_bh; | |
280 | uint8_t *lst; | |
281 | uint8_t *res_fis; | |
4ac557c8 KW |
282 | bool done_atapi_packet; |
283 | int32_t busy_slot; | |
284 | bool init_d2h_sent; | |
03c7a6a8 SH |
285 | AHCICmdHdr *cur_cmd; |
286 | NCQTransferState ncq_tfs[AHCI_MAX_CMDS]; | |
287 | }; | |
288 | ||
289 | typedef struct AHCIState { | |
bb639f82 AF |
290 | DeviceState *container; |
291 | ||
2c4b9d0e | 292 | AHCIDevice *dev; |
03c7a6a8 | 293 | AHCIControlRegs control_regs; |
67e576c2 | 294 | MemoryRegion mem; |
465f1ab1 DV |
295 | MemoryRegion idp; /* Index-Data Pair I/O port space */ |
296 | unsigned idp_offset; /* Offset of index in I/O port space */ | |
297 | uint32_t idp_index; /* Current IDP index */ | |
4ac557c8 | 298 | int32_t ports; |
03c7a6a8 | 299 | qemu_irq irq; |
df32fd1c | 300 | AddressSpace *as; |
03c7a6a8 SH |
301 | } AHCIState; |
302 | ||
303 | typedef struct AHCIPCIState { | |
0d3aea56 AF |
304 | /*< private >*/ |
305 | PCIDevice parent_obj; | |
306 | /*< public >*/ | |
307 | ||
03c7a6a8 SH |
308 | AHCIState ahci; |
309 | } AHCIPCIState; | |
310 | ||
fd58922c PC |
311 | #define TYPE_ICH9_AHCI "ich9-ahci" |
312 | ||
313 | #define ICH_AHCI(obj) \ | |
314 | OBJECT_CHECK(AHCIPCIState, (obj), TYPE_ICH9_AHCI) | |
315 | ||
a2623021 JB |
316 | extern const VMStateDescription vmstate_ahci; |
317 | ||
318 | #define VMSTATE_AHCI(_field, _state) { \ | |
319 | .name = (stringify(_field)), \ | |
320 | .size = sizeof(AHCIState), \ | |
321 | .vmsd = &vmstate_ahci, \ | |
322 | .flags = VMS_STRUCT, \ | |
323 | .offset = vmstate_offset_value(_state, _field, AHCIState), \ | |
324 | } | |
325 | ||
7763ed15 JS |
326 | /** |
327 | * NCQFrame is the same as a Register H2D FIS (described in SATA 3.2), | |
328 | * but some fields have been re-mapped and re-purposed, as seen in | |
329 | * SATA 3.2 section 13.6.4.1 ("READ FPDMA QUEUED") | |
330 | * | |
331 | * cmd_fis[3], feature 7:0, becomes sector count 7:0. | |
332 | * cmd_fis[7], device 7:0, uses bit 7 as the Force Unit Access bit. | |
333 | * cmd_fis[11], feature 15:8, becomes sector count 15:8. | |
334 | * cmd_fis[12], count 7:0, becomes the NCQ TAG (7:3) and RARC bit (0) | |
335 | * cmd_fis[13], count 15:8, becomes the priority value (7:6) | |
336 | * bytes 16-19 become an le32 "auxiliary" field. | |
337 | */ | |
03c7a6a8 SH |
338 | typedef struct NCQFrame { |
339 | uint8_t fis_type; | |
340 | uint8_t c; | |
341 | uint8_t command; | |
7763ed15 | 342 | uint8_t sector_count_low; /* (feature 7:0) */ |
03c7a6a8 SH |
343 | uint8_t lba0; |
344 | uint8_t lba1; | |
345 | uint8_t lba2; | |
7763ed15 | 346 | uint8_t fua; /* (device 7:0) */ |
03c7a6a8 SH |
347 | uint8_t lba3; |
348 | uint8_t lba4; | |
349 | uint8_t lba5; | |
7763ed15 JS |
350 | uint8_t sector_count_high; /* (feature 15:8) */ |
351 | uint8_t tag; /* (count 0:7) */ | |
352 | uint8_t prio; /* (count 15:8) */ | |
353 | uint8_t icc; | |
03c7a6a8 | 354 | uint8_t control; |
7763ed15 JS |
355 | uint8_t aux0; |
356 | uint8_t aux1; | |
357 | uint8_t aux2; | |
358 | uint8_t aux3; | |
541dc0d4 | 359 | } QEMU_PACKED NCQFrame; |
03c7a6a8 | 360 | |
54a7f8f3 JS |
361 | typedef struct SDBFIS { |
362 | uint8_t type; | |
363 | uint8_t flags; | |
364 | uint8_t status; | |
365 | uint8_t error; | |
366 | uint32_t payload; | |
367 | } QEMU_PACKED SDBFIS; | |
368 | ||
df32fd1c | 369 | void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports); |
2c4b9d0e | 370 | void ahci_uninit(AHCIState *s); |
03c7a6a8 | 371 | |
8ab60a07 | 372 | void ahci_reset(AHCIState *s); |
03c7a6a8 | 373 | |
d93162e1 JS |
374 | void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd); |
375 | ||
5ea8b9c5 AF |
376 | #define TYPE_SYSBUS_AHCI "sysbus-ahci" |
377 | #define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI) | |
378 | ||
379 | typedef struct SysbusAHCIState { | |
380 | /*< private >*/ | |
381 | SysBusDevice parent_obj; | |
382 | /*< public >*/ | |
383 | ||
384 | AHCIState ahci; | |
385 | uint32_t num_ports; | |
386 | } SysbusAHCIState; | |
387 | ||
03c7a6a8 | 388 | #endif /* HW_IDE_AHCI_H */ |