root / hw / ide / ahci.c @ df32fd1c
History | View | Annotate | Download (38.7 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 |
|
24 |
#include <hw/hw.h> |
25 |
#include <hw/pci/msi.h> |
26 |
#include <hw/i386/pc.h> |
27 |
#include <hw/pci/pci.h> |
28 |
#include <hw/sysbus.h> |
29 |
|
30 |
#include "monitor/monitor.h" |
31 |
#include "sysemu/dma.h" |
32 |
#include "internal.h" |
33 |
#include <hw/ide/pci.h> |
34 |
#include <hw/ide/ahci.h> |
35 |
|
36 |
/* #define DEBUG_AHCI */
|
37 |
|
38 |
#ifdef DEBUG_AHCI
|
39 |
#define DPRINTF(port, fmt, ...) \
|
40 |
do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \ |
41 |
fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) |
42 |
#else
|
43 |
#define DPRINTF(port, fmt, ...) do {} while(0) |
44 |
#endif
|
45 |
|
46 |
static void check_cmd(AHCIState *s, int port); |
47 |
static int handle_cmd(AHCIState *s,int port,int slot); |
48 |
static void ahci_reset_port(AHCIState *s, int port); |
49 |
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis); |
50 |
static void ahci_init_d2h(AHCIDevice *ad); |
51 |
|
52 |
static uint32_t ahci_port_read(AHCIState *s, int port, int offset) |
53 |
{ |
54 |
uint32_t val; |
55 |
AHCIPortRegs *pr; |
56 |
pr = &s->dev[port].port_regs; |
57 |
|
58 |
switch (offset) {
|
59 |
case PORT_LST_ADDR:
|
60 |
val = pr->lst_addr; |
61 |
break;
|
62 |
case PORT_LST_ADDR_HI:
|
63 |
val = pr->lst_addr_hi; |
64 |
break;
|
65 |
case PORT_FIS_ADDR:
|
66 |
val = pr->fis_addr; |
67 |
break;
|
68 |
case PORT_FIS_ADDR_HI:
|
69 |
val = pr->fis_addr_hi; |
70 |
break;
|
71 |
case PORT_IRQ_STAT:
|
72 |
val = pr->irq_stat; |
73 |
break;
|
74 |
case PORT_IRQ_MASK:
|
75 |
val = pr->irq_mask; |
76 |
break;
|
77 |
case PORT_CMD:
|
78 |
val = pr->cmd; |
79 |
break;
|
80 |
case PORT_TFDATA:
|
81 |
val = ((uint16_t)s->dev[port].port.ifs[0].error << 8) | |
82 |
s->dev[port].port.ifs[0].status;
|
83 |
break;
|
84 |
case PORT_SIG:
|
85 |
val = pr->sig; |
86 |
break;
|
87 |
case PORT_SCR_STAT:
|
88 |
if (s->dev[port].port.ifs[0].bs) { |
89 |
val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP | |
90 |
SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE; |
91 |
} else {
|
92 |
val = SATA_SCR_SSTATUS_DET_NODEV; |
93 |
} |
94 |
break;
|
95 |
case PORT_SCR_CTL:
|
96 |
val = pr->scr_ctl; |
97 |
break;
|
98 |
case PORT_SCR_ERR:
|
99 |
val = pr->scr_err; |
100 |
break;
|
101 |
case PORT_SCR_ACT:
|
102 |
pr->scr_act &= ~s->dev[port].finished; |
103 |
s->dev[port].finished = 0;
|
104 |
val = pr->scr_act; |
105 |
break;
|
106 |
case PORT_CMD_ISSUE:
|
107 |
val = pr->cmd_issue; |
108 |
break;
|
109 |
case PORT_RESERVED:
|
110 |
default:
|
111 |
val = 0;
|
112 |
} |
113 |
DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
|
114 |
return val;
|
115 |
|
116 |
} |
117 |
|
118 |
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev) |
119 |
{ |
120 |
struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
121 |
|
122 |
DPRINTF(0, "raise irq\n"); |
123 |
|
124 |
if (msi_enabled(&d->card)) {
|
125 |
msi_notify(&d->card, 0);
|
126 |
} else {
|
127 |
qemu_irq_raise(s->irq); |
128 |
} |
129 |
} |
130 |
|
131 |
static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev) |
132 |
{ |
133 |
struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
134 |
|
135 |
DPRINTF(0, "lower irq\n"); |
136 |
|
137 |
if (!msi_enabled(&d->card)) {
|
138 |
qemu_irq_lower(s->irq); |
139 |
} |
140 |
} |
141 |
|
142 |
static void ahci_check_irq(AHCIState *s) |
143 |
{ |
144 |
int i;
|
145 |
|
146 |
DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus); |
147 |
|
148 |
s->control_regs.irqstatus = 0;
|
149 |
for (i = 0; i < s->ports; i++) { |
150 |
AHCIPortRegs *pr = &s->dev[i].port_regs; |
151 |
if (pr->irq_stat & pr->irq_mask) {
|
152 |
s->control_regs.irqstatus |= (1 << i);
|
153 |
} |
154 |
} |
155 |
|
156 |
if (s->control_regs.irqstatus &&
|
157 |
(s->control_regs.ghc & HOST_CTL_IRQ_EN)) { |
158 |
ahci_irq_raise(s, NULL);
|
159 |
} else {
|
160 |
ahci_irq_lower(s, NULL);
|
161 |
} |
162 |
} |
163 |
|
164 |
static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d, |
165 |
int irq_type)
|
166 |
{ |
167 |
DPRINTF(d->port_no, "trigger irq %#x -> %x\n",
|
168 |
irq_type, d->port_regs.irq_mask & irq_type); |
169 |
|
170 |
d->port_regs.irq_stat |= irq_type; |
171 |
ahci_check_irq(s); |
172 |
} |
173 |
|
174 |
static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted) |
175 |
{ |
176 |
hwaddr len = wanted; |
177 |
|
178 |
if (*ptr) {
|
179 |
cpu_physical_memory_unmap(*ptr, len, 1, len);
|
180 |
} |
181 |
|
182 |
*ptr = cpu_physical_memory_map(addr, &len, 1);
|
183 |
if (len < wanted) {
|
184 |
cpu_physical_memory_unmap(*ptr, len, 1, len);
|
185 |
*ptr = NULL;
|
186 |
} |
187 |
} |
188 |
|
189 |
static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) |
190 |
{ |
191 |
AHCIPortRegs *pr = &s->dev[port].port_regs; |
192 |
|
193 |
DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
|
194 |
switch (offset) {
|
195 |
case PORT_LST_ADDR:
|
196 |
pr->lst_addr = val; |
197 |
map_page(&s->dev[port].lst, |
198 |
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024); |
199 |
s->dev[port].cur_cmd = NULL;
|
200 |
break;
|
201 |
case PORT_LST_ADDR_HI:
|
202 |
pr->lst_addr_hi = val; |
203 |
map_page(&s->dev[port].lst, |
204 |
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024); |
205 |
s->dev[port].cur_cmd = NULL;
|
206 |
break;
|
207 |
case PORT_FIS_ADDR:
|
208 |
pr->fis_addr = val; |
209 |
map_page(&s->dev[port].res_fis, |
210 |
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256); |
211 |
break;
|
212 |
case PORT_FIS_ADDR_HI:
|
213 |
pr->fis_addr_hi = val; |
214 |
map_page(&s->dev[port].res_fis, |
215 |
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256); |
216 |
break;
|
217 |
case PORT_IRQ_STAT:
|
218 |
pr->irq_stat &= ~val; |
219 |
ahci_check_irq(s); |
220 |
break;
|
221 |
case PORT_IRQ_MASK:
|
222 |
pr->irq_mask = val & 0xfdc000ff;
|
223 |
ahci_check_irq(s); |
224 |
break;
|
225 |
case PORT_CMD:
|
226 |
pr->cmd = val & ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON); |
227 |
|
228 |
if (pr->cmd & PORT_CMD_START) {
|
229 |
pr->cmd |= PORT_CMD_LIST_ON; |
230 |
} |
231 |
|
232 |
if (pr->cmd & PORT_CMD_FIS_RX) {
|
233 |
pr->cmd |= PORT_CMD_FIS_ON; |
234 |
} |
235 |
|
236 |
/* XXX usually the FIS would be pending on the bus here and
|
237 |
issuing deferred until the OS enables FIS receival.
|
238 |
Instead, we only submit it once - which works in most
|
239 |
cases, but is a hack. */
|
240 |
if ((pr->cmd & PORT_CMD_FIS_ON) &&
|
241 |
!s->dev[port].init_d2h_sent) { |
242 |
ahci_init_d2h(&s->dev[port]); |
243 |
s->dev[port].init_d2h_sent = true;
|
244 |
} |
245 |
|
246 |
check_cmd(s, port); |
247 |
break;
|
248 |
case PORT_TFDATA:
|
249 |
s->dev[port].port.ifs[0].error = (val >> 8) & 0xff; |
250 |
s->dev[port].port.ifs[0].status = val & 0xff; |
251 |
break;
|
252 |
case PORT_SIG:
|
253 |
pr->sig = val; |
254 |
break;
|
255 |
case PORT_SCR_STAT:
|
256 |
pr->scr_stat = val; |
257 |
break;
|
258 |
case PORT_SCR_CTL:
|
259 |
if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) && |
260 |
((val & AHCI_SCR_SCTL_DET) == 0)) {
|
261 |
ahci_reset_port(s, port); |
262 |
} |
263 |
pr->scr_ctl = val; |
264 |
break;
|
265 |
case PORT_SCR_ERR:
|
266 |
pr->scr_err &= ~val; |
267 |
break;
|
268 |
case PORT_SCR_ACT:
|
269 |
/* RW1 */
|
270 |
pr->scr_act |= val; |
271 |
break;
|
272 |
case PORT_CMD_ISSUE:
|
273 |
pr->cmd_issue |= val; |
274 |
check_cmd(s, port); |
275 |
break;
|
276 |
default:
|
277 |
break;
|
278 |
} |
279 |
} |
280 |
|
281 |
static uint64_t ahci_mem_read(void *opaque, hwaddr addr, |
282 |
unsigned size)
|
283 |
{ |
284 |
AHCIState *s = opaque; |
285 |
uint32_t val = 0;
|
286 |
|
287 |
if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
|
288 |
switch (addr) {
|
289 |
case HOST_CAP:
|
290 |
val = s->control_regs.cap; |
291 |
break;
|
292 |
case HOST_CTL:
|
293 |
val = s->control_regs.ghc; |
294 |
break;
|
295 |
case HOST_IRQ_STAT:
|
296 |
val = s->control_regs.irqstatus; |
297 |
break;
|
298 |
case HOST_PORTS_IMPL:
|
299 |
val = s->control_regs.impl; |
300 |
break;
|
301 |
case HOST_VERSION:
|
302 |
val = s->control_regs.version; |
303 |
break;
|
304 |
} |
305 |
|
306 |
DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val); |
307 |
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) && |
308 |
(addr < (AHCI_PORT_REGS_START_ADDR + |
309 |
(s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) { |
310 |
val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
|
311 |
addr & AHCI_PORT_ADDR_OFFSET_MASK); |
312 |
} |
313 |
|
314 |
return val;
|
315 |
} |
316 |
|
317 |
|
318 |
|
319 |
static void ahci_mem_write(void *opaque, hwaddr addr, |
320 |
uint64_t val, unsigned size)
|
321 |
{ |
322 |
AHCIState *s = opaque; |
323 |
|
324 |
/* Only aligned reads are allowed on AHCI */
|
325 |
if (addr & 3) { |
326 |
fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
|
327 |
TARGET_FMT_plx "\n", addr);
|
328 |
return;
|
329 |
} |
330 |
|
331 |
if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
|
332 |
DPRINTF(-1, "(addr 0x%08X), val 0x%08"PRIX64"\n", (unsigned) addr, val); |
333 |
|
334 |
switch (addr) {
|
335 |
case HOST_CAP: /* R/WO, RO */ |
336 |
/* FIXME handle R/WO */
|
337 |
break;
|
338 |
case HOST_CTL: /* R/W */ |
339 |
if (val & HOST_CTL_RESET) {
|
340 |
DPRINTF(-1, "HBA Reset\n"); |
341 |
ahci_reset(s); |
342 |
} else {
|
343 |
s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
|
344 |
ahci_check_irq(s); |
345 |
} |
346 |
break;
|
347 |
case HOST_IRQ_STAT: /* R/WC, RO */ |
348 |
s->control_regs.irqstatus &= ~val; |
349 |
ahci_check_irq(s); |
350 |
break;
|
351 |
case HOST_PORTS_IMPL: /* R/WO, RO */ |
352 |
/* FIXME handle R/WO */
|
353 |
break;
|
354 |
case HOST_VERSION: /* RO */ |
355 |
/* FIXME report write? */
|
356 |
break;
|
357 |
default:
|
358 |
DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr); |
359 |
} |
360 |
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) && |
361 |
(addr < (AHCI_PORT_REGS_START_ADDR + |
362 |
(s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) { |
363 |
ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
|
364 |
addr & AHCI_PORT_ADDR_OFFSET_MASK, val); |
365 |
} |
366 |
|
367 |
} |
368 |
|
369 |
static const MemoryRegionOps ahci_mem_ops = { |
370 |
.read = ahci_mem_read, |
371 |
.write = ahci_mem_write, |
372 |
.endianness = DEVICE_LITTLE_ENDIAN, |
373 |
}; |
374 |
|
375 |
static uint64_t ahci_idp_read(void *opaque, hwaddr addr, |
376 |
unsigned size)
|
377 |
{ |
378 |
AHCIState *s = opaque; |
379 |
|
380 |
if (addr == s->idp_offset) {
|
381 |
/* index register */
|
382 |
return s->idp_index;
|
383 |
} else if (addr == s->idp_offset + 4) { |
384 |
/* data register - do memory read at location selected by index */
|
385 |
return ahci_mem_read(opaque, s->idp_index, size);
|
386 |
} else {
|
387 |
return 0; |
388 |
} |
389 |
} |
390 |
|
391 |
static void ahci_idp_write(void *opaque, hwaddr addr, |
392 |
uint64_t val, unsigned size)
|
393 |
{ |
394 |
AHCIState *s = opaque; |
395 |
|
396 |
if (addr == s->idp_offset) {
|
397 |
/* index register - mask off reserved bits */
|
398 |
s->idp_index = (uint32_t)val & ((AHCI_MEM_BAR_SIZE - 1) & ~3); |
399 |
} else if (addr == s->idp_offset + 4) { |
400 |
/* data register - do memory write at location selected by index */
|
401 |
ahci_mem_write(opaque, s->idp_index, val, size); |
402 |
} |
403 |
} |
404 |
|
405 |
static const MemoryRegionOps ahci_idp_ops = { |
406 |
.read = ahci_idp_read, |
407 |
.write = ahci_idp_write, |
408 |
.endianness = DEVICE_LITTLE_ENDIAN, |
409 |
}; |
410 |
|
411 |
|
412 |
static void ahci_reg_init(AHCIState *s) |
413 |
{ |
414 |
int i;
|
415 |
|
416 |
s->control_regs.cap = (s->ports - 1) |
|
417 |
(AHCI_NUM_COMMAND_SLOTS << 8) |
|
418 |
(AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) | |
419 |
HOST_CAP_NCQ | HOST_CAP_AHCI; |
420 |
|
421 |
s->control_regs.impl = (1 << s->ports) - 1; |
422 |
|
423 |
s->control_regs.version = AHCI_VERSION_1_0; |
424 |
|
425 |
for (i = 0; i < s->ports; i++) { |
426 |
s->dev[i].port_state = STATE_RUN; |
427 |
} |
428 |
} |
429 |
|
430 |
static void check_cmd(AHCIState *s, int port) |
431 |
{ |
432 |
AHCIPortRegs *pr = &s->dev[port].port_regs; |
433 |
int slot;
|
434 |
|
435 |
if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
|
436 |
for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) { |
437 |
if ((pr->cmd_issue & (1 << slot)) && |
438 |
!handle_cmd(s, port, slot)) { |
439 |
pr->cmd_issue &= ~(1 << slot);
|
440 |
} |
441 |
} |
442 |
} |
443 |
} |
444 |
|
445 |
static void ahci_check_cmd_bh(void *opaque) |
446 |
{ |
447 |
AHCIDevice *ad = opaque; |
448 |
|
449 |
qemu_bh_delete(ad->check_bh); |
450 |
ad->check_bh = NULL;
|
451 |
|
452 |
if ((ad->busy_slot != -1) && |
453 |
!(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
|
454 |
/* no longer busy */
|
455 |
ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
|
456 |
ad->busy_slot = -1;
|
457 |
} |
458 |
|
459 |
check_cmd(ad->hba, ad->port_no); |
460 |
} |
461 |
|
462 |
static void ahci_init_d2h(AHCIDevice *ad) |
463 |
{ |
464 |
uint8_t init_fis[20];
|
465 |
IDEState *ide_state = &ad->port.ifs[0];
|
466 |
|
467 |
memset(init_fis, 0, sizeof(init_fis)); |
468 |
|
469 |
init_fis[4] = 1; |
470 |
init_fis[12] = 1; |
471 |
|
472 |
if (ide_state->drive_kind == IDE_CD) {
|
473 |
init_fis[5] = ide_state->lcyl;
|
474 |
init_fis[6] = ide_state->hcyl;
|
475 |
} |
476 |
|
477 |
ahci_write_fis_d2h(ad, init_fis); |
478 |
} |
479 |
|
480 |
static void ahci_reset_port(AHCIState *s, int port) |
481 |
{ |
482 |
AHCIDevice *d = &s->dev[port]; |
483 |
AHCIPortRegs *pr = &d->port_regs; |
484 |
IDEState *ide_state = &d->port.ifs[0];
|
485 |
int i;
|
486 |
|
487 |
DPRINTF(port, "reset port\n");
|
488 |
|
489 |
ide_bus_reset(&d->port); |
490 |
ide_state->ncq_queues = AHCI_MAX_CMDS; |
491 |
|
492 |
pr->scr_stat = 0;
|
493 |
pr->scr_err = 0;
|
494 |
pr->scr_act = 0;
|
495 |
d->busy_slot = -1;
|
496 |
d->init_d2h_sent = false;
|
497 |
|
498 |
ide_state = &s->dev[port].port.ifs[0];
|
499 |
if (!ide_state->bs) {
|
500 |
return;
|
501 |
} |
502 |
|
503 |
/* reset ncq queue */
|
504 |
for (i = 0; i < AHCI_MAX_CMDS; i++) { |
505 |
NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i]; |
506 |
if (!ncq_tfs->used) {
|
507 |
continue;
|
508 |
} |
509 |
|
510 |
if (ncq_tfs->aiocb) {
|
511 |
bdrv_aio_cancel(ncq_tfs->aiocb); |
512 |
ncq_tfs->aiocb = NULL;
|
513 |
} |
514 |
|
515 |
/* Maybe we just finished the request thanks to bdrv_aio_cancel() */
|
516 |
if (!ncq_tfs->used) {
|
517 |
continue;
|
518 |
} |
519 |
|
520 |
qemu_sglist_destroy(&ncq_tfs->sglist); |
521 |
ncq_tfs->used = 0;
|
522 |
} |
523 |
|
524 |
s->dev[port].port_state = STATE_RUN; |
525 |
if (!ide_state->bs) {
|
526 |
s->dev[port].port_regs.sig = 0;
|
527 |
ide_state->status = SEEK_STAT | WRERR_STAT; |
528 |
} else if (ide_state->drive_kind == IDE_CD) { |
529 |
s->dev[port].port_regs.sig = SATA_SIGNATURE_CDROM; |
530 |
ide_state->lcyl = 0x14;
|
531 |
ide_state->hcyl = 0xeb;
|
532 |
DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl);
|
533 |
ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT; |
534 |
} else {
|
535 |
s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK; |
536 |
ide_state->status = SEEK_STAT | WRERR_STAT; |
537 |
} |
538 |
|
539 |
ide_state->error = 1;
|
540 |
ahci_init_d2h(d); |
541 |
} |
542 |
|
543 |
static void debug_print_fis(uint8_t *fis, int cmd_len) |
544 |
{ |
545 |
#ifdef DEBUG_AHCI
|
546 |
int i;
|
547 |
|
548 |
fprintf(stderr, "fis:");
|
549 |
for (i = 0; i < cmd_len; i++) { |
550 |
if ((i & 0xf) == 0) { |
551 |
fprintf(stderr, "\n%02x:",i);
|
552 |
} |
553 |
fprintf(stderr, "%02x ",fis[i]);
|
554 |
} |
555 |
fprintf(stderr, "\n");
|
556 |
#endif
|
557 |
} |
558 |
|
559 |
static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished) |
560 |
{ |
561 |
AHCIPortRegs *pr = &s->dev[port].port_regs; |
562 |
IDEState *ide_state; |
563 |
uint8_t *sdb_fis; |
564 |
|
565 |
if (!s->dev[port].res_fis ||
|
566 |
!(pr->cmd & PORT_CMD_FIS_RX)) { |
567 |
return;
|
568 |
} |
569 |
|
570 |
sdb_fis = &s->dev[port].res_fis[RES_FIS_SDBFIS]; |
571 |
ide_state = &s->dev[port].port.ifs[0];
|
572 |
|
573 |
/* clear memory */
|
574 |
*(uint32_t*)sdb_fis = 0;
|
575 |
|
576 |
/* write values */
|
577 |
sdb_fis[0] = ide_state->error;
|
578 |
sdb_fis[2] = ide_state->status & 0x77; |
579 |
s->dev[port].finished |= finished; |
580 |
*(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished);
|
581 |
|
582 |
ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_STAT_SDBS); |
583 |
} |
584 |
|
585 |
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) |
586 |
{ |
587 |
AHCIPortRegs *pr = &ad->port_regs; |
588 |
uint8_t *d2h_fis; |
589 |
int i;
|
590 |
dma_addr_t cmd_len = 0x80;
|
591 |
int cmd_mapped = 0; |
592 |
|
593 |
if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
|
594 |
return;
|
595 |
} |
596 |
|
597 |
if (!cmd_fis) {
|
598 |
/* map cmd_fis */
|
599 |
uint64_t tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr); |
600 |
cmd_fis = dma_memory_map(ad->hba->as, tbl_addr, &cmd_len, |
601 |
DMA_DIRECTION_TO_DEVICE); |
602 |
cmd_mapped = 1;
|
603 |
} |
604 |
|
605 |
d2h_fis = &ad->res_fis[RES_FIS_RFIS]; |
606 |
|
607 |
d2h_fis[0] = 0x34; |
608 |
d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0); |
609 |
d2h_fis[2] = ad->port.ifs[0].status; |
610 |
d2h_fis[3] = ad->port.ifs[0].error; |
611 |
|
612 |
d2h_fis[4] = cmd_fis[4]; |
613 |
d2h_fis[5] = cmd_fis[5]; |
614 |
d2h_fis[6] = cmd_fis[6]; |
615 |
d2h_fis[7] = cmd_fis[7]; |
616 |
d2h_fis[8] = cmd_fis[8]; |
617 |
d2h_fis[9] = cmd_fis[9]; |
618 |
d2h_fis[10] = cmd_fis[10]; |
619 |
d2h_fis[11] = cmd_fis[11]; |
620 |
d2h_fis[12] = cmd_fis[12]; |
621 |
d2h_fis[13] = cmd_fis[13]; |
622 |
for (i = 14; i < 20; i++) { |
623 |
d2h_fis[i] = 0;
|
624 |
} |
625 |
|
626 |
if (d2h_fis[2] & ERR_STAT) { |
627 |
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_TFES); |
628 |
} |
629 |
|
630 |
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS); |
631 |
|
632 |
if (cmd_mapped) {
|
633 |
dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len, |
634 |
DMA_DIRECTION_TO_DEVICE, cmd_len); |
635 |
} |
636 |
} |
637 |
|
638 |
static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset) |
639 |
{ |
640 |
AHCICmdHdr *cmd = ad->cur_cmd; |
641 |
uint32_t opts = le32_to_cpu(cmd->opts); |
642 |
uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;
|
643 |
int sglist_alloc_hint = opts >> AHCI_CMD_HDR_PRDT_LEN;
|
644 |
dma_addr_t prdt_len = (sglist_alloc_hint * sizeof(AHCI_SG));
|
645 |
dma_addr_t real_prdt_len = prdt_len; |
646 |
uint8_t *prdt; |
647 |
int i;
|
648 |
int r = 0; |
649 |
int sum = 0; |
650 |
int off_idx = -1; |
651 |
int off_pos = -1; |
652 |
int tbl_entry_size;
|
653 |
|
654 |
if (!sglist_alloc_hint) {
|
655 |
DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
|
656 |
return -1; |
657 |
} |
658 |
|
659 |
/* map PRDT */
|
660 |
if (!(prdt = dma_memory_map(ad->hba->as, prdt_addr, &prdt_len,
|
661 |
DMA_DIRECTION_TO_DEVICE))){ |
662 |
DPRINTF(ad->port_no, "map failed\n");
|
663 |
return -1; |
664 |
} |
665 |
|
666 |
if (prdt_len < real_prdt_len) {
|
667 |
DPRINTF(ad->port_no, "mapped less than expected\n");
|
668 |
r = -1;
|
669 |
goto out;
|
670 |
} |
671 |
|
672 |
/* Get entries in the PRDT, init a qemu sglist accordingly */
|
673 |
if (sglist_alloc_hint > 0) { |
674 |
AHCI_SG *tbl = (AHCI_SG *)prdt; |
675 |
sum = 0;
|
676 |
for (i = 0; i < sglist_alloc_hint; i++) { |
677 |
/* flags_size is zero-based */
|
678 |
tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);
|
679 |
if (offset <= (sum + tbl_entry_size)) {
|
680 |
off_idx = i; |
681 |
off_pos = offset - sum; |
682 |
break;
|
683 |
} |
684 |
sum += tbl_entry_size; |
685 |
} |
686 |
if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) { |
687 |
DPRINTF(ad->port_no, "%s: Incorrect offset! "
|
688 |
"off_idx: %d, off_pos: %d\n",
|
689 |
__func__, off_idx, off_pos); |
690 |
r = -1;
|
691 |
goto out;
|
692 |
} |
693 |
|
694 |
qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx), ad->hba->as); |
695 |
qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos), |
696 |
le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);
|
697 |
|
698 |
for (i = off_idx + 1; i < sglist_alloc_hint; i++) { |
699 |
/* flags_size is zero-based */
|
700 |
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr), |
701 |
le32_to_cpu(tbl[i].flags_size) + 1);
|
702 |
} |
703 |
} |
704 |
|
705 |
out:
|
706 |
dma_memory_unmap(ad->hba->as, prdt, prdt_len, |
707 |
DMA_DIRECTION_TO_DEVICE, prdt_len); |
708 |
return r;
|
709 |
} |
710 |
|
711 |
static void ncq_cb(void *opaque, int ret) |
712 |
{ |
713 |
NCQTransferState *ncq_tfs = (NCQTransferState *)opaque; |
714 |
IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
|
715 |
|
716 |
/* Clear bit for this tag in SActive */
|
717 |
ncq_tfs->drive->port_regs.scr_act &= ~(1 << ncq_tfs->tag);
|
718 |
|
719 |
if (ret < 0) { |
720 |
/* error */
|
721 |
ide_state->error = ABRT_ERR; |
722 |
ide_state->status = READY_STAT | ERR_STAT; |
723 |
ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
|
724 |
} else {
|
725 |
ide_state->status = READY_STAT | SEEK_STAT; |
726 |
} |
727 |
|
728 |
ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs->drive->port_no, |
729 |
(1 << ncq_tfs->tag));
|
730 |
|
731 |
DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
|
732 |
ncq_tfs->tag); |
733 |
|
734 |
bdrv_acct_done(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct);
|
735 |
qemu_sglist_destroy(&ncq_tfs->sglist); |
736 |
ncq_tfs->used = 0;
|
737 |
} |
738 |
|
739 |
static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, |
740 |
int slot)
|
741 |
{ |
742 |
NCQFrame *ncq_fis = (NCQFrame*)cmd_fis; |
743 |
uint8_t tag = ncq_fis->tag >> 3;
|
744 |
NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[tag]; |
745 |
|
746 |
if (ncq_tfs->used) {
|
747 |
/* error - already in use */
|
748 |
fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
|
749 |
return;
|
750 |
} |
751 |
|
752 |
ncq_tfs->used = 1;
|
753 |
ncq_tfs->drive = &s->dev[port]; |
754 |
ncq_tfs->slot = slot; |
755 |
ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
|
756 |
((uint64_t)ncq_fis->lba4 << 32) |
|
757 |
((uint64_t)ncq_fis->lba3 << 24) |
|
758 |
((uint64_t)ncq_fis->lba2 << 16) |
|
759 |
((uint64_t)ncq_fis->lba1 << 8) |
|
760 |
(uint64_t)ncq_fis->lba0; |
761 |
|
762 |
/* Note: We calculate the sector count, but don't currently rely on it.
|
763 |
* The total size of the DMA buffer tells us the transfer size instead. */
|
764 |
ncq_tfs->sector_count = ((uint16_t)ncq_fis->sector_count_high << 8) |
|
765 |
ncq_fis->sector_count_low; |
766 |
|
767 |
DPRINTF(port, "NCQ transfer LBA from %"PRId64" to %"PRId64", " |
768 |
"drive max %"PRId64"\n", |
769 |
ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
|
770 |
s->dev[port].port.ifs[0].nb_sectors - 1); |
771 |
|
772 |
ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist, 0);
|
773 |
ncq_tfs->tag = tag; |
774 |
|
775 |
switch(ncq_fis->command) {
|
776 |
case READ_FPDMA_QUEUED:
|
777 |
DPRINTF(port, "NCQ reading %d sectors from LBA %"PRId64", " |
778 |
"tag %d\n",
|
779 |
ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
|
780 |
|
781 |
DPRINTF(port, "tag %d aio read %"PRId64"\n", |
782 |
ncq_tfs->tag, ncq_tfs->lba); |
783 |
|
784 |
dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
|
785 |
&ncq_tfs->sglist, BDRV_ACCT_READ); |
786 |
ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs,
|
787 |
&ncq_tfs->sglist, ncq_tfs->lba, |
788 |
ncq_cb, ncq_tfs); |
789 |
break;
|
790 |
case WRITE_FPDMA_QUEUED:
|
791 |
DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n", |
792 |
ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
|
793 |
|
794 |
DPRINTF(port, "tag %d aio write %"PRId64"\n", |
795 |
ncq_tfs->tag, ncq_tfs->lba); |
796 |
|
797 |
dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
|
798 |
&ncq_tfs->sglist, BDRV_ACCT_WRITE); |
799 |
ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs,
|
800 |
&ncq_tfs->sglist, ncq_tfs->lba, |
801 |
ncq_cb, ncq_tfs); |
802 |
break;
|
803 |
default:
|
804 |
DPRINTF(port, "error: tried to process non-NCQ command as NCQ\n");
|
805 |
qemu_sglist_destroy(&ncq_tfs->sglist); |
806 |
break;
|
807 |
} |
808 |
} |
809 |
|
810 |
static int handle_cmd(AHCIState *s, int port, int slot) |
811 |
{ |
812 |
IDEState *ide_state; |
813 |
uint32_t opts; |
814 |
uint64_t tbl_addr; |
815 |
AHCICmdHdr *cmd; |
816 |
uint8_t *cmd_fis; |
817 |
dma_addr_t cmd_len; |
818 |
|
819 |
if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) { |
820 |
/* Engine currently busy, try again later */
|
821 |
DPRINTF(port, "engine busy\n");
|
822 |
return -1; |
823 |
} |
824 |
|
825 |
cmd = &((AHCICmdHdr *)s->dev[port].lst)[slot]; |
826 |
|
827 |
if (!s->dev[port].lst) {
|
828 |
DPRINTF(port, "error: lst not given but cmd handled");
|
829 |
return -1; |
830 |
} |
831 |
|
832 |
/* remember current slot handle for later */
|
833 |
s->dev[port].cur_cmd = cmd; |
834 |
|
835 |
opts = le32_to_cpu(cmd->opts); |
836 |
tbl_addr = le64_to_cpu(cmd->tbl_addr); |
837 |
|
838 |
cmd_len = 0x80;
|
839 |
cmd_fis = dma_memory_map(s->as, tbl_addr, &cmd_len, |
840 |
DMA_DIRECTION_FROM_DEVICE); |
841 |
|
842 |
if (!cmd_fis) {
|
843 |
DPRINTF(port, "error: guest passed us an invalid cmd fis\n");
|
844 |
return -1; |
845 |
} |
846 |
|
847 |
/* The device we are working for */
|
848 |
ide_state = &s->dev[port].port.ifs[0];
|
849 |
|
850 |
if (!ide_state->bs) {
|
851 |
DPRINTF(port, "error: guest accessed unused port");
|
852 |
goto out;
|
853 |
} |
854 |
|
855 |
debug_print_fis(cmd_fis, 0x90);
|
856 |
//debug_print_fis(cmd_fis, (opts & AHCI_CMD_HDR_CMD_FIS_LEN) * 4);
|
857 |
|
858 |
switch (cmd_fis[0]) { |
859 |
case SATA_FIS_TYPE_REGISTER_H2D:
|
860 |
break;
|
861 |
default:
|
862 |
DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
|
863 |
"cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1], |
864 |
cmd_fis[2]);
|
865 |
goto out;
|
866 |
break;
|
867 |
} |
868 |
|
869 |
switch (cmd_fis[1]) { |
870 |
case SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER:
|
871 |
break;
|
872 |
case 0: |
873 |
break;
|
874 |
default:
|
875 |
DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
|
876 |
"cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1], |
877 |
cmd_fis[2]);
|
878 |
goto out;
|
879 |
break;
|
880 |
} |
881 |
|
882 |
switch (s->dev[port].port_state) {
|
883 |
case STATE_RUN:
|
884 |
if (cmd_fis[15] & ATA_SRST) { |
885 |
s->dev[port].port_state = STATE_RESET; |
886 |
} |
887 |
break;
|
888 |
case STATE_RESET:
|
889 |
if (!(cmd_fis[15] & ATA_SRST)) { |
890 |
ahci_reset_port(s, port); |
891 |
} |
892 |
break;
|
893 |
} |
894 |
|
895 |
if (cmd_fis[1] == SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER) { |
896 |
|
897 |
/* Check for NCQ command */
|
898 |
if ((cmd_fis[2] == READ_FPDMA_QUEUED) || |
899 |
(cmd_fis[2] == WRITE_FPDMA_QUEUED)) {
|
900 |
process_ncq_command(s, port, cmd_fis, slot); |
901 |
goto out;
|
902 |
} |
903 |
|
904 |
/* Decompose the FIS */
|
905 |
ide_state->nsector = (int64_t)((cmd_fis[13] << 8) | cmd_fis[12]); |
906 |
ide_state->feature = cmd_fis[3];
|
907 |
if (!ide_state->nsector) {
|
908 |
ide_state->nsector = 256;
|
909 |
} |
910 |
|
911 |
if (ide_state->drive_kind != IDE_CD) {
|
912 |
/*
|
913 |
* We set the sector depending on the sector defined in the FIS.
|
914 |
* Unfortunately, the spec isn't exactly obvious on this one.
|
915 |
*
|
916 |
* Apparently LBA48 commands set fis bytes 10,9,8,6,5,4 to the
|
917 |
* 48 bit sector number. ATA_CMD_READ_DMA_EXT is an example for
|
918 |
* such a command.
|
919 |
*
|
920 |
* Non-LBA48 commands however use 7[lower 4 bits],6,5,4 to define a
|
921 |
* 28-bit sector number. ATA_CMD_READ_DMA is an example for such
|
922 |
* a command.
|
923 |
*
|
924 |
* Since the spec doesn't explicitly state what each field should
|
925 |
* do, I simply assume non-used fields as reserved and OR everything
|
926 |
* together, independent of the command.
|
927 |
*/
|
928 |
ide_set_sector(ide_state, ((uint64_t)cmd_fis[10] << 40) |
929 |
| ((uint64_t)cmd_fis[9] << 32) |
930 |
/* This is used for LBA48 commands */
|
931 |
| ((uint64_t)cmd_fis[8] << 24) |
932 |
/* This is used for non-LBA48 commands */
|
933 |
| ((uint64_t)(cmd_fis[7] & 0xf) << 24) |
934 |
| ((uint64_t)cmd_fis[6] << 16) |
935 |
| ((uint64_t)cmd_fis[5] << 8) |
936 |
| cmd_fis[4]);
|
937 |
} |
938 |
|
939 |
/* Copy the ACMD field (ATAPI packet, if any) from the AHCI command
|
940 |
* table to ide_state->io_buffer
|
941 |
*/
|
942 |
if (opts & AHCI_CMD_ATAPI) {
|
943 |
memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10);
|
944 |
ide_state->lcyl = 0x14;
|
945 |
ide_state->hcyl = 0xeb;
|
946 |
debug_print_fis(ide_state->io_buffer, 0x10);
|
947 |
ide_state->feature = IDE_FEATURE_DMA; |
948 |
s->dev[port].done_atapi_packet = false;
|
949 |
/* XXX send PIO setup FIS */
|
950 |
} |
951 |
|
952 |
ide_state->error = 0;
|
953 |
|
954 |
/* Reset transferred byte counter */
|
955 |
cmd->status = 0;
|
956 |
|
957 |
/* We're ready to process the command in FIS byte 2. */
|
958 |
ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
|
959 |
|
960 |
if (s->dev[port].port.ifs[0].status & READY_STAT) { |
961 |
ahci_write_fis_d2h(&s->dev[port], cmd_fis); |
962 |
} |
963 |
} |
964 |
|
965 |
out:
|
966 |
dma_memory_unmap(s->as, cmd_fis, cmd_len, DMA_DIRECTION_FROM_DEVICE, |
967 |
cmd_len); |
968 |
|
969 |
if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) { |
970 |
/* async command, complete later */
|
971 |
s->dev[port].busy_slot = slot; |
972 |
return -1; |
973 |
} |
974 |
|
975 |
/* done handling the command */
|
976 |
return 0; |
977 |
} |
978 |
|
979 |
/* DMA dev <-> ram */
|
980 |
static int ahci_start_transfer(IDEDMA *dma) |
981 |
{ |
982 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
983 |
IDEState *s = &ad->port.ifs[0];
|
984 |
uint32_t size = (uint32_t)(s->data_end - s->data_ptr); |
985 |
/* write == ram -> device */
|
986 |
uint32_t opts = le32_to_cpu(ad->cur_cmd->opts); |
987 |
int is_write = opts & AHCI_CMD_WRITE;
|
988 |
int is_atapi = opts & AHCI_CMD_ATAPI;
|
989 |
int has_sglist = 0; |
990 |
|
991 |
if (is_atapi && !ad->done_atapi_packet) {
|
992 |
/* already prepopulated iobuffer */
|
993 |
ad->done_atapi_packet = true;
|
994 |
goto out;
|
995 |
} |
996 |
|
997 |
if (!ahci_populate_sglist(ad, &s->sg, 0)) { |
998 |
has_sglist = 1;
|
999 |
} |
1000 |
|
1001 |
DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n",
|
1002 |
is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata", |
1003 |
has_sglist ? "" : "o"); |
1004 |
|
1005 |
if (has_sglist && size) {
|
1006 |
if (is_write) {
|
1007 |
dma_buf_write(s->data_ptr, size, &s->sg); |
1008 |
} else {
|
1009 |
dma_buf_read(s->data_ptr, size, &s->sg); |
1010 |
} |
1011 |
} |
1012 |
|
1013 |
/* update number of transferred bytes */
|
1014 |
ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + size); |
1015 |
|
1016 |
out:
|
1017 |
/* declare that we processed everything */
|
1018 |
s->data_ptr = s->data_end; |
1019 |
|
1020 |
if (has_sglist) {
|
1021 |
qemu_sglist_destroy(&s->sg); |
1022 |
} |
1023 |
|
1024 |
s->end_transfer_func(s); |
1025 |
|
1026 |
if (!(s->status & DRQ_STAT)) {
|
1027 |
/* done with DMA */
|
1028 |
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS); |
1029 |
} |
1030 |
|
1031 |
return 0; |
1032 |
} |
1033 |
|
1034 |
static void ahci_start_dma(IDEDMA *dma, IDEState *s, |
1035 |
BlockDriverCompletionFunc *dma_cb) |
1036 |
{ |
1037 |
#ifdef DEBUG_AHCI
|
1038 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1039 |
#endif
|
1040 |
DPRINTF(ad->port_no, "\n");
|
1041 |
s->io_buffer_offset = 0;
|
1042 |
dma_cb(s, 0);
|
1043 |
} |
1044 |
|
1045 |
static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write) |
1046 |
{ |
1047 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1048 |
IDEState *s = &ad->port.ifs[0];
|
1049 |
|
1050 |
ahci_populate_sglist(ad, &s->sg, 0);
|
1051 |
s->io_buffer_size = s->sg.size; |
1052 |
|
1053 |
DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
|
1054 |
return s->io_buffer_size != 0; |
1055 |
} |
1056 |
|
1057 |
static int ahci_dma_rw_buf(IDEDMA *dma, int is_write) |
1058 |
{ |
1059 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1060 |
IDEState *s = &ad->port.ifs[0];
|
1061 |
uint8_t *p = s->io_buffer + s->io_buffer_index; |
1062 |
int l = s->io_buffer_size - s->io_buffer_index;
|
1063 |
|
1064 |
if (ahci_populate_sglist(ad, &s->sg, s->io_buffer_offset)) {
|
1065 |
return 0; |
1066 |
} |
1067 |
|
1068 |
if (is_write) {
|
1069 |
dma_buf_read(p, l, &s->sg); |
1070 |
} else {
|
1071 |
dma_buf_write(p, l, &s->sg); |
1072 |
} |
1073 |
|
1074 |
/* free sglist that was created in ahci_populate_sglist() */
|
1075 |
qemu_sglist_destroy(&s->sg); |
1076 |
|
1077 |
/* update number of transferred bytes */
|
1078 |
ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l); |
1079 |
s->io_buffer_index += l; |
1080 |
s->io_buffer_offset += l; |
1081 |
|
1082 |
DPRINTF(ad->port_no, "len=%#x\n", l);
|
1083 |
|
1084 |
return 1; |
1085 |
} |
1086 |
|
1087 |
static int ahci_dma_set_unit(IDEDMA *dma, int unit) |
1088 |
{ |
1089 |
/* only a single unit per link */
|
1090 |
return 0; |
1091 |
} |
1092 |
|
1093 |
static int ahci_dma_add_status(IDEDMA *dma, int status) |
1094 |
{ |
1095 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1096 |
DPRINTF(ad->port_no, "set status: %x\n", status);
|
1097 |
|
1098 |
if (status & BM_STATUS_INT) {
|
1099 |
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS); |
1100 |
} |
1101 |
|
1102 |
return 0; |
1103 |
} |
1104 |
|
1105 |
static int ahci_dma_set_inactive(IDEDMA *dma) |
1106 |
{ |
1107 |
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); |
1108 |
|
1109 |
DPRINTF(ad->port_no, "dma done\n");
|
1110 |
|
1111 |
/* update d2h status */
|
1112 |
ahci_write_fis_d2h(ad, NULL);
|
1113 |
|
1114 |
if (!ad->check_bh) {
|
1115 |
/* maybe we still have something to process, check later */
|
1116 |
ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad); |
1117 |
qemu_bh_schedule(ad->check_bh); |
1118 |
} |
1119 |
|
1120 |
return 0; |
1121 |
} |
1122 |
|
1123 |
static void ahci_irq_set(void *opaque, int n, int level) |
1124 |
{ |
1125 |
} |
1126 |
|
1127 |
static void ahci_dma_restart_cb(void *opaque, int running, RunState state) |
1128 |
{ |
1129 |
} |
1130 |
|
1131 |
static int ahci_dma_reset(IDEDMA *dma) |
1132 |
{ |
1133 |
return 0; |
1134 |
} |
1135 |
|
1136 |
static const IDEDMAOps ahci_dma_ops = { |
1137 |
.start_dma = ahci_start_dma, |
1138 |
.start_transfer = ahci_start_transfer, |
1139 |
.prepare_buf = ahci_dma_prepare_buf, |
1140 |
.rw_buf = ahci_dma_rw_buf, |
1141 |
.set_unit = ahci_dma_set_unit, |
1142 |
.add_status = ahci_dma_add_status, |
1143 |
.set_inactive = ahci_dma_set_inactive, |
1144 |
.restart_cb = ahci_dma_restart_cb, |
1145 |
.reset = ahci_dma_reset, |
1146 |
}; |
1147 |
|
1148 |
void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports) |
1149 |
{ |
1150 |
qemu_irq *irqs; |
1151 |
int i;
|
1152 |
|
1153 |
s->as = as; |
1154 |
s->ports = ports; |
1155 |
s->dev = g_malloc0(sizeof(AHCIDevice) * ports);
|
1156 |
ahci_reg_init(s); |
1157 |
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
|
1158 |
memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", AHCI_MEM_BAR_SIZE);
|
1159 |
memory_region_init_io(&s->idp, &ahci_idp_ops, s, "ahci-idp", 32); |
1160 |
|
1161 |
irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports); |
1162 |
|
1163 |
for (i = 0; i < s->ports; i++) { |
1164 |
AHCIDevice *ad = &s->dev[i]; |
1165 |
|
1166 |
ide_bus_new(&ad->port, qdev, i, 1);
|
1167 |
ide_init2(&ad->port, irqs[i]); |
1168 |
|
1169 |
ad->hba = s; |
1170 |
ad->port_no = i; |
1171 |
ad->port.dma = &ad->dma; |
1172 |
ad->port.dma->ops = &ahci_dma_ops; |
1173 |
} |
1174 |
} |
1175 |
|
1176 |
void ahci_uninit(AHCIState *s)
|
1177 |
{ |
1178 |
memory_region_destroy(&s->mem); |
1179 |
memory_region_destroy(&s->idp); |
1180 |
g_free(s->dev); |
1181 |
} |
1182 |
|
1183 |
void ahci_reset(AHCIState *s)
|
1184 |
{ |
1185 |
AHCIPortRegs *pr; |
1186 |
int i;
|
1187 |
|
1188 |
s->control_regs.irqstatus = 0;
|
1189 |
s->control_regs.ghc = 0;
|
1190 |
|
1191 |
for (i = 0; i < s->ports; i++) { |
1192 |
pr = &s->dev[i].port_regs; |
1193 |
pr->irq_stat = 0;
|
1194 |
pr->irq_mask = 0;
|
1195 |
pr->scr_ctl = 0;
|
1196 |
pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON; |
1197 |
ahci_reset_port(s, i); |
1198 |
} |
1199 |
} |
1200 |
|
1201 |
static const VMStateDescription vmstate_ahci_device = { |
1202 |
.name = "ahci port",
|
1203 |
.version_id = 1,
|
1204 |
.fields = (VMStateField []) { |
1205 |
VMSTATE_IDE_BUS(port, AHCIDevice), |
1206 |
VMSTATE_UINT32(port_state, AHCIDevice), |
1207 |
VMSTATE_UINT32(finished, AHCIDevice), |
1208 |
VMSTATE_UINT32(port_regs.lst_addr, AHCIDevice), |
1209 |
VMSTATE_UINT32(port_regs.lst_addr_hi, AHCIDevice), |
1210 |
VMSTATE_UINT32(port_regs.fis_addr, AHCIDevice), |
1211 |
VMSTATE_UINT32(port_regs.fis_addr_hi, AHCIDevice), |
1212 |
VMSTATE_UINT32(port_regs.irq_stat, AHCIDevice), |
1213 |
VMSTATE_UINT32(port_regs.irq_mask, AHCIDevice), |
1214 |
VMSTATE_UINT32(port_regs.cmd, AHCIDevice), |
1215 |
VMSTATE_UINT32(port_regs.tfdata, AHCIDevice), |
1216 |
VMSTATE_UINT32(port_regs.sig, AHCIDevice), |
1217 |
VMSTATE_UINT32(port_regs.scr_stat, AHCIDevice), |
1218 |
VMSTATE_UINT32(port_regs.scr_ctl, AHCIDevice), |
1219 |
VMSTATE_UINT32(port_regs.scr_err, AHCIDevice), |
1220 |
VMSTATE_UINT32(port_regs.scr_act, AHCIDevice), |
1221 |
VMSTATE_UINT32(port_regs.cmd_issue, AHCIDevice), |
1222 |
VMSTATE_BOOL(done_atapi_packet, AHCIDevice), |
1223 |
VMSTATE_INT32(busy_slot, AHCIDevice), |
1224 |
VMSTATE_BOOL(init_d2h_sent, AHCIDevice), |
1225 |
VMSTATE_END_OF_LIST() |
1226 |
}, |
1227 |
}; |
1228 |
|
1229 |
static int ahci_state_post_load(void *opaque, int version_id) |
1230 |
{ |
1231 |
int i;
|
1232 |
struct AHCIDevice *ad;
|
1233 |
AHCIState *s = opaque; |
1234 |
|
1235 |
for (i = 0; i < s->ports; i++) { |
1236 |
ad = &s->dev[i]; |
1237 |
AHCIPortRegs *pr = &ad->port_regs; |
1238 |
|
1239 |
map_page(&ad->lst, |
1240 |
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024); |
1241 |
map_page(&ad->res_fis, |
1242 |
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256); |
1243 |
/*
|
1244 |
* All pending i/o should be flushed out on a migrate. However,
|
1245 |
* we might not have cleared the busy_slot since this is done
|
1246 |
* in a bh. Also, issue i/o against any slots that are pending.
|
1247 |
*/
|
1248 |
if ((ad->busy_slot != -1) && |
1249 |
!(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
|
1250 |
pr->cmd_issue &= ~(1 << ad->busy_slot);
|
1251 |
ad->busy_slot = -1;
|
1252 |
} |
1253 |
check_cmd(s, i); |
1254 |
} |
1255 |
|
1256 |
return 0; |
1257 |
} |
1258 |
|
1259 |
const VMStateDescription vmstate_ahci = {
|
1260 |
.name = "ahci",
|
1261 |
.version_id = 1,
|
1262 |
.post_load = ahci_state_post_load, |
1263 |
.fields = (VMStateField []) { |
1264 |
VMSTATE_STRUCT_VARRAY_POINTER_INT32(dev, AHCIState, ports, |
1265 |
vmstate_ahci_device, AHCIDevice), |
1266 |
VMSTATE_UINT32(control_regs.cap, AHCIState), |
1267 |
VMSTATE_UINT32(control_regs.ghc, AHCIState), |
1268 |
VMSTATE_UINT32(control_regs.irqstatus, AHCIState), |
1269 |
VMSTATE_UINT32(control_regs.impl, AHCIState), |
1270 |
VMSTATE_UINT32(control_regs.version, AHCIState), |
1271 |
VMSTATE_UINT32(idp_index, AHCIState), |
1272 |
VMSTATE_INT32(ports, AHCIState), |
1273 |
VMSTATE_END_OF_LIST() |
1274 |
}, |
1275 |
}; |
1276 |
|
1277 |
typedef struct SysbusAHCIState { |
1278 |
SysBusDevice busdev; |
1279 |
AHCIState ahci; |
1280 |
uint32_t num_ports; |
1281 |
} SysbusAHCIState; |
1282 |
|
1283 |
static const VMStateDescription vmstate_sysbus_ahci = { |
1284 |
.name = "sysbus-ahci",
|
1285 |
.unmigratable = 1, /* Still buggy under I/O load */ |
1286 |
.fields = (VMStateField []) { |
1287 |
VMSTATE_AHCI(ahci, AHCIPCIState), |
1288 |
VMSTATE_END_OF_LIST() |
1289 |
}, |
1290 |
}; |
1291 |
|
1292 |
static void sysbus_ahci_reset(DeviceState *dev) |
1293 |
{ |
1294 |
SysbusAHCIState *s = DO_UPCAST(SysbusAHCIState, busdev.qdev, dev); |
1295 |
|
1296 |
ahci_reset(&s->ahci); |
1297 |
} |
1298 |
|
1299 |
static int sysbus_ahci_init(SysBusDevice *dev) |
1300 |
{ |
1301 |
SysbusAHCIState *s = FROM_SYSBUS(SysbusAHCIState, dev); |
1302 |
ahci_init(&s->ahci, &dev->qdev, NULL, s->num_ports);
|
1303 |
|
1304 |
sysbus_init_mmio(dev, &s->ahci.mem); |
1305 |
sysbus_init_irq(dev, &s->ahci.irq); |
1306 |
return 0; |
1307 |
} |
1308 |
|
1309 |
static Property sysbus_ahci_properties[] = {
|
1310 |
DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1), |
1311 |
DEFINE_PROP_END_OF_LIST(), |
1312 |
}; |
1313 |
|
1314 |
static void sysbus_ahci_class_init(ObjectClass *klass, void *data) |
1315 |
{ |
1316 |
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); |
1317 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1318 |
|
1319 |
sbc->init = sysbus_ahci_init; |
1320 |
dc->vmsd = &vmstate_sysbus_ahci; |
1321 |
dc->props = sysbus_ahci_properties; |
1322 |
dc->reset = sysbus_ahci_reset; |
1323 |
} |
1324 |
|
1325 |
static const TypeInfo sysbus_ahci_info = { |
1326 |
.name = "sysbus-ahci",
|
1327 |
.parent = TYPE_SYS_BUS_DEVICE, |
1328 |
.instance_size = sizeof(SysbusAHCIState),
|
1329 |
.class_init = sysbus_ahci_class_init, |
1330 |
}; |
1331 |
|
1332 |
static void sysbus_ahci_register_types(void) |
1333 |
{ |
1334 |
type_register_static(&sysbus_ahci_info); |
1335 |
} |
1336 |
|
1337 |
type_init(sysbus_ahci_register_types) |