[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20180927090307.961382188@linuxfoundation.org>
Date: Thu, 27 Sep 2018 11:03:40 +0200
From: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
To: linux-kernel@...r.kernel.org
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
stable@...r.kernel.org, Paul Sbarra <sbarra.paul@...il.com>,
Jens Axboe <axboe@...nel.dk>
Subject: [PATCH 4.18 59/88] libata: mask swap internal and hardware tag
4.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <axboe@...nel.dk>
commit 7ce5c8cd753f9afa8e79e9ec40351998e354f239 upstream.
hen we're comparing the hardware completion mask passed in from the
driver with the internal tag pending mask, we need to account for the
fact that the internal tag is different from the hardware tag. If not,
then we can end up either prematurely completing the internal tag (since
it's not set in the hw mask), or simply flag an error:
ata2: illegal qc_active transition (100000000->00000001)
If the internal tag is set, then swap that with the hardware tag in this
case before comparing with what the hardware reports.
Fixes: 28361c403683 ("libata: add extra internal command")
Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=201151
Cc: stable@...r.kernel.org
Reported-by: Paul Sbarra <sbarra.paul@...il.com>
Tested-by: Paul Sbarra <sbarra.paul@...il.com>
Signed-off-by: Jens Axboe <axboe@...nel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
---
drivers/ata/libata-core.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5358,10 +5358,20 @@ void ata_qc_complete(struct ata_queued_c
*/
int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active)
{
+ u64 done_mask, ap_qc_active = ap->qc_active;
int nr_done = 0;
- u64 done_mask;
- done_mask = ap->qc_active ^ qc_active;
+ /*
+ * If the internal tag is set on ap->qc_active, then we care about
+ * bit0 on the passed in qc_active mask. Move that bit up to match
+ * the internal tag.
+ */
+ if (ap_qc_active & (1ULL << ATA_TAG_INTERNAL)) {
+ qc_active |= (qc_active & 0x01) << ATA_TAG_INTERNAL;
+ qc_active ^= qc_active & 0x01;
+ }
+
+ done_mask = ap_qc_active ^ qc_active;
if (unlikely(done_mask & qc_active)) {
ata_port_err(ap, "illegal qc_active transition (%08llx->%08llx)\n",
Powered by blists - more mailing lists