Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/ata/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 113 kB image not shown  

Quelle  libata-eh.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  libata-eh.c - libata error handling
 *
 *  Copyright 2006 Tejun Heo <htejun@gmail.com>
 *
 *  libata documentation is available via 'make {ps|pdf}docs',
 *  as Documentation/driver-api/libata.rst
 *
 *  Hardware documentation available from http://www.t13.org/ and
 *  http://www.sata-io.org/
 */


#include <linux/kernel.h>
#include <linux/blkdev.h>
#include <linux/export.h>
#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include "../scsi/scsi_transport_api.h"

#include <linux/libata.h>

#include <trace/events/libata.h>
#include "libata.h"

enum {
 /* speed down verdicts */
 ATA_EH_SPDN_NCQ_OFF  = (1 << 0),
 ATA_EH_SPDN_SPEED_DOWN  = (1 << 1),
 ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2),
 ATA_EH_SPDN_KEEP_ERRORS  = (1 << 3),

 /* error flags */
 ATA_EFLAG_IS_IO   = (1 << 0),
 ATA_EFLAG_DUBIOUS_XFER  = (1 << 1),
 ATA_EFLAG_OLD_ER                = (1 << 31),

 /* error categories */
 ATA_ECAT_NONE   = 0,
 ATA_ECAT_ATA_BUS  = 1,
 ATA_ECAT_TOUT_HSM  = 2,
 ATA_ECAT_UNK_DEV  = 3,
 ATA_ECAT_DUBIOUS_NONE  = 4,
 ATA_ECAT_DUBIOUS_ATA_BUS = 5,
 ATA_ECAT_DUBIOUS_TOUT_HSM = 6,
 ATA_ECAT_DUBIOUS_UNK_DEV = 7,
 ATA_ECAT_NR   = 8,

 ATA_EH_CMD_DFL_TIMEOUT  =  5000,

 /* always put at least this amount of time between resets */
 ATA_EH_RESET_COOL_DOWN  =  5000,

 /* Waiting in ->prereset can never be reliable.  It's
 * sometimes nice to wait there but it can't be depended upon;
 * otherwise, we wouldn't be resetting.  Just give it enough
 * time for most drives to spin up.
 */

 ATA_EH_PRERESET_TIMEOUT  = 10000,
 ATA_EH_FASTDRAIN_INTERVAL =  3000,

 ATA_EH_UA_TRIES   = 5,

 /* probe speed down parameters, see ata_eh_schedule_probe() */
 ATA_EH_PROBE_TRIAL_INTERVAL = 60000, /* 1 min */
 ATA_EH_PROBE_TRIALS  = 2,
};

/* The following table determines how we sequence resets.  Each entry
 * represents timeout for that try.  The first try can be soft or
 * hardreset.  All others are hardreset if available.  In most cases
 * the first reset w/ 10sec timeout should succeed.  Following entries
 * are mostly for error handling, hotplug and those outlier devices that
 * take an exceptionally long time to recover from reset.
 */

static const unsigned int ata_eh_reset_timeouts[] = {
 10000, /* most drives spin up by 10sec */
 10000, /* > 99% working drives spin up before 20sec */
 35000, /* give > 30 secs of idleness for outlier devices */
  5000, /* and sweet one last chance */
 UINT_MAX, /* > 1 min has elapsed, give up */
};

static const unsigned int ata_eh_identify_timeouts[] = {
  5000, /* covers > 99% of successes and not too boring on failures */
 10000,  /* combined time till here is enough even for media access */
 30000, /* for true idiots */
 UINT_MAX,
};

static const unsigned int ata_eh_revalidate_timeouts[] = {
 15000, /* Some drives are slow to read log pages when waking-up */
 15000,  /* combined time till here is enough even for media access */
 UINT_MAX,
};

static const unsigned int ata_eh_flush_timeouts[] = {
 15000, /* be generous with flush */
 15000,  /* ditto */
 30000, /* and even more generous */
 UINT_MAX,
};

static const unsigned int ata_eh_other_timeouts[] = {
  5000, /* same rationale as identify timeout */
 10000, /* ditto */
 /* but no merciful 30sec for other commands, it just isn't worth it */
 UINT_MAX,
};

struct ata_eh_cmd_timeout_ent {
 const u8  *commands;
 const unsigned int *timeouts;
};

/* The following table determines timeouts to use for EH internal
 * commands.  Each table entry is a command class and matches the
 * commands the entry applies to and the timeout table to use.
 *
 * On the retry after a command timed out, the next timeout value from
 * the table is used.  If the table doesn't contain further entries,
 * the last value is used.
 *
 * ehc->cmd_timeout_idx keeps track of which timeout to use per
 * command class, so if SET_FEATURES times out on the first try, the
 * next try will use the second timeout value only for that class.
 */

#define CMDS(cmds...) (const u8 []){ cmds, 0 }
static const struct ata_eh_cmd_timeout_ent
ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
 { .commands = CMDS(ATA_CMD_ID_ATA, ATA_CMD_ID_ATAPI),
   .timeouts = ata_eh_identify_timeouts, },
 { .commands = CMDS(ATA_CMD_READ_LOG_EXT, ATA_CMD_READ_LOG_DMA_EXT),
   .timeouts = ata_eh_revalidate_timeouts, },
 { .commands = CMDS(ATA_CMD_READ_NATIVE_MAX, ATA_CMD_READ_NATIVE_MAX_EXT),
   .timeouts = ata_eh_other_timeouts, },
 { .commands = CMDS(ATA_CMD_SET_MAX, ATA_CMD_SET_MAX_EXT),
   .timeouts = ata_eh_other_timeouts, },
 { .commands = CMDS(ATA_CMD_SET_FEATURES),
   .timeouts = ata_eh_other_timeouts, },
 { .commands = CMDS(ATA_CMD_INIT_DEV_PARAMS),
   .timeouts = ata_eh_other_timeouts, },
 { .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT),
   .timeouts = ata_eh_flush_timeouts },
 { .commands = CMDS(ATA_CMD_VERIFY),
   .timeouts = ata_eh_reset_timeouts },
};
#undef CMDS

static void __ata_port_freeze(struct ata_port *ap);
#ifdef CONFIG_PM
static void ata_eh_handle_port_suspend(struct ata_port *ap);
static void ata_eh_handle_port_resume(struct ata_port *ap);
#else /* CONFIG_PM */
static void ata_eh_handle_port_suspend(struct ata_port *ap)
{ }

static void ata_eh_handle_port_resume(struct ata_port *ap)
{ }
#endif /* CONFIG_PM */

static __printf(2, 0) void __ata_ehi_pushv_desc(struct ata_eh_info *ehi,
     const char *fmt, va_list args)
{
 ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len,
         ATA_EH_DESC_LEN - ehi->desc_len,
         fmt, args);
}

/**
 * __ata_ehi_push_desc - push error description without adding separator
 * @ehi: target EHI
 * @fmt: printf format string
 *
 * Format string according to @fmt and append it to @ehi->desc.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 */

void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
{
 va_list args;

 va_start(args, fmt);
 __ata_ehi_pushv_desc(ehi, fmt, args);
 va_end(args);
}
EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);

/**
 * ata_ehi_push_desc - push error description with separator
 * @ehi: target EHI
 * @fmt: printf format string
 *
 * Format string according to @fmt and append it to @ehi->desc.
 * If @ehi->desc is not empty, ", " is added in-between.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 */

void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
{
 va_list args;

 if (ehi->desc_len)
  __ata_ehi_push_desc(ehi, ", ");

 va_start(args, fmt);
 __ata_ehi_pushv_desc(ehi, fmt, args);
 va_end(args);
}
EXPORT_SYMBOL_GPL(ata_ehi_push_desc);

/**
 * ata_ehi_clear_desc - clean error description
 * @ehi: target EHI
 *
 * Clear @ehi->desc.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 */

void ata_ehi_clear_desc(struct ata_eh_info *ehi)
{
 ehi->desc[0] = '\0';
 ehi->desc_len = 0;
}
EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);

/**
 * ata_port_desc - append port description
 * @ap: target ATA port
 * @fmt: printf format string
 *
 * Format string according to @fmt and append it to port
 * description.  If port description is not empty, " " is added
 * in-between.  This function is to be used while initializing
 * ata_host.  The description is printed on host registration.
 *
 * LOCKING:
 * None.
 */

void ata_port_desc(struct ata_port *ap, const char *fmt, ...)
{
 va_list args;

 WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING));

 if (ap->link.eh_info.desc_len)
  __ata_ehi_push_desc(&ap->link.eh_info, " ");

 va_start(args, fmt);
 __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args);
 va_end(args);
}
EXPORT_SYMBOL_GPL(ata_port_desc);

#ifdef CONFIG_PCI
/**
 * ata_port_pbar_desc - append PCI BAR description
 * @ap: target ATA port
 * @bar: target PCI BAR
 * @offset: offset into PCI BAR
 * @name: name of the area
 *
 * If @offset is negative, this function formats a string which
 * contains the name, address, size and type of the BAR and
 * appends it to the port description.  If @offset is zero or
 * positive, only name and offsetted address is appended.
 *
 * LOCKING:
 * None.
 */

