18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * libata-eh.c - libata error handling 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2006 Tejun Heo <htejun@gmail.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * libata documentation is available via 'make {ps|pdf}docs', 88c2ecf20Sopenharmony_ci * as Documentation/driver-api/libata.rst 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Hardware documentation available from http://www.t13.org/ and 118c2ecf20Sopenharmony_ci * http://www.sata-io.org/ 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 168c2ecf20Sopenharmony_ci#include <linux/export.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 198c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 208c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h> 218c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 228c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 238c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 248c2ecf20Sopenharmony_ci#include "../scsi/scsi_transport_api.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/libata.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <trace/events/libata.h> 298c2ecf20Sopenharmony_ci#include "libata.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cienum { 328c2ecf20Sopenharmony_ci /* speed down verdicts */ 338c2ecf20Sopenharmony_ci ATA_EH_SPDN_NCQ_OFF = (1 << 0), 348c2ecf20Sopenharmony_ci ATA_EH_SPDN_SPEED_DOWN = (1 << 1), 358c2ecf20Sopenharmony_ci ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2), 368c2ecf20Sopenharmony_ci ATA_EH_SPDN_KEEP_ERRORS = (1 << 3), 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* error flags */ 398c2ecf20Sopenharmony_ci ATA_EFLAG_IS_IO = (1 << 0), 408c2ecf20Sopenharmony_ci ATA_EFLAG_DUBIOUS_XFER = (1 << 1), 418c2ecf20Sopenharmony_ci ATA_EFLAG_OLD_ER = (1 << 31), 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* error categories */ 448c2ecf20Sopenharmony_ci ATA_ECAT_NONE = 0, 458c2ecf20Sopenharmony_ci ATA_ECAT_ATA_BUS = 1, 468c2ecf20Sopenharmony_ci ATA_ECAT_TOUT_HSM = 2, 478c2ecf20Sopenharmony_ci ATA_ECAT_UNK_DEV = 3, 488c2ecf20Sopenharmony_ci ATA_ECAT_DUBIOUS_NONE = 4, 498c2ecf20Sopenharmony_ci ATA_ECAT_DUBIOUS_ATA_BUS = 5, 508c2ecf20Sopenharmony_ci ATA_ECAT_DUBIOUS_TOUT_HSM = 6, 518c2ecf20Sopenharmony_ci ATA_ECAT_DUBIOUS_UNK_DEV = 7, 528c2ecf20Sopenharmony_ci ATA_ECAT_NR = 8, 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci ATA_EH_CMD_DFL_TIMEOUT = 5000, 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* always put at least this amount of time between resets */ 578c2ecf20Sopenharmony_ci ATA_EH_RESET_COOL_DOWN = 5000, 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* Waiting in ->prereset can never be reliable. It's 608c2ecf20Sopenharmony_ci * sometimes nice to wait there but it can't be depended upon; 618c2ecf20Sopenharmony_ci * otherwise, we wouldn't be resetting. Just give it enough 628c2ecf20Sopenharmony_ci * time for most drives to spin up. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci ATA_EH_PRERESET_TIMEOUT = 10000, 658c2ecf20Sopenharmony_ci ATA_EH_FASTDRAIN_INTERVAL = 3000, 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci ATA_EH_UA_TRIES = 5, 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* probe speed down parameters, see ata_eh_schedule_probe() */ 708c2ecf20Sopenharmony_ci ATA_EH_PROBE_TRIAL_INTERVAL = 60000, /* 1 min */ 718c2ecf20Sopenharmony_ci ATA_EH_PROBE_TRIALS = 2, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* The following table determines how we sequence resets. Each entry 758c2ecf20Sopenharmony_ci * represents timeout for that try. The first try can be soft or 768c2ecf20Sopenharmony_ci * hardreset. All others are hardreset if available. In most cases 778c2ecf20Sopenharmony_ci * the first reset w/ 10sec timeout should succeed. Following entries 788c2ecf20Sopenharmony_ci * are mostly for error handling, hotplug and those outlier devices that 798c2ecf20Sopenharmony_ci * take an exceptionally long time to recover from reset. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_cistatic const unsigned long ata_eh_reset_timeouts[] = { 828c2ecf20Sopenharmony_ci 10000, /* most drives spin up by 10sec */ 838c2ecf20Sopenharmony_ci 10000, /* > 99% working drives spin up before 20sec */ 848c2ecf20Sopenharmony_ci 35000, /* give > 30 secs of idleness for outlier devices */ 858c2ecf20Sopenharmony_ci 5000, /* and sweet one last chance */ 868c2ecf20Sopenharmony_ci ULONG_MAX, /* > 1 min has elapsed, give up */ 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic const unsigned long ata_eh_identify_timeouts[] = { 908c2ecf20Sopenharmony_ci 5000, /* covers > 99% of successes and not too boring on failures */ 918c2ecf20Sopenharmony_ci 10000, /* combined time till here is enough even for media access */ 928c2ecf20Sopenharmony_ci 30000, /* for true idiots */ 938c2ecf20Sopenharmony_ci ULONG_MAX, 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic const unsigned long ata_eh_revalidate_timeouts[] = { 978c2ecf20Sopenharmony_ci 15000, /* Some drives are slow to read log pages when waking-up */ 988c2ecf20Sopenharmony_ci 15000, /* combined time till here is enough even for media access */ 998c2ecf20Sopenharmony_ci ULONG_MAX, 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic const unsigned long ata_eh_flush_timeouts[] = { 1038c2ecf20Sopenharmony_ci 15000, /* be generous with flush */ 1048c2ecf20Sopenharmony_ci 15000, /* ditto */ 1058c2ecf20Sopenharmony_ci 30000, /* and even more generous */ 1068c2ecf20Sopenharmony_ci ULONG_MAX, 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic const unsigned long ata_eh_other_timeouts[] = { 1108c2ecf20Sopenharmony_ci 5000, /* same rationale as identify timeout */ 1118c2ecf20Sopenharmony_ci 10000, /* ditto */ 1128c2ecf20Sopenharmony_ci /* but no merciful 30sec for other commands, it just isn't worth it */ 1138c2ecf20Sopenharmony_ci ULONG_MAX, 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistruct ata_eh_cmd_timeout_ent { 1178c2ecf20Sopenharmony_ci const u8 *commands; 1188c2ecf20Sopenharmony_ci const unsigned long *timeouts; 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* The following table determines timeouts to use for EH internal 1228c2ecf20Sopenharmony_ci * commands. Each table entry is a command class and matches the 1238c2ecf20Sopenharmony_ci * commands the entry applies to and the timeout table to use. 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * On the retry after a command timed out, the next timeout value from 1268c2ecf20Sopenharmony_ci * the table is used. If the table doesn't contain further entries, 1278c2ecf20Sopenharmony_ci * the last value is used. 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * ehc->cmd_timeout_idx keeps track of which timeout to use per 1308c2ecf20Sopenharmony_ci * command class, so if SET_FEATURES times out on the first try, the 1318c2ecf20Sopenharmony_ci * next try will use the second timeout value only for that class. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci#define CMDS(cmds...) (const u8 []){ cmds, 0 } 1348c2ecf20Sopenharmony_cistatic const struct ata_eh_cmd_timeout_ent 1358c2ecf20Sopenharmony_ciata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = { 1368c2ecf20Sopenharmony_ci { .commands = CMDS(ATA_CMD_ID_ATA, ATA_CMD_ID_ATAPI), 1378c2ecf20Sopenharmony_ci .timeouts = ata_eh_identify_timeouts, }, 1388c2ecf20Sopenharmony_ci { .commands = CMDS(ATA_CMD_READ_LOG_EXT, ATA_CMD_READ_LOG_DMA_EXT), 1398c2ecf20Sopenharmony_ci .timeouts = ata_eh_revalidate_timeouts, }, 1408c2ecf20Sopenharmony_ci { .commands = CMDS(ATA_CMD_READ_NATIVE_MAX, ATA_CMD_READ_NATIVE_MAX_EXT), 1418c2ecf20Sopenharmony_ci .timeouts = ata_eh_other_timeouts, }, 1428c2ecf20Sopenharmony_ci { .commands = CMDS(ATA_CMD_SET_MAX, ATA_CMD_SET_MAX_EXT), 1438c2ecf20Sopenharmony_ci .timeouts = ata_eh_other_timeouts, }, 1448c2ecf20Sopenharmony_ci { .commands = CMDS(ATA_CMD_SET_FEATURES), 1458c2ecf20Sopenharmony_ci .timeouts = ata_eh_other_timeouts, }, 1468c2ecf20Sopenharmony_ci { .commands = CMDS(ATA_CMD_INIT_DEV_PARAMS), 1478c2ecf20Sopenharmony_ci .timeouts = ata_eh_other_timeouts, }, 1488c2ecf20Sopenharmony_ci { .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT), 1498c2ecf20Sopenharmony_ci .timeouts = ata_eh_flush_timeouts }, 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci#undef CMDS 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void __ata_port_freeze(struct ata_port *ap); 1548c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1558c2ecf20Sopenharmony_cistatic void ata_eh_handle_port_suspend(struct ata_port *ap); 1568c2ecf20Sopenharmony_cistatic void ata_eh_handle_port_resume(struct ata_port *ap); 1578c2ecf20Sopenharmony_ci#else /* CONFIG_PM */ 1588c2ecf20Sopenharmony_cistatic void ata_eh_handle_port_suspend(struct ata_port *ap) 1598c2ecf20Sopenharmony_ci{ } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void ata_eh_handle_port_resume(struct ata_port *ap) 1628c2ecf20Sopenharmony_ci{ } 1638c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic __printf(2, 0) void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, 1668c2ecf20Sopenharmony_ci const char *fmt, va_list args) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len, 1698c2ecf20Sopenharmony_ci ATA_EH_DESC_LEN - ehi->desc_len, 1708c2ecf20Sopenharmony_ci fmt, args); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * __ata_ehi_push_desc - push error description without adding separator 1758c2ecf20Sopenharmony_ci * @ehi: target EHI 1768c2ecf20Sopenharmony_ci * @fmt: printf format string 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * Format string according to @fmt and append it to @ehi->desc. 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * LOCKING: 1818c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_civoid __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci va_list args; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci va_start(args, fmt); 1888c2ecf20Sopenharmony_ci __ata_ehi_pushv_desc(ehi, fmt, args); 1898c2ecf20Sopenharmony_ci va_end(args); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__ata_ehi_push_desc); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/** 1948c2ecf20Sopenharmony_ci * ata_ehi_push_desc - push error description with separator 1958c2ecf20Sopenharmony_ci * @ehi: target EHI 1968c2ecf20Sopenharmony_ci * @fmt: printf format string 1978c2ecf20Sopenharmony_ci * 1988c2ecf20Sopenharmony_ci * Format string according to @fmt and append it to @ehi->desc. 1998c2ecf20Sopenharmony_ci * If @ehi->desc is not empty, ", " is added in-between. 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci * LOCKING: 2028c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_civoid ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci va_list args; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (ehi->desc_len) 2098c2ecf20Sopenharmony_ci __ata_ehi_push_desc(ehi, ", "); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci va_start(args, fmt); 2128c2ecf20Sopenharmony_ci __ata_ehi_pushv_desc(ehi, fmt, args); 2138c2ecf20Sopenharmony_ci va_end(args); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_ehi_push_desc); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/** 2188c2ecf20Sopenharmony_ci * ata_ehi_clear_desc - clean error description 2198c2ecf20Sopenharmony_ci * @ehi: target EHI 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci * Clear @ehi->desc. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * LOCKING: 2248c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_civoid ata_ehi_clear_desc(struct ata_eh_info *ehi) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci ehi->desc[0] = '\0'; 2298c2ecf20Sopenharmony_ci ehi->desc_len = 0; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_ehi_clear_desc); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/** 2348c2ecf20Sopenharmony_ci * ata_port_desc - append port description 2358c2ecf20Sopenharmony_ci * @ap: target ATA port 2368c2ecf20Sopenharmony_ci * @fmt: printf format string 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * Format string according to @fmt and append it to port 2398c2ecf20Sopenharmony_ci * description. If port description is not empty, " " is added 2408c2ecf20Sopenharmony_ci * in-between. This function is to be used while initializing 2418c2ecf20Sopenharmony_ci * ata_host. The description is printed on host registration. 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci * LOCKING: 2448c2ecf20Sopenharmony_ci * None. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_civoid ata_port_desc(struct ata_port *ap, const char *fmt, ...) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci va_list args; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING)); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (ap->link.eh_info.desc_len) 2538c2ecf20Sopenharmony_ci __ata_ehi_push_desc(&ap->link.eh_info, " "); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci va_start(args, fmt); 2568c2ecf20Sopenharmony_ci __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args); 2578c2ecf20Sopenharmony_ci va_end(args); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_port_desc); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 2628c2ecf20Sopenharmony_ci/** 2638c2ecf20Sopenharmony_ci * ata_port_pbar_desc - append PCI BAR description 2648c2ecf20Sopenharmony_ci * @ap: target ATA port 2658c2ecf20Sopenharmony_ci * @bar: target PCI BAR 2668c2ecf20Sopenharmony_ci * @offset: offset into PCI BAR 2678c2ecf20Sopenharmony_ci * @name: name of the area 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * If @offset is negative, this function formats a string which 2708c2ecf20Sopenharmony_ci * contains the name, address, size and type of the BAR and 2718c2ecf20Sopenharmony_ci * appends it to the port description. If @offset is zero or 2728c2ecf20Sopenharmony_ci * positive, only name and offsetted address is appended. 2738c2ecf20Sopenharmony_ci * 2748c2ecf20Sopenharmony_ci * LOCKING: 2758c2ecf20Sopenharmony_ci * None. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_civoid ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset, 2788c2ecf20Sopenharmony_ci const char *name) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(ap->host->dev); 2818c2ecf20Sopenharmony_ci char *type = ""; 2828c2ecf20Sopenharmony_ci unsigned long long start, len; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) 2858c2ecf20Sopenharmony_ci type = "m"; 2868c2ecf20Sopenharmony_ci else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) 2878c2ecf20Sopenharmony_ci type = "i"; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci start = (unsigned long long)pci_resource_start(pdev, bar); 2908c2ecf20Sopenharmony_ci len = (unsigned long long)pci_resource_len(pdev, bar); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (offset < 0) 2938c2ecf20Sopenharmony_ci ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start); 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci ata_port_desc(ap, "%s 0x%llx", name, 2968c2ecf20Sopenharmony_ci start + (unsigned long long)offset); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_port_pbar_desc); 2998c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int ata_lookup_timeout_table(u8 cmd) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci int i; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci for (i = 0; i < ATA_EH_CMD_TIMEOUT_TABLE_SIZE; i++) { 3068c2ecf20Sopenharmony_ci const u8 *cur; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci for (cur = ata_eh_cmd_timeout_table[i].commands; *cur; cur++) 3098c2ecf20Sopenharmony_ci if (*cur == cmd) 3108c2ecf20Sopenharmony_ci return i; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return -1; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/** 3178c2ecf20Sopenharmony_ci * ata_internal_cmd_timeout - determine timeout for an internal command 3188c2ecf20Sopenharmony_ci * @dev: target device 3198c2ecf20Sopenharmony_ci * @cmd: internal command to be issued 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci * Determine timeout for internal command @cmd for @dev. 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * LOCKING: 3248c2ecf20Sopenharmony_ci * EH context. 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * RETURNS: 3278c2ecf20Sopenharmony_ci * Determined timeout. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_ciunsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &dev->link->eh_context; 3328c2ecf20Sopenharmony_ci int ent = ata_lookup_timeout_table(cmd); 3338c2ecf20Sopenharmony_ci int idx; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (ent < 0) 3368c2ecf20Sopenharmony_ci return ATA_EH_CMD_DFL_TIMEOUT; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci idx = ehc->cmd_timeout_idx[dev->devno][ent]; 3398c2ecf20Sopenharmony_ci return ata_eh_cmd_timeout_table[ent].timeouts[idx]; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/** 3438c2ecf20Sopenharmony_ci * ata_internal_cmd_timed_out - notification for internal command timeout 3448c2ecf20Sopenharmony_ci * @dev: target device 3458c2ecf20Sopenharmony_ci * @cmd: internal command which timed out 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci * Notify EH that internal command @cmd for @dev timed out. This 3488c2ecf20Sopenharmony_ci * function should be called only for commands whose timeouts are 3498c2ecf20Sopenharmony_ci * determined using ata_internal_cmd_timeout(). 3508c2ecf20Sopenharmony_ci * 3518c2ecf20Sopenharmony_ci * LOCKING: 3528c2ecf20Sopenharmony_ci * EH context. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_civoid ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &dev->link->eh_context; 3578c2ecf20Sopenharmony_ci int ent = ata_lookup_timeout_table(cmd); 3588c2ecf20Sopenharmony_ci int idx; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (ent < 0) 3618c2ecf20Sopenharmony_ci return; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci idx = ehc->cmd_timeout_idx[dev->devno][ent]; 3648c2ecf20Sopenharmony_ci if (ata_eh_cmd_timeout_table[ent].timeouts[idx + 1] != ULONG_MAX) 3658c2ecf20Sopenharmony_ci ehc->cmd_timeout_idx[dev->devno][ent]++; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void ata_ering_record(struct ata_ering *ering, unsigned int eflags, 3698c2ecf20Sopenharmony_ci unsigned int err_mask) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct ata_ering_entry *ent; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci WARN_ON(!err_mask); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ering->cursor++; 3768c2ecf20Sopenharmony_ci ering->cursor %= ATA_ERING_SIZE; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci ent = &ering->ring[ering->cursor]; 3798c2ecf20Sopenharmony_ci ent->eflags = eflags; 3808c2ecf20Sopenharmony_ci ent->err_mask = err_mask; 3818c2ecf20Sopenharmony_ci ent->timestamp = get_jiffies_64(); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic struct ata_ering_entry *ata_ering_top(struct ata_ering *ering) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct ata_ering_entry *ent = &ering->ring[ering->cursor]; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (ent->err_mask) 3898c2ecf20Sopenharmony_ci return ent; 3908c2ecf20Sopenharmony_ci return NULL; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ciint ata_ering_map(struct ata_ering *ering, 3948c2ecf20Sopenharmony_ci int (*map_fn)(struct ata_ering_entry *, void *), 3958c2ecf20Sopenharmony_ci void *arg) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci int idx, rc = 0; 3988c2ecf20Sopenharmony_ci struct ata_ering_entry *ent; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci idx = ering->cursor; 4018c2ecf20Sopenharmony_ci do { 4028c2ecf20Sopenharmony_ci ent = &ering->ring[idx]; 4038c2ecf20Sopenharmony_ci if (!ent->err_mask) 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci rc = map_fn(ent, arg); 4068c2ecf20Sopenharmony_ci if (rc) 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE; 4098c2ecf20Sopenharmony_ci } while (idx != ering->cursor); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return rc; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci ent->eflags |= ATA_EFLAG_OLD_ER; 4178c2ecf20Sopenharmony_ci return 0; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void ata_ering_clear(struct ata_ering *ering) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci ata_ering_map(ering, ata_ering_clear_cb, NULL); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic unsigned int ata_eh_dev_action(struct ata_device *dev) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &dev->link->eh_context; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return ehc->i.action | ehc->i.dev_action[dev->devno]; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev, 4338c2ecf20Sopenharmony_ci struct ata_eh_info *ehi, unsigned int action) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct ata_device *tdev; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (!dev) { 4388c2ecf20Sopenharmony_ci ehi->action &= ~action; 4398c2ecf20Sopenharmony_ci ata_for_each_dev(tdev, link, ALL) 4408c2ecf20Sopenharmony_ci ehi->dev_action[tdev->devno] &= ~action; 4418c2ecf20Sopenharmony_ci } else { 4428c2ecf20Sopenharmony_ci /* doesn't make sense for port-wide EH actions */ 4438c2ecf20Sopenharmony_ci WARN_ON(!(action & ATA_EH_PERDEV_MASK)); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* break ehi->action into ehi->dev_action */ 4468c2ecf20Sopenharmony_ci if (ehi->action & action) { 4478c2ecf20Sopenharmony_ci ata_for_each_dev(tdev, link, ALL) 4488c2ecf20Sopenharmony_ci ehi->dev_action[tdev->devno] |= 4498c2ecf20Sopenharmony_ci ehi->action & action; 4508c2ecf20Sopenharmony_ci ehi->action &= ~action; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* turn off the specified per-dev action */ 4548c2ecf20Sopenharmony_ci ehi->dev_action[dev->devno] &= ~action; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/** 4598c2ecf20Sopenharmony_ci * ata_eh_acquire - acquire EH ownership 4608c2ecf20Sopenharmony_ci * @ap: ATA port to acquire EH ownership for 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci * Acquire EH ownership for @ap. This is the basic exclusion 4638c2ecf20Sopenharmony_ci * mechanism for ports sharing a host. Only one port hanging off 4648c2ecf20Sopenharmony_ci * the same host can claim the ownership of EH. 4658c2ecf20Sopenharmony_ci * 4668c2ecf20Sopenharmony_ci * LOCKING: 4678c2ecf20Sopenharmony_ci * EH context. 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_civoid ata_eh_acquire(struct ata_port *ap) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci mutex_lock(&ap->host->eh_mutex); 4728c2ecf20Sopenharmony_ci WARN_ON_ONCE(ap->host->eh_owner); 4738c2ecf20Sopenharmony_ci ap->host->eh_owner = current; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci/** 4778c2ecf20Sopenharmony_ci * ata_eh_release - release EH ownership 4788c2ecf20Sopenharmony_ci * @ap: ATA port to release EH ownership for 4798c2ecf20Sopenharmony_ci * 4808c2ecf20Sopenharmony_ci * Release EH ownership for @ap if the caller. The caller must 4818c2ecf20Sopenharmony_ci * have acquired EH ownership using ata_eh_acquire() previously. 4828c2ecf20Sopenharmony_ci * 4838c2ecf20Sopenharmony_ci * LOCKING: 4848c2ecf20Sopenharmony_ci * EH context. 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_civoid ata_eh_release(struct ata_port *ap) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci WARN_ON_ONCE(ap->host->eh_owner != current); 4898c2ecf20Sopenharmony_ci ap->host->eh_owner = NULL; 4908c2ecf20Sopenharmony_ci mutex_unlock(&ap->host->eh_mutex); 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic void ata_eh_unload(struct ata_port *ap) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct ata_link *link; 4968c2ecf20Sopenharmony_ci struct ata_device *dev; 4978c2ecf20Sopenharmony_ci unsigned long flags; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* Restore SControl IPM and SPD for the next driver and 5008c2ecf20Sopenharmony_ci * disable attached devices. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, PMP_FIRST) { 5038c2ecf20Sopenharmony_ci sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0); 5048c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) 5058c2ecf20Sopenharmony_ci ata_dev_disable(dev); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* freeze and set UNLOADED */ 5098c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci ata_port_freeze(ap); /* won't be thawed */ 5128c2ecf20Sopenharmony_ci ap->pflags &= ~ATA_PFLAG_EH_PENDING; /* clear pending from freeze */ 5138c2ecf20Sopenharmony_ci ap->pflags |= ATA_PFLAG_UNLOADED; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci/** 5198c2ecf20Sopenharmony_ci * ata_scsi_error - SCSI layer error handler callback 5208c2ecf20Sopenharmony_ci * @host: SCSI host on which error occurred 5218c2ecf20Sopenharmony_ci * 5228c2ecf20Sopenharmony_ci * Handles SCSI-layer-thrown error events. 5238c2ecf20Sopenharmony_ci * 5248c2ecf20Sopenharmony_ci * LOCKING: 5258c2ecf20Sopenharmony_ci * Inherited from SCSI layer (none, can sleep) 5268c2ecf20Sopenharmony_ci * 5278c2ecf20Sopenharmony_ci * RETURNS: 5288c2ecf20Sopenharmony_ci * Zero. 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_civoid ata_scsi_error(struct Scsi_Host *host) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct ata_port *ap = ata_shost_to_port(host); 5338c2ecf20Sopenharmony_ci unsigned long flags; 5348c2ecf20Sopenharmony_ci LIST_HEAD(eh_work_q); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci DPRINTK("ENTER\n"); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci spin_lock_irqsave(host->host_lock, flags); 5398c2ecf20Sopenharmony_ci list_splice_init(&host->eh_cmd_q, &eh_work_q); 5408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, flags); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci ata_scsi_cmd_error_handler(host, ap, &eh_work_q); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* If we timed raced normal completion and there is nothing to 5458c2ecf20Sopenharmony_ci recover nr_timedout == 0 why exactly are we doing error recovery ? */ 5468c2ecf20Sopenharmony_ci ata_scsi_port_error_handler(host, ap); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* finish or retry handled scmd's and clean up */ 5498c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&eh_work_q)); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci DPRINTK("EXIT\n"); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/** 5558c2ecf20Sopenharmony_ci * ata_scsi_cmd_error_handler - error callback for a list of commands 5568c2ecf20Sopenharmony_ci * @host: scsi host containing the port 5578c2ecf20Sopenharmony_ci * @ap: ATA port within the host 5588c2ecf20Sopenharmony_ci * @eh_work_q: list of commands to process 5598c2ecf20Sopenharmony_ci * 5608c2ecf20Sopenharmony_ci * process the given list of commands and return those finished to the 5618c2ecf20Sopenharmony_ci * ap->eh_done_q. This function is the first part of the libata error 5628c2ecf20Sopenharmony_ci * handler which processes a given list of failed commands. 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_civoid ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, 5658c2ecf20Sopenharmony_ci struct list_head *eh_work_q) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci int i; 5688c2ecf20Sopenharmony_ci unsigned long flags; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* make sure sff pio task is not running */ 5718c2ecf20Sopenharmony_ci ata_sff_flush_pio_task(ap); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* synchronize with host lock and sort out timeouts */ 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* For new EH, all qcs are finished in one of three ways - 5768c2ecf20Sopenharmony_ci * normal completion, error completion, and SCSI timeout. 5778c2ecf20Sopenharmony_ci * Both completions can race against SCSI timeout. When normal 5788c2ecf20Sopenharmony_ci * completion wins, the qc never reaches EH. When error 5798c2ecf20Sopenharmony_ci * completion wins, the qc has ATA_QCFLAG_FAILED set. 5808c2ecf20Sopenharmony_ci * 5818c2ecf20Sopenharmony_ci * When SCSI timeout wins, things are a bit more complex. 5828c2ecf20Sopenharmony_ci * Normal or error completion can occur after the timeout but 5838c2ecf20Sopenharmony_ci * before this point. In such cases, both types of 5848c2ecf20Sopenharmony_ci * completions are honored. A scmd is determined to have 5858c2ecf20Sopenharmony_ci * timed out iff its associated qc is active and not failed. 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 5888c2ecf20Sopenharmony_ci if (ap->ops->error_handler) { 5898c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd, *tmp; 5908c2ecf20Sopenharmony_ci int nr_timedout = 0; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* This must occur under the ap->lock as we don't want 5938c2ecf20Sopenharmony_ci a polled recovery to race the real interrupt handler 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci The lost_interrupt handler checks for any completed but 5968c2ecf20Sopenharmony_ci non-notified command and completes much like an IRQ handler. 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci We then fall into the error recovery code which will treat 5998c2ecf20Sopenharmony_ci this as if normal completion won the race */ 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (ap->ops->lost_interrupt) 6028c2ecf20Sopenharmony_ci ap->ops->lost_interrupt(ap); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) { 6058c2ecf20Sopenharmony_ci struct ata_queued_cmd *qc; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci ata_qc_for_each_raw(ap, qc, i) { 6088c2ecf20Sopenharmony_ci if (qc->flags & ATA_QCFLAG_ACTIVE && 6098c2ecf20Sopenharmony_ci qc->scsicmd == scmd) 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (i < ATA_MAX_QUEUE) { 6148c2ecf20Sopenharmony_ci /* the scmd has an associated qc */ 6158c2ecf20Sopenharmony_ci if (!(qc->flags & ATA_QCFLAG_FAILED)) { 6168c2ecf20Sopenharmony_ci /* which hasn't failed yet, timeout */ 6178c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_TIMEOUT; 6188c2ecf20Sopenharmony_ci qc->flags |= ATA_QCFLAG_FAILED; 6198c2ecf20Sopenharmony_ci nr_timedout++; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci } else { 6228c2ecf20Sopenharmony_ci /* Normal completion occurred after 6238c2ecf20Sopenharmony_ci * SCSI timeout but before this point. 6248c2ecf20Sopenharmony_ci * Successfully complete it. 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_ci scmd->retries = scmd->allowed; 6278c2ecf20Sopenharmony_ci scsi_eh_finish_cmd(scmd, &ap->eh_done_q); 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* If we have timed out qcs. They belong to EH from 6328c2ecf20Sopenharmony_ci * this point but the state of the controller is 6338c2ecf20Sopenharmony_ci * unknown. Freeze the port to make sure the IRQ 6348c2ecf20Sopenharmony_ci * handler doesn't diddle with those qcs. This must 6358c2ecf20Sopenharmony_ci * be done atomically w.r.t. setting QCFLAG_FAILED. 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_ci if (nr_timedout) 6388c2ecf20Sopenharmony_ci __ata_port_freeze(ap); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* initialize eh_tries */ 6428c2ecf20Sopenharmony_ci ap->eh_tries = ATA_EH_MAX_TRIES; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ata_scsi_cmd_error_handler); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/** 6508c2ecf20Sopenharmony_ci * ata_scsi_port_error_handler - recover the port after the commands 6518c2ecf20Sopenharmony_ci * @host: SCSI host containing the port 6528c2ecf20Sopenharmony_ci * @ap: the ATA port 6538c2ecf20Sopenharmony_ci * 6548c2ecf20Sopenharmony_ci * Handle the recovery of the port @ap after all the commands 6558c2ecf20Sopenharmony_ci * have been recovered. 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_civoid ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci unsigned long flags; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* invoke error handler */ 6628c2ecf20Sopenharmony_ci if (ap->ops->error_handler) { 6638c2ecf20Sopenharmony_ci struct ata_link *link; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* acquire EH ownership */ 6668c2ecf20Sopenharmony_ci ata_eh_acquire(ap); 6678c2ecf20Sopenharmony_ci repeat: 6688c2ecf20Sopenharmony_ci /* kill fast drain timer */ 6698c2ecf20Sopenharmony_ci del_timer_sync(&ap->fastdrain_timer); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* process port resume request */ 6728c2ecf20Sopenharmony_ci ata_eh_handle_port_resume(ap); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* fetch & clear EH info */ 6758c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, HOST_FIRST) { 6788c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 6798c2ecf20Sopenharmony_ci struct ata_device *dev; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci memset(&link->eh_context, 0, sizeof(link->eh_context)); 6828c2ecf20Sopenharmony_ci link->eh_context.i = link->eh_info; 6838c2ecf20Sopenharmony_ci memset(&link->eh_info, 0, sizeof(link->eh_info)); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ENABLED) { 6868c2ecf20Sopenharmony_ci int devno = dev->devno; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci ehc->saved_xfer_mode[devno] = dev->xfer_mode; 6898c2ecf20Sopenharmony_ci if (ata_ncq_enabled(dev)) 6908c2ecf20Sopenharmony_ci ehc->saved_ncq_enabled |= 1 << devno; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; 6958c2ecf20Sopenharmony_ci ap->pflags &= ~ATA_PFLAG_EH_PENDING; 6968c2ecf20Sopenharmony_ci ap->excl_link = NULL; /* don't maintain exclusion over EH */ 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* invoke EH, skip if unloading or suspended */ 7018c2ecf20Sopenharmony_ci if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED))) 7028c2ecf20Sopenharmony_ci ap->ops->error_handler(ap); 7038c2ecf20Sopenharmony_ci else { 7048c2ecf20Sopenharmony_ci /* if unloading, commence suicide */ 7058c2ecf20Sopenharmony_ci if ((ap->pflags & ATA_PFLAG_UNLOADING) && 7068c2ecf20Sopenharmony_ci !(ap->pflags & ATA_PFLAG_UNLOADED)) 7078c2ecf20Sopenharmony_ci ata_eh_unload(ap); 7088c2ecf20Sopenharmony_ci ata_eh_finish(ap); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* process port suspend request */ 7128c2ecf20Sopenharmony_ci ata_eh_handle_port_suspend(ap); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Exception might have happened after ->error_handler 7158c2ecf20Sopenharmony_ci * recovered the port but before this point. Repeat 7168c2ecf20Sopenharmony_ci * EH in such case. 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_EH_PENDING) { 7218c2ecf20Sopenharmony_ci if (--ap->eh_tries) { 7228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 7238c2ecf20Sopenharmony_ci goto repeat; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci ata_port_err(ap, 7268c2ecf20Sopenharmony_ci "EH pending after %d tries, giving up\n", 7278c2ecf20Sopenharmony_ci ATA_EH_MAX_TRIES); 7288c2ecf20Sopenharmony_ci ap->pflags &= ~ATA_PFLAG_EH_PENDING; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* this run is complete, make sure EH info is clear */ 7328c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, HOST_FIRST) 7338c2ecf20Sopenharmony_ci memset(&link->eh_info, 0, sizeof(link->eh_info)); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* end eh (clear host_eh_scheduled) while holding 7368c2ecf20Sopenharmony_ci * ap->lock such that if exception occurs after this 7378c2ecf20Sopenharmony_ci * point but before EH completion, SCSI midlayer will 7388c2ecf20Sopenharmony_ci * re-initiate EH. 7398c2ecf20Sopenharmony_ci */ 7408c2ecf20Sopenharmony_ci ap->ops->end_eh(ap); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 7438c2ecf20Sopenharmony_ci ata_eh_release(ap); 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL); 7468c2ecf20Sopenharmony_ci ap->ops->eng_timeout(ap); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci scsi_eh_flush_done_q(&ap->eh_done_q); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* clean up */ 7528c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_LOADING) 7558c2ecf20Sopenharmony_ci ap->pflags &= ~ATA_PFLAG_LOADING; 7568c2ecf20Sopenharmony_ci else if ((ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) && 7578c2ecf20Sopenharmony_ci !(ap->flags & ATA_FLAG_SAS_HOST)) 7588c2ecf20Sopenharmony_ci schedule_delayed_work(&ap->hotplug_task, 0); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_RECOVERED) 7618c2ecf20Sopenharmony_ci ata_port_info(ap, "EH complete\n"); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* tell wait_eh that we're done */ 7668c2ecf20Sopenharmony_ci ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS; 7678c2ecf20Sopenharmony_ci wake_up_all(&ap->eh_wait_q); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_scsi_port_error_handler); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci/** 7748c2ecf20Sopenharmony_ci * ata_port_wait_eh - Wait for the currently pending EH to complete 7758c2ecf20Sopenharmony_ci * @ap: Port to wait EH for 7768c2ecf20Sopenharmony_ci * 7778c2ecf20Sopenharmony_ci * Wait until the currently pending EH is complete. 7788c2ecf20Sopenharmony_ci * 7798c2ecf20Sopenharmony_ci * LOCKING: 7808c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_civoid ata_port_wait_eh(struct ata_port *ap) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci unsigned long flags; 7858c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci retry: 7888c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) { 7918c2ecf20Sopenharmony_ci prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE); 7928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 7938c2ecf20Sopenharmony_ci schedule(); 7948c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci finish_wait(&ap->eh_wait_q, &wait); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* make sure SCSI EH is complete */ 8018c2ecf20Sopenharmony_ci if (scsi_host_in_recovery(ap->scsi_host)) { 8028c2ecf20Sopenharmony_ci ata_msleep(ap, 10); 8038c2ecf20Sopenharmony_ci goto retry; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_port_wait_eh); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic int ata_eh_nr_in_flight(struct ata_port *ap) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci struct ata_queued_cmd *qc; 8118c2ecf20Sopenharmony_ci unsigned int tag; 8128c2ecf20Sopenharmony_ci int nr = 0; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* count only non-internal commands */ 8158c2ecf20Sopenharmony_ci ata_qc_for_each(ap, qc, tag) { 8168c2ecf20Sopenharmony_ci if (qc) 8178c2ecf20Sopenharmony_ci nr++; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return nr; 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_civoid ata_eh_fastdrain_timerfn(struct timer_list *t) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct ata_port *ap = from_timer(ap, t, fastdrain_timer); 8268c2ecf20Sopenharmony_ci unsigned long flags; 8278c2ecf20Sopenharmony_ci int cnt; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci cnt = ata_eh_nr_in_flight(ap); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* are we done? */ 8348c2ecf20Sopenharmony_ci if (!cnt) 8358c2ecf20Sopenharmony_ci goto out_unlock; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (cnt == ap->fastdrain_cnt) { 8388c2ecf20Sopenharmony_ci struct ata_queued_cmd *qc; 8398c2ecf20Sopenharmony_ci unsigned int tag; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* No progress during the last interval, tag all 8428c2ecf20Sopenharmony_ci * in-flight qcs as timed out and freeze the port. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci ata_qc_for_each(ap, qc, tag) { 8458c2ecf20Sopenharmony_ci if (qc) 8468c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_TIMEOUT; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci ata_port_freeze(ap); 8508c2ecf20Sopenharmony_ci } else { 8518c2ecf20Sopenharmony_ci /* some qcs have finished, give it another chance */ 8528c2ecf20Sopenharmony_ci ap->fastdrain_cnt = cnt; 8538c2ecf20Sopenharmony_ci ap->fastdrain_timer.expires = 8548c2ecf20Sopenharmony_ci ata_deadline(jiffies, ATA_EH_FASTDRAIN_INTERVAL); 8558c2ecf20Sopenharmony_ci add_timer(&ap->fastdrain_timer); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci out_unlock: 8598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/** 8638c2ecf20Sopenharmony_ci * ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain 8648c2ecf20Sopenharmony_ci * @ap: target ATA port 8658c2ecf20Sopenharmony_ci * @fastdrain: activate fast drain 8668c2ecf20Sopenharmony_ci * 8678c2ecf20Sopenharmony_ci * Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain 8688c2ecf20Sopenharmony_ci * is non-zero and EH wasn't pending before. Fast drain ensures 8698c2ecf20Sopenharmony_ci * that EH kicks in in timely manner. 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * LOCKING: 8728c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 8738c2ecf20Sopenharmony_ci */ 8748c2ecf20Sopenharmony_cistatic void ata_eh_set_pending(struct ata_port *ap, int fastdrain) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci int cnt; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* already scheduled? */ 8798c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_EH_PENDING) 8808c2ecf20Sopenharmony_ci return; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci ap->pflags |= ATA_PFLAG_EH_PENDING; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (!fastdrain) 8858c2ecf20Sopenharmony_ci return; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* do we have in-flight qcs? */ 8888c2ecf20Sopenharmony_ci cnt = ata_eh_nr_in_flight(ap); 8898c2ecf20Sopenharmony_ci if (!cnt) 8908c2ecf20Sopenharmony_ci return; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci /* activate fast drain */ 8938c2ecf20Sopenharmony_ci ap->fastdrain_cnt = cnt; 8948c2ecf20Sopenharmony_ci ap->fastdrain_timer.expires = 8958c2ecf20Sopenharmony_ci ata_deadline(jiffies, ATA_EH_FASTDRAIN_INTERVAL); 8968c2ecf20Sopenharmony_ci add_timer(&ap->fastdrain_timer); 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci/** 9008c2ecf20Sopenharmony_ci * ata_qc_schedule_eh - schedule qc for error handling 9018c2ecf20Sopenharmony_ci * @qc: command to schedule error handling for 9028c2ecf20Sopenharmony_ci * 9038c2ecf20Sopenharmony_ci * Schedule error handling for @qc. EH will kick in as soon as 9048c2ecf20Sopenharmony_ci * other commands are drained. 9058c2ecf20Sopenharmony_ci * 9068c2ecf20Sopenharmony_ci * LOCKING: 9078c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 9088c2ecf20Sopenharmony_ci */ 9098c2ecf20Sopenharmony_civoid ata_qc_schedule_eh(struct ata_queued_cmd *qc) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci struct ata_port *ap = qc->ap; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci WARN_ON(!ap->ops->error_handler); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci qc->flags |= ATA_QCFLAG_FAILED; 9168c2ecf20Sopenharmony_ci ata_eh_set_pending(ap, 1); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* The following will fail if timeout has already expired. 9198c2ecf20Sopenharmony_ci * ata_scsi_error() takes care of such scmds on EH entry. 9208c2ecf20Sopenharmony_ci * Note that ATA_QCFLAG_FAILED is unconditionally set after 9218c2ecf20Sopenharmony_ci * this function completes. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci blk_abort_request(qc->scsicmd->request); 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci/** 9278c2ecf20Sopenharmony_ci * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine 9288c2ecf20Sopenharmony_ci * @ap: ATA port to schedule EH for 9298c2ecf20Sopenharmony_ci * 9308c2ecf20Sopenharmony_ci * LOCKING: inherited from ata_port_schedule_eh 9318c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 9328c2ecf20Sopenharmony_ci */ 9338c2ecf20Sopenharmony_civoid ata_std_sched_eh(struct ata_port *ap) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci WARN_ON(!ap->ops->error_handler); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_INITIALIZING) 9388c2ecf20Sopenharmony_ci return; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci ata_eh_set_pending(ap, 1); 9418c2ecf20Sopenharmony_ci scsi_schedule_eh(ap->scsi_host); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci DPRINTK("port EH scheduled\n"); 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_std_sched_eh); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci/** 9488c2ecf20Sopenharmony_ci * ata_std_end_eh - non-libsas ata_ports complete eh with this common routine 9498c2ecf20Sopenharmony_ci * @ap: ATA port to end EH for 9508c2ecf20Sopenharmony_ci * 9518c2ecf20Sopenharmony_ci * In the libata object model there is a 1:1 mapping of ata_port to 9528c2ecf20Sopenharmony_ci * shost, so host fields can be directly manipulated under ap->lock, in 9538c2ecf20Sopenharmony_ci * the libsas case we need to hold a lock at the ha->level to coordinate 9548c2ecf20Sopenharmony_ci * these events. 9558c2ecf20Sopenharmony_ci * 9568c2ecf20Sopenharmony_ci * LOCKING: 9578c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 9588c2ecf20Sopenharmony_ci */ 9598c2ecf20Sopenharmony_civoid ata_std_end_eh(struct ata_port *ap) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci struct Scsi_Host *host = ap->scsi_host; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci host->host_eh_scheduled = 0; 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ata_std_end_eh); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci/** 9698c2ecf20Sopenharmony_ci * ata_port_schedule_eh - schedule error handling without a qc 9708c2ecf20Sopenharmony_ci * @ap: ATA port to schedule EH for 9718c2ecf20Sopenharmony_ci * 9728c2ecf20Sopenharmony_ci * Schedule error handling for @ap. EH will kick in as soon as 9738c2ecf20Sopenharmony_ci * all commands are drained. 9748c2ecf20Sopenharmony_ci * 9758c2ecf20Sopenharmony_ci * LOCKING: 9768c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 9778c2ecf20Sopenharmony_ci */ 9788c2ecf20Sopenharmony_civoid ata_port_schedule_eh(struct ata_port *ap) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci /* see: ata_std_sched_eh, unless you know better */ 9818c2ecf20Sopenharmony_ci ap->ops->sched_eh(ap); 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_port_schedule_eh); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct ata_queued_cmd *qc; 9888c2ecf20Sopenharmony_ci int tag, nr_aborted = 0; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci WARN_ON(!ap->ops->error_handler); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* we're gonna abort all commands, no need for fast drain */ 9938c2ecf20Sopenharmony_ci ata_eh_set_pending(ap, 0); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* include internal tag in iteration */ 9968c2ecf20Sopenharmony_ci ata_qc_for_each_with_internal(ap, qc, tag) { 9978c2ecf20Sopenharmony_ci if (qc && (!link || qc->dev->link == link)) { 9988c2ecf20Sopenharmony_ci qc->flags |= ATA_QCFLAG_FAILED; 9998c2ecf20Sopenharmony_ci ata_qc_complete(qc); 10008c2ecf20Sopenharmony_ci nr_aborted++; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (!nr_aborted) 10058c2ecf20Sopenharmony_ci ata_port_schedule_eh(ap); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci return nr_aborted; 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci/** 10118c2ecf20Sopenharmony_ci * ata_link_abort - abort all qc's on the link 10128c2ecf20Sopenharmony_ci * @link: ATA link to abort qc's for 10138c2ecf20Sopenharmony_ci * 10148c2ecf20Sopenharmony_ci * Abort all active qc's active on @link and schedule EH. 10158c2ecf20Sopenharmony_ci * 10168c2ecf20Sopenharmony_ci * LOCKING: 10178c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 10188c2ecf20Sopenharmony_ci * 10198c2ecf20Sopenharmony_ci * RETURNS: 10208c2ecf20Sopenharmony_ci * Number of aborted qc's. 10218c2ecf20Sopenharmony_ci */ 10228c2ecf20Sopenharmony_ciint ata_link_abort(struct ata_link *link) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci return ata_do_link_abort(link->ap, link); 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_link_abort); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci/** 10298c2ecf20Sopenharmony_ci * ata_port_abort - abort all qc's on the port 10308c2ecf20Sopenharmony_ci * @ap: ATA port to abort qc's for 10318c2ecf20Sopenharmony_ci * 10328c2ecf20Sopenharmony_ci * Abort all active qc's of @ap and schedule EH. 10338c2ecf20Sopenharmony_ci * 10348c2ecf20Sopenharmony_ci * LOCKING: 10358c2ecf20Sopenharmony_ci * spin_lock_irqsave(host_set lock) 10368c2ecf20Sopenharmony_ci * 10378c2ecf20Sopenharmony_ci * RETURNS: 10388c2ecf20Sopenharmony_ci * Number of aborted qc's. 10398c2ecf20Sopenharmony_ci */ 10408c2ecf20Sopenharmony_ciint ata_port_abort(struct ata_port *ap) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci return ata_do_link_abort(ap, NULL); 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_port_abort); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci/** 10478c2ecf20Sopenharmony_ci * __ata_port_freeze - freeze port 10488c2ecf20Sopenharmony_ci * @ap: ATA port to freeze 10498c2ecf20Sopenharmony_ci * 10508c2ecf20Sopenharmony_ci * This function is called when HSM violation or some other 10518c2ecf20Sopenharmony_ci * condition disrupts normal operation of the port. Frozen port 10528c2ecf20Sopenharmony_ci * is not allowed to perform any operation until the port is 10538c2ecf20Sopenharmony_ci * thawed, which usually follows a successful reset. 10548c2ecf20Sopenharmony_ci * 10558c2ecf20Sopenharmony_ci * ap->ops->freeze() callback can be used for freezing the port 10568c2ecf20Sopenharmony_ci * hardware-wise (e.g. mask interrupt and stop DMA engine). If a 10578c2ecf20Sopenharmony_ci * port cannot be frozen hardware-wise, the interrupt handler 10588c2ecf20Sopenharmony_ci * must ack and clear interrupts unconditionally while the port 10598c2ecf20Sopenharmony_ci * is frozen. 10608c2ecf20Sopenharmony_ci * 10618c2ecf20Sopenharmony_ci * LOCKING: 10628c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 10638c2ecf20Sopenharmony_ci */ 10648c2ecf20Sopenharmony_cistatic void __ata_port_freeze(struct ata_port *ap) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci WARN_ON(!ap->ops->error_handler); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (ap->ops->freeze) 10698c2ecf20Sopenharmony_ci ap->ops->freeze(ap); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci ap->pflags |= ATA_PFLAG_FROZEN; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci DPRINTK("ata%u port frozen\n", ap->print_id); 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci/** 10778c2ecf20Sopenharmony_ci * ata_port_freeze - abort & freeze port 10788c2ecf20Sopenharmony_ci * @ap: ATA port to freeze 10798c2ecf20Sopenharmony_ci * 10808c2ecf20Sopenharmony_ci * Abort and freeze @ap. The freeze operation must be called 10818c2ecf20Sopenharmony_ci * first, because some hardware requires special operations 10828c2ecf20Sopenharmony_ci * before the taskfile registers are accessible. 10838c2ecf20Sopenharmony_ci * 10848c2ecf20Sopenharmony_ci * LOCKING: 10858c2ecf20Sopenharmony_ci * spin_lock_irqsave(host lock) 10868c2ecf20Sopenharmony_ci * 10878c2ecf20Sopenharmony_ci * RETURNS: 10888c2ecf20Sopenharmony_ci * Number of aborted commands. 10898c2ecf20Sopenharmony_ci */ 10908c2ecf20Sopenharmony_ciint ata_port_freeze(struct ata_port *ap) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci int nr_aborted; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci WARN_ON(!ap->ops->error_handler); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci __ata_port_freeze(ap); 10978c2ecf20Sopenharmony_ci nr_aborted = ata_port_abort(ap); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return nr_aborted; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_port_freeze); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci/** 11048c2ecf20Sopenharmony_ci * ata_eh_freeze_port - EH helper to freeze port 11058c2ecf20Sopenharmony_ci * @ap: ATA port to freeze 11068c2ecf20Sopenharmony_ci * 11078c2ecf20Sopenharmony_ci * Freeze @ap. 11088c2ecf20Sopenharmony_ci * 11098c2ecf20Sopenharmony_ci * LOCKING: 11108c2ecf20Sopenharmony_ci * None. 11118c2ecf20Sopenharmony_ci */ 11128c2ecf20Sopenharmony_civoid ata_eh_freeze_port(struct ata_port *ap) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci unsigned long flags; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (!ap->ops->error_handler) 11178c2ecf20Sopenharmony_ci return; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 11208c2ecf20Sopenharmony_ci __ata_port_freeze(ap); 11218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_eh_freeze_port); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci/** 11268c2ecf20Sopenharmony_ci * ata_eh_thaw_port - EH helper to thaw port 11278c2ecf20Sopenharmony_ci * @ap: ATA port to thaw 11288c2ecf20Sopenharmony_ci * 11298c2ecf20Sopenharmony_ci * Thaw frozen port @ap. 11308c2ecf20Sopenharmony_ci * 11318c2ecf20Sopenharmony_ci * LOCKING: 11328c2ecf20Sopenharmony_ci * None. 11338c2ecf20Sopenharmony_ci */ 11348c2ecf20Sopenharmony_civoid ata_eh_thaw_port(struct ata_port *ap) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci unsigned long flags; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (!ap->ops->error_handler) 11398c2ecf20Sopenharmony_ci return; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci ap->pflags &= ~ATA_PFLAG_FROZEN; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (ap->ops->thaw) 11468c2ecf20Sopenharmony_ci ap->ops->thaw(ap); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci DPRINTK("ata%u port thawed\n", ap->print_id); 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic void ata_eh_scsidone(struct scsi_cmnd *scmd) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci /* nada */ 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic void __ata_eh_qc_complete(struct ata_queued_cmd *qc) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci struct ata_port *ap = qc->ap; 11618c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd = qc->scsicmd; 11628c2ecf20Sopenharmony_ci unsigned long flags; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 11658c2ecf20Sopenharmony_ci qc->scsidone = ata_eh_scsidone; 11668c2ecf20Sopenharmony_ci __ata_qc_complete(qc); 11678c2ecf20Sopenharmony_ci WARN_ON(ata_tag_valid(qc->tag)); 11688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci scsi_eh_finish_cmd(scmd, &ap->eh_done_q); 11718c2ecf20Sopenharmony_ci} 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci/** 11748c2ecf20Sopenharmony_ci * ata_eh_qc_complete - Complete an active ATA command from EH 11758c2ecf20Sopenharmony_ci * @qc: Command to complete 11768c2ecf20Sopenharmony_ci * 11778c2ecf20Sopenharmony_ci * Indicate to the mid and upper layers that an ATA command has 11788c2ecf20Sopenharmony_ci * completed. To be used from EH. 11798c2ecf20Sopenharmony_ci */ 11808c2ecf20Sopenharmony_civoid ata_eh_qc_complete(struct ata_queued_cmd *qc) 11818c2ecf20Sopenharmony_ci{ 11828c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd = qc->scsicmd; 11838c2ecf20Sopenharmony_ci scmd->retries = scmd->allowed; 11848c2ecf20Sopenharmony_ci __ata_eh_qc_complete(qc); 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci/** 11888c2ecf20Sopenharmony_ci * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH 11898c2ecf20Sopenharmony_ci * @qc: Command to retry 11908c2ecf20Sopenharmony_ci * 11918c2ecf20Sopenharmony_ci * Indicate to the mid and upper layers that an ATA command 11928c2ecf20Sopenharmony_ci * should be retried. To be used from EH. 11938c2ecf20Sopenharmony_ci * 11948c2ecf20Sopenharmony_ci * SCSI midlayer limits the number of retries to scmd->allowed. 11958c2ecf20Sopenharmony_ci * scmd->allowed is incremented for commands which get retried 11968c2ecf20Sopenharmony_ci * due to unrelated failures (qc->err_mask is zero). 11978c2ecf20Sopenharmony_ci */ 11988c2ecf20Sopenharmony_civoid ata_eh_qc_retry(struct ata_queued_cmd *qc) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd = qc->scsicmd; 12018c2ecf20Sopenharmony_ci if (!qc->err_mask) 12028c2ecf20Sopenharmony_ci scmd->allowed++; 12038c2ecf20Sopenharmony_ci __ata_eh_qc_complete(qc); 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci/** 12078c2ecf20Sopenharmony_ci * ata_dev_disable - disable ATA device 12088c2ecf20Sopenharmony_ci * @dev: ATA device to disable 12098c2ecf20Sopenharmony_ci * 12108c2ecf20Sopenharmony_ci * Disable @dev. 12118c2ecf20Sopenharmony_ci * 12128c2ecf20Sopenharmony_ci * Locking: 12138c2ecf20Sopenharmony_ci * EH context. 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_civoid ata_dev_disable(struct ata_device *dev) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci if (!ata_dev_enabled(dev)) 12188c2ecf20Sopenharmony_ci return; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (ata_msg_drv(dev->link->ap)) 12218c2ecf20Sopenharmony_ci ata_dev_warn(dev, "disabled\n"); 12228c2ecf20Sopenharmony_ci ata_acpi_on_disable(dev); 12238c2ecf20Sopenharmony_ci ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET); 12248c2ecf20Sopenharmony_ci dev->class++; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* From now till the next successful probe, ering is used to 12278c2ecf20Sopenharmony_ci * track probe failures. Clear accumulated device error info. 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci ata_ering_clear(&dev->ering); 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_dev_disable); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci/** 12348c2ecf20Sopenharmony_ci * ata_eh_detach_dev - detach ATA device 12358c2ecf20Sopenharmony_ci * @dev: ATA device to detach 12368c2ecf20Sopenharmony_ci * 12378c2ecf20Sopenharmony_ci * Detach @dev. 12388c2ecf20Sopenharmony_ci * 12398c2ecf20Sopenharmony_ci * LOCKING: 12408c2ecf20Sopenharmony_ci * None. 12418c2ecf20Sopenharmony_ci */ 12428c2ecf20Sopenharmony_civoid ata_eh_detach_dev(struct ata_device *dev) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci struct ata_link *link = dev->link; 12458c2ecf20Sopenharmony_ci struct ata_port *ap = link->ap; 12468c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 12478c2ecf20Sopenharmony_ci unsigned long flags; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci ata_dev_disable(dev); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci dev->flags &= ~ATA_DFLAG_DETACH; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (ata_scsi_offline_dev(dev)) { 12568c2ecf20Sopenharmony_ci dev->flags |= ATA_DFLAG_DETACHED; 12578c2ecf20Sopenharmony_ci ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci /* clear per-dev EH info */ 12618c2ecf20Sopenharmony_ci ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK); 12628c2ecf20Sopenharmony_ci ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK); 12638c2ecf20Sopenharmony_ci ehc->saved_xfer_mode[dev->devno] = 0; 12648c2ecf20Sopenharmony_ci ehc->saved_ncq_enabled &= ~(1 << dev->devno); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci/** 12708c2ecf20Sopenharmony_ci * ata_eh_about_to_do - about to perform eh_action 12718c2ecf20Sopenharmony_ci * @link: target ATA link 12728c2ecf20Sopenharmony_ci * @dev: target ATA dev for per-dev action (can be NULL) 12738c2ecf20Sopenharmony_ci * @action: action about to be performed 12748c2ecf20Sopenharmony_ci * 12758c2ecf20Sopenharmony_ci * Called just before performing EH actions to clear related bits 12768c2ecf20Sopenharmony_ci * in @link->eh_info such that eh actions are not unnecessarily 12778c2ecf20Sopenharmony_ci * repeated. 12788c2ecf20Sopenharmony_ci * 12798c2ecf20Sopenharmony_ci * LOCKING: 12808c2ecf20Sopenharmony_ci * None. 12818c2ecf20Sopenharmony_ci */ 12828c2ecf20Sopenharmony_civoid ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, 12838c2ecf20Sopenharmony_ci unsigned int action) 12848c2ecf20Sopenharmony_ci{ 12858c2ecf20Sopenharmony_ci struct ata_port *ap = link->ap; 12868c2ecf20Sopenharmony_ci struct ata_eh_info *ehi = &link->eh_info; 12878c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 12888c2ecf20Sopenharmony_ci unsigned long flags; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci ata_eh_clear_action(link, dev, ehi, action); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* About to take EH action, set RECOVERED. Ignore actions on 12958c2ecf20Sopenharmony_ci * slave links as master will do them again. 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_ci if (!(ehc->i.flags & ATA_EHI_QUIET) && link != ap->slave_link) 12988c2ecf20Sopenharmony_ci ap->pflags |= ATA_PFLAG_RECOVERED; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 13018c2ecf20Sopenharmony_ci} 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci/** 13048c2ecf20Sopenharmony_ci * ata_eh_done - EH action complete 13058c2ecf20Sopenharmony_ci * @link: ATA link for which EH actions are complete 13068c2ecf20Sopenharmony_ci * @dev: target ATA dev for per-dev action (can be NULL) 13078c2ecf20Sopenharmony_ci * @action: action just completed 13088c2ecf20Sopenharmony_ci * 13098c2ecf20Sopenharmony_ci * Called right after performing EH actions to clear related bits 13108c2ecf20Sopenharmony_ci * in @link->eh_context. 13118c2ecf20Sopenharmony_ci * 13128c2ecf20Sopenharmony_ci * LOCKING: 13138c2ecf20Sopenharmony_ci * None. 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_civoid ata_eh_done(struct ata_link *link, struct ata_device *dev, 13168c2ecf20Sopenharmony_ci unsigned int action) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci ata_eh_clear_action(link, dev, &ehc->i, action); 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci/** 13248c2ecf20Sopenharmony_ci * ata_err_string - convert err_mask to descriptive string 13258c2ecf20Sopenharmony_ci * @err_mask: error mask to convert to string 13268c2ecf20Sopenharmony_ci * 13278c2ecf20Sopenharmony_ci * Convert @err_mask to descriptive string. Errors are 13288c2ecf20Sopenharmony_ci * prioritized according to severity and only the most severe 13298c2ecf20Sopenharmony_ci * error is reported. 13308c2ecf20Sopenharmony_ci * 13318c2ecf20Sopenharmony_ci * LOCKING: 13328c2ecf20Sopenharmony_ci * None. 13338c2ecf20Sopenharmony_ci * 13348c2ecf20Sopenharmony_ci * RETURNS: 13358c2ecf20Sopenharmony_ci * Descriptive string for @err_mask 13368c2ecf20Sopenharmony_ci */ 13378c2ecf20Sopenharmony_cistatic const char *ata_err_string(unsigned int err_mask) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_HOST_BUS) 13408c2ecf20Sopenharmony_ci return "host bus error"; 13418c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_ATA_BUS) 13428c2ecf20Sopenharmony_ci return "ATA bus error"; 13438c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_TIMEOUT) 13448c2ecf20Sopenharmony_ci return "timeout"; 13458c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_HSM) 13468c2ecf20Sopenharmony_ci return "HSM violation"; 13478c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_SYSTEM) 13488c2ecf20Sopenharmony_ci return "internal error"; 13498c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_MEDIA) 13508c2ecf20Sopenharmony_ci return "media error"; 13518c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_INVALID) 13528c2ecf20Sopenharmony_ci return "invalid argument"; 13538c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_DEV) 13548c2ecf20Sopenharmony_ci return "device error"; 13558c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_NCQ) 13568c2ecf20Sopenharmony_ci return "NCQ error"; 13578c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_NODEV_HINT) 13588c2ecf20Sopenharmony_ci return "Polling detection error"; 13598c2ecf20Sopenharmony_ci return "unknown error"; 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci/** 13638c2ecf20Sopenharmony_ci * atapi_eh_tur - perform ATAPI TEST_UNIT_READY 13648c2ecf20Sopenharmony_ci * @dev: target ATAPI device 13658c2ecf20Sopenharmony_ci * @r_sense_key: out parameter for sense_key 13668c2ecf20Sopenharmony_ci * 13678c2ecf20Sopenharmony_ci * Perform ATAPI TEST_UNIT_READY. 13688c2ecf20Sopenharmony_ci * 13698c2ecf20Sopenharmony_ci * LOCKING: 13708c2ecf20Sopenharmony_ci * EH context (may sleep). 13718c2ecf20Sopenharmony_ci * 13728c2ecf20Sopenharmony_ci * RETURNS: 13738c2ecf20Sopenharmony_ci * 0 on success, AC_ERR_* mask on failure. 13748c2ecf20Sopenharmony_ci */ 13758c2ecf20Sopenharmony_ciunsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 }; 13788c2ecf20Sopenharmony_ci struct ata_taskfile tf; 13798c2ecf20Sopenharmony_ci unsigned int err_mask; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci ata_tf_init(dev, &tf); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; 13848c2ecf20Sopenharmony_ci tf.command = ATA_CMD_PACKET; 13858c2ecf20Sopenharmony_ci tf.protocol = ATAPI_PROT_NODATA; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci err_mask = ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0); 13888c2ecf20Sopenharmony_ci if (err_mask == AC_ERR_DEV) 13898c2ecf20Sopenharmony_ci *r_sense_key = tf.feature >> 4; 13908c2ecf20Sopenharmony_ci return err_mask; 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci/** 13948c2ecf20Sopenharmony_ci * ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT 13958c2ecf20Sopenharmony_ci * @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to 13968c2ecf20Sopenharmony_ci * @cmd: scsi command for which the sense code should be set 13978c2ecf20Sopenharmony_ci * 13988c2ecf20Sopenharmony_ci * Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK 13998c2ecf20Sopenharmony_ci * SENSE. This function is an EH helper. 14008c2ecf20Sopenharmony_ci * 14018c2ecf20Sopenharmony_ci * LOCKING: 14028c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 14038c2ecf20Sopenharmony_ci */ 14048c2ecf20Sopenharmony_cistatic void ata_eh_request_sense(struct ata_queued_cmd *qc, 14058c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci struct ata_device *dev = qc->dev; 14088c2ecf20Sopenharmony_ci struct ata_taskfile tf; 14098c2ecf20Sopenharmony_ci unsigned int err_mask; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (qc->ap->pflags & ATA_PFLAG_FROZEN) { 14128c2ecf20Sopenharmony_ci ata_dev_warn(dev, "sense data available but port frozen\n"); 14138c2ecf20Sopenharmony_ci return; 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (!cmd || qc->flags & ATA_QCFLAG_SENSE_VALID) 14178c2ecf20Sopenharmony_ci return; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (!ata_id_sense_reporting_enabled(dev->id)) { 14208c2ecf20Sopenharmony_ci ata_dev_warn(qc->dev, "sense data reporting disabled\n"); 14218c2ecf20Sopenharmony_ci return; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci DPRINTK("ATA request sense\n"); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci ata_tf_init(dev, &tf); 14278c2ecf20Sopenharmony_ci tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; 14288c2ecf20Sopenharmony_ci tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; 14298c2ecf20Sopenharmony_ci tf.command = ATA_CMD_REQ_SENSE_DATA; 14308c2ecf20Sopenharmony_ci tf.protocol = ATA_PROT_NODATA; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); 14338c2ecf20Sopenharmony_ci /* Ignore err_mask; ATA_ERR might be set */ 14348c2ecf20Sopenharmony_ci if (tf.command & ATA_SENSE) { 14358c2ecf20Sopenharmony_ci ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal); 14368c2ecf20Sopenharmony_ci qc->flags |= ATA_QCFLAG_SENSE_VALID; 14378c2ecf20Sopenharmony_ci } else { 14388c2ecf20Sopenharmony_ci ata_dev_warn(dev, "request sense failed stat %02x emask %x\n", 14398c2ecf20Sopenharmony_ci tf.command, err_mask); 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci/** 14448c2ecf20Sopenharmony_ci * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE 14458c2ecf20Sopenharmony_ci * @dev: device to perform REQUEST_SENSE to 14468c2ecf20Sopenharmony_ci * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long) 14478c2ecf20Sopenharmony_ci * @dfl_sense_key: default sense key to use 14488c2ecf20Sopenharmony_ci * 14498c2ecf20Sopenharmony_ci * Perform ATAPI REQUEST_SENSE after the device reported CHECK 14508c2ecf20Sopenharmony_ci * SENSE. This function is EH helper. 14518c2ecf20Sopenharmony_ci * 14528c2ecf20Sopenharmony_ci * LOCKING: 14538c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 14548c2ecf20Sopenharmony_ci * 14558c2ecf20Sopenharmony_ci * RETURNS: 14568c2ecf20Sopenharmony_ci * 0 on success, AC_ERR_* mask on failure 14578c2ecf20Sopenharmony_ci */ 14588c2ecf20Sopenharmony_ciunsigned int atapi_eh_request_sense(struct ata_device *dev, 14598c2ecf20Sopenharmony_ci u8 *sense_buf, u8 dfl_sense_key) 14608c2ecf20Sopenharmony_ci{ 14618c2ecf20Sopenharmony_ci u8 cdb[ATAPI_CDB_LEN] = 14628c2ecf20Sopenharmony_ci { REQUEST_SENSE, 0, 0, 0, SCSI_SENSE_BUFFERSIZE, 0 }; 14638c2ecf20Sopenharmony_ci struct ata_port *ap = dev->link->ap; 14648c2ecf20Sopenharmony_ci struct ata_taskfile tf; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci DPRINTK("ATAPI request sense\n"); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* initialize sense_buf with the error register, 14718c2ecf20Sopenharmony_ci * for the case where they are -not- overwritten 14728c2ecf20Sopenharmony_ci */ 14738c2ecf20Sopenharmony_ci sense_buf[0] = 0x70; 14748c2ecf20Sopenharmony_ci sense_buf[2] = dfl_sense_key; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* some devices time out if garbage left in tf */ 14778c2ecf20Sopenharmony_ci ata_tf_init(dev, &tf); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; 14808c2ecf20Sopenharmony_ci tf.command = ATA_CMD_PACKET; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* is it pointless to prefer PIO for "safety reasons"? */ 14838c2ecf20Sopenharmony_ci if (ap->flags & ATA_FLAG_PIO_DMA) { 14848c2ecf20Sopenharmony_ci tf.protocol = ATAPI_PROT_DMA; 14858c2ecf20Sopenharmony_ci tf.feature |= ATAPI_PKT_DMA; 14868c2ecf20Sopenharmony_ci } else { 14878c2ecf20Sopenharmony_ci tf.protocol = ATAPI_PROT_PIO; 14888c2ecf20Sopenharmony_ci tf.lbam = SCSI_SENSE_BUFFERSIZE; 14898c2ecf20Sopenharmony_ci tf.lbah = 0; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE, 14938c2ecf20Sopenharmony_ci sense_buf, SCSI_SENSE_BUFFERSIZE, 0); 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci/** 14978c2ecf20Sopenharmony_ci * ata_eh_analyze_serror - analyze SError for a failed port 14988c2ecf20Sopenharmony_ci * @link: ATA link to analyze SError for 14998c2ecf20Sopenharmony_ci * 15008c2ecf20Sopenharmony_ci * Analyze SError if available and further determine cause of 15018c2ecf20Sopenharmony_ci * failure. 15028c2ecf20Sopenharmony_ci * 15038c2ecf20Sopenharmony_ci * LOCKING: 15048c2ecf20Sopenharmony_ci * None. 15058c2ecf20Sopenharmony_ci */ 15068c2ecf20Sopenharmony_cistatic void ata_eh_analyze_serror(struct ata_link *link) 15078c2ecf20Sopenharmony_ci{ 15088c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 15098c2ecf20Sopenharmony_ci u32 serror = ehc->i.serror; 15108c2ecf20Sopenharmony_ci unsigned int err_mask = 0, action = 0; 15118c2ecf20Sopenharmony_ci u32 hotplug_mask; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci if (serror & (SERR_PERSISTENT | SERR_DATA)) { 15148c2ecf20Sopenharmony_ci err_mask |= AC_ERR_ATA_BUS; 15158c2ecf20Sopenharmony_ci action |= ATA_EH_RESET; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci if (serror & SERR_PROTOCOL) { 15188c2ecf20Sopenharmony_ci err_mask |= AC_ERR_HSM; 15198c2ecf20Sopenharmony_ci action |= ATA_EH_RESET; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci if (serror & SERR_INTERNAL) { 15228c2ecf20Sopenharmony_ci err_mask |= AC_ERR_SYSTEM; 15238c2ecf20Sopenharmony_ci action |= ATA_EH_RESET; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* Determine whether a hotplug event has occurred. Both 15278c2ecf20Sopenharmony_ci * SError.N/X are considered hotplug events for enabled or 15288c2ecf20Sopenharmony_ci * host links. For disabled PMP links, only N bit is 15298c2ecf20Sopenharmony_ci * considered as X bit is left at 1 for link plugging. 15308c2ecf20Sopenharmony_ci */ 15318c2ecf20Sopenharmony_ci if (link->lpm_policy > ATA_LPM_MAX_POWER) 15328c2ecf20Sopenharmony_ci hotplug_mask = 0; /* hotplug doesn't work w/ LPM */ 15338c2ecf20Sopenharmony_ci else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) 15348c2ecf20Sopenharmony_ci hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; 15358c2ecf20Sopenharmony_ci else 15368c2ecf20Sopenharmony_ci hotplug_mask = SERR_PHYRDY_CHG; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (serror & hotplug_mask) 15398c2ecf20Sopenharmony_ci ata_ehi_hotplugged(&ehc->i); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci ehc->i.err_mask |= err_mask; 15428c2ecf20Sopenharmony_ci ehc->i.action |= action; 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci/** 15468c2ecf20Sopenharmony_ci * ata_eh_analyze_tf - analyze taskfile of a failed qc 15478c2ecf20Sopenharmony_ci * @qc: qc to analyze 15488c2ecf20Sopenharmony_ci * @tf: Taskfile registers to analyze 15498c2ecf20Sopenharmony_ci * 15508c2ecf20Sopenharmony_ci * Analyze taskfile of @qc and further determine cause of 15518c2ecf20Sopenharmony_ci * failure. This function also requests ATAPI sense data if 15528c2ecf20Sopenharmony_ci * available. 15538c2ecf20Sopenharmony_ci * 15548c2ecf20Sopenharmony_ci * LOCKING: 15558c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 15568c2ecf20Sopenharmony_ci * 15578c2ecf20Sopenharmony_ci * RETURNS: 15588c2ecf20Sopenharmony_ci * Determined recovery action 15598c2ecf20Sopenharmony_ci */ 15608c2ecf20Sopenharmony_cistatic unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, 15618c2ecf20Sopenharmony_ci const struct ata_taskfile *tf) 15628c2ecf20Sopenharmony_ci{ 15638c2ecf20Sopenharmony_ci unsigned int tmp, action = 0; 15648c2ecf20Sopenharmony_ci u8 stat = tf->command, err = tf->feature; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) { 15678c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_HSM; 15688c2ecf20Sopenharmony_ci return ATA_EH_RESET; 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (stat & (ATA_ERR | ATA_DF)) { 15728c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_DEV; 15738c2ecf20Sopenharmony_ci /* 15748c2ecf20Sopenharmony_ci * Sense data reporting does not work if the 15758c2ecf20Sopenharmony_ci * device fault bit is set. 15768c2ecf20Sopenharmony_ci */ 15778c2ecf20Sopenharmony_ci if (stat & ATA_DF) 15788c2ecf20Sopenharmony_ci stat &= ~ATA_SENSE; 15798c2ecf20Sopenharmony_ci } else { 15808c2ecf20Sopenharmony_ci return 0; 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci switch (qc->dev->class) { 15848c2ecf20Sopenharmony_ci case ATA_DEV_ZAC: 15858c2ecf20Sopenharmony_ci if (stat & ATA_SENSE) 15868c2ecf20Sopenharmony_ci ata_eh_request_sense(qc, qc->scsicmd); 15878c2ecf20Sopenharmony_ci fallthrough; 15888c2ecf20Sopenharmony_ci case ATA_DEV_ATA: 15898c2ecf20Sopenharmony_ci if (err & ATA_ICRC) 15908c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_ATA_BUS; 15918c2ecf20Sopenharmony_ci if (err & (ATA_UNC | ATA_AMNF)) 15928c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_MEDIA; 15938c2ecf20Sopenharmony_ci if (err & ATA_IDNF) 15948c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_INVALID; 15958c2ecf20Sopenharmony_ci break; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci case ATA_DEV_ATAPI: 15988c2ecf20Sopenharmony_ci if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) { 15998c2ecf20Sopenharmony_ci tmp = atapi_eh_request_sense(qc->dev, 16008c2ecf20Sopenharmony_ci qc->scsicmd->sense_buffer, 16018c2ecf20Sopenharmony_ci qc->result_tf.feature >> 4); 16028c2ecf20Sopenharmony_ci if (!tmp) 16038c2ecf20Sopenharmony_ci qc->flags |= ATA_QCFLAG_SENSE_VALID; 16048c2ecf20Sopenharmony_ci else 16058c2ecf20Sopenharmony_ci qc->err_mask |= tmp; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci if (qc->flags & ATA_QCFLAG_SENSE_VALID) { 16108c2ecf20Sopenharmony_ci enum scsi_disposition ret = scsi_check_sense(qc->scsicmd); 16118c2ecf20Sopenharmony_ci /* 16128c2ecf20Sopenharmony_ci * SUCCESS here means that the sense code could be 16138c2ecf20Sopenharmony_ci * evaluated and should be passed to the upper layers 16148c2ecf20Sopenharmony_ci * for correct evaluation. 16158c2ecf20Sopenharmony_ci * FAILED means the sense code could not be interpreted 16168c2ecf20Sopenharmony_ci * and the device would need to be reset. 16178c2ecf20Sopenharmony_ci * NEEDS_RETRY and ADD_TO_MLQUEUE means that the 16188c2ecf20Sopenharmony_ci * command would need to be retried. 16198c2ecf20Sopenharmony_ci */ 16208c2ecf20Sopenharmony_ci if (ret == NEEDS_RETRY || ret == ADD_TO_MLQUEUE) { 16218c2ecf20Sopenharmony_ci qc->flags |= ATA_QCFLAG_RETRY; 16228c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_OTHER; 16238c2ecf20Sopenharmony_ci } else if (ret != SUCCESS) { 16248c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_HSM; 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) 16288c2ecf20Sopenharmony_ci action |= ATA_EH_RESET; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci return action; 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic int ata_eh_categorize_error(unsigned int eflags, unsigned int err_mask, 16348c2ecf20Sopenharmony_ci int *xfer_ok) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci int base = 0; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (!(eflags & ATA_EFLAG_DUBIOUS_XFER)) 16398c2ecf20Sopenharmony_ci *xfer_ok = 1; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (!*xfer_ok) 16428c2ecf20Sopenharmony_ci base = ATA_ECAT_DUBIOUS_NONE; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_ATA_BUS) 16458c2ecf20Sopenharmony_ci return base + ATA_ECAT_ATA_BUS; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_TIMEOUT) 16488c2ecf20Sopenharmony_ci return base + ATA_ECAT_TOUT_HSM; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci if (eflags & ATA_EFLAG_IS_IO) { 16518c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_HSM) 16528c2ecf20Sopenharmony_ci return base + ATA_ECAT_TOUT_HSM; 16538c2ecf20Sopenharmony_ci if ((err_mask & 16548c2ecf20Sopenharmony_ci (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV) 16558c2ecf20Sopenharmony_ci return base + ATA_ECAT_UNK_DEV; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci return 0; 16598c2ecf20Sopenharmony_ci} 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_cistruct speed_down_verdict_arg { 16628c2ecf20Sopenharmony_ci u64 since; 16638c2ecf20Sopenharmony_ci int xfer_ok; 16648c2ecf20Sopenharmony_ci int nr_errors[ATA_ECAT_NR]; 16658c2ecf20Sopenharmony_ci}; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_cistatic int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci struct speed_down_verdict_arg *arg = void_arg; 16708c2ecf20Sopenharmony_ci int cat; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if ((ent->eflags & ATA_EFLAG_OLD_ER) || (ent->timestamp < arg->since)) 16738c2ecf20Sopenharmony_ci return -1; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci cat = ata_eh_categorize_error(ent->eflags, ent->err_mask, 16768c2ecf20Sopenharmony_ci &arg->xfer_ok); 16778c2ecf20Sopenharmony_ci arg->nr_errors[cat]++; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci return 0; 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci/** 16838c2ecf20Sopenharmony_ci * ata_eh_speed_down_verdict - Determine speed down verdict 16848c2ecf20Sopenharmony_ci * @dev: Device of interest 16858c2ecf20Sopenharmony_ci * 16868c2ecf20Sopenharmony_ci * This function examines error ring of @dev and determines 16878c2ecf20Sopenharmony_ci * whether NCQ needs to be turned off, transfer speed should be 16888c2ecf20Sopenharmony_ci * stepped down, or falling back to PIO is necessary. 16898c2ecf20Sopenharmony_ci * 16908c2ecf20Sopenharmony_ci * ECAT_ATA_BUS : ATA_BUS error for any command 16918c2ecf20Sopenharmony_ci * 16928c2ecf20Sopenharmony_ci * ECAT_TOUT_HSM : TIMEOUT for any command or HSM violation for 16938c2ecf20Sopenharmony_ci * IO commands 16948c2ecf20Sopenharmony_ci * 16958c2ecf20Sopenharmony_ci * ECAT_UNK_DEV : Unknown DEV error for IO commands 16968c2ecf20Sopenharmony_ci * 16978c2ecf20Sopenharmony_ci * ECAT_DUBIOUS_* : Identical to above three but occurred while 16988c2ecf20Sopenharmony_ci * data transfer hasn't been verified. 16998c2ecf20Sopenharmony_ci * 17008c2ecf20Sopenharmony_ci * Verdicts are 17018c2ecf20Sopenharmony_ci * 17028c2ecf20Sopenharmony_ci * NCQ_OFF : Turn off NCQ. 17038c2ecf20Sopenharmony_ci * 17048c2ecf20Sopenharmony_ci * SPEED_DOWN : Speed down transfer speed but don't fall back 17058c2ecf20Sopenharmony_ci * to PIO. 17068c2ecf20Sopenharmony_ci * 17078c2ecf20Sopenharmony_ci * FALLBACK_TO_PIO : Fall back to PIO. 17088c2ecf20Sopenharmony_ci * 17098c2ecf20Sopenharmony_ci * Even if multiple verdicts are returned, only one action is 17108c2ecf20Sopenharmony_ci * taken per error. An action triggered by non-DUBIOUS errors 17118c2ecf20Sopenharmony_ci * clears ering, while one triggered by DUBIOUS_* errors doesn't. 17128c2ecf20Sopenharmony_ci * This is to expedite speed down decisions right after device is 17138c2ecf20Sopenharmony_ci * initially configured. 17148c2ecf20Sopenharmony_ci * 17158c2ecf20Sopenharmony_ci * The following are speed down rules. #1 and #2 deal with 17168c2ecf20Sopenharmony_ci * DUBIOUS errors. 17178c2ecf20Sopenharmony_ci * 17188c2ecf20Sopenharmony_ci * 1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors 17198c2ecf20Sopenharmony_ci * occurred during last 5 mins, SPEED_DOWN and FALLBACK_TO_PIO. 17208c2ecf20Sopenharmony_ci * 17218c2ecf20Sopenharmony_ci * 2. If more than one DUBIOUS_TOUT_HSM or DUBIOUS_UNK_DEV errors 17228c2ecf20Sopenharmony_ci * occurred during last 5 mins, NCQ_OFF. 17238c2ecf20Sopenharmony_ci * 17248c2ecf20Sopenharmony_ci * 3. If more than 8 ATA_BUS, TOUT_HSM or UNK_DEV errors 17258c2ecf20Sopenharmony_ci * occurred during last 5 mins, FALLBACK_TO_PIO 17268c2ecf20Sopenharmony_ci * 17278c2ecf20Sopenharmony_ci * 4. If more than 3 TOUT_HSM or UNK_DEV errors occurred 17288c2ecf20Sopenharmony_ci * during last 10 mins, NCQ_OFF. 17298c2ecf20Sopenharmony_ci * 17308c2ecf20Sopenharmony_ci * 5. If more than 3 ATA_BUS or TOUT_HSM errors, or more than 6 17318c2ecf20Sopenharmony_ci * UNK_DEV errors occurred during last 10 mins, SPEED_DOWN. 17328c2ecf20Sopenharmony_ci * 17338c2ecf20Sopenharmony_ci * LOCKING: 17348c2ecf20Sopenharmony_ci * Inherited from caller. 17358c2ecf20Sopenharmony_ci * 17368c2ecf20Sopenharmony_ci * RETURNS: 17378c2ecf20Sopenharmony_ci * OR of ATA_EH_SPDN_* flags. 17388c2ecf20Sopenharmony_ci */ 17398c2ecf20Sopenharmony_cistatic unsigned int ata_eh_speed_down_verdict(struct ata_device *dev) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci const u64 j5mins = 5LLU * 60 * HZ, j10mins = 10LLU * 60 * HZ; 17428c2ecf20Sopenharmony_ci u64 j64 = get_jiffies_64(); 17438c2ecf20Sopenharmony_ci struct speed_down_verdict_arg arg; 17448c2ecf20Sopenharmony_ci unsigned int verdict = 0; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci /* scan past 5 mins of error history */ 17478c2ecf20Sopenharmony_ci memset(&arg, 0, sizeof(arg)); 17488c2ecf20Sopenharmony_ci arg.since = j64 - min(j64, j5mins); 17498c2ecf20Sopenharmony_ci ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg); 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci if (arg.nr_errors[ATA_ECAT_DUBIOUS_ATA_BUS] + 17528c2ecf20Sopenharmony_ci arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] > 1) 17538c2ecf20Sopenharmony_ci verdict |= ATA_EH_SPDN_SPEED_DOWN | 17548c2ecf20Sopenharmony_ci ATA_EH_SPDN_FALLBACK_TO_PIO | ATA_EH_SPDN_KEEP_ERRORS; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci if (arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] + 17578c2ecf20Sopenharmony_ci arg.nr_errors[ATA_ECAT_DUBIOUS_UNK_DEV] > 1) 17588c2ecf20Sopenharmony_ci verdict |= ATA_EH_SPDN_NCQ_OFF | ATA_EH_SPDN_KEEP_ERRORS; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci if (arg.nr_errors[ATA_ECAT_ATA_BUS] + 17618c2ecf20Sopenharmony_ci arg.nr_errors[ATA_ECAT_TOUT_HSM] + 17628c2ecf20Sopenharmony_ci arg.nr_errors[ATA_ECAT_UNK_DEV] > 6) 17638c2ecf20Sopenharmony_ci verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci /* scan past 10 mins of error history */ 17668c2ecf20Sopenharmony_ci memset(&arg, 0, sizeof(arg)); 17678c2ecf20Sopenharmony_ci arg.since = j64 - min(j64, j10mins); 17688c2ecf20Sopenharmony_ci ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci if (arg.nr_errors[ATA_ECAT_TOUT_HSM] + 17718c2ecf20Sopenharmony_ci arg.nr_errors[ATA_ECAT_UNK_DEV] > 3) 17728c2ecf20Sopenharmony_ci verdict |= ATA_EH_SPDN_NCQ_OFF; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci if (arg.nr_errors[ATA_ECAT_ATA_BUS] + 17758c2ecf20Sopenharmony_ci arg.nr_errors[ATA_ECAT_TOUT_HSM] > 3 || 17768c2ecf20Sopenharmony_ci arg.nr_errors[ATA_ECAT_UNK_DEV] > 6) 17778c2ecf20Sopenharmony_ci verdict |= ATA_EH_SPDN_SPEED_DOWN; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci return verdict; 17808c2ecf20Sopenharmony_ci} 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci/** 17838c2ecf20Sopenharmony_ci * ata_eh_speed_down - record error and speed down if necessary 17848c2ecf20Sopenharmony_ci * @dev: Failed device 17858c2ecf20Sopenharmony_ci * @eflags: mask of ATA_EFLAG_* flags 17868c2ecf20Sopenharmony_ci * @err_mask: err_mask of the error 17878c2ecf20Sopenharmony_ci * 17888c2ecf20Sopenharmony_ci * Record error and examine error history to determine whether 17898c2ecf20Sopenharmony_ci * adjusting transmission speed is necessary. It also sets 17908c2ecf20Sopenharmony_ci * transmission limits appropriately if such adjustment is 17918c2ecf20Sopenharmony_ci * necessary. 17928c2ecf20Sopenharmony_ci * 17938c2ecf20Sopenharmony_ci * LOCKING: 17948c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 17958c2ecf20Sopenharmony_ci * 17968c2ecf20Sopenharmony_ci * RETURNS: 17978c2ecf20Sopenharmony_ci * Determined recovery action. 17988c2ecf20Sopenharmony_ci */ 17998c2ecf20Sopenharmony_cistatic unsigned int ata_eh_speed_down(struct ata_device *dev, 18008c2ecf20Sopenharmony_ci unsigned int eflags, unsigned int err_mask) 18018c2ecf20Sopenharmony_ci{ 18028c2ecf20Sopenharmony_ci struct ata_link *link = ata_dev_phys_link(dev); 18038c2ecf20Sopenharmony_ci int xfer_ok = 0; 18048c2ecf20Sopenharmony_ci unsigned int verdict; 18058c2ecf20Sopenharmony_ci unsigned int action = 0; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci /* don't bother if Cat-0 error */ 18088c2ecf20Sopenharmony_ci if (ata_eh_categorize_error(eflags, err_mask, &xfer_ok) == 0) 18098c2ecf20Sopenharmony_ci return 0; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* record error and determine whether speed down is necessary */ 18128c2ecf20Sopenharmony_ci ata_ering_record(&dev->ering, eflags, err_mask); 18138c2ecf20Sopenharmony_ci verdict = ata_eh_speed_down_verdict(dev); 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci /* turn off NCQ? */ 18168c2ecf20Sopenharmony_ci if ((verdict & ATA_EH_SPDN_NCQ_OFF) && 18178c2ecf20Sopenharmony_ci (dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ | 18188c2ecf20Sopenharmony_ci ATA_DFLAG_NCQ_OFF)) == ATA_DFLAG_NCQ) { 18198c2ecf20Sopenharmony_ci dev->flags |= ATA_DFLAG_NCQ_OFF; 18208c2ecf20Sopenharmony_ci ata_dev_warn(dev, "NCQ disabled due to excessive errors\n"); 18218c2ecf20Sopenharmony_ci goto done; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci /* speed down? */ 18258c2ecf20Sopenharmony_ci if (verdict & ATA_EH_SPDN_SPEED_DOWN) { 18268c2ecf20Sopenharmony_ci /* speed down SATA link speed if possible */ 18278c2ecf20Sopenharmony_ci if (sata_down_spd_limit(link, 0) == 0) { 18288c2ecf20Sopenharmony_ci action |= ATA_EH_RESET; 18298c2ecf20Sopenharmony_ci goto done; 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci /* lower transfer mode */ 18338c2ecf20Sopenharmony_ci if (dev->spdn_cnt < 2) { 18348c2ecf20Sopenharmony_ci static const int dma_dnxfer_sel[] = 18358c2ecf20Sopenharmony_ci { ATA_DNXFER_DMA, ATA_DNXFER_40C }; 18368c2ecf20Sopenharmony_ci static const int pio_dnxfer_sel[] = 18378c2ecf20Sopenharmony_ci { ATA_DNXFER_PIO, ATA_DNXFER_FORCE_PIO0 }; 18388c2ecf20Sopenharmony_ci int sel; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (dev->xfer_shift != ATA_SHIFT_PIO) 18418c2ecf20Sopenharmony_ci sel = dma_dnxfer_sel[dev->spdn_cnt]; 18428c2ecf20Sopenharmony_ci else 18438c2ecf20Sopenharmony_ci sel = pio_dnxfer_sel[dev->spdn_cnt]; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci dev->spdn_cnt++; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci if (ata_down_xfermask_limit(dev, sel) == 0) { 18488c2ecf20Sopenharmony_ci action |= ATA_EH_RESET; 18498c2ecf20Sopenharmony_ci goto done; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* Fall back to PIO? Slowing down to PIO is meaningless for 18558c2ecf20Sopenharmony_ci * SATA ATA devices. Consider it only for PATA and SATAPI. 18568c2ecf20Sopenharmony_ci */ 18578c2ecf20Sopenharmony_ci if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) && 18588c2ecf20Sopenharmony_ci (link->ap->cbl != ATA_CBL_SATA || dev->class == ATA_DEV_ATAPI) && 18598c2ecf20Sopenharmony_ci (dev->xfer_shift != ATA_SHIFT_PIO)) { 18608c2ecf20Sopenharmony_ci if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) { 18618c2ecf20Sopenharmony_ci dev->spdn_cnt = 0; 18628c2ecf20Sopenharmony_ci action |= ATA_EH_RESET; 18638c2ecf20Sopenharmony_ci goto done; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci } 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci return 0; 18688c2ecf20Sopenharmony_ci done: 18698c2ecf20Sopenharmony_ci /* device has been slowed down, blow error history */ 18708c2ecf20Sopenharmony_ci if (!(verdict & ATA_EH_SPDN_KEEP_ERRORS)) 18718c2ecf20Sopenharmony_ci ata_ering_clear(&dev->ering); 18728c2ecf20Sopenharmony_ci return action; 18738c2ecf20Sopenharmony_ci} 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci/** 18768c2ecf20Sopenharmony_ci * ata_eh_worth_retry - analyze error and decide whether to retry 18778c2ecf20Sopenharmony_ci * @qc: qc to possibly retry 18788c2ecf20Sopenharmony_ci * 18798c2ecf20Sopenharmony_ci * Look at the cause of the error and decide if a retry 18808c2ecf20Sopenharmony_ci * might be useful or not. We don't want to retry media errors 18818c2ecf20Sopenharmony_ci * because the drive itself has probably already taken 10-30 seconds 18828c2ecf20Sopenharmony_ci * doing its own internal retries before reporting the failure. 18838c2ecf20Sopenharmony_ci */ 18848c2ecf20Sopenharmony_cistatic inline int ata_eh_worth_retry(struct ata_queued_cmd *qc) 18858c2ecf20Sopenharmony_ci{ 18868c2ecf20Sopenharmony_ci if (qc->err_mask & AC_ERR_MEDIA) 18878c2ecf20Sopenharmony_ci return 0; /* don't retry media errors */ 18888c2ecf20Sopenharmony_ci if (qc->flags & ATA_QCFLAG_IO) 18898c2ecf20Sopenharmony_ci return 1; /* otherwise retry anything from fs stack */ 18908c2ecf20Sopenharmony_ci if (qc->err_mask & AC_ERR_INVALID) 18918c2ecf20Sopenharmony_ci return 0; /* don't retry these */ 18928c2ecf20Sopenharmony_ci return qc->err_mask != AC_ERR_DEV; /* retry if not dev error */ 18938c2ecf20Sopenharmony_ci} 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci/** 18968c2ecf20Sopenharmony_ci * ata_eh_quiet - check if we need to be quiet about a command error 18978c2ecf20Sopenharmony_ci * @qc: qc to check 18988c2ecf20Sopenharmony_ci * 18998c2ecf20Sopenharmony_ci * Look at the qc flags anbd its scsi command request flags to determine 19008c2ecf20Sopenharmony_ci * if we need to be quiet about the command failure. 19018c2ecf20Sopenharmony_ci */ 19028c2ecf20Sopenharmony_cistatic inline bool ata_eh_quiet(struct ata_queued_cmd *qc) 19038c2ecf20Sopenharmony_ci{ 19048c2ecf20Sopenharmony_ci if (qc->scsicmd && 19058c2ecf20Sopenharmony_ci qc->scsicmd->request->rq_flags & RQF_QUIET) 19068c2ecf20Sopenharmony_ci qc->flags |= ATA_QCFLAG_QUIET; 19078c2ecf20Sopenharmony_ci return qc->flags & ATA_QCFLAG_QUIET; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci/** 19118c2ecf20Sopenharmony_ci * ata_eh_link_autopsy - analyze error and determine recovery action 19128c2ecf20Sopenharmony_ci * @link: host link to perform autopsy on 19138c2ecf20Sopenharmony_ci * 19148c2ecf20Sopenharmony_ci * Analyze why @link failed and determine which recovery actions 19158c2ecf20Sopenharmony_ci * are needed. This function also sets more detailed AC_ERR_* 19168c2ecf20Sopenharmony_ci * values and fills sense data for ATAPI CHECK SENSE. 19178c2ecf20Sopenharmony_ci * 19188c2ecf20Sopenharmony_ci * LOCKING: 19198c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 19208c2ecf20Sopenharmony_ci */ 19218c2ecf20Sopenharmony_cistatic void ata_eh_link_autopsy(struct ata_link *link) 19228c2ecf20Sopenharmony_ci{ 19238c2ecf20Sopenharmony_ci struct ata_port *ap = link->ap; 19248c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 19258c2ecf20Sopenharmony_ci struct ata_queued_cmd *qc; 19268c2ecf20Sopenharmony_ci struct ata_device *dev; 19278c2ecf20Sopenharmony_ci unsigned int all_err_mask = 0, eflags = 0; 19288c2ecf20Sopenharmony_ci int tag, nr_failed = 0, nr_quiet = 0; 19298c2ecf20Sopenharmony_ci u32 serror; 19308c2ecf20Sopenharmony_ci int rc; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci DPRINTK("ENTER\n"); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci if (ehc->i.flags & ATA_EHI_NO_AUTOPSY) 19358c2ecf20Sopenharmony_ci return; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci /* obtain and analyze SError */ 19388c2ecf20Sopenharmony_ci rc = sata_scr_read(link, SCR_ERROR, &serror); 19398c2ecf20Sopenharmony_ci if (rc == 0) { 19408c2ecf20Sopenharmony_ci ehc->i.serror |= serror; 19418c2ecf20Sopenharmony_ci ata_eh_analyze_serror(link); 19428c2ecf20Sopenharmony_ci } else if (rc != -EOPNOTSUPP) { 19438c2ecf20Sopenharmony_ci /* SError read failed, force reset and probing */ 19448c2ecf20Sopenharmony_ci ehc->i.probe_mask |= ATA_ALL_DEVICES; 19458c2ecf20Sopenharmony_ci ehc->i.action |= ATA_EH_RESET; 19468c2ecf20Sopenharmony_ci ehc->i.err_mask |= AC_ERR_OTHER; 19478c2ecf20Sopenharmony_ci } 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci /* analyze NCQ failure */ 19508c2ecf20Sopenharmony_ci ata_eh_analyze_ncq_error(link); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci /* any real error trumps AC_ERR_OTHER */ 19538c2ecf20Sopenharmony_ci if (ehc->i.err_mask & ~AC_ERR_OTHER) 19548c2ecf20Sopenharmony_ci ehc->i.err_mask &= ~AC_ERR_OTHER; 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci all_err_mask |= ehc->i.err_mask; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci ata_qc_for_each_raw(ap, qc, tag) { 19598c2ecf20Sopenharmony_ci if (!(qc->flags & ATA_QCFLAG_FAILED) || 19608c2ecf20Sopenharmony_ci ata_dev_phys_link(qc->dev) != link) 19618c2ecf20Sopenharmony_ci continue; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci /* inherit upper level err_mask */ 19648c2ecf20Sopenharmony_ci qc->err_mask |= ehc->i.err_mask; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci /* analyze TF */ 19678c2ecf20Sopenharmony_ci ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci /* DEV errors are probably spurious in case of ATA_BUS error */ 19708c2ecf20Sopenharmony_ci if (qc->err_mask & AC_ERR_ATA_BUS) 19718c2ecf20Sopenharmony_ci qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA | 19728c2ecf20Sopenharmony_ci AC_ERR_INVALID); 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci /* any real error trumps unknown error */ 19758c2ecf20Sopenharmony_ci if (qc->err_mask & ~AC_ERR_OTHER) 19768c2ecf20Sopenharmony_ci qc->err_mask &= ~AC_ERR_OTHER; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci /* 19798c2ecf20Sopenharmony_ci * SENSE_VALID trumps dev/unknown error and revalidation. Upper 19808c2ecf20Sopenharmony_ci * layers will determine whether the command is worth retrying 19818c2ecf20Sopenharmony_ci * based on the sense data and device class/type. Otherwise, 19828c2ecf20Sopenharmony_ci * determine directly if the command is worth retrying using its 19838c2ecf20Sopenharmony_ci * error mask and flags. 19848c2ecf20Sopenharmony_ci */ 19858c2ecf20Sopenharmony_ci if (qc->flags & ATA_QCFLAG_SENSE_VALID) 19868c2ecf20Sopenharmony_ci qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); 19878c2ecf20Sopenharmony_ci else if (ata_eh_worth_retry(qc)) 19888c2ecf20Sopenharmony_ci qc->flags |= ATA_QCFLAG_RETRY; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci /* accumulate error info */ 19918c2ecf20Sopenharmony_ci ehc->i.dev = qc->dev; 19928c2ecf20Sopenharmony_ci all_err_mask |= qc->err_mask; 19938c2ecf20Sopenharmony_ci if (qc->flags & ATA_QCFLAG_IO) 19948c2ecf20Sopenharmony_ci eflags |= ATA_EFLAG_IS_IO; 19958c2ecf20Sopenharmony_ci trace_ata_eh_link_autopsy_qc(qc); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci /* Count quiet errors */ 19988c2ecf20Sopenharmony_ci if (ata_eh_quiet(qc)) 19998c2ecf20Sopenharmony_ci nr_quiet++; 20008c2ecf20Sopenharmony_ci nr_failed++; 20018c2ecf20Sopenharmony_ci } 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci /* If all failed commands requested silence, then be quiet */ 20048c2ecf20Sopenharmony_ci if (nr_quiet == nr_failed) 20058c2ecf20Sopenharmony_ci ehc->i.flags |= ATA_EHI_QUIET; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci /* enforce default EH actions */ 20088c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_FROZEN || 20098c2ecf20Sopenharmony_ci all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) 20108c2ecf20Sopenharmony_ci ehc->i.action |= ATA_EH_RESET; 20118c2ecf20Sopenharmony_ci else if (((eflags & ATA_EFLAG_IS_IO) && all_err_mask) || 20128c2ecf20Sopenharmony_ci (!(eflags & ATA_EFLAG_IS_IO) && (all_err_mask & ~AC_ERR_DEV))) 20138c2ecf20Sopenharmony_ci ehc->i.action |= ATA_EH_REVALIDATE; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci /* If we have offending qcs and the associated failed device, 20168c2ecf20Sopenharmony_ci * perform per-dev EH action only on the offending device. 20178c2ecf20Sopenharmony_ci */ 20188c2ecf20Sopenharmony_ci if (ehc->i.dev) { 20198c2ecf20Sopenharmony_ci ehc->i.dev_action[ehc->i.dev->devno] |= 20208c2ecf20Sopenharmony_ci ehc->i.action & ATA_EH_PERDEV_MASK; 20218c2ecf20Sopenharmony_ci ehc->i.action &= ~ATA_EH_PERDEV_MASK; 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci /* propagate timeout to host link */ 20258c2ecf20Sopenharmony_ci if ((all_err_mask & AC_ERR_TIMEOUT) && !ata_is_host_link(link)) 20268c2ecf20Sopenharmony_ci ap->link.eh_context.i.err_mask |= AC_ERR_TIMEOUT; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci /* record error and consider speeding down */ 20298c2ecf20Sopenharmony_ci dev = ehc->i.dev; 20308c2ecf20Sopenharmony_ci if (!dev && ((ata_link_max_devices(link) == 1 && 20318c2ecf20Sopenharmony_ci ata_dev_enabled(link->device)))) 20328c2ecf20Sopenharmony_ci dev = link->device; 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci if (dev) { 20358c2ecf20Sopenharmony_ci if (dev->flags & ATA_DFLAG_DUBIOUS_XFER) 20368c2ecf20Sopenharmony_ci eflags |= ATA_EFLAG_DUBIOUS_XFER; 20378c2ecf20Sopenharmony_ci ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask); 20388c2ecf20Sopenharmony_ci trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask); 20398c2ecf20Sopenharmony_ci } 20408c2ecf20Sopenharmony_ci DPRINTK("EXIT\n"); 20418c2ecf20Sopenharmony_ci} 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci/** 20448c2ecf20Sopenharmony_ci * ata_eh_autopsy - analyze error and determine recovery action 20458c2ecf20Sopenharmony_ci * @ap: host port to perform autopsy on 20468c2ecf20Sopenharmony_ci * 20478c2ecf20Sopenharmony_ci * Analyze all links of @ap and determine why they failed and 20488c2ecf20Sopenharmony_ci * which recovery actions are needed. 20498c2ecf20Sopenharmony_ci * 20508c2ecf20Sopenharmony_ci * LOCKING: 20518c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 20528c2ecf20Sopenharmony_ci */ 20538c2ecf20Sopenharmony_civoid ata_eh_autopsy(struct ata_port *ap) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci struct ata_link *link; 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) 20588c2ecf20Sopenharmony_ci ata_eh_link_autopsy(link); 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci /* Handle the frigging slave link. Autopsy is done similarly 20618c2ecf20Sopenharmony_ci * but actions and flags are transferred over to the master 20628c2ecf20Sopenharmony_ci * link and handled from there. 20638c2ecf20Sopenharmony_ci */ 20648c2ecf20Sopenharmony_ci if (ap->slave_link) { 20658c2ecf20Sopenharmony_ci struct ata_eh_context *mehc = &ap->link.eh_context; 20668c2ecf20Sopenharmony_ci struct ata_eh_context *sehc = &ap->slave_link->eh_context; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci /* transfer control flags from master to slave */ 20698c2ecf20Sopenharmony_ci sehc->i.flags |= mehc->i.flags & ATA_EHI_TO_SLAVE_MASK; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci /* perform autopsy on the slave link */ 20728c2ecf20Sopenharmony_ci ata_eh_link_autopsy(ap->slave_link); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci /* transfer actions from slave to master and clear slave */ 20758c2ecf20Sopenharmony_ci ata_eh_about_to_do(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS); 20768c2ecf20Sopenharmony_ci mehc->i.action |= sehc->i.action; 20778c2ecf20Sopenharmony_ci mehc->i.dev_action[1] |= sehc->i.dev_action[1]; 20788c2ecf20Sopenharmony_ci mehc->i.flags |= sehc->i.flags; 20798c2ecf20Sopenharmony_ci ata_eh_done(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS); 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci /* Autopsy of fanout ports can affect host link autopsy. 20838c2ecf20Sopenharmony_ci * Perform host link autopsy last. 20848c2ecf20Sopenharmony_ci */ 20858c2ecf20Sopenharmony_ci if (sata_pmp_attached(ap)) 20868c2ecf20Sopenharmony_ci ata_eh_link_autopsy(&ap->link); 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci/** 20908c2ecf20Sopenharmony_ci * ata_get_cmd_descript - get description for ATA command 20918c2ecf20Sopenharmony_ci * @command: ATA command code to get description for 20928c2ecf20Sopenharmony_ci * 20938c2ecf20Sopenharmony_ci * Return a textual description of the given command, or NULL if the 20948c2ecf20Sopenharmony_ci * command is not known. 20958c2ecf20Sopenharmony_ci * 20968c2ecf20Sopenharmony_ci * LOCKING: 20978c2ecf20Sopenharmony_ci * None 20988c2ecf20Sopenharmony_ci */ 20998c2ecf20Sopenharmony_ciconst char *ata_get_cmd_descript(u8 command) 21008c2ecf20Sopenharmony_ci{ 21018c2ecf20Sopenharmony_ci#ifdef CONFIG_ATA_VERBOSE_ERROR 21028c2ecf20Sopenharmony_ci static const struct 21038c2ecf20Sopenharmony_ci { 21048c2ecf20Sopenharmony_ci u8 command; 21058c2ecf20Sopenharmony_ci const char *text; 21068c2ecf20Sopenharmony_ci } cmd_descr[] = { 21078c2ecf20Sopenharmony_ci { ATA_CMD_DEV_RESET, "DEVICE RESET" }, 21088c2ecf20Sopenharmony_ci { ATA_CMD_CHK_POWER, "CHECK POWER MODE" }, 21098c2ecf20Sopenharmony_ci { ATA_CMD_STANDBY, "STANDBY" }, 21108c2ecf20Sopenharmony_ci { ATA_CMD_IDLE, "IDLE" }, 21118c2ecf20Sopenharmony_ci { ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" }, 21128c2ecf20Sopenharmony_ci { ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" }, 21138c2ecf20Sopenharmony_ci { ATA_CMD_DOWNLOAD_MICRO_DMA, "DOWNLOAD MICROCODE DMA" }, 21148c2ecf20Sopenharmony_ci { ATA_CMD_NOP, "NOP" }, 21158c2ecf20Sopenharmony_ci { ATA_CMD_FLUSH, "FLUSH CACHE" }, 21168c2ecf20Sopenharmony_ci { ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" }, 21178c2ecf20Sopenharmony_ci { ATA_CMD_ID_ATA, "IDENTIFY DEVICE" }, 21188c2ecf20Sopenharmony_ci { ATA_CMD_ID_ATAPI, "IDENTIFY PACKET DEVICE" }, 21198c2ecf20Sopenharmony_ci { ATA_CMD_SERVICE, "SERVICE" }, 21208c2ecf20Sopenharmony_ci { ATA_CMD_READ, "READ DMA" }, 21218c2ecf20Sopenharmony_ci { ATA_CMD_READ_EXT, "READ DMA EXT" }, 21228c2ecf20Sopenharmony_ci { ATA_CMD_READ_QUEUED, "READ DMA QUEUED" }, 21238c2ecf20Sopenharmony_ci { ATA_CMD_READ_STREAM_EXT, "READ STREAM EXT" }, 21248c2ecf20Sopenharmony_ci { ATA_CMD_READ_STREAM_DMA_EXT, "READ STREAM DMA EXT" }, 21258c2ecf20Sopenharmony_ci { ATA_CMD_WRITE, "WRITE DMA" }, 21268c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_EXT, "WRITE DMA EXT" }, 21278c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_QUEUED, "WRITE DMA QUEUED EXT" }, 21288c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_STREAM_EXT, "WRITE STREAM EXT" }, 21298c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_STREAM_DMA_EXT, "WRITE STREAM DMA EXT" }, 21308c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_FUA_EXT, "WRITE DMA FUA EXT" }, 21318c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" }, 21328c2ecf20Sopenharmony_ci { ATA_CMD_FPDMA_READ, "READ FPDMA QUEUED" }, 21338c2ecf20Sopenharmony_ci { ATA_CMD_FPDMA_WRITE, "WRITE FPDMA QUEUED" }, 21348c2ecf20Sopenharmony_ci { ATA_CMD_NCQ_NON_DATA, "NCQ NON-DATA" }, 21358c2ecf20Sopenharmony_ci { ATA_CMD_FPDMA_SEND, "SEND FPDMA QUEUED" }, 21368c2ecf20Sopenharmony_ci { ATA_CMD_FPDMA_RECV, "RECEIVE FPDMA QUEUED" }, 21378c2ecf20Sopenharmony_ci { ATA_CMD_PIO_READ, "READ SECTOR(S)" }, 21388c2ecf20Sopenharmony_ci { ATA_CMD_PIO_READ_EXT, "READ SECTOR(S) EXT" }, 21398c2ecf20Sopenharmony_ci { ATA_CMD_PIO_WRITE, "WRITE SECTOR(S)" }, 21408c2ecf20Sopenharmony_ci { ATA_CMD_PIO_WRITE_EXT, "WRITE SECTOR(S) EXT" }, 21418c2ecf20Sopenharmony_ci { ATA_CMD_READ_MULTI, "READ MULTIPLE" }, 21428c2ecf20Sopenharmony_ci { ATA_CMD_READ_MULTI_EXT, "READ MULTIPLE EXT" }, 21438c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_MULTI, "WRITE MULTIPLE" }, 21448c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_MULTI_EXT, "WRITE MULTIPLE EXT" }, 21458c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_MULTI_FUA_EXT, "WRITE MULTIPLE FUA EXT" }, 21468c2ecf20Sopenharmony_ci { ATA_CMD_SET_FEATURES, "SET FEATURES" }, 21478c2ecf20Sopenharmony_ci { ATA_CMD_SET_MULTI, "SET MULTIPLE MODE" }, 21488c2ecf20Sopenharmony_ci { ATA_CMD_VERIFY, "READ VERIFY SECTOR(S)" }, 21498c2ecf20Sopenharmony_ci { ATA_CMD_VERIFY_EXT, "READ VERIFY SECTOR(S) EXT" }, 21508c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_UNCORR_EXT, "WRITE UNCORRECTABLE EXT" }, 21518c2ecf20Sopenharmony_ci { ATA_CMD_STANDBYNOW1, "STANDBY IMMEDIATE" }, 21528c2ecf20Sopenharmony_ci { ATA_CMD_IDLEIMMEDIATE, "IDLE IMMEDIATE" }, 21538c2ecf20Sopenharmony_ci { ATA_CMD_SLEEP, "SLEEP" }, 21548c2ecf20Sopenharmony_ci { ATA_CMD_INIT_DEV_PARAMS, "INITIALIZE DEVICE PARAMETERS" }, 21558c2ecf20Sopenharmony_ci { ATA_CMD_READ_NATIVE_MAX, "READ NATIVE MAX ADDRESS" }, 21568c2ecf20Sopenharmony_ci { ATA_CMD_READ_NATIVE_MAX_EXT, "READ NATIVE MAX ADDRESS EXT" }, 21578c2ecf20Sopenharmony_ci { ATA_CMD_SET_MAX, "SET MAX ADDRESS" }, 21588c2ecf20Sopenharmony_ci { ATA_CMD_SET_MAX_EXT, "SET MAX ADDRESS EXT" }, 21598c2ecf20Sopenharmony_ci { ATA_CMD_READ_LOG_EXT, "READ LOG EXT" }, 21608c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_LOG_EXT, "WRITE LOG EXT" }, 21618c2ecf20Sopenharmony_ci { ATA_CMD_READ_LOG_DMA_EXT, "READ LOG DMA EXT" }, 21628c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" }, 21638c2ecf20Sopenharmony_ci { ATA_CMD_TRUSTED_NONDATA, "TRUSTED NON-DATA" }, 21648c2ecf20Sopenharmony_ci { ATA_CMD_TRUSTED_RCV, "TRUSTED RECEIVE" }, 21658c2ecf20Sopenharmony_ci { ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" }, 21668c2ecf20Sopenharmony_ci { ATA_CMD_TRUSTED_SND, "TRUSTED SEND" }, 21678c2ecf20Sopenharmony_ci { ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" }, 21688c2ecf20Sopenharmony_ci { ATA_CMD_PMP_READ, "READ BUFFER" }, 21698c2ecf20Sopenharmony_ci { ATA_CMD_PMP_READ_DMA, "READ BUFFER DMA" }, 21708c2ecf20Sopenharmony_ci { ATA_CMD_PMP_WRITE, "WRITE BUFFER" }, 21718c2ecf20Sopenharmony_ci { ATA_CMD_PMP_WRITE_DMA, "WRITE BUFFER DMA" }, 21728c2ecf20Sopenharmony_ci { ATA_CMD_CONF_OVERLAY, "DEVICE CONFIGURATION OVERLAY" }, 21738c2ecf20Sopenharmony_ci { ATA_CMD_SEC_SET_PASS, "SECURITY SET PASSWORD" }, 21748c2ecf20Sopenharmony_ci { ATA_CMD_SEC_UNLOCK, "SECURITY UNLOCK" }, 21758c2ecf20Sopenharmony_ci { ATA_CMD_SEC_ERASE_PREP, "SECURITY ERASE PREPARE" }, 21768c2ecf20Sopenharmony_ci { ATA_CMD_SEC_ERASE_UNIT, "SECURITY ERASE UNIT" }, 21778c2ecf20Sopenharmony_ci { ATA_CMD_SEC_FREEZE_LOCK, "SECURITY FREEZE LOCK" }, 21788c2ecf20Sopenharmony_ci { ATA_CMD_SEC_DISABLE_PASS, "SECURITY DISABLE PASSWORD" }, 21798c2ecf20Sopenharmony_ci { ATA_CMD_CONFIG_STREAM, "CONFIGURE STREAM" }, 21808c2ecf20Sopenharmony_ci { ATA_CMD_SMART, "SMART" }, 21818c2ecf20Sopenharmony_ci { ATA_CMD_MEDIA_LOCK, "DOOR LOCK" }, 21828c2ecf20Sopenharmony_ci { ATA_CMD_MEDIA_UNLOCK, "DOOR UNLOCK" }, 21838c2ecf20Sopenharmony_ci { ATA_CMD_DSM, "DATA SET MANAGEMENT" }, 21848c2ecf20Sopenharmony_ci { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" }, 21858c2ecf20Sopenharmony_ci { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" }, 21868c2ecf20Sopenharmony_ci { ATA_CMD_CFA_WRITE_NE, "CFA WRITE SECTORS WITHOUT ERASE" }, 21878c2ecf20Sopenharmony_ci { ATA_CMD_CFA_TRANS_SECT, "CFA TRANSLATE SECTOR" }, 21888c2ecf20Sopenharmony_ci { ATA_CMD_CFA_ERASE, "CFA ERASE SECTORS" }, 21898c2ecf20Sopenharmony_ci { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" }, 21908c2ecf20Sopenharmony_ci { ATA_CMD_REQ_SENSE_DATA, "REQUEST SENSE DATA EXT" }, 21918c2ecf20Sopenharmony_ci { ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" }, 21928c2ecf20Sopenharmony_ci { ATA_CMD_ZAC_MGMT_IN, "ZAC MANAGEMENT IN" }, 21938c2ecf20Sopenharmony_ci { ATA_CMD_ZAC_MGMT_OUT, "ZAC MANAGEMENT OUT" }, 21948c2ecf20Sopenharmony_ci { ATA_CMD_READ_LONG, "READ LONG (with retries)" }, 21958c2ecf20Sopenharmony_ci { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" }, 21968c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" }, 21978c2ecf20Sopenharmony_ci { ATA_CMD_WRITE_LONG_ONCE, "WRITE LONG (without retries)" }, 21988c2ecf20Sopenharmony_ci { ATA_CMD_RESTORE, "RECALIBRATE" }, 21998c2ecf20Sopenharmony_ci { 0, NULL } /* terminate list */ 22008c2ecf20Sopenharmony_ci }; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci unsigned int i; 22038c2ecf20Sopenharmony_ci for (i = 0; cmd_descr[i].text; i++) 22048c2ecf20Sopenharmony_ci if (cmd_descr[i].command == command) 22058c2ecf20Sopenharmony_ci return cmd_descr[i].text; 22068c2ecf20Sopenharmony_ci#endif 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci return NULL; 22098c2ecf20Sopenharmony_ci} 22108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_get_cmd_descript); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci/** 22138c2ecf20Sopenharmony_ci * ata_eh_link_report - report error handling to user 22148c2ecf20Sopenharmony_ci * @link: ATA link EH is going on 22158c2ecf20Sopenharmony_ci * 22168c2ecf20Sopenharmony_ci * Report EH to user. 22178c2ecf20Sopenharmony_ci * 22188c2ecf20Sopenharmony_ci * LOCKING: 22198c2ecf20Sopenharmony_ci * None. 22208c2ecf20Sopenharmony_ci */ 22218c2ecf20Sopenharmony_cistatic void ata_eh_link_report(struct ata_link *link) 22228c2ecf20Sopenharmony_ci{ 22238c2ecf20Sopenharmony_ci struct ata_port *ap = link->ap; 22248c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 22258c2ecf20Sopenharmony_ci struct ata_queued_cmd *qc; 22268c2ecf20Sopenharmony_ci const char *frozen, *desc; 22278c2ecf20Sopenharmony_ci char tries_buf[16] = ""; 22288c2ecf20Sopenharmony_ci int tag, nr_failed = 0; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci if (ehc->i.flags & ATA_EHI_QUIET) 22318c2ecf20Sopenharmony_ci return; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci desc = NULL; 22348c2ecf20Sopenharmony_ci if (ehc->i.desc[0] != '\0') 22358c2ecf20Sopenharmony_ci desc = ehc->i.desc; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci ata_qc_for_each_raw(ap, qc, tag) { 22388c2ecf20Sopenharmony_ci if (!(qc->flags & ATA_QCFLAG_FAILED) || 22398c2ecf20Sopenharmony_ci ata_dev_phys_link(qc->dev) != link || 22408c2ecf20Sopenharmony_ci ((qc->flags & ATA_QCFLAG_QUIET) && 22418c2ecf20Sopenharmony_ci qc->err_mask == AC_ERR_DEV)) 22428c2ecf20Sopenharmony_ci continue; 22438c2ecf20Sopenharmony_ci if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask) 22448c2ecf20Sopenharmony_ci continue; 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci nr_failed++; 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci if (!nr_failed && !ehc->i.err_mask) 22508c2ecf20Sopenharmony_ci return; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci frozen = ""; 22538c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_FROZEN) 22548c2ecf20Sopenharmony_ci frozen = " frozen"; 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci if (ap->eh_tries < ATA_EH_MAX_TRIES) 22578c2ecf20Sopenharmony_ci snprintf(tries_buf, sizeof(tries_buf), " t%d", 22588c2ecf20Sopenharmony_ci ap->eh_tries); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci if (ehc->i.dev) { 22618c2ecf20Sopenharmony_ci ata_dev_err(ehc->i.dev, "exception Emask 0x%x " 22628c2ecf20Sopenharmony_ci "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", 22638c2ecf20Sopenharmony_ci ehc->i.err_mask, link->sactive, ehc->i.serror, 22648c2ecf20Sopenharmony_ci ehc->i.action, frozen, tries_buf); 22658c2ecf20Sopenharmony_ci if (desc) 22668c2ecf20Sopenharmony_ci ata_dev_err(ehc->i.dev, "%s\n", desc); 22678c2ecf20Sopenharmony_ci } else { 22688c2ecf20Sopenharmony_ci ata_link_err(link, "exception Emask 0x%x " 22698c2ecf20Sopenharmony_ci "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", 22708c2ecf20Sopenharmony_ci ehc->i.err_mask, link->sactive, ehc->i.serror, 22718c2ecf20Sopenharmony_ci ehc->i.action, frozen, tries_buf); 22728c2ecf20Sopenharmony_ci if (desc) 22738c2ecf20Sopenharmony_ci ata_link_err(link, "%s\n", desc); 22748c2ecf20Sopenharmony_ci } 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci#ifdef CONFIG_ATA_VERBOSE_ERROR 22778c2ecf20Sopenharmony_ci if (ehc->i.serror) 22788c2ecf20Sopenharmony_ci ata_link_err(link, 22798c2ecf20Sopenharmony_ci "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n", 22808c2ecf20Sopenharmony_ci ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "", 22818c2ecf20Sopenharmony_ci ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "", 22828c2ecf20Sopenharmony_ci ehc->i.serror & SERR_DATA ? "UnrecovData " : "", 22838c2ecf20Sopenharmony_ci ehc->i.serror & SERR_PERSISTENT ? "Persist " : "", 22848c2ecf20Sopenharmony_ci ehc->i.serror & SERR_PROTOCOL ? "Proto " : "", 22858c2ecf20Sopenharmony_ci ehc->i.serror & SERR_INTERNAL ? "HostInt " : "", 22868c2ecf20Sopenharmony_ci ehc->i.serror & SERR_PHYRDY_CHG ? "PHYRdyChg " : "", 22878c2ecf20Sopenharmony_ci ehc->i.serror & SERR_PHY_INT_ERR ? "PHYInt " : "", 22888c2ecf20Sopenharmony_ci ehc->i.serror & SERR_COMM_WAKE ? "CommWake " : "", 22898c2ecf20Sopenharmony_ci ehc->i.serror & SERR_10B_8B_ERR ? "10B8B " : "", 22908c2ecf20Sopenharmony_ci ehc->i.serror & SERR_DISPARITY ? "Dispar " : "", 22918c2ecf20Sopenharmony_ci ehc->i.serror & SERR_CRC ? "BadCRC " : "", 22928c2ecf20Sopenharmony_ci ehc->i.serror & SERR_HANDSHAKE ? "Handshk " : "", 22938c2ecf20Sopenharmony_ci ehc->i.serror & SERR_LINK_SEQ_ERR ? "LinkSeq " : "", 22948c2ecf20Sopenharmony_ci ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "", 22958c2ecf20Sopenharmony_ci ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "", 22968c2ecf20Sopenharmony_ci ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : ""); 22978c2ecf20Sopenharmony_ci#endif 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci ata_qc_for_each_raw(ap, qc, tag) { 23008c2ecf20Sopenharmony_ci struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; 23018c2ecf20Sopenharmony_ci char data_buf[20] = ""; 23028c2ecf20Sopenharmony_ci char cdb_buf[70] = ""; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci if (!(qc->flags & ATA_QCFLAG_FAILED) || 23058c2ecf20Sopenharmony_ci ata_dev_phys_link(qc->dev) != link || !qc->err_mask) 23068c2ecf20Sopenharmony_ci continue; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci if (qc->dma_dir != DMA_NONE) { 23098c2ecf20Sopenharmony_ci static const char *dma_str[] = { 23108c2ecf20Sopenharmony_ci [DMA_BIDIRECTIONAL] = "bidi", 23118c2ecf20Sopenharmony_ci [DMA_TO_DEVICE] = "out", 23128c2ecf20Sopenharmony_ci [DMA_FROM_DEVICE] = "in", 23138c2ecf20Sopenharmony_ci }; 23148c2ecf20Sopenharmony_ci const char *prot_str = NULL; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci switch (qc->tf.protocol) { 23178c2ecf20Sopenharmony_ci case ATA_PROT_UNKNOWN: 23188c2ecf20Sopenharmony_ci prot_str = "unknown"; 23198c2ecf20Sopenharmony_ci break; 23208c2ecf20Sopenharmony_ci case ATA_PROT_NODATA: 23218c2ecf20Sopenharmony_ci prot_str = "nodata"; 23228c2ecf20Sopenharmony_ci break; 23238c2ecf20Sopenharmony_ci case ATA_PROT_PIO: 23248c2ecf20Sopenharmony_ci prot_str = "pio"; 23258c2ecf20Sopenharmony_ci break; 23268c2ecf20Sopenharmony_ci case ATA_PROT_DMA: 23278c2ecf20Sopenharmony_ci prot_str = "dma"; 23288c2ecf20Sopenharmony_ci break; 23298c2ecf20Sopenharmony_ci case ATA_PROT_NCQ: 23308c2ecf20Sopenharmony_ci prot_str = "ncq dma"; 23318c2ecf20Sopenharmony_ci break; 23328c2ecf20Sopenharmony_ci case ATA_PROT_NCQ_NODATA: 23338c2ecf20Sopenharmony_ci prot_str = "ncq nodata"; 23348c2ecf20Sopenharmony_ci break; 23358c2ecf20Sopenharmony_ci case ATAPI_PROT_NODATA: 23368c2ecf20Sopenharmony_ci prot_str = "nodata"; 23378c2ecf20Sopenharmony_ci break; 23388c2ecf20Sopenharmony_ci case ATAPI_PROT_PIO: 23398c2ecf20Sopenharmony_ci prot_str = "pio"; 23408c2ecf20Sopenharmony_ci break; 23418c2ecf20Sopenharmony_ci case ATAPI_PROT_DMA: 23428c2ecf20Sopenharmony_ci prot_str = "dma"; 23438c2ecf20Sopenharmony_ci break; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci snprintf(data_buf, sizeof(data_buf), " %s %u %s", 23468c2ecf20Sopenharmony_ci prot_str, qc->nbytes, dma_str[qc->dma_dir]); 23478c2ecf20Sopenharmony_ci } 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci if (ata_is_atapi(qc->tf.protocol)) { 23508c2ecf20Sopenharmony_ci const u8 *cdb = qc->cdb; 23518c2ecf20Sopenharmony_ci size_t cdb_len = qc->dev->cdb_len; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci if (qc->scsicmd) { 23548c2ecf20Sopenharmony_ci cdb = qc->scsicmd->cmnd; 23558c2ecf20Sopenharmony_ci cdb_len = qc->scsicmd->cmd_len; 23568c2ecf20Sopenharmony_ci } 23578c2ecf20Sopenharmony_ci __scsi_format_command(cdb_buf, sizeof(cdb_buf), 23588c2ecf20Sopenharmony_ci cdb, cdb_len); 23598c2ecf20Sopenharmony_ci } else { 23608c2ecf20Sopenharmony_ci const char *descr = ata_get_cmd_descript(cmd->command); 23618c2ecf20Sopenharmony_ci if (descr) 23628c2ecf20Sopenharmony_ci ata_dev_err(qc->dev, "failed command: %s\n", 23638c2ecf20Sopenharmony_ci descr); 23648c2ecf20Sopenharmony_ci } 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci ata_dev_err(qc->dev, 23678c2ecf20Sopenharmony_ci "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " 23688c2ecf20Sopenharmony_ci "tag %d%s\n %s" 23698c2ecf20Sopenharmony_ci "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " 23708c2ecf20Sopenharmony_ci "Emask 0x%x (%s)%s\n", 23718c2ecf20Sopenharmony_ci cmd->command, cmd->feature, cmd->nsect, 23728c2ecf20Sopenharmony_ci cmd->lbal, cmd->lbam, cmd->lbah, 23738c2ecf20Sopenharmony_ci cmd->hob_feature, cmd->hob_nsect, 23748c2ecf20Sopenharmony_ci cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah, 23758c2ecf20Sopenharmony_ci cmd->device, qc->tag, data_buf, cdb_buf, 23768c2ecf20Sopenharmony_ci res->command, res->feature, res->nsect, 23778c2ecf20Sopenharmony_ci res->lbal, res->lbam, res->lbah, 23788c2ecf20Sopenharmony_ci res->hob_feature, res->hob_nsect, 23798c2ecf20Sopenharmony_ci res->hob_lbal, res->hob_lbam, res->hob_lbah, 23808c2ecf20Sopenharmony_ci res->device, qc->err_mask, ata_err_string(qc->err_mask), 23818c2ecf20Sopenharmony_ci qc->err_mask & AC_ERR_NCQ ? " <F>" : ""); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci#ifdef CONFIG_ATA_VERBOSE_ERROR 23848c2ecf20Sopenharmony_ci if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | 23858c2ecf20Sopenharmony_ci ATA_SENSE | ATA_ERR)) { 23868c2ecf20Sopenharmony_ci if (res->command & ATA_BUSY) 23878c2ecf20Sopenharmony_ci ata_dev_err(qc->dev, "status: { Busy }\n"); 23888c2ecf20Sopenharmony_ci else 23898c2ecf20Sopenharmony_ci ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n", 23908c2ecf20Sopenharmony_ci res->command & ATA_DRDY ? "DRDY " : "", 23918c2ecf20Sopenharmony_ci res->command & ATA_DF ? "DF " : "", 23928c2ecf20Sopenharmony_ci res->command & ATA_DRQ ? "DRQ " : "", 23938c2ecf20Sopenharmony_ci res->command & ATA_SENSE ? "SENSE " : "", 23948c2ecf20Sopenharmony_ci res->command & ATA_ERR ? "ERR " : ""); 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci if (cmd->command != ATA_CMD_PACKET && 23988c2ecf20Sopenharmony_ci (res->feature & (ATA_ICRC | ATA_UNC | ATA_AMNF | 23998c2ecf20Sopenharmony_ci ATA_IDNF | ATA_ABORTED))) 24008c2ecf20Sopenharmony_ci ata_dev_err(qc->dev, "error: { %s%s%s%s%s}\n", 24018c2ecf20Sopenharmony_ci res->feature & ATA_ICRC ? "ICRC " : "", 24028c2ecf20Sopenharmony_ci res->feature & ATA_UNC ? "UNC " : "", 24038c2ecf20Sopenharmony_ci res->feature & ATA_AMNF ? "AMNF " : "", 24048c2ecf20Sopenharmony_ci res->feature & ATA_IDNF ? "IDNF " : "", 24058c2ecf20Sopenharmony_ci res->feature & ATA_ABORTED ? "ABRT " : ""); 24068c2ecf20Sopenharmony_ci#endif 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci} 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci/** 24118c2ecf20Sopenharmony_ci * ata_eh_report - report error handling to user 24128c2ecf20Sopenharmony_ci * @ap: ATA port to report EH about 24138c2ecf20Sopenharmony_ci * 24148c2ecf20Sopenharmony_ci * Report EH to user. 24158c2ecf20Sopenharmony_ci * 24168c2ecf20Sopenharmony_ci * LOCKING: 24178c2ecf20Sopenharmony_ci * None. 24188c2ecf20Sopenharmony_ci */ 24198c2ecf20Sopenharmony_civoid ata_eh_report(struct ata_port *ap) 24208c2ecf20Sopenharmony_ci{ 24218c2ecf20Sopenharmony_ci struct ata_link *link; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, HOST_FIRST) 24248c2ecf20Sopenharmony_ci ata_eh_link_report(link); 24258c2ecf20Sopenharmony_ci} 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_cistatic int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, 24288c2ecf20Sopenharmony_ci unsigned int *classes, unsigned long deadline, 24298c2ecf20Sopenharmony_ci bool clear_classes) 24308c2ecf20Sopenharmony_ci{ 24318c2ecf20Sopenharmony_ci struct ata_device *dev; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci if (clear_classes) 24348c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) 24358c2ecf20Sopenharmony_ci classes[dev->devno] = ATA_DEV_UNKNOWN; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci return reset(link, classes, deadline); 24388c2ecf20Sopenharmony_ci} 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_cistatic int ata_eh_followup_srst_needed(struct ata_link *link, int rc) 24418c2ecf20Sopenharmony_ci{ 24428c2ecf20Sopenharmony_ci if ((link->flags & ATA_LFLAG_NO_SRST) || ata_link_offline(link)) 24438c2ecf20Sopenharmony_ci return 0; 24448c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 24458c2ecf20Sopenharmony_ci return 1; 24468c2ecf20Sopenharmony_ci if (sata_pmp_supported(link->ap) && ata_is_host_link(link)) 24478c2ecf20Sopenharmony_ci return 1; 24488c2ecf20Sopenharmony_ci return 0; 24498c2ecf20Sopenharmony_ci} 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ciint ata_eh_reset(struct ata_link *link, int classify, 24528c2ecf20Sopenharmony_ci ata_prereset_fn_t prereset, ata_reset_fn_t softreset, 24538c2ecf20Sopenharmony_ci ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) 24548c2ecf20Sopenharmony_ci{ 24558c2ecf20Sopenharmony_ci struct ata_port *ap = link->ap; 24568c2ecf20Sopenharmony_ci struct ata_link *slave = ap->slave_link; 24578c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 24588c2ecf20Sopenharmony_ci struct ata_eh_context *sehc = slave ? &slave->eh_context : NULL; 24598c2ecf20Sopenharmony_ci unsigned int *classes = ehc->classes; 24608c2ecf20Sopenharmony_ci unsigned int lflags = link->flags; 24618c2ecf20Sopenharmony_ci int verbose = !(ehc->i.flags & ATA_EHI_QUIET); 24628c2ecf20Sopenharmony_ci int max_tries = 0, try = 0; 24638c2ecf20Sopenharmony_ci struct ata_link *failed_link; 24648c2ecf20Sopenharmony_ci struct ata_device *dev; 24658c2ecf20Sopenharmony_ci unsigned long deadline, now; 24668c2ecf20Sopenharmony_ci ata_reset_fn_t reset; 24678c2ecf20Sopenharmony_ci unsigned long flags; 24688c2ecf20Sopenharmony_ci u32 sstatus; 24698c2ecf20Sopenharmony_ci int nr_unknown, rc; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci /* 24728c2ecf20Sopenharmony_ci * Prepare to reset 24738c2ecf20Sopenharmony_ci */ 24748c2ecf20Sopenharmony_ci while (ata_eh_reset_timeouts[max_tries] != ULONG_MAX) 24758c2ecf20Sopenharmony_ci max_tries++; 24768c2ecf20Sopenharmony_ci if (link->flags & ATA_LFLAG_RST_ONCE) 24778c2ecf20Sopenharmony_ci max_tries = 1; 24788c2ecf20Sopenharmony_ci if (link->flags & ATA_LFLAG_NO_HRST) 24798c2ecf20Sopenharmony_ci hardreset = NULL; 24808c2ecf20Sopenharmony_ci if (link->flags & ATA_LFLAG_NO_SRST) 24818c2ecf20Sopenharmony_ci softreset = NULL; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci /* make sure each reset attempt is at least COOL_DOWN apart */ 24848c2ecf20Sopenharmony_ci if (ehc->i.flags & ATA_EHI_DID_RESET) { 24858c2ecf20Sopenharmony_ci now = jiffies; 24868c2ecf20Sopenharmony_ci WARN_ON(time_after(ehc->last_reset, now)); 24878c2ecf20Sopenharmony_ci deadline = ata_deadline(ehc->last_reset, 24888c2ecf20Sopenharmony_ci ATA_EH_RESET_COOL_DOWN); 24898c2ecf20Sopenharmony_ci if (time_before(now, deadline)) 24908c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(deadline - now); 24918c2ecf20Sopenharmony_ci } 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 24948c2ecf20Sopenharmony_ci ap->pflags |= ATA_PFLAG_RESETTING; 24958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci ata_eh_about_to_do(link, NULL, ATA_EH_RESET); 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 25008c2ecf20Sopenharmony_ci /* If we issue an SRST then an ATA drive (not ATAPI) 25018c2ecf20Sopenharmony_ci * may change configuration and be in PIO0 timing. If 25028c2ecf20Sopenharmony_ci * we do a hard reset (or are coming from power on) 25038c2ecf20Sopenharmony_ci * this is true for ATA or ATAPI. Until we've set a 25048c2ecf20Sopenharmony_ci * suitable controller mode we should not touch the 25058c2ecf20Sopenharmony_ci * bus as we may be talking too fast. 25068c2ecf20Sopenharmony_ci */ 25078c2ecf20Sopenharmony_ci dev->pio_mode = XFER_PIO_0; 25088c2ecf20Sopenharmony_ci dev->dma_mode = 0xff; 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci /* If the controller has a pio mode setup function 25118c2ecf20Sopenharmony_ci * then use it to set the chipset to rights. Don't 25128c2ecf20Sopenharmony_ci * touch the DMA setup as that will be dealt with when 25138c2ecf20Sopenharmony_ci * configuring devices. 25148c2ecf20Sopenharmony_ci */ 25158c2ecf20Sopenharmony_ci if (ap->ops->set_piomode) 25168c2ecf20Sopenharmony_ci ap->ops->set_piomode(ap, dev); 25178c2ecf20Sopenharmony_ci } 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci /* prefer hardreset */ 25208c2ecf20Sopenharmony_ci reset = NULL; 25218c2ecf20Sopenharmony_ci ehc->i.action &= ~ATA_EH_RESET; 25228c2ecf20Sopenharmony_ci if (hardreset) { 25238c2ecf20Sopenharmony_ci reset = hardreset; 25248c2ecf20Sopenharmony_ci ehc->i.action |= ATA_EH_HARDRESET; 25258c2ecf20Sopenharmony_ci } else if (softreset) { 25268c2ecf20Sopenharmony_ci reset = softreset; 25278c2ecf20Sopenharmony_ci ehc->i.action |= ATA_EH_SOFTRESET; 25288c2ecf20Sopenharmony_ci } 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci if (prereset) { 25318c2ecf20Sopenharmony_ci unsigned long deadline = ata_deadline(jiffies, 25328c2ecf20Sopenharmony_ci ATA_EH_PRERESET_TIMEOUT); 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci if (slave) { 25358c2ecf20Sopenharmony_ci sehc->i.action &= ~ATA_EH_RESET; 25368c2ecf20Sopenharmony_ci sehc->i.action |= ehc->i.action; 25378c2ecf20Sopenharmony_ci } 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci rc = prereset(link, deadline); 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci /* If present, do prereset on slave link too. Reset 25428c2ecf20Sopenharmony_ci * is skipped iff both master and slave links report 25438c2ecf20Sopenharmony_ci * -ENOENT or clear ATA_EH_RESET. 25448c2ecf20Sopenharmony_ci */ 25458c2ecf20Sopenharmony_ci if (slave && (rc == 0 || rc == -ENOENT)) { 25468c2ecf20Sopenharmony_ci int tmp; 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci tmp = prereset(slave, deadline); 25498c2ecf20Sopenharmony_ci if (tmp != -ENOENT) 25508c2ecf20Sopenharmony_ci rc = tmp; 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci ehc->i.action |= sehc->i.action; 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci if (rc) { 25568c2ecf20Sopenharmony_ci if (rc == -ENOENT) { 25578c2ecf20Sopenharmony_ci ata_link_dbg(link, "port disabled--ignoring\n"); 25588c2ecf20Sopenharmony_ci ehc->i.action &= ~ATA_EH_RESET; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) 25618c2ecf20Sopenharmony_ci classes[dev->devno] = ATA_DEV_NONE; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci rc = 0; 25648c2ecf20Sopenharmony_ci } else 25658c2ecf20Sopenharmony_ci ata_link_err(link, 25668c2ecf20Sopenharmony_ci "prereset failed (errno=%d)\n", 25678c2ecf20Sopenharmony_ci rc); 25688c2ecf20Sopenharmony_ci goto out; 25698c2ecf20Sopenharmony_ci } 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci /* prereset() might have cleared ATA_EH_RESET. If so, 25728c2ecf20Sopenharmony_ci * bang classes, thaw and return. 25738c2ecf20Sopenharmony_ci */ 25748c2ecf20Sopenharmony_ci if (reset && !(ehc->i.action & ATA_EH_RESET)) { 25758c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) 25768c2ecf20Sopenharmony_ci classes[dev->devno] = ATA_DEV_NONE; 25778c2ecf20Sopenharmony_ci if ((ap->pflags & ATA_PFLAG_FROZEN) && 25788c2ecf20Sopenharmony_ci ata_is_host_link(link)) 25798c2ecf20Sopenharmony_ci ata_eh_thaw_port(ap); 25808c2ecf20Sopenharmony_ci rc = 0; 25818c2ecf20Sopenharmony_ci goto out; 25828c2ecf20Sopenharmony_ci } 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci retry: 25868c2ecf20Sopenharmony_ci /* 25878c2ecf20Sopenharmony_ci * Perform reset 25888c2ecf20Sopenharmony_ci */ 25898c2ecf20Sopenharmony_ci if (ata_is_host_link(link)) 25908c2ecf20Sopenharmony_ci ata_eh_freeze_port(ap); 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci deadline = ata_deadline(jiffies, ata_eh_reset_timeouts[try++]); 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci if (reset) { 25958c2ecf20Sopenharmony_ci if (verbose) 25968c2ecf20Sopenharmony_ci ata_link_info(link, "%s resetting link\n", 25978c2ecf20Sopenharmony_ci reset == softreset ? "soft" : "hard"); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci /* mark that this EH session started with reset */ 26008c2ecf20Sopenharmony_ci ehc->last_reset = jiffies; 26018c2ecf20Sopenharmony_ci if (reset == hardreset) 26028c2ecf20Sopenharmony_ci ehc->i.flags |= ATA_EHI_DID_HARDRESET; 26038c2ecf20Sopenharmony_ci else 26048c2ecf20Sopenharmony_ci ehc->i.flags |= ATA_EHI_DID_SOFTRESET; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci rc = ata_do_reset(link, reset, classes, deadline, true); 26078c2ecf20Sopenharmony_ci if (rc && rc != -EAGAIN) { 26088c2ecf20Sopenharmony_ci failed_link = link; 26098c2ecf20Sopenharmony_ci goto fail; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci /* hardreset slave link if existent */ 26138c2ecf20Sopenharmony_ci if (slave && reset == hardreset) { 26148c2ecf20Sopenharmony_ci int tmp; 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci if (verbose) 26178c2ecf20Sopenharmony_ci ata_link_info(slave, "hard resetting link\n"); 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci ata_eh_about_to_do(slave, NULL, ATA_EH_RESET); 26208c2ecf20Sopenharmony_ci tmp = ata_do_reset(slave, reset, classes, deadline, 26218c2ecf20Sopenharmony_ci false); 26228c2ecf20Sopenharmony_ci switch (tmp) { 26238c2ecf20Sopenharmony_ci case -EAGAIN: 26248c2ecf20Sopenharmony_ci rc = -EAGAIN; 26258c2ecf20Sopenharmony_ci case 0: 26268c2ecf20Sopenharmony_ci break; 26278c2ecf20Sopenharmony_ci default: 26288c2ecf20Sopenharmony_ci failed_link = slave; 26298c2ecf20Sopenharmony_ci rc = tmp; 26308c2ecf20Sopenharmony_ci goto fail; 26318c2ecf20Sopenharmony_ci } 26328c2ecf20Sopenharmony_ci } 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci /* perform follow-up SRST if necessary */ 26358c2ecf20Sopenharmony_ci if (reset == hardreset && 26368c2ecf20Sopenharmony_ci ata_eh_followup_srst_needed(link, rc)) { 26378c2ecf20Sopenharmony_ci reset = softreset; 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci if (!reset) { 26408c2ecf20Sopenharmony_ci ata_link_err(link, 26418c2ecf20Sopenharmony_ci "follow-up softreset required but no softreset available\n"); 26428c2ecf20Sopenharmony_ci failed_link = link; 26438c2ecf20Sopenharmony_ci rc = -EINVAL; 26448c2ecf20Sopenharmony_ci goto fail; 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci ata_eh_about_to_do(link, NULL, ATA_EH_RESET); 26488c2ecf20Sopenharmony_ci rc = ata_do_reset(link, reset, classes, deadline, true); 26498c2ecf20Sopenharmony_ci if (rc) { 26508c2ecf20Sopenharmony_ci failed_link = link; 26518c2ecf20Sopenharmony_ci goto fail; 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci } 26548c2ecf20Sopenharmony_ci } else { 26558c2ecf20Sopenharmony_ci if (verbose) 26568c2ecf20Sopenharmony_ci ata_link_info(link, 26578c2ecf20Sopenharmony_ci "no reset method available, skipping reset\n"); 26588c2ecf20Sopenharmony_ci if (!(lflags & ATA_LFLAG_ASSUME_CLASS)) 26598c2ecf20Sopenharmony_ci lflags |= ATA_LFLAG_ASSUME_ATA; 26608c2ecf20Sopenharmony_ci } 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci /* 26638c2ecf20Sopenharmony_ci * Post-reset processing 26648c2ecf20Sopenharmony_ci */ 26658c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 26668c2ecf20Sopenharmony_ci /* After the reset, the device state is PIO 0 and the 26678c2ecf20Sopenharmony_ci * controller state is undefined. Reset also wakes up 26688c2ecf20Sopenharmony_ci * drives from sleeping mode. 26698c2ecf20Sopenharmony_ci */ 26708c2ecf20Sopenharmony_ci dev->pio_mode = XFER_PIO_0; 26718c2ecf20Sopenharmony_ci dev->flags &= ~ATA_DFLAG_SLEEPING; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci if (ata_phys_link_offline(ata_dev_phys_link(dev))) 26748c2ecf20Sopenharmony_ci continue; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci /* apply class override */ 26778c2ecf20Sopenharmony_ci if (lflags & ATA_LFLAG_ASSUME_ATA) 26788c2ecf20Sopenharmony_ci classes[dev->devno] = ATA_DEV_ATA; 26798c2ecf20Sopenharmony_ci else if (lflags & ATA_LFLAG_ASSUME_SEMB) 26808c2ecf20Sopenharmony_ci classes[dev->devno] = ATA_DEV_SEMB_UNSUP; 26818c2ecf20Sopenharmony_ci } 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci /* record current link speed */ 26848c2ecf20Sopenharmony_ci if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) 26858c2ecf20Sopenharmony_ci link->sata_spd = (sstatus >> 4) & 0xf; 26868c2ecf20Sopenharmony_ci if (slave && sata_scr_read(slave, SCR_STATUS, &sstatus) == 0) 26878c2ecf20Sopenharmony_ci slave->sata_spd = (sstatus >> 4) & 0xf; 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci /* thaw the port */ 26908c2ecf20Sopenharmony_ci if (ata_is_host_link(link)) 26918c2ecf20Sopenharmony_ci ata_eh_thaw_port(ap); 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci /* postreset() should clear hardware SError. Although SError 26948c2ecf20Sopenharmony_ci * is cleared during link resume, clearing SError here is 26958c2ecf20Sopenharmony_ci * necessary as some PHYs raise hotplug events after SRST. 26968c2ecf20Sopenharmony_ci * This introduces race condition where hotplug occurs between 26978c2ecf20Sopenharmony_ci * reset and here. This race is mediated by cross checking 26988c2ecf20Sopenharmony_ci * link onlineness and classification result later. 26998c2ecf20Sopenharmony_ci */ 27008c2ecf20Sopenharmony_ci if (postreset) { 27018c2ecf20Sopenharmony_ci postreset(link, classes); 27028c2ecf20Sopenharmony_ci if (slave) 27038c2ecf20Sopenharmony_ci postreset(slave, classes); 27048c2ecf20Sopenharmony_ci } 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci /* clear cached SError */ 27078c2ecf20Sopenharmony_ci spin_lock_irqsave(link->ap->lock, flags); 27088c2ecf20Sopenharmony_ci link->eh_info.serror = 0; 27098c2ecf20Sopenharmony_ci if (slave) 27108c2ecf20Sopenharmony_ci slave->eh_info.serror = 0; 27118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(link->ap->lock, flags); 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_FROZEN) 27148c2ecf20Sopenharmony_ci ata_eh_thaw_port(ap); 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci /* 27178c2ecf20Sopenharmony_ci * Make sure onlineness and classification result correspond. 27188c2ecf20Sopenharmony_ci * Hotplug could have happened during reset and some 27198c2ecf20Sopenharmony_ci * controllers fail to wait while a drive is spinning up after 27208c2ecf20Sopenharmony_ci * being hotplugged causing misdetection. By cross checking 27218c2ecf20Sopenharmony_ci * link on/offlineness and classification result, those 27228c2ecf20Sopenharmony_ci * conditions can be reliably detected and retried. 27238c2ecf20Sopenharmony_ci */ 27248c2ecf20Sopenharmony_ci nr_unknown = 0; 27258c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 27268c2ecf20Sopenharmony_ci if (ata_phys_link_online(ata_dev_phys_link(dev))) { 27278c2ecf20Sopenharmony_ci if (classes[dev->devno] == ATA_DEV_UNKNOWN) { 27288c2ecf20Sopenharmony_ci ata_dev_dbg(dev, "link online but device misclassified\n"); 27298c2ecf20Sopenharmony_ci classes[dev->devno] = ATA_DEV_NONE; 27308c2ecf20Sopenharmony_ci nr_unknown++; 27318c2ecf20Sopenharmony_ci } 27328c2ecf20Sopenharmony_ci } else if (ata_phys_link_offline(ata_dev_phys_link(dev))) { 27338c2ecf20Sopenharmony_ci if (ata_class_enabled(classes[dev->devno])) 27348c2ecf20Sopenharmony_ci ata_dev_dbg(dev, 27358c2ecf20Sopenharmony_ci "link offline, clearing class %d to NONE\n", 27368c2ecf20Sopenharmony_ci classes[dev->devno]); 27378c2ecf20Sopenharmony_ci classes[dev->devno] = ATA_DEV_NONE; 27388c2ecf20Sopenharmony_ci } else if (classes[dev->devno] == ATA_DEV_UNKNOWN) { 27398c2ecf20Sopenharmony_ci ata_dev_dbg(dev, 27408c2ecf20Sopenharmony_ci "link status unknown, clearing UNKNOWN to NONE\n"); 27418c2ecf20Sopenharmony_ci classes[dev->devno] = ATA_DEV_NONE; 27428c2ecf20Sopenharmony_ci } 27438c2ecf20Sopenharmony_ci } 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci if (classify && nr_unknown) { 27468c2ecf20Sopenharmony_ci if (try < max_tries) { 27478c2ecf20Sopenharmony_ci ata_link_warn(link, 27488c2ecf20Sopenharmony_ci "link online but %d devices misclassified, retrying\n", 27498c2ecf20Sopenharmony_ci nr_unknown); 27508c2ecf20Sopenharmony_ci failed_link = link; 27518c2ecf20Sopenharmony_ci rc = -EAGAIN; 27528c2ecf20Sopenharmony_ci goto fail; 27538c2ecf20Sopenharmony_ci } 27548c2ecf20Sopenharmony_ci ata_link_warn(link, 27558c2ecf20Sopenharmony_ci "link online but %d devices misclassified, " 27568c2ecf20Sopenharmony_ci "device detection might fail\n", nr_unknown); 27578c2ecf20Sopenharmony_ci } 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci /* reset successful, schedule revalidation */ 27608c2ecf20Sopenharmony_ci ata_eh_done(link, NULL, ATA_EH_RESET); 27618c2ecf20Sopenharmony_ci if (slave) 27628c2ecf20Sopenharmony_ci ata_eh_done(slave, NULL, ATA_EH_RESET); 27638c2ecf20Sopenharmony_ci ehc->last_reset = jiffies; /* update to completion time */ 27648c2ecf20Sopenharmony_ci ehc->i.action |= ATA_EH_REVALIDATE; 27658c2ecf20Sopenharmony_ci link->lpm_policy = ATA_LPM_UNKNOWN; /* reset LPM state */ 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci rc = 0; 27688c2ecf20Sopenharmony_ci out: 27698c2ecf20Sopenharmony_ci /* clear hotplug flag */ 27708c2ecf20Sopenharmony_ci ehc->i.flags &= ~ATA_EHI_HOTPLUGGED; 27718c2ecf20Sopenharmony_ci if (slave) 27728c2ecf20Sopenharmony_ci sehc->i.flags &= ~ATA_EHI_HOTPLUGGED; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 27758c2ecf20Sopenharmony_ci ap->pflags &= ~ATA_PFLAG_RESETTING; 27768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 27778c2ecf20Sopenharmony_ci 27788c2ecf20Sopenharmony_ci return rc; 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci fail: 27818c2ecf20Sopenharmony_ci /* if SCR isn't accessible on a fan-out port, PMP needs to be reset */ 27828c2ecf20Sopenharmony_ci if (!ata_is_host_link(link) && 27838c2ecf20Sopenharmony_ci sata_scr_read(link, SCR_STATUS, &sstatus)) 27848c2ecf20Sopenharmony_ci rc = -ERESTART; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci if (try >= max_tries) { 27878c2ecf20Sopenharmony_ci /* 27888c2ecf20Sopenharmony_ci * Thaw host port even if reset failed, so that the port 27898c2ecf20Sopenharmony_ci * can be retried on the next phy event. This risks 27908c2ecf20Sopenharmony_ci * repeated EH runs but seems to be a better tradeoff than 27918c2ecf20Sopenharmony_ci * shutting down a port after a botched hotplug attempt. 27928c2ecf20Sopenharmony_ci */ 27938c2ecf20Sopenharmony_ci if (ata_is_host_link(link)) 27948c2ecf20Sopenharmony_ci ata_eh_thaw_port(ap); 27958c2ecf20Sopenharmony_ci goto out; 27968c2ecf20Sopenharmony_ci } 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci now = jiffies; 27998c2ecf20Sopenharmony_ci if (time_before(now, deadline)) { 28008c2ecf20Sopenharmony_ci unsigned long delta = deadline - now; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci ata_link_warn(failed_link, 28038c2ecf20Sopenharmony_ci "reset failed (errno=%d), retrying in %u secs\n", 28048c2ecf20Sopenharmony_ci rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000)); 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci ata_eh_release(ap); 28078c2ecf20Sopenharmony_ci while (delta) 28088c2ecf20Sopenharmony_ci delta = schedule_timeout_uninterruptible(delta); 28098c2ecf20Sopenharmony_ci ata_eh_acquire(ap); 28108c2ecf20Sopenharmony_ci } 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci /* 28138c2ecf20Sopenharmony_ci * While disks spinup behind PMP, some controllers fail sending SRST. 28148c2ecf20Sopenharmony_ci * They need to be reset - as well as the PMP - before retrying. 28158c2ecf20Sopenharmony_ci */ 28168c2ecf20Sopenharmony_ci if (rc == -ERESTART) { 28178c2ecf20Sopenharmony_ci if (ata_is_host_link(link)) 28188c2ecf20Sopenharmony_ci ata_eh_thaw_port(ap); 28198c2ecf20Sopenharmony_ci goto out; 28208c2ecf20Sopenharmony_ci } 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci if (try == max_tries - 1) { 28238c2ecf20Sopenharmony_ci sata_down_spd_limit(link, 0); 28248c2ecf20Sopenharmony_ci if (slave) 28258c2ecf20Sopenharmony_ci sata_down_spd_limit(slave, 0); 28268c2ecf20Sopenharmony_ci } else if (rc == -EPIPE) 28278c2ecf20Sopenharmony_ci sata_down_spd_limit(failed_link, 0); 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci if (hardreset) 28308c2ecf20Sopenharmony_ci reset = hardreset; 28318c2ecf20Sopenharmony_ci goto retry; 28328c2ecf20Sopenharmony_ci} 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_cistatic inline void ata_eh_pull_park_action(struct ata_port *ap) 28358c2ecf20Sopenharmony_ci{ 28368c2ecf20Sopenharmony_ci struct ata_link *link; 28378c2ecf20Sopenharmony_ci struct ata_device *dev; 28388c2ecf20Sopenharmony_ci unsigned long flags; 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci /* 28418c2ecf20Sopenharmony_ci * This function can be thought of as an extended version of 28428c2ecf20Sopenharmony_ci * ata_eh_about_to_do() specially crafted to accommodate the 28438c2ecf20Sopenharmony_ci * requirements of ATA_EH_PARK handling. Since the EH thread 28448c2ecf20Sopenharmony_ci * does not leave the do {} while () loop in ata_eh_recover as 28458c2ecf20Sopenharmony_ci * long as the timeout for a park request to *one* device on 28468c2ecf20Sopenharmony_ci * the port has not expired, and since we still want to pick 28478c2ecf20Sopenharmony_ci * up park requests to other devices on the same port or 28488c2ecf20Sopenharmony_ci * timeout updates for the same device, we have to pull 28498c2ecf20Sopenharmony_ci * ATA_EH_PARK actions from eh_info into eh_context.i 28508c2ecf20Sopenharmony_ci * ourselves at the beginning of each pass over the loop. 28518c2ecf20Sopenharmony_ci * 28528c2ecf20Sopenharmony_ci * Additionally, all write accesses to &ap->park_req_pending 28538c2ecf20Sopenharmony_ci * through reinit_completion() (see below) or complete_all() 28548c2ecf20Sopenharmony_ci * (see ata_scsi_park_store()) are protected by the host lock. 28558c2ecf20Sopenharmony_ci * As a result we have that park_req_pending.done is zero on 28568c2ecf20Sopenharmony_ci * exit from this function, i.e. when ATA_EH_PARK actions for 28578c2ecf20Sopenharmony_ci * *all* devices on port ap have been pulled into the 28588c2ecf20Sopenharmony_ci * respective eh_context structs. If, and only if, 28598c2ecf20Sopenharmony_ci * park_req_pending.done is non-zero by the time we reach 28608c2ecf20Sopenharmony_ci * wait_for_completion_timeout(), another ATA_EH_PARK action 28618c2ecf20Sopenharmony_ci * has been scheduled for at least one of the devices on port 28628c2ecf20Sopenharmony_ci * ap and we have to cycle over the do {} while () loop in 28638c2ecf20Sopenharmony_ci * ata_eh_recover() again. 28648c2ecf20Sopenharmony_ci */ 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 28678c2ecf20Sopenharmony_ci reinit_completion(&ap->park_req_pending); 28688c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) { 28698c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 28708c2ecf20Sopenharmony_ci struct ata_eh_info *ehi = &link->eh_info; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci link->eh_context.i.dev_action[dev->devno] |= 28738c2ecf20Sopenharmony_ci ehi->dev_action[dev->devno] & ATA_EH_PARK; 28748c2ecf20Sopenharmony_ci ata_eh_clear_action(link, dev, ehi, ATA_EH_PARK); 28758c2ecf20Sopenharmony_ci } 28768c2ecf20Sopenharmony_ci } 28778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 28788c2ecf20Sopenharmony_ci} 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_cistatic void ata_eh_park_issue_cmd(struct ata_device *dev, int park) 28818c2ecf20Sopenharmony_ci{ 28828c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &dev->link->eh_context; 28838c2ecf20Sopenharmony_ci struct ata_taskfile tf; 28848c2ecf20Sopenharmony_ci unsigned int err_mask; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci ata_tf_init(dev, &tf); 28878c2ecf20Sopenharmony_ci if (park) { 28888c2ecf20Sopenharmony_ci ehc->unloaded_mask |= 1 << dev->devno; 28898c2ecf20Sopenharmony_ci tf.command = ATA_CMD_IDLEIMMEDIATE; 28908c2ecf20Sopenharmony_ci tf.feature = 0x44; 28918c2ecf20Sopenharmony_ci tf.lbal = 0x4c; 28928c2ecf20Sopenharmony_ci tf.lbam = 0x4e; 28938c2ecf20Sopenharmony_ci tf.lbah = 0x55; 28948c2ecf20Sopenharmony_ci } else { 28958c2ecf20Sopenharmony_ci ehc->unloaded_mask &= ~(1 << dev->devno); 28968c2ecf20Sopenharmony_ci tf.command = ATA_CMD_CHK_POWER; 28978c2ecf20Sopenharmony_ci } 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; 29008c2ecf20Sopenharmony_ci tf.protocol = ATA_PROT_NODATA; 29018c2ecf20Sopenharmony_ci err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); 29028c2ecf20Sopenharmony_ci if (park && (err_mask || tf.lbal != 0xc4)) { 29038c2ecf20Sopenharmony_ci ata_dev_err(dev, "head unload failed!\n"); 29048c2ecf20Sopenharmony_ci ehc->unloaded_mask &= ~(1 << dev->devno); 29058c2ecf20Sopenharmony_ci } 29068c2ecf20Sopenharmony_ci} 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_cistatic int ata_eh_revalidate_and_attach(struct ata_link *link, 29098c2ecf20Sopenharmony_ci struct ata_device **r_failed_dev) 29108c2ecf20Sopenharmony_ci{ 29118c2ecf20Sopenharmony_ci struct ata_port *ap = link->ap; 29128c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 29138c2ecf20Sopenharmony_ci struct ata_device *dev; 29148c2ecf20Sopenharmony_ci unsigned int new_mask = 0; 29158c2ecf20Sopenharmony_ci unsigned long flags; 29168c2ecf20Sopenharmony_ci int rc = 0; 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci DPRINTK("ENTER\n"); 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci /* For PATA drive side cable detection to work, IDENTIFY must 29218c2ecf20Sopenharmony_ci * be done backwards such that PDIAG- is released by the slave 29228c2ecf20Sopenharmony_ci * device before the master device is identified. 29238c2ecf20Sopenharmony_ci */ 29248c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL_REVERSE) { 29258c2ecf20Sopenharmony_ci unsigned int action = ata_eh_dev_action(dev); 29268c2ecf20Sopenharmony_ci unsigned int readid_flags = 0; 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci if (ehc->i.flags & ATA_EHI_DID_RESET) 29298c2ecf20Sopenharmony_ci readid_flags |= ATA_READID_POSTRESET; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { 29328c2ecf20Sopenharmony_ci WARN_ON(dev->class == ATA_DEV_PMP); 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci if (ata_phys_link_offline(ata_dev_phys_link(dev))) { 29358c2ecf20Sopenharmony_ci rc = -EIO; 29368c2ecf20Sopenharmony_ci goto err; 29378c2ecf20Sopenharmony_ci } 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE); 29408c2ecf20Sopenharmony_ci rc = ata_dev_revalidate(dev, ehc->classes[dev->devno], 29418c2ecf20Sopenharmony_ci readid_flags); 29428c2ecf20Sopenharmony_ci if (rc) 29438c2ecf20Sopenharmony_ci goto err; 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci ata_eh_done(link, dev, ATA_EH_REVALIDATE); 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci /* Configuration may have changed, reconfigure 29488c2ecf20Sopenharmony_ci * transfer mode. 29498c2ecf20Sopenharmony_ci */ 29508c2ecf20Sopenharmony_ci ehc->i.flags |= ATA_EHI_SETMODE; 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci /* schedule the scsi_rescan_device() here */ 29538c2ecf20Sopenharmony_ci schedule_work(&(ap->scsi_rescan_task)); 29548c2ecf20Sopenharmony_ci } else if (dev->class == ATA_DEV_UNKNOWN && 29558c2ecf20Sopenharmony_ci ehc->tries[dev->devno] && 29568c2ecf20Sopenharmony_ci ata_class_enabled(ehc->classes[dev->devno])) { 29578c2ecf20Sopenharmony_ci /* Temporarily set dev->class, it will be 29588c2ecf20Sopenharmony_ci * permanently set once all configurations are 29598c2ecf20Sopenharmony_ci * complete. This is necessary because new 29608c2ecf20Sopenharmony_ci * device configuration is done in two 29618c2ecf20Sopenharmony_ci * separate loops. 29628c2ecf20Sopenharmony_ci */ 29638c2ecf20Sopenharmony_ci dev->class = ehc->classes[dev->devno]; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci if (dev->class == ATA_DEV_PMP) 29668c2ecf20Sopenharmony_ci rc = sata_pmp_attach(dev); 29678c2ecf20Sopenharmony_ci else 29688c2ecf20Sopenharmony_ci rc = ata_dev_read_id(dev, &dev->class, 29698c2ecf20Sopenharmony_ci readid_flags, dev->id); 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci /* read_id might have changed class, store and reset */ 29728c2ecf20Sopenharmony_ci ehc->classes[dev->devno] = dev->class; 29738c2ecf20Sopenharmony_ci dev->class = ATA_DEV_UNKNOWN; 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci switch (rc) { 29768c2ecf20Sopenharmony_ci case 0: 29778c2ecf20Sopenharmony_ci /* clear error info accumulated during probe */ 29788c2ecf20Sopenharmony_ci ata_ering_clear(&dev->ering); 29798c2ecf20Sopenharmony_ci new_mask |= 1 << dev->devno; 29808c2ecf20Sopenharmony_ci break; 29818c2ecf20Sopenharmony_ci case -ENOENT: 29828c2ecf20Sopenharmony_ci /* IDENTIFY was issued to non-existent 29838c2ecf20Sopenharmony_ci * device. No need to reset. Just 29848c2ecf20Sopenharmony_ci * thaw and ignore the device. 29858c2ecf20Sopenharmony_ci */ 29868c2ecf20Sopenharmony_ci ata_eh_thaw_port(ap); 29878c2ecf20Sopenharmony_ci break; 29888c2ecf20Sopenharmony_ci default: 29898c2ecf20Sopenharmony_ci goto err; 29908c2ecf20Sopenharmony_ci } 29918c2ecf20Sopenharmony_ci } 29928c2ecf20Sopenharmony_ci } 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci /* PDIAG- should have been released, ask cable type if post-reset */ 29958c2ecf20Sopenharmony_ci if ((ehc->i.flags & ATA_EHI_DID_RESET) && ata_is_host_link(link)) { 29968c2ecf20Sopenharmony_ci if (ap->ops->cable_detect) 29978c2ecf20Sopenharmony_ci ap->cbl = ap->ops->cable_detect(ap); 29988c2ecf20Sopenharmony_ci ata_force_cbl(ap); 29998c2ecf20Sopenharmony_ci } 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci /* Configure new devices forward such that user doesn't see 30028c2ecf20Sopenharmony_ci * device detection messages backwards. 30038c2ecf20Sopenharmony_ci */ 30048c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 30058c2ecf20Sopenharmony_ci if (!(new_mask & (1 << dev->devno))) 30068c2ecf20Sopenharmony_ci continue; 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci dev->class = ehc->classes[dev->devno]; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci if (dev->class == ATA_DEV_PMP) 30118c2ecf20Sopenharmony_ci continue; 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci ehc->i.flags |= ATA_EHI_PRINTINFO; 30148c2ecf20Sopenharmony_ci rc = ata_dev_configure(dev); 30158c2ecf20Sopenharmony_ci ehc->i.flags &= ~ATA_EHI_PRINTINFO; 30168c2ecf20Sopenharmony_ci if (rc) { 30178c2ecf20Sopenharmony_ci dev->class = ATA_DEV_UNKNOWN; 30188c2ecf20Sopenharmony_ci goto err; 30198c2ecf20Sopenharmony_ci } 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 30228c2ecf20Sopenharmony_ci ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; 30238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci /* new device discovered, configure xfermode */ 30268c2ecf20Sopenharmony_ci ehc->i.flags |= ATA_EHI_SETMODE; 30278c2ecf20Sopenharmony_ci } 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci return 0; 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci err: 30328c2ecf20Sopenharmony_ci *r_failed_dev = dev; 30338c2ecf20Sopenharmony_ci DPRINTK("EXIT rc=%d\n", rc); 30348c2ecf20Sopenharmony_ci return rc; 30358c2ecf20Sopenharmony_ci} 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci/** 30388c2ecf20Sopenharmony_ci * ata_set_mode - Program timings and issue SET FEATURES - XFER 30398c2ecf20Sopenharmony_ci * @link: link on which timings will be programmed 30408c2ecf20Sopenharmony_ci * @r_failed_dev: out parameter for failed device 30418c2ecf20Sopenharmony_ci * 30428c2ecf20Sopenharmony_ci * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If 30438c2ecf20Sopenharmony_ci * ata_set_mode() fails, pointer to the failing device is 30448c2ecf20Sopenharmony_ci * returned in @r_failed_dev. 30458c2ecf20Sopenharmony_ci * 30468c2ecf20Sopenharmony_ci * LOCKING: 30478c2ecf20Sopenharmony_ci * PCI/etc. bus probe sem. 30488c2ecf20Sopenharmony_ci * 30498c2ecf20Sopenharmony_ci * RETURNS: 30508c2ecf20Sopenharmony_ci * 0 on success, negative errno otherwise 30518c2ecf20Sopenharmony_ci */ 30528c2ecf20Sopenharmony_ciint ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) 30538c2ecf20Sopenharmony_ci{ 30548c2ecf20Sopenharmony_ci struct ata_port *ap = link->ap; 30558c2ecf20Sopenharmony_ci struct ata_device *dev; 30568c2ecf20Sopenharmony_ci int rc; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci /* if data transfer is verified, clear DUBIOUS_XFER on ering top */ 30598c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ENABLED) { 30608c2ecf20Sopenharmony_ci if (!(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) { 30618c2ecf20Sopenharmony_ci struct ata_ering_entry *ent; 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci ent = ata_ering_top(&dev->ering); 30648c2ecf20Sopenharmony_ci if (ent) 30658c2ecf20Sopenharmony_ci ent->eflags &= ~ATA_EFLAG_DUBIOUS_XFER; 30668c2ecf20Sopenharmony_ci } 30678c2ecf20Sopenharmony_ci } 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci /* has private set_mode? */ 30708c2ecf20Sopenharmony_ci if (ap->ops->set_mode) 30718c2ecf20Sopenharmony_ci rc = ap->ops->set_mode(link, r_failed_dev); 30728c2ecf20Sopenharmony_ci else 30738c2ecf20Sopenharmony_ci rc = ata_do_set_mode(link, r_failed_dev); 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci /* if transfer mode has changed, set DUBIOUS_XFER on device */ 30768c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ENABLED) { 30778c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 30788c2ecf20Sopenharmony_ci u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno]; 30798c2ecf20Sopenharmony_ci u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno)); 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci if (dev->xfer_mode != saved_xfer_mode || 30828c2ecf20Sopenharmony_ci ata_ncq_enabled(dev) != saved_ncq) 30838c2ecf20Sopenharmony_ci dev->flags |= ATA_DFLAG_DUBIOUS_XFER; 30848c2ecf20Sopenharmony_ci } 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci return rc; 30878c2ecf20Sopenharmony_ci} 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci/** 30908c2ecf20Sopenharmony_ci * atapi_eh_clear_ua - Clear ATAPI UNIT ATTENTION after reset 30918c2ecf20Sopenharmony_ci * @dev: ATAPI device to clear UA for 30928c2ecf20Sopenharmony_ci * 30938c2ecf20Sopenharmony_ci * Resets and other operations can make an ATAPI device raise 30948c2ecf20Sopenharmony_ci * UNIT ATTENTION which causes the next operation to fail. This 30958c2ecf20Sopenharmony_ci * function clears UA. 30968c2ecf20Sopenharmony_ci * 30978c2ecf20Sopenharmony_ci * LOCKING: 30988c2ecf20Sopenharmony_ci * EH context (may sleep). 30998c2ecf20Sopenharmony_ci * 31008c2ecf20Sopenharmony_ci * RETURNS: 31018c2ecf20Sopenharmony_ci * 0 on success, -errno on failure. 31028c2ecf20Sopenharmony_ci */ 31038c2ecf20Sopenharmony_cistatic int atapi_eh_clear_ua(struct ata_device *dev) 31048c2ecf20Sopenharmony_ci{ 31058c2ecf20Sopenharmony_ci int i; 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci for (i = 0; i < ATA_EH_UA_TRIES; i++) { 31088c2ecf20Sopenharmony_ci u8 *sense_buffer = dev->link->ap->sector_buf; 31098c2ecf20Sopenharmony_ci u8 sense_key = 0; 31108c2ecf20Sopenharmony_ci unsigned int err_mask; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci err_mask = atapi_eh_tur(dev, &sense_key); 31138c2ecf20Sopenharmony_ci if (err_mask != 0 && err_mask != AC_ERR_DEV) { 31148c2ecf20Sopenharmony_ci ata_dev_warn(dev, 31158c2ecf20Sopenharmony_ci "TEST_UNIT_READY failed (err_mask=0x%x)\n", 31168c2ecf20Sopenharmony_ci err_mask); 31178c2ecf20Sopenharmony_ci return -EIO; 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci if (!err_mask || sense_key != UNIT_ATTENTION) 31218c2ecf20Sopenharmony_ci return 0; 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci err_mask = atapi_eh_request_sense(dev, sense_buffer, sense_key); 31248c2ecf20Sopenharmony_ci if (err_mask) { 31258c2ecf20Sopenharmony_ci ata_dev_warn(dev, "failed to clear " 31268c2ecf20Sopenharmony_ci "UNIT ATTENTION (err_mask=0x%x)\n", err_mask); 31278c2ecf20Sopenharmony_ci return -EIO; 31288c2ecf20Sopenharmony_ci } 31298c2ecf20Sopenharmony_ci } 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci ata_dev_warn(dev, "UNIT ATTENTION persists after %d tries\n", 31328c2ecf20Sopenharmony_ci ATA_EH_UA_TRIES); 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci return 0; 31358c2ecf20Sopenharmony_ci} 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci/** 31388c2ecf20Sopenharmony_ci * ata_eh_maybe_retry_flush - Retry FLUSH if necessary 31398c2ecf20Sopenharmony_ci * @dev: ATA device which may need FLUSH retry 31408c2ecf20Sopenharmony_ci * 31418c2ecf20Sopenharmony_ci * If @dev failed FLUSH, it needs to be reported upper layer 31428c2ecf20Sopenharmony_ci * immediately as it means that @dev failed to remap and already 31438c2ecf20Sopenharmony_ci * lost at least a sector and further FLUSH retrials won't make 31448c2ecf20Sopenharmony_ci * any difference to the lost sector. However, if FLUSH failed 31458c2ecf20Sopenharmony_ci * for other reasons, for example transmission error, FLUSH needs 31468c2ecf20Sopenharmony_ci * to be retried. 31478c2ecf20Sopenharmony_ci * 31488c2ecf20Sopenharmony_ci * This function determines whether FLUSH failure retry is 31498c2ecf20Sopenharmony_ci * necessary and performs it if so. 31508c2ecf20Sopenharmony_ci * 31518c2ecf20Sopenharmony_ci * RETURNS: 31528c2ecf20Sopenharmony_ci * 0 if EH can continue, -errno if EH needs to be repeated. 31538c2ecf20Sopenharmony_ci */ 31548c2ecf20Sopenharmony_cistatic int ata_eh_maybe_retry_flush(struct ata_device *dev) 31558c2ecf20Sopenharmony_ci{ 31568c2ecf20Sopenharmony_ci struct ata_link *link = dev->link; 31578c2ecf20Sopenharmony_ci struct ata_port *ap = link->ap; 31588c2ecf20Sopenharmony_ci struct ata_queued_cmd *qc; 31598c2ecf20Sopenharmony_ci struct ata_taskfile tf; 31608c2ecf20Sopenharmony_ci unsigned int err_mask; 31618c2ecf20Sopenharmony_ci int rc = 0; 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ci /* did flush fail for this device? */ 31648c2ecf20Sopenharmony_ci if (!ata_tag_valid(link->active_tag)) 31658c2ecf20Sopenharmony_ci return 0; 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci qc = __ata_qc_from_tag(ap, link->active_tag); 31688c2ecf20Sopenharmony_ci if (qc->dev != dev || (qc->tf.command != ATA_CMD_FLUSH_EXT && 31698c2ecf20Sopenharmony_ci qc->tf.command != ATA_CMD_FLUSH)) 31708c2ecf20Sopenharmony_ci return 0; 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_ci /* if the device failed it, it should be reported to upper layers */ 31738c2ecf20Sopenharmony_ci if (qc->err_mask & AC_ERR_DEV) 31748c2ecf20Sopenharmony_ci return 0; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci /* flush failed for some other reason, give it another shot */ 31778c2ecf20Sopenharmony_ci ata_tf_init(dev, &tf); 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci tf.command = qc->tf.command; 31808c2ecf20Sopenharmony_ci tf.flags |= ATA_TFLAG_DEVICE; 31818c2ecf20Sopenharmony_ci tf.protocol = ATA_PROT_NODATA; 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci ata_dev_warn(dev, "retrying FLUSH 0x%x Emask 0x%x\n", 31848c2ecf20Sopenharmony_ci tf.command, qc->err_mask); 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); 31878c2ecf20Sopenharmony_ci if (!err_mask) { 31888c2ecf20Sopenharmony_ci /* 31898c2ecf20Sopenharmony_ci * FLUSH is complete but there's no way to 31908c2ecf20Sopenharmony_ci * successfully complete a failed command from EH. 31918c2ecf20Sopenharmony_ci * Making sure retry is allowed at least once and 31928c2ecf20Sopenharmony_ci * retrying it should do the trick - whatever was in 31938c2ecf20Sopenharmony_ci * the cache is already on the platter and this won't 31948c2ecf20Sopenharmony_ci * cause infinite loop. 31958c2ecf20Sopenharmony_ci */ 31968c2ecf20Sopenharmony_ci qc->scsicmd->allowed = max(qc->scsicmd->allowed, 1); 31978c2ecf20Sopenharmony_ci } else { 31988c2ecf20Sopenharmony_ci ata_dev_warn(dev, "FLUSH failed Emask 0x%x\n", 31998c2ecf20Sopenharmony_ci err_mask); 32008c2ecf20Sopenharmony_ci rc = -EIO; 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci /* if device failed it, report it to upper layers */ 32038c2ecf20Sopenharmony_ci if (err_mask & AC_ERR_DEV) { 32048c2ecf20Sopenharmony_ci qc->err_mask |= AC_ERR_DEV; 32058c2ecf20Sopenharmony_ci qc->result_tf = tf; 32068c2ecf20Sopenharmony_ci if (!(ap->pflags & ATA_PFLAG_FROZEN)) 32078c2ecf20Sopenharmony_ci rc = 0; 32088c2ecf20Sopenharmony_ci } 32098c2ecf20Sopenharmony_ci } 32108c2ecf20Sopenharmony_ci return rc; 32118c2ecf20Sopenharmony_ci} 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci/** 32148c2ecf20Sopenharmony_ci * ata_eh_set_lpm - configure SATA interface power management 32158c2ecf20Sopenharmony_ci * @link: link to configure power management 32168c2ecf20Sopenharmony_ci * @policy: the link power management policy 32178c2ecf20Sopenharmony_ci * @r_failed_dev: out parameter for failed device 32188c2ecf20Sopenharmony_ci * 32198c2ecf20Sopenharmony_ci * Enable SATA Interface power management. This will enable 32208c2ecf20Sopenharmony_ci * Device Interface Power Management (DIPM) for min_power and 32218c2ecf20Sopenharmony_ci * medium_power_with_dipm policies, and then call driver specific 32228c2ecf20Sopenharmony_ci * callbacks for enabling Host Initiated Power management. 32238c2ecf20Sopenharmony_ci * 32248c2ecf20Sopenharmony_ci * LOCKING: 32258c2ecf20Sopenharmony_ci * EH context. 32268c2ecf20Sopenharmony_ci * 32278c2ecf20Sopenharmony_ci * RETURNS: 32288c2ecf20Sopenharmony_ci * 0 on success, -errno on failure. 32298c2ecf20Sopenharmony_ci */ 32308c2ecf20Sopenharmony_cistatic int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, 32318c2ecf20Sopenharmony_ci struct ata_device **r_failed_dev) 32328c2ecf20Sopenharmony_ci{ 32338c2ecf20Sopenharmony_ci struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL; 32348c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 32358c2ecf20Sopenharmony_ci struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL; 32368c2ecf20Sopenharmony_ci enum ata_lpm_policy old_policy = link->lpm_policy; 32378c2ecf20Sopenharmony_ci bool no_dipm = link->ap->flags & ATA_FLAG_NO_DIPM; 32388c2ecf20Sopenharmony_ci unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; 32398c2ecf20Sopenharmony_ci unsigned int err_mask; 32408c2ecf20Sopenharmony_ci int rc; 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci /* if the link or host doesn't do LPM, noop */ 32438c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_SATA_HOST) || 32448c2ecf20Sopenharmony_ci (link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm)) 32458c2ecf20Sopenharmony_ci return 0; 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci /* 32488c2ecf20Sopenharmony_ci * DIPM is enabled only for MIN_POWER as some devices 32498c2ecf20Sopenharmony_ci * misbehave when the host NACKs transition to SLUMBER. Order 32508c2ecf20Sopenharmony_ci * device and link configurations such that the host always 32518c2ecf20Sopenharmony_ci * allows DIPM requests. 32528c2ecf20Sopenharmony_ci */ 32538c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ENABLED) { 32548c2ecf20Sopenharmony_ci bool hipm = ata_id_has_hipm(dev->id); 32558c2ecf20Sopenharmony_ci bool dipm = ata_id_has_dipm(dev->id) && !no_dipm; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci /* find the first enabled and LPM enabled devices */ 32588c2ecf20Sopenharmony_ci if (!link_dev) 32598c2ecf20Sopenharmony_ci link_dev = dev; 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci if (!lpm_dev && (hipm || dipm)) 32628c2ecf20Sopenharmony_ci lpm_dev = dev; 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci hints &= ~ATA_LPM_EMPTY; 32658c2ecf20Sopenharmony_ci if (!hipm) 32668c2ecf20Sopenharmony_ci hints &= ~ATA_LPM_HIPM; 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci /* disable DIPM before changing link config */ 32698c2ecf20Sopenharmony_ci if (policy < ATA_LPM_MED_POWER_WITH_DIPM && dipm) { 32708c2ecf20Sopenharmony_ci err_mask = ata_dev_set_feature(dev, 32718c2ecf20Sopenharmony_ci SETFEATURES_SATA_DISABLE, SATA_DIPM); 32728c2ecf20Sopenharmony_ci if (err_mask && err_mask != AC_ERR_DEV) { 32738c2ecf20Sopenharmony_ci ata_dev_warn(dev, 32748c2ecf20Sopenharmony_ci "failed to disable DIPM, Emask 0x%x\n", 32758c2ecf20Sopenharmony_ci err_mask); 32768c2ecf20Sopenharmony_ci rc = -EIO; 32778c2ecf20Sopenharmony_ci goto fail; 32788c2ecf20Sopenharmony_ci } 32798c2ecf20Sopenharmony_ci } 32808c2ecf20Sopenharmony_ci } 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci if (ap) { 32838c2ecf20Sopenharmony_ci rc = ap->ops->set_lpm(link, policy, hints); 32848c2ecf20Sopenharmony_ci if (!rc && ap->slave_link) 32858c2ecf20Sopenharmony_ci rc = ap->ops->set_lpm(ap->slave_link, policy, hints); 32868c2ecf20Sopenharmony_ci } else 32878c2ecf20Sopenharmony_ci rc = sata_pmp_set_lpm(link, policy, hints); 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci /* 32908c2ecf20Sopenharmony_ci * Attribute link config failure to the first (LPM) enabled 32918c2ecf20Sopenharmony_ci * device on the link. 32928c2ecf20Sopenharmony_ci */ 32938c2ecf20Sopenharmony_ci if (rc) { 32948c2ecf20Sopenharmony_ci if (rc == -EOPNOTSUPP) { 32958c2ecf20Sopenharmony_ci link->flags |= ATA_LFLAG_NO_LPM; 32968c2ecf20Sopenharmony_ci return 0; 32978c2ecf20Sopenharmony_ci } 32988c2ecf20Sopenharmony_ci dev = lpm_dev ? lpm_dev : link_dev; 32998c2ecf20Sopenharmony_ci goto fail; 33008c2ecf20Sopenharmony_ci } 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci /* 33038c2ecf20Sopenharmony_ci * Low level driver acked the transition. Issue DIPM command 33048c2ecf20Sopenharmony_ci * with the new policy set. 33058c2ecf20Sopenharmony_ci */ 33068c2ecf20Sopenharmony_ci link->lpm_policy = policy; 33078c2ecf20Sopenharmony_ci if (ap && ap->slave_link) 33088c2ecf20Sopenharmony_ci ap->slave_link->lpm_policy = policy; 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci /* host config updated, enable DIPM if transitioning to MIN_POWER */ 33118c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ENABLED) { 33128c2ecf20Sopenharmony_ci if (policy >= ATA_LPM_MED_POWER_WITH_DIPM && !no_dipm && 33138c2ecf20Sopenharmony_ci ata_id_has_dipm(dev->id)) { 33148c2ecf20Sopenharmony_ci err_mask = ata_dev_set_feature(dev, 33158c2ecf20Sopenharmony_ci SETFEATURES_SATA_ENABLE, SATA_DIPM); 33168c2ecf20Sopenharmony_ci if (err_mask && err_mask != AC_ERR_DEV) { 33178c2ecf20Sopenharmony_ci ata_dev_warn(dev, 33188c2ecf20Sopenharmony_ci "failed to enable DIPM, Emask 0x%x\n", 33198c2ecf20Sopenharmony_ci err_mask); 33208c2ecf20Sopenharmony_ci rc = -EIO; 33218c2ecf20Sopenharmony_ci goto fail; 33228c2ecf20Sopenharmony_ci } 33238c2ecf20Sopenharmony_ci } 33248c2ecf20Sopenharmony_ci } 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci link->last_lpm_change = jiffies; 33278c2ecf20Sopenharmony_ci link->flags |= ATA_LFLAG_CHANGED; 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci return 0; 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_cifail: 33328c2ecf20Sopenharmony_ci /* restore the old policy */ 33338c2ecf20Sopenharmony_ci link->lpm_policy = old_policy; 33348c2ecf20Sopenharmony_ci if (ap && ap->slave_link) 33358c2ecf20Sopenharmony_ci ap->slave_link->lpm_policy = old_policy; 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci /* if no device or only one more chance is left, disable LPM */ 33388c2ecf20Sopenharmony_ci if (!dev || ehc->tries[dev->devno] <= 2) { 33398c2ecf20Sopenharmony_ci ata_link_warn(link, "disabling LPM on the link\n"); 33408c2ecf20Sopenharmony_ci link->flags |= ATA_LFLAG_NO_LPM; 33418c2ecf20Sopenharmony_ci } 33428c2ecf20Sopenharmony_ci if (r_failed_dev) 33438c2ecf20Sopenharmony_ci *r_failed_dev = dev; 33448c2ecf20Sopenharmony_ci return rc; 33458c2ecf20Sopenharmony_ci} 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ciint ata_link_nr_enabled(struct ata_link *link) 33488c2ecf20Sopenharmony_ci{ 33498c2ecf20Sopenharmony_ci struct ata_device *dev; 33508c2ecf20Sopenharmony_ci int cnt = 0; 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ENABLED) 33538c2ecf20Sopenharmony_ci cnt++; 33548c2ecf20Sopenharmony_ci return cnt; 33558c2ecf20Sopenharmony_ci} 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_cistatic int ata_link_nr_vacant(struct ata_link *link) 33588c2ecf20Sopenharmony_ci{ 33598c2ecf20Sopenharmony_ci struct ata_device *dev; 33608c2ecf20Sopenharmony_ci int cnt = 0; 33618c2ecf20Sopenharmony_ci 33628c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) 33638c2ecf20Sopenharmony_ci if (dev->class == ATA_DEV_UNKNOWN) 33648c2ecf20Sopenharmony_ci cnt++; 33658c2ecf20Sopenharmony_ci return cnt; 33668c2ecf20Sopenharmony_ci} 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_cistatic int ata_eh_skip_recovery(struct ata_link *link) 33698c2ecf20Sopenharmony_ci{ 33708c2ecf20Sopenharmony_ci struct ata_port *ap = link->ap; 33718c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 33728c2ecf20Sopenharmony_ci struct ata_device *dev; 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ci /* skip disabled links */ 33758c2ecf20Sopenharmony_ci if (link->flags & ATA_LFLAG_DISABLED) 33768c2ecf20Sopenharmony_ci return 1; 33778c2ecf20Sopenharmony_ci 33788c2ecf20Sopenharmony_ci /* skip if explicitly requested */ 33798c2ecf20Sopenharmony_ci if (ehc->i.flags & ATA_EHI_NO_RECOVERY) 33808c2ecf20Sopenharmony_ci return 1; 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci /* thaw frozen port and recover failed devices */ 33838c2ecf20Sopenharmony_ci if ((ap->pflags & ATA_PFLAG_FROZEN) || ata_link_nr_enabled(link)) 33848c2ecf20Sopenharmony_ci return 0; 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ci /* reset at least once if reset is requested */ 33878c2ecf20Sopenharmony_ci if ((ehc->i.action & ATA_EH_RESET) && 33888c2ecf20Sopenharmony_ci !(ehc->i.flags & ATA_EHI_DID_RESET)) 33898c2ecf20Sopenharmony_ci return 0; 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci /* skip if class codes for all vacant slots are ATA_DEV_NONE */ 33928c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 33938c2ecf20Sopenharmony_ci if (dev->class == ATA_DEV_UNKNOWN && 33948c2ecf20Sopenharmony_ci ehc->classes[dev->devno] != ATA_DEV_NONE) 33958c2ecf20Sopenharmony_ci return 0; 33968c2ecf20Sopenharmony_ci } 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci return 1; 33998c2ecf20Sopenharmony_ci} 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_cistatic int ata_count_probe_trials_cb(struct ata_ering_entry *ent, void *void_arg) 34028c2ecf20Sopenharmony_ci{ 34038c2ecf20Sopenharmony_ci u64 interval = msecs_to_jiffies(ATA_EH_PROBE_TRIAL_INTERVAL); 34048c2ecf20Sopenharmony_ci u64 now = get_jiffies_64(); 34058c2ecf20Sopenharmony_ci int *trials = void_arg; 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_ci if ((ent->eflags & ATA_EFLAG_OLD_ER) || 34088c2ecf20Sopenharmony_ci (ent->timestamp < now - min(now, interval))) 34098c2ecf20Sopenharmony_ci return -1; 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci (*trials)++; 34128c2ecf20Sopenharmony_ci return 0; 34138c2ecf20Sopenharmony_ci} 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_cistatic int ata_eh_schedule_probe(struct ata_device *dev) 34168c2ecf20Sopenharmony_ci{ 34178c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &dev->link->eh_context; 34188c2ecf20Sopenharmony_ci struct ata_link *link = ata_dev_phys_link(dev); 34198c2ecf20Sopenharmony_ci int trials = 0; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci if (!(ehc->i.probe_mask & (1 << dev->devno)) || 34228c2ecf20Sopenharmony_ci (ehc->did_probe_mask & (1 << dev->devno))) 34238c2ecf20Sopenharmony_ci return 0; 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci ata_eh_detach_dev(dev); 34268c2ecf20Sopenharmony_ci ata_dev_init(dev); 34278c2ecf20Sopenharmony_ci ehc->did_probe_mask |= (1 << dev->devno); 34288c2ecf20Sopenharmony_ci ehc->i.action |= ATA_EH_RESET; 34298c2ecf20Sopenharmony_ci ehc->saved_xfer_mode[dev->devno] = 0; 34308c2ecf20Sopenharmony_ci ehc->saved_ncq_enabled &= ~(1 << dev->devno); 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci /* the link maybe in a deep sleep, wake it up */ 34338c2ecf20Sopenharmony_ci if (link->lpm_policy > ATA_LPM_MAX_POWER) { 34348c2ecf20Sopenharmony_ci if (ata_is_host_link(link)) 34358c2ecf20Sopenharmony_ci link->ap->ops->set_lpm(link, ATA_LPM_MAX_POWER, 34368c2ecf20Sopenharmony_ci ATA_LPM_EMPTY); 34378c2ecf20Sopenharmony_ci else 34388c2ecf20Sopenharmony_ci sata_pmp_set_lpm(link, ATA_LPM_MAX_POWER, 34398c2ecf20Sopenharmony_ci ATA_LPM_EMPTY); 34408c2ecf20Sopenharmony_ci } 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci /* Record and count probe trials on the ering. The specific 34438c2ecf20Sopenharmony_ci * error mask used is irrelevant. Because a successful device 34448c2ecf20Sopenharmony_ci * detection clears the ering, this count accumulates only if 34458c2ecf20Sopenharmony_ci * there are consecutive failed probes. 34468c2ecf20Sopenharmony_ci * 34478c2ecf20Sopenharmony_ci * If the count is equal to or higher than ATA_EH_PROBE_TRIALS 34488c2ecf20Sopenharmony_ci * in the last ATA_EH_PROBE_TRIAL_INTERVAL, link speed is 34498c2ecf20Sopenharmony_ci * forced to 1.5Gbps. 34508c2ecf20Sopenharmony_ci * 34518c2ecf20Sopenharmony_ci * This is to work around cases where failed link speed 34528c2ecf20Sopenharmony_ci * negotiation results in device misdetection leading to 34538c2ecf20Sopenharmony_ci * infinite DEVXCHG or PHRDY CHG events. 34548c2ecf20Sopenharmony_ci */ 34558c2ecf20Sopenharmony_ci ata_ering_record(&dev->ering, 0, AC_ERR_OTHER); 34568c2ecf20Sopenharmony_ci ata_ering_map(&dev->ering, ata_count_probe_trials_cb, &trials); 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci if (trials > ATA_EH_PROBE_TRIALS) 34598c2ecf20Sopenharmony_ci sata_down_spd_limit(link, 1); 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ci return 1; 34628c2ecf20Sopenharmony_ci} 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_cistatic int ata_eh_handle_dev_fail(struct ata_device *dev, int err) 34658c2ecf20Sopenharmony_ci{ 34668c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &dev->link->eh_context; 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci /* -EAGAIN from EH routine indicates retry without prejudice. 34698c2ecf20Sopenharmony_ci * The requester is responsible for ensuring forward progress. 34708c2ecf20Sopenharmony_ci */ 34718c2ecf20Sopenharmony_ci if (err != -EAGAIN) 34728c2ecf20Sopenharmony_ci ehc->tries[dev->devno]--; 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci switch (err) { 34758c2ecf20Sopenharmony_ci case -ENODEV: 34768c2ecf20Sopenharmony_ci /* device missing or wrong IDENTIFY data, schedule probing */ 34778c2ecf20Sopenharmony_ci ehc->i.probe_mask |= (1 << dev->devno); 34788c2ecf20Sopenharmony_ci fallthrough; 34798c2ecf20Sopenharmony_ci case -EINVAL: 34808c2ecf20Sopenharmony_ci /* give it just one more chance */ 34818c2ecf20Sopenharmony_ci ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1); 34828c2ecf20Sopenharmony_ci fallthrough; 34838c2ecf20Sopenharmony_ci case -EIO: 34848c2ecf20Sopenharmony_ci if (ehc->tries[dev->devno] == 1) { 34858c2ecf20Sopenharmony_ci /* This is the last chance, better to slow 34868c2ecf20Sopenharmony_ci * down than lose it. 34878c2ecf20Sopenharmony_ci */ 34888c2ecf20Sopenharmony_ci sata_down_spd_limit(ata_dev_phys_link(dev), 0); 34898c2ecf20Sopenharmony_ci if (dev->pio_mode > XFER_PIO_0) 34908c2ecf20Sopenharmony_ci ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); 34918c2ecf20Sopenharmony_ci } 34928c2ecf20Sopenharmony_ci } 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_ci if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) { 34958c2ecf20Sopenharmony_ci /* disable device if it has used up all its chances */ 34968c2ecf20Sopenharmony_ci ata_dev_disable(dev); 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci /* detach if offline */ 34998c2ecf20Sopenharmony_ci if (ata_phys_link_offline(ata_dev_phys_link(dev))) 35008c2ecf20Sopenharmony_ci ata_eh_detach_dev(dev); 35018c2ecf20Sopenharmony_ci 35028c2ecf20Sopenharmony_ci /* schedule probe if necessary */ 35038c2ecf20Sopenharmony_ci if (ata_eh_schedule_probe(dev)) { 35048c2ecf20Sopenharmony_ci ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; 35058c2ecf20Sopenharmony_ci memset(ehc->cmd_timeout_idx[dev->devno], 0, 35068c2ecf20Sopenharmony_ci sizeof(ehc->cmd_timeout_idx[dev->devno])); 35078c2ecf20Sopenharmony_ci } 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci return 1; 35108c2ecf20Sopenharmony_ci } else { 35118c2ecf20Sopenharmony_ci ehc->i.action |= ATA_EH_RESET; 35128c2ecf20Sopenharmony_ci return 0; 35138c2ecf20Sopenharmony_ci } 35148c2ecf20Sopenharmony_ci} 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci/** 35178c2ecf20Sopenharmony_ci * ata_eh_recover - recover host port after error 35188c2ecf20Sopenharmony_ci * @ap: host port to recover 35198c2ecf20Sopenharmony_ci * @prereset: prereset method (can be NULL) 35208c2ecf20Sopenharmony_ci * @softreset: softreset method (can be NULL) 35218c2ecf20Sopenharmony_ci * @hardreset: hardreset method (can be NULL) 35228c2ecf20Sopenharmony_ci * @postreset: postreset method (can be NULL) 35238c2ecf20Sopenharmony_ci * @r_failed_link: out parameter for failed link 35248c2ecf20Sopenharmony_ci * 35258c2ecf20Sopenharmony_ci * This is the alpha and omega, eum and yang, heart and soul of 35268c2ecf20Sopenharmony_ci * libata exception handling. On entry, actions required to 35278c2ecf20Sopenharmony_ci * recover each link and hotplug requests are recorded in the 35288c2ecf20Sopenharmony_ci * link's eh_context. This function executes all the operations 35298c2ecf20Sopenharmony_ci * with appropriate retrials and fallbacks to resurrect failed 35308c2ecf20Sopenharmony_ci * devices, detach goners and greet newcomers. 35318c2ecf20Sopenharmony_ci * 35328c2ecf20Sopenharmony_ci * LOCKING: 35338c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 35348c2ecf20Sopenharmony_ci * 35358c2ecf20Sopenharmony_ci * RETURNS: 35368c2ecf20Sopenharmony_ci * 0 on success, -errno on failure. 35378c2ecf20Sopenharmony_ci */ 35388c2ecf20Sopenharmony_ciint ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, 35398c2ecf20Sopenharmony_ci ata_reset_fn_t softreset, ata_reset_fn_t hardreset, 35408c2ecf20Sopenharmony_ci ata_postreset_fn_t postreset, 35418c2ecf20Sopenharmony_ci struct ata_link **r_failed_link) 35428c2ecf20Sopenharmony_ci{ 35438c2ecf20Sopenharmony_ci struct ata_link *link; 35448c2ecf20Sopenharmony_ci struct ata_device *dev; 35458c2ecf20Sopenharmony_ci int rc, nr_fails; 35468c2ecf20Sopenharmony_ci unsigned long flags, deadline; 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_ci DPRINTK("ENTER\n"); 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci /* prep for recovery */ 35518c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) { 35528c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci /* re-enable link? */ 35558c2ecf20Sopenharmony_ci if (ehc->i.action & ATA_EH_ENABLE_LINK) { 35568c2ecf20Sopenharmony_ci ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK); 35578c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 35588c2ecf20Sopenharmony_ci link->flags &= ~ATA_LFLAG_DISABLED; 35598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 35608c2ecf20Sopenharmony_ci ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK); 35618c2ecf20Sopenharmony_ci } 35628c2ecf20Sopenharmony_ci 35638c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 35648c2ecf20Sopenharmony_ci if (link->flags & ATA_LFLAG_NO_RETRY) 35658c2ecf20Sopenharmony_ci ehc->tries[dev->devno] = 1; 35668c2ecf20Sopenharmony_ci else 35678c2ecf20Sopenharmony_ci ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; 35688c2ecf20Sopenharmony_ci 35698c2ecf20Sopenharmony_ci /* collect port action mask recorded in dev actions */ 35708c2ecf20Sopenharmony_ci ehc->i.action |= ehc->i.dev_action[dev->devno] & 35718c2ecf20Sopenharmony_ci ~ATA_EH_PERDEV_MASK; 35728c2ecf20Sopenharmony_ci ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci /* process hotplug request */ 35758c2ecf20Sopenharmony_ci if (dev->flags & ATA_DFLAG_DETACH) 35768c2ecf20Sopenharmony_ci ata_eh_detach_dev(dev); 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci /* schedule probe if necessary */ 35798c2ecf20Sopenharmony_ci if (!ata_dev_enabled(dev)) 35808c2ecf20Sopenharmony_ci ata_eh_schedule_probe(dev); 35818c2ecf20Sopenharmony_ci } 35828c2ecf20Sopenharmony_ci } 35838c2ecf20Sopenharmony_ci 35848c2ecf20Sopenharmony_ci retry: 35858c2ecf20Sopenharmony_ci rc = 0; 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_ci /* if UNLOADING, finish immediately */ 35888c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_UNLOADING) 35898c2ecf20Sopenharmony_ci goto out; 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_ci /* prep for EH */ 35928c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) { 35938c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci /* skip EH if possible. */ 35968c2ecf20Sopenharmony_ci if (ata_eh_skip_recovery(link)) 35978c2ecf20Sopenharmony_ci ehc->i.action = 0; 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) 36008c2ecf20Sopenharmony_ci ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; 36018c2ecf20Sopenharmony_ci } 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci /* reset */ 36048c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) { 36058c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 36068c2ecf20Sopenharmony_ci 36078c2ecf20Sopenharmony_ci if (!(ehc->i.action & ATA_EH_RESET)) 36088c2ecf20Sopenharmony_ci continue; 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci rc = ata_eh_reset(link, ata_link_nr_vacant(link), 36118c2ecf20Sopenharmony_ci prereset, softreset, hardreset, postreset); 36128c2ecf20Sopenharmony_ci if (rc) { 36138c2ecf20Sopenharmony_ci ata_link_err(link, "reset failed, giving up\n"); 36148c2ecf20Sopenharmony_ci goto out; 36158c2ecf20Sopenharmony_ci } 36168c2ecf20Sopenharmony_ci } 36178c2ecf20Sopenharmony_ci 36188c2ecf20Sopenharmony_ci do { 36198c2ecf20Sopenharmony_ci unsigned long now; 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci /* 36228c2ecf20Sopenharmony_ci * clears ATA_EH_PARK in eh_info and resets 36238c2ecf20Sopenharmony_ci * ap->park_req_pending 36248c2ecf20Sopenharmony_ci */ 36258c2ecf20Sopenharmony_ci ata_eh_pull_park_action(ap); 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci deadline = jiffies; 36288c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) { 36298c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 36308c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 36318c2ecf20Sopenharmony_ci unsigned long tmp; 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_ci if (dev->class != ATA_DEV_ATA && 36348c2ecf20Sopenharmony_ci dev->class != ATA_DEV_ZAC) 36358c2ecf20Sopenharmony_ci continue; 36368c2ecf20Sopenharmony_ci if (!(ehc->i.dev_action[dev->devno] & 36378c2ecf20Sopenharmony_ci ATA_EH_PARK)) 36388c2ecf20Sopenharmony_ci continue; 36398c2ecf20Sopenharmony_ci tmp = dev->unpark_deadline; 36408c2ecf20Sopenharmony_ci if (time_before(deadline, tmp)) 36418c2ecf20Sopenharmony_ci deadline = tmp; 36428c2ecf20Sopenharmony_ci else if (time_before_eq(tmp, jiffies)) 36438c2ecf20Sopenharmony_ci continue; 36448c2ecf20Sopenharmony_ci if (ehc->unloaded_mask & (1 << dev->devno)) 36458c2ecf20Sopenharmony_ci continue; 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci ata_eh_park_issue_cmd(dev, 1); 36488c2ecf20Sopenharmony_ci } 36498c2ecf20Sopenharmony_ci } 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci now = jiffies; 36528c2ecf20Sopenharmony_ci if (time_before_eq(deadline, now)) 36538c2ecf20Sopenharmony_ci break; 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci ata_eh_release(ap); 36568c2ecf20Sopenharmony_ci deadline = wait_for_completion_timeout(&ap->park_req_pending, 36578c2ecf20Sopenharmony_ci deadline - now); 36588c2ecf20Sopenharmony_ci ata_eh_acquire(ap); 36598c2ecf20Sopenharmony_ci } while (deadline); 36608c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) { 36618c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 36628c2ecf20Sopenharmony_ci if (!(link->eh_context.unloaded_mask & 36638c2ecf20Sopenharmony_ci (1 << dev->devno))) 36648c2ecf20Sopenharmony_ci continue; 36658c2ecf20Sopenharmony_ci 36668c2ecf20Sopenharmony_ci ata_eh_park_issue_cmd(dev, 0); 36678c2ecf20Sopenharmony_ci ata_eh_done(link, dev, ATA_EH_PARK); 36688c2ecf20Sopenharmony_ci } 36698c2ecf20Sopenharmony_ci } 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci /* the rest */ 36728c2ecf20Sopenharmony_ci nr_fails = 0; 36738c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, PMP_FIRST) { 36748c2ecf20Sopenharmony_ci struct ata_eh_context *ehc = &link->eh_context; 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci if (sata_pmp_attached(ap) && ata_is_host_link(link)) 36778c2ecf20Sopenharmony_ci goto config_lpm; 36788c2ecf20Sopenharmony_ci 36798c2ecf20Sopenharmony_ci /* revalidate existing devices and attach new ones */ 36808c2ecf20Sopenharmony_ci rc = ata_eh_revalidate_and_attach(link, &dev); 36818c2ecf20Sopenharmony_ci if (rc) 36828c2ecf20Sopenharmony_ci goto rest_fail; 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_ci /* if PMP got attached, return, pmp EH will take care of it */ 36858c2ecf20Sopenharmony_ci if (link->device->class == ATA_DEV_PMP) { 36868c2ecf20Sopenharmony_ci ehc->i.action = 0; 36878c2ecf20Sopenharmony_ci return 0; 36888c2ecf20Sopenharmony_ci } 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci /* configure transfer mode if necessary */ 36918c2ecf20Sopenharmony_ci if (ehc->i.flags & ATA_EHI_SETMODE) { 36928c2ecf20Sopenharmony_ci rc = ata_set_mode(link, &dev); 36938c2ecf20Sopenharmony_ci if (rc) 36948c2ecf20Sopenharmony_ci goto rest_fail; 36958c2ecf20Sopenharmony_ci ehc->i.flags &= ~ATA_EHI_SETMODE; 36968c2ecf20Sopenharmony_ci } 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci /* If reset has been issued, clear UA to avoid 36998c2ecf20Sopenharmony_ci * disrupting the current users of the device. 37008c2ecf20Sopenharmony_ci */ 37018c2ecf20Sopenharmony_ci if (ehc->i.flags & ATA_EHI_DID_RESET) { 37028c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 37038c2ecf20Sopenharmony_ci if (dev->class != ATA_DEV_ATAPI) 37048c2ecf20Sopenharmony_ci continue; 37058c2ecf20Sopenharmony_ci rc = atapi_eh_clear_ua(dev); 37068c2ecf20Sopenharmony_ci if (rc) 37078c2ecf20Sopenharmony_ci goto rest_fail; 37088c2ecf20Sopenharmony_ci if (zpodd_dev_enabled(dev)) 37098c2ecf20Sopenharmony_ci zpodd_post_poweron(dev); 37108c2ecf20Sopenharmony_ci } 37118c2ecf20Sopenharmony_ci } 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci /* retry flush if necessary */ 37148c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 37158c2ecf20Sopenharmony_ci if (dev->class != ATA_DEV_ATA && 37168c2ecf20Sopenharmony_ci dev->class != ATA_DEV_ZAC) 37178c2ecf20Sopenharmony_ci continue; 37188c2ecf20Sopenharmony_ci rc = ata_eh_maybe_retry_flush(dev); 37198c2ecf20Sopenharmony_ci if (rc) 37208c2ecf20Sopenharmony_ci goto rest_fail; 37218c2ecf20Sopenharmony_ci } 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci config_lpm: 37248c2ecf20Sopenharmony_ci /* configure link power saving */ 37258c2ecf20Sopenharmony_ci if (link->lpm_policy != ap->target_lpm_policy) { 37268c2ecf20Sopenharmony_ci rc = ata_eh_set_lpm(link, ap->target_lpm_policy, &dev); 37278c2ecf20Sopenharmony_ci if (rc) 37288c2ecf20Sopenharmony_ci goto rest_fail; 37298c2ecf20Sopenharmony_ci } 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci /* this link is okay now */ 37328c2ecf20Sopenharmony_ci ehc->i.flags = 0; 37338c2ecf20Sopenharmony_ci continue; 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_ci rest_fail: 37368c2ecf20Sopenharmony_ci nr_fails++; 37378c2ecf20Sopenharmony_ci if (dev) 37388c2ecf20Sopenharmony_ci ata_eh_handle_dev_fail(dev, rc); 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci if (ap->pflags & ATA_PFLAG_FROZEN) { 37418c2ecf20Sopenharmony_ci /* PMP reset requires working host port. 37428c2ecf20Sopenharmony_ci * Can't retry if it's frozen. 37438c2ecf20Sopenharmony_ci */ 37448c2ecf20Sopenharmony_ci if (sata_pmp_attached(ap)) 37458c2ecf20Sopenharmony_ci goto out; 37468c2ecf20Sopenharmony_ci break; 37478c2ecf20Sopenharmony_ci } 37488c2ecf20Sopenharmony_ci } 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_ci if (nr_fails) 37518c2ecf20Sopenharmony_ci goto retry; 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci out: 37548c2ecf20Sopenharmony_ci if (rc && r_failed_link) 37558c2ecf20Sopenharmony_ci *r_failed_link = link; 37568c2ecf20Sopenharmony_ci 37578c2ecf20Sopenharmony_ci DPRINTK("EXIT, rc=%d\n", rc); 37588c2ecf20Sopenharmony_ci return rc; 37598c2ecf20Sopenharmony_ci} 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ci/** 37628c2ecf20Sopenharmony_ci * ata_eh_finish - finish up EH 37638c2ecf20Sopenharmony_ci * @ap: host port to finish EH for 37648c2ecf20Sopenharmony_ci * 37658c2ecf20Sopenharmony_ci * Recovery is complete. Clean up EH states and retry or finish 37668c2ecf20Sopenharmony_ci * failed qcs. 37678c2ecf20Sopenharmony_ci * 37688c2ecf20Sopenharmony_ci * LOCKING: 37698c2ecf20Sopenharmony_ci * None. 37708c2ecf20Sopenharmony_ci */ 37718c2ecf20Sopenharmony_civoid ata_eh_finish(struct ata_port *ap) 37728c2ecf20Sopenharmony_ci{ 37738c2ecf20Sopenharmony_ci struct ata_queued_cmd *qc; 37748c2ecf20Sopenharmony_ci int tag; 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_ci /* retry or finish qcs */ 37778c2ecf20Sopenharmony_ci ata_qc_for_each_raw(ap, qc, tag) { 37788c2ecf20Sopenharmony_ci if (!(qc->flags & ATA_QCFLAG_FAILED)) 37798c2ecf20Sopenharmony_ci continue; 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci if (qc->err_mask) { 37828c2ecf20Sopenharmony_ci /* FIXME: Once EH migration is complete, 37838c2ecf20Sopenharmony_ci * generate sense data in this function, 37848c2ecf20Sopenharmony_ci * considering both err_mask and tf. 37858c2ecf20Sopenharmony_ci */ 37868c2ecf20Sopenharmony_ci if (qc->flags & ATA_QCFLAG_RETRY) 37878c2ecf20Sopenharmony_ci ata_eh_qc_retry(qc); 37888c2ecf20Sopenharmony_ci else 37898c2ecf20Sopenharmony_ci ata_eh_qc_complete(qc); 37908c2ecf20Sopenharmony_ci } else { 37918c2ecf20Sopenharmony_ci if (qc->flags & ATA_QCFLAG_SENSE_VALID) { 37928c2ecf20Sopenharmony_ci ata_eh_qc_complete(qc); 37938c2ecf20Sopenharmony_ci } else { 37948c2ecf20Sopenharmony_ci /* feed zero TF to sense generation */ 37958c2ecf20Sopenharmony_ci memset(&qc->result_tf, 0, sizeof(qc->result_tf)); 37968c2ecf20Sopenharmony_ci ata_eh_qc_retry(qc); 37978c2ecf20Sopenharmony_ci } 37988c2ecf20Sopenharmony_ci } 37998c2ecf20Sopenharmony_ci } 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci /* make sure nr_active_links is zero after EH */ 38028c2ecf20Sopenharmony_ci WARN_ON(ap->nr_active_links); 38038c2ecf20Sopenharmony_ci ap->nr_active_links = 0; 38048c2ecf20Sopenharmony_ci} 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci/** 38078c2ecf20Sopenharmony_ci * ata_do_eh - do standard error handling 38088c2ecf20Sopenharmony_ci * @ap: host port to handle error for 38098c2ecf20Sopenharmony_ci * 38108c2ecf20Sopenharmony_ci * @prereset: prereset method (can be NULL) 38118c2ecf20Sopenharmony_ci * @softreset: softreset method (can be NULL) 38128c2ecf20Sopenharmony_ci * @hardreset: hardreset method (can be NULL) 38138c2ecf20Sopenharmony_ci * @postreset: postreset method (can be NULL) 38148c2ecf20Sopenharmony_ci * 38158c2ecf20Sopenharmony_ci * Perform standard error handling sequence. 38168c2ecf20Sopenharmony_ci * 38178c2ecf20Sopenharmony_ci * LOCKING: 38188c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 38198c2ecf20Sopenharmony_ci */ 38208c2ecf20Sopenharmony_civoid ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, 38218c2ecf20Sopenharmony_ci ata_reset_fn_t softreset, ata_reset_fn_t hardreset, 38228c2ecf20Sopenharmony_ci ata_postreset_fn_t postreset) 38238c2ecf20Sopenharmony_ci{ 38248c2ecf20Sopenharmony_ci struct ata_device *dev; 38258c2ecf20Sopenharmony_ci int rc; 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_ci ata_eh_autopsy(ap); 38288c2ecf20Sopenharmony_ci ata_eh_report(ap); 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_ci rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset, 38318c2ecf20Sopenharmony_ci NULL); 38328c2ecf20Sopenharmony_ci if (rc) { 38338c2ecf20Sopenharmony_ci ata_for_each_dev(dev, &ap->link, ALL) 38348c2ecf20Sopenharmony_ci ata_dev_disable(dev); 38358c2ecf20Sopenharmony_ci } 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci ata_eh_finish(ap); 38388c2ecf20Sopenharmony_ci} 38398c2ecf20Sopenharmony_ci 38408c2ecf20Sopenharmony_ci/** 38418c2ecf20Sopenharmony_ci * ata_std_error_handler - standard error handler 38428c2ecf20Sopenharmony_ci * @ap: host port to handle error for 38438c2ecf20Sopenharmony_ci * 38448c2ecf20Sopenharmony_ci * Standard error handler 38458c2ecf20Sopenharmony_ci * 38468c2ecf20Sopenharmony_ci * LOCKING: 38478c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 38488c2ecf20Sopenharmony_ci */ 38498c2ecf20Sopenharmony_civoid ata_std_error_handler(struct ata_port *ap) 38508c2ecf20Sopenharmony_ci{ 38518c2ecf20Sopenharmony_ci struct ata_port_operations *ops = ap->ops; 38528c2ecf20Sopenharmony_ci ata_reset_fn_t hardreset = ops->hardreset; 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_ci /* ignore built-in hardreset if SCR access is not available */ 38558c2ecf20Sopenharmony_ci if (hardreset == sata_std_hardreset && !sata_scr_valid(&ap->link)) 38568c2ecf20Sopenharmony_ci hardreset = NULL; 38578c2ecf20Sopenharmony_ci 38588c2ecf20Sopenharmony_ci ata_do_eh(ap, ops->prereset, ops->softreset, hardreset, ops->postreset); 38598c2ecf20Sopenharmony_ci} 38608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_std_error_handler); 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 38638c2ecf20Sopenharmony_ci/** 38648c2ecf20Sopenharmony_ci * ata_eh_handle_port_suspend - perform port suspend operation 38658c2ecf20Sopenharmony_ci * @ap: port to suspend 38668c2ecf20Sopenharmony_ci * 38678c2ecf20Sopenharmony_ci * Suspend @ap. 38688c2ecf20Sopenharmony_ci * 38698c2ecf20Sopenharmony_ci * LOCKING: 38708c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 38718c2ecf20Sopenharmony_ci */ 38728c2ecf20Sopenharmony_cistatic void ata_eh_handle_port_suspend(struct ata_port *ap) 38738c2ecf20Sopenharmony_ci{ 38748c2ecf20Sopenharmony_ci unsigned long flags; 38758c2ecf20Sopenharmony_ci int rc = 0; 38768c2ecf20Sopenharmony_ci struct ata_device *dev; 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_ci /* are we suspending? */ 38798c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 38808c2ecf20Sopenharmony_ci if (!(ap->pflags & ATA_PFLAG_PM_PENDING) || 38818c2ecf20Sopenharmony_ci ap->pm_mesg.event & PM_EVENT_RESUME) { 38828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 38838c2ecf20Sopenharmony_ci return; 38848c2ecf20Sopenharmony_ci } 38858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci /* 38908c2ecf20Sopenharmony_ci * If we have a ZPODD attached, check its zero 38918c2ecf20Sopenharmony_ci * power ready status before the port is frozen. 38928c2ecf20Sopenharmony_ci * Only needed for runtime suspend. 38938c2ecf20Sopenharmony_ci */ 38948c2ecf20Sopenharmony_ci if (PMSG_IS_AUTO(ap->pm_mesg)) { 38958c2ecf20Sopenharmony_ci ata_for_each_dev(dev, &ap->link, ENABLED) { 38968c2ecf20Sopenharmony_ci if (zpodd_dev_enabled(dev)) 38978c2ecf20Sopenharmony_ci zpodd_on_suspend(dev); 38988c2ecf20Sopenharmony_ci } 38998c2ecf20Sopenharmony_ci } 39008c2ecf20Sopenharmony_ci 39018c2ecf20Sopenharmony_ci /* tell ACPI we're suspending */ 39028c2ecf20Sopenharmony_ci rc = ata_acpi_on_suspend(ap); 39038c2ecf20Sopenharmony_ci if (rc) 39048c2ecf20Sopenharmony_ci goto out; 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_ci /* suspend */ 39078c2ecf20Sopenharmony_ci ata_eh_freeze_port(ap); 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ci if (ap->ops->port_suspend) 39108c2ecf20Sopenharmony_ci rc = ap->ops->port_suspend(ap, ap->pm_mesg); 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ci ata_acpi_set_state(ap, ap->pm_mesg); 39138c2ecf20Sopenharmony_ci out: 39148c2ecf20Sopenharmony_ci /* update the flags */ 39158c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 39168c2ecf20Sopenharmony_ci 39178c2ecf20Sopenharmony_ci ap->pflags &= ~ATA_PFLAG_PM_PENDING; 39188c2ecf20Sopenharmony_ci if (rc == 0) 39198c2ecf20Sopenharmony_ci ap->pflags |= ATA_PFLAG_SUSPENDED; 39208c2ecf20Sopenharmony_ci else if (ap->pflags & ATA_PFLAG_FROZEN) 39218c2ecf20Sopenharmony_ci ata_port_schedule_eh(ap); 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci return; 39268c2ecf20Sopenharmony_ci} 39278c2ecf20Sopenharmony_ci 39288c2ecf20Sopenharmony_ci/** 39298c2ecf20Sopenharmony_ci * ata_eh_handle_port_resume - perform port resume operation 39308c2ecf20Sopenharmony_ci * @ap: port to resume 39318c2ecf20Sopenharmony_ci * 39328c2ecf20Sopenharmony_ci * Resume @ap. 39338c2ecf20Sopenharmony_ci * 39348c2ecf20Sopenharmony_ci * LOCKING: 39358c2ecf20Sopenharmony_ci * Kernel thread context (may sleep). 39368c2ecf20Sopenharmony_ci */ 39378c2ecf20Sopenharmony_cistatic void ata_eh_handle_port_resume(struct ata_port *ap) 39388c2ecf20Sopenharmony_ci{ 39398c2ecf20Sopenharmony_ci struct ata_link *link; 39408c2ecf20Sopenharmony_ci struct ata_device *dev; 39418c2ecf20Sopenharmony_ci unsigned long flags; 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci /* are we resuming? */ 39448c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 39458c2ecf20Sopenharmony_ci if (!(ap->pflags & ATA_PFLAG_PM_PENDING) || 39468c2ecf20Sopenharmony_ci !(ap->pm_mesg.event & PM_EVENT_RESUME)) { 39478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 39488c2ecf20Sopenharmony_ci return; 39498c2ecf20Sopenharmony_ci } 39508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci WARN_ON(!(ap->pflags & ATA_PFLAG_SUSPENDED)); 39538c2ecf20Sopenharmony_ci 39548c2ecf20Sopenharmony_ci /* 39558c2ecf20Sopenharmony_ci * Error timestamps are in jiffies which doesn't run while 39568c2ecf20Sopenharmony_ci * suspended and PHY events during resume isn't too uncommon. 39578c2ecf20Sopenharmony_ci * When the two are combined, it can lead to unnecessary speed 39588c2ecf20Sopenharmony_ci * downs if the machine is suspended and resumed repeatedly. 39598c2ecf20Sopenharmony_ci * Clear error history. 39608c2ecf20Sopenharmony_ci */ 39618c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, HOST_FIRST) 39628c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ALL) 39638c2ecf20Sopenharmony_ci ata_ering_clear(&dev->ering); 39648c2ecf20Sopenharmony_ci 39658c2ecf20Sopenharmony_ci ata_acpi_set_state(ap, ap->pm_mesg); 39668c2ecf20Sopenharmony_ci 39678c2ecf20Sopenharmony_ci if (ap->ops->port_resume) 39688c2ecf20Sopenharmony_ci ap->ops->port_resume(ap); 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci /* tell ACPI that we're resuming */ 39718c2ecf20Sopenharmony_ci ata_acpi_on_resume(ap); 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci /* update the flags */ 39748c2ecf20Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 39758c2ecf20Sopenharmony_ci ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); 39768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 39778c2ecf20Sopenharmony_ci} 39788c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 3979