diff options
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 68 |
1 files changed, 58 insertions, 10 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 214b935c2ced..3f0144e7dc80 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -500,10 +500,13 @@ static void ata_eh_dev_disable(struct ata_device *dev) ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET); dev->class++; - /* From now till the next successful probe, ering is used to + /* + * From now till the next successful probe, ering is used to * track probe failures. Clear accumulated device error info. */ ata_ering_clear(&dev->ering); + + ata_dev_free_resources(dev); } static void ata_eh_unload(struct ata_port *ap) @@ -630,6 +633,14 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) { struct ata_queued_cmd *qc; + /* + * If the scmd was added to EH, via ata_qc_schedule_eh() -> + * scsi_timeout() -> scsi_eh_scmd_add(), scsi_timeout() will + * have set DID_TIME_OUT (since libata does not have an abort + * handler). Thus, to clear DID_TIME_OUT, clear the host byte. + */ + set_host_byte(scmd, DID_OK); + ata_qc_for_each_raw(ap, qc, i) { if (qc->flags & ATA_QCFLAG_ACTIVE && qc->scsicmd == scmd) @@ -1402,6 +1413,43 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) } /** + * ata_eh_decide_disposition - Disposition a qc based on sense data + * @qc: qc to examine + * + * For a regular SCSI command, the SCSI completion callback (scsi_done()) + * will call scsi_complete(), which will call scsi_decide_disposition(), + * which will call scsi_check_sense(). scsi_complete() finally calls + * scsi_finish_command(). This is fine for SCSI, since any eventual sense + * data is usually returned in the completion itself (without invoking SCSI + * EH). However, for a QC, we always need to fetch the sense data + * explicitly using SCSI EH. + * + * A command that is completed via SCSI EH will instead be completed using + * scsi_eh_flush_done_q(), which will call scsi_finish_command() directly + * (without ever calling scsi_check_sense()). + * + * For a command that went through SCSI EH, it is the responsibility of the + * SCSI EH strategy handler to call scsi_decide_disposition(), see e.g. how + * scsi_eh_get_sense() calls scsi_decide_disposition() for SCSI LLDDs that + * do not get the sense data as part of the completion. + * + * Thus, for QC commands that went via SCSI EH, we need to call + * scsi_check_sense() ourselves, similar to how scsi_eh_get_sense() calls + * scsi_decide_disposition(), which calls scsi_check_sense(), in order to + * set the correct SCSI ML byte (if any). + * + * LOCKING: + * EH context. + * + * RETURNS: + * SUCCESS or FAILED or NEEDS_RETRY or ADD_TO_MLQUEUE + */ +enum scsi_disposition ata_eh_decide_disposition(struct ata_queued_cmd *qc) +{ + return scsi_check_sense(qc->scsicmd); +} + +/** * ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT * @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to * @@ -1627,7 +1675,8 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc) } if (qc->flags & ATA_QCFLAG_SENSE_VALID) { - enum scsi_disposition ret = scsi_check_sense(qc->scsicmd); + enum scsi_disposition ret = ata_eh_decide_disposition(qc); + /* * SUCCESS here means that the sense code could be * evaluated and should be passed to the upper layers @@ -1924,7 +1973,7 @@ static inline bool ata_eh_quiet(struct ata_queued_cmd *qc) return qc->flags & ATA_QCFLAG_QUIET; } -static int ata_eh_read_sense_success_non_ncq(struct ata_link *link) +static int ata_eh_get_non_ncq_success_sense(struct ata_link *link) { struct ata_port *ap = link->ap; struct ata_queued_cmd *qc; @@ -1942,11 +1991,10 @@ static int ata_eh_read_sense_success_non_ncq(struct ata_link *link) return -EIO; /* - * If we have sense data, call scsi_check_sense() in order to set the - * correct SCSI ML byte (if any). No point in checking the return value, - * since the command has already completed successfully. + * No point in checking the return value, since the command has already + * completed successfully. */ - scsi_check_sense(qc->scsicmd); + ata_eh_decide_disposition(qc); return 0; } @@ -1976,9 +2024,9 @@ static void ata_eh_get_success_sense(struct ata_link *link) * request sense ext command to retrieve the sense data. */ if (link->sactive) - ret = ata_eh_read_sense_success_ncq_log(link); + ret = ata_eh_get_ncq_success_sense(link); else - ret = ata_eh_read_sense_success_non_ncq(link); + ret = ata_eh_get_non_ncq_success_sense(link); if (ret) goto out; @@ -3247,7 +3295,7 @@ static int atapi_eh_clear_ua(struct ata_device *dev) int i; for (i = 0; i < ATA_EH_UA_TRIES; i++) { - u8 *sense_buffer = dev->link->ap->sector_buf; + u8 *sense_buffer = dev->sector_buf; u8 sense_key = 0; unsigned int err_mask; |