void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
   const char *name)
{
 struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 char *type = "";
 unsigned long long start, len;

 if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
  type = "m";
 else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
  type = "i";

 start = (unsigned long long)pci_resource_start(pdev, bar);
 len = (unsigned long long)pci_resource_len(pdev, bar);

 if (offset < 0)
  ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start);
 else
  ata_port_desc(ap, "%s 0x%llx", name,
    start + (unsigned long long)offset);
}
EXPORT_SYMBOL_GPL(ata_port_pbar_desc);
#endif /* CONFIG_PCI */

static int ata_lookup_timeout_table(u8 cmd)
{
 int i;

 for (i = 0; i < ATA_EH_CMD_TIMEOUT_TABLE_SIZE; i++) {
  const u8 *cur;

  for (cur = ata_eh_cmd_timeout_table[i].commands; *cur; cur++)
   if (*cur == cmd)
    return i;
 }

 return -1;
}

/**
 * ata_internal_cmd_timeout - determine timeout for an internal command
 * @dev: target device
 * @cmd: internal command to be issued
 *
 * Determine timeout for internal command @cmd for @dev.
 *
 * LOCKING:
 * EH context.
 *
 * RETURNS:
 * Determined timeout.
 */

unsigned int ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd)
{
 struct ata_eh_context *ehc = &dev->link->eh_context;
 int ent = ata_lookup_timeout_table(cmd);
 int idx;

 if (ent < 0)
  return ATA_EH_CMD_DFL_TIMEOUT;

 idx = ehc->cmd_timeout_idx[dev->devno][ent];
 return ata_eh_cmd_timeout_table[ent].timeouts[idx];
}

/**
 * ata_internal_cmd_timed_out - notification for internal command timeout
 * @dev: target device
 * @cmd: internal command which timed out
 *
 * Notify EH that internal command @cmd for @dev timed out.  This
 * function should be called only for commands whose timeouts are
 * determined using ata_internal_cmd_timeout().
 *
 * LOCKING:
 * EH context.
 */

void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd)
{
 struct ata_eh_context *ehc = &dev->link->eh_context;
 int ent = ata_lookup_timeout_table(cmd);
 int idx;

 if (ent < 0)
  return;

 idx = ehc->cmd_timeout_idx[dev->devno][ent];
 if (ata_eh_cmd_timeout_table[ent].timeouts[idx + 1] != UINT_MAX)
  ehc->cmd_timeout_idx[dev->devno][ent]++;
}

static void ata_ering_record(struct ata_ering *ering, unsigned int eflags,
        unsigned int err_mask)
{
 struct ata_ering_entry *ent;

 WARN_ON(!err_mask);

 ering->cursor++;
 ering->cursor %= ATA_ERING_SIZE;

 ent = &ering->ring[ering->cursor];
 ent->eflags = eflags;
 ent->err_mask = err_mask;
 ent->timestamp = get_jiffies_64();
}

static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering)
{
 struct ata_ering_entry *ent = &ering->ring[ering->cursor];

 if (ent->err_mask)
  return ent;
 return NULL;
}

int ata_ering_map(struct ata_ering *ering,
    int (*map_fn)(struct ata_ering_entry *, void *),
    void *arg)
{
 int idx, rc = 0;
 struct ata_ering_entry *ent;

 idx = ering->cursor;
 do {
  ent = &ering->ring[idx];
  if (!ent->err_mask)
   break;
  rc = map_fn(ent, arg);
  if (rc)
   break;
  idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE;
 } while (idx != ering->cursor);

 return rc;
}

static int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg)
{
 ent->eflags |= ATA_EFLAG_OLD_ER;
 return 0;
}

static void ata_ering_clear(struct ata_ering *ering)
{
 ata_ering_map(ering, ata_ering_clear_cb, NULL);
}

static unsigned int ata_eh_dev_action(struct ata_device *dev)
{
 struct ata_eh_context *ehc = &dev->link->eh_context;

 return ehc->i.action | ehc->i.dev_action[dev->devno];
}

static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
    struct ata_eh_info *ehi, unsigned int action)
{
 struct ata_device *tdev;

 if (!dev) {
  ehi->action &= ~action;
  ata_for_each_dev(tdev, link, ALL)
   ehi->dev_action[tdev->devno] &= ~action;
 } else {
  /* doesn't make sense for port-wide EH actions */
  WARN_ON(!(action & ATA_EH_PERDEV_MASK));

  /* break ehi->action into ehi->dev_action */
  if (ehi->action & action) {
   ata_for_each_dev(tdev, link, ALL)
    ehi->dev_action[tdev->devno] |=
     ehi->action & action;
   ehi->action &= ~action;
  }

  /* turn off the specified per-dev action */
  ehi->dev_action[dev->devno] &= ~action;
 }
}

/**
 * ata_eh_acquire - acquire EH ownership
 * @ap: ATA port to acquire EH ownership for
 *
 * Acquire EH ownership for @ap.  This is the basic exclusion
 * mechanism for ports sharing a host.  Only one port hanging off
 * the same host can claim the ownership of EH.
 *
 * LOCKING:
 * EH context.
 */

void ata_eh_acquire(struct ata_port *ap)
{
 mutex_lock(&ap->host->eh_mutex);
 WARN_ON_ONCE(ap->host->eh_owner);
 ap->host->eh_owner = current;
}

/**
 * ata_eh_release - release EH ownership
 * @ap: ATA port to release EH ownership for
 *
 * Release EH ownership for @ap if the caller.  The caller must
 * have acquired EH ownership using ata_eh_acquire() previously.
 *
 * LOCKING:
 * EH context.
 */

void ata_eh_release(struct ata_port *ap)
{
 WARN_ON_ONCE(ap->host->eh_owner != current);
 ap->host->eh_owner = NULL;
 mutex_unlock(&ap->host->eh_mutex);
}

static void ata_eh_dev_disable(struct ata_device *dev)
{
 ata_acpi_on_disable(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
 * 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)
{
 struct ata_link *link;
 struct ata_device *dev;
 unsigned long flags;

 /*
 * Unless we are restarting, transition all enabled devices to
 * standby power mode.
 */

 if (system_state != SYSTEM_RESTART) {
  ata_for_each_link(link, ap, PMP_FIRST) {
   ata_for_each_dev(dev, link, ENABLED)
    ata_dev_power_set_standby(dev);
  }
 }

 /*
 * Restore SControl IPM and SPD for the next driver and
 * disable attached devices.
 */

 ata_for_each_link(link, ap, PMP_FIRST) {
  sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0);
  ata_for_each_dev(dev, link, ENABLED)
   ata_eh_dev_disable(dev);
 }

 /* freeze and set UNLOADED */
 spin_lock_irqsave(ap->lock, flags);

 ata_port_freeze(ap);   /* won't be thawed */
 ap->pflags &= ~ATA_PFLAG_EH_PENDING; /* clear pending from freeze */
 ap->pflags |= ATA_PFLAG_UNLOADED;

 spin_unlock_irqrestore(ap->lock, flags);
}

/**
 * ata_scsi_error - SCSI layer error handler callback
 * @host: SCSI host on which error occurred
 *
 * Handles SCSI-layer-thrown error events.
 *
 * LOCKING:
 * Inherited from SCSI layer (none, can sleep)
 *
 * RETURNS:
 * Zero.
 */

void ata_scsi_error(struct Scsi_Host *host)
{
 struct ata_port *ap = ata_shost_to_port(host);
 unsigned long flags;
 LIST_HEAD(eh_work_q);

 spin_lock_irqsave(host->host_lock, flags);
 list_splice_init(&host->eh_cmd_q, &eh_work_q);
 spin_unlock_irqrestore(host->host_lock, flags);

 ata_scsi_cmd_error_handler(host, ap, &eh_work_q);

 /* If we timed raced normal completion and there is nothing to
   recover nr_timedout == 0 why exactly are we doing error recovery ? */

 ata_scsi_port_error_handler(host, ap);

 /* finish or retry handled scmd's and clean up */
 WARN_ON(!list_empty(&eh_work_q));

}

/**
 * ata_scsi_cmd_error_handler - error callback for a list of commands
 * @host: scsi host containing the port
 * @ap: ATA port within the host
 * @eh_work_q: list of commands to process
 *
 * process the given list of commands and return those finished to the
 * ap->eh_done_q.  This function is the first part of the libata error
 * handler which processes a given list of failed commands.
 */

void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
    struct list_head *eh_work_q)
{
 int i;
 unsigned long flags;
 struct scsi_cmnd *scmd, *tmp;
 int nr_timedout = 0;

 /* make sure sff pio task is not running */
 ata_sff_flush_pio_task(ap);

 /* synchronize with host lock and sort out timeouts */

 /*
 * For EH, all qcs are finished in one of three ways -
 * normal completion, error completion, and SCSI timeout.
 * Both completions can race against SCSI timeout.  When normal
 * completion wins, the qc never reaches EH.  When error
 * completion wins, the qc has ATA_QCFLAG_EH set.
 *
 * When SCSI timeout wins, things are a bit more complex.
 * Normal or error completion can occur after the timeout but
 * before this point.  In such cases, both types of
 * completions are honored.  A scmd is determined to have
 * timed out iff its associated qc is active and not failed.
 */

