libata sense code update
cover libata sense code update
Hi all,
with ACS-4 ATA drives inherited the possibility to return SCSI sense codes, allowing for a more precise error handling. Not to mention a nice alignment with the SCSI error handling. This patchset implements both, support for NCQ Autosense and the sense data reporting feature set.
Plus some whitespace and assorted cleanups.
And I've added some tracepoints, too.
Hannes Reinecke (9):
libata: use READ_LOG_DMA_EXT
libata: whitespace cleanup in ata_get_cmd_descript()
libata: whitespace fixes in ata_to_sense_error() ide,ata: Rename ATA_IDX to ATA_SENSE
libata: use status bit definitions in ata_dump_status()
libata: Implement NCQ autosense
libata: Implement support for sense data reporting
libata-eh: Set 'information' field for autosense
libata: Add tracepoints
drivers/ata/Makefile | 3 +- drivers/ata/libata-core.c | 32 ++++- drivers/ata/libata-eh.c | 168 ++++++++++++++++++---- drivers/ata/libata-scsi.c | 111 ++++++++++----- drivers/ata/libata-trace.c | 151 ++++++++++++++++++++ drivers/ata/libata.h | 6 +- drivers/ide/ide-lib.c | 4 +- drivers/ide/ide-probe.c | 2 +- drivers/scsi/scsi_error.c | 31 ++++ include/linux/ata.h | 29 +++- include/scsi/scsi_eh.h | 1 + include/trace/events/libata.h | 325 ++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 786 insertions(+), 77 deletions(-) create mode 100644 drivers/ata/libata-trace.c create mode 100644 include/trace/events/libata.h
Signature · 1 line
1.8.5.2
PATCH 1/9 libata: use READ_LOG_DMA_EXT
If READ_LOG_DMA_EXT is supported we should try to use it for reading the log pages.
--- drivers/ata/libata-eh.c | 9 +++++++-- include/linux/ata.h | 7 +++++++ 2 files changed, 14 insertions(+), 2 deletions(-)
drivers/ata/libata-eh.c +7 -2
@@ -1510,13 +1510,18 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,DPRINTK ("read log page - log 0x%x, page 0x%x\n" , log, page);ata_tf_init (dev, &tf); - tf.command =ATA_CMD_READ_LOG_EXT ; +if (dev->dma_mode &&ata_id_has_read_log_dma_ext (dev->id)) { + tf.command =ATA_CMD_READ_LOG_DMA_EXT ; + tf.protocol =ATA_PROT_DMA ; + }else { + tf.command =ATA_CMD_READ_LOG_EXT ; + tf.protocol =ATA_PROT_PIO ; + } tf.lbal = log; tf.lbam = page; tf.nsect = sectors; tf.hob_nsect = sectors >>8 ; tf.flags |=ATA_TFLAG_ISADDR |ATA_TFLAG_LBA48 |ATA_TFLAG_DEVICE ; - tf.protocol =ATA_PROT_PIO ; err_mask =ata_exec_internal (dev, &tf,NULL ,DMA_FROM_DEVICE , buf, sectors *ATA_SECT_SIZE ,0 );
include/linux/ata.h +7 -0
@@ -696,6 +696,13 @@ static inline bool ata_id_wcache_enabled(const u16 *id)return id[ATA_ID_CFS_ENABLE_1 ] & (1 <<5 ); } +static inline bool ata_id_has_read_log_dma_ext (const u16 *id) +{ +if (!(id[ATA_ID_CFS_ENABLE_2 ] & (1 <<15 ))) +return false; +return id[ATA_ID_COMMAND_SET_3 ] & (1 <<3 ); +} +/** * ata_id_major_version - get ATA level of drive * @id: Identify data
Signature · 1 line
1.8.5.2
PATCH 2/9 libata: whitespace cleanup in ata_get_cmd_descript()
In reply to Hannes Reinecke--- drivers/ata/libata-eh.c | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-)
drivers/ata/libata-eh.c +25 -25
@@ -2294,27 +2294,27 @@ const char *ata_get_cmd_descript(u8 command)const char *text; } cmd_descr[] = { { ATA_CMD_DEV_RESET, "DEVICE RESET" }, - { ATA_CMD_CHK_POWER, "CHECK POWER MODE" }, - { ATA_CMD_STANDBY, "STANDBY" }, - { ATA_CMD_IDLE, "IDLE" }, - { ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" }, - { ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" }, + { ATA_CMD_CHK_POWER, "CHECK POWER MODE" }, + { ATA_CMD_STANDBY, "STANDBY" }, + { ATA_CMD_IDLE, "IDLE" }, + { ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" }, + { ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" }, { ATA_CMD_DOWNLOAD_MICRO_DMA, "DOWNLOAD MICROCODE DMA" }, { ATA_CMD_NOP, "NOP" }, - { ATA_CMD_FLUSH, "FLUSH CACHE" }, - { ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" }, - { ATA_CMD_ID_ATA, "IDENTIFY DEVICE" }, - { ATA_CMD_ID_ATAPI, "IDENTIFY PACKET DEVICE" }, - { ATA_CMD_SERVICE, "SERVICE" }, - { ATA_CMD_READ, "READ DMA" }, - { ATA_CMD_READ_EXT, "READ DMA EXT" }, - { ATA_CMD_READ_QUEUED, "READ DMA QUEUED" }, - { ATA_CMD_READ_STREAM_EXT, "READ STREAM EXT" }, + { ATA_CMD_FLUSH, "FLUSH CACHE" }, + { ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" }, + { ATA_CMD_ID_ATA, "IDENTIFY DEVICE" }, + { ATA_CMD_ID_ATAPI, "IDENTIFY PACKET DEVICE" }, + { ATA_CMD_SERVICE, "SERVICE" }, + { ATA_CMD_READ, "READ DMA" }, + { ATA_CMD_READ_EXT, "READ DMA EXT" }, + { ATA_CMD_READ_QUEUED, "READ DMA QUEUED" }, + { ATA_CMD_READ_STREAM_EXT, "READ STREAM EXT" }, { ATA_CMD_READ_STREAM_DMA_EXT, "READ STREAM DMA EXT" }, - { ATA_CMD_WRITE, "WRITE DMA" }, - { ATA_CMD_WRITE_EXT, "WRITE DMA EXT" }, - { ATA_CMD_WRITE_QUEUED, "WRITE DMA QUEUED EXT" }, - { ATA_CMD_WRITE_STREAM_EXT, "WRITE STREAM EXT" }, + { ATA_CMD_WRITE, "WRITE DMA" }, + { ATA_CMD_WRITE_EXT, "WRITE DMA EXT" }, + { ATA_CMD_WRITE_QUEUED, "WRITE DMA QUEUED EXT" }, + { ATA_CMD_WRITE_STREAM_EXT, "WRITE STREAM EXT" }, { ATA_CMD_WRITE_STREAM_DMA_EXT, "WRITE STREAM DMA EXT" }, { ATA_CMD_WRITE_FUA_EXT, "WRITE DMA FUA EXT" }, { ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" },
@@ -2330,7 +2330,7 @@ const char *ata_get_cmd_descript(u8 command) { ATA_CMD_READ_MULTI_EXT, "READ MULTIPLE EXT" }, { ATA_CMD_WRITE_MULTI, "WRITE MULTIPLE" }, { ATA_CMD_WRITE_MULTI_EXT, "WRITE MULTIPLE EXT" }, - { ATA_CMD_WRITE_MULTI_FUA_EXT, "WRITE MULTIPLE FUA EXT" }, + { ATA_CMD_WRITE_MULTI_FUA_EXT, "WRITE MULTIPLE FUA EXT" }, { ATA_CMD_SET_FEATURES, "SET FEATURES" }, { ATA_CMD_SET_MULTI, "SET MULTIPLE MODE" }, { ATA_CMD_VERIFY, "READ VERIFY SECTOR(S)" },
@@ -2347,12 +2347,12 @@ const char *ata_get_cmd_descript(u8 command) { ATA_CMD_READ_LOG_EXT, "READ LOG EXT" }, { ATA_CMD_WRITE_LOG_EXT, "WRITE LOG EXT" }, { ATA_CMD_READ_LOG_DMA_EXT, "READ LOG DMA EXT" }, - { ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" }, + { ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" }, { ATA_CMD_TRUSTED_NONDATA, "TRUSTED NON-DATA" }, { ATA_CMD_TRUSTED_RCV, "TRUSTED RECEIVE" }, - { ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" }, + { ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" }, { ATA_CMD_TRUSTED_SND, "TRUSTED SEND" }, - { ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" }, + { ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" }, { ATA_CMD_PMP_READ, "READ BUFFER" }, { ATA_CMD_PMP_READ_DMA, "READ BUFFER DMA" }, { ATA_CMD_PMP_WRITE, "WRITE BUFFER" },
@@ -2369,12 +2369,12 @@ const char *ata_get_cmd_descript(u8 command) { ATA_CMD_MEDIA_LOCK, "DOOR LOCK" }, { ATA_CMD_MEDIA_UNLOCK, "DOOR UNLOCK" }, { ATA_CMD_DSM, "DATA SET MANAGEMENT" }, - { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" }, - { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" }, + { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" }, + { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" }, { ATA_CMD_CFA_WRITE_NE, "CFA WRITE SECTORS WITHOUT ERASE" }, { ATA_CMD_CFA_TRANS_SECT, "CFA TRANSLATE SECTOR" }, { ATA_CMD_CFA_ERASE, "CFA ERASE SECTORS" }, - { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" }, + { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" }, { ATA_CMD_REQ_SENSE_DATA, "REQUEST SENSE DATA EXT" }, { ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" }, { ATA_CMD_READ_LONG, "READ LONG (with retries)" },
Signature · 1 line
1.8.5.2
PATCH 3/9 libata: whitespace fixes in ata_to_sense_error()
In reply to Hannes Reinecke--- drivers/ata/libata-scsi.c | 61 +++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 21 deletions(-)
drivers/ata/libata-scsi.c +40 -21
@@ -849,40 +849,59 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,/* Based on the 3ware driver translation table */ static const unsigned char sense_table[][4 ] = {/* BBD|ECC|ID|MAR */ - {0xd1 ,ABORTED_COMMAND ,0x00 ,0x00 },// Device busy Aborted command + {0xd1 ,ABORTED_COMMAND ,0x00 ,0x00 }, +// Device busy Aborted command /* BBD|ECC|ID */ - {0xd0 ,ABORTED_COMMAND ,0x00 ,0x00 },// Device busy Aborted command + {0xd0 ,ABORTED_COMMAND ,0x00 ,0x00 }, +// Device busy Aborted command /* ECC|MC|MARK */ - {0x61 ,HARDWARE_ERROR ,0x00 ,0x00 },// Device fault Hardware error + {0x61 ,HARDWARE_ERROR ,0x00 ,0x00 }, +// Device fault Hardware error /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */ - {0x84 ,ABORTED_COMMAND ,0x47 ,0x00 },// Data CRC error SCSI parity error + {0x84 ,ABORTED_COMMAND ,0x47 ,0x00 }, +// Data CRC error SCSI parity error /* MC|ID|ABRT|TRK0|MARK */ - {0x37 ,NOT_READY ,0x04 ,0x00 },// Unit offline Not ready + {0x37 ,NOT_READY ,0x04 ,0x00 }, +// Unit offline Not ready /* MCR|MARK */ - {0x09 ,NOT_READY ,0x04 ,0x00 },// Unrecovered disk error Not ready + {0x09 ,NOT_READY ,0x04 ,0x00 }, +// Unrecovered disk error Not ready /* Bad address mark */ - {0x01 ,MEDIUM_ERROR ,0x13 ,0x00 },// Address mark not found Address mark not found for data field -/* TRK0 */ - {0x02 ,HARDWARE_ERROR ,0x00 ,0x00 },// Track 0 not found Hardware error + {0x01 ,MEDIUM_ERROR ,0x13 ,0x00 }, +// Address mark not found for data field +/* TRK0 - Track 0 not found */ + {0x02 ,HARDWARE_ERROR ,0x00 ,0x00 }, +// Hardware error /* Abort: 0x04 is not translated here, see below */ /* Media change request */ - {0x08 ,NOT_READY ,0x04 ,0x00 },// Media change request FIXME: faking offline -/* SRV/IDNF */ - {0x10 ,ILLEGAL_REQUEST ,0x21 ,0x00 },// ID not found Logical address out of range -/* MC */ - {0x20 ,UNIT_ATTENTION ,0x28 ,0x00 },// Media Changed Not ready to ready change, medium may have changed -/* ECC */ - {0x40 ,MEDIUM_ERROR ,0x11 ,0x04 },// Uncorrectable ECC error Unrecovered read error + {0x08 ,NOT_READY ,0x04 ,0x00 }, +// FIXME: faking offline +/* SRV/IDNF - ID not found */ + {0x10 ,ILLEGAL_REQUEST ,0x21 ,0x00 }, +// Logical address out of range +/* MC - Media Changed */ + {0x20 ,UNIT_ATTENTION ,0x28 ,0x00 }, +// Not ready to ready change, medium may have changed +/* ECC - Uncorrectable ECC error */ + {0x40 ,MEDIUM_ERROR ,0x11 ,0x04 }, +// Unrecovered read error /* BBD - block marked bad */ - {0x80 ,MEDIUM_ERROR ,0x11 ,0x04 },// Block marked bad Medium error, unrecovered read error + {0x80 ,MEDIUM_ERROR ,0x11 ,0x04 }, +// Block marked bad Medium error, unrecovered read error {0xFF ,0xFF ,0xFF ,0xFF },// END mark };static const unsigned char stat_table[][4 ] = {/* Must be first because BUSY means no other bits valid */ - {0x80 ,ABORTED_COMMAND ,0x47 ,0x00 },// Busy, fake parity for now - {0x20 ,HARDWARE_ERROR ,0x44 ,0x00 },// Device fault, internal target failure - {0x08 ,ABORTED_COMMAND ,0x47 ,0x00 },// Timed out in xfer, fake parity for now - {0x04 ,RECOVERED_ERROR ,0x11 ,0x00 },// Recovered ECC error Medium error, recovered + {0x80 ,ABORTED_COMMAND ,0x47 ,0x00 }, +// Busy, fake parity for now + {0x40 ,ILLEGAL_REQUEST ,0x21 ,0x04 }, +// Device ready, unaligned write command + {0x20 ,HARDWARE_ERROR ,0x44 ,0x00 }, +// Device fault, internal target failure + {0x08 ,ABORTED_COMMAND ,0x47 ,0x00 }, +// Timed out in xfer, fake parity for now + {0x04 ,RECOVERED_ERROR ,0x11 ,0x00 }, +// Recovered ECC error Medium error, recovered {0xFF ,0xFF ,0xFF ,0xFF },// END mark };
Signature · 1 line
1.8.5.2
PATCH 4/9 ide,ata: Rename ATA_IDX to ATA_SENSE
In reply to Hannes ReineckeATA-8 defines bit 1 as 'ATA_SENSE', not 'ATA_IDX'.
--- drivers/ata/libata-scsi.c | 2 +- drivers/ide/ide-lib.c | 4 ++-- drivers/ide/ide-probe.c | 2 +- include/linux/ata.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-)
drivers/ata/libata-scsi.c +1 -1
@@ -804,7 +804,7 @@ static void ata_dump_status(unsigned id, struct ata_taskfile *tf)if (stat &0x10 )printk ("SeekComplete " );if (stat &0x08 )printk ("DataRequest " );if (stat &0x04 )printk ("CorrectedError " ); -if (stat &0x02 )printk ("Index " ); +if (stat &0x02 )printk ("Sense " );if (stat &0x01 )printk ("Error " );printk ("}\n" );
drivers/ide/ide-lib.c +2 -2
@@ -148,8 +148,8 @@ u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)printk (KERN_CONT "DataRequest " );if (stat &ATA_CORR )printk (KERN_CONT "CorrectedError " ); -if (stat &ATA_IDX ) -printk (KERN_CONT "Index " ); +if (stat &ATA_SENSE ) +printk (KERN_CONT "Sense " );if (stat &ATA_ERR )printk (KERN_CONT "Error " ); }
drivers/ide/ide-probe.c +1 -1
@@ -273,7 +273,7 @@ int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id, int irq_ctx) (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) { a = tp_ops->read_altstatus (hwif); s = tp_ops->read_status (hwif); -if ((a ^ s) & ~ATA_IDX ) +if ((a ^ s) & ~ATA_SENSE )/* ancient Seagate drives, broken interfaces */ printk(KERN_INFO "%s: probing with STATUS(0x%02x) " "instead of ALTSTATUS(0x%02x)\n",
include/linux/ata.h +1 -1
@@ -177,7 +177,7 @@ enum {ATA_DSC = (1 <<4 ),/* drive seek complete */ ATA_DRQ = (1 <<3 ),/* data request i/o */ ATA_CORR = (1 <<2 ),/* corrected data error */ -ATA_IDX = (1 <<1 ),/* index */ +ATA_SENSE = (1 <<1 ),/* sense code available */ ATA_ERR = (1 <<0 ),/* have an error */ ATA_SRST = (1 <<2 ),/* software reset */ ATA_ICRC = (1 << 7), /* interface CRC error */
Signature · 1 line
1.8.5.2
Re: [PATCH 4/9] ide,ata: Rename ATA_IDX to ATA_SENSE
From: Hannes Reinecke <[email protected]>
Date: Fri, 27 Mar 2015 16:46:33 +0100
Quoted 3 lines
ATA-8 defines bit 1 as '
ATA_SENSE', not 'ATA_IDX'.Signed-off-by Hannes Reinecke <[email protected]>
PATCH 5/9 libata: use status bit definitions in ata_dump_status()
In reply to Hannes ReineckeUse the bit definitions for better readability.
--- drivers/ata/libata-scsi.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
drivers/ata/libata-scsi.c +15 -14
@@ -799,26 +799,27 @@ static void ata_dump_status(unsigned id, struct ata_taskfile *tf)if (stat &ATA_BUSY ) {printk ("Busy }\n" );/* Data is not valid in this case */ }else { -if (stat &0x40 )printk ("DriveReady " ); -if (stat &0x20 )printk ("DeviceFault " ); -if (stat &0x10 )printk ("SeekComplete " ); -if (stat &0x08 )printk ("DataRequest " ); -if (stat &0x04 )printk ("CorrectedError " ); -if (stat &0x02 )printk ("Sense " ); -if (stat &0x01 )printk ("Error " ); +if (stat &ATA_DRDY )printk ("DriveReady " ); +if (stat &ATA_DF )printk ("DeviceFault " ); +if (stat &ATA_DSC )printk ("SeekComplete " ); +if (stat &ATA_DRQ )printk ("DataRequest " ); +if (stat &ATA_CORR )printk ("CorrectedError " ); +if (stat &ATA_SENSE )printk ("Sense " ); +if (stat &ATA_ERR )printk ("Error " );printk ("}\n" );if (err) {printk (KERN_WARNING "ata%u: error=0x%02x { " , id, err); -if (err &0x04 )printk ("DriveStatusError " ); -if (err &0x80 ) { -if (err &0x04 )printk ("BadCRC " ); +if (err &ATA_ABORTED )printk ("DriveStatusError " ); +if (err &ATA_ICRC ) { +if (err &ATA_ABORTED ) +printk ("BadCRC " );else printk ("Sector " ); } -if (err &0x40 )printk ("UncorrectableError " ); -if (err &0x10 )printk ("SectorIdNotFound " ); -if (err &0x02 )printk ("TrackZeroNotFound " ); -if (err &0x01 )printk ("AddrMarkNotFound " ); +if (err &ATA_UNC )printk ("UncorrectableError " ); +if (err &ATA_IDNF )printk ("SectorIdNotFound " ); +if (err &ATA_TRK0NF )printk ("TrackZeroNotFound " ); +if (err &ATA_AMNF )printk ("AddrMarkNotFound " );printk ("}\n" ); } }
Signature · 1 line
1.8.5.2
PATCH 6/9 libata: Implement NCQ autosense
In reply to Hannes ReineckeSome newer devices support NCQ autosense (cf ACS-4), so we should be using it to retrieve the sense code and speed up recovery.
--- drivers/ata/libata-eh.c | 18 ++++++++++++++++++ drivers/ata/libata-scsi.c | 9 +++++++-- drivers/ata/libata.h | 1 + include/linux/ata.h | 2 ++ 4 files changed, 28 insertions(+), 2 deletions(-)
drivers/ata/libata-eh.c +18 -0
@@ -1580,6 +1580,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev, tf->hob_lbah = buf[10 ]; tf->nsect = buf[12 ]; tf->hob_nsect = buf[13 ]; +if (ata_id_has_ncq_autosense (dev->id)) + tf->auxiliary = buf[14 ] <<16 | buf[15 ] <<8 | buf[16 ];return 0 ; }
@@ -1777,6 +1779,18 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)memcpy (&qc->result_tf, &tf,sizeof (tf)); qc->result_tf.flags =ATA_TFLAG_ISADDR |ATA_TFLAG_LBA |ATA_TFLAG_LBA48 ; qc->err_mask |=AC_ERR_DEV |AC_ERR_NCQ ; +if (qc->result_tf.auxiliary) { +char sense_key, asc, ascq; + + sense_key = (qc->result_tf.auxiliary >>16 ) &0xff ; + asc = (qc->result_tf.auxiliary >>8 ) &0xff ; + ascq = qc->result_tf.auxiliary &0xff ; +ata_dev_dbg (dev,"NCQ Autosense %02x/%02x/%02x\n" , + sense_key, asc, ascq); +ata_scsi_set_sense (qc->scsicmd, sense_key, asc, ascq); + qc->flags |=ATA_QCFLAG_SENSE_VALID ; + } + ehc->i.err_mask &= ~AC_ERR_DEV ; }
@@ -1806,6 +1820,10 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,return ATA_EH_RESET ; } +/* Set by NCQ autosense */ +if (qc->flags &ATA_QCFLAG_SENSE_VALID ) +return 0 ; +if (stat & (ATA_ERR |ATA_DF )) qc->err_mask |=AC_ERR_DEV ;else
drivers/ata/libata-scsi.c +7 -2
@@ -270,8 +270,11 @@ DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR, ata_scsi_park_show, ata_scsi_park_store);EXPORT_SYMBOL_GPL (dev_attr_unload_heads); -static void ata_scsi_set_sense (struct scsi_cmnd *cmd,u8 sk,u8 asc,u8 ascq) +void ata_scsi_set_sense (struct scsi_cmnd *cmd,u8 sk,u8 asc,u8 ascq) { +if (!cmd) +return ; + cmd->result = (DRIVER_SENSE <<24 ) |SAM_STAT_CHECK_CONDITION ;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) ((cdb[2] & 0x20) || need_sense)) { ata_gen_passthru_sense(qc); } else { -if (!need_sense) { +if (qc->flags &ATA_QCFLAG_SENSE_VALID ) { + cmd->result =SAM_STAT_CHECK_CONDITION ; + }else if (!need_sense) { cmd->result =SAM_STAT_GOOD ; }else {/* TODO: decide which descriptor format to use
drivers/ata/libata.h +1 -0
@@ -137,6 +137,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht);extern void ata_scsi_scan_host (struct ata_port *ap,int sync);extern int ata_scsi_offline_dev (struct ata_device *dev); +extern void ata_scsi_set_sense (struct scsi_cmnd *cmd,u8 sk,u8 asc,u8 ascq);extern void ata_scsi_media_change_notify (struct ata_device *dev);extern void ata_scsi_hotplug (struct work_struct *work);extern void ata_schedule_scsi_eh (struct Scsi_Host *shost);
include/linux/ata.h +2 -0
@@ -525,6 +525,8 @@ struct ata_bmdma_prd {#define ata_id_cdb_intr (id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20)#define ata_id_has_da (id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4))#define ata_id_has_devslp (id) ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8)) +#define ata_id_has_ncq_autosense (id) \ + ((id)[ATA_ID_FEATURE_SUPP] & (1 << 7))static inline bool ata_id_has_hipm (const u16 *id) {
Signature · 1 line
1.8.5.2
PATCH 7/9 libata: Implement support for sense data reporting
In reply to Hannes ReineckeACS-4 defines a sense data reporting feature set.
This patch implements support for it.
--- drivers/ata/libata-core.c | 20 ++++++++++- drivers/ata/libata-eh.c | 86 +++++++++++++++++++++++++++++++++++++++++++++-- include/linux/ata.h | 18 ++++++++++ 3 files changed, 120 insertions(+), 4 deletions(-)
drivers/ata/libata-core.c +19 -1
@@ -2144,6 +2144,24 @@ static int ata_dev_config_ncq(struct ata_device *dev,return 0 ; } +static void ata_dev_config_sense_reporting (struct ata_device *dev) +{ +unsigned int err_mask; + +if (!ata_id_has_sense_reporting (dev->id)) +return ; + +if (ata_id_sense_reporting_enabled (dev->id)) +return ; + + err_mask =ata_dev_set_feature (dev,SETFEATURE_SENSE_DATA ,0x1 ); +if (err_mask) { +ata_dev_dbg (dev, +"failed to enable Sense Data Reporting, Emask 0x%x\n" , + err_mask); + } +} +/** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure
@@ -2366,7 +2384,7 @@ int ata_dev_configure(struct ata_device *dev) dev->devslp_timing[i] = sata_setting[j]; } } - +ata_dev_config_sense_reporting (dev); dev->cdb_len =16 ; }
drivers/ata/libata-eh.c +83 -3
110 lines not on this page · raw message
include/linux/ata.h +18 -0
@@ -94,6 +94,8 @@ enum {ATA_ID_SECTOR_SIZE =106 ,ATA_ID_WWN =108 ,ATA_ID_LOGICAL_SECTOR_SIZE =117 ,/* and 118 */ +ATA_ID_COMMAND_SET_3 =119 , +ATA_ID_COMMAND_SET_4 =120 ,ATA_ID_LAST_LUN =126 ,ATA_ID_DLF =128 , ATA_ID_CSFO = 129,
@@ -382,6 +384,8 @@ enum {SATA_SSP =0x06 ,/* Software Settings Preservation */ SATA_DEVSLP =0x09 ,/* Device Sleep */ +SETFEATURE_SENSE_DATA =0xC3 ,/* Sense Data Reporting feature */ +/* feature values for SET_MAX */ ATA_SET_MAX_ADDR =0x00 , ATA_SET_MAX_PASSWD = 0x01,
@@ -705,6 +709,20 @@ static inline bool ata_id_has_read_log_dma_ext(const u16 *id)return id[ATA_ID_COMMAND_SET_3 ] & (1 <<3 ); } +static inline bool ata_id_has_sense_reporting (const u16 *id) +{ +if (!(id[ATA_ID_CFS_ENABLE_2 ] & (1 <<15 ))) +return false; +return id[ATA_ID_COMMAND_SET_3 ] & (1 <<6 ); +} + +static inline bool ata_id_sense_reporting_enabled (const u16 *id) +{ +if (!(id[ATA_ID_CFS_ENABLE_2 ] & (1 <<15 ))) +return false; +return id[ATA_ID_COMMAND_SET_4 ] & (1 <<6 ); +} +/** * ata_id_major_version - get ATA level of drive * @id: Identify data
Signature · 1 line
1.8.5.2
PATCH 8/9 libata-eh: Set 'information' field for autosense
In reply to Hannes ReineckeIf NCQ autosense or the sense data reporting feature is enabled the LBA of the offending command should be stored in the sense data 'information' field.
--- drivers/ata/libata-core.c | 4 ++-- drivers/ata/libata-eh.c | 3 +++ drivers/ata/libata-scsi.c | 12 ++++++++++++ drivers/ata/libata.h | 5 ++++- drivers/scsi/scsi_error.c | 31 +++++++++++++++++++++++++++++++ include/scsi/scsi_eh.h | 1 + 6 files changed, 53 insertions(+), 3 deletions(-)
drivers/ata/libata-core.c +2 -2
@@ -691,11 +691,11 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)* RETURNS: * Block address read from @tf. */ -u64 ata_tf_read_block (struct ata_taskfile *tf,struct ata_device *dev) +u64 ata_tf_read_block (const struct ata_taskfile *tf,struct ata_device *dev) {u64 block =0 ; -if (tf->flags &ATA_TFLAG_LBA ) { +if (!dev || tf->flags &ATA_TFLAG_LBA ) {if (tf->flags &ATA_TFLAG_LBA48 ) { block |= (u64 )tf->hob_lbah <<40 ; block |= (u64 )tf->hob_lbam <<32 ;
drivers/ata/libata-eh.c +3 -0
@@ -1852,6 +1852,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)ata_dev_dbg (dev,"NCQ Autosense %02x/%02x/%02x\n" , sense_key, asc, ascq);ata_scsi_set_sense (qc->scsicmd, sense_key, asc, ascq); +ata_scsi_set_sense_information (qc->scsicmd, &qc->result_tf); qc->flags |=ATA_QCFLAG_SENSE_VALID ; }
@@ -1894,6 +1895,8 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, tmp =ata_eh_request_sense (qc, qc->scsicmd);if (tmp) qc->err_mask |= tmp; +else +ata_scsi_set_sense_information (qc->scsicmd, tf); }else {ata_dev_warn (qc->dev,"sense data available but port frozen\n" ); }
drivers/ata/libata-scsi.c +12 -0
@@ -280,6 +280,18 @@ void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)scsi_build_sense_buffer (0 , cmd->sense_buffer, sk, asc, ascq); } +void ata_scsi_set_sense_information (struct scsi_cmnd *cmd, +const struct ata_taskfile *tf) +{ +u64 information; + +if (!cmd) +return ; + + information =ata_tf_read_block (tf,NULL ); +scsi_set_sense_information (cmd->sense_buffer, information); +} +static ssize_t ata_scsi_em_message_store (struct device *dev,struct device_attribute *attr,const char *buf,size_t count)
drivers/ata/libata.h +4 -1
@@ -67,7 +67,8 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);extern int ata_build_rw_tf (struct ata_taskfile *tf,struct ata_device *dev,u64 block,u32 n_block,unsigned int tf_flags,unsigned int tag); -extern u64 ata_tf_read_block (struct ata_taskfile *tf,struct ata_device *dev); +extern u64 ata_tf_read_block (const struct ata_taskfile *tf, +struct ata_device *dev); extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen,
@@ -138,6 +139,8 @@ extern int ata_scsi_add_hosts(struct ata_host *host,extern void ata_scsi_scan_host (struct ata_port *ap,int sync);extern int ata_scsi_offline_dev (struct ata_device *dev);extern void ata_scsi_set_sense (struct scsi_cmnd *cmd,u8 sk,u8 asc,u8 ascq); +extern void ata_scsi_set_sense_information (struct scsi_cmnd *cmd, +const struct ata_taskfile *tf);extern void ata_scsi_media_change_notify (struct ata_device *dev);extern void ata_scsi_hotplug (struct work_struct *work);extern void ata_schedule_scsi_eh (struct Scsi_Host *shost);
drivers/scsi/scsi_error.c +31 -0
@@ -26,6 +26,7 @@#include <linux/blkdev.h> #include <linux/delay.h> #include <linux/jiffies.h> +#include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h>
@@ -2586,3 +2587,33 @@ void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) } }EXPORT_SYMBOL (scsi_build_sense_buffer); + +/** +* scsi_set_sense_information - set the information field in a +* formatted sense data buffer +* @buf: Where to build sense data +* @info: 64-bit information value to be set +* +**/ +void scsi_set_sense_information (u8 *buf,u64 info) +{ +if ((buf[0 ] &0x7f ) ==0x72 ) { +u8 *ucp, len; + + len = buf[7 ]; + ucp = (char *)scsi_sense_desc_find (buf, len +8 ,0 ); +if (!ucp) { + buf[7 ] = len +0xa ; + ucp = buf +8 + len; + } + ucp[0 ] =0 ; + ucp[1 ] =0xa ; + ucp[2 ] =0x80 ;/* Valid bit */ + ucp[3 ] =0 ; +put_unaligned_be64 (info, &ucp[4 ]); + }else if ((buf[0 ] &0x7f ) ==0x70 ) { + buf[0 ] |=0x80 ; +put_unaligned_be64 (info, &buf[3 ]); + } +} +EXPORT_SYMBOL (scsi_set_sense_information);
include/scsi/scsi_eh.h +1 -0
@@ -59,6 +59,7 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, u64 * info_out);extern void scsi_build_sense_buffer (int desc,u8 *buf,u8 key,u8 asc,u8 ascq); +extern void scsi_set_sense_information (u8 *buf,u64 info);extern int scsi_ioctl_reset (struct scsi_device *,int __user *);
Signature · 1 line
1.8.5.2
PATCH 9/9 libata: Add tracepoints
In reply to Hannes ReineckeAdd some tracepoints for ata_qc_issue, ata_qc_complete, and ata_eh_link_autopsy.
--- drivers/ata/Makefile | 3 +- drivers/ata/libata-core.c | 8 +- drivers/ata/libata-eh.c | 4 +- drivers/ata/libata-trace.c | 151 ++++++++++++++++++++ include/trace/events/libata.h | 325 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 488 insertions(+), 3 deletions(-) create mode 100644 drivers/ata/libata-trace.c create mode 100644 include/trace/events/libata.h
drivers/ata/Makefile +2 -1
@@ -111,7 +111,8 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o -libata-y := libata-core.o libata-scsi.o libata-eh.o libata-transport.o +libata-y := libata-core.o libata-scsi.o libata-eh.o \ + libata-transport.o libata-trace.o libata-$(CONFIG_ATA_SFF) += libata-sff.o libata-$(CONFIG_SATA_PMP) += libata-pmp.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o
drivers/ata/libata-core.c +7 -1
@@ -70,6 +70,9 @@#include <linux/pm_runtime.h> #include <linux/platform_device.h> +#define CREATE_TRACE_POINTS +#include <trace/events/libata.h> +#include "libata.h" #include "libata-transport.h"
@@ -4904,6 +4907,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)*/ if (unlikely (ata_tag_internal (qc->tag))) {fill_result_tf (qc); +trace_ata_qc_complete_internal (qc);__ata_qc_complete (qc);return ; }
@@ -4914,6 +4918,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)*/ if (unlikely (qc->flags &ATA_QCFLAG_FAILED )) {fill_result_tf (qc); +trace_ata_qc_complete_failed (qc);ata_qc_schedule_eh (qc);return ; }
@@ -4924,6 +4929,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)if (qc->flags &ATA_QCFLAG_RESULT_TF )fill_result_tf (qc); +trace_ata_qc_complete_done (qc);/* Some commands need post-processing after successful * completion. */
@@ -5071,7 +5077,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc) } ap->ops->qc_prep (qc); - +trace_ata_qc_issue (qc); qc->err_mask |= ap->ops->qc_issue (qc);if (unlikely (qc->err_mask)) goto err;
drivers/ata/libata-eh.c +3 -1
@@ -46,6 +46,7 @@#include <linux/libata.h> +#include <trace/events/libata.h> #include "libata.h" enum {
@@ -2291,6 +2292,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) all_err_mask |= qc->err_mask;if (qc->flags &ATA_QCFLAG_IO ) eflags |=ATA_EFLAG_IS_IO ; +trace_ata_eh_link_autopsy_qc (qc); }/* enforce default EH actions */
@@ -2325,7 +2327,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) eflags |=ATA_EFLAG_DUBIOUS_XFER ; ehc->i.action |=ata_eh_speed_down (dev, eflags, all_err_mask); } - +trace_ata_eh_link_autopsy (dev, ehc->i.action, all_err_mask);DPRINTK ("EXIT\n" ); }
drivers/ata/libata-trace.c new file +151 -0
151 lines not on this page · raw message
include/trace/events/libata.h new file +325 -0
325 lines not on this page · raw message
Signature · 1 line
1.8.5.2
Quoted 9 lines · Hannes Reinecke
Hi all,
with ACS-4 ATA drives inherited the possibility to return SCSI sense codes, allowing for a more precise error handling. Not to mention a nice alignment with the SCSI error handling. This patchset implements both, support for NCQ Autosense and the sense data reporting feature set.
Plus some whitespace and assorted cleanups.
And I've added some tracepoints, too.
Applied 1-9 to libata/for-4.1.
Thanks a lot for the excellent patchset.
Signature · 1 line
tejun