aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Cassel <niklas.cassel@wdc.com>2023-06-09 16:08:44 +0200
committerMichael Tokarev <mjt@tls.msk.ru>2023-09-21 19:35:19 +0300
commitd5361580ac60d5d08f30e6ca8a6c68d32eee233f (patch)
treeda99930860f5d65c959329dd09136e0ba7f878b8
parente8f5ca57e450fb225ad52205536280b6fd9c37d4 (diff)
downloadqemu-d5361580ac60d5d08f30e6ca8a6c68d32eee233f.zip
qemu-d5361580ac60d5d08f30e6ca8a6c68d32eee233f.tar.gz
qemu-d5361580ac60d5d08f30e6ca8a6c68d32eee233f.tar.bz2
hw/ide/ahci: fix broken SError handling
When encountering an NCQ error, you should not write the NCQ tag to the SError register. This is completely wrong. The SError register has a clear definition, where each bit represents a different error, see PxSERR definition in AHCI 1.3.1. If we write a random value (like the NCQ tag) in SError, e.g. Linux will read SError, and will trigger arbitrary error handling depending on the NCQ tag that happened to be executing. In case of success, ncq_cb() will call ncq_finish(). In case of error, ncq_cb() will call ncq_err() (which will clear ncq_tfs->used), and then call ncq_finish(), thus using ncq_tfs->used is sufficient to tell if finished should get set or not. Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20230609140844.202795-9-nks@flawful.org Signed-off-by: John Snow <jsnow@redhat.com> (cherry picked from commit 9f89423537653de07ca40c18b5ff5b70b104cc93) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
-rw-r--r--hw/ide/ahci.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index ef6c9fc..d0a774b 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1012,7 +1012,6 @@ static void ncq_err(NCQTransferState *ncq_tfs)
ide_state->error = ABRT_ERR;
ide_state->status = READY_STAT | ERR_STAT;
- ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
qemu_sglist_destroy(&ncq_tfs->sglist);
ncq_tfs->used = 0;
}
@@ -1022,7 +1021,7 @@ static void ncq_finish(NCQTransferState *ncq_tfs)
/* If we didn't error out, set our finished bit. Errored commands
* do not get a bit set for the SDB FIS ACT register, nor do they
* clear the outstanding bit in scr_act (PxSACT). */
- if (!(ncq_tfs->drive->port_regs.scr_err & (1 << ncq_tfs->tag))) {
+ if (ncq_tfs->used) {
ncq_tfs->drive->finished |= (1 << ncq_tfs->tag);
}