 spin_lock_irqsave(ap->lock, flags);

 /*
 * This must occur under the ap->lock as we don't want
 * a polled recovery to race the real interrupt handler
 *
 * The lost_interrupt handler checks for any completed but
 * non-notified command and completes much like an IRQ handler.
 *
 * We then fall into the error recovery code which will treat
 * this as if normal completion won the race
 */

 if (ap->ops->lost_interrupt)
  ap->ops->lost_interrupt(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)
    break;
  }

  if (i < ATA_MAX_QUEUE) {
   /* the scmd has an associated qc */
   if (!(qc->flags & ATA_QCFLAG_EH)) {
    /* which hasn't failed yet, timeout */
    set_host_byte(scmd, DID_TIME_OUT);
    qc->err_mask |= AC_ERR_TIMEOUT;
    qc->flags |= ATA_QCFLAG_EH;
    nr_timedout++;
   }
  } else {
   /* Normal completion occurred after
 * SCSI timeout but before this point.
 * Successfully complete it.
 */

   scmd->retries = scmd->allowed;
   scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
  }
 }

 /*
 * If we have timed out qcs.  They belong to EH from
 * this point but the state of the controller is
 * unknown.  Freeze the port to make sure the IRQ
 * handler doesn't diddle with those qcs.  This must
 * be done atomically w.r.t. setting ATA_QCFLAG_EH.
 */

 if (nr_timedout)
  __ata_port_freeze(ap);

 /* initialize eh_tries */
 ap->eh_tries = ATA_EH_MAX_TRIES;

 spin_unlock_irqrestore(ap->lock, flags);
}
EXPORT_SYMBOL(ata_scsi_cmd_error_handler);

/**
 * ata_scsi_port_error_handler - recover the port after the commands
 * @host: SCSI host containing the port
 * @ap: the ATA port
 *
 * Handle the recovery of the port @ap after all the commands
 * have been recovered.
 */

void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
{
 unsigned long flags;
 struct ata_link *link;

 /* acquire EH ownership */
 ata_eh_acquire(ap);
 repeat:
 /* kill fast drain timer */
 timer_delete_sync(&ap->fastdrain_timer);

 /* process port resume request */
 ata_eh_handle_port_resume(ap);

 /* fetch & clear EH info */
 spin_lock_irqsave(ap->lock, flags);

 ata_for_each_link(link, ap, HOST_FIRST) {
  struct ata_eh_context *ehc = &link->eh_context;
  struct ata_device *dev;

  memset(&link->eh_context, 0, sizeof(link->eh_context));
  link->eh_context.i = link->eh_info;
  memset(&link->eh_info, 0, sizeof(link->eh_info));

  ata_for_each_dev(dev, link, ENABLED) {
   int devno = dev->devno;

   ehc->saved_xfer_mode[devno] = dev->xfer_mode;
   if (ata_ncq_enabled(dev))
    ehc->saved_ncq_enabled |= 1 << devno;

   /* If we are resuming, wake up the device */
   if (ap->pflags & ATA_PFLAG_RESUMING) {
    dev->flags |= ATA_DFLAG_RESUMING;
    ehc->i.dev_action[devno] |= ATA_EH_SET_ACTIVE;
   }
  }
 }

 ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
 ap->pflags &= ~ATA_PFLAG_EH_PENDING;
 ap->excl_link = NULL; /* don't maintain exclusion over EH */

 spin_unlock_irqrestore(ap->lock, flags);

 /* invoke EH, skip if unloading or suspended */
 if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
  ap->ops->error_handler(ap);
 else {
  /* if unloading, commence suicide */
  if ((ap->pflags & ATA_PFLAG_UNLOADING) &&
      !(ap->pflags & ATA_PFLAG_UNLOADED))
   ata_eh_unload(ap);
  ata_eh_finish(ap);
 }

 /* process port suspend request */
 ata_eh_handle_port_suspend(ap);

 /*
 * Exception might have happened after ->error_handler recovered the
 * port but before this point.  Repeat EH in such case.
 */

 spin_lock_irqsave(ap->lock, flags);

 if (ap->pflags & ATA_PFLAG_EH_PENDING) {
  if (--ap->eh_tries) {
   spin_unlock_irqrestore(ap->lock, flags);
   goto repeat;
  }
  ata_port_err(ap,
        "EH pending after %d tries, giving up\n",
        ATA_EH_MAX_TRIES);
  ap->pflags &= ~ATA_PFLAG_EH_PENDING;
 }

 /* this run is complete, make sure EH info is clear */
 ata_for_each_link(link, ap, HOST_FIRST)
  memset(&link->eh_info, 0, sizeof(link->eh_info));

 /*
 * end eh (clear host_eh_scheduled) while holding ap->lock such that if
 * exception occurs after this point but before EH completion, SCSI
 * midlayer will re-initiate EH.
 */

 ap->ops->end_eh(ap);

 spin_unlock_irqrestore(ap->lock, flags);
 ata_eh_release(ap);

 scsi_eh_flush_done_q(&ap->eh_done_q);

 /* clean up */
 spin_lock_irqsave(ap->lock, flags);

 ap->pflags &= ~ATA_PFLAG_RESUMING;

 if (ap->pflags & ATA_PFLAG_LOADING)
  ap->pflags &= ~ATA_PFLAG_LOADING;
 else if ((ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) &&
  !(ap->flags & ATA_FLAG_SAS_HOST))
  schedule_delayed_work(&ap->hotplug_task, 0);

 if (ap->pflags & ATA_PFLAG_RECOVERED)
  ata_port_info(ap, "EH complete\n");

 ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);

 /* tell wait_eh that we're done */
 ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
 wake_up_all(&ap->eh_wait_q);

 spin_unlock_irqrestore(ap->lock, flags);
}
EXPORT_SYMBOL_GPL(ata_scsi_port_error_handler);

/**
 * ata_port_wait_eh - Wait for the currently pending EH to complete
 * @ap: Port to wait EH for
 *
 * Wait until the currently pending EH is complete.
 *
 * LOCKING:
 * Kernel thread context (may sleep).
 */

void ata_port_wait_eh(struct ata_port *ap)
{
 unsigned long flags;
 DEFINE_WAIT(wait);

 retry:
 spin_lock_irqsave(ap->lock, flags);

 while (ata_port_eh_scheduled(ap)) {
  prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
  spin_unlock_irqrestore(ap->lock, flags);
  schedule();
  spin_lock_irqsave(ap->lock, flags);
 }
 finish_wait(&ap->eh_wait_q, &wait);

 spin_unlock_irqrestore(ap->lock, flags);

 /* make sure SCSI EH is complete */
 if (scsi_host_in_recovery(ap->scsi_host)) {
  ata_msleep(ap, 10);
  goto retry;
 }
}
EXPORT_SYMBOL_GPL(ata_port_wait_eh);

static unsigned int ata_eh_nr_in_flight(struct ata_port *ap)
{
 struct ata_queued_cmd *qc;
 unsigned int tag;
 unsigned int nr = 0;

 /* count only non-internal commands */
 ata_qc_for_each(ap, qc, tag) {
  if (qc)
   nr++;
 }

 return nr;
}

void ata_eh_fastdrain_timerfn(struct timer_list *t)
{
 struct ata_port *ap = timer_container_of(ap, t, fastdrain_timer);
 unsigned long flags;
 unsigned int cnt;

 spin_lock_irqsave(ap->lock, flags);

 cnt = ata_eh_nr_in_flight(ap);

 /* are we done? */
 if (!cnt)
  goto out_unlock;

 if (cnt == ap->fastdrain_cnt) {
  struct ata_queued_cmd *qc;
  unsigned int tag;

  /* No progress during the last interval, tag all
 * in-flight qcs as timed out and freeze the port.
 */

  ata_qc_for_each(ap, qc, tag) {
   if (qc)
    qc->err_mask |= AC_ERR_TIMEOUT;
  }

  ata_port_freeze(ap);
 } else {
  /* some qcs have finished, give it another chance */
  ap->fastdrain_cnt = cnt;
  ap->fastdrain_timer.expires =
   ata_deadline(jiffies, ATA_EH_FASTDRAIN_INTERVAL);
  add_timer(&ap->fastdrain_timer);
 }

 out_unlock:
 spin_unlock_irqrestore(ap->lock, flags);
}

/**
 * ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
 * @ap: target ATA port
 * @fastdrain: activate fast drain
 *
 * Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
 * is non-zero and EH wasn't pending before.  Fast drain ensures
 * that EH kicks in in timely manner.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 */

static void ata_eh_set_pending(struct ata_port *ap, bool fastdrain)
{
 unsigned int cnt;

 /* already scheduled? */
 if (ap->pflags & ATA_PFLAG_EH_PENDING)
  return;

 ap->pflags |= ATA_PFLAG_EH_PENDING;

 if (!fastdrain)
  return;

 /* do we have in-flight qcs? */
 cnt = ata_eh_nr_in_flight(ap);
 if (!cnt)
  return;

 /* activate fast drain */
 ap->fastdrain_cnt = cnt;
 ap->fastdrain_timer.expires =
  ata_deadline(jiffies, ATA_EH_FASTDRAIN_INTERVAL);
 add_timer(&ap->fastdrain_timer);
}

