// SPDX-License-Identifier: GPL-2.0-or-later /* * libata-eh.c - libata error handling * * Copyright 2006 Tejun Heo <[email protected]> * * 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 { … }; /* 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[] = …; static const unsigned int ata_eh_identify_timeouts[] = …; static const unsigned int ata_eh_revalidate_timeouts[] = …; static const unsigned int ata_eh_flush_timeouts[] = …; static const unsigned int ata_eh_other_timeouts[] = …; struct ata_eh_cmd_timeout_ent { … }; /* 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 … static const struct ata_eh_cmd_timeout_ent ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = …; #undef CMDS static void __ata_port_freeze(struct ata_port *ap); static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, struct ata_device **r_failed_dev); #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) { … } /** * __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, ...) { … } EXPORT_SYMBOL_GPL(…); /** * 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, ...) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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, ...) { … } EXPORT_SYMBOL_GPL(…); #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) { … } EXPORT_SYMBOL_GPL(…); #endif /* CONFIG_PCI */ static int ata_lookup_timeout_table(u8 cmd) { … } /** * 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) { … } /** * 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) { … } static void ata_ering_record(struct ata_ering *ering, unsigned int eflags, unsigned int err_mask) { … } static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering) { … } int ata_ering_map(struct ata_ering *ering, int (*map_fn)(struct ata_ering_entry *, void *), void *arg) { … } static int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg) { … } static void ata_ering_clear(struct ata_ering *ering) { … } static unsigned int ata_eh_dev_action(struct ata_device *dev) { … } static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev, struct ata_eh_info *ehi, unsigned int 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) { … } /** * 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) { … } static void ata_eh_dev_disable(struct ata_device *dev) { … } static void ata_eh_unload(struct ata_port *ap) { … } /** * 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) { … } /** * 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) { … } EXPORT_SYMBOL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); static unsigned int ata_eh_nr_in_flight(struct ata_port *ap) { … } void ata_eh_fastdrain_timerfn(struct timer_list *t) { … } /** * 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, int fastdrain) { … } /** * 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) { … } /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) { … } /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * __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) { … } /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } static void ata_eh_scsidone(struct scsi_cmnd *scmd) { … } static void __ata_eh_qc_complete(struct ata_queued_cmd *qc) { … } /** * 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) { … } /** * 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) { … } /** * ata_dev_disable - disable ATA device * @dev: ATA device to disable * * Disable @dev. * * Locking: * EH context. */ void ata_dev_disable(struct ata_device *dev) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } static int ata_eh_categorize_error(unsigned int eflags, unsigned int err_mask, int *xfer_ok) { … } struct speed_down_verdict_arg { … }; static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } static int ata_eh_read_sense_success_non_ncq(struct ata_link *link) { … } static void ata_eh_get_success_sense(struct ata_link *link) { … } /** * 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) { … } /** * 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) { … } /** * ata_get_cmd_name - get name for ATA command * @command: ATA command code to get name for * * Return a textual name of the given command or "unknown" * * LOCKING: * None */ const char *ata_get_cmd_name(u8 command) { … } EXPORT_SYMBOL_GPL(…); /** * ata_eh_link_report - report error handling to user * @link: ATA link EH is going on * * Report EH to user. * * LOCKING: * None. */ static void ata_eh_link_report(struct ata_link *link) { … } /** * ata_eh_report - report error handling to user * @ap: ATA port to report EH about * * Report EH to user. * * LOCKING: * None. */ void ata_eh_report(struct ata_port *ap) { … } static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline, bool clear_classes) { … } static int ata_eh_followup_srst_needed(struct ata_link *link, int rc) { … } int ata_eh_reset(struct ata_link *link, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { … } static inline void ata_eh_pull_park_action(struct ata_port *ap) { … } static void ata_eh_park_issue_cmd(struct ata_device *dev, int park) { … } static int ata_eh_revalidate_and_attach(struct ata_link *link, struct ata_device **r_failed_dev) { … } /** * ata_set_mode - Program timings and issue SET FEATURES - XFER * @link: link on which timings will be programmed * @r_failed_dev: out parameter for failed device * * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If * ata_set_mode() fails, pointer to the failing device is * returned in @r_failed_dev. * * LOCKING: * PCI/etc. bus probe sem. * * RETURNS: * 0 on success, negative errno otherwise */ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { … } /** * atapi_eh_clear_ua - Clear ATAPI UNIT ATTENTION after reset * @dev: ATAPI device to clear UA for * * Resets and other operations can make an ATAPI device raise * UNIT ATTENTION which causes the next operation to fail. This * function clears UA. * * LOCKING: * EH context (may sleep). * * RETURNS: * 0 on success, -errno on failure. */ static int atapi_eh_clear_ua(struct ata_device *dev) { … } /** * ata_eh_maybe_retry_flush - Retry FLUSH if necessary * @dev: ATA device which may need FLUSH retry * * If @dev failed FLUSH, it needs to be reported upper layer * immediately as it means that @dev failed to remap and already * lost at least a sector and further FLUSH retrials won't make * any difference to the lost sector. However, if FLUSH failed * for other reasons, for example transmission error, FLUSH needs * to be retried. * * This function determines whether FLUSH failure retry is * necessary and performs it if so. * * RETURNS: * 0 if EH can continue, -errno if EH needs to be repeated. */ static int ata_eh_maybe_retry_flush(struct ata_device *dev) { … } /** * ata_eh_set_lpm - configure SATA interface power management * @link: link to configure power management * @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_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, struct ata_device **r_failed_dev) { … } int ata_link_nr_enabled(struct ata_link *link) { … } static int ata_link_nr_vacant(struct ata_link *link) { … } static int ata_eh_skip_recovery(struct ata_link *link) { … } static int ata_count_probe_trials_cb(struct ata_ering_entry *ent, void *void_arg) { … } static int ata_eh_schedule_probe(struct ata_device *dev) { … } static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) { … } /** * ata_eh_recover - recover host port after error * @ap: host port to recover * @prereset: prereset method (can be NULL) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) * @postreset: postreset method (can be NULL) * @r_failed_link: out parameter for failed link * * This is the alpha and omega, eum and yang, heart and soul of * libata exception handling. On entry, actions required to * recover each link and hotplug requests are recorded in the * link's eh_context. This function executes all the operations * with appropriate retrials and fallbacks to resurrect failed * devices, detach goners and greet newcomers. * * LOCKING: * Kernel thread context (may sleep). * * RETURNS: * 0 on success, -errno on failure. */ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, struct ata_link **r_failed_link) { … } /** * ata_eh_finish - finish up EH * @ap: host port to finish EH for * * Recovery is complete. Clean up EH states and retry or finish * failed qcs. * * LOCKING: * None. */ void ata_eh_finish(struct ata_port *ap) { … } /** * ata_do_eh - do standard error handling * @ap: host port to handle error for * * @prereset: prereset method (can be NULL) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) * @postreset: postreset method (can be NULL) * * Perform standard error handling sequence. * * LOCKING: * Kernel thread context (may sleep). */ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { … } /** * ata_std_error_handler - standard error handler * @ap: host port to handle error for * * Standard error handler * * LOCKING: * Kernel thread context (may sleep). */ void ata_std_error_handler(struct ata_port *ap) { … } EXPORT_SYMBOL_GPL(…); #ifdef CONFIG_PM /** * ata_eh_handle_port_suspend - perform port suspend operation * @ap: port to suspend * * Suspend @ap. * * LOCKING: * Kernel thread context (may sleep). */ static void ata_eh_handle_port_suspend(struct ata_port *ap) { … } /** * ata_eh_handle_port_resume - perform port resume operation * @ap: port to resume * * Resume @ap. * * LOCKING: * Kernel thread context (may sleep). */ static void ata_eh_handle_port_resume(struct ata_port *ap) { … } #endif /* CONFIG_PM */