Patchwork [3/8] ahci: send init d2h fis on fis enable

login
register
mail settings
Submitter Alexander Graf
Date Dec. 20, 2010, 9:13 p.m.
Message ID <1292879604-22268-4-git-send-email-agraf@suse.de>
Download mbox | patch
Permalink /patch/76224/
State New
Headers show

Comments

Alexander Graf - Dec. 20, 2010, 9:13 p.m.
The drive sends a d2h init fis on initialization. Usually, the guest doesn't
receive fises yet at that point though, so the delivery is deferred.

Let's reflect that by sending the init fis on fis receive enablement.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/ide/ahci.c |   34 +++++++++++++++++++++++++++-------
 hw/ide/ahci.h |    1 +
 2 files changed, 28 insertions(+), 7 deletions(-)
Kevin Wolf - Jan. 18, 2011, 12:25 p.m.
Am 20.12.2010 22:13, schrieb Alexander Graf:
> The drive sends a d2h init fis on initialization. Usually, the guest doesn't
> receive fises yet at that point though, so the delivery is deferred.
> 
> Let's reflect that by sending the init fis on fis receive enablement.
> 
> Signed-off-by: Alexander Graf <agraf@suse.de>

Hm... If I read the spec right, the real solution wouldn't be an
init_d2h_sent flag, but implementing a queue for FISes that are received
when the guest hasn't set FRE yet.

I'm not against taking a hack like this, but maybe leave a comment
somewhere at least.

Kevin
Alexander Graf - Jan. 18, 2011, 12:42 p.m.
On 18.01.2011, at 13:25, Kevin Wolf wrote:

> Am 20.12.2010 22:13, schrieb Alexander Graf:
>> The drive sends a d2h init fis on initialization. Usually, the guest doesn't
>> receive fises yet at that point though, so the delivery is deferred.
>> 
>> Let's reflect that by sending the init fis on fis receive enablement.
>> 
>> Signed-off-by: Alexander Graf <agraf@suse.de>
> 
> Hm... If I read the spec right, the real solution wouldn't be an
> init_d2h_sent flag, but implementing a queue for FISes that are received
> when the guest hasn't set FRE yet.
> 
> I'm not against taking a hack like this, but maybe leave a comment
> somewhere at least.

Yes, they'd get queued. In practice it doesn't really matter that much, which is why the hack works :). But you're right - a comment would be nice.


Alex

Patch

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 18187c8..fa97f9b 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -48,6 +48,7 @@  static void check_cmd(AHCIState *s, int port);
 static int handle_cmd(AHCIState *s,int port,int slot);
 static void ahci_reset_port(AHCIState *s, int port);
 static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
+static void ahci_init_d2h(AHCIDevice *ad);
 
 static uint32_t  ahci_port_read(AHCIState *s, int port, int offset)
 {
@@ -231,6 +232,12 @@  static void  ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
                 pr->cmd |= PORT_CMD_FIS_ON;
             }
 
+            if ((pr->cmd & PORT_CMD_FIS_ON) &&
+                !s->dev[port].init_d2h_sent) {
+                ahci_init_d2h(&s->dev[port]);
+                s->dev[port].init_d2h_sent = 1;
+            }
+
             check_cmd(s, port);
             break;
         case PORT_TFDATA:
@@ -463,12 +470,29 @@  static void ahci_check_cmd_bh(void *opaque)
     check_cmd(ad->hba, ad->port_no);
 }
 
+static void ahci_init_d2h(AHCIDevice *ad)
+{
+    uint8_t init_fis[0x20];
+    IDEState *ide_state = &ad->port.ifs[0];
+
+    memset(init_fis, 0, sizeof(init_fis));
+
+    init_fis[4] = 1;
+    init_fis[12] = 1;
+
+    if (ide_state->drive_kind == IDE_CD) {
+        init_fis[5] = ide_state->lcyl;
+        init_fis[6] = ide_state->hcyl;
+    }
+
+    ahci_write_fis_d2h(ad, init_fis);
+}
+
 static void ahci_reset_port(AHCIState *s, int port)
 {
     AHCIDevice *d = &s->dev[port];
     AHCIPortRegs *pr = &d->port_regs;
     IDEState *ide_state = &d->port.ifs[0];
-    uint8_t init_fis[0x20];
     int i;
 
     DPRINTF(port, "reset port\n");
@@ -483,6 +507,7 @@  static void ahci_reset_port(AHCIState *s, int port)
     pr->scr_err = 0;
     pr->scr_act = 0;
     d->busy_slot = -1;
+    d->init_d2h_sent = 0;
 
     ide_state = &s->dev[port].port.ifs[0];
     if (!ide_state->bs) {
@@ -505,7 +530,6 @@  static void ahci_reset_port(AHCIState *s, int port)
         ncq_tfs->used = 0;
     }
 
-    memset(init_fis, 0, sizeof(init_fis));
     s->dev[port].port_state = STATE_RUN;
     if (!ide_state->bs) {
         s->dev[port].port_regs.sig = 0;
@@ -515,8 +539,6 @@  static void ahci_reset_port(AHCIState *s, int port)
         ide_state->lcyl = 0x14;
         ide_state->hcyl = 0xeb;
         DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl);
-        init_fis[5] = ide_state->lcyl;
-        init_fis[6] = ide_state->hcyl;
         ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT;
     } else {
         s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK;
@@ -524,9 +546,7 @@  static void ahci_reset_port(AHCIState *s, int port)
     }
 
     ide_state->error = 1;
-    init_fis[4] = 1;
-    init_fis[12] = 1;
-    ahci_write_fis_d2h(d, init_fis);
+    ahci_init_d2h(d);
 }
 
 static void debug_print_fis(uint8_t *fis, int cmd_len)
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 63ef785..5f8126a 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -259,6 +259,7 @@  struct AHCIDevice {
     int dma_status;
     int done_atapi_packet;
     int busy_slot;
+    int init_d2h_sent;
     BlockDriverCompletionFunc *dma_cb;
     AHCICmdHdr *cur_cmd;
     NCQTransferState ncq_tfs[AHCI_MAX_CMDS];