/**
 * ata_qc_schedule_eh - schedule qc for error handling
 * @qc: command to schedule error handling for
 *
 * Schedule error handling for @qc.  EH will kick in as soon as
 * other commands are drained.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 */

void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
{
 struct ata_port *ap = qc->ap;

 qc->flags |= ATA_QCFLAG_EH;
 ata_eh_set_pending(ap, true);

 /* The following will fail if timeout has already expired.
 * ata_scsi_error() takes care of such scmds on EH entry.
 * Note that ATA_QCFLAG_EH is unconditionally set after
 * this function completes.
 */

 blk_abort_request(scsi_cmd_to_rq(qc->scsicmd));
}

/**
 * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine
 * @ap: ATA port to schedule EH for
 *
 * LOCKING: inherited from ata_port_schedule_eh
 * spin_lock_irqsave(host lock)
 */

void ata_std_sched_eh(struct ata_port *ap)
{
 if (ap->pflags & ATA_PFLAG_INITIALIZING)
  return;

 ata_eh_set_pending(ap, true);
 scsi_schedule_eh(ap->scsi_host);

 trace_ata_std_sched_eh(ap);
}
EXPORT_SYMBOL_GPL(ata_std_sched_eh);

/**
 * ata_std_end_eh - non-libsas ata_ports complete eh with this common routine
 * @ap: ATA port to end EH for
 *
 * In the libata object model there is a 1:1 mapping of ata_port to
 * shost, so host fields can be directly manipulated under ap->lock, in
 * the libsas case we need to hold a lock at the ha->level to coordinate
 * these events.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 */

void ata_std_end_eh(struct ata_port *ap)
{
 struct Scsi_Host *host = ap->scsi_host;

 host->host_eh_scheduled = 0;
}
EXPORT_SYMBOL(ata_std_end_eh);


/**
 * ata_port_schedule_eh - schedule error handling without a qc
 * @ap: ATA port to schedule EH for
 *
 * Schedule error handling for @ap.  EH will kick in as soon as
 * all commands are drained.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 */

void ata_port_schedule_eh(struct ata_port *ap)
{
 /* see: ata_std_sched_eh, unless you know better */
 ap->ops->sched_eh(ap);
}
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);

static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
{
 struct ata_queued_cmd *qc;
 int tag, nr_aborted = 0;

 /* we're gonna abort all commands, no need for fast drain */
 ata_eh_set_pending(ap, false);

 /* include internal tag in iteration */
 ata_qc_for_each_with_internal(ap, qc, tag) {
  if (qc && (!link || qc->dev->link == link)) {
   qc->flags |= ATA_QCFLAG_EH;
   ata_qc_complete(qc);
   nr_aborted++;
  }
 }

 if (!nr_aborted)
  ata_port_schedule_eh(ap);

 return nr_aborted;
}

/**
 * ata_link_abort - abort all qc's on the link
 * @link: ATA link to abort qc's for
 *
 * Abort all active qc's active on @link and schedule EH.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 *
 * RETURNS:
 * Number of aborted qc's.
 */

int ata_link_abort(struct ata_link *link)
{
 return ata_do_link_abort(link->ap, link);
}
EXPORT_SYMBOL_GPL(ata_link_abort);

/**
 * ata_port_abort - abort all qc's on the port
 * @ap: ATA port to abort qc's for
 *
 * Abort all active qc's of @ap and schedule EH.
 *
 * LOCKING:
 * spin_lock_irqsave(host_set lock)
 *
 * RETURNS:
 * Number of aborted qc's.
 */

int ata_port_abort(struct ata_port *ap)
{
 return ata_do_link_abort(ap, NULL);
}
EXPORT_SYMBOL_GPL(ata_port_abort);

/**
 * __ata_port_freeze - freeze port
 * @ap: ATA port to freeze
 *
 * This function is called when HSM violation or some other
 * condition disrupts normal operation of the port.  Frozen port
 * is not allowed to perform any operation until the port is
 * thawed, which usually follows a successful reset.
 *
 * ap->ops->freeze() callback can be used for freezing the port
 * hardware-wise (e.g. mask interrupt and stop DMA engine).  If a
 * port cannot be frozen hardware-wise, the interrupt handler
 * must ack and clear interrupts unconditionally while the port
 * is frozen.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 */

static void __ata_port_freeze(struct ata_port *ap)
{
 if (ap->ops->freeze)
  ap->ops->freeze(ap);

 ap->pflags |= ATA_PFLAG_FROZEN;

 trace_ata_port_freeze(ap);
}

/**
 * ata_port_freeze - abort & freeze port
 * @ap: ATA port to freeze
 *
 * Abort and freeze @ap.  The freeze operation must be called
 * first, because some hardware requires special operations
 * before the taskfile registers are accessible.
 *
 * LOCKING:
 * spin_lock_irqsave(host lock)
 *
 * RETURNS:
 * Number of aborted commands.
 */

int ata_port_freeze(struct ata_port *ap)
{
 __ata_port_freeze(ap);

 return ata_port_abort(ap);
}
EXPORT_SYMBOL_GPL(ata_port_freeze);

/**
 * ata_eh_freeze_port - EH helper to freeze port
 * @ap: ATA port to freeze
 *
 * Freeze @ap.
 *
 * LOCKING:
 * None.
 */

void ata_eh_freeze_port(struct ata_port *ap)
{
 unsigned long flags;

 spin_lock_irqsave(ap->lock, flags);
 __ata_port_freeze(ap);
 spin_unlock_irqrestore(ap->lock, flags);
}
EXPORT_SYMBOL_GPL(ata_eh_freeze_port);

/**
 * ata_eh_thaw_port - EH helper to thaw port
 * @ap: ATA port to thaw
 *
 * Thaw frozen port @ap.
 *
 * LOCKING:
 * None.
 */

void ata_eh_thaw_port(struct ata_port *ap)
{
 unsigned long flags;

 spin_lock_irqsave(ap->lock, flags);

 ap->pflags &= ~ATA_PFLAG_FROZEN;

 if (ap->ops->thaw)
  ap->ops->thaw(ap);

 spin_unlock_irqrestore(ap->lock, flags);

 trace_ata_port_thaw(ap);
}

static void ata_eh_scsidone(struct scsi_cmnd *scmd)
{
 /* nada */
}

static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
{
 struct ata_port *ap = qc->ap;
 struct scsi_cmnd *scmd = qc->scsicmd;
 unsigned long flags;

 spin_lock_irqsave(ap->lock, flags);
 qc->scsidone = ata_eh_scsidone;
 __ata_qc_complete(qc);
 WARN_ON(ata_tag_valid(qc->tag));
 spin_unlock_irqrestore(ap->lock, flags);

 scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
}

/**
 * ata_eh_qc_complete - Complete an active ATA command from EH
 * @qc: Command to complete
 *
 * Indicate to the mid and upper layers that an ATA command has
 * completed.  To be used from EH.
 */

void ata_eh_qc_complete(struct ata_queued_cmd *qc)
{
 struct scsi_cmnd *scmd = qc->scsicmd;
 scmd->retries = scmd->allowed;
 __ata_eh_qc_complete(qc);
}

/**
 * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
 * @qc: Command to retry
 *
 * Indicate to the mid and upper layers that an ATA command
 * should be retried.  To be used from EH.
 *
 * SCSI midlayer limits the number of retries to scmd->allowed.
 * scmd->allowed is incremented for commands which get retried
 * due to unrelated failures (qc->err_mask is zero).
 */

void ata_eh_qc_retry(struct ata_queued_cmd *qc)
{
 struct scsi_cmnd *scmd = qc->scsicmd;
 if (!qc->err_mask)
  scmd->allowed++;
 __ata_eh_qc_complete(qc);
}

/**
 * ata_dev_disable - disable ATA device
 * @dev: ATA device to disable
 *
 * Disable @dev.
 *
 * Locking:
 * EH context.
 */

void ata_dev_disable(struct ata_device *dev)
{
 if (!ata_dev_enabled(dev))
  return;

 ata_dev_warn(dev, "disable device\n");

 ata_eh_dev_disable(dev);
}
EXPORT_SYMBOL_GPL(ata_dev_disable);

/**
 * ata_eh_detach_dev - detach ATA device
 * @dev: ATA device to detach
 *
 * Detach @dev.
 *
 * LOCKING:
 * None.
 */

void ata_eh_detach_dev(struct ata_device *dev)
{
 struct ata_link *link = dev->link;
 struct ata_port *ap = link->ap;
 struct ata_eh_context *ehc = &link->eh_context;
 unsigned long flags;

 /*
 * If the device is still enabled, transition it to standby power mode
 * (i.e. spin down HDDs) and disable it.
 */

 if (ata_dev_enabled(dev)) {
  ata_dev_power_set_standby(dev);
  ata_eh_dev_disable(dev);
 }

 spin_lock_irqsave(ap->lock, flags);

 dev->flags &= ~ATA_DFLAG_DETACH;

 if (ata_scsi_offline_dev(dev)) {
  dev->flags |= ATA_DFLAG_DETACHED;
  ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
 }

 /* clear per-dev EH info */
 ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK);
 ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK);
 ehc->saved_xfer_mode[dev->devno] = 0;
 ehc->saved_ncq_enabled &= ~(1 << dev->devno);

 spin_unlock_irqrestore(ap->lock, flags);
}

