diff options
-rw-r--r-- | drivers/ata/libata-core.c | 19 | ||||
-rw-r--r-- | drivers/ata/libata-eh.c | 33 | ||||
-rw-r--r-- | include/linux/libata.h | 3 |
3 files changed, 53 insertions, 2 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 86c10cc751e9..124b6f111cc3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -5797,6 +5797,22 @@ static void fill_result_tf(struct ata_queued_cmd *qc) | |||
5797 | ap->ops->tf_read(ap, &qc->result_tf); | 5797 | ap->ops->tf_read(ap, &qc->result_tf); |
5798 | } | 5798 | } |
5799 | 5799 | ||
5800 | static void ata_verify_xfer(struct ata_queued_cmd *qc) | ||
5801 | { | ||
5802 | struct ata_device *dev = qc->dev; | ||
5803 | |||
5804 | if (ata_tag_internal(qc->tag)) | ||
5805 | return; | ||
5806 | |||
5807 | if (ata_is_nodata(qc->tf.protocol)) | ||
5808 | return; | ||
5809 | |||
5810 | if ((dev->mwdma_mask || dev->udma_mask) && ata_is_pio(qc->tf.protocol)) | ||
5811 | return; | ||
5812 | |||
5813 | dev->flags &= ~ATA_DFLAG_DUBIOUS_XFER; | ||
5814 | } | ||
5815 | |||
5800 | /** | 5816 | /** |
5801 | * ata_qc_complete - Complete an active ATA command | 5817 | * ata_qc_complete - Complete an active ATA command |
5802 | * @qc: Command to complete | 5818 | * @qc: Command to complete |
@@ -5868,6 +5884,9 @@ void ata_qc_complete(struct ata_queued_cmd *qc) | |||
5868 | break; | 5884 | break; |
5869 | } | 5885 | } |
5870 | 5886 | ||
5887 | if (unlikely(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) | ||
5888 | ata_verify_xfer(qc); | ||
5889 | |||
5871 | __ata_qc_complete(qc); | 5890 | __ata_qc_complete(qc); |
5872 | } else { | 5891 | } else { |
5873 | if (qc->flags & ATA_QCFLAG_EH_SCHEDULED) | 5892 | if (qc->flags & ATA_QCFLAG_EH_SCHEDULED) |
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7d766ada7a5d..359a5ace8473 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -456,9 +456,20 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
456 | spin_lock_irqsave(ap->lock, flags); | 456 | spin_lock_irqsave(ap->lock, flags); |
457 | 457 | ||
458 | __ata_port_for_each_link(link, ap) { | 458 | __ata_port_for_each_link(link, ap) { |
459 | struct ata_eh_context *ehc = &link->eh_context; | ||
460 | struct ata_device *dev; | ||
461 | |||
459 | memset(&link->eh_context, 0, sizeof(link->eh_context)); | 462 | memset(&link->eh_context, 0, sizeof(link->eh_context)); |
460 | link->eh_context.i = link->eh_info; | 463 | link->eh_context.i = link->eh_info; |
461 | memset(&link->eh_info, 0, sizeof(link->eh_info)); | 464 | memset(&link->eh_info, 0, sizeof(link->eh_info)); |
465 | |||
466 | ata_link_for_each_dev(dev, link) { | ||
467 | int devno = dev->devno; | ||
468 | |||
469 | ehc->saved_xfer_mode[devno] = dev->xfer_mode; | ||
470 | if (ata_ncq_enabled(dev)) | ||
471 | ehc->saved_ncq_enabled |= 1 << devno; | ||
472 | } | ||
462 | } | 473 | } |
463 | 474 | ||
464 | ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; | 475 | ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; |
@@ -2376,11 +2387,27 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, | |||
2376 | int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) | 2387 | int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) |
2377 | { | 2388 | { |
2378 | struct ata_port *ap = link->ap; | 2389 | struct ata_port *ap = link->ap; |
2390 | struct ata_device *dev; | ||
2391 | int rc; | ||
2379 | 2392 | ||
2380 | /* has private set_mode? */ | 2393 | /* has private set_mode? */ |
2381 | if (ap->ops->set_mode) | 2394 | if (ap->ops->set_mode) |
2382 | return ap->ops->set_mode(link, r_failed_dev); | 2395 | rc = ap->ops->set_mode(link, r_failed_dev); |
2383 | return ata_do_set_mode(link, r_failed_dev); | 2396 | else |
2397 | rc = ata_do_set_mode(link, r_failed_dev); | ||
2398 | |||
2399 | /* if transfer mode has changed, set DUBIOUS_XFER on device */ | ||
2400 | ata_link_for_each_dev(dev, link) { | ||
2401 | struct ata_eh_context *ehc = &link->eh_context; | ||
2402 | u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno]; | ||
2403 | u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno)); | ||
2404 | |||
2405 | if (dev->xfer_mode != saved_xfer_mode || | ||
2406 | ata_ncq_enabled(dev) != saved_ncq) | ||
2407 | dev->flags |= ATA_DFLAG_DUBIOUS_XFER; | ||
2408 | } | ||
2409 | |||
2410 | return rc; | ||
2384 | } | 2411 | } |
2385 | 2412 | ||
2386 | static int ata_link_nr_enabled(struct ata_link *link) | 2413 | static int ata_link_nr_enabled(struct ata_link *link) |
@@ -2441,6 +2468,8 @@ static int ata_eh_schedule_probe(struct ata_device *dev) | |||
2441 | ata_dev_init(dev); | 2468 | ata_dev_init(dev); |
2442 | ehc->did_probe_mask |= (1 << dev->devno); | 2469 | ehc->did_probe_mask |= (1 << dev->devno); |
2443 | ehc->i.action |= ATA_EH_SOFTRESET; | 2470 | ehc->i.action |= ATA_EH_SOFTRESET; |
2471 | ehc->saved_xfer_mode[dev->devno] = 0; | ||
2472 | ehc->saved_ncq_enabled &= ~(1 << dev->devno); | ||
2444 | 2473 | ||
2445 | return 1; | 2474 | return 1; |
2446 | } | 2475 | } |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 74f1255e2524..131fb6625e14 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -143,6 +143,7 @@ enum { | |||
143 | ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */ | 143 | ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */ |
144 | ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */ | 144 | ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */ |
145 | ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ | 145 | ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ |
146 | ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */ | ||
146 | ATA_DFLAG_INIT_MASK = (1 << 24) - 1, | 147 | ATA_DFLAG_INIT_MASK = (1 << 24) - 1, |
147 | 148 | ||
148 | ATA_DFLAG_DETACH = (1 << 24), | 149 | ATA_DFLAG_DETACH = (1 << 24), |
@@ -560,6 +561,8 @@ struct ata_eh_context { | |||
560 | int tries[ATA_MAX_DEVICES]; | 561 | int tries[ATA_MAX_DEVICES]; |
561 | unsigned int classes[ATA_MAX_DEVICES]; | 562 | unsigned int classes[ATA_MAX_DEVICES]; |
562 | unsigned int did_probe_mask; | 563 | unsigned int did_probe_mask; |
564 | unsigned int saved_ncq_enabled; | ||
565 | u8 saved_xfer_mode[ATA_MAX_DEVICES]; | ||
563 | }; | 566 | }; |
564 | 567 | ||
565 | struct ata_acpi_drive | 568 | struct ata_acpi_drive |