diff options
author | Hannes Reinecke <hare@suse.de> | 2015-03-27 11:46:35 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2015-03-27 11:59:22 -0400 |
commit | 42b966fbf35da9c87f08d98f9b8978edf9e717cf (patch) | |
tree | a7fd32da1b3a746cab71966d42a08aeeb0d7203d /drivers/ata | |
parent | 1308d7f0107b264b480e7048dc345fc6b7408e7e (diff) |
libata: Implement NCQ autosense
Some newer devices support NCQ autosense (cf ACS-4), so we should
be using it to retrieve the sense code and speed up recovery.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-eh.c | 18 | ||||
-rw-r--r-- | drivers/ata/libata-scsi.c | 9 | ||||
-rw-r--r-- | drivers/ata/libata.h | 1 |
3 files changed, 26 insertions, 2 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 50ffd4e98978..c9b19949708c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -1580,6 +1580,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev, | |||
1580 | tf->hob_lbah = buf[10]; | 1580 | tf->hob_lbah = buf[10]; |
1581 | tf->nsect = buf[12]; | 1581 | tf->nsect = buf[12]; |
1582 | tf->hob_nsect = buf[13]; | 1582 | tf->hob_nsect = buf[13]; |
1583 | if (ata_id_has_ncq_autosense(dev->id)) | ||
1584 | tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16]; | ||
1583 | 1585 | ||
1584 | return 0; | 1586 | return 0; |
1585 | } | 1587 | } |
@@ -1777,6 +1779,18 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) | |||
1777 | memcpy(&qc->result_tf, &tf, sizeof(tf)); | 1779 | memcpy(&qc->result_tf, &tf, sizeof(tf)); |
1778 | qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; | 1780 | qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; |
1779 | qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; | 1781 | qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; |
1782 | if (qc->result_tf.auxiliary) { | ||
1783 | char sense_key, asc, ascq; | ||
1784 | |||
1785 | sense_key = (qc->result_tf.auxiliary >> 16) & 0xff; | ||
1786 | asc = (qc->result_tf.auxiliary >> 8) & 0xff; | ||
1787 | ascq = qc->result_tf.auxiliary & 0xff; | ||
1788 | ata_dev_dbg(dev, "NCQ Autosense %02x/%02x/%02x\n", | ||
1789 | sense_key, asc, ascq); | ||
1790 | ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq); | ||
1791 | qc->flags |= ATA_QCFLAG_SENSE_VALID; | ||
1792 | } | ||
1793 | |||
1780 | ehc->i.err_mask &= ~AC_ERR_DEV; | 1794 | ehc->i.err_mask &= ~AC_ERR_DEV; |
1781 | } | 1795 | } |
1782 | 1796 | ||
@@ -1806,6 +1820,10 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, | |||
1806 | return ATA_EH_RESET; | 1820 | return ATA_EH_RESET; |
1807 | } | 1821 | } |
1808 | 1822 | ||
1823 | /* Set by NCQ autosense */ | ||
1824 | if (qc->flags & ATA_QCFLAG_SENSE_VALID) | ||
1825 | return 0; | ||
1826 | |||
1809 | if (stat & (ATA_ERR | ATA_DF)) | 1827 | if (stat & (ATA_ERR | ATA_DF)) |
1810 | qc->err_mask |= AC_ERR_DEV; | 1828 | qc->err_mask |= AC_ERR_DEV; |
1811 | else | 1829 | else |
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index bb57d81083ca..3ac5be3acdbe 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -270,8 +270,11 @@ DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR, | |||
270 | ata_scsi_park_show, ata_scsi_park_store); | 270 | ata_scsi_park_show, ata_scsi_park_store); |
271 | EXPORT_SYMBOL_GPL(dev_attr_unload_heads); | 271 | EXPORT_SYMBOL_GPL(dev_attr_unload_heads); |
272 | 272 | ||
273 | static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) | 273 | void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) |
274 | { | 274 | { |
275 | if (!cmd) | ||
276 | return; | ||
277 | |||
275 | cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; | 278 | cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; |
276 | 279 | ||
277 | scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); | 280 | scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); |
@@ -1777,7 +1780,9 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) | |||
1777 | ((cdb[2] & 0x20) || need_sense)) { | 1780 | ((cdb[2] & 0x20) || need_sense)) { |
1778 | ata_gen_passthru_sense(qc); | 1781 | ata_gen_passthru_sense(qc); |
1779 | } else { | 1782 | } else { |
1780 | if (!need_sense) { | 1783 | if (qc->flags & ATA_QCFLAG_SENSE_VALID) { |
1784 | cmd->result = SAM_STAT_CHECK_CONDITION; | ||
1785 | } else if (!need_sense) { | ||
1781 | cmd->result = SAM_STAT_GOOD; | 1786 | cmd->result = SAM_STAT_GOOD; |
1782 | } else { | 1787 | } else { |
1783 | /* TODO: decide which descriptor format to use | 1788 | /* TODO: decide which descriptor format to use |
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index f840ca18a7c0..8cfdd9616d16 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h | |||
@@ -137,6 +137,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host, | |||
137 | struct scsi_host_template *sht); | 137 | struct scsi_host_template *sht); |
138 | extern void ata_scsi_scan_host(struct ata_port *ap, int sync); | 138 | extern void ata_scsi_scan_host(struct ata_port *ap, int sync); |
139 | extern int ata_scsi_offline_dev(struct ata_device *dev); | 139 | extern int ata_scsi_offline_dev(struct ata_device *dev); |
140 | extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq); | ||
140 | extern void ata_scsi_media_change_notify(struct ata_device *dev); | 141 | extern void ata_scsi_media_change_notify(struct ata_device *dev); |
141 | extern void ata_scsi_hotplug(struct work_struct *work); | 142 | extern void ata_scsi_hotplug(struct work_struct *work); |
142 | extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); | 143 | extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); |