/**
 * ata_eh_about_to_do - about to perform eh_action
 * @link: target ATA link
 * @dev: target ATA dev for per-dev action (can be NULL)
 * @action: action about to be performed
 *
 * Called just before performing EH actions to clear related bits
 * in @link->eh_info such that eh actions are not unnecessarily
 * repeated.
 *
 * LOCKING:
 * None.
 */

void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
   unsigned int action)
{
 struct ata_port *ap = link->ap;
 struct ata_eh_info *ehi = &link->eh_info;
 struct ata_eh_context *ehc = &link->eh_context;
 unsigned long flags;

 trace_ata_eh_about_to_do(link, dev ? dev->devno : 0, action);

 spin_lock_irqsave(ap->lock, flags);

 ata_eh_clear_action(link, dev, ehi, action);

 /* About to take EH action, set RECOVERED.  Ignore actions on
 * slave links as master will do them again.
 */

 if (!(ehc->i.flags & ATA_EHI_QUIET) && link != ap->slave_link)
  ap->pflags |= ATA_PFLAG_RECOVERED;

 spin_unlock_irqrestore(ap->lock, flags);
}

/**
 * ata_eh_done - EH action complete
 * @link: ATA link for which EH actions are complete
 * @dev: target ATA dev for per-dev action (can be NULL)
 * @action: action just completed
 *
 * Called right after performing EH actions to clear related bits
 * in @link->eh_context.
 *
 * LOCKING:
 * None.
 */

void ata_eh_done(struct ata_link *link, struct ata_device *dev,
   unsigned int action)
{
 struct ata_eh_context *ehc = &link->eh_context;

 trace_ata_eh_done(link, dev ? dev->devno : 0, action);

 ata_eh_clear_action(link, dev, &ehc->i, action);
}

/**
 * ata_err_string - convert err_mask to descriptive string
 * @err_mask: error mask to convert to string
 *
 * Convert @err_mask to descriptive string.  Errors are
 * prioritized according to severity and only the most severe
 * error is reported.
 *
 * LOCKING:
 * None.
 *
 * RETURNS:
 * Descriptive string for @err_mask
 */

static const char *ata_err_string(unsigned int err_mask)
{
 if (err_mask & AC_ERR_HOST_BUS)
  return "host bus error";
 if (err_mask & AC_ERR_ATA_BUS)
  return "ATA bus error";
 if (err_mask & AC_ERR_TIMEOUT)
  return "timeout";
 if (err_mask & AC_ERR_HSM)
  return "HSM violation";
 if (err_mask & AC_ERR_SYSTEM)
  return "internal error";
 if (err_mask & AC_ERR_MEDIA)
  return "media error";
 if (err_mask & AC_ERR_INVALID)
  return "invalid argument";
 if (err_mask & AC_ERR_DEV)
  return "device error";
 if (err_mask & AC_ERR_NCQ)
  return "NCQ error";
 if (err_mask & AC_ERR_NODEV_HINT)
  return "Polling detection error";
 return "unknown error";
}

/**
 * atapi_eh_tur - perform ATAPI TEST_UNIT_READY
 * @dev: target ATAPI device
 * @r_sense_key: out parameter for sense_key
 *
 * Perform ATAPI TEST_UNIT_READY.
 *
 * LOCKING:
 * EH context (may sleep).
 *
 * RETURNS:
 * 0 on success, AC_ERR_* mask on failure.
 */

unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
{
 u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
 struct ata_taskfile tf;
 unsigned int err_mask;

 ata_tf_init(dev, &tf);

 tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 tf.command = ATA_CMD_PACKET;
 tf.protocol = ATAPI_PROT_NODATA;

 err_mask = ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
 if (err_mask == AC_ERR_DEV)
  *r_sense_key = tf.error >> 4;
 return err_mask;
}

/**
 * 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
 *
 * Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
 * SENSE.  This function is an EH helper.
 *
 * LOCKING:
 * Kernel thread context (may sleep).
 *
 * RETURNS:
 * true if sense data could be fetched, false otherwise.
 */

static bool ata_eh_request_sense(struct ata_queued_cmd *qc)
{
 struct scsi_cmnd *cmd = qc->scsicmd;
 struct ata_device *dev = qc->dev;
 struct ata_taskfile tf;
 unsigned int err_mask;

 if (ata_port_is_frozen(qc->ap)) {
  ata_dev_warn(dev, "sense data available but port frozen\n");
  return false;
 }

 if (!ata_id_sense_reporting_enabled(dev->id)) {
  ata_dev_warn(qc->dev, "sense data reporting disabled\n");
  return false;
 }

 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.status & ATA_SENSE) {
  if (ata_scsi_sense_is_valid(tf.lbah, tf.lbam, tf.lbal)) {
   /* Set sense without also setting scsicmd->result */
   scsi_build_sense_buffer(dev->flags & ATA_DFLAG_D_SENSE,
      cmd->sense_buffer, tf.lbah,
      tf.lbam, tf.lbal);
   qc->flags |= ATA_QCFLAG_SENSE_VALID;
   return true;
  }
 } else {
  ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
        tf.status, err_mask);
 }

 return false;
}

/**
 * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
 * @dev: device to perform REQUEST_SENSE to
 * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
 * @dfl_sense_key: default sense key to use
 *
 * Perform ATAPI REQUEST_SENSE after the device reported CHECK
 * SENSE.  This function is EH helper.
 *
 * LOCKING:
 * Kernel thread context (may sleep).
 *
 * RETURNS:
 * 0 on success, AC_ERR_* mask on failure
 */

unsigned int atapi_eh_request_sense(struct ata_device *dev,
        u8 *sense_buf, u8 dfl_sense_key)
{
 u8 cdb[ATAPI_CDB_LEN] =
  { REQUEST_SENSE, 0, 0, 0, SCSI_SENSE_BUFFERSIZE, 0 };
 struct ata_port *ap = dev->link->ap;
 struct ata_taskfile tf;

 memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);

 /* initialize sense_buf with the error register,
 * for the case where they are -not- overwritten
 */

 sense_buf[0] = 0x70;
 sense_buf[2] = dfl_sense_key;

 /* some devices time out if garbage left in tf */
 ata_tf_init(dev, &tf);

 tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 tf.command = ATA_CMD_PACKET;

 /*
 * Do not use DMA if the connected device only supports PIO, even if the
 * port prefers PIO commands via DMA.
 *
 * Ideally, we should call atapi_check_dma() to check if it is safe for
 * the LLD to use DMA for REQUEST_SENSE, but we don't have a qc.
 * Since we can't check the command, perhaps we should only use pio?
 */

 if ((ap->flags & ATA_FLAG_PIO_DMA) && !(dev->flags & ATA_DFLAG_PIO)) {
  tf.protocol = ATAPI_PROT_DMA;
  tf.feature |= ATAPI_PKT_DMA;
 } else {
  tf.protocol = ATAPI_PROT_PIO;
  tf.lbam = SCSI_SENSE_BUFFERSIZE;
  tf.lbah = 0;
 }

 return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
     sense_buf, SCSI_SENSE_BUFFERSIZE, 0);
}

/**
 * ata_eh_analyze_serror - analyze SError for a failed port
 * @link: ATA link to analyze SError for
 *
 * Analyze SError if available and further determine cause of
 * failure.
 *
 * LOCKING:
 * None.
 */

static void ata_eh_analyze_serror(struct ata_link *link)
{
 struct ata_eh_context *ehc = &link->eh_context;
 u32 serror = ehc->i.serror;
 unsigned int err_mask = 0, action = 0;
 u32 hotplug_mask;

 if (serror & (SERR_PERSISTENT | SERR_DATA)) {
  err_mask |= AC_ERR_ATA_BUS;
  action |= ATA_EH_RESET;
 }
 if (serror & SERR_PROTOCOL) {
  err_mask |= AC_ERR_HSM;
  action |= ATA_EH_RESET;
 }
 if (serror & SERR_INTERNAL) {
  err_mask |= AC_ERR_SYSTEM;
  action |= ATA_EH_RESET;
 }

 /* Determine whether a hotplug event has occurred.  Both
 * SError.N/X are considered hotplug events for enabled or
 * host links.  For disabled PMP links, only N bit is
 * considered as X bit is left at 1 for link plugging.
 */

 if (link->lpm_policy > ATA_LPM_MAX_POWER)
  hotplug_mask = 0; /* hotplug doesn't work w/ LPM */
 else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
  hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
 else
  hotplug_mask = SERR_PHYRDY_CHG;

 if (serror & hotplug_mask)
  ata_ehi_hotplugged(&ehc->i);

 ehc->i.err_mask |= err_mask;
 ehc->i.action |= action;
}

/**
 * ata_eh_analyze_tf - analyze taskfile of a failed qc
 * @qc: qc to analyze
 *
 * Analyze taskfile of @qc and further determine cause of
 * failure.  This function also requests ATAPI sense data if
 * available.
 *
 * LOCKING:
 * Kernel thread context (may sleep).
 *
 * RETURNS:
 * Determined recovery action
 */

