* [PATCH libata-dev-2.6 00/05] libata: scsi error handling improvements
@ 2005-03-17 22:20 Brett Russ
2005-03-17 22:20 ` [PATCH libata-dev-2.6 01/05] libata: AHCI tf_read() support Brett Russ
` (4 more replies)
0 siblings, 5 replies; 14+ messages in thread
From: Brett Russ @ 2005-03-17 22:20 UTC (permalink / raw)
To: linux-ide, linux-kernel; +Cc: jgarzik
This patch series attempts to clean up the SCSI error handling a bit.
See comments in below TOC or patch emails. All of the below have been
tested in success and error paths through the VERIFY_10 and ATA_16
commands using the AHCI driver.
IMPORTANT: the patchset below against libata-dev-2.6 relies on the
recent AHCI driver fixes recently patched into libata-2.6. I am
including the two specific patches as 1 and 2 of this series for
completeness, although of course they should be merged from libata-2.6
instead. Therefore, you may ignore these two unless you want to test
this series now on libata-dev.
[ Start of patch descriptions ]
01_libata_garzik-ahci-tf-read.patch
: AHCI tf_read() support
(included in libata-2.6) This is Jeff's tf_read() support
patch for AHCI.
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
02_libata_ahci-err-int.patch
: AHCI error handling fix
(included in libata-2.6) Fixes AHCI bits during handling of
fatal error int.
03_libata_update_desc_code.patch
: update ATA PT sense desc code
Change the ATA pass through sense block descriptor code to
0x09 per SAT
04_libata_control_pg_desc_bit.patch
: support descriptor sense in ctrl page
libata must support the descriptor format sense blocks as they
are required to properly report results of ATA pass through
commands as well as other SCSI commands reporting 48b LBAs.
This patch adjusts the control mode page to properly report
this.
05_libata_split_ata_to_sense_error.patch
: rework how CCs generated
This patch fixes several bugs as well as reorganizes the way
check conditions are generated. Bugs fixed: 1) in
ata_scsi_qc_complete(), ATA_12/16 commands wouldn't call
ata_pass_thru_cc() on error status; 2) ata_pass_thru_cc()
wouldn't put the SK, ASC, and ASCQ from ata_to_sense_error()
in the correct place in the sense block because
ata_to_sense_error() was writing a fixed sense block.
Per the recommendations in the comments, ata_to_sense_error()
is now split into 3 parts. The existing fcn is only used for
outputting a sense key/ASC/ASCQ triplicate. A new function
ata_dump_status() was created to print the error info, similar
to the ide variety. A third function ata_gen_fixed_sense()
was created to generate a fixed length sense block. I added
the use of the info field for 28b LBAs only.
ata_pass_thru_cc() renamed to ata_gen_ata_desc_sense() to
match naming convention, presumably to include another
descriptor format function in the future (see question 2
below).
Questions:
1) I made the ata_gen_..._sense() routines read the status
register themselves rather than use the drv_stat values
that used to be passed in? These values seemed
unreliable/useless since they were often hard coded (see
calls to ata_qc_complete() for origins of most drv_stat
variables). Sound ok?
2) the SAT spec has little about error handling and sense
information, sepcifically what descriptor format is valid
for use by SAT commands. I want to use descriptor type 00
(information) in my next patch until a spec says
differently. Sound ok?
[ End of patch descriptions ]
BR
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH libata-dev-2.6 01/05] libata: AHCI tf_read() support 2005-03-17 22:20 [PATCH libata-dev-2.6 00/05] libata: scsi error handling improvements Brett Russ @ 2005-03-17 22:20 ` Brett Russ 2005-03-17 22:20 ` [PATCH libata-dev-2.6 02/05] libata: AHCI error handling fix Brett Russ ` (3 subsequent siblings) 4 siblings, 0 replies; 14+ messages in thread From: Brett Russ @ 2005-03-17 22:20 UTC (permalink / raw) To: linux-ide, linux-kernel; +Cc: jgarzik 01_libata_garzik-ahci-tf-read.patch (included in libata-2.6) This is Jeff's tf_read() support patch for AHCI. Signed-off-by: Jeff Garzik <jgarzik@pobox.com> ahci.c | 11 +++++++++++ 1 files changed, 11 insertions(+) Index: libata-dev-2.6/drivers/scsi/ahci.c =================================================================== --- libata-dev-2.6.orig/drivers/scsi/ahci.c 2005-03-17 12:36:29.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/ahci.c 2005-03-17 17:16:57.000000000 -0500 @@ -179,6 +179,7 @@ static void ahci_eng_timeout(struct ata_ static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); static void ahci_host_stop(struct ata_host_set *host_set); +static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void ahci_qc_prep(struct ata_queued_cmd *qc); static u8 ahci_check_status(struct ata_port *ap); static u8 ahci_check_err(struct ata_port *ap); @@ -213,6 +214,8 @@ static struct ata_port_operations ahci_o .check_err = ahci_check_err, .dev_select = ata_noop_dev_select, + .tf_read = ahci_tf_read, + .phy_reset = ahci_phy_reset, .qc_prep = ahci_qc_prep, @@ -466,6 +469,14 @@ static u8 ahci_check_err(struct ata_port return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF; } +static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ahci_port_priv *pp = ap->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + + ata_tf_from_fis(d2h_fis, tf); +} + static void ahci_fill_sg(struct ata_queued_cmd *qc) { struct ahci_port_priv *pp = qc->ap->private_data; ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 02/05] libata: AHCI error handling fix 2005-03-17 22:20 [PATCH libata-dev-2.6 00/05] libata: scsi error handling improvements Brett Russ 2005-03-17 22:20 ` [PATCH libata-dev-2.6 01/05] libata: AHCI tf_read() support Brett Russ @ 2005-03-17 22:20 ` Brett Russ 2005-03-17 22:20 ` [PATCH libata-dev-2.6 03/05] libata: update ATA PT sense desc code Brett Russ ` (2 subsequent siblings) 4 siblings, 0 replies; 14+ messages in thread From: Brett Russ @ 2005-03-17 22:20 UTC (permalink / raw) To: linux-ide, linux-kernel; +Cc: jgarzik 02_libata_ahci-err-int.patch (included in libata-2.6) Fixes AHCI bits during handling of fatal error int. Signed-off-by: Brett Russ <russb@emc.com> ahci.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) Index: libata-dev-2.6/drivers/scsi/ahci.c =================================================================== --- libata-dev-2.6.orig/drivers/scsi/ahci.c 2005-03-17 17:16:57.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/ahci.c 2005-03-17 17:16:57.000000000 -0500 @@ -548,7 +548,7 @@ static void ahci_intr_error(struct ata_p /* stop DMA */ tmp = readl(port_mmio + PORT_CMD); - tmp &= PORT_CMD_START | PORT_CMD_FIS_RX; + tmp &= ~PORT_CMD_START; writel(tmp, port_mmio + PORT_CMD); /* wait for engine to stop. TODO: this could be @@ -580,7 +580,7 @@ static void ahci_intr_error(struct ata_p /* re-start DMA */ tmp = readl(port_mmio + PORT_CMD); - tmp |= PORT_CMD_START | PORT_CMD_FIS_RX; + tmp |= PORT_CMD_START; writel(tmp, port_mmio + PORT_CMD); readl(port_mmio + PORT_CMD); /* flush */ ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 03/05] libata: update ATA PT sense desc code 2005-03-17 22:20 [PATCH libata-dev-2.6 00/05] libata: scsi error handling improvements Brett Russ 2005-03-17 22:20 ` [PATCH libata-dev-2.6 01/05] libata: AHCI tf_read() support Brett Russ 2005-03-17 22:20 ` [PATCH libata-dev-2.6 02/05] libata: AHCI error handling fix Brett Russ @ 2005-03-17 22:20 ` Brett Russ 2005-03-23 5:10 ` Jeff Garzik 2005-03-17 22:20 ` [PATCH libata-dev-2.6 04/05] libata: support descriptor sense in ctrl page Brett Russ 2005-03-17 22:20 ` [PATCH libata-dev-2.6 05/05] libata: rework how CCs generated Brett Russ 4 siblings, 1 reply; 14+ messages in thread From: Brett Russ @ 2005-03-17 22:20 UTC (permalink / raw) To: linux-ide, linux-kernel; +Cc: jgarzik 03_libata_update_desc_code.patch Change the ATA pass through sense block descriptor code to 0x09 per SAT Signed-off-by: Brett Russ <russb@emc.com> libata-scsi.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) Index: libata-dev-2.6/drivers/scsi/libata-scsi.c =================================================================== --- libata-dev-2.6.orig/drivers/scsi/libata-scsi.c 2005-03-08 08:47:48.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/libata-scsi.c 2005-03-17 17:16:58.000000000 -0500 @@ -531,7 +531,7 @@ void ata_pass_thru_cc(struct ata_queued_ */ sb[0] = 0x72 ; - desc[0] = 0x8e ; /* TODO: replace with official value. */ + desc[0] = 0x09; /* * Set length of additional sense data. @@ -2059,7 +2059,7 @@ void ata_scsi_simulate(u16 *id, ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); break; - /* mandantory commands we haven't implemented yet */ + /* mandatory commands we haven't implemented yet */ case REQUEST_SENSE: /* all other commands */ ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 03/05] libata: update ATA PT sense desc code 2005-03-17 22:20 ` [PATCH libata-dev-2.6 03/05] libata: update ATA PT sense desc code Brett Russ @ 2005-03-23 5:10 ` Jeff Garzik 0 siblings, 0 replies; 14+ messages in thread From: Jeff Garzik @ 2005-03-23 5:10 UTC (permalink / raw) To: Brett Russ; +Cc: linux-ide, linux-kernel Brett Russ wrote: > 03_libata_update_desc_code.patch > > Change the ATA pass through sense block descriptor code to > 0x09 per SAT > > Signed-off-by: Brett Russ <russb@emc.com> applied ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 04/05] libata: support descriptor sense in ctrl page 2005-03-17 22:20 [PATCH libata-dev-2.6 00/05] libata: scsi error handling improvements Brett Russ ` (2 preceding siblings ...) 2005-03-17 22:20 ` [PATCH libata-dev-2.6 03/05] libata: update ATA PT sense desc code Brett Russ @ 2005-03-17 22:20 ` Brett Russ 2005-03-23 4:24 ` Jeff Garzik 2005-03-17 22:20 ` [PATCH libata-dev-2.6 05/05] libata: rework how CCs generated Brett Russ 4 siblings, 1 reply; 14+ messages in thread From: Brett Russ @ 2005-03-17 22:20 UTC (permalink / raw) To: linux-ide, linux-kernel; +Cc: jgarzik 04_libata_control_pg_desc_bit.patch libata must support the descriptor format sense blocks as they are required to properly report results of ATA pass through commands as well as other SCSI commands reporting 48b LBAs. This patch adjusts the control mode page to properly report this. Signed-off-by: Brett Russ <russb@emc.com> libata-scsi.c | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletion(-) Index: libata-dev-2.6/drivers/scsi/libata-scsi.c =================================================================== --- libata-dev-2.6.orig/drivers/scsi/libata-scsi.c 2005-03-17 17:16:58.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/libata-scsi.c 2005-03-17 17:16:58.000000000 -0500 @@ -1370,7 +1370,12 @@ static unsigned int ata_msense_caching(u static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) { - const u8 page[] = {0xa, 0xa, 2, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30}; + const u8 page[] = {0xa, 0xa, 6, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30}; + + /* byte 2: set the descriptor format sense data bit (bit 2) + * since we need to support returning this format for SAT + * commands and any SCSI commands against a 48b LBA device. + */ ata_msense_push(ptr_io, last, page, sizeof(page)); return sizeof(page); ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 04/05] libata: support descriptor sense in ctrl page 2005-03-17 22:20 ` [PATCH libata-dev-2.6 04/05] libata: support descriptor sense in ctrl page Brett Russ @ 2005-03-23 4:24 ` Jeff Garzik 0 siblings, 0 replies; 14+ messages in thread From: Jeff Garzik @ 2005-03-23 4:24 UTC (permalink / raw) To: Brett Russ; +Cc: linux-ide, linux-kernel Brett Russ wrote: > 04_libata_control_pg_desc_bit.patch > > libata must support the descriptor format sense blocks as they > are required to properly report results of ATA pass through > commands as well as other SCSI commands reporting 48b LBAs. > This patch adjusts the control mode page to properly report > this. > > Signed-off-by: Brett Russ <russb@emc.com> applied ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 05/05] libata: rework how CCs generated 2005-03-17 22:20 [PATCH libata-dev-2.6 00/05] libata: scsi error handling improvements Brett Russ ` (3 preceding siblings ...) 2005-03-17 22:20 ` [PATCH libata-dev-2.6 04/05] libata: support descriptor sense in ctrl page Brett Russ @ 2005-03-17 22:20 ` Brett Russ 2005-03-23 5:12 ` Jeff Garzik 4 siblings, 1 reply; 14+ messages in thread From: Brett Russ @ 2005-03-17 22:20 UTC (permalink / raw) To: linux-ide, linux-kernel; +Cc: jgarzik 05_libata_split_ata_to_sense_error.patch This patch fixes several bugs as well as reorganizes the way check conditions are generated. Bugs fixed: 1) in ata_scsi_qc_complete(), ATA_12/16 commands wouldn't call ata_pass_thru_cc() on error status; 2) ata_pass_thru_cc() wouldn't put the SK, ASC, and ASCQ from ata_to_sense_error() in the correct place in the sense block because ata_to_sense_error() was writing a fixed sense block. Per the recommendations in the comments, ata_to_sense_error() is now split into 3 parts. The existing fcn is only used for outputting a sense key/ASC/ASCQ triplicate. A new function ata_dump_status() was created to print the error info, similar to the ide variety. A third function ata_gen_fixed_sense() was created to generate a fixed length sense block. I added the use of the info field for 28b LBAs only. ata_pass_thru_cc() renamed to ata_gen_ata_desc_sense() to match naming convention, presumably to include another descriptor format function in the future (see question 2 below). Questions: 1) I made the ata_gen_..._sense() routines read the status register themselves rather than use the drv_stat values that used to be passed in? These values seemed unreliable/useless since they were often hard coded (see calls to ata_qc_complete() for origins of most drv_stat variables). Sound ok? 2) the SAT spec has little about error handling and sense information, sepcifically what descriptor format is valid for use by SAT commands. I want to use descriptor type 00 (information) in my next patch until a spec says differently. Sound ok? Signed-off-by: Brett Russ <russb@emc.com> libata-scsi.c | 342 +++++++++++++++++++++++++++++++++------------------------- libata.h | 1 2 files changed, 197 insertions(+), 146 deletions(-) Index: libata-dev-2.6/drivers/scsi/libata-scsi.c =================================================================== --- libata-dev-2.6.orig/drivers/scsi/libata-scsi.c 2005-03-17 17:16:58.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/libata-scsi.c 2005-03-17 17:16:59.000000000 -0500 @@ -331,24 +331,69 @@ struct ata_queued_cmd *ata_scsi_qc_new(s } /** + * ata_dump_status - user friendly display of error info + * @id: id of the port in question + * @tf: ptr to filled out taskfile + * + * Decode and dump the ATA error/status registers for the user so + * that they have some idea what really happened at the non + * make-believe layer. + * + * LOCKING: + * inherited from caller + */ +void ata_dump_status(unsigned id, struct ata_taskfile *tf) +{ + u8 stat = tf->command, err = tf->feature; + + printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat); + 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("Index "); + if (stat & 0x01) 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 "); + else printk("Sector "); + } + if (err & 0x40) printk("UncorrectableError "); + if (err & 0x10) printk("SectorIdNotFound "); + if (err & 0x02) printk("TrackZeroNotFound "); + if (err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + } + } +} + +/** * ata_to_sense_error - convert ATA error to SCSI error - * @qc: Command that we are erroring out * @drv_stat: value contained in ATA status register + * @drv_err: value contained in ATA error register + * @sk: the sense key we'll fill out + * @asc: the additional sense code we'll fill out + * @ascq: the additional sense code qualifier we'll fill out * - * Converts an ATA error into a SCSI error. While we are at it - * we decode and dump the ATA error for the user so that they - * have some idea what really happened at the non make-believe - * layer. + * Converts an ATA error into a SCSI error. Fill out pointers to + * SK, ASC, and ASCQ bytes for later use in fixed or descriptor + * format sense blocks. * * LOCKING: * spin_lock_irqsave(host_set lock) */ - -void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, + u8 *ascq) { - struct scsi_cmnd *cmd = qc->scsicmd; - u8 err = 0; - unsigned char *sb = cmd->sense_buffer; + int i; /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ @@ -389,147 +434,99 @@ void ata_to_sense_error(struct ata_queue {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; - int i = 0; - - cmd->result = SAM_STAT_CHECK_CONDITION; /* * Is this an error we can process/parse */ - - if(drv_stat & ATA_ERR) - /* Read the err bits */ - err = ata_chk_err(qc->ap); - - /* Display the ATA level error info */ - - printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); - if(drv_stat & 0x80) - { - printk("Busy "); - err = 0; /* Data is not valid in this case */ - } - else { - if(drv_stat & 0x40) printk("DriveReady "); - if(drv_stat & 0x20) printk("DeviceFault "); - if(drv_stat & 0x10) printk("SeekComplete "); - if(drv_stat & 0x08) printk("DataRequest "); - if(drv_stat & 0x04) printk("CorrectedError "); - if(drv_stat & 0x02) printk("Index "); - if(drv_stat & 0x01) printk("Error "); - } - printk("}\n"); - - if(err) - { - printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); - if(err & 0x04) printk("DriveStatusError "); - if(err & 0x80) - { - if(err & 0x04) - 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 "); - printk("}\n"); - - /* Should we dump sector info here too ?? */ + if (drv_stat & ATA_BUSY) { + drv_err = 0; /* Ignore the err bits, they're invalid */ } + printk(KERN_ERR "ata%u: translating stat 0x%02x err 0x%02x to sense\n", + id,drv_stat,drv_err); - /* Look for err */ - while(sense_table[i][0] != 0xFF) - { - /* Look for best matches first */ - if((sense_table[i][0] & err) == sense_table[i][0]) - { - sb[0] = 0x70; - sb[2] = sense_table[i][1]; - sb[7] = 0x0a; - sb[12] = sense_table[i][2]; - sb[13] = sense_table[i][3]; - return; + if (drv_err) { + /* Look for drv_err */ + for (i = 0; sense_table[i][0] != 0xFF; i++) { + /* Look for best matches first */ + if ((sense_table[i][0] & drv_err) == sense_table[i][0]) { + *sk = sense_table[i][1]; + *asc = sense_table[i][2]; + *ascq = sense_table[i][3]; + return; + } } - i++; + /* No immediate match */ + printk(KERN_DEBUG "ata%u: no sense translation for " + "error 0x%02x\n", id, drv_err); } - /* No immediate match */ - if(err) - printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); - i = 0; /* Fall back to interpreting status bits */ - while(stat_table[i][0] != 0xFF) - { - if(stat_table[i][0] & drv_stat) - { - sb[0] = 0x70; - sb[2] = stat_table[i][1]; - sb[7] = 0x0a; - sb[12] = stat_table[i][2]; - sb[13] = stat_table[i][3]; + for (i = 0; stat_table[i][0] != 0xFF; i++) { + if (stat_table[i][0] & drv_stat) { + *sk = stat_table[i][1]; + *asc = stat_table[i][2]; + *ascq = stat_table[i][3]; return; } - i++; - } - /* No error ?? */ - printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); - /* additional-sense-code[-qualifier] */ - - sb[0] = 0x70; - sb[2] = MEDIUM_ERROR; - sb[7] = 0x0A; - if (cmd->sc_data_direction == SCSI_DATA_READ) { - sb[12] = 0x11; /* "unrecovered read error" */ - sb[13] = 0x04; - } else { - sb[12] = 0x0C; /* "write error - */ - sb[13] = 0x02; /* auto-reallocation failed" */ } + /* No error? Undecoded? */ + printk(KERN_ERR "ata%u: no sense translation for status: 0x%02x\n", + id, drv_stat); + + /* For our last chance pick, use medium read error because + * it's much more common than an ATA drive telling you a write + * has failed. + */ + *sk = MEDIUM_ERROR; + *asc = 0x11; /* "unrecovered read error" */ + *ascq = 0x04; /* "auto-reallocation failed" */ } /* - * ata_pass_thru_cc - Generate check condition sense block. + * ata_gen_ata_desc_sense - Generate check condition sense block. * @qc: Command that completed. * - * Regardless of whether the command errored or not, return - * a sense block. Copy all controller registers into - * the sense block. Clear sense key, ASC & ASCQ if - * there is no error. + * This function is specific to the ATA descriptor format sense + * block specified for the ATA pass through commands. Regardless + * of whether the command errored or not, return a sense + * block. Copy all controller registers into the sense + * block. Clear sense key, ASC & ASCQ if there is no error. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_pass_thru_cc(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->tf; unsigned char *sb = cmd->sense_buffer; - unsigned char *desc = sb + 8 ; + unsigned char *desc = sb + 8; + + memset(sb, 0, 32); cmd->result = SAM_STAT_CHECK_CONDITION; /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* * Use ata_to_sense_error() to map status register bits - * onto sense key, asc & ascq. We will overwrite some - * (many) of the fields later. - * - * TODO: reorganise better, by splitting ata_to_sense_error() + * onto sense key, asc & ascq. */ - if (unlikely(drv_stat & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { - ata_to_sense_error(qc, drv_stat) ; - } else { - sb[3] = sb[2] = sb[1] = 0x00 ; + if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[1], &sb[2], &sb[3]); + sb[1] &= 0x0f; } /* - * Sense data is current and format is - * descriptor. + * Sense data is current and format is descriptor. */ - sb[0] = 0x72 ; + sb[0] = 0x72; desc[0] = 0x09; @@ -538,35 +535,78 @@ void ata_pass_thru_cc(struct ata_queued_ * Since we only populate descriptor 0, the total * length is the same (fixed) length as descriptor 0. */ - desc[1] = sb[7] = 14 ; - - /* - * Read the controller registers. - */ - qc->ap->ops->tf_read(qc->ap, tf); + desc[1] = sb[7] = 14; /* * Copy registers into sense buffer. */ - desc[2] = 0x00 ; - desc[3] = tf->feature ; /* Note: becomes error register when read. */ - desc[5] = tf->nsect ; - desc[7] = tf->lbal ; - desc[9] = tf->lbam ; - desc[11] = tf->lbah ; - desc[12] = tf->device ; - desc[13] = drv_stat ; + desc[2] = 0x00; + desc[3] = tf->feature; /* == error reg */ + desc[5] = tf->nsect; + desc[7] = tf->lbal; + desc[9] = tf->lbam; + desc[11] = tf->lbah; + desc[12] = tf->device; + desc[13] = tf->command; /* == status reg */ /* * Fill in Extend bit, and the high order bytes * if applicable. */ if (tf->flags & ATA_TFLAG_LBA48) { - desc[2] |= 0x01 ; - desc[4] = tf->hob_nsect ; - desc[6] = tf->hob_lbal ; - desc[8] = tf->hob_lbam ; - desc[10] = tf->hob_lbah ; + desc[2] |= 0x01; + desc[4] = tf->hob_nsect; + desc[6] = tf->hob_lbal; + desc[8] = tf->hob_lbam; + desc[10] = tf->hob_lbah; + } +} + +/** + * ata_gen_fixed_sense - generate a SCSI fixed sense block + * @qc: Command that we are erroring out + * + * Leverage ata_to_sense_error() to give us the codes. Fit our + * LBA in here if there's room. + * + * LOCKING: + * inherited from caller + */ +void ata_gen_fixed_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + + cmd->result = SAM_STAT_CHECK_CONDITION; + + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[2], &sb[12], &sb[13]); + sb[2] &= 0x0f; + } + + sb[0] = 0x70; + sb[7] = 0x0a; + if (tf->flags & ATA_TFLAG_LBA && !(tf->flags & ATA_TFLAG_LBA48)) { + /* A small (28b) LBA will fit in the 32b info field */ + sb[0] |= 0x80; /* set valid bit */ + sb[3] = tf->device & 0x0f; + sb[4] = tf->lbah; + sb[5] = tf->lbam; + sb[6] = tf->lbal; } } @@ -946,23 +986,35 @@ static unsigned int ata_scsi_rw_xlat(str static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + int need_sense = drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ); - /* - * If this was a pass-thru command, and the user requested - * a check condition return including register values. - * Note that check condition is generated, and the ATA - * register values are returned, whether the command completed - * successfully or not. If there was no error, SK, ASC and - * ASCQ will all be zero. + /* For ATA pass thru (SAT) commands, generate a sense block if + * user mandated it or if there's an error. Note that if we + * generate because the user forced us to, a check condition + * is generated and the ATA register values are returned + * whether the command completed successfully or not. If there + * was no error, SK, ASC and ASCQ will all be zero. */ if (((cmd->cmnd[0] == ATA_16) || (cmd->cmnd[0] == ATA_12)) && - (cmd->cmnd[2] & 0x20)) { - ata_pass_thru_cc(qc, drv_stat) ; + ((cmd->cmnd[2] & 0x20) || need_sense)) { + ata_gen_ata_desc_sense(qc); } else { - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) - ata_to_sense_error(qc, drv_stat); - else + if (!need_sense) { cmd->result = SAM_STAT_GOOD; + } else { + /* TODO: decide which descriptor format to use + * for 48b LBA devices and call that here + * instead of the fixed desc, which is only + * good for smaller LBA (and maybe CHS?) + * devices. + */ + ata_gen_fixed_sense(qc); + } + } + + if (need_sense) { + /* The ata_gen_..._sense routines fill in tf */ + ata_dump_status(qc->ap->id, &qc->tf); } qc->scsidone(cmd); Index: libata-dev-2.6/drivers/scsi/libata.h =================================================================== --- libata-dev-2.6.orig/drivers/scsi/libata.h 2005-03-17 01:33:26.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/libata.h 2005-03-17 17:16:59.000000000 -0500 @@ -45,7 +45,6 @@ extern int ata_cmd_ioctl(struct scsi_dev /* libata-scsi.c */ -extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 05/05] libata: rework how CCs generated 2005-03-17 22:20 ` [PATCH libata-dev-2.6 05/05] libata: rework how CCs generated Brett Russ @ 2005-03-23 5:12 ` Jeff Garzik 2005-03-23 20:36 ` [PATCH libata-dev-2.6 00/03] libata: scsi error handling improvements Brett Russ 0 siblings, 1 reply; 14+ messages in thread From: Jeff Garzik @ 2005-03-23 5:12 UTC (permalink / raw) To: Brett Russ; +Cc: linux-ide, linux-kernel Brett Russ wrote: > 05_libata_split_ata_to_sense_error.patch > > This patch fixes several bugs as well as reorganizes the way > check conditions are generated. Bugs fixed: 1) in > ata_scsi_qc_complete(), ATA_12/16 commands wouldn't call > ata_pass_thru_cc() on error status; 2) ata_pass_thru_cc() > wouldn't put the SK, ASC, and ASCQ from ata_to_sense_error() > in the correct place in the sense block because > ata_to_sense_error() was writing a fixed sense block. > > Per the recommendations in the comments, ata_to_sense_error() > is now split into 3 parts. The existing fcn is only used for > outputting a sense key/ASC/ASCQ triplicate. A new function > ata_dump_status() was created to print the error info, similar > to the ide variety. A third function ata_gen_fixed_sense() > was created to generate a fixed length sense block. I added > the use of the info field for 28b LBAs only. > ata_pass_thru_cc() renamed to ata_gen_ata_desc_sense() to > match naming convention, presumably to include another > descriptor format function in the future (see question 2 > below). > > Questions: > > 1) I made the ata_gen_..._sense() routines read the status > register themselves rather than use the drv_stat values > that used to be passed in? These values seemed > unreliable/useless since they were often hard coded (see > calls to ata_qc_complete() for origins of most drv_stat > variables). Sound ok? > > 2) the SAT spec has little about error handling and sense > information, sepcifically what descriptor format is valid > for use by SAT commands. I want to use descriptor type 00 > (information) in my next patch until a spec says > differently. Sound ok? > > Signed-off-by: Brett Russ <russb@emc.com> Patch in general is OK, but I would prefer that it be split up a bit more. Suggested split: * whitespace changes (obscures reviewing the code) * create and use ata_dump_status() * the rest of the changes Regards, Jeff ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH libata-dev-2.6 00/03] libata: scsi error handling improvements 2005-03-23 5:12 ` Jeff Garzik @ 2005-03-23 20:36 ` Brett Russ 2005-03-23 20:39 ` [PATCH libata-dev-2.6 01/03] libata: whitespace updates Brett Russ ` (2 more replies) 0 siblings, 3 replies; 14+ messages in thread From: Brett Russ @ 2005-03-23 20:36 UTC (permalink / raw) To: jgarzik; +Cc: linux-ide, linux-kernel These patches are a resubmit of patch 5/5 of the first series submitted 2005-03-17. Jeff requested that the single patch be split into a suggested 3 smaller patches; the results are below. I also took this opportunity to further clean up the changes. [ Start of patch descriptions ] 01_libata_libata-whitespace.patch : whitespace updates This patch adjusts some whitespace to bring the format of libata-scsi.c to a consistent state. 02_libata_ata_dump_status.patch : create/use ata_dump_status() This patch introduces the ata_dump_status() function, which for now is called from ata_to_sense_error() only. 03_libata_rework-cc-generation.patch : rework check condition handling This patch refactors the check condition creation within libata. Changes include: - ata_to_sense_error() now *only* performs the translation from an ATA status/error register combination to a SCSI SK/ASC/ASCQ combination. Additionally, the translation is logged at level KERNEL_ERR and any untranslatable combos are logged at level KERNEL_WARNING. - ata_dump_status() is modified to take a taskfile struct as argument in preparation for a future patch which will add proper display of the failing location (LBA or CHS) - created ata_gen_fixed_sense() to generate a fixed length CC sense block. - ata_pass_thru_cc() has been renamed to ata_gen_ata_desc_sense() to fit the naming convention mentioned above. Its guts were changed a bit as well. - ata_scsi_qc_complete() has been modified to fix a bug where ATA_12/16 commands would not generate a sense block on error. Other changes made here as well, including the call to ata_dump_status(). [ End of patch descriptions ] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 01/03] libata: whitespace updates 2005-03-23 20:36 ` [PATCH libata-dev-2.6 00/03] libata: scsi error handling improvements Brett Russ @ 2005-03-23 20:39 ` Brett Russ 2005-03-25 4:28 ` Jeff Garzik 2005-03-23 20:42 ` [PATCH libata-dev-2.6 02/03] libata: create/use ata_dump_status() Brett Russ 2005-03-23 20:45 ` [PATCH libata-dev-2.6 03/03] libata: rework check condition handling Brett Russ 2 siblings, 1 reply; 14+ messages in thread From: Brett Russ @ 2005-03-23 20:39 UTC (permalink / raw) To: jgarzik; +Cc: linux-ide, linux-kernel 01_libata_libata-whitespace.patch This patch adjusts some whitespace to bring the format of libata-scsi.c to a consistent state. Signed-off-by: Brett Russ <russb@emc.com> libata-scsi.c | 112 +++++++++++++++++++++++++--------------------------------- 1 files changed, 50 insertions(+), 62 deletions(-) Index: libata-dev-2.6/drivers/scsi/libata-scsi.c =================================================================== --- libata-dev-2.6.orig/drivers/scsi/libata-scsi.c 2005-03-23 15:35:08.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/libata-scsi.c 2005-03-23 15:35:09.000000000 -0500 @@ -397,56 +397,46 @@ void ata_to_sense_error(struct ata_queue * Is this an error we can process/parse */ - if(drv_stat & ATA_ERR) - /* Read the err bits */ - err = ata_chk_err(qc->ap); + if (drv_stat & ATA_ERR) + err = ata_chk_err(qc->ap); /* Read the err bits */ /* Display the ATA level error info */ printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); - if(drv_stat & 0x80) - { + if (drv_stat & 0x80) { printk("Busy "); err = 0; /* Data is not valid in this case */ - } - else { - if(drv_stat & 0x40) printk("DriveReady "); - if(drv_stat & 0x20) printk("DeviceFault "); - if(drv_stat & 0x10) printk("SeekComplete "); - if(drv_stat & 0x08) printk("DataRequest "); - if(drv_stat & 0x04) printk("CorrectedError "); - if(drv_stat & 0x02) printk("Index "); - if(drv_stat & 0x01) printk("Error "); + } else { + if (drv_stat & 0x40) printk("DriveReady "); + if (drv_stat & 0x20) printk("DeviceFault "); + if (drv_stat & 0x10) printk("SeekComplete "); + if (drv_stat & 0x08) printk("DataRequest "); + if (drv_stat & 0x04) printk("CorrectedError "); + if (drv_stat & 0x02) printk("Index "); + if (drv_stat & 0x01) printk("Error "); } printk("}\n"); - if(err) - { + if (err) { printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); - if(err & 0x04) printk("DriveStatusError "); - if(err & 0x80) - { - if(err & 0x04) - printk("BadCRC "); - else - printk("Sector "); + if (err & 0x04) printk("DriveStatusError "); + if (err & 0x80) { + if (err & 0x04) 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 & 0x40) printk("UncorrectableError "); + if (err & 0x10) printk("SectorIdNotFound "); + if (err & 0x02) printk("TrackZeroNotFound "); + if (err & 0x01) printk("AddrMarkNotFound "); printk("}\n"); /* Should we dump sector info here too ?? */ } - /* Look for err */ - while(sense_table[i][0] != 0xFF) - { + while (sense_table[i][0] != 0xFF) { /* Look for best matches first */ - if((sense_table[i][0] & err) == sense_table[i][0]) - { + if ((sense_table[i][0] & err) == sense_table[i][0]) { sb[0] = 0x70; sb[2] = sense_table[i][1]; sb[7] = 0x0a; @@ -457,15 +447,13 @@ void ata_to_sense_error(struct ata_queue i++; } /* No immediate match */ - if(err) + if (err) printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); i = 0; /* Fall back to interpreting status bits */ - while(stat_table[i][0] != 0xFF) - { - if(stat_table[i][0] & drv_stat) - { + while (stat_table[i][0] != 0xFF) { + if (stat_table[i][0] & drv_stat) { sb[0] = 0x70; sb[2] = stat_table[i][1]; sb[7] = 0x0a; @@ -508,7 +496,7 @@ void ata_pass_thru_cc(struct ata_queued_ struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->tf; unsigned char *sb = cmd->sense_buffer; - unsigned char *desc = sb + 8 ; + unsigned char *desc = sb + 8; cmd->result = SAM_STAT_CHECK_CONDITION; @@ -520,16 +508,16 @@ void ata_pass_thru_cc(struct ata_queued_ * TODO: reorganise better, by splitting ata_to_sense_error() */ if (unlikely(drv_stat & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { - ata_to_sense_error(qc, drv_stat) ; + ata_to_sense_error(qc, drv_stat); } else { - sb[3] = sb[2] = sb[1] = 0x00 ; + sb[3] = sb[2] = sb[1] = 0x00; } /* * Sense data is current and format is * descriptor. */ - sb[0] = 0x72 ; + sb[0] = 0x72; desc[0] = 0x09; @@ -538,7 +526,7 @@ void ata_pass_thru_cc(struct ata_queued_ * Since we only populate descriptor 0, the total * length is the same (fixed) length as descriptor 0. */ - desc[1] = sb[7] = 14 ; + desc[1] = sb[7] = 14; /* * Read the controller registers. @@ -548,25 +536,25 @@ void ata_pass_thru_cc(struct ata_queued_ /* * Copy registers into sense buffer. */ - desc[2] = 0x00 ; - desc[3] = tf->feature ; /* Note: becomes error register when read. */ - desc[5] = tf->nsect ; - desc[7] = tf->lbal ; - desc[9] = tf->lbam ; - desc[11] = tf->lbah ; - desc[12] = tf->device ; - desc[13] = drv_stat ; + desc[2] = 0x00; + desc[3] = tf->feature; /* Note: becomes error register when read. */ + desc[5] = tf->nsect; + desc[7] = tf->lbal; + desc[9] = tf->lbam; + desc[11] = tf->lbah; + desc[12] = tf->device; + desc[13] = drv_stat; /* * Fill in Extend bit, and the high order bytes * if applicable. */ if (tf->flags & ATA_TFLAG_LBA48) { - desc[2] |= 0x01 ; - desc[4] = tf->hob_nsect ; - desc[6] = tf->hob_lbal ; - desc[8] = tf->hob_lbam ; - desc[10] = tf->hob_lbah ; + desc[2] |= 0x01; + desc[4] = tf->hob_nsect; + desc[6] = tf->hob_lbal; + desc[8] = tf->hob_lbam; + desc[10] = tf->hob_lbah; } } @@ -957,7 +945,7 @@ static int ata_scsi_qc_complete(struct a */ if (((cmd->cmnd[0] == ATA_16) || (cmd->cmnd[0] == ATA_12)) && (cmd->cmnd[2] & 0x20)) { - ata_pass_thru_cc(qc, drv_stat) ; + ata_pass_thru_cc(qc, drv_stat); } else { if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) ata_to_sense_error(qc, drv_stat); @@ -1811,9 +1799,9 @@ ata_scsi_pass_thru(struct ata_queued_cmd tf->hob_lbal = scsicmd[7]; tf->hob_lbam = scsicmd[9]; tf->hob_lbah = scsicmd[11]; - tf->flags |= ATA_TFLAG_LBA48 ; + tf->flags |= ATA_TFLAG_LBA48; } else - tf->flags &= ~ATA_TFLAG_LBA48 ; + tf->flags &= ~ATA_TFLAG_LBA48; /* * Always copy low byte, device and command registers. @@ -1829,7 +1817,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd /* * 12-byte CDB - incapable of extended commands. */ - tf->flags &= ~ATA_TFLAG_LBA48 ; + tf->flags &= ~ATA_TFLAG_LBA48; tf->feature = scsicmd[3]; tf->nsect = scsicmd[4]; @@ -1856,7 +1844,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd * and pass on write indication (used for PIO/DMA * setup.) */ - tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE) ; + tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE); if (cmd->sc_data_direction == SCSI_DATA_WRITE) tf->flags |= ATA_TFLAG_WRITE; @@ -1867,7 +1855,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd * TODO: find out if we need to do more here to * cover scatter/gather case. */ - qc->nsect = cmd->bufflen / ATA_SECT_SIZE ; + qc->nsect = cmd->bufflen / ATA_SECT_SIZE; return 0; } @@ -1907,7 +1895,7 @@ static inline ata_xlat_func_t ata_get_xl case ATA_12: case ATA_16: - return ata_scsi_pass_thru ; + return ata_scsi_pass_thru; } return NULL; ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 01/03] libata: whitespace updates 2005-03-23 20:39 ` [PATCH libata-dev-2.6 01/03] libata: whitespace updates Brett Russ @ 2005-03-25 4:28 ` Jeff Garzik 0 siblings, 0 replies; 14+ messages in thread From: Jeff Garzik @ 2005-03-25 4:28 UTC (permalink / raw) To: Brett Russ; +Cc: linux-ide, linux-kernel applied patches 1-3, thanks much. Small administrivia request, though: after using my patch merging script to merge your patches, I have to do the following things manually: * delete diffstat output * delete patch filename * un-indent patch description text It would be great if I didn't have to do those manual steps :) On the other hand, I really like your "patch 0/N" email with a description of the entire patchset. Keep sending those, thanks. Everything else looks great. Jeff ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 02/03] libata: create/use ata_dump_status() 2005-03-23 20:36 ` [PATCH libata-dev-2.6 00/03] libata: scsi error handling improvements Brett Russ 2005-03-23 20:39 ` [PATCH libata-dev-2.6 01/03] libata: whitespace updates Brett Russ @ 2005-03-23 20:42 ` Brett Russ 2005-03-23 20:45 ` [PATCH libata-dev-2.6 03/03] libata: rework check condition handling Brett Russ 2 siblings, 0 replies; 14+ messages in thread From: Brett Russ @ 2005-03-23 20:42 UTC (permalink / raw) To: jgarzik; +Cc: linux-ide, linux-kernel 02_libata_ata_dump_status.patch This patch introduces the ata_dump_status() function, which for now is called from ata_to_sense_error() only. Signed-off-by: Brett Russ <russb@emc.com> libata-scsi.c | 76 +++++++++++++++++++++++++++++++++------------------------- 1 files changed, 44 insertions(+), 32 deletions(-) Index: libata-dev-2.6/drivers/scsi/libata-scsi.c =================================================================== --- libata-dev-2.6.orig/drivers/scsi/libata-scsi.c 2005-03-23 15:35:09.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/libata-scsi.c 2005-03-23 15:35:09.000000000 -0500 @@ -331,6 +331,49 @@ struct ata_queued_cmd *ata_scsi_qc_new(s } /** + * ata_dump_status - user friendly display of error info + * @id: id of the port in question + * @tf: ptr to filled out taskfile + * + * Decode and dump the ATA error/status registers for the user so + * that they have some idea what really happened at the non + * make-believe layer. + * + * LOCKING: + * inherited from caller + */ +void ata_dump_status(unsigned id, u8 stat, u8 err) +{ + printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat); + 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("Index "); + if (stat & 0x01) 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 "); + else printk("Sector "); + } + if (err & 0x40) printk("UncorrectableError "); + if (err & 0x10) printk("SectorIdNotFound "); + if (err & 0x02) printk("TrackZeroNotFound "); + if (err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + } + } +} + +/** * ata_to_sense_error - convert ATA error to SCSI error * @qc: Command that we are erroring out * @drv_stat: value contained in ATA status register @@ -400,38 +443,7 @@ void ata_to_sense_error(struct ata_queue if (drv_stat & ATA_ERR) err = ata_chk_err(qc->ap); /* Read the err bits */ - /* Display the ATA level error info */ - - printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); - if (drv_stat & 0x80) { - printk("Busy "); - err = 0; /* Data is not valid in this case */ - } else { - if (drv_stat & 0x40) printk("DriveReady "); - if (drv_stat & 0x20) printk("DeviceFault "); - if (drv_stat & 0x10) printk("SeekComplete "); - if (drv_stat & 0x08) printk("DataRequest "); - if (drv_stat & 0x04) printk("CorrectedError "); - if (drv_stat & 0x02) printk("Index "); - if (drv_stat & 0x01) printk("Error "); - } - printk("}\n"); - - if (err) { - printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); - if (err & 0x04) printk("DriveStatusError "); - if (err & 0x80) { - if (err & 0x04) 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 "); - printk("}\n"); - - /* Should we dump sector info here too ?? */ - } + ata_dump_status(qc->ap->id, drv_stat, err); /* Look for err */ while (sense_table[i][0] != 0xFF) { ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH libata-dev-2.6 03/03] libata: rework check condition handling 2005-03-23 20:36 ` [PATCH libata-dev-2.6 00/03] libata: scsi error handling improvements Brett Russ 2005-03-23 20:39 ` [PATCH libata-dev-2.6 01/03] libata: whitespace updates Brett Russ 2005-03-23 20:42 ` [PATCH libata-dev-2.6 02/03] libata: create/use ata_dump_status() Brett Russ @ 2005-03-23 20:45 ` Brett Russ 2 siblings, 0 replies; 14+ messages in thread From: Brett Russ @ 2005-03-23 20:45 UTC (permalink / raw) To: jgarzik; +Cc: linux-ide, linux-kernel 03_libata_rework-cc-generation.patch This patch refactors the check condition creation within libata. Changes include: - ata_to_sense_error() now *only* performs the translation from an ATA status/error register combination to a SCSI SK/ASC/ASCQ combination. Additionally, the translation is logged at level KERNEL_ERR and any untranslatable combos are logged at level KERNEL_WARNING. - ata_dump_status() is modified to take a taskfile struct as argument in preparation for a future patch which will add proper display of the failing location (LBA or CHS) - created ata_gen_fixed_sense() to generate a fixed length CC sense block. - ata_pass_thru_cc() has been renamed to ata_gen_ata_desc_sense() to fit the naming convention mentioned above. Its guts were changed a bit as well. - ata_scsi_qc_complete() has been modified to fix a bug where ATA_12/16 commands would not generate a sense block on error. Other changes made here as well, including the call to ata_dump_status(). Signed-off-by: Brett Russ <russb@emc.com> libata-scsi.c | 238 +++++++++++++++++++++++++++++++++++----------------------- libata.h | 1 2 files changed, 147 insertions(+), 92 deletions(-) Index: libata-dev-2.6/drivers/scsi/libata-scsi.c =================================================================== --- libata-dev-2.6.orig/drivers/scsi/libata-scsi.c 2005-03-23 15:35:09.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/libata-scsi.c 2005-03-23 15:35:10.000000000 -0500 @@ -342,8 +342,10 @@ struct ata_queued_cmd *ata_scsi_qc_new(s * LOCKING: * inherited from caller */ -void ata_dump_status(unsigned id, u8 stat, u8 err) +void ata_dump_status(unsigned id, struct ata_taskfile *tf) { + u8 stat = tf->command, err = tf->feature; + printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat); if (stat & ATA_BUSY) { printk("Busy }\n"); /* Data is not valid in this case */ @@ -375,23 +377,23 @@ void ata_dump_status(unsigned id, u8 sta /** * ata_to_sense_error - convert ATA error to SCSI error - * @qc: Command that we are erroring out * @drv_stat: value contained in ATA status register + * @drv_err: value contained in ATA error register + * @sk: the sense key we'll fill out + * @asc: the additional sense code we'll fill out + * @ascq: the additional sense code qualifier we'll fill out * - * Converts an ATA error into a SCSI error. While we are at it - * we decode and dump the ATA error for the user so that they - * have some idea what really happened at the non make-believe - * layer. + * Converts an ATA error into a SCSI error. Fill out pointers to + * SK, ASC, and ASCQ bytes for later use in fixed or descriptor + * format sense blocks. * * LOCKING: * spin_lock_irqsave(host_set lock) */ - -void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, + u8 *ascq) { - struct scsi_cmnd *cmd = qc->scsicmd; - u8 err = 0; - unsigned char *sb = cmd->sense_buffer; + int i; /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ @@ -432,102 +434,101 @@ void ata_to_sense_error(struct ata_queue {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; - int i = 0; - - cmd->result = SAM_STAT_CHECK_CONDITION; /* * Is this an error we can process/parse */ + if (drv_stat & ATA_BUSY) { + drv_err = 0; /* Ignore the err bits, they're invalid */ + } - if (drv_stat & ATA_ERR) - err = ata_chk_err(qc->ap); /* Read the err bits */ - - ata_dump_status(qc->ap->id, drv_stat, err); - - /* Look for err */ - while (sense_table[i][0] != 0xFF) { - /* Look for best matches first */ - if ((sense_table[i][0] & err) == sense_table[i][0]) { - sb[0] = 0x70; - sb[2] = sense_table[i][1]; - sb[7] = 0x0a; - sb[12] = sense_table[i][2]; - sb[13] = sense_table[i][3]; - return; + if (drv_err) { + /* Look for drv_err */ + for (i = 0; sense_table[i][0] != 0xFF; i++) { + /* Look for best matches first */ + if ((sense_table[i][0] & drv_err) == + sense_table[i][0]) { + *sk = sense_table[i][1]; + *asc = sense_table[i][2]; + *ascq = sense_table[i][3]; + goto translate_done; + } } - i++; + /* No immediate match */ + printk(KERN_WARNING "ata%u: no sense translation for " + "error 0x%02x\n", id, drv_err); } - /* No immediate match */ - if (err) - printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); - i = 0; /* Fall back to interpreting status bits */ - while (stat_table[i][0] != 0xFF) { + for (i = 0; stat_table[i][0] != 0xFF; i++) { if (stat_table[i][0] & drv_stat) { - sb[0] = 0x70; - sb[2] = stat_table[i][1]; - sb[7] = 0x0a; - sb[12] = stat_table[i][2]; - sb[13] = stat_table[i][3]; - return; + *sk = stat_table[i][1]; + *asc = stat_table[i][2]; + *ascq = stat_table[i][3]; + goto translate_done; } - i++; - } - /* No error ?? */ - printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); - /* additional-sense-code[-qualifier] */ - - sb[0] = 0x70; - sb[2] = MEDIUM_ERROR; - sb[7] = 0x0A; - if (cmd->sc_data_direction == SCSI_DATA_READ) { - sb[12] = 0x11; /* "unrecovered read error" */ - sb[13] = 0x04; - } else { - sb[12] = 0x0C; /* "write error - */ - sb[13] = 0x02; /* auto-reallocation failed" */ } + /* No error? Undecoded? */ + printk(KERN_WARNING "ata%u: no sense translation for status: 0x%02x\n", + id, drv_stat); + + /* For our last chance pick, use medium read error because + * it's much more common than an ATA drive telling you a write + * has failed. + */ + *sk = MEDIUM_ERROR; + *asc = 0x11; /* "unrecovered read error" */ + *ascq = 0x04; /* "auto-reallocation failed" */ + + translate_done: + printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x to " + "SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", id, drv_stat, drv_err, + *sk, *asc, *ascq); + return; } /* - * ata_pass_thru_cc - Generate check condition sense block. + * ata_gen_ata_desc_sense - Generate check condition sense block. * @qc: Command that completed. * - * Regardless of whether the command errored or not, return - * a sense block. Copy all controller registers into - * the sense block. Clear sense key, ASC & ASCQ if - * there is no error. + * This function is specific to the ATA descriptor format sense + * block specified for the ATA pass through commands. Regardless + * of whether the command errored or not, return a sense + * block. Copy all controller registers into the sense + * block. Clear sense key, ASC & ASCQ if there is no error. * * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_pass_thru_cc(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->tf; unsigned char *sb = cmd->sense_buffer; unsigned char *desc = sb + 8; + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + cmd->result = SAM_STAT_CHECK_CONDITION; /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* * Use ata_to_sense_error() to map status register bits - * onto sense key, asc & ascq. We will overwrite some - * (many) of the fields later. - * - * TODO: reorganise better, by splitting ata_to_sense_error() + * onto sense key, asc & ascq. */ - if (unlikely(drv_stat & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { - ata_to_sense_error(qc, drv_stat); - } else { - sb[3] = sb[2] = sb[1] = 0x00; + if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[1], &sb[2], &sb[3]); + sb[1] &= 0x0f; } /* - * Sense data is current and format is - * descriptor. + * Sense data is current and format is descriptor. */ sb[0] = 0x72; @@ -541,21 +542,16 @@ void ata_pass_thru_cc(struct ata_queued_ desc[1] = sb[7] = 14; /* - * Read the controller registers. - */ - qc->ap->ops->tf_read(qc->ap, tf); - - /* * Copy registers into sense buffer. */ desc[2] = 0x00; - desc[3] = tf->feature; /* Note: becomes error register when read. */ + desc[3] = tf->feature; /* == error reg */ desc[5] = tf->nsect; desc[7] = tf->lbal; desc[9] = tf->lbam; desc[11] = tf->lbah; desc[12] = tf->device; - desc[13] = drv_stat; + desc[13] = tf->command; /* == status reg */ /* * Fill in Extend bit, and the high order bytes @@ -571,6 +567,54 @@ void ata_pass_thru_cc(struct ata_queued_ } /** + * ata_gen_fixed_sense - generate a SCSI fixed sense block + * @qc: Command that we are erroring out + * + * Leverage ata_to_sense_error() to give us the codes. Fit our + * LBA in here if there's room. + * + * LOCKING: + * inherited from caller + */ +void ata_gen_fixed_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + + cmd->result = SAM_STAT_CHECK_CONDITION; + + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[2], &sb[12], &sb[13]); + sb[2] &= 0x0f; + } + + sb[0] = 0x70; + sb[7] = 0x0a; + if (tf->flags & ATA_TFLAG_LBA && !(tf->flags & ATA_TFLAG_LBA48)) { + /* A small (28b) LBA will fit in the 32b info field */ + sb[0] |= 0x80; /* set valid bit */ + sb[3] = tf->device & 0x0f; + sb[4] = tf->lbah; + sb[5] = tf->lbam; + sb[6] = tf->lbal; + } +} + +/** * ata_scsi_slave_config - Set SCSI device attributes * @sdev: SCSI device to examine * @@ -946,23 +990,35 @@ static unsigned int ata_scsi_rw_xlat(str static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + int need_sense = drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ); - /* - * If this was a pass-thru command, and the user requested - * a check condition return including register values. - * Note that check condition is generated, and the ATA - * register values are returned, whether the command completed - * successfully or not. If there was no error, SK, ASC and - * ASCQ will all be zero. + /* For ATA pass thru (SAT) commands, generate a sense block if + * user mandated it or if there's an error. Note that if we + * generate because the user forced us to, a check condition + * is generated and the ATA register values are returned + * whether the command completed successfully or not. If there + * was no error, SK, ASC and ASCQ will all be zero. */ if (((cmd->cmnd[0] == ATA_16) || (cmd->cmnd[0] == ATA_12)) && - (cmd->cmnd[2] & 0x20)) { - ata_pass_thru_cc(qc, drv_stat); + ((cmd->cmnd[2] & 0x20) || need_sense)) { + ata_gen_ata_desc_sense(qc); } else { - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) - ata_to_sense_error(qc, drv_stat); - else + if (!need_sense) { cmd->result = SAM_STAT_GOOD; + } else { + /* TODO: decide which descriptor format to use + * for 48b LBA devices and call that here + * instead of the fixed desc, which is only + * good for smaller LBA (and maybe CHS?) + * devices. + */ + ata_gen_fixed_sense(qc); + } + } + + if (need_sense) { + /* The ata_gen_..._sense routines fill in tf */ + ata_dump_status(qc->ap->id, &qc->tf); } qc->scsidone(cmd); Index: libata-dev-2.6/drivers/scsi/libata.h =================================================================== --- libata-dev-2.6.orig/drivers/scsi/libata.h 2005-03-17 01:33:26.000000000 -0500 +++ libata-dev-2.6/drivers/scsi/libata.h 2005-03-23 15:35:10.000000000 -0500 @@ -45,7 +45,6 @@ extern int ata_cmd_ioctl(struct scsi_dev /* libata-scsi.c */ -extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2005-03-25 4:28 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-03-17 22:20 [PATCH libata-dev-2.6 00/05] libata: scsi error handling improvements Brett Russ 2005-03-17 22:20 ` [PATCH libata-dev-2.6 01/05] libata: AHCI tf_read() support Brett Russ 2005-03-17 22:20 ` [PATCH libata-dev-2.6 02/05] libata: AHCI error handling fix Brett Russ 2005-03-17 22:20 ` [PATCH libata-dev-2.6 03/05] libata: update ATA PT sense desc code Brett Russ 2005-03-23 5:10 ` Jeff Garzik 2005-03-17 22:20 ` [PATCH libata-dev-2.6 04/05] libata: support descriptor sense in ctrl page Brett Russ 2005-03-23 4:24 ` Jeff Garzik 2005-03-17 22:20 ` [PATCH libata-dev-2.6 05/05] libata: rework how CCs generated Brett Russ 2005-03-23 5:12 ` Jeff Garzik 2005-03-23 20:36 ` [PATCH libata-dev-2.6 00/03] libata: scsi error handling improvements Brett Russ 2005-03-23 20:39 ` [PATCH libata-dev-2.6 01/03] libata: whitespace updates Brett Russ 2005-03-25 4:28 ` Jeff Garzik 2005-03-23 20:42 ` [PATCH libata-dev-2.6 02/03] libata: create/use ata_dump_status() Brett Russ 2005-03-23 20:45 ` [PATCH libata-dev-2.6 03/03] libata: rework check condition handling Brett Russ
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).