Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Hannes Reinecke and committed by
Tejun Heo
42b966fb 1308d7f0

+28 -2
+18
drivers/ata/libata-eh.c
··· 1580 1580 tf->hob_lbah = buf[10]; 1581 1581 tf->nsect = buf[12]; 1582 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 1586 return 0; 1585 1587 } ··· 1779 1777 memcpy(&qc->result_tf, &tf, sizeof(tf)); 1780 1778 qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; 1781 1779 qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; 1780 + if (qc->result_tf.auxiliary) { 1781 + char sense_key, asc, ascq; 1782 + 1783 + sense_key = (qc->result_tf.auxiliary >> 16) & 0xff; 1784 + asc = (qc->result_tf.auxiliary >> 8) & 0xff; 1785 + ascq = qc->result_tf.auxiliary & 0xff; 1786 + ata_dev_dbg(dev, "NCQ Autosense %02x/%02x/%02x\n", 1787 + sense_key, asc, ascq); 1788 + ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq); 1789 + qc->flags |= ATA_QCFLAG_SENSE_VALID; 1790 + } 1791 + 1782 1792 ehc->i.err_mask &= ~AC_ERR_DEV; 1783 1793 } 1784 1794 ··· 1819 1805 qc->err_mask |= AC_ERR_HSM; 1820 1806 return ATA_EH_RESET; 1821 1807 } 1808 + 1809 + /* Set by NCQ autosense */ 1810 + if (qc->flags & ATA_QCFLAG_SENSE_VALID) 1811 + return 0; 1822 1812 1823 1813 if (stat & (ATA_ERR | ATA_DF)) 1824 1814 qc->err_mask |= AC_ERR_DEV;
+7 -2
drivers/ata/libata-scsi.c
··· 270 270 ata_scsi_park_show, ata_scsi_park_store); 271 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 278 cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 276 279 277 280 scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); ··· 1780 1777 ((cdb[2] & 0x20) || need_sense)) { 1781 1778 ata_gen_passthru_sense(qc); 1782 1779 } else { 1783 - if (!need_sense) { 1780 + if (qc->flags & ATA_QCFLAG_SENSE_VALID) { 1781 + cmd->result = SAM_STAT_CHECK_CONDITION; 1782 + } else if (!need_sense) { 1784 1783 cmd->result = SAM_STAT_GOOD; 1785 1784 } else { 1786 1785 /* TODO: decide which descriptor format to use
+1
drivers/ata/libata.h
··· 137 137 struct scsi_host_template *sht); 138 138 extern void ata_scsi_scan_host(struct ata_port *ap, int sync); 139 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 141 extern void ata_scsi_media_change_notify(struct ata_device *dev); 141 142 extern void ata_scsi_hotplug(struct work_struct *work); 142 143 extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
+2
include/linux/ata.h
··· 525 525 #define ata_id_cdb_intr(id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20) 526 526 #define ata_id_has_da(id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4)) 527 527 #define ata_id_has_devslp(id) ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8)) 528 + #define ata_id_has_ncq_autosense(id) \ 529 + ((id)[ATA_ID_FEATURE_SUPP] & (1 << 7)) 528 530 529 531 static inline bool ata_id_has_hipm(const u16 *id) 530 532 {