static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc)
{
 const struct ata_taskfile *tf = &qc->result_tf;
 unsigned int tmp, action = 0;
 u8 stat = tf->status, err = tf->error;

 if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) {
  qc->err_mask |= AC_ERR_HSM;
  return ATA_EH_RESET;
 }

 if (stat & (ATA_ERR | ATA_DF)) {
  qc->err_mask |= AC_ERR_DEV;
  /*
 * Sense data reporting does not work if the
 * device fault bit is set.
 */

  if (stat & ATA_DF)
   stat &= ~ATA_SENSE;
 } else {
  return 0;
 }

 switch (qc->dev->class) {
 case ATA_DEV_ATA:
 case ATA_DEV_ZAC:
  /*
 * Fetch the sense data explicitly if:
 * -It was a non-NCQ command that failed, or
 * -It was a NCQ command that failed, but the sense data
 *  was not included in the NCQ command error log
 *  (i.e. NCQ autosense is not supported by the device).
 */

  if (!(qc->flags & ATA_QCFLAG_SENSE_VALID) &&
      (stat & ATA_SENSE) && ata_eh_request_sense(qc))
   set_status_byte(qc->scsicmd, SAM_STAT_CHECK_CONDITION);
  if (err & ATA_ICRC)
   qc->err_mask |= AC_ERR_ATA_BUS;
  if (err & (ATA_UNC | ATA_AMNF))
   qc->err_mask |= AC_ERR_MEDIA;
  if (err & ATA_IDNF)
   qc->err_mask |= AC_ERR_INVALID;
  break;

 case ATA_DEV_ATAPI:
  if (!ata_port_is_frozen(qc->ap)) {
   tmp = atapi_eh_request_sense(qc->dev,
      qc->scsicmd->sense_buffer,
      qc->result_tf.error >> 4);
   if (!tmp)
    qc->flags |= ATA_QCFLAG_SENSE_VALID;
   else
    qc->err_mask |= tmp;
  }
 }

 if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
  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
 * for correct evaluation.
 * FAILED means the sense code could not be 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))
  action |= ATA_EH_RESET;

 return action;
}

static int ata_eh_categorize_error(unsigned int eflags, unsigned int err_mask,
       int *xfer_ok)
{
 int base = 0;

 if (!(eflags & ATA_EFLAG_DUBIOUS_XFER))
  *xfer_ok = 1;

 if (!*xfer_ok)
  base = ATA_ECAT_DUBIOUS_NONE;

 if (err_mask & AC_ERR_ATA_BUS)
  return base + ATA_ECAT_ATA_BUS;

 if (err_mask & AC_ERR_TIMEOUT)
  return base + ATA_ECAT_TOUT_HSM;

 if (eflags & ATA_EFLAG_IS_IO) {
  if (err_mask & AC_ERR_HSM)
   return base + ATA_ECAT_TOUT_HSM;
  if ((err_mask &
       (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
   return base + ATA_ECAT_UNK_DEV;
 }

 return 0;
}

struct speed_down_verdict_arg {
 u64 since;
 int xfer_ok;
 int nr_errors[ATA_ECAT_NR];
};

static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
{
 struct speed_down_verdict_arg *arg = void_arg;
 int cat;

 if ((ent->eflags & ATA_EFLAG_OLD_ER) || (ent->timestamp < arg->since))
  return -1;

 cat = ata_eh_categorize_error(ent->eflags, ent->err_mask,
          &arg->xfer_ok);
 arg->nr_errors[cat]++;

 return 0;
}

/**
 * ata_eh_speed_down_verdict - Determine speed down verdict
 * @dev: Device of interest
 *
 * This function examines error ring of @dev and determines
 * whether NCQ needs to be turned off, transfer speed should be
 * stepped down, or falling back to PIO is necessary.
 *
 * ECAT_ATA_BUS : ATA_BUS error for any command
 *
 * ECAT_TOUT_HSM : TIMEOUT for any command or HSM violation for
 *   IO commands
 *
 * ECAT_UNK_DEV : Unknown DEV error for IO commands
 *
 * ECAT_DUBIOUS_* : Identical to above three but occurred while
 *   data transfer hasn't been verified.
 *
 * Verdicts are
 *
 * NCQ_OFF : Turn off NCQ.
 *
 * SPEED_DOWN : Speed down transfer speed but don't fall back
 *   to PIO.
 *
 * FALLBACK_TO_PIO : Fall back to PIO.
 *
 * Even if multiple verdicts are returned, only one action is
 * taken per error.  An action triggered by non-DUBIOUS errors
 * clears ering, while one triggered by DUBIOUS_* errors doesn't.
 * This is to expedite speed down decisions right after device is
 * initially configured.
 *
 * The following are speed down rules.  #1 and #2 deal with
 * DUBIOUS errors.
 *
 * 1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors
 *    occurred during last 5 mins, SPEED_DOWN and FALLBACK_TO_PIO.
 *
 * 2. If more than one DUBIOUS_TOUT_HSM or DUBIOUS_UNK_DEV errors
 *    occurred during last 5 mins, NCQ_OFF.
 *
 * 3. If more than 8 ATA_BUS, TOUT_HSM or UNK_DEV errors
 *    occurred during last 5 mins, FALLBACK_TO_PIO
 *
 * 4. If more than 3 TOUT_HSM or UNK_DEV errors occurred
 *    during last 10 mins, NCQ_OFF.
 *
 * 5. If more than 3 ATA_BUS or TOUT_HSM errors, or more than 6
 *    UNK_DEV errors occurred during last 10 mins, SPEED_DOWN.
 *
 * LOCKING:
 * Inherited from caller.
 *
 * RETURNS:
 * OR of ATA_EH_SPDN_* flags.
 */

static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
{
 const u64 j5mins = 5LLU * 60 * HZ, j10mins = 10LLU * 60 * HZ;
 u64 j64 = get_jiffies_64();
 struct speed_down_verdict_arg arg;
 unsigned int verdict = 0;

 /* scan past 5 mins of error history */
 memset(&arg, 0, sizeof(arg));
 arg.since = j64 - min(j64, j5mins);
 ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg);

 if (arg.nr_errors[ATA_ECAT_DUBIOUS_ATA_BUS] +
     arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] > 1)
  verdict |= ATA_EH_SPDN_SPEED_DOWN |
   ATA_EH_SPDN_FALLBACK_TO_PIO | ATA_EH_SPDN_KEEP_ERRORS;

 if (arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] +
     arg.nr_errors[ATA_ECAT_DUBIOUS_UNK_DEV] > 1)
  verdict |= ATA_EH_SPDN_NCQ_OFF | ATA_EH_SPDN_KEEP_ERRORS;

 if (arg.nr_errors[ATA_ECAT_ATA_BUS] +
     arg.nr_errors[ATA_ECAT_TOUT_HSM] +
     arg.nr_errors[ATA_ECAT_UNK_DEV] > 6)
  verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO;

 /* scan past 10 mins of error history */
 memset(&arg, 0, sizeof(arg));
 arg.since = j64 - min(j64, j10mins);
 ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg);

 if (arg.nr_errors[ATA_ECAT_TOUT_HSM] +
     arg.nr_errors[ATA_ECAT_UNK_DEV] > 3)
  verdict |= ATA_EH_SPDN_NCQ_OFF;

 if (arg.nr_errors[ATA_ECAT_ATA_BUS] +
     arg.nr_errors[ATA_ECAT_TOUT_HSM] > 3 ||
     arg.nr_errors[ATA_ECAT_UNK_DEV] > 6)
  verdict |= ATA_EH_SPDN_SPEED_DOWN;

 return verdict;
}

/**
 * ata_eh_speed_down - record error and speed down if necessary
 * @dev: Failed device
 * @eflags: mask of ATA_EFLAG_* flags
 * @err_mask: err_mask of the error
 *
 * Record error and examine error history to determine whether
 * adjusting transmission speed is necessary.  It also sets
 * transmission limits appropriately if such adjustment is
 * necessary.
 *
 * LOCKING:
 * Kernel thread context (may sleep).
 *
 * RETURNS:
 * Determined recovery action.
 */

