Loading src/drivers/ata/libata-eh.c +177 −107 Original line number Original line Diff line number Diff line Loading @@ -25,7 +25,7 @@ * * * * * libata documentation is available via 'make {ps|pdf}docs', * libata documentation is available via 'make {ps|pdf}docs', * as Documentation/DocBook/libata.* * as Documentation/driver-api/libata.rst * * * Hardware documentation available from http://www.t13.org/ and * Hardware documentation available from http://www.t13.org/ and * http://www.sata-io.org/ * http://www.sata-io.org/ Loading @@ -46,6 +46,7 @@ #include <linux/libata.h> #include <linux/libata.h> #include <trace/events/libata.h> #include "libata.h" #include "libata.h" enum { enum { Loading Loading @@ -548,6 +549,7 @@ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) DPRINTK("EXIT, ret=%d\n", ret); DPRINTK("EXIT, ret=%d\n", ret); return ret; return ret; } } EXPORT_SYMBOL(ata_scsi_timed_out); static void ata_eh_unload(struct ata_port *ap) static void ata_eh_unload(struct ata_port *ap) { { Loading Loading @@ -605,7 +607,7 @@ void ata_scsi_error(struct Scsi_Host *host) ata_scsi_port_error_handler(host, ap); ata_scsi_port_error_handler(host, ap); /* finish or retry handled scmd's and clean up */ /* finish or retry handled scmd's and clean up */ WARN_ON(host->host_failed || !list_empty(&eh_work_q)); WARN_ON(!list_empty(&eh_work_q)); DPRINTK("EXIT\n"); DPRINTK("EXIT\n"); } } Loading Loading @@ -643,12 +645,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, * completions are honored. A scmd is determined to have * completions are honored. A scmd is determined to have * timed out iff its associated qc is active and not failed. * timed out iff its associated qc is active and not failed. */ */ spin_lock_irqsave(ap->lock, flags); if (ap->ops->error_handler) { if (ap->ops->error_handler) { struct scsi_cmnd *scmd, *tmp; struct scsi_cmnd *scmd, *tmp; int nr_timedout = 0; int nr_timedout = 0; spin_lock_irqsave(ap->lock, flags); /* This must occur under the ap->lock as we don't want /* This must occur under the ap->lock as we don't want a polled recovery to race the real interrupt handler a polled recovery to race the real interrupt handler Loading Loading @@ -698,12 +699,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, if (nr_timedout) if (nr_timedout) __ata_port_freeze(ap); __ata_port_freeze(ap); spin_unlock_irqrestore(ap->lock, flags); /* initialize eh_tries */ /* initialize eh_tries */ ap->eh_tries = ATA_EH_MAX_TRIES; ap->eh_tries = ATA_EH_MAX_TRIES; } else } spin_unlock_wait(ap->lock); spin_unlock_irqrestore(ap->lock, flags); } } EXPORT_SYMBOL(ata_scsi_cmd_error_handler); EXPORT_SYMBOL(ata_scsi_cmd_error_handler); Loading Loading @@ -968,7 +968,7 @@ static void ata_eh_set_pending(struct ata_port *ap, int fastdrain) void ata_qc_schedule_eh(struct ata_queued_cmd *qc) void ata_qc_schedule_eh(struct ata_queued_cmd *qc) { { struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap; struct request_queue *q; struct request_queue *q = qc->scsicmd->device->request_queue; unsigned long flags; unsigned long flags; WARN_ON(!ap->ops->error_handler); WARN_ON(!ap->ops->error_handler); Loading @@ -981,13 +981,10 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) * Note that ATA_QCFLAG_FAILED is unconditionally set after * Note that ATA_QCFLAG_FAILED is unconditionally set after * this function completes. * this function completes. */ */ if (qc->scsicmd != NULL) { q = qc->scsicmd->device->request_queue; spin_lock_irqsave(q->queue_lock, flags); spin_lock_irqsave(q->queue_lock, flags); blk_abort_request(qc->scsicmd->request); blk_abort_request(qc->scsicmd->request); spin_unlock_irqrestore(q->queue_lock, flags); spin_unlock_irqrestore(q->queue_lock, flags); } } } /** /** * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine Loading Loading @@ -1435,7 +1432,7 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, /** /** * ata_eh_done - EH action complete * ata_eh_done - EH action complete * @ap: target ATA port * @link: ATA link for which EH actions are complete * @dev: target ATA dev for per-dev action (can be NULL) * @dev: target ATA dev for per-dev action (can be NULL) * @action: action just completed * @action: action just completed * * Loading Loading @@ -1488,46 +1485,6 @@ static const char *ata_err_string(unsigned int err_mask) return "unknown error"; return "unknown error"; } } /** * ata_read_log_page - read a specific log page * @dev: target device * @log: log to read * @page: page to read * @buf: buffer to store read page * @sectors: number of sectors to read * * Read log page using READ_LOG_EXT command. * * LOCKING: * Kernel thread context (may sleep). * * RETURNS: * 0 on success, AC_ERR_* mask otherwise. */ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, u8 page, void *buf, unsigned int sectors) { struct ata_taskfile tf; unsigned int err_mask; 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; 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); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; } /** /** * ata_eh_read_log_10h - Read log page 10h for NCQ error details * ata_eh_read_log_10h - Read log page 10h for NCQ error details * @dev: Device to read log page 10h from * @dev: Device to read log page 10h from Loading Loading @@ -1578,6 +1535,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev, tf->hob_lbah = buf[10]; tf->hob_lbah = buf[10]; tf->nsect = buf[12]; tf->nsect = buf[12]; tf->hob_nsect = buf[13]; 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; return 0; } } Loading Loading @@ -1613,6 +1572,56 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) return err_mask; return err_mask; } } /** * ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT * @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to * @cmd: scsi command for which the sense code should be set * * Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK * SENSE. This function is an EH helper. * * LOCKING: * Kernel thread context (may sleep). */ static void ata_eh_request_sense(struct ata_queued_cmd *qc, struct scsi_cmnd *cmd) { struct ata_device *dev = qc->dev; struct ata_taskfile tf; unsigned int err_mask; if (qc->ap->pflags & ATA_PFLAG_FROZEN) { ata_dev_warn(dev, "sense data available but port frozen\n"); return; } if (!cmd || qc->flags & ATA_QCFLAG_SENSE_VALID) return; if (!ata_id_sense_reporting_enabled(dev->id)) { ata_dev_warn(qc->dev, "sense data reporting disabled\n"); return; } DPRINTK("ATA request sense\n"); ata_tf_init(dev, &tf); tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; tf.command = ATA_CMD_REQ_SENSE_DATA; tf.protocol = ATA_PROT_NODATA; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); /* Ignore err_mask; ATA_ERR might be set */ if (tf.command & ATA_SENSE) { ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal); qc->flags |= ATA_QCFLAG_SENSE_VALID; } else { ata_dev_warn(dev, "request sense failed stat %02x emask %x\n", tf.command, err_mask); } } /** /** * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE * @dev: device to perform REQUEST_SENSE to * @dev: device to perform REQUEST_SENSE to Loading Loading @@ -1775,6 +1784,18 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) memcpy(&qc->result_tf, &tf, sizeof(tf)); memcpy(&qc->result_tf, &tf, sizeof(tf)); qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; if ((qc->result_tf.command & ATA_SENSE) || 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_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, ascq); ata_scsi_set_sense_information(dev, qc->scsicmd, &qc->result_tf); qc->flags |= ATA_QCFLAG_SENSE_VALID; } ehc->i.err_mask &= ~AC_ERR_DEV; ehc->i.err_mask &= ~AC_ERR_DEV; } } Loading Loading @@ -1804,14 +1825,23 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, return ATA_EH_RESET; return ATA_EH_RESET; } } if (stat & (ATA_ERR | ATA_DF)) if (stat & (ATA_ERR | ATA_DF)) { qc->err_mask |= AC_ERR_DEV; qc->err_mask |= AC_ERR_DEV; else /* * Sense data reporting does not work if the * device fault bit is set. */ if (stat & ATA_DF) stat &= ~ATA_SENSE; } else { return 0; return 0; } switch (qc->dev->class) { switch (qc->dev->class) { case ATA_DEV_ATA: case ATA_DEV_ATA: case ATA_DEV_ZAC: case ATA_DEV_ZAC: if (stat & ATA_SENSE) ata_eh_request_sense(qc, qc->scsicmd); if (err & ATA_ICRC) if (err & ATA_ICRC) qc->err_mask |= AC_ERR_ATA_BUS; qc->err_mask |= AC_ERR_ATA_BUS; if (err & (ATA_UNC | ATA_AMNF)) if (err & (ATA_UNC | ATA_AMNF)) Loading @@ -1825,20 +1855,31 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, tmp = atapi_eh_request_sense(qc->dev, tmp = atapi_eh_request_sense(qc->dev, qc->scsicmd->sense_buffer, qc->scsicmd->sense_buffer, qc->result_tf.feature >> 4); qc->result_tf.feature >> 4); if (!tmp) { if (!tmp) /* ATA_QCFLAG_SENSE_VALID is used to * tell atapi_qc_complete() that sense * data is already valid. * * TODO: interpret sense data and set * appropriate err_mask. */ qc->flags |= ATA_QCFLAG_SENSE_VALID; qc->flags |= ATA_QCFLAG_SENSE_VALID; } else else qc->err_mask |= tmp; qc->err_mask |= tmp; } } } } if (qc->flags & ATA_QCFLAG_SENSE_VALID) { int ret = scsi_check_sense(qc->scsicmd); /* * SUCCESS here means that the sense code could * evaluated and should be passed to the upper layers * for correct evaluation. * FAILED means the sense code could not interpreted * and the device would need to be reset. * NEEDS_RETRY and ADD_TO_MLQUEUE means that the * command would need to be retried. */ if (ret == NEEDS_RETRY || ret == ADD_TO_MLQUEUE) { qc->flags |= ATA_QCFLAG_RETRY; qc->err_mask |= AC_ERR_OTHER; } else if (ret != SUCCESS) { qc->err_mask |= AC_ERR_HSM; } } if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) action |= ATA_EH_RESET; action |= ATA_EH_RESET; Loading Loading @@ -1927,7 +1968,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) * This is to expedite speed down decisions right after device is * This is to expedite speed down decisions right after device is * initially configured. * initially configured. * * * The followings are speed down rules. #1 and #2 deal with * The following are speed down rules. #1 and #2 deal with * DUBIOUS errors. * DUBIOUS errors. * * * 1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors * 1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors Loading Loading @@ -2189,6 +2230,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) all_err_mask |= qc->err_mask; all_err_mask |= qc->err_mask; if (qc->flags & ATA_QCFLAG_IO) if (qc->flags & ATA_QCFLAG_IO) eflags |= ATA_EFLAG_IS_IO; eflags |= ATA_EFLAG_IS_IO; trace_ata_eh_link_autopsy_qc(qc); } } /* enforce default EH actions */ /* enforce default EH actions */ Loading Loading @@ -2223,7 +2265,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) eflags |= ATA_EFLAG_DUBIOUS_XFER; eflags |= ATA_EFLAG_DUBIOUS_XFER; ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask); 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"); DPRINTK("EXIT\n"); } } Loading Loading @@ -2375,6 +2417,8 @@ const char *ata_get_cmd_descript(u8 command) { 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_REQ_SENSE_DATA, "REQUEST SENSE DATA EXT" }, { ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" }, { ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" }, { ATA_CMD_ZAC_MGMT_IN, "ZAC MANAGEMENT IN" }, { ATA_CMD_ZAC_MGMT_OUT, "ZAC MANAGEMENT OUT" }, { ATA_CMD_READ_LONG, "READ LONG (with retries)" }, { ATA_CMD_READ_LONG, "READ LONG (with retries)" }, { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" }, { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" }, { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" }, { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" }, Loading Loading @@ -2499,17 +2543,39 @@ static void ata_eh_link_report(struct ata_link *link) [DMA_TO_DEVICE] = "out", [DMA_TO_DEVICE] = "out", [DMA_FROM_DEVICE] = "in", [DMA_FROM_DEVICE] = "in", }; }; static const char *prot_str[] = { const char *prot_str = NULL; [ATA_PROT_PIO] = "pio", [ATA_PROT_DMA] = "dma", [ATA_PROT_NCQ] = "ncq", [ATAPI_PROT_PIO] = "pio", [ATAPI_PROT_DMA] = "dma", }; switch (qc->tf.protocol) { case ATA_PROT_UNKNOWN: prot_str = "unknown"; break; case ATA_PROT_NODATA: prot_str = "nodata"; break; case ATA_PROT_PIO: prot_str = "pio"; break; case ATA_PROT_DMA: prot_str = "dma"; break; case ATA_PROT_NCQ: prot_str = "ncq dma"; break; case ATA_PROT_NCQ_NODATA: prot_str = "ncq nodata"; break; case ATAPI_PROT_NODATA: prot_str = "nodata"; break; case ATAPI_PROT_PIO: prot_str = "pio"; break; case ATAPI_PROT_DMA: prot_str = "dma"; break; } snprintf(data_buf, sizeof(data_buf), " %s %u %s", snprintf(data_buf, sizeof(data_buf), " %s %u %s", prot_str[qc->tf.protocol], qc->nbytes, prot_str, qc->nbytes, dma_str[qc->dma_dir]); dma_str[qc->dma_dir]); } } if (ata_is_atapi(qc->tf.protocol)) { if (ata_is_atapi(qc->tf.protocol)) { Loading Loading @@ -2551,14 +2617,15 @@ static void ata_eh_link_report(struct ata_link *link) #ifdef CONFIG_ATA_VERBOSE_ERROR #ifdef CONFIG_ATA_VERBOSE_ERROR if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) { ATA_SENSE | ATA_ERR)) { if (res->command & ATA_BUSY) if (res->command & ATA_BUSY) ata_dev_err(qc->dev, "status: { Busy }\n"); ata_dev_err(qc->dev, "status: { Busy }\n"); else else ata_dev_err(qc->dev, "status: { %s%s%s%s}\n", ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n", res->command & ATA_DRDY ? "DRDY " : "", res->command & ATA_DRDY ? "DRDY " : "", res->command & ATA_DF ? "DF " : "", res->command & ATA_DF ? "DF " : "", res->command & ATA_DRQ ? "DRQ " : "", res->command & ATA_DRQ ? "DRQ " : "", res->command & ATA_SENSE ? "SENSE " : "", res->command & ATA_ERR ? "ERR " : ""); res->command & ATA_ERR ? "ERR " : ""); } } Loading @@ -2574,6 +2641,7 @@ static void ata_eh_link_report(struct ata_link *link) #endif #endif } } } } /** /** * ata_eh_report - report error handling to user * ata_eh_report - report error handling to user * @ap: ATA port to report EH about * @ap: ATA port to report EH about Loading Loading @@ -3071,7 +3139,7 @@ static void ata_eh_park_issue_cmd(struct ata_device *dev, int park) } } tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; tf.protocol |= ATA_PROT_NODATA; tf.protocol = ATA_PROT_NODATA; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); if (park && (err_mask || tf.lbal != 0xc4)) { if (park && (err_mask || tf.lbal != 0xc4)) { ata_dev_err(dev, "head unload failed!\n"); ata_dev_err(dev, "head unload failed!\n"); Loading Loading @@ -3496,6 +3564,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, } } } } link->last_lpm_change = jiffies; link->flags |= ATA_LFLAG_CHANGED; return 0; return 0; fail: fail: Loading Loading @@ -4107,7 +4178,6 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) struct ata_link *link; struct ata_link *link; struct ata_device *dev; struct ata_device *dev; unsigned long flags; unsigned long flags; int rc = 0; /* are we resuming? */ /* are we resuming? */ spin_lock_irqsave(ap->lock, flags); spin_lock_irqsave(ap->lock, flags); Loading @@ -4134,7 +4204,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) ata_acpi_set_state(ap, ap->pm_mesg); ata_acpi_set_state(ap, ap->pm_mesg); if (ap->ops->port_resume) if (ap->ops->port_resume) rc = ap->ops->port_resume(ap); ap->ops->port_resume(ap); /* tell ACPI that we're resuming */ /* tell ACPI that we're resuming */ ata_acpi_on_resume(ap); ata_acpi_on_resume(ap); Loading Loading
src/drivers/ata/libata-eh.c +177 −107 Original line number Original line Diff line number Diff line Loading @@ -25,7 +25,7 @@ * * * * * libata documentation is available via 'make {ps|pdf}docs', * libata documentation is available via 'make {ps|pdf}docs', * as Documentation/DocBook/libata.* * as Documentation/driver-api/libata.rst * * * Hardware documentation available from http://www.t13.org/ and * Hardware documentation available from http://www.t13.org/ and * http://www.sata-io.org/ * http://www.sata-io.org/ Loading @@ -46,6 +46,7 @@ #include <linux/libata.h> #include <linux/libata.h> #include <trace/events/libata.h> #include "libata.h" #include "libata.h" enum { enum { Loading Loading @@ -548,6 +549,7 @@ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) DPRINTK("EXIT, ret=%d\n", ret); DPRINTK("EXIT, ret=%d\n", ret); return ret; return ret; } } EXPORT_SYMBOL(ata_scsi_timed_out); static void ata_eh_unload(struct ata_port *ap) static void ata_eh_unload(struct ata_port *ap) { { Loading Loading @@ -605,7 +607,7 @@ void ata_scsi_error(struct Scsi_Host *host) ata_scsi_port_error_handler(host, ap); ata_scsi_port_error_handler(host, ap); /* finish or retry handled scmd's and clean up */ /* finish or retry handled scmd's and clean up */ WARN_ON(host->host_failed || !list_empty(&eh_work_q)); WARN_ON(!list_empty(&eh_work_q)); DPRINTK("EXIT\n"); DPRINTK("EXIT\n"); } } Loading Loading @@ -643,12 +645,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, * completions are honored. A scmd is determined to have * completions are honored. A scmd is determined to have * timed out iff its associated qc is active and not failed. * timed out iff its associated qc is active and not failed. */ */ spin_lock_irqsave(ap->lock, flags); if (ap->ops->error_handler) { if (ap->ops->error_handler) { struct scsi_cmnd *scmd, *tmp; struct scsi_cmnd *scmd, *tmp; int nr_timedout = 0; int nr_timedout = 0; spin_lock_irqsave(ap->lock, flags); /* This must occur under the ap->lock as we don't want /* This must occur under the ap->lock as we don't want a polled recovery to race the real interrupt handler a polled recovery to race the real interrupt handler Loading Loading @@ -698,12 +699,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, if (nr_timedout) if (nr_timedout) __ata_port_freeze(ap); __ata_port_freeze(ap); spin_unlock_irqrestore(ap->lock, flags); /* initialize eh_tries */ /* initialize eh_tries */ ap->eh_tries = ATA_EH_MAX_TRIES; ap->eh_tries = ATA_EH_MAX_TRIES; } else } spin_unlock_wait(ap->lock); spin_unlock_irqrestore(ap->lock, flags); } } EXPORT_SYMBOL(ata_scsi_cmd_error_handler); EXPORT_SYMBOL(ata_scsi_cmd_error_handler); Loading Loading @@ -968,7 +968,7 @@ static void ata_eh_set_pending(struct ata_port *ap, int fastdrain) void ata_qc_schedule_eh(struct ata_queued_cmd *qc) void ata_qc_schedule_eh(struct ata_queued_cmd *qc) { { struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap; struct request_queue *q; struct request_queue *q = qc->scsicmd->device->request_queue; unsigned long flags; unsigned long flags; WARN_ON(!ap->ops->error_handler); WARN_ON(!ap->ops->error_handler); Loading @@ -981,13 +981,10 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) * Note that ATA_QCFLAG_FAILED is unconditionally set after * Note that ATA_QCFLAG_FAILED is unconditionally set after * this function completes. * this function completes. */ */ if (qc->scsicmd != NULL) { q = qc->scsicmd->device->request_queue; spin_lock_irqsave(q->queue_lock, flags); spin_lock_irqsave(q->queue_lock, flags); blk_abort_request(qc->scsicmd->request); blk_abort_request(qc->scsicmd->request); spin_unlock_irqrestore(q->queue_lock, flags); spin_unlock_irqrestore(q->queue_lock, flags); } } } /** /** * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine Loading Loading @@ -1435,7 +1432,7 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, /** /** * ata_eh_done - EH action complete * ata_eh_done - EH action complete * @ap: target ATA port * @link: ATA link for which EH actions are complete * @dev: target ATA dev for per-dev action (can be NULL) * @dev: target ATA dev for per-dev action (can be NULL) * @action: action just completed * @action: action just completed * * Loading Loading @@ -1488,46 +1485,6 @@ static const char *ata_err_string(unsigned int err_mask) return "unknown error"; return "unknown error"; } } /** * ata_read_log_page - read a specific log page * @dev: target device * @log: log to read * @page: page to read * @buf: buffer to store read page * @sectors: number of sectors to read * * Read log page using READ_LOG_EXT command. * * LOCKING: * Kernel thread context (may sleep). * * RETURNS: * 0 on success, AC_ERR_* mask otherwise. */ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, u8 page, void *buf, unsigned int sectors) { struct ata_taskfile tf; unsigned int err_mask; 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; 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); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; } /** /** * ata_eh_read_log_10h - Read log page 10h for NCQ error details * ata_eh_read_log_10h - Read log page 10h for NCQ error details * @dev: Device to read log page 10h from * @dev: Device to read log page 10h from Loading Loading @@ -1578,6 +1535,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev, tf->hob_lbah = buf[10]; tf->hob_lbah = buf[10]; tf->nsect = buf[12]; tf->nsect = buf[12]; tf->hob_nsect = buf[13]; 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; return 0; } } Loading Loading @@ -1613,6 +1572,56 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) return err_mask; return err_mask; } } /** * ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT * @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to * @cmd: scsi command for which the sense code should be set * * Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK * SENSE. This function is an EH helper. * * LOCKING: * Kernel thread context (may sleep). */ static void ata_eh_request_sense(struct ata_queued_cmd *qc, struct scsi_cmnd *cmd) { struct ata_device *dev = qc->dev; struct ata_taskfile tf; unsigned int err_mask; if (qc->ap->pflags & ATA_PFLAG_FROZEN) { ata_dev_warn(dev, "sense data available but port frozen\n"); return; } if (!cmd || qc->flags & ATA_QCFLAG_SENSE_VALID) return; if (!ata_id_sense_reporting_enabled(dev->id)) { ata_dev_warn(qc->dev, "sense data reporting disabled\n"); return; } DPRINTK("ATA request sense\n"); ata_tf_init(dev, &tf); tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; tf.command = ATA_CMD_REQ_SENSE_DATA; tf.protocol = ATA_PROT_NODATA; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); /* Ignore err_mask; ATA_ERR might be set */ if (tf.command & ATA_SENSE) { ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal); qc->flags |= ATA_QCFLAG_SENSE_VALID; } else { ata_dev_warn(dev, "request sense failed stat %02x emask %x\n", tf.command, err_mask); } } /** /** * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE * @dev: device to perform REQUEST_SENSE to * @dev: device to perform REQUEST_SENSE to Loading Loading @@ -1775,6 +1784,18 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) memcpy(&qc->result_tf, &tf, sizeof(tf)); memcpy(&qc->result_tf, &tf, sizeof(tf)); qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; if ((qc->result_tf.command & ATA_SENSE) || 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_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, ascq); ata_scsi_set_sense_information(dev, qc->scsicmd, &qc->result_tf); qc->flags |= ATA_QCFLAG_SENSE_VALID; } ehc->i.err_mask &= ~AC_ERR_DEV; ehc->i.err_mask &= ~AC_ERR_DEV; } } Loading Loading @@ -1804,14 +1825,23 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, return ATA_EH_RESET; return ATA_EH_RESET; } } if (stat & (ATA_ERR | ATA_DF)) if (stat & (ATA_ERR | ATA_DF)) { qc->err_mask |= AC_ERR_DEV; qc->err_mask |= AC_ERR_DEV; else /* * Sense data reporting does not work if the * device fault bit is set. */ if (stat & ATA_DF) stat &= ~ATA_SENSE; } else { return 0; return 0; } switch (qc->dev->class) { switch (qc->dev->class) { case ATA_DEV_ATA: case ATA_DEV_ATA: case ATA_DEV_ZAC: case ATA_DEV_ZAC: if (stat & ATA_SENSE) ata_eh_request_sense(qc, qc->scsicmd); if (err & ATA_ICRC) if (err & ATA_ICRC) qc->err_mask |= AC_ERR_ATA_BUS; qc->err_mask |= AC_ERR_ATA_BUS; if (err & (ATA_UNC | ATA_AMNF)) if (err & (ATA_UNC | ATA_AMNF)) Loading @@ -1825,20 +1855,31 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, tmp = atapi_eh_request_sense(qc->dev, tmp = atapi_eh_request_sense(qc->dev, qc->scsicmd->sense_buffer, qc->scsicmd->sense_buffer, qc->result_tf.feature >> 4); qc->result_tf.feature >> 4); if (!tmp) { if (!tmp) /* ATA_QCFLAG_SENSE_VALID is used to * tell atapi_qc_complete() that sense * data is already valid. * * TODO: interpret sense data and set * appropriate err_mask. */ qc->flags |= ATA_QCFLAG_SENSE_VALID; qc->flags |= ATA_QCFLAG_SENSE_VALID; } else else qc->err_mask |= tmp; qc->err_mask |= tmp; } } } } if (qc->flags & ATA_QCFLAG_SENSE_VALID) { int ret = scsi_check_sense(qc->scsicmd); /* * SUCCESS here means that the sense code could * evaluated and should be passed to the upper layers * for correct evaluation. * FAILED means the sense code could not interpreted * and the device would need to be reset. * NEEDS_RETRY and ADD_TO_MLQUEUE means that the * command would need to be retried. */ if (ret == NEEDS_RETRY || ret == ADD_TO_MLQUEUE) { qc->flags |= ATA_QCFLAG_RETRY; qc->err_mask |= AC_ERR_OTHER; } else if (ret != SUCCESS) { qc->err_mask |= AC_ERR_HSM; } } if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) action |= ATA_EH_RESET; action |= ATA_EH_RESET; Loading Loading @@ -1927,7 +1968,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) * This is to expedite speed down decisions right after device is * This is to expedite speed down decisions right after device is * initially configured. * initially configured. * * * The followings are speed down rules. #1 and #2 deal with * The following are speed down rules. #1 and #2 deal with * DUBIOUS errors. * DUBIOUS errors. * * * 1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors * 1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors Loading Loading @@ -2189,6 +2230,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) all_err_mask |= qc->err_mask; all_err_mask |= qc->err_mask; if (qc->flags & ATA_QCFLAG_IO) if (qc->flags & ATA_QCFLAG_IO) eflags |= ATA_EFLAG_IS_IO; eflags |= ATA_EFLAG_IS_IO; trace_ata_eh_link_autopsy_qc(qc); } } /* enforce default EH actions */ /* enforce default EH actions */ Loading Loading @@ -2223,7 +2265,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) eflags |= ATA_EFLAG_DUBIOUS_XFER; eflags |= ATA_EFLAG_DUBIOUS_XFER; ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask); 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"); DPRINTK("EXIT\n"); } } Loading Loading @@ -2375,6 +2417,8 @@ const char *ata_get_cmd_descript(u8 command) { 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_REQ_SENSE_DATA, "REQUEST SENSE DATA EXT" }, { ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" }, { ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" }, { ATA_CMD_ZAC_MGMT_IN, "ZAC MANAGEMENT IN" }, { ATA_CMD_ZAC_MGMT_OUT, "ZAC MANAGEMENT OUT" }, { ATA_CMD_READ_LONG, "READ LONG (with retries)" }, { ATA_CMD_READ_LONG, "READ LONG (with retries)" }, { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" }, { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" }, { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" }, { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" }, Loading Loading @@ -2499,17 +2543,39 @@ static void ata_eh_link_report(struct ata_link *link) [DMA_TO_DEVICE] = "out", [DMA_TO_DEVICE] = "out", [DMA_FROM_DEVICE] = "in", [DMA_FROM_DEVICE] = "in", }; }; static const char *prot_str[] = { const char *prot_str = NULL; [ATA_PROT_PIO] = "pio", [ATA_PROT_DMA] = "dma", [ATA_PROT_NCQ] = "ncq", [ATAPI_PROT_PIO] = "pio", [ATAPI_PROT_DMA] = "dma", }; switch (qc->tf.protocol) { case ATA_PROT_UNKNOWN: prot_str = "unknown"; break; case ATA_PROT_NODATA: prot_str = "nodata"; break; case ATA_PROT_PIO: prot_str = "pio"; break; case ATA_PROT_DMA: prot_str = "dma"; break; case ATA_PROT_NCQ: prot_str = "ncq dma"; break; case ATA_PROT_NCQ_NODATA: prot_str = "ncq nodata"; break; case ATAPI_PROT_NODATA: prot_str = "nodata"; break; case ATAPI_PROT_PIO: prot_str = "pio"; break; case ATAPI_PROT_DMA: prot_str = "dma"; break; } snprintf(data_buf, sizeof(data_buf), " %s %u %s", snprintf(data_buf, sizeof(data_buf), " %s %u %s", prot_str[qc->tf.protocol], qc->nbytes, prot_str, qc->nbytes, dma_str[qc->dma_dir]); dma_str[qc->dma_dir]); } } if (ata_is_atapi(qc->tf.protocol)) { if (ata_is_atapi(qc->tf.protocol)) { Loading Loading @@ -2551,14 +2617,15 @@ static void ata_eh_link_report(struct ata_link *link) #ifdef CONFIG_ATA_VERBOSE_ERROR #ifdef CONFIG_ATA_VERBOSE_ERROR if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) { ATA_SENSE | ATA_ERR)) { if (res->command & ATA_BUSY) if (res->command & ATA_BUSY) ata_dev_err(qc->dev, "status: { Busy }\n"); ata_dev_err(qc->dev, "status: { Busy }\n"); else else ata_dev_err(qc->dev, "status: { %s%s%s%s}\n", ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n", res->command & ATA_DRDY ? "DRDY " : "", res->command & ATA_DRDY ? "DRDY " : "", res->command & ATA_DF ? "DF " : "", res->command & ATA_DF ? "DF " : "", res->command & ATA_DRQ ? "DRQ " : "", res->command & ATA_DRQ ? "DRQ " : "", res->command & ATA_SENSE ? "SENSE " : "", res->command & ATA_ERR ? "ERR " : ""); res->command & ATA_ERR ? "ERR " : ""); } } Loading @@ -2574,6 +2641,7 @@ static void ata_eh_link_report(struct ata_link *link) #endif #endif } } } } /** /** * ata_eh_report - report error handling to user * ata_eh_report - report error handling to user * @ap: ATA port to report EH about * @ap: ATA port to report EH about Loading Loading @@ -3071,7 +3139,7 @@ static void ata_eh_park_issue_cmd(struct ata_device *dev, int park) } } tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; tf.protocol |= ATA_PROT_NODATA; tf.protocol = ATA_PROT_NODATA; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); if (park && (err_mask || tf.lbal != 0xc4)) { if (park && (err_mask || tf.lbal != 0xc4)) { ata_dev_err(dev, "head unload failed!\n"); ata_dev_err(dev, "head unload failed!\n"); Loading Loading @@ -3496,6 +3564,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, } } } } link->last_lpm_change = jiffies; link->flags |= ATA_LFLAG_CHANGED; return 0; return 0; fail: fail: Loading Loading @@ -4107,7 +4178,6 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) struct ata_link *link; struct ata_link *link; struct ata_device *dev; struct ata_device *dev; unsigned long flags; unsigned long flags; int rc = 0; /* are we resuming? */ /* are we resuming? */ spin_lock_irqsave(ap->lock, flags); spin_lock_irqsave(ap->lock, flags); Loading @@ -4134,7 +4204,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) ata_acpi_set_state(ap, ap->pm_mesg); ata_acpi_set_state(ap, ap->pm_mesg); if (ap->ops->port_resume) if (ap->ops->port_resume) rc = ap->ops->port_resume(ap); ap->ops->port_resume(ap); /* tell ACPI that we're resuming */ /* tell ACPI that we're resuming */ ata_acpi_on_resume(ap); ata_acpi_on_resume(ap); Loading