root / hw / ide / ahci.c @ f6ad2e32
History | View | Annotate | Download (46.3 kB)
1 |
/*
|
---|---|
2 |
* QEMU AHCI Emulation
|
3 |
*
|
4 |
* Copyright (c) 2010 qiaochong@loongson.cn
|
5 |
* Copyright (c) 2010 Roland Elek <elek.roland@gmail.com>
|
6 |
* Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de>
|
7 |
* Copyright (c) 2010 Alexander Graf <agraf@suse.de>
|
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 |
* lspci dump of a ICH-9 real device in IDE mode (hopefully close enough):
|
24 |
*
|
25 |
* 00:1f.2 SATA controller [0106]: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] (rev 02) (prog-if 01 [AHCI 1.0])
|
26 |
* Subsystem: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922]
|
27 |
* Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
|
28 |
* Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
|
29 |
* Latency: 0
|
30 |
* Interrupt: pin B routed to IRQ 222
|
31 |
* Region 0: I/O ports at d000 [size=8]
|
32 |
* Region 1: I/O ports at cc00 [size=4]
|
33 |
* Region 2: I/O ports at c880 [size=8]
|
34 |
* Region 3: I/O ports at c800 [size=4]
|
35 |
* Region 4: I/O ports at c480 [size=32]
|
36 |
* Region 5: Memory at febf9000 (32-bit, non-prefetchable) [size=2K]
|
37 |
* Capabilities: [80] Message Signalled Interrupts: Mask- 64bit- Count=1/16 Enable+
|
38 |
* Address: fee0f00c Data: 41d9
|
39 |
* Capabilities: [70] Power Management version 3
|
40 |
* Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-)
|
41 |
* Status: D0 PME-Enable- DSel=0 DScale=0 PME-
|
42 |
* Capabilities: [a8] SATA HBA <?>
|
43 |
* Capabilities: [b0] Vendor Specific Information <?>
|
44 |
* Kernel driver in use: ahci
|
45 |
* Kernel modules: ahci
|
46 |
* 00: 86 80 22 29 07 04 b0 02 02 01 06 01 00 00 00 00
|
47 |
* 10: 01 d0 00 00 01 cc 00 00 81 c8 00 00 01 c8 00 00
|
48 |
* 20: 81 c4 00 00 00 90 bf fe 00 00 00 00 86 80 22 29
|
49 |
* 30: 00 00 00 00 80 00 00 00 00 00 00 00 0f 02 00 00
|
50 |
* 40: 00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00
|
51 |
* 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
52 |
* 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
53 |
* 70: 01 a8 03 40 08 00 00 00 00 00 00 00 00 00 00 00
|
54 |
* 80: 05 70 09 00 0c f0 e0 fe d9 41 00 00 00 00 00 00
|
55 |
* 90: 40 00 0f 82 93 01 00 00 00 00 00 00 00 00 00 00
|
56 |
* a0: ac 00 00 00 0a 00 12 00 12 b0 10 00 48 00 00 00
|
57 |
* b0: 09 00 06 20 00 00 00 00 00 00 00 00 00 00 00 00
|
58 |
* c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
59 |
* d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
60 |
* e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
61 |
* f0: 00 00 00 00 00 00 00 00 86 0f 02 00 00 00 00 00
|
62 |
*
|
63 |
*/
|
64 |
|
65 |
#include <hw/hw.h> |
66 |
#include <hw/msi.h> |
67 |
#include <hw/pc.h> |
68 |
#include <hw/pci.h> |
69 |
|
70 |
#include "monitor.h" |
71 |
#include "dma.h" |
72 |
#include "cpu-common.h" |
73 |
#include "blockdev.h" |
74 |
#include "internal.h" |
75 |
#include <hw/ide/pci.h> |
76 |
|
77 |
/* #define DEBUG_AHCI */
|
78 |
|
79 |
#ifdef DEBUG_AHCI
|
80 |
#define DPRINTF(port, fmt, ...) \
|
81 |
do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \ |
82 |
fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) |
83 |
#else
|
84 |
#define DPRINTF(port, fmt, ...) do {} while(0) |
85 |
#endif
|
86 |
|
87 |
#define AHCI_PCI_BAR 5 |
88 |
#define AHCI_MAX_PORTS 32 |
89 |
#define AHCI_MAX_SG 168 /* hardware max is 64K */ |
90 |
#define AHCI_DMA_BOUNDARY 0xffffffff |
91 |
#define AHCI_USE_CLUSTERING 0 |
92 |
#define AHCI_MAX_CMDS 32 |
93 |
#define AHCI_CMD_SZ 32 |
94 |
#define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ)
|
95 |
#define AHCI_RX_FIS_SZ 256 |
96 |
#define AHCI_CMD_TBL_CDB 0x40 |
97 |
#define AHCI_CMD_TBL_HDR_SZ 0x80 |
98 |
#define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16)) |
99 |
#define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS)
|
100 |
#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
|
101 |
AHCI_RX_FIS_SZ) |
102 |
|
103 |
#define AHCI_IRQ_ON_SG (1 << 31) |
104 |
#define AHCI_CMD_ATAPI (1 << 5) |
105 |
#define AHCI_CMD_WRITE (1 << 6) |
106 |
#define AHCI_CMD_PREFETCH (1 << 7) |
107 |
#define AHCI_CMD_RESET (1 << 8) |
108 |
#define AHCI_CMD_CLR_BUSY (1 << 10) |
109 |
|
110 |
#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */ |
111 |
#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */ |
112 |
#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */ |
113 |
|
114 |
/* global controller registers */
|
115 |
#define HOST_CAP 0x00 /* host capabilities */ |
116 |
#define HOST_CTL 0x04 /* global host control */ |
117 |
#define HOST_IRQ_STAT 0x08 /* interrupt status */ |
118 |
#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */ |
119 |
#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */ |
120 |
|
121 |
/* HOST_CTL bits */
|
122 |
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */ |
123 |
#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */ |
124 |
#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */ |
125 |
|
126 |
/* HOST_CAP bits */
|
127 |
#define HOST_CAP_SSC (1 << 14) /* Slumber capable */ |
128 |
#define HOST_CAP_AHCI (1 << 18) /* AHCI only */ |
129 |
#define HOST_CAP_CLO (1 << 24) /* Command List Override support */ |
130 |
#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */ |
131 |
#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */ |
132 |
#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */ |
133 |
|
134 |
/* registers for each SATA port */
|
135 |
#define PORT_LST_ADDR 0x00 /* command list DMA addr */ |
136 |
#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */ |
137 |
#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */ |
138 |
#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */ |
139 |
#define PORT_IRQ_STAT 0x10 /* interrupt status */ |
140 |
#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */ |
141 |
#define PORT_CMD 0x18 /* port command */ |
142 |
#define PORT_TFDATA 0x20 /* taskfile data */ |
143 |
#define PORT_SIG 0x24 /* device TF signature */ |
144 |
#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */ |
145 |
#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */ |
146 |
#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */ |
147 |
#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */ |
148 |
#define PORT_CMD_ISSUE 0x38 /* command issue */ |
149 |
#define PORT_RESERVED 0x3c /* reserved */ |
150 |
|
151 |
/* PORT_IRQ_{STAT,MASK} bits */
|
152 |
#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */ |
153 |
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */ |
154 |
#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */ |
155 |
#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */ |
156 |
#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */ |
157 |
#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */ |
158 |
#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */ |
159 |
#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */ |
160 |
|
161 |
#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */ |
162 |
#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */ |
163 |
#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */ |
164 |
#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */ |
165 |
#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */ |
166 |
#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */ |
167 |
#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */ |
168 |
#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */ |
169 |
#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */ |
170 |
|
171 |
#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \
|
172 |
PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \ |
173 |
PORT_IRQ_UNK_FIS) |
174 |
#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \
|
175 |
PORT_IRQ_HBUS_DATA_ERR) |
176 |
#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \
|
177 |
PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \ |
178 |
PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS) |
179 |
|
180 |
/* PORT_CMD bits */
|
181 |
#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */ |
182 |
#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */ |
183 |
#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */ |
184 |
#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */ |
185 |
#define PORT_CMD_CLO (1 << 3) /* Command list override */ |
186 |
#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */ |
187 |
#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */ |
188 |
#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */ |
189 |
|
190 |
#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */ |
191 |
#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */ |
192 |
#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */ |
193 |
#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */ |
194 |
|
195 |
#define PORT_IRQ_STAT_DHRS (1 << 0) /* Device to Host Register FIS */ |
196 |
#define PORT_IRQ_STAT_PSS (1 << 1) /* PIO Setup FIS */ |
197 |
#define PORT_IRQ_STAT_DSS (1 << 2) /* DMA Setup FIS */ |
198 |
#define PORT_IRQ_STAT_SDBS (1 << 3) /* Set Device Bits */ |
199 |
#define PORT_IRQ_STAT_UFS (1 << 4) /* Unknown FIS */ |
200 |
#define PORT_IRQ_STAT_DPS (1 << 5) /* Descriptor Processed */ |
201 |
#define PORT_IRQ_STAT_PCS (1 << 6) /* Port Connect Change Status */ |
202 |
#define PORT_IRQ_STAT_DMPS (1 << 7) /* Device Mechanical Presence |
203 |
Status */
|
204 |
#define PORT_IRQ_STAT_PRCS (1 << 22) /* File Ready Status */ |
205 |
#define PORT_IRQ_STAT_IPMS (1 << 23) /* Incorrect Port Multiplier |
206 |
Status */
|
207 |
#define PORT_IRQ_STAT_OFS (1 << 24) /* Overflow Status */ |
208 |
#define PORT_IRQ_STAT_INFS (1 << 26) /* Interface Non-Fatal Error |
209 |
Status */
|
210 |
#define PORT_IRQ_STAT_IFS (1 << 27) /* Interface Fatal Error */ |
211 |
#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */ |
212 |
#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */ |
213 |
#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */ |
214 |
#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */ |
215 |
|
216 |
/* ap->flags bits */
|
217 |
#define AHCI_FLAG_NO_NCQ (1 << 24) |
218 |
#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */ |
219 |
#define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */ |
220 |
#define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */ |
221 |
#define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */ |
222 |
|
223 |
#define ATA_SRST (1 << 2) /* software reset */ |
224 |
|
225 |
#define STATE_RUN 0 |
226 |
#define STATE_RESET 1 |
227 |
|
228 |
#define SATA_SCR_SSTATUS_DET_NODEV 0x0 |
229 |
#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3 |
230 |
|
231 |
#define SATA_SCR_SSTATUS_SPD_NODEV 0x00 |
232 |
#define SATA_SCR_SSTATUS_SPD_GEN1 0x10 |
233 |
|
234 |
#define SATA_SCR_SSTATUS_IPM_NODEV 0x000 |
235 |
#define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100 |
236 |
|
237 |
#define AHCI_SCR_SCTL_DET 0xf |
238 |
|
239 |
#define SATA_FIS_TYPE_REGISTER_H2D 0x27 |
240 |
#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80 |
241 |
|
242 |
#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f |
243 |
#define AHCI_CMD_HDR_PRDT_LEN 16 |
244 |
|
245 |
#define SATA_SIGNATURE_CDROM 0xeb140000 |
246 |
#define SATA_SIGNATURE_DISK 0x00000101 |
247 |
|
248 |
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20 |
249 |
/* Shouldn't this be 0x2c? */
|
250 |
|
251 |
#define SATA_PORTS 4 |
252 |
|
253 |
#define AHCI_PORT_REGS_START_ADDR 0x100 |
254 |
#define AHCI_PORT_REGS_END_ADDR (AHCI_PORT_REGS_START_ADDR + SATA_PORTS * 0x80) |
255 |
#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f |
256 |
|
257 |
#define AHCI_NUM_COMMAND_SLOTS 31 |
258 |
#define AHCI_SUPPORTED_SPEED 20 |
259 |
#define AHCI_SUPPORTED_SPEED_GEN1 1 |
260 |
#define AHCI_VERSION_1_0 0x10000 |
261 |
|
262 |
#define AHCI_PROGMODE_MAJOR_REV_1 1 |
263 |
|
264 |
#define AHCI_COMMAND_TABLE_ACMD 0x40 |
265 |
|
266 |
#define IDE_FEATURE_DMA 1 |
267 |
|
268 |
#define READ_FPDMA_QUEUED 0x60 |
269 |
#define WRITE_FPDMA_QUEUED 0x61 |
270 |
|
271 |
#define RES_FIS_DSFIS 0x00 |
272 |
#define RES_FIS_PSFIS 0x20 |
273 |
#define RES_FIS_RFIS 0x40 |
274 |
#define RES_FIS_SDBFIS 0x58 |
275 |
#define RES_FIS_UFIS 0x60 |
276 |
|
277 |
typedef struct AHCIControlRegs { |
278 |
uint32_t cap; |
279 |
uint32_t ghc; |
280 |
uint32_t irqstatus; |
281 |
uint32_t impl; |
282 |
uint32_t version; |
283 |
} AHCIControlRegs; |
284 |
|
285 |
typedef struct AHCIPortRegs { |
286 |
uint32_t lst_addr; |
287 |
uint32_t lst_addr_hi; |
288 |
uint32_t fis_addr; |
289 |
uint32_t fis_addr_hi; |
290 |
uint32_t irq_stat; |
291 |
uint32_t irq_mask; |
292 |
uint32_t cmd; |
293 |
uint32_t unused0; |
294 |
uint32_t tfdata; |
295 |
uint32_t sig; |
296 |
uint32_t scr_stat; |
297 |
uint32_t scr_ctl; |
298 |
uint32_t scr_err; |
299 |
uint32_t scr_act; |
300 |
uint32_t cmd_issue; |
301 |
uint32_t reserved; |
302 |
} AHCIPortRegs; |
303 |
|
304 |
typedef struct AHCICmdHdr { |
305 |
uint32_t opts; |
306 |
uint32_t status; |
307 |
uint64_t tbl_addr; |
308 |
uint32_t reserved[4];
|
309 |
} __attribute__ ((packed)) AHCICmdHdr; |
310 |
|
311 |
typedef struct AHCI_SG { |
312 |
uint64_t addr; |
313 |
uint32_t reserved; |
314 |
uint32_t flags_size; |
315 |
} __attribute__ ((packed)) AHCI_SG; |
316 |
|
317 |
typedef struct AHCIDevice AHCIDevice; |
318 |
|
319 |
typedef struct NCQTransferState { |
320 |
AHCIDevice *drive; |
321 |
BlockDriverAIOCB *aiocb; |
322 |
QEMUSGList sglist; |
323 |
int is_read;
|
324 |
uint16_t sector_count; |
325 |
uint64_t lba; |
326 |
uint8_t tag; |
327 |
int slot;
|
328 |
int used;
|
329 |
} NCQTransferState; |
330 |
|
331 |
struct AHCIDevice {
|
332 |
IDEDMA dma; |
333 |
IDEBus port; |
334 |
int port_no;
|
335 |
uint32_t port_state; |
336 |
uint32_t finished; |
337 |
AHCIPortRegs port_regs; |
338 |
struct AHCIState *hba;
|
339 |
QEMUBH *check_bh; |
340 |
uint8_t *lst; |
341 |
uint8_t *res_fis; |
342 |
int dma_status;
|
343 |
int done_atapi_packet;
|
344 |
int busy_slot;
|
345 |
BlockDriverCompletionFunc *dma_cb; |
346 |
AHCICmdHdr *cur_cmd; |
347 |
NCQTransferState ncq_tfs[AHCI_MAX_CMDS]; |
348 |
}; |
349 |
|
350 |
typedef struct AHCIState { |
351 |
AHCIDevice dev[SATA_PORTS]; |
352 |
AHCIControlRegs control_regs; |
353 |
int mem;
|
354 |
qemu_irq irq; |
355 |
} AHCIState; |
356 |
|
357 |
typedef struct AHCIPCIState { |
358 |
PCIDevice card; |
359 |
AHCIState ahci; |
360 |
} AHCIPCIState; |
361 |
|
362 |
typedef struct NCQFrame { |
363 |
uint8_t fis_type; |
364 |
uint8_t c; |
365 |
uint8_t command; |
366 |
uint8_t sector_count_low; |
367 |
uint8_t lba0; |
368 |
uint8_t lba1; |
369 |
uint8_t lba2; |
370 |
uint8_t fua; |
371 |
uint8_t lba3; |
372 |
uint8_t lba4; |
373 |
uint8_t lba5; |
374 |
uint8_t sector_count_high; |
375 |
uint8_t tag; |
376 |
uint8_t reserved5; |
377 |
uint8_t reserved6; |
378 |
uint8_t control; |
379 |
uint8_t reserved7; |
380 |
uint8_t reserved8; |
381 |
uint8_t reserved9; |
382 |
uint8_t reserved10; |
383 |
} __attribute__ ((packed)) NCQFrame; |
384 |
|
385 |
static void check_cmd(AHCIState *s, int port); |
386 |
static int handle_cmd(AHCIState *s,int port,int slot); |
387 |
static void ahci_reset_port(AHCIState *s, int port); |
388 |
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis); |
389 |
|
390 |
static uint32_t ahci_port_read(AHCIState *s, int port, int offset) |
391 |
{ |
392 |
uint32_t val; |
393 |
AHCIPortRegs *pr; |
394 |
pr = &s->dev[port].port_regs; |
395 |
|
396 |
switch (offset) {
|
397 |
case PORT_LST_ADDR:
|
398 |
val = pr->lst_addr; |
399 |
break;
|
400 |
case PORT_LST_ADDR_HI:
|
401 |
val = pr->lst_addr_hi; |
402 |
break;
|
403 |
case PORT_FIS_ADDR:
|
404 |
val = pr->fis_addr; |
405 |
break;
|
406 |
case PORT_FIS_ADDR_HI:
|
407 |
val = pr->fis_addr_hi; |
408 |
break;
|
409 |
case PORT_IRQ_STAT:
|
410 |
val = pr->irq_stat; |
411 |
break;
|
412 |
case PORT_IRQ_MASK:
|
413 |
val = pr->irq_mask; |
414 |
break;
|
415 |
case PORT_CMD:
|
416 |
val = pr->cmd; |
417 |
break;
|
418 |
case PORT_TFDATA:
|
419 |
val = ((uint16_t)s->dev[port].port.ifs[0].error << 8) | |
420 |
s->dev[port].port.ifs[0].status;
|
421 |
break;
|
422 |
case PORT_SIG:
|
423 |
val = pr->sig; |
424 |
break;
|
425 |
case PORT_SCR_STAT:
|
426 |
if (s->dev[port].port.ifs[0].bs) { |
427 |
val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP | |
428 |
SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE; |
429 |
} else {
|
430 |
val = SATA_SCR_SSTATUS_DET_NODEV; |
431 |
} |
432 |
break;
|
433 |
case PORT_SCR_CTL:
|
434 |
val = pr->scr_ctl; |
435 |
break;
|
436 |
case PORT_SCR_ERR:
|
437 |
val = pr->scr_err; |
438 |
break;
|
439 |
case PORT_SCR_ACT:
|
440 |
pr->scr_act &= ~s->dev[port].finished; |
441 |
s->dev[port].finished = 0;
|
442 |
val = pr->scr_act; |
443 |
break;
|
444 |
case PORT_CMD_ISSUE:
|
445 |
val = pr->cmd_issue; |
446 |
break;
|
447 |
case PORT_RESERVED:
|
448 |
default:
|
449 |
val = 0;
|
450 |
} |
451 |
DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
|
452 |
return val;
|
453 |
|
454 |
} |
455 |
|
456 |
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev) |
457 |
{ |
458 |
struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
459 |
|
460 |
DPRINTF(0, "raise irq\n"); |
461 |
|
462 |
if (msi_enabled(&d->card)) {
|
463 |
msi_notify(&d->card, 0);
|
464 |
} else {
|
465 |
qemu_irq_raise(s->irq); |
466 |
} |
467 |
} |
468 |
|
469 |
static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev) |
470 |
{ |
471 |
struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
472 |
|
473 |
DPRINTF(0, "lower irq\n"); |
474 |
|
475 |
if (!msi_enabled(&d->card)) {
|
476 |
qemu_irq_lower(s->irq); |
477 |
} |
478 |
} |
479 |
|
480 |
static void ahci_check_irq(AHCIState *s) |
481 |
{ |
482 |
int i;
|
483 |
|
484 |
DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus); |
485 |
|
486 |
for (i = 0; i < SATA_PORTS; i++) { |
487 |
AHCIPortRegs *pr = &s->dev[i].port_regs; |
488 |
if (pr->irq_stat & pr->irq_mask) {
|
489 |
s->control_regs.irqstatus |= (1 << i);
|
490 |
} |
491 |
} |
492 |
|
493 |
if (s->control_regs.irqstatus &&
|
494 |
(s->control_regs.ghc & HOST_CTL_IRQ_EN)) { |
495 |
ahci_irq_raise(s, NULL);
|
496 |
} else {
|
497 |
ahci_irq_lower(s, NULL);
|
498 |
} |
499 |
} |
500 |
|
501 |
static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d, |
502 |
int irq_type)
|
503 |
{ |
504 |
DPRINTF(d->port_no, "trigger irq %#x -> %x\n",
|
505 |
irq_type, d->port_regs.irq_mask & irq_type); |
506 |
|
507 |
d->port_regs.irq_stat |= irq_type; |
508 |
ahci_check_irq(s); |
509 |
} |
510 |
|
511 |
static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted) |
512 |
{ |
513 |
target_phys_addr_t len = wanted; |
514 |
|
515 |
if (*ptr) {
|
516 |
cpu_physical_memory_unmap(*ptr, 1, len, len);
|
517 |
} |
518 |
|
519 |
*ptr = cpu_physical_memory_map(addr, &len, 1);
|
520 |
if (len < wanted) {
|
521 |
cpu_physical_memory_unmap(*ptr, 1, len, len);
|
522 |
*ptr = NULL;
|
523 |
} |
524 |
} |
525 |
|
526 |
static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) |
527 |
{ |
528 |
AHCIPortRegs *pr = &s->dev[port].port_regs; |
529 |
|
530 |
DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
|
531 |
switch (offset) {
|
532 |
case PORT_LST_ADDR:
|
533 |
pr->lst_addr = val; |
534 |
map_page(&s->dev[port].lst, |
535 |
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024); |
536 |
s->dev[port].cur_cmd = NULL;
|
537 |
break;
|
538 |
case PORT_LST_ADDR_HI:
|
539 |
pr->lst_addr_hi = val; |
540 |
map_page(&s->dev[port].lst, |
541 |
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024); |
542 |
s->dev[port].cur_cmd = NULL;
|
543 |
break;
|
544 |
case PORT_FIS_ADDR:
|
545 |
pr->fis_addr = val; |
546 |
map_page(&s->dev[port].res_fis, |
547 |
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256); |
548 |
break;
|
549 |
case PORT_FIS_ADDR_HI:
|
550 |
pr->fis_addr_hi = val; |
551 |
map_page(&s->dev[port].res_fis, |
552 |
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256); |
553 |
break;
|
554 |
case PORT_IRQ_STAT:
|
555 |
pr->irq_stat &= ~val; |
556 |
break;
|
557 |
case PORT_IRQ_MASK:
|
558 |
pr->irq_mask = val & 0xfdc000ff;
|
559 |
ahci_check_irq(s); |
560 |
break;
|
561 |
case PORT_CMD:
|
562 |
pr->cmd = val & ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON); |
563 |
|
564 |
if (pr->cmd & PORT_CMD_START) {
|
565 |
pr->cmd |= PORT_CMD_LIST_ON; |
566 |
} |
567 |
|
568 |
if (pr->cmd & PORT_CMD_FIS_RX) {
|
569 |
pr->cmd |= PORT_CMD_FIS_ON; |
570 |
} |
571 |
|
572 |
check_cmd(s, port); |
573 |
break;
|
574 |
case PORT_TFDATA:
|
575 |
s->dev[port].port.ifs[0].error = (val >> 8) & 0xff; |
576 |
s->dev[port].port.ifs[0].status = val & 0xff; |
577 |
break;
|
578 |
case PORT_SIG:
|
579 |
pr->sig = val; |
580 |
break;
|
581 |
case PORT_SCR_STAT:
|
582 |
pr->scr_stat = val; |
583 |
break;
|
584 |
case PORT_SCR_CTL:
|
585 |
if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) && |
586 |
((val & AHCI_SCR_SCTL_DET) == 0)) {
|
587 |
ahci_reset_port(s, port); |
588 |
} |
589 |
pr->scr_ctl = val; |
590 |
break;
|
591 |
case PORT_SCR_ERR:
|
592 |
pr->scr_err &= ~val; |
593 |
break;
|
594 |
case PORT_SCR_ACT:
|
595 |
/* RW1 */
|
596 |
pr->scr_act |= val; |
597 |
break;
|
598 |
case PORT_CMD_ISSUE:
|
599 |
pr->cmd_issue |= val; |
600 |
check_cmd(s, port); |
601 |
break;
|
602 |
default:
|
603 |
break;
|
604 |
} |
605 |
} |
606 |
|
607 |
static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr) |
608 |
{ |
609 |
AHCIState *s = ptr; |
610 |
uint32_t val = 0;
|
611 |
|
612 |
addr = addr & 0xfff;
|
613 |
if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
|
614 |
switch (addr) {
|
615 |
case HOST_CAP:
|
616 |
val = s->control_regs.cap; |
617 |
break;
|
618 |
case HOST_CTL:
|
619 |
val = s->control_regs.ghc; |
620 |
break;
|
621 |
case HOST_IRQ_STAT:
|
622 |
val = s->control_regs.irqstatus; |
623 |
break;
|
624 |
case HOST_PORTS_IMPL:
|
625 |
val = s->control_regs.impl; |
626 |
break;
|
627 |
case HOST_VERSION:
|
628 |
val = s->control_regs.version; |
629 |
break;
|
630 |
} |
631 |
|
632 |
DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val); |
633 |
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) && |
634 |
(addr < AHCI_PORT_REGS_END_ADDR)) { |
635 |
val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
|
636 |
addr & AHCI_PORT_ADDR_OFFSET_MASK); |
637 |
} |
638 |
|
639 |
return val;
|
640 |
} |
641 |
|
642 |
|
643 |
|
644 |
static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) |
645 |
{ |
646 |
AHCIState *s = ptr; |
647 |
addr = addr & 0xfff;
|
648 |
|
649 |
/* Only aligned reads are allowed on AHCI */
|
650 |
if (addr & 3) { |
651 |
fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
|
652 |
TARGET_FMT_plx "\n", addr);
|
653 |
return;
|
654 |
} |
655 |
|
656 |
if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
|
657 |
DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val); |
658 |
|
659 |
switch (addr) {
|
660 |
case HOST_CAP: /* R/WO, RO */ |
661 |
/* FIXME handle R/WO */
|
662 |
break;
|
663 |
case HOST_CTL: /* R/W */ |
664 |
if (val & HOST_CTL_RESET) {
|
665 |
DPRINTF(-1, "HBA Reset\n"); |
666 |
/* FIXME reset? */
|
667 |
} else {
|
668 |
s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
|
669 |
ahci_check_irq(s); |
670 |
} |
671 |
break;
|
672 |
case HOST_IRQ_STAT: /* R/WC, RO */ |
673 |
s->control_regs.irqstatus &= ~val; |
674 |
ahci_check_irq(s); |
675 |
break;
|
676 |
case HOST_PORTS_IMPL: /* R/WO, RO */ |
677 |
/* FIXME handle R/WO */
|
678 |
break;
|
679 |
case HOST_VERSION: /* RO */ |
680 |
/* FIXME report write? */
|
681 |
break;
|
682 |
default:
|
683 |
DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr); |
684 |
} |
685 |
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) && |
686 |
(addr < AHCI_PORT_REGS_END_ADDR)) { |
687 |
ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
|
688 |
addr & AHCI_PORT_ADDR_OFFSET_MASK, val); |
689 |
} |
690 |
|
691 |
} |
692 |
|
693 |
static CPUReadMemoryFunc * const ahci_readfn[3]={ |
694 |
ahci_mem_readl, |
695 |
ahci_mem_readl, |
696 |
ahci_mem_readl |
697 |
}; |
698 |
|
699 |
static CPUWriteMemoryFunc * const ahci_writefn[3]={ |
700 |
ahci_mem_writel, |
701 |
ahci_mem_writel, |
702 |
ahci_mem_writel |
703 |
}; |
704 |
|
705 |
static void ahci_reg_init(AHCIState *s) |
706 |
{ |
707 |
int i;
|
708 |
|
709 |
s->control_regs.cap = (SATA_PORTS - 1) |
|
710 |
(AHCI_NUM_COMMAND_SLOTS << 8) |
|
711 |
(AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) | |
712 |
HOST_CAP_NCQ | HOST_CAP_AHCI; |
713 |
|
714 |
s->control_regs.impl = (1 << SATA_PORTS) - 1; |
715 |
|
716 |
s->control_regs.version = AHCI_VERSION_1_0; |
717 |
|
718 |
for (i = 0; i < SATA_PORTS; i++) { |
719 |
s->dev[i].port_state = STATE_RUN; |
720 |
} |
721 |
} |
722 |
|
723 |
static uint32_t read_from_sglist(uint8_t *buffer, uint32_t len,
|
724 |
QEMUSGList *sglist) |
725 |
{ |
726 |
uint32_t i = 0;
|
727 |
uint32_t total = 0, once;
|
728 |
ScatterGatherEntry *cur_prd; |
729 |
uint32_t sgcount; |
730 |
|
731 |
cur_prd = sglist->sg; |
732 |
sgcount = sglist->nsg; |
733 |
for (i = 0; len && sgcount; i++) { |
734 |
once = MIN(cur_prd->len, len); |
735 |
cpu_physical_memory_read(cur_prd->base, buffer, once); |
736 |
cur_prd++; |
737 |
sgcount--; |
738 |
len -= once; |
739 |
buffer += once; |
740 |
total += once; |
741 |
} |
742 |
|
743 |
return total;
|
744 |
} |
745 |
|
746 |
static uint32_t write_to_sglist(uint8_t *buffer, uint32_t len,
|
747 |
QEMUSGList *sglist) |
748 |
{ |
749 |
uint32_t i = 0;
|
750 |
uint32_t total = 0, once;
|
751 |
ScatterGatherEntry *cur_prd; |
752 |
uint32_t sgcount; |
753 |
|
754 |
DPRINTF(-1, "total: 0x%x bytes\n", len); |
755 |
|
756 |
cur_prd = sglist->sg; |
757 |
sgcount = sglist->nsg; |
758 |
for (i = 0; len && sgcount; i++) { |
759 |
once = MIN(cur_prd->len, len); |
760 |
DPRINTF(-1, "write 0x%x bytes to 0x%lx\n", once, (long)cur_prd->base); |
761 |
cpu_physical_memory_write(cur_prd->base, buffer, once); |
762 |
cur_prd++; |
763 |
sgcount--; |
764 |
len -= once; |
765 |
buffer += once; |
766 |
total += once; |
767 |
} |
768 |
|
769 |
return total;
|
770 |
} |
771 |
|
772 |
static void check_cmd(AHCIState *s, int port) |
773 |
{ |
774 |
AHCIPortRegs *pr = &s->dev[port].port_regs; |
775 |
int slot;
|
776 |
|
777 |
if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
|
778 |
for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) { |
779 |
if ((pr->cmd_issue & (1 << slot)) && |
780 |
!handle_cmd(s, port, slot)) { |
781 |
pr->cmd_issue &= ~(1 << slot);
|
782 |
} |
783 |
} |
784 |
} |
785 |
} |
786 |
|
787 |
static void ahci_check_cmd_bh(void *opaque) |
788 |
{ |
789 |
AHCIDevice *ad = opaque; |
790 |
|
791 |
qemu_bh_delete(ad->check_bh); |
792 |
ad->check_bh = NULL;
|
793 |
|
794 |
if ((ad->busy_slot != -1) && |
795 |
!(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
|
796 |
/* no longer busy */
|
797 |
ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
|
798 |
ad->busy_slot = -1;
|
799 |
} |
800 |
|
801 |
check_cmd(ad->hba, ad->port_no); |
802 |
} |
803 |
|
804 |
static void ahci_reset_port(AHCIState *s, int port) |
805 |
{ |
806 |
AHCIDevice *d = &s->dev[port]; |
807 |
AHCIPortRegs *pr = &d->port_regs; |
808 |
IDEState *ide_state = &d->port.ifs[0];
|
809 |
uint8_t init_fis[0x20];
|
810 |
uint32_t tfd; |
811 |
int i;
|
812 |
|
813 |
DPRINTF(port, "reset port\n");
|
814 |
|
815 |
ide_bus_reset(&d->port); |
816 |
ide_state->ncq_queues = AHCI_MAX_CMDS; |
817 |
|
818 |
pr->irq_stat = 0;
|
819 |
pr->irq_mask = 0;
|
820 |
pr->scr_stat = 0;
|
821 |
pr->scr_ctl = 0;
|
822 |
pr->scr_err = 0;
|
823 |
pr->scr_act = 0;
|
824 |
d->busy_slot = -1;
|
825 |
|
826 |
ide_state = &s->dev[port].port.ifs[0];
|
827 |
if (!ide_state->bs) {
|
828 |
return;
|
829 |
} |
830 |
|
831 |
/* reset ncq queue */
|
832 |
for (i = 0; i < AHCI_MAX_CMDS; i++) { |
833 |
NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i]; |
834 |
if (!ncq_tfs->used) {
|
835 |
continue;
|
836 |
} |
837 |
|
838 |
if (ncq_tfs->aiocb) {
|
839 |
bdrv_aio_cancel(ncq_tfs->aiocb); |
840 |
ncq_tfs->aiocb = NULL;
|
841 |
} |
842 |
|
843 |
qemu_sglist_destroy(&ncq_tfs->sglist); |
844 |
ncq_tfs->used = 0;
|
845 |
} |
846 |
|
847 |
memset(init_fis, 0, sizeof(init_fis)); |
848 |
s->dev[port].port_state = STATE_RUN; |
849 |
if (!ide_state->bs) {
|
850 |
s->dev[port].port_regs.sig = 0;
|
851 |
tfd = (1 << 8) | SEEK_STAT | WRERR_STAT; |
852 |
} else if (ide_state->drive_kind == IDE_CD) { |
853 |
s->dev[port].port_regs.sig = SATA_SIGNATURE_CDROM; |
854 |
ide_state->lcyl = 0x14;
|
855 |
ide_state->hcyl = 0xeb;
|
856 |
DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl);
|
857 |
init_fis[5] = ide_state->lcyl;
|
858 |
init_fis[6] = ide_state->hcyl;
|
859 |
ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT; |
860 |
} else {
|
861 |
s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK; |
862 |
ide_state->status = SEEK_STAT | WRERR_STAT; |
863 |
} |
864 |
|
865 |
ide_state->error = 1;
|
866 |
init_fis[4] = 1; |
867 |
init_fis[12] = 1; |
868 |
ahci_write_fis_d2h(d, init_fis); |
869 |
} |
870 |
|
871 |
static void debug_print_fis(uint8_t *fis, int cmd_len) |
872 |
{ |
873 |
#ifdef DEBUG_AHCI
|
874 |
int i;
|
875 |
|
876 |
fprintf(stderr, "fis:");
|
877 |
for (i = 0; i < cmd_len; i++) { |
878 |
if ((i & 0xf) == 0) { |
879 |
fprintf(stderr, "\n%02x:",i);
|
880 |
} |
881 |
fprintf(stderr, "%02x ",fis[i]);
|
882 |
} |
883 |
fprintf(stderr, "\n");
|
884 |
#endif
|
885 |
} |
886 |
|
887 |
static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished) |
888 |
{ |
889 |
AHCIPortRegs *pr = &s->dev[port].port_regs; |
890 |
IDEState *ide_state; |
891 |
uint8_t *sdb_fis; |
892 |
|
893 |
if (!s->dev[port].res_fis ||
|
894 |
!(pr->cmd & PORT_CMD_FIS_RX)) { |
895 |
return;
|
896 |
} |
897 |
|
898 |
sdb_fis = &s->dev[port].res_fis[RES_FIS_SDBFIS]; |
899 |
ide_state = &s->dev[port].port.ifs[0];
|
900 |
|
901 |
/* clear memory */
|
902 |
*(uint32_t*)sdb_fis = 0;
|
903 |
|
904 |
/* write values */
|
905 |
sdb_fis[0] = ide_state->error;
|
906 |
sdb_fis[2] = ide_state->status & 0x77; |
907 |
s->dev[port].finished |= finished; |
908 |
*(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished);
|
909 |
|
910 |
ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_STAT_SDBS); |
911 |
} |
912 |
|
913 |
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) |
914 |
{ |
915 |
AHCIPortRegs *pr = &ad->port_regs; |
916 |
uint8_t *d2h_fis; |
917 |
int i;
|
918 |
target_phys_addr_t cmd_len = 0x80;
|
919 |
int cmd_mapped = 0; |
920 |
|
921 |
if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
|
922 |
return;
|
923 |
} |
924 |
|
925 |
if (!cmd_fis) {
|
926 |
/* map cmd_fis */
|
927 |
uint64_t tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr); |
928 |
cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 0);
|
929 |
cmd_mapped = 1;
|
930 |
} |
931 |
|
932 |
d2h_fis = &ad->res_fis[RES_FIS_RFIS]; |
933 |
|
934 |
d2h_fis[0] = 0x34; |
935 |
d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0); |
936 |
d2h_fis[2] = ad->port.ifs[0].status; |
937 |
d2h_fis[3] = ad->port.ifs[0].error; |
938 |
|
939 |
d2h_fis[4] = cmd_fis[4]; |
940 |
d2h_fis[5] = cmd_fis[5]; |
941 |
d2h_fis[6] = cmd_fis[6]; |
942 |
d2h_fis[7] = cmd_fis[7]; |
943 |
d2h_fis[8] = cmd_fis[8]; |
944 |
d2h_fis[9] = cmd_fis[9]; |
945 |
d2h_fis[10] = cmd_fis[10]; |
946 |
d2h_fis[11] = cmd_fis[11]; |
947 |
d2h_fis[12] = cmd_fis[12]; |
948 |
d2h_fis[13] = cmd_fis[13]; |
949 |
for (i = 14; i < 0x20; i++) { |
950 |
d2h_fis[i] = 0;
|
951 |
} |
952 |
|
953 |
if (d2h_fis[2] & ERR_STAT) { |
954 |
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_TFES); |
955 |
} |
956 |
|
957 |
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS); |
958 |
|
959 |
if (cmd_mapped) {
|
960 |
cpu_physical_memory_unmap(cmd_fis, 0, cmd_len, cmd_len);
|
961 |
} |
962 |
} |
963 |
|
964 |
static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist) |
965 |
{ |
966 |
AHCICmdHdr *cmd = ad->cur_cmd; |
967 |
uint32_t opts = le32_to_cpu(cmd->opts); |
968 |
uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;
|
969 |
int sglist_alloc_hint = opts >> AHCI_CMD_HDR_PRDT_LEN;
|
970 |
target_phys_addr_t prdt_len = (sglist_alloc_hint * sizeof(AHCI_SG));
|
971 |
target_phys_addr_t real_prdt_len = prdt_len; |
972 |
uint8_t *prdt; |
973 |
int i;
|
974 |
int r = 0; |
975 |
|
976 |
if (!sglist_alloc_hint) {
|
977 |
DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
|
978 |
return -1; |
979 |
} |
980 |
|
981 |
/* map PRDT */
|
982 |
if (!(prdt = cpu_physical_memory_map(prdt_addr, &prdt_len, 0))){ |
983 |
DPRINTF(ad->port_no, "map failed\n");
|
984 |
return -1; |
985 |
} |
986 |
|
987 |
if (prdt_len < real_prdt_len) {
|
988 |
DPRINTF(ad->port_no, "mapped less than expected\n");
|
989 |
r = -1;
|
990 |
goto out;
|
991 |
} |
992 |
|
993 |
/* Get entries in the PRDT, init a qemu sglist accordingly */
|
994 |
if (sglist_alloc_hint > 0) { |
995 |
AHCI_SG *tbl = (AHCI_SG *)prdt; |
996 |
|
997 |
qemu_sglist_init(sglist, sglist_alloc_hint); |
998 |
for (i = 0; i < sglist_alloc_hint; i++) { |
999 |
/* flags_size is zero-based */
|
1000 |
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr), |
1001 |
le32_to_cpu(tbl[i].flags_size) + 1);
|
1002 |
} |
1003 |
} |
1004 |
|
1005 |
out:
|
1006 |
cpu_physical_memory_unmap(prdt, 0, prdt_len, prdt_len);
|
1007 |
return r;
|
1008 |
} |
1009 |
|
1010 |
static void ncq_cb(void *opaque, int ret) |
1011 |
{ |
1012 |
NCQTransferState *ncq_tfs = (NCQTransferState *)opaque; |
1013 |
IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
|
1014 |
|
1015 |
/* Clear bit for this tag in SActive */
|
1016 |
ncq_tfs->drive->port_regs.scr_act &= ~(1 << ncq_tfs->tag);
|
1017 |
|
1018 |
if (ret < 0) { |
1019 |
/* error */
|
1020 |
ide_state->error = ABRT_ERR; |
1021 |
ide_state->status = READY_STAT | ERR_STAT; |
1022 |
ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
|
1023 |
} else {
|
1024 |
ide_state->status = READY_STAT | SEEK_STAT; |
1025 |
} |
1026 |
|
1027 |
ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs->drive->port_no, |
1028 |
(1 << ncq_tfs->tag));
|
1029 |
|
1030 |
DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
|
1031 |
ncq_tfs->tag); |
1032 |
|
1033 |
qemu_sglist_destroy(&ncq_tfs->sglist); |
1034 |
ncq_tfs->used = 0;
|
1035 |
} |
1036 |
|
1037 |
static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, |
1038 |
int slot)
|
1039 |
{ |
1040 |
NCQFrame *ncq_fis = (NCQFrame*)cmd_fis; |
1041 |
uint8_t tag = ncq_fis->tag >> 3;
|
1042 |
NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[tag]; |
1043 |
|
1044 |
if (ncq_tfs->used) {
|
1045 |
/* error - already in use */
|
1046 |
fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
|
1047 |
return;
|
1048 |
} |
1049 |
|
1050 |
ncq_tfs->used = 1;
|
1051 |
ncq_tfs->drive = &s->dev[port]; |
1052 |
ncq_tfs->slot = slot; |
1053 |
ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
|
1054 |
((uint64_t)ncq_fis->lba4 << 32) |
|
1055 |
((uint64_t)ncq_fis->lba3 << 24) |
|
1056 |
((uint64_t)ncq_fis->lba2 << 16) |
|
1057 |
((uint64_t)ncq_fis->lba1 << 8) |
|
1058 |
(uint64_t)ncq_fis->lba0; |
1059 |
|
1060 |
/* Note: We calculate the sector count, but don't currently rely on it.
|
1061 |
* The total size of the DMA buffer tells us the transfer size instead. */
|
1062 |
ncq_tfs->sector_count = ((uint16_t)ncq_fis->sector_count_high << 8) |
|
1063 |
ncq_fis->sector_count_low; |
1064 |
|
1065 |
DPRINTF(port, "NCQ transfer LBA from %ld to %ld, drive max %ld\n",
|
1066 |
ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
|
1067 |
s->dev[port].port.ifs[0].nb_sectors - 1); |
1068 |
|
1069 |
ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist); |
1070 |
ncq_tfs->tag = tag; |
1071 |
|
1072 |
switch(ncq_fis->command) {
|
1073 |
case READ_FPDMA_QUEUED:
|
1074 |
DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n",
|
1075 |
ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
|
1076 |
ncq_tfs->is_read = 1;
|
1077 |
|
1078 |
DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba);
|
1079 |
ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs,
|
1080 |
&ncq_tfs->sglist, ncq_tfs->lba, |
1081 |
ncq_cb, ncq_tfs); |
1082 |
break;
|
1083 |
case WRITE_FPDMA_QUEUED:
|
1084 |
DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n",
|
1085 |
ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
|
1086 |
ncq_tfs->is_read = 0;
|
1087 |
|
1088 |
DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba);
|
1089 |
ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs,
|
1090 |
&ncq_tfs->sglist, ncq_tfs->lba, |
1091 |
ncq_cb, ncq_tfs); |
1092 |
break;
|
1093 |
default:
|
1094 |
DPRINTF(port, "error: tried to process non-NCQ command as NCQ\n");
|
1095 |
qemu_sglist_destroy(&ncq_tfs->sglist); |
1096 |
break;
|
1097 |
} |
1098 |
} |
1099 |
|
1100 |
static int handle_cmd(AHCIState *s, int port, int slot) |
1101 |
{ |
1102 |
IDEState *ide_state; |
1103 |
AHCIPortRegs *pr; |
1104 |
uint32_t opts; |
1105 |
uint64_t tbl_addr; |
1106 |
AHCICmdHdr *cmd; |
1107 |
uint8_t *cmd_fis; |
1108 |
target_phys_addr_t cmd_len; |
1109 |
|
1110 |
if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) { |
1111 |
/* Engine currently busy, try again later */
|
1112 |
DPRINTF(port, "engine busy\n");
|
1113 |
return -1; |
1114 |
} |
1115 |
|
1116 |
pr = &s->dev[port].port_regs; |
1117 |
cmd = &((AHCICmdHdr *)s->dev[port].lst)[slot]; |
1118 |
|
1119 |
if (!s->dev[port].lst) {
|
1120 |
DPRINTF(port, "error: lst not given but cmd handled");
|
1121 |
return -1; |
1122 |
} |
1123 |
|
1124 |
/* remember current slot handle for later */
|
1125 |
s->dev[port].cur_cmd = cmd; |
1126 |
|
1127 |
opts = le32_to_cpu(cmd->opts); |
1128 |
tbl_addr = le64_to_cpu(cmd->tbl_addr); |
1129 |
|
1130 |
cmd_len = 0x80;
|
1131 |
cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 1);
|
1132 |
|
1133 |
if (!cmd_fis) {
|
1134 |
DPRINTF(port, "error: guest passed us an invalid cmd fis\n");
|
1135 |
return -1; |
1136 |
} |
1137 |
|
1138 |
/* The device we are working for */
|
1139 |
ide_state = &s->dev[port].port.ifs[0];
|
1140 |
|
1141 |
if (!ide_state->bs) {
|
1142 |
DPRINTF(port, "error: guest accessed unused port");
|
1143 |
goto out;
|
1144 |
} |
1145 |
|
1146 |
debug_print_fis(cmd_fis, 0x90);
|
1147 |
//debug_print_fis(cmd_fis, (opts & AHCI_CMD_HDR_CMD_FIS_LEN) * 4);
|
1148 |
|
1149 |
switch (cmd_fis[0]) { |
1150 |
case SATA_FIS_TYPE_REGISTER_H2D:
|
1151 |
break;
|
1152 |
default:
|
1153 |
DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
|
1154 |
"cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1], |
1155 |
cmd_fis[2]);
|
1156 |
goto out;
|
1157 |
break;
|
1158 |
} |
1159 |
|
1160 |
switch (cmd_fis[1]) { |
1161 |
case SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER:
|
1162 |
break;
|
1163 |
case 0: |
1164 |
break;
|
1165 |
default:
|
1166 |
DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
|
1167 |
"cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1], |
1168 |
cmd_fis[2]);
|
1169 |
goto out;
|
1170 |
break;
|
1171 |
} |
1172 |
|
1173 |
switch (s->dev[port].port_state) {
|
1174 |
case STATE_RUN:
|
1175 |
if (cmd_fis[15] & ATA_SRST) { |
1176 |
s->dev[port].port_state = STATE_RESET; |
1177 |
} |
1178 |
break;
|
1179 |
case STATE_RESET:
|
1180 |
if (!(cmd_fis[15] & ATA_SRST)) { |
1181 |
ahci_reset_port(s, port); |
1182 |
} |
1183 |
break;
|
1184 |
} |
1185 |
|
1186 |
if (cmd_fis[1] == SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER) { |
1187 |
|
1188 |
/* Check for NCQ command */
|
1189 |
if ((cmd_fis[2] == READ_FPDMA_QUEUED) || |
1190 |
(cmd_fis[2] == WRITE_FPDMA_QUEUED)) {
|
1191 |
process_ncq_command(s, port, cmd_fis, slot); |
1192 |
goto out;
|
1193 |
} |
1194 |
|
1195 |
/* Decompose the FIS */
|
1196 |
ide_state->nsector = (int64_t)((cmd_fis[13] << 8) | cmd_fis[12]); |
1197 |
ide_state->feature = cmd_fis[3];
|
1198 |
if (!ide_state->nsector) {
|
1199 |
ide_state->nsector = 256;
|
1200 |
} |
1201 |
|
1202 |
if (ide_state->drive_kind != IDE_CD) {
|
1203 |
ide_set_sector(ide_state, (cmd_fis[6] << 16) | (cmd_fis[5] << 8) | |
1204 |
cmd_fis[4]);
|
1205 |
} |
1206 |
|
1207 |
/* Copy the ACMD field (ATAPI packet, if any) from the AHCI command
|
1208 |
* table to ide_state->io_buffer
|
1209 |
*/
|
1210 |
if (opts & AHCI_CMD_ATAPI) {
|
1211 |
memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10);
|
1212 |
ide_state->lcyl = 0x14;
|
1213 |
ide_state->hcyl = 0xeb;
|
1214 |
debug_print_fis(ide_state->io_buffer, 0x10);
|
1215 |
ide_state->feature = IDE_FEATURE_DMA; |
1216 |
s->dev[port].done_atapi_packet = 0;
|
1217 |
/* XXX send PIO setup FIS */
|
1218 |
} |
1219 |
|
1220 |
ide_state->error = 0;
|
1221 |
|
1222 |
/* Reset transferred byte counter */
|
1223 |
cmd->status = 0;
|
1224 |
|
1225 |
/* We're ready to process the command in FIS byte 2. */
|
1226 |
ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
|
1227 |
|
1228 |
if (s->dev[port].port.ifs[0].status & READY_STAT) { |
1229 |
ahci_write_fis_d2h(&s->dev[port], cmd_fis); |
1230 |
} |
1231 |
} |
1232 |
|
1233 |
out:
|
1234 |
cpu_physical_memory_unmap(cmd_fis, 1, cmd_len, cmd_len);
|
1235 |
|
1236 |
if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) { |
1237 |
/* async command, complete later */
|
1238 |
s->dev[port].busy_slot = slot; |
1239 |
return -1; |
1240 |
} |
1241 |
|
1242 |
/* done handling the command */
|
1243 |
return 0; |
1244 |
} |
1245 |
|
1246 |
/* DMA dev <-> ram */
|
1247 |
static int ahci_start_transfer(IDEDMA *dma) |
1248 |
{ |
1249 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1250 |
IDEState *s = &ad->port.ifs[0];
|
1251 |
uint32_t size = (uint32_t)(s->data_end - s->data_ptr); |
1252 |
/* write == ram -> device */
|
1253 |
uint32_t opts = le32_to_cpu(ad->cur_cmd->opts); |
1254 |
int is_write = opts & AHCI_CMD_WRITE;
|
1255 |
int is_atapi = opts & AHCI_CMD_ATAPI;
|
1256 |
int has_sglist = 0; |
1257 |
|
1258 |
if (is_atapi && !ad->done_atapi_packet) {
|
1259 |
/* already prepopulated iobuffer */
|
1260 |
ad->done_atapi_packet = 1;
|
1261 |
goto out;
|
1262 |
} |
1263 |
|
1264 |
if (!ahci_populate_sglist(ad, &s->sg)) {
|
1265 |
has_sglist = 1;
|
1266 |
} |
1267 |
|
1268 |
DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n",
|
1269 |
is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata", |
1270 |
has_sglist ? "" : "o"); |
1271 |
|
1272 |
if (is_write && has_sglist && (s->data_ptr < s->data_end)) {
|
1273 |
read_from_sglist(s->data_ptr, size, &s->sg); |
1274 |
} |
1275 |
|
1276 |
if (!is_write && has_sglist && (s->data_ptr < s->data_end)) {
|
1277 |
write_to_sglist(s->data_ptr, size, &s->sg); |
1278 |
} |
1279 |
|
1280 |
/* update number of transferred bytes */
|
1281 |
ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + size); |
1282 |
|
1283 |
out:
|
1284 |
/* declare that we processed everything */
|
1285 |
s->data_ptr = s->data_end; |
1286 |
|
1287 |
if (has_sglist) {
|
1288 |
qemu_sglist_destroy(&s->sg); |
1289 |
} |
1290 |
|
1291 |
s->end_transfer_func(s); |
1292 |
|
1293 |
if (!(s->status & DRQ_STAT)) {
|
1294 |
/* done with DMA */
|
1295 |
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS); |
1296 |
} |
1297 |
|
1298 |
return 0; |
1299 |
} |
1300 |
|
1301 |
static void ahci_start_dma(IDEDMA *dma, IDEState *s, |
1302 |
BlockDriverCompletionFunc *dma_cb) |
1303 |
{ |
1304 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1305 |
|
1306 |
DPRINTF(ad->port_no, "\n");
|
1307 |
ad->dma_cb = dma_cb; |
1308 |
ad->dma_status |= BM_STATUS_DMAING; |
1309 |
dma_cb(s, 0);
|
1310 |
} |
1311 |
|
1312 |
static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write) |
1313 |
{ |
1314 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1315 |
IDEState *s = &ad->port.ifs[0];
|
1316 |
int i;
|
1317 |
|
1318 |
ahci_populate_sglist(ad, &s->sg); |
1319 |
|
1320 |
s->io_buffer_size = 0;
|
1321 |
for (i = 0; i < s->sg.nsg; i++) { |
1322 |
s->io_buffer_size += s->sg.sg[i].len; |
1323 |
} |
1324 |
|
1325 |
DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
|
1326 |
return s->io_buffer_size != 0; |
1327 |
} |
1328 |
|
1329 |
static int ahci_dma_rw_buf(IDEDMA *dma, int is_write) |
1330 |
{ |
1331 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1332 |
IDEState *s = &ad->port.ifs[0];
|
1333 |
uint8_t *p = s->io_buffer + s->io_buffer_index; |
1334 |
int l = s->io_buffer_size - s->io_buffer_index;
|
1335 |
|
1336 |
if (ahci_populate_sglist(ad, &s->sg)) {
|
1337 |
return 0; |
1338 |
} |
1339 |
|
1340 |
if (is_write) {
|
1341 |
write_to_sglist(p, l, &s->sg); |
1342 |
} else {
|
1343 |
read_from_sglist(p, l, &s->sg); |
1344 |
} |
1345 |
|
1346 |
/* update number of transferred bytes */
|
1347 |
ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l); |
1348 |
s->io_buffer_index += l; |
1349 |
|
1350 |
DPRINTF(ad->port_no, "len=%#x\n", l);
|
1351 |
|
1352 |
return 1; |
1353 |
} |
1354 |
|
1355 |
static int ahci_dma_set_unit(IDEDMA *dma, int unit) |
1356 |
{ |
1357 |
/* only a single unit per link */
|
1358 |
return 0; |
1359 |
} |
1360 |
|
1361 |
static int ahci_dma_add_status(IDEDMA *dma, int status) |
1362 |
{ |
1363 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1364 |
ad->dma_status |= status; |
1365 |
DPRINTF(ad->port_no, "set status: %x\n", status);
|
1366 |
|
1367 |
if (status & BM_STATUS_INT) {
|
1368 |
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS); |
1369 |
} |
1370 |
|
1371 |
return 0; |
1372 |
} |
1373 |
|
1374 |
static int ahci_dma_set_inactive(IDEDMA *dma) |
1375 |
{ |
1376 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1377 |
|
1378 |
DPRINTF(ad->port_no, "dma done\n");
|
1379 |
|
1380 |
/* update d2h status */
|
1381 |
ahci_write_fis_d2h(ad, NULL);
|
1382 |
|
1383 |
ad->dma_cb = NULL;
|
1384 |
|
1385 |
/* maybe we still have something to process, check later */
|
1386 |
ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad); |
1387 |
qemu_bh_schedule(ad->check_bh); |
1388 |
|
1389 |
return 0; |
1390 |
} |
1391 |
|
1392 |
static void ahci_irq_set(void *opaque, int n, int level) |
1393 |
{ |
1394 |
} |
1395 |
|
1396 |
static void ahci_dma_restart_cb(void *opaque, int running, int reason) |
1397 |
{ |
1398 |
} |
1399 |
|
1400 |
static int ahci_dma_reset(IDEDMA *dma) |
1401 |
{ |
1402 |
return 0; |
1403 |
} |
1404 |
|
1405 |
static const IDEDMAOps ahci_dma_ops = { |
1406 |
.start_dma = ahci_start_dma, |
1407 |
.start_transfer = ahci_start_transfer, |
1408 |
.prepare_buf = ahci_dma_prepare_buf, |
1409 |
.rw_buf = ahci_dma_rw_buf, |
1410 |
.set_unit = ahci_dma_set_unit, |
1411 |
.add_status = ahci_dma_add_status, |
1412 |
.set_inactive = ahci_dma_set_inactive, |
1413 |
.restart_cb = ahci_dma_restart_cb, |
1414 |
.reset = ahci_dma_reset, |
1415 |
}; |
1416 |
|
1417 |
static void ahci_init(AHCIState *s, DeviceState *qdev) |
1418 |
{ |
1419 |
qemu_irq *irqs; |
1420 |
int i;
|
1421 |
|
1422 |
ahci_reg_init(s); |
1423 |
s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s, |
1424 |
DEVICE_LITTLE_ENDIAN); |
1425 |
irqs = qemu_allocate_irqs(ahci_irq_set, s, SATA_PORTS); |
1426 |
|
1427 |
for (i = 0; i < SATA_PORTS; i++) { |
1428 |
AHCIDevice *ad = &s->dev[i]; |
1429 |
|
1430 |
ide_bus_new(&ad->port, qdev, i); |
1431 |
ide_init2(&ad->port, irqs[i]); |
1432 |
|
1433 |
ad->hba = s; |
1434 |
ad->port_no = i; |
1435 |
ad->port.dma = &ad->dma; |
1436 |
ad->port.dma->ops = &ahci_dma_ops; |
1437 |
ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON; |
1438 |
} |
1439 |
} |
1440 |
|
1441 |
static void ahci_pci_map(PCIDevice *pci_dev, int region_num, |
1442 |
pcibus_t addr, pcibus_t size, int type)
|
1443 |
{ |
1444 |
struct AHCIPCIState *d = (struct AHCIPCIState *)pci_dev; |
1445 |
AHCIState *s = &d->ahci; |
1446 |
|
1447 |
cpu_register_physical_memory(addr, size, s->mem); |
1448 |
} |
1449 |
|
1450 |
static void ahci_reset(void *opaque) |
1451 |
{ |
1452 |
struct AHCIPCIState *d = opaque;
|
1453 |
int i;
|
1454 |
|
1455 |
for (i = 0; i < SATA_PORTS; i++) { |
1456 |
ahci_reset_port(&d->ahci, i); |
1457 |
} |
1458 |
} |
1459 |
|
1460 |
static int pci_ahci_init(PCIDevice *dev) |
1461 |
{ |
1462 |
struct AHCIPCIState *d;
|
1463 |
d = DO_UPCAST(struct AHCIPCIState, card, dev);
|
1464 |
|
1465 |
pci_config_set_vendor_id(d->card.config, PCI_VENDOR_ID_INTEL); |
1466 |
pci_config_set_device_id(d->card.config, PCI_DEVICE_ID_INTEL_82801IR); |
1467 |
|
1468 |
pci_config_set_class(d->card.config, PCI_CLASS_STORAGE_SATA); |
1469 |
pci_config_set_revision(d->card.config, 0x02);
|
1470 |
pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1); |
1471 |
|
1472 |
d->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */ |
1473 |
d->card.config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */ |
1474 |
pci_config_set_interrupt_pin(d->card.config, 1);
|
1475 |
|
1476 |
qemu_register_reset(ahci_reset, d); |
1477 |
|
1478 |
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
|
1479 |
pci_register_bar(&d->card, 5, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY, |
1480 |
ahci_pci_map); |
1481 |
|
1482 |
msi_init(dev, 0x50, 1, true, false); |
1483 |
|
1484 |
ahci_init(&d->ahci, &dev->qdev); |
1485 |
d->ahci.irq = d->card.irq[0];
|
1486 |
|
1487 |
return 0; |
1488 |
} |
1489 |
|
1490 |
static int pci_ahci_uninit(PCIDevice *dev) |
1491 |
{ |
1492 |
struct AHCIPCIState *d;
|
1493 |
d = DO_UPCAST(struct AHCIPCIState, card, dev);
|
1494 |
|
1495 |
if (msi_enabled(dev)) {
|
1496 |
msi_uninit(dev); |
1497 |
} |
1498 |
|
1499 |
qemu_unregister_reset(ahci_reset, d); |
1500 |
|
1501 |
return 0; |
1502 |
} |
1503 |
|
1504 |
static void pci_ahci_write_config(PCIDevice *pci, uint32_t addr, |
1505 |
uint32_t val, int len)
|
1506 |
{ |
1507 |
pci_default_write_config(pci, addr, val, len); |
1508 |
msi_write_config(pci, addr, val, len); |
1509 |
} |
1510 |
|
1511 |
static PCIDeviceInfo ahci_info = {
|
1512 |
.qdev.name = "ahci",
|
1513 |
.qdev.size = sizeof(AHCIPCIState),
|
1514 |
.init = pci_ahci_init, |
1515 |
.exit = pci_ahci_uninit, |
1516 |
.config_write = pci_ahci_write_config, |
1517 |
}; |
1518 |
|
1519 |
static void ahci_pci_register_devices(void) |
1520 |
{ |
1521 |
pci_qdev_register(&ahci_info); |
1522 |
} |
1523 |
|
1524 |
device_init(ahci_pci_register_devices) |