static unsigned int ata_eh_speed_down(struct ata_device *dev,
    unsigned int eflags, unsigned int err_mask)
{
 struct ata_link *link = ata_dev_phys_link(dev);
 int xfer_ok = 0;
 unsigned int verdict;
 unsigned int action = 0;

 /* don't bother if Cat-0 error */
 if (ata_eh_categorize_error(eflags, err_mask, &xfer_ok) == 0)
  return 0;

 /* record error and determine whether speed down is necessary */
 ata_ering_record(&dev->ering, eflags, err_mask);
 verdict = ata_eh_speed_down_verdict(dev);

 /* turn off NCQ? */
 if ((verdict & ATA_EH_SPDN_NCQ_OFF) && ata_ncq_enabled(dev)) {
  dev->flags |= ATA_DFLAG_NCQ_OFF;
  ata_dev_warn(dev, "NCQ disabled due to excessive errors\n");
  goto done;
 }

 /* speed down? */
 if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
  /* speed down SATA link speed if possible */
  if (sata_down_spd_limit(link, 0) == 0) {
   action |= ATA_EH_RESET;
   goto done;
  }

  /* lower transfer mode */
  if (dev->spdn_cnt < 2) {
   static const int dma_dnxfer_sel[] =
    { ATA_DNXFER_DMA, ATA_DNXFER_40C };
   static const int pio_dnxfer_sel[] =
    { ATA_DNXFER_PIO, ATA_DNXFER_FORCE_PIO0 };
   int sel;

   if (dev->xfer_shift != ATA_SHIFT_PIO)
    sel = dma_dnxfer_sel[dev->spdn_cnt];
   else
    sel = pio_dnxfer_sel[dev->spdn_cnt];

   dev->spdn_cnt++;

   if (ata_down_xfermask_limit(dev, sel) == 0) {
    action |= ATA_EH_RESET;
    goto done;
   }
  }
 }

 /* Fall back to PIO?  Slowing down to PIO is meaningless for
 * SATA ATA devices.  Consider it only for PATA and SATAPI.
 */

 if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) &&
     (link->ap->cbl != ATA_CBL_SATA || dev->class == ATA_DEV_ATAPI) &&
     (dev->xfer_shift != ATA_SHIFT_PIO)) {
  if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) {
   dev->spdn_cnt = 0;
   action |= ATA_EH_RESET;
   goto done;
  }
 }

 return 0;
 done:
 /* device has been slowed down, blow error history */
 if (!(verdict & ATA_EH_SPDN_KEEP_ERRORS))
  ata_ering_clear(&dev->ering);
 return action;
}

/**
 * ata_eh_worth_retry - analyze error and decide whether to retry
 * @qc: qc to possibly retry
 *
 * Look at the cause of the error and decide if a retry
 *  might be useful or not.  We don't want to retry media errors
 * because the drive itself has probably already taken 10-30 seconds
 * doing its own internal retries before reporting the failure.
 */

static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc)
{
 if (qc->err_mask & AC_ERR_MEDIA)
  return 0; /* don't retry media errors */
 if (qc->flags & ATA_QCFLAG_IO)
  return 1; /* otherwise retry anything from fs stack */
 if (qc->err_mask & AC_ERR_INVALID)
  return 0; /* don't retry these */
 return qc->err_mask != AC_ERR_DEV;  /* retry if not dev error */
}

/**
 *      ata_eh_quiet - check if we need to be quiet about a command error
 *      @qc: qc to check
 *
 *      Look at the qc flags anbd its scsi command request flags to determine
 *      if we need to be quiet about the command failure.
 */

static inline bool ata_eh_quiet(struct ata_queued_cmd *qc)
{
 if (qc->scsicmd && scsi_cmd_to_rq(qc->scsicmd)->rq_flags & RQF_QUIET)
  qc->flags |= ATA_QCFLAG_QUIET;
 return qc->flags & ATA_QCFLAG_QUIET;
}

static int ata_eh_get_non_ncq_success_sense(struct ata_link *link)
{
 struct ata_port *ap = link->ap;
 struct ata_queued_cmd *qc;

 qc = __ata_qc_from_tag(ap, link->active_tag);
 if (!qc)
  return -EIO;

 if (!(qc->flags & ATA_QCFLAG_EH) ||
     !(qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) ||
     qc->err_mask)
  return -EIO;

 if (!ata_eh_request_sense(qc))
  return -EIO;

 /*
 * No point in checking the return value, since the command has already
 * completed successfully.
 */

 ata_eh_decide_disposition(qc);

 return 0;
}

static void ata_eh_get_success_sense(struct ata_link *link)
{
 struct ata_eh_context *ehc = &link->eh_context;
 struct ata_device *dev = link->device;
 struct ata_port *ap = link->ap;
 struct ata_queued_cmd *qc;
 int tag, ret = 0;

 if (!(ehc->i.dev_action[dev->devno] & ATA_EH_GET_SUCCESS_SENSE))
  return;

 /* if frozen, we can't do much */
 if (ata_port_is_frozen(ap)) {
  ata_dev_warn(dev,
   "successful sense data available but port frozen\n");
  goto out;
 }

 /*
 * If the link has sactive set, then we have outstanding NCQ commands
 * and have to read the Successful NCQ Commands log to get the sense
 * data. Otherwise, we are dealing with a non-NCQ command and use
 * request sense ext command to retrieve the sense data.
 */

 if (link->sactive)
  ret = ata_eh_get_ncq_success_sense(link);
 else
  ret = ata_eh_get_non_ncq_success_sense(link);
 if (ret)
  goto out;

 ata_eh_done(link, dev, ATA_EH_GET_SUCCESS_SENSE);
 return;

out:
 /*
 * If we failed to get sense data for a successful command that ought to
 * have sense data, we cannot simply return BLK_STS_OK to user space.
 * This is because we can't know if the sense data that we couldn't get
 * was actually "DATA CURRENTLY UNAVAILABLE". Reporting such a command
 * as success to user space would result in a silent data corruption.
 * Thus, add a bogus ABORTED_COMMAND sense data to such commands, such
 * that SCSI will report these commands as BLK_STS_IOERR to user space.
 */

 ata_qc_for_each_raw(ap, qc, tag) {
  if (!(qc->flags & ATA_QCFLAG_EH) ||
      !(qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) ||
      qc->err_mask ||
      ata_dev_phys_link(qc->dev) != link)
   continue;

  /* We managed to get sense for this success command, skip. */
  if (qc->flags & ATA_QCFLAG_SENSE_VALID)
   continue;

  /* This success command did not have any sense data, skip. */
  if (!(qc->result_tf.status & ATA_SENSE))
   continue;

  /* This success command had sense data, but we failed to get. */
  ata_scsi_set_sense(dev, qc->scsicmd, ABORTED_COMMAND, 0, 0);
  qc->flags |= ATA_QCFLAG_SENSE_VALID;
 }
 ata_eh_done(link, dev, ATA_EH_GET_SUCCESS_SENSE);
}

/*
 * Check if a link is established. This is a relaxed version of
 * ata_phys_link_online() which accounts for the fact that this is potentially
 * called after changing the link power management policy, which may not be
 * reflected immediately in the SStatus register (e.g., we may still be seeing
 * the PHY in partial, slumber or devsleep Partial power management state.
 * So check that:
 * - A device is still present, that is, DET is 1h (Device presence detected
 *   but Phy communication not established) or 3h (Device presence detected and
 *   Phy communication established)
 * - Communication is established, that is, IPM is not 0h, indicating that PHY
 *   is online or in a low power state.
 */

static bool ata_eh_link_established(struct ata_link *link)
{
 u32 sstatus;
 u8 det, ipm;

 /*
 * For old IDE/PATA adapters that do not have a valid scr_read method,
 * or if reading the SStatus register fails, assume that the device is
 * present. Device probe will determine if that is really the case.
 */

 if (sata_scr_read(link, SCR_STATUS, &sstatus))
  return true;

 det = sstatus & 0x0f;
 ipm = (sstatus >> 8) & 0x0f;

 return (det & 0x01) && ipm;
}

/**
 * ata_eh_link_set_lpm - configure SATA interface power management
 * @link: link to configure
 * @policy: the link power management policy
 * @r_failed_dev: out parameter for failed device
 *
 * Enable SATA Interface power management.  This will enable
 * Device Interface Power Management (DIPM) for min_power and
 * medium_power_with_dipm policies, and then call driver specific
 * callbacks for enabling Host Initiated Power management.
 *
 * LOCKING:
 * EH context.
 *
 * RETURNS:
 * 0 on success, -errno on failure.
 */

static int ata_eh_link_set_lpm(struct ata_link *link,
          enum ata_lpm_policy policy,
          struct ata_device **r_failed_dev)
{
 struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL;
 struct ata_eh_context *ehc = &link->eh_context;
 struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
 enum ata_lpm_policy old_policy = link->lpm_policy;
 bool host_has_dipm = !(link->ap->flags & ATA_FLAG_NO_DIPM);
 unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
 unsigned int err_mask;
 int rc;

 /* if the link or host doesn't do LPM, noop */
 if (!IS_ENABLED(CONFIG_SATA_HOST) ||
     (link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm))
  return 0;

 /*
 * This function currently assumes that it will never be supplied policy
 * ATA_LPM_UNKNOWN.
 */

 if (WARN_ON_ONCE(policy == ATA_LPM_UNKNOWN))
  return 0;

 ata_link_dbg(link, "Set LPM policy: %d -> %d\n", old_policy, policy);

 /*
 * DIPM is enabled only for ATA_LPM_MIN_POWER,
 * ATA_LPM_MIN_POWER_WITH_PARTIAL, and ATA_LPM_MED_POWER_WITH_DIPM, as
 * some devices misbehave when the host NACKs transition to SLUMBER.
 */

