Skip to content

Commit 7ce5c8c

Browse files
committed
libata: mask swap internal and hardware tag
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: 28361c4 ("libata: add extra internal command") Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=201151 Cc: stable@vger.kernel.org Reported-by: Paul Sbarra <sbarra.paul@gmail.com> Tested-by: Paul Sbarra <sbarra.paul@gmail.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent b228ba1 commit 7ce5c8c

File tree

1 file changed

+12
-2
lines changed

1 file changed

+12
-2
lines changed

drivers/ata/libata-core.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5359,10 +5359,20 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
53595359
*/
53605360
int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active)
53615361
{
5362+
u64 done_mask, ap_qc_active = ap->qc_active;
53625363
int nr_done = 0;
5363-
u64 done_mask;
53645364

5365-
done_mask = ap->qc_active ^ qc_active;
5365+
/*
5366+
* If the internal tag is set on ap->qc_active, then we care about
5367+
* bit0 on the passed in qc_active mask. Move that bit up to match
5368+
* the internal tag.
5369+
*/
5370+
if (ap_qc_active & (1ULL << ATA_TAG_INTERNAL)) {
5371+
qc_active |= (qc_active & 0x01) << ATA_TAG_INTERNAL;
5372+
qc_active ^= qc_active & 0x01;
5373+
}
5374+
5375+
done_mask = ap_qc_active ^ qc_active;
53665376

53675377
if (unlikely(done_mask & qc_active)) {
53685378
ata_port_err(ap, "illegal qc_active transition (%08llx->%08llx)\n",

0 commit comments

Comments
 (0)