aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2018-09-20 10:30:55 -0400
committerJens Axboe <axboe@kernel.dk>2018-09-20 10:30:55 -0400
commit7ce5c8cd753f9afa8e79e9ec40351998e354f239 (patch)
treee96780b5a38b979bc8555717c5eb798edc171017
parentb228ba1cb95afbaeeb86cf06cd9fd6f6369c3b14 (diff)
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: 28361c403683 ("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>
-rw-r--r--drivers/ata/libata-core.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 172e32840256..3893f9bde1e6 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5359,10 +5359,20 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
5359 */ 5359 */
5360int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active) 5360int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active)
5361{ 5361{
5362 u64 done_mask, ap_qc_active = ap->qc_active;
5362 int nr_done = 0; 5363 int nr_done = 0;
5363 u64 done_mask;
5364 5364
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;
5366 5376
5367 if (unlikely(done_mask & qc_active)) { 5377 if (unlikely(done_mask & qc_active)) {
5368 ata_port_err(ap, "illegal qc_active transition (%08llx->%08llx)\n", 5378 ata_port_err(ap, "illegal qc_active transition (%08llx->%08llx)\n",