 ata_for_each_dev(dev, link, ENABLED) {
  bool dev_has_hipm = ata_id_has_hipm(dev->id);
  bool dev_has_dipm = ata_id_has_dipm(dev->id);

  /* find the first enabled and LPM enabled devices */
  if (!link_dev)
   link_dev = dev;

  if (!lpm_dev &&
      (dev_has_hipm || (dev_has_dipm && host_has_dipm)))
   lpm_dev = dev;

  hints &= ~ATA_LPM_EMPTY;
  if (!dev_has_hipm)
   hints &= ~ATA_LPM_HIPM;

  /* disable DIPM before changing link config */
  if (dev_has_dipm) {
   err_mask = ata_dev_set_feature(dev,
     SETFEATURES_SATA_DISABLE, SATA_DIPM);
   if (err_mask && err_mask != AC_ERR_DEV) {
    ata_dev_warn(dev,
          "failed to disable DIPM, Emask 0x%x\n",
          err_mask);
    rc = -EIO;
    goto fail;
   }
  }
 }

 if (ap) {
  rc = ap->ops->set_lpm(link, policy, hints);
  if (!rc && ap->slave_link)
   rc = ap->ops->set_lpm(ap->slave_link, policy, hints);
 } else
  rc = sata_pmp_set_lpm(link, policy, hints);

 /*
 * Attribute link config failure to the first (LPM) enabled
 * device on the link.
 */

 if (rc) {
  if (rc == -EOPNOTSUPP) {
   link->flags |= ATA_LFLAG_NO_LPM;
   return 0;
  }
  dev = lpm_dev ? lpm_dev : link_dev;
  goto fail;
 }

 /*
 * Low level driver acked the transition.  Issue DIPM command
 * with the new policy set.
 */

 link->lpm_policy = policy;
 if (ap && ap->slave_link)
  ap->slave_link->lpm_policy = policy;

 /*
 * Host config updated, enable DIPM if transitioning to
 * ATA_LPM_MIN_POWER, ATA_LPM_MIN_POWER_WITH_PARTIAL, or
 * ATA_LPM_MED_POWER_WITH_DIPM.
 */

 ata_for_each_dev(dev, link, ENABLED) {
  bool dev_has_dipm = ata_id_has_dipm(dev->id);

  if (policy >= ATA_LPM_MED_POWER_WITH_DIPM && host_has_dipm &&
      dev_has_dipm) {
   err_mask = ata_dev_set_feature(dev,
     SETFEATURES_SATA_ENABLE, SATA_DIPM);
   if (err_mask && err_mask != AC_ERR_DEV) {
    ata_dev_warn(dev,
     "failed to enable DIPM, Emask 0x%x\n",
     err_mask);
    rc = -EIO;
    goto fail;
   }
  }
 }

 link->last_lpm_change = jiffies;
 link->flags |= ATA_LFLAG_CHANGED;

 return 0;

fail:
 /* restore the old policy */
 link->lpm_policy = old_policy;
 if (ap && ap->slave_link)
  ap->slave_link->lpm_policy = old_policy;

 /* if no device or only one more chance is left, disable LPM */
 if (!dev || ehc->tries[dev->devno] <= 2) {
  ata_link_warn(link, "disabling LPM on the link\n");
  link->flags |= ATA_LFLAG_NO_LPM;
 }
 if (r_failed_dev)
  *r_failed_dev = dev;
 return rc;
}

/**
 * ata_eh_link_autopsy - analyze error and determine recovery action
 * @link: host link to perform autopsy on
 *
 * Analyze why @link failed and determine which recovery actions
 * are needed.  This function also sets more detailed AC_ERR_*
 * values and fills sense data for ATAPI CHECK SENSE.
 *
 * LOCKING:
 * Kernel thread context (may sleep).
 */

static void ata_eh_link_autopsy(struct ata_link *link)
{
 struct ata_port *ap = link->ap;
 struct ata_eh_context *ehc = &link->eh_context;
 struct ata_queued_cmd *qc;
 struct ata_device *dev;
 unsigned int all_err_mask = 0, eflags = 0;
 int tag, nr_failed = 0, nr_quiet = 0;
 u32 serror;
 int rc;

 if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
  return;

 /* obtain and analyze SError */
 rc = sata_scr_read(link, SCR_ERROR, &serror);
 if (rc == 0) {
  ehc->i.serror |= serror;
  ata_eh_analyze_serror(link);
 } else if (rc != -EOPNOTSUPP) {
  /* SError read failed, force reset and probing */
  ehc->i.probe_mask |= ATA_ALL_DEVICES;
  ehc->i.action |= ATA_EH_RESET;
  ehc->i.err_mask |= AC_ERR_OTHER;
 }

 /* analyze NCQ failure */
 ata_eh_analyze_ncq_error(link);

 /*
 * Check if this was a successful command that simply needs sense data.
 * Since the sense data is not part of the completion, we need to fetch
 * it using an additional command. Since this can't be done from irq
 * context, the sense data for successful commands are fetched by EH.
 */

 ata_eh_get_success_sense(link);

 /* any real error trumps AC_ERR_OTHER */
 if (ehc->i.err_mask & ~AC_ERR_OTHER)
  ehc->i.err_mask &= ~AC_ERR_OTHER;

 all_err_mask |= ehc->i.err_mask;

 ata_qc_for_each_raw(ap, qc, tag) {
  if (!(qc->flags & ATA_QCFLAG_EH) ||
      qc->flags & ATA_QCFLAG_RETRY ||
      qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD ||
      ata_dev_phys_link(qc->dev) != link)
   continue;

  /* inherit upper level err_mask */
  qc->err_mask |= ehc->i.err_mask;

  /* analyze TF */
  ehc->i.action |= ata_eh_analyze_tf(qc);

  /* DEV errors are probably spurious in case of ATA_BUS error */
  if (qc->err_mask & AC_ERR_ATA_BUS)
   qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA |
       AC_ERR_INVALID);

  /* any real error trumps unknown error */
  if (qc->err_mask & ~AC_ERR_OTHER)
   qc->err_mask &= ~AC_ERR_OTHER;

  /*
 * SENSE_VALID trumps dev/unknown error and revalidation. Upper
 * layers will determine whether the command is worth retrying
 * based on the sense data and device class/type. Otherwise,
 * determine directly if the command is worth retrying using its
 * error mask and flags.
 */

  if (qc->flags & ATA_QCFLAG_SENSE_VALID)
   qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
  else if (ata_eh_worth_retry(qc))
   qc->flags |= ATA_QCFLAG_RETRY;

  /* accumulate error info */
  ehc->i.dev = qc->dev;
  all_err_mask |= qc->err_mask;
  if (qc->flags & ATA_QCFLAG_IO)
   eflags |= ATA_EFLAG_IS_IO;
  trace_ata_eh_link_autopsy_qc(qc);

  /* Count quiet errors */
  if (ata_eh_quiet(qc))
   nr_quiet++;
  nr_failed++;
 }

 /* If all failed commands requested silence, then be quiet */
 if (nr_quiet == nr_failed)
  ehc->i.flags |= ATA_EHI_QUIET;

 /* enforce default EH actions */
 if (ata_port_is_frozen(ap) ||
     all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
  ehc->i.action |= ATA_EH_RESET;
 else if (((eflags & ATA_EFLAG_IS_IO) && all_err_mask) ||
   (!(eflags & ATA_EFLAG_IS_IO) && (all_err_mask & ~AC_ERR_DEV)))
  ehc->i.action |= ATA_EH_REVALIDATE;

 /* If we have offending qcs and the associated failed device,
 * perform per-dev EH action only on the offending device.
 */

 if (ehc->i.dev) {
  ehc->i.dev_action[ehc->i.dev->devno] |=
   ehc->i.action & ATA_EH_PERDEV_MASK;
  ehc->i.action &= ~ATA_EH_PERDEV_MASK;
 }

 /* propagate timeout to host link */
 if ((all_err_mask & AC_ERR_TIMEOUT) && !ata_is_host_link(link))
  ap->link.eh_context.i.err_mask |= AC_ERR_TIMEOUT;

 /* record error and consider speeding down */
 dev = ehc->i.dev;
 if (!dev && ((ata_link_max_devices(link) == 1 &&
        ata_dev_enabled(link->device))))
     dev = link->device;

 if (dev) {
  if (dev->flags & ATA_DFLAG_DUBIOUS_XFER)
   eflags |= ATA_EFLAG_DUBIOUS_XFER;
  ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask);
  trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask);
 }
}

/**
 * ata_eh_autopsy - analyze error and determine recovery action
 * @ap: host port to perform autopsy on
 *
 * Analyze all links of @ap and determine why they failed and
 * which recovery actions are needed.
 *
 * LOCKING:
 * Kernel thread context (may sleep).
 */

void ata_eh_autopsy(struct ata_port *ap)
{
 struct ata_link *link;

 ata_for_each_link(link, ap, EDGE)
  ata_eh_link_autopsy(link);

 /* Handle the frigging slave link.  Autopsy is done similarly
 * but actions and flags are transferred over to the master
 * link and handled from there.
 */

 if (ap->slave_link) {
  struct ata_eh_context *mehc = &ap->link.eh_context;
  struct ata_eh_context *sehc = &ap->slave_link->eh_context;

  /* transfer control flags from master to slave */
  sehc->i.flags |= mehc->i.flags & ATA_EHI_TO_SLAVE_MASK;

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=96 G=93

¤ Dauer der Verarbeitung: 0.19 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.