18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * zfcp device driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Error Recovery Procedures (ERP). 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2002, 2020 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "zfcp" 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kthread.h> 148c2ecf20Sopenharmony_ci#include <linux/bug.h> 158c2ecf20Sopenharmony_ci#include "zfcp_ext.h" 168c2ecf20Sopenharmony_ci#include "zfcp_reqlist.h" 178c2ecf20Sopenharmony_ci#include "zfcp_diag.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define ZFCP_MAX_ERPS 3 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cienum zfcp_erp_act_flags { 228c2ecf20Sopenharmony_ci ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000, 238c2ecf20Sopenharmony_ci ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000, 248c2ecf20Sopenharmony_ci ZFCP_STATUS_ERP_DISMISSED = 0x00200000, 258c2ecf20Sopenharmony_ci ZFCP_STATUS_ERP_LOWMEM = 0x00400000, 268c2ecf20Sopenharmony_ci ZFCP_STATUS_ERP_NO_REF = 0x00800000, 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * Eyecatcher pseudo flag to bitwise or-combine with enum zfcp_erp_act_type. 318c2ecf20Sopenharmony_ci * Used to indicate that an ERP action could not be set up despite a detected 328c2ecf20Sopenharmony_ci * need for some recovery. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci#define ZFCP_ERP_ACTION_NONE 0xc0 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Eyecatcher pseudo flag to bitwise or-combine with enum zfcp_erp_act_type. 378c2ecf20Sopenharmony_ci * Used to indicate that ERP not needed because the object has 388c2ecf20Sopenharmony_ci * ZFCP_STATUS_COMMON_ERP_FAILED. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci#define ZFCP_ERP_ACTION_FAILED 0xe0 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cienum zfcp_erp_act_result { 438c2ecf20Sopenharmony_ci ZFCP_ERP_SUCCEEDED = 0, 448c2ecf20Sopenharmony_ci ZFCP_ERP_FAILED = 1, 458c2ecf20Sopenharmony_ci ZFCP_ERP_CONTINUES = 2, 468c2ecf20Sopenharmony_ci ZFCP_ERP_EXIT = 3, 478c2ecf20Sopenharmony_ci ZFCP_ERP_DISMISSED = 4, 488c2ecf20Sopenharmony_ci ZFCP_ERP_NOMEM = 5, 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci zfcp_erp_clear_adapter_status(adapter, 548c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_UNBLOCKED | mask); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic bool zfcp_erp_action_is_running(struct zfcp_erp_action *act) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct zfcp_erp_action *curr_act; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci list_for_each_entry(curr_act, &act->adapter->erp_running_head, list) 628c2ecf20Sopenharmony_ci if (act == curr_act) 638c2ecf20Sopenharmony_ci return true; 648c2ecf20Sopenharmony_ci return false; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void zfcp_erp_action_ready(struct zfcp_erp_action *act) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci list_move(&act->list, &adapter->erp_ready_head); 728c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("erardy1", act); 738c2ecf20Sopenharmony_ci wake_up(&adapter->erp_ready_wq); 748c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("erardy2", act); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci act->status |= ZFCP_STATUS_ERP_DISMISSED; 808c2ecf20Sopenharmony_ci if (zfcp_erp_action_is_running(act)) 818c2ecf20Sopenharmony_ci zfcp_erp_action_ready(act); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE) 898c2ecf20Sopenharmony_ci zfcp_erp_action_dismiss(&zfcp_sdev->erp_action); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dismiss_port(struct zfcp_port *port) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct scsi_device *sdev; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) 978c2ecf20Sopenharmony_ci zfcp_erp_action_dismiss(&port->erp_action); 988c2ecf20Sopenharmony_ci else { 998c2ecf20Sopenharmony_ci spin_lock(port->adapter->scsi_host->host_lock); 1008c2ecf20Sopenharmony_ci __shost_for_each_device(sdev, port->adapter->scsi_host) 1018c2ecf20Sopenharmony_ci if (sdev_to_zfcp(sdev)->port == port) 1028c2ecf20Sopenharmony_ci zfcp_erp_action_dismiss_lun(sdev); 1038c2ecf20Sopenharmony_ci spin_unlock(port->adapter->scsi_host->host_lock); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct zfcp_port *port; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE) 1128c2ecf20Sopenharmony_ci zfcp_erp_action_dismiss(&adapter->erp_action); 1138c2ecf20Sopenharmony_ci else { 1148c2ecf20Sopenharmony_ci read_lock(&adapter->port_list_lock); 1158c2ecf20Sopenharmony_ci list_for_each_entry(port, &adapter->port_list, list) 1168c2ecf20Sopenharmony_ci zfcp_erp_action_dismiss_port(port); 1178c2ecf20Sopenharmony_ci read_unlock(&adapter->port_list_lock); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_type zfcp_erp_handle_failed( 1228c2ecf20Sopenharmony_ci enum zfcp_erp_act_type want, struct zfcp_adapter *adapter, 1238c2ecf20Sopenharmony_ci struct zfcp_port *port, struct scsi_device *sdev) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci enum zfcp_erp_act_type need = want; 1268c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zsdev; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci switch (want) { 1298c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 1308c2ecf20Sopenharmony_ci zsdev = sdev_to_zfcp(sdev); 1318c2ecf20Sopenharmony_ci if (atomic_read(&zsdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) 1328c2ecf20Sopenharmony_ci need = 0; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1358c2ecf20Sopenharmony_ci if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) 1368c2ecf20Sopenharmony_ci need = 0; 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 1398c2ecf20Sopenharmony_ci if (atomic_read(&port->status) & 1408c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED) { 1418c2ecf20Sopenharmony_ci need = 0; 1428c2ecf20Sopenharmony_ci /* ensure propagation of failed status to new devices */ 1438c2ecf20Sopenharmony_ci zfcp_erp_set_port_status( 1448c2ecf20Sopenharmony_ci port, ZFCP_STATUS_COMMON_ERP_FAILED); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1488c2ecf20Sopenharmony_ci if (atomic_read(&adapter->status) & 1498c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED) { 1508c2ecf20Sopenharmony_ci need = 0; 1518c2ecf20Sopenharmony_ci /* ensure propagation of failed status to new devices */ 1528c2ecf20Sopenharmony_ci zfcp_erp_set_adapter_status( 1538c2ecf20Sopenharmony_ci adapter, ZFCP_STATUS_COMMON_ERP_FAILED); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return need; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want, 1628c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter, 1638c2ecf20Sopenharmony_ci struct zfcp_port *port, 1648c2ecf20Sopenharmony_ci struct scsi_device *sdev) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci enum zfcp_erp_act_type need = want; 1678c2ecf20Sopenharmony_ci int l_status, p_status, a_status; 1688c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci switch (want) { 1718c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 1728c2ecf20Sopenharmony_ci zfcp_sdev = sdev_to_zfcp(sdev); 1738c2ecf20Sopenharmony_ci l_status = atomic_read(&zfcp_sdev->status); 1748c2ecf20Sopenharmony_ci if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE) 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci p_status = atomic_read(&port->status); 1778c2ecf20Sopenharmony_ci if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || 1788c2ecf20Sopenharmony_ci p_status & ZFCP_STATUS_COMMON_ERP_FAILED) 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) 1818c2ecf20Sopenharmony_ci need = ZFCP_ERP_ACTION_REOPEN_PORT; 1828c2ecf20Sopenharmony_ci fallthrough; 1838c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1848c2ecf20Sopenharmony_ci p_status = atomic_read(&port->status); 1858c2ecf20Sopenharmony_ci if (!(p_status & ZFCP_STATUS_COMMON_OPEN)) 1868c2ecf20Sopenharmony_ci need = ZFCP_ERP_ACTION_REOPEN_PORT; 1878c2ecf20Sopenharmony_ci fallthrough; 1888c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 1898c2ecf20Sopenharmony_ci p_status = atomic_read(&port->status); 1908c2ecf20Sopenharmony_ci if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE) 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci a_status = atomic_read(&adapter->status); 1938c2ecf20Sopenharmony_ci if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || 1948c2ecf20Sopenharmony_ci a_status & ZFCP_STATUS_COMMON_ERP_FAILED) 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci if (p_status & ZFCP_STATUS_COMMON_NOESC) 1978c2ecf20Sopenharmony_ci return need; 1988c2ecf20Sopenharmony_ci if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) 1998c2ecf20Sopenharmony_ci need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; 2008c2ecf20Sopenharmony_ci fallthrough; 2018c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 2028c2ecf20Sopenharmony_ci a_status = atomic_read(&adapter->status); 2038c2ecf20Sopenharmony_ci if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) && 2068c2ecf20Sopenharmony_ci !(a_status & ZFCP_STATUS_COMMON_OPEN)) 2078c2ecf20Sopenharmony_ci return 0; /* shutdown requested for closed adapter */ 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return need; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic struct zfcp_erp_action *zfcp_erp_setup_act(enum zfcp_erp_act_type need, 2148c2ecf20Sopenharmony_ci u32 act_status, 2158c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter, 2168c2ecf20Sopenharmony_ci struct zfcp_port *port, 2178c2ecf20Sopenharmony_ci struct scsi_device *sdev) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action; 2208c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(need != ZFCP_ERP_ACTION_REOPEN_LUN && 2238c2ecf20Sopenharmony_ci need != ZFCP_ERP_ACTION_REOPEN_PORT && 2248c2ecf20Sopenharmony_ci need != ZFCP_ERP_ACTION_REOPEN_PORT_FORCED && 2258c2ecf20Sopenharmony_ci need != ZFCP_ERP_ACTION_REOPEN_ADAPTER)) 2268c2ecf20Sopenharmony_ci return NULL; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci switch (need) { 2298c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 2308c2ecf20Sopenharmony_ci zfcp_sdev = sdev_to_zfcp(sdev); 2318c2ecf20Sopenharmony_ci if (!(act_status & ZFCP_STATUS_ERP_NO_REF)) 2328c2ecf20Sopenharmony_ci if (scsi_device_get(sdev)) 2338c2ecf20Sopenharmony_ci return NULL; 2348c2ecf20Sopenharmony_ci atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, 2358c2ecf20Sopenharmony_ci &zfcp_sdev->status); 2368c2ecf20Sopenharmony_ci erp_action = &zfcp_sdev->erp_action; 2378c2ecf20Sopenharmony_ci WARN_ON_ONCE(erp_action->port != port); 2388c2ecf20Sopenharmony_ci WARN_ON_ONCE(erp_action->sdev != sdev); 2398c2ecf20Sopenharmony_ci if (!(atomic_read(&zfcp_sdev->status) & 2408c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_RUNNING)) 2418c2ecf20Sopenharmony_ci act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 2458c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 2468c2ecf20Sopenharmony_ci if (!get_device(&port->dev)) 2478c2ecf20Sopenharmony_ci return NULL; 2488c2ecf20Sopenharmony_ci zfcp_erp_action_dismiss_port(port); 2498c2ecf20Sopenharmony_ci atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); 2508c2ecf20Sopenharmony_ci erp_action = &port->erp_action; 2518c2ecf20Sopenharmony_ci WARN_ON_ONCE(erp_action->port != port); 2528c2ecf20Sopenharmony_ci WARN_ON_ONCE(erp_action->sdev != NULL); 2538c2ecf20Sopenharmony_ci if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) 2548c2ecf20Sopenharmony_ci act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 2588c2ecf20Sopenharmony_ci kref_get(&adapter->ref); 2598c2ecf20Sopenharmony_ci zfcp_erp_action_dismiss_adapter(adapter); 2608c2ecf20Sopenharmony_ci atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); 2618c2ecf20Sopenharmony_ci erp_action = &adapter->erp_action; 2628c2ecf20Sopenharmony_ci WARN_ON_ONCE(erp_action->port != NULL); 2638c2ecf20Sopenharmony_ci WARN_ON_ONCE(erp_action->sdev != NULL); 2648c2ecf20Sopenharmony_ci if (!(atomic_read(&adapter->status) & 2658c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_RUNNING)) 2668c2ecf20Sopenharmony_ci act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci WARN_ON_ONCE(erp_action->adapter != adapter); 2718c2ecf20Sopenharmony_ci memset(&erp_action->list, 0, sizeof(erp_action->list)); 2728c2ecf20Sopenharmony_ci memset(&erp_action->timer, 0, sizeof(erp_action->timer)); 2738c2ecf20Sopenharmony_ci erp_action->step = ZFCP_ERP_STEP_UNINITIALIZED; 2748c2ecf20Sopenharmony_ci erp_action->fsf_req_id = 0; 2758c2ecf20Sopenharmony_ci erp_action->type = need; 2768c2ecf20Sopenharmony_ci erp_action->status = act_status; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return erp_action; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic void zfcp_erp_action_enqueue(enum zfcp_erp_act_type want, 2828c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter, 2838c2ecf20Sopenharmony_ci struct zfcp_port *port, 2848c2ecf20Sopenharmony_ci struct scsi_device *sdev, 2858c2ecf20Sopenharmony_ci char *dbftag, u32 act_status) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci enum zfcp_erp_act_type need; 2888c2ecf20Sopenharmony_ci struct zfcp_erp_action *act; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci need = zfcp_erp_handle_failed(want, adapter, port, sdev); 2918c2ecf20Sopenharmony_ci if (!need) { 2928c2ecf20Sopenharmony_ci need = ZFCP_ERP_ACTION_FAILED; /* marker for trace */ 2938c2ecf20Sopenharmony_ci goto out; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!adapter->erp_thread) { 2978c2ecf20Sopenharmony_ci need = ZFCP_ERP_ACTION_NONE; /* marker for trace */ 2988c2ecf20Sopenharmony_ci goto out; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci need = zfcp_erp_required_act(want, adapter, port, sdev); 3028c2ecf20Sopenharmony_ci if (!need) 3038c2ecf20Sopenharmony_ci goto out; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev); 3068c2ecf20Sopenharmony_ci if (!act) { 3078c2ecf20Sopenharmony_ci need |= ZFCP_ERP_ACTION_NONE; /* marker for trace */ 3088c2ecf20Sopenharmony_ci goto out; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci atomic_or(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); 3118c2ecf20Sopenharmony_ci ++adapter->erp_total_count; 3128c2ecf20Sopenharmony_ci list_add_tail(&act->list, &adapter->erp_ready_head); 3138c2ecf20Sopenharmony_ci wake_up(&adapter->erp_ready_wq); 3148c2ecf20Sopenharmony_ci out: 3158c2ecf20Sopenharmony_ci zfcp_dbf_rec_trig(dbftag, adapter, port, sdev, want, need); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_civoid zfcp_erp_port_forced_no_port_dbf(char *dbftag, 3198c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter, 3208c2ecf20Sopenharmony_ci u64 port_name, u32 port_id) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci unsigned long flags; 3238c2ecf20Sopenharmony_ci static /* don't waste stack */ struct zfcp_port tmpport; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 3268c2ecf20Sopenharmony_ci /* Stand-in zfcp port with fields just good enough for 3278c2ecf20Sopenharmony_ci * zfcp_dbf_rec_trig() and zfcp_dbf_set_common(). 3288c2ecf20Sopenharmony_ci * Under lock because tmpport is static. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci atomic_set(&tmpport.status, -1); /* unknown */ 3318c2ecf20Sopenharmony_ci tmpport.wwpn = port_name; 3328c2ecf20Sopenharmony_ci tmpport.d_id = port_id; 3338c2ecf20Sopenharmony_ci zfcp_dbf_rec_trig(dbftag, adapter, &tmpport, NULL, 3348c2ecf20Sopenharmony_ci ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, 3358c2ecf20Sopenharmony_ci ZFCP_ERP_ACTION_NONE); 3368c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, 3408c2ecf20Sopenharmony_ci int clear_mask, char *dbftag) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci zfcp_erp_adapter_block(adapter, clear_mask); 3438c2ecf20Sopenharmony_ci zfcp_scsi_schedule_rports_block(adapter); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, 3468c2ecf20Sopenharmony_ci adapter, NULL, NULL, dbftag, 0); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/** 3508c2ecf20Sopenharmony_ci * zfcp_erp_adapter_reopen - Reopen adapter. 3518c2ecf20Sopenharmony_ci * @adapter: Adapter to reopen. 3528c2ecf20Sopenharmony_ci * @clear: Status flags to clear. 3538c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_civoid zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, 3568c2ecf20Sopenharmony_ci char *dbftag) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci unsigned long flags; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci zfcp_erp_adapter_block(adapter, clear); 3618c2ecf20Sopenharmony_ci zfcp_scsi_schedule_rports_block(adapter); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 3648c2ecf20Sopenharmony_ci zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, 3658c2ecf20Sopenharmony_ci NULL, NULL, dbftag, 0); 3668c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci/** 3708c2ecf20Sopenharmony_ci * zfcp_erp_adapter_shutdown - Shutdown adapter. 3718c2ecf20Sopenharmony_ci * @adapter: Adapter to shut down. 3728c2ecf20Sopenharmony_ci * @clear: Status flags to clear. 3738c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_civoid zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, 3768c2ecf20Sopenharmony_ci char *dbftag) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 3798c2ecf20Sopenharmony_ci zfcp_erp_adapter_reopen(adapter, clear | flags, dbftag); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci/** 3838c2ecf20Sopenharmony_ci * zfcp_erp_port_shutdown - Shutdown port 3848c2ecf20Sopenharmony_ci * @port: Port to shut down. 3858c2ecf20Sopenharmony_ci * @clear: Status flags to clear. 3868c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event. 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_civoid zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *dbftag) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 3918c2ecf20Sopenharmony_ci zfcp_erp_port_reopen(port, clear | flags, dbftag); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic void zfcp_erp_port_block(struct zfcp_port *port, int clear) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci zfcp_erp_clear_port_status(port, 3978c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_UNBLOCKED | clear); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, 4018c2ecf20Sopenharmony_ci char *dbftag) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci zfcp_erp_port_block(port, clear); 4048c2ecf20Sopenharmony_ci zfcp_scsi_schedule_rport_block(port); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, 4078c2ecf20Sopenharmony_ci port->adapter, port, NULL, dbftag, 0); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci/** 4118c2ecf20Sopenharmony_ci * zfcp_erp_port_forced_reopen - Forced close of port and open again 4128c2ecf20Sopenharmony_ci * @port: Port to force close and to reopen. 4138c2ecf20Sopenharmony_ci * @clear: Status flags to clear. 4148c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event. 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_civoid zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, 4178c2ecf20Sopenharmony_ci char *dbftag) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci unsigned long flags; 4208c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = port->adapter; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 4238c2ecf20Sopenharmony_ci _zfcp_erp_port_forced_reopen(port, clear, dbftag); 4248c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic void _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, 4288c2ecf20Sopenharmony_ci char *dbftag) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci zfcp_erp_port_block(port, clear); 4318c2ecf20Sopenharmony_ci zfcp_scsi_schedule_rport_block(port); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, 4348c2ecf20Sopenharmony_ci port->adapter, port, NULL, dbftag, 0); 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci/** 4388c2ecf20Sopenharmony_ci * zfcp_erp_port_reopen - trigger remote port recovery 4398c2ecf20Sopenharmony_ci * @port: port to recover 4408c2ecf20Sopenharmony_ci * @clear: flags in port status to be cleared 4418c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_civoid zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *dbftag) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci unsigned long flags; 4468c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = port->adapter; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 4498c2ecf20Sopenharmony_ci _zfcp_erp_port_reopen(port, clear, dbftag); 4508c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci zfcp_erp_clear_lun_status(sdev, 4568c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, 4608c2ecf20Sopenharmony_ci char *dbftag, u32 act_status) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 4638c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci zfcp_erp_lun_block(sdev, clear); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter, 4688c2ecf20Sopenharmony_ci zfcp_sdev->port, sdev, dbftag, act_status); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/** 4728c2ecf20Sopenharmony_ci * zfcp_erp_lun_reopen - initiate reopen of a LUN 4738c2ecf20Sopenharmony_ci * @sdev: SCSI device / LUN to be reopened 4748c2ecf20Sopenharmony_ci * @clear: specifies flags in LUN status to be cleared 4758c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event. 4768c2ecf20Sopenharmony_ci * 4778c2ecf20Sopenharmony_ci * Return: 0 on success, < 0 on error 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_civoid zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *dbftag) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci unsigned long flags; 4828c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 4838c2ecf20Sopenharmony_ci struct zfcp_port *port = zfcp_sdev->port; 4848c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = port->adapter; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 4878c2ecf20Sopenharmony_ci _zfcp_erp_lun_reopen(sdev, clear, dbftag, 0); 4888c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci/** 4928c2ecf20Sopenharmony_ci * zfcp_erp_lun_shutdown - Shutdown LUN 4938c2ecf20Sopenharmony_ci * @sdev: SCSI device / LUN to shut down. 4948c2ecf20Sopenharmony_ci * @clear: Status flags to clear. 4958c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_civoid zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *dbftag) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 5008c2ecf20Sopenharmony_ci zfcp_erp_lun_reopen(sdev, clear | flags, dbftag); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/** 5048c2ecf20Sopenharmony_ci * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion 5058c2ecf20Sopenharmony_ci * @sdev: SCSI device / LUN to shut down. 5068c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event. 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * Do not acquire a reference for the LUN when creating the ERP 5098c2ecf20Sopenharmony_ci * action. It is safe, because this function waits for the ERP to 5108c2ecf20Sopenharmony_ci * complete first. This allows to shutdown the LUN, even when the SCSI 5118c2ecf20Sopenharmony_ci * device is in the state SDEV_DEL when scsi_device_get will fail. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_civoid zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *dbftag) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci unsigned long flags; 5168c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 5178c2ecf20Sopenharmony_ci struct zfcp_port *port = zfcp_sdev->port; 5188c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = port->adapter; 5198c2ecf20Sopenharmony_ci int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 5228c2ecf20Sopenharmony_ci _zfcp_erp_lun_reopen(sdev, clear, dbftag, ZFCP_STATUS_ERP_NO_REF); 5238c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci zfcp_erp_wait(adapter); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int zfcp_erp_status_change_set(unsigned long mask, atomic_t *status) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci return (atomic_read(status) ^ mask) & mask; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, 5368c2ecf20Sopenharmony_ci &adapter->status)) 5378c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("eraubl1", &adapter->erp_action); 5388c2ecf20Sopenharmony_ci atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic void zfcp_erp_port_unblock(struct zfcp_port *port) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, 5448c2ecf20Sopenharmony_ci &port->status)) 5458c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("erpubl1", &port->erp_action); 5468c2ecf20Sopenharmony_ci atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic void zfcp_erp_lun_unblock(struct scsi_device *sdev) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, 5548c2ecf20Sopenharmony_ci &zfcp_sdev->status)) 5558c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action); 5568c2ecf20Sopenharmony_ci atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci list_move(&erp_action->list, &erp_action->adapter->erp_running_head); 5628c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("erator1", erp_action); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 5688c2ecf20Sopenharmony_ci struct zfcp_fsf_req *req; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (!act->fsf_req_id) 5718c2ecf20Sopenharmony_ci return; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci spin_lock(&adapter->req_list->lock); 5748c2ecf20Sopenharmony_ci req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id); 5758c2ecf20Sopenharmony_ci if (req && req->erp_action == act) { 5768c2ecf20Sopenharmony_ci if (act->status & (ZFCP_STATUS_ERP_DISMISSED | 5778c2ecf20Sopenharmony_ci ZFCP_STATUS_ERP_TIMEDOUT)) { 5788c2ecf20Sopenharmony_ci req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; 5798c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("erscf_1", act); 5808c2ecf20Sopenharmony_ci /* lock-free concurrent access with 5818c2ecf20Sopenharmony_ci * zfcp_erp_timeout_handler() 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci WRITE_ONCE(req->erp_action, NULL); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) 5868c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("erscf_2", act); 5878c2ecf20Sopenharmony_ci if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) 5888c2ecf20Sopenharmony_ci act->fsf_req_id = 0; 5898c2ecf20Sopenharmony_ci } else 5908c2ecf20Sopenharmony_ci act->fsf_req_id = 0; 5918c2ecf20Sopenharmony_ci spin_unlock(&adapter->req_list->lock); 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci/** 5958c2ecf20Sopenharmony_ci * zfcp_erp_notify - Trigger ERP action. 5968c2ecf20Sopenharmony_ci * @erp_action: ERP action to continue. 5978c2ecf20Sopenharmony_ci * @set_mask: ERP action status flags to set. 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_civoid zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = erp_action->adapter; 6028c2ecf20Sopenharmony_ci unsigned long flags; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 6058c2ecf20Sopenharmony_ci if (zfcp_erp_action_is_running(erp_action)) { 6068c2ecf20Sopenharmony_ci erp_action->status |= set_mask; 6078c2ecf20Sopenharmony_ci zfcp_erp_action_ready(erp_action); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci/** 6138c2ecf20Sopenharmony_ci * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request 6148c2ecf20Sopenharmony_ci * @t: timer list entry embedded in zfcp FSF request 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_civoid zfcp_erp_timeout_handler(struct timer_list *t) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct zfcp_fsf_req *fsf_req = from_timer(fsf_req, t, timer); 6198c2ecf20Sopenharmony_ci struct zfcp_erp_action *act; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) 6228c2ecf20Sopenharmony_ci return; 6238c2ecf20Sopenharmony_ci /* lock-free concurrent access with zfcp_erp_strategy_check_fsfreq() */ 6248c2ecf20Sopenharmony_ci act = READ_ONCE(fsf_req->erp_action); 6258c2ecf20Sopenharmony_ci if (!act) 6268c2ecf20Sopenharmony_ci return; 6278c2ecf20Sopenharmony_ci zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic void zfcp_erp_memwait_handler(struct timer_list *t) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct zfcp_erp_action *act = from_timer(act, t, timer); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci zfcp_erp_notify(act, 0); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci timer_setup(&erp_action->timer, zfcp_erp_memwait_handler, 0); 6408c2ecf20Sopenharmony_ci erp_action->timer.expires = jiffies + HZ; 6418c2ecf20Sopenharmony_ci add_timer(&erp_action->timer); 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_civoid zfcp_erp_port_forced_reopen_all(struct zfcp_adapter *adapter, 6458c2ecf20Sopenharmony_ci int clear, char *dbftag) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci unsigned long flags; 6488c2ecf20Sopenharmony_ci struct zfcp_port *port; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 6518c2ecf20Sopenharmony_ci read_lock(&adapter->port_list_lock); 6528c2ecf20Sopenharmony_ci list_for_each_entry(port, &adapter->port_list, list) 6538c2ecf20Sopenharmony_ci _zfcp_erp_port_forced_reopen(port, clear, dbftag); 6548c2ecf20Sopenharmony_ci read_unlock(&adapter->port_list_lock); 6558c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, 6598c2ecf20Sopenharmony_ci int clear, char *dbftag) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci struct zfcp_port *port; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci read_lock(&adapter->port_list_lock); 6648c2ecf20Sopenharmony_ci list_for_each_entry(port, &adapter->port_list, list) 6658c2ecf20Sopenharmony_ci _zfcp_erp_port_reopen(port, clear, dbftag); 6668c2ecf20Sopenharmony_ci read_unlock(&adapter->port_list_lock); 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear, 6708c2ecf20Sopenharmony_ci char *dbftag) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci struct scsi_device *sdev; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci spin_lock(port->adapter->scsi_host->host_lock); 6758c2ecf20Sopenharmony_ci __shost_for_each_device(sdev, port->adapter->scsi_host) 6768c2ecf20Sopenharmony_ci if (sdev_to_zfcp(sdev)->port == port) 6778c2ecf20Sopenharmony_ci _zfcp_erp_lun_reopen(sdev, clear, dbftag, 0); 6788c2ecf20Sopenharmony_ci spin_unlock(port->adapter->scsi_host->host_lock); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci switch (act->type) { 6848c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 6858c2ecf20Sopenharmony_ci _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1"); 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 6888c2ecf20Sopenharmony_ci _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2"); 6898c2ecf20Sopenharmony_ci break; 6908c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 6918c2ecf20Sopenharmony_ci _zfcp_erp_port_reopen(act->port, 0, "ersff_3"); 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 6948c2ecf20Sopenharmony_ci _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0); 6958c2ecf20Sopenharmony_ci break; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci switch (act->type) { 7028c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 7038c2ecf20Sopenharmony_ci _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1"); 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 7068c2ecf20Sopenharmony_ci _zfcp_erp_port_reopen(act->port, 0, "ersfs_2"); 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 7098c2ecf20Sopenharmony_ci _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3"); 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 7128c2ecf20Sopenharmony_ci /* NOP */ 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic void zfcp_erp_wakeup(struct zfcp_adapter *adapter) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci unsigned long flags; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci read_lock_irqsave(&adapter->erp_lock, flags); 7228c2ecf20Sopenharmony_ci if (list_empty(&adapter->erp_ready_head) && 7238c2ecf20Sopenharmony_ci list_empty(&adapter->erp_running_head)) { 7248c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_ADAPTER_ERP_PENDING, 7258c2ecf20Sopenharmony_ci &adapter->status); 7268c2ecf20Sopenharmony_ci wake_up(&adapter->erp_done_wqh); 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci read_unlock_irqrestore(&adapter->erp_lock, flags); 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct zfcp_port *port; 7348c2ecf20Sopenharmony_ci port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, 7358c2ecf20Sopenharmony_ci adapter->peer_d_id); 7368c2ecf20Sopenharmony_ci if (IS_ERR(port)) /* error or port already attached */ 7378c2ecf20Sopenharmony_ci return; 7388c2ecf20Sopenharmony_ci zfcp_erp_port_reopen(port, 0, "ereptp1"); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strat_fsf_xconf( 7428c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci int retries; 7458c2ecf20Sopenharmony_ci int sleep = 1; 7468c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = erp_action->adapter; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci for (retries = 7; retries; retries--) { 7518c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, 7528c2ecf20Sopenharmony_ci &adapter->status); 7538c2ecf20Sopenharmony_ci write_lock_irq(&adapter->erp_lock); 7548c2ecf20Sopenharmony_ci zfcp_erp_action_to_running(erp_action); 7558c2ecf20Sopenharmony_ci write_unlock_irq(&adapter->erp_lock); 7568c2ecf20Sopenharmony_ci if (zfcp_fsf_exchange_config_data(erp_action)) { 7578c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, 7588c2ecf20Sopenharmony_ci &adapter->status); 7598c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci wait_event(adapter->erp_ready_wq, 7638c2ecf20Sopenharmony_ci !list_empty(&adapter->erp_ready_head)); 7648c2ecf20Sopenharmony_ci if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (!(atomic_read(&adapter->status) & 7688c2ecf20Sopenharmony_ci ZFCP_STATUS_ADAPTER_HOST_CON_INIT)) 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci ssleep(sleep); 7728c2ecf20Sopenharmony_ci sleep *= 2; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, 7768c2ecf20Sopenharmony_ci &adapter->status); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK)) 7798c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic void 7858c2ecf20Sopenharmony_cizfcp_erp_adapter_strategy_open_ptp_port(struct zfcp_adapter *const adapter) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) 7888c2ecf20Sopenharmony_ci zfcp_erp_enqueue_ptp_port(adapter); 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strategy_open_fsf_xport( 7928c2ecf20Sopenharmony_ci struct zfcp_erp_action *act) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci int ret; 7958c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci write_lock_irq(&adapter->erp_lock); 7988c2ecf20Sopenharmony_ci zfcp_erp_action_to_running(act); 7998c2ecf20Sopenharmony_ci write_unlock_irq(&adapter->erp_lock); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci ret = zfcp_fsf_exchange_port_data(act); 8028c2ecf20Sopenharmony_ci if (ret == -EOPNOTSUPP) 8038c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 8048c2ecf20Sopenharmony_ci if (ret) 8058c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("erasox1", act); 8088c2ecf20Sopenharmony_ci wait_event(adapter->erp_ready_wq, 8098c2ecf20Sopenharmony_ci !list_empty(&adapter->erp_ready_head)); 8108c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("erasox2", act); 8118c2ecf20Sopenharmony_ci if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) 8128c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result 8188c2ecf20Sopenharmony_cizfcp_erp_adapter_strategy_alloc_shost(struct zfcp_adapter *const adapter) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct zfcp_diag_adapter_config_data *const config_data = 8218c2ecf20Sopenharmony_ci &adapter->diagnostics->config_data; 8228c2ecf20Sopenharmony_ci struct zfcp_diag_adapter_port_data *const port_data = 8238c2ecf20Sopenharmony_ci &adapter->diagnostics->port_data; 8248c2ecf20Sopenharmony_ci unsigned long flags; 8258c2ecf20Sopenharmony_ci int rc; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci rc = zfcp_scsi_adapter_register(adapter); 8288c2ecf20Sopenharmony_ci if (rc == -EEXIST) 8298c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 8308c2ecf20Sopenharmony_ci else if (rc) 8318c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* 8348c2ecf20Sopenharmony_ci * We allocated the shost for the first time. Before it was NULL, 8358c2ecf20Sopenharmony_ci * and so we deferred all updates in the xconf- and xport-data 8368c2ecf20Sopenharmony_ci * handlers. We need to make up for that now, and make all the updates 8378c2ecf20Sopenharmony_ci * that would have been done before. 8388c2ecf20Sopenharmony_ci * 8398c2ecf20Sopenharmony_ci * We can be sure that xconf- and xport-data succeeded, because 8408c2ecf20Sopenharmony_ci * otherwise this function is not called. But they might have been 8418c2ecf20Sopenharmony_ci * incomplete. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci spin_lock_irqsave(&config_data->header.access_lock, flags); 8458c2ecf20Sopenharmony_ci zfcp_scsi_shost_update_config_data(adapter, &config_data->data, 8468c2ecf20Sopenharmony_ci !!config_data->header.incomplete); 8478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&config_data->header.access_lock, flags); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { 8508c2ecf20Sopenharmony_ci spin_lock_irqsave(&port_data->header.access_lock, flags); 8518c2ecf20Sopenharmony_ci zfcp_scsi_shost_update_port_data(adapter, &port_data->data); 8528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port_data->header.access_lock, flags); 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* 8568c2ecf20Sopenharmony_ci * There is a remote possibility that the 'Exchange Port Data' request 8578c2ecf20Sopenharmony_ci * reports a different connectivity status than 'Exchange Config Data'. 8588c2ecf20Sopenharmony_ci * But any change to the connectivity status of the local optic that 8598c2ecf20Sopenharmony_ci * happens after the initial xconf request is expected to be reported 8608c2ecf20Sopenharmony_ci * to us, as soon as we post Status Read Buffers to the FCP channel 8618c2ecf20Sopenharmony_ci * firmware after this function. So any resulting inconsistency will 8628c2ecf20Sopenharmony_ci * only be momentary. 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_ci if (config_data->header.incomplete) 8658c2ecf20Sopenharmony_ci zfcp_fsf_fc_host_link_down(adapter); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strategy_open_fsf( 8718c2ecf20Sopenharmony_ci struct zfcp_erp_action *act) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED) 8748c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) 8778c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (zfcp_erp_adapter_strategy_alloc_shost(act->adapter) == 8808c2ecf20Sopenharmony_ci ZFCP_ERP_FAILED) 8818c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci zfcp_erp_adapter_strategy_open_ptp_port(act->adapter); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (mempool_resize(act->adapter->pool.sr_data, 8868c2ecf20Sopenharmony_ci act->adapter->stat_read_buf_num)) 8878c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (mempool_resize(act->adapter->pool.status_read_req, 8908c2ecf20Sopenharmony_ci act->adapter->stat_read_buf_num)) 8918c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num); 8948c2ecf20Sopenharmony_ci if (zfcp_status_read_refill(act->adapter)) 8958c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* close queues to ensure that buffers are not accessed by adapter */ 9058c2ecf20Sopenharmony_ci zfcp_qdio_close(adapter->qdio); 9068c2ecf20Sopenharmony_ci zfcp_fsf_req_dismiss_all(adapter); 9078c2ecf20Sopenharmony_ci adapter->fsf_req_seq_no = 0; 9088c2ecf20Sopenharmony_ci zfcp_fc_wka_ports_force_offline(adapter->gs); 9098c2ecf20Sopenharmony_ci /* all ports and LUNs are closed */ 9108c2ecf20Sopenharmony_ci zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK | 9138c2ecf20Sopenharmony_ci ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strategy_open( 9178c2ecf20Sopenharmony_ci struct zfcp_erp_action *act) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (zfcp_qdio_open(adapter->qdio)) { 9228c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK | 9238c2ecf20Sopenharmony_ci ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, 9248c2ecf20Sopenharmony_ci &adapter->status); 9258c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (zfcp_erp_adapter_strategy_open_fsf(act)) { 9298c2ecf20Sopenharmony_ci zfcp_erp_adapter_strategy_close(act); 9308c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci atomic_or(ZFCP_STATUS_COMMON_OPEN, &adapter->status); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strategy( 9398c2ecf20Sopenharmony_ci struct zfcp_erp_action *act) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) { 9448c2ecf20Sopenharmony_ci zfcp_erp_adapter_strategy_close(act); 9458c2ecf20Sopenharmony_ci if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 9468c2ecf20Sopenharmony_ci return ZFCP_ERP_EXIT; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (zfcp_erp_adapter_strategy_open(act)) { 9508c2ecf20Sopenharmony_ci ssleep(8); 9518c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_forced_strategy_close( 9588c2ecf20Sopenharmony_ci struct zfcp_erp_action *act) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci int retval; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci retval = zfcp_fsf_close_physical_port(act); 9638c2ecf20Sopenharmony_ci if (retval == -ENOMEM) 9648c2ecf20Sopenharmony_ci return ZFCP_ERP_NOMEM; 9658c2ecf20Sopenharmony_ci act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; 9668c2ecf20Sopenharmony_ci if (retval) 9678c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci return ZFCP_ERP_CONTINUES; 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_forced_strategy( 9738c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci struct zfcp_port *port = erp_action->port; 9768c2ecf20Sopenharmony_ci int status = atomic_read(&port->status); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci switch (erp_action->step) { 9798c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_UNINITIALIZED: 9808c2ecf20Sopenharmony_ci if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) && 9818c2ecf20Sopenharmony_ci (status & ZFCP_STATUS_COMMON_OPEN)) 9828c2ecf20Sopenharmony_ci return zfcp_erp_port_forced_strategy_close(erp_action); 9838c2ecf20Sopenharmony_ci else 9848c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: 9878c2ecf20Sopenharmony_ci if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN)) 9888c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 9898c2ecf20Sopenharmony_ci break; 9908c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PORT_CLOSING: 9918c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PORT_OPENING: 9928c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_LUN_CLOSING: 9938c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_LUN_OPENING: 9948c2ecf20Sopenharmony_ci /* NOP */ 9958c2ecf20Sopenharmony_ci break; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_strategy_close( 10018c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci int retval; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci retval = zfcp_fsf_close_port(erp_action); 10068c2ecf20Sopenharmony_ci if (retval == -ENOMEM) 10078c2ecf20Sopenharmony_ci return ZFCP_ERP_NOMEM; 10088c2ecf20Sopenharmony_ci erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; 10098c2ecf20Sopenharmony_ci if (retval) 10108c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 10118c2ecf20Sopenharmony_ci return ZFCP_ERP_CONTINUES; 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_strategy_open_port( 10158c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci int retval; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci retval = zfcp_fsf_open_port(erp_action); 10208c2ecf20Sopenharmony_ci if (retval == -ENOMEM) 10218c2ecf20Sopenharmony_ci return ZFCP_ERP_NOMEM; 10228c2ecf20Sopenharmony_ci erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; 10238c2ecf20Sopenharmony_ci if (retval) 10248c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 10258c2ecf20Sopenharmony_ci return ZFCP_ERP_CONTINUES; 10268c2ecf20Sopenharmony_ci} 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_cistatic int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 10318c2ecf20Sopenharmony_ci struct zfcp_port *port = act->port; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (port->wwpn != adapter->peer_wwpn) { 10348c2ecf20Sopenharmony_ci zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); 10358c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci port->d_id = adapter->peer_d_id; 10388c2ecf20Sopenharmony_ci return zfcp_erp_port_strategy_open_port(act); 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_strategy_open_common( 10428c2ecf20Sopenharmony_ci struct zfcp_erp_action *act) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 10458c2ecf20Sopenharmony_ci struct zfcp_port *port = act->port; 10468c2ecf20Sopenharmony_ci int p_status = atomic_read(&port->status); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci switch (act->step) { 10498c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_UNINITIALIZED: 10508c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: 10518c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PORT_CLOSING: 10528c2ecf20Sopenharmony_ci if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) 10538c2ecf20Sopenharmony_ci return zfcp_erp_open_ptp_port(act); 10548c2ecf20Sopenharmony_ci if (!port->d_id) { 10558c2ecf20Sopenharmony_ci zfcp_fc_trigger_did_lookup(port); 10568c2ecf20Sopenharmony_ci return ZFCP_ERP_EXIT; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci return zfcp_erp_port_strategy_open_port(act); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PORT_OPENING: 10618c2ecf20Sopenharmony_ci /* D_ID might have changed during open */ 10628c2ecf20Sopenharmony_ci if (p_status & ZFCP_STATUS_COMMON_OPEN) { 10638c2ecf20Sopenharmony_ci if (!port->d_id) { 10648c2ecf20Sopenharmony_ci zfcp_fc_trigger_did_lookup(port); 10658c2ecf20Sopenharmony_ci return ZFCP_ERP_EXIT; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { 10708c2ecf20Sopenharmony_ci port->d_id = 0; 10718c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci /* no early return otherwise, continue after switch case */ 10748c2ecf20Sopenharmony_ci break; 10758c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_LUN_CLOSING: 10768c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_LUN_OPENING: 10778c2ecf20Sopenharmony_ci /* NOP */ 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_strategy( 10848c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct zfcp_port *port = erp_action->port; 10878c2ecf20Sopenharmony_ci int p_status = atomic_read(&port->status); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if ((p_status & ZFCP_STATUS_COMMON_NOESC) && 10908c2ecf20Sopenharmony_ci !(p_status & ZFCP_STATUS_COMMON_OPEN)) 10918c2ecf20Sopenharmony_ci goto close_init_done; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci switch (erp_action->step) { 10948c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_UNINITIALIZED: 10958c2ecf20Sopenharmony_ci if (p_status & ZFCP_STATUS_COMMON_OPEN) 10968c2ecf20Sopenharmony_ci return zfcp_erp_port_strategy_close(erp_action); 10978c2ecf20Sopenharmony_ci break; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PORT_CLOSING: 11008c2ecf20Sopenharmony_ci if (p_status & ZFCP_STATUS_COMMON_OPEN) 11018c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: 11048c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PORT_OPENING: 11058c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_LUN_CLOSING: 11068c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_LUN_OPENING: 11078c2ecf20Sopenharmony_ci /* NOP */ 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ciclose_init_done: 11128c2ecf20Sopenharmony_ci if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 11138c2ecf20Sopenharmony_ci return ZFCP_ERP_EXIT; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci return zfcp_erp_port_strategy_open_common(erp_action); 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cistatic void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_DENIED, 11238c2ecf20Sopenharmony_ci &zfcp_sdev->status); 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_lun_strategy_close( 11278c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 11288c2ecf20Sopenharmony_ci{ 11298c2ecf20Sopenharmony_ci int retval = zfcp_fsf_close_lun(erp_action); 11308c2ecf20Sopenharmony_ci if (retval == -ENOMEM) 11318c2ecf20Sopenharmony_ci return ZFCP_ERP_NOMEM; 11328c2ecf20Sopenharmony_ci erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING; 11338c2ecf20Sopenharmony_ci if (retval) 11348c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 11358c2ecf20Sopenharmony_ci return ZFCP_ERP_CONTINUES; 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_lun_strategy_open( 11398c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci int retval = zfcp_fsf_open_lun(erp_action); 11428c2ecf20Sopenharmony_ci if (retval == -ENOMEM) 11438c2ecf20Sopenharmony_ci return ZFCP_ERP_NOMEM; 11448c2ecf20Sopenharmony_ci erp_action->step = ZFCP_ERP_STEP_LUN_OPENING; 11458c2ecf20Sopenharmony_ci if (retval) 11468c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 11478c2ecf20Sopenharmony_ci return ZFCP_ERP_CONTINUES; 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_lun_strategy( 11518c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci struct scsi_device *sdev = erp_action->sdev; 11548c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci switch (erp_action->step) { 11578c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_UNINITIALIZED: 11588c2ecf20Sopenharmony_ci zfcp_erp_lun_strategy_clearstati(sdev); 11598c2ecf20Sopenharmony_ci if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) 11608c2ecf20Sopenharmony_ci return zfcp_erp_lun_strategy_close(erp_action); 11618c2ecf20Sopenharmony_ci /* already closed */ 11628c2ecf20Sopenharmony_ci fallthrough; 11638c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_LUN_CLOSING: 11648c2ecf20Sopenharmony_ci if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) 11658c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 11668c2ecf20Sopenharmony_ci if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 11678c2ecf20Sopenharmony_ci return ZFCP_ERP_EXIT; 11688c2ecf20Sopenharmony_ci return zfcp_erp_lun_strategy_open(erp_action); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_LUN_OPENING: 11718c2ecf20Sopenharmony_ci if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) 11728c2ecf20Sopenharmony_ci return ZFCP_ERP_SUCCEEDED; 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: 11758c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PORT_CLOSING: 11768c2ecf20Sopenharmony_ci case ZFCP_ERP_STEP_PORT_OPENING: 11778c2ecf20Sopenharmony_ci /* NOP */ 11788c2ecf20Sopenharmony_ci break; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_check_lun( 11848c2ecf20Sopenharmony_ci struct scsi_device *sdev, enum zfcp_erp_act_result result) 11858c2ecf20Sopenharmony_ci{ 11868c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci switch (result) { 11898c2ecf20Sopenharmony_ci case ZFCP_ERP_SUCCEEDED : 11908c2ecf20Sopenharmony_ci atomic_set(&zfcp_sdev->erp_counter, 0); 11918c2ecf20Sopenharmony_ci zfcp_erp_lun_unblock(sdev); 11928c2ecf20Sopenharmony_ci break; 11938c2ecf20Sopenharmony_ci case ZFCP_ERP_FAILED : 11948c2ecf20Sopenharmony_ci atomic_inc(&zfcp_sdev->erp_counter); 11958c2ecf20Sopenharmony_ci if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) { 11968c2ecf20Sopenharmony_ci dev_err(&zfcp_sdev->port->adapter->ccw_device->dev, 11978c2ecf20Sopenharmony_ci "ERP failed for LUN 0x%016Lx on " 11988c2ecf20Sopenharmony_ci "port 0x%016Lx\n", 11998c2ecf20Sopenharmony_ci (unsigned long long)zfcp_scsi_dev_lun(sdev), 12008c2ecf20Sopenharmony_ci (unsigned long long)zfcp_sdev->port->wwpn); 12018c2ecf20Sopenharmony_ci zfcp_erp_set_lun_status(sdev, 12028c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED); 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci break; 12058c2ecf20Sopenharmony_ci case ZFCP_ERP_CONTINUES: 12068c2ecf20Sopenharmony_ci case ZFCP_ERP_EXIT: 12078c2ecf20Sopenharmony_ci case ZFCP_ERP_DISMISSED: 12088c2ecf20Sopenharmony_ci case ZFCP_ERP_NOMEM: 12098c2ecf20Sopenharmony_ci /* NOP */ 12108c2ecf20Sopenharmony_ci break; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 12148c2ecf20Sopenharmony_ci zfcp_erp_lun_block(sdev, 0); 12158c2ecf20Sopenharmony_ci result = ZFCP_ERP_EXIT; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci return result; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_check_port( 12218c2ecf20Sopenharmony_ci struct zfcp_port *port, enum zfcp_erp_act_result result) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci switch (result) { 12248c2ecf20Sopenharmony_ci case ZFCP_ERP_SUCCEEDED : 12258c2ecf20Sopenharmony_ci atomic_set(&port->erp_counter, 0); 12268c2ecf20Sopenharmony_ci zfcp_erp_port_unblock(port); 12278c2ecf20Sopenharmony_ci break; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci case ZFCP_ERP_FAILED : 12308c2ecf20Sopenharmony_ci if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) { 12318c2ecf20Sopenharmony_ci zfcp_erp_port_block(port, 0); 12328c2ecf20Sopenharmony_ci result = ZFCP_ERP_EXIT; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci atomic_inc(&port->erp_counter); 12358c2ecf20Sopenharmony_ci if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) { 12368c2ecf20Sopenharmony_ci dev_err(&port->adapter->ccw_device->dev, 12378c2ecf20Sopenharmony_ci "ERP failed for remote port 0x%016Lx\n", 12388c2ecf20Sopenharmony_ci (unsigned long long)port->wwpn); 12398c2ecf20Sopenharmony_ci zfcp_erp_set_port_status(port, 12408c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED); 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci break; 12438c2ecf20Sopenharmony_ci case ZFCP_ERP_CONTINUES: 12448c2ecf20Sopenharmony_ci case ZFCP_ERP_EXIT: 12458c2ecf20Sopenharmony_ci case ZFCP_ERP_DISMISSED: 12468c2ecf20Sopenharmony_ci case ZFCP_ERP_NOMEM: 12478c2ecf20Sopenharmony_ci /* NOP */ 12488c2ecf20Sopenharmony_ci break; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 12528c2ecf20Sopenharmony_ci zfcp_erp_port_block(port, 0); 12538c2ecf20Sopenharmony_ci result = ZFCP_ERP_EXIT; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci return result; 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_check_adapter( 12598c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter, enum zfcp_erp_act_result result) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci switch (result) { 12628c2ecf20Sopenharmony_ci case ZFCP_ERP_SUCCEEDED : 12638c2ecf20Sopenharmony_ci atomic_set(&adapter->erp_counter, 0); 12648c2ecf20Sopenharmony_ci zfcp_erp_adapter_unblock(adapter); 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci case ZFCP_ERP_FAILED : 12688c2ecf20Sopenharmony_ci atomic_inc(&adapter->erp_counter); 12698c2ecf20Sopenharmony_ci if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) { 12708c2ecf20Sopenharmony_ci dev_err(&adapter->ccw_device->dev, 12718c2ecf20Sopenharmony_ci "ERP cannot recover an error " 12728c2ecf20Sopenharmony_ci "on the FCP device\n"); 12738c2ecf20Sopenharmony_ci zfcp_erp_set_adapter_status(adapter, 12748c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED); 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci break; 12778c2ecf20Sopenharmony_ci case ZFCP_ERP_CONTINUES: 12788c2ecf20Sopenharmony_ci case ZFCP_ERP_EXIT: 12798c2ecf20Sopenharmony_ci case ZFCP_ERP_DISMISSED: 12808c2ecf20Sopenharmony_ci case ZFCP_ERP_NOMEM: 12818c2ecf20Sopenharmony_ci /* NOP */ 12828c2ecf20Sopenharmony_ci break; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 12868c2ecf20Sopenharmony_ci zfcp_erp_adapter_block(adapter, 0); 12878c2ecf20Sopenharmony_ci result = ZFCP_ERP_EXIT; 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci return result; 12908c2ecf20Sopenharmony_ci} 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_check_target( 12938c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action, enum zfcp_erp_act_result result) 12948c2ecf20Sopenharmony_ci{ 12958c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = erp_action->adapter; 12968c2ecf20Sopenharmony_ci struct zfcp_port *port = erp_action->port; 12978c2ecf20Sopenharmony_ci struct scsi_device *sdev = erp_action->sdev; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci switch (erp_action->type) { 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 13028c2ecf20Sopenharmony_ci result = zfcp_erp_strategy_check_lun(sdev, result); 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 13068c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 13078c2ecf20Sopenharmony_ci result = zfcp_erp_strategy_check_port(port, result); 13088c2ecf20Sopenharmony_ci break; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 13118c2ecf20Sopenharmony_ci result = zfcp_erp_strategy_check_adapter(adapter, result); 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci return result; 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci int status = atomic_read(target_status); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if ((status & ZFCP_STATUS_COMMON_RUNNING) && 13228c2ecf20Sopenharmony_ci (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) 13238c2ecf20Sopenharmony_ci return 1; /* take it online */ 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (!(status & ZFCP_STATUS_COMMON_RUNNING) && 13268c2ecf20Sopenharmony_ci !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) 13278c2ecf20Sopenharmony_ci return 1; /* take it offline */ 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci return 0; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_statechange( 13338c2ecf20Sopenharmony_ci struct zfcp_erp_action *act, enum zfcp_erp_act_result result) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci enum zfcp_erp_act_type type = act->type; 13368c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 13378c2ecf20Sopenharmony_ci struct zfcp_port *port = act->port; 13388c2ecf20Sopenharmony_ci struct scsi_device *sdev = act->sdev; 13398c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev; 13408c2ecf20Sopenharmony_ci u32 erp_status = act->status; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci switch (type) { 13438c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 13448c2ecf20Sopenharmony_ci if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { 13458c2ecf20Sopenharmony_ci _zfcp_erp_adapter_reopen(adapter, 13468c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED, 13478c2ecf20Sopenharmony_ci "ersscg1"); 13488c2ecf20Sopenharmony_ci return ZFCP_ERP_EXIT; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci break; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 13538c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 13548c2ecf20Sopenharmony_ci if (zfcp_erp_strat_change_det(&port->status, erp_status)) { 13558c2ecf20Sopenharmony_ci _zfcp_erp_port_reopen(port, 13568c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED, 13578c2ecf20Sopenharmony_ci "ersscg2"); 13588c2ecf20Sopenharmony_ci return ZFCP_ERP_EXIT; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci break; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 13638c2ecf20Sopenharmony_ci zfcp_sdev = sdev_to_zfcp(sdev); 13648c2ecf20Sopenharmony_ci if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) { 13658c2ecf20Sopenharmony_ci _zfcp_erp_lun_reopen(sdev, 13668c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED, 13678c2ecf20Sopenharmony_ci "ersscg3", 0); 13688c2ecf20Sopenharmony_ci return ZFCP_ERP_EXIT; 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci break; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci return result; 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = erp_action->adapter; 13788c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci adapter->erp_total_count--; 13818c2ecf20Sopenharmony_ci if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { 13828c2ecf20Sopenharmony_ci adapter->erp_low_mem_count--; 13838c2ecf20Sopenharmony_ci erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci list_del(&erp_action->list); 13878c2ecf20Sopenharmony_ci zfcp_dbf_rec_run("eractd1", erp_action); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci switch (erp_action->type) { 13908c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 13918c2ecf20Sopenharmony_ci zfcp_sdev = sdev_to_zfcp(erp_action->sdev); 13928c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE, 13938c2ecf20Sopenharmony_ci &zfcp_sdev->status); 13948c2ecf20Sopenharmony_ci break; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 13978c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 13988c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE, 13998c2ecf20Sopenharmony_ci &erp_action->port->status); 14008c2ecf20Sopenharmony_ci break; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 14038c2ecf20Sopenharmony_ci atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE, 14048c2ecf20Sopenharmony_ci &erp_action->adapter->status); 14058c2ecf20Sopenharmony_ci break; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci} 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci/** 14108c2ecf20Sopenharmony_ci * zfcp_erp_try_rport_unblock - unblock rport if no more/new recovery 14118c2ecf20Sopenharmony_ci * @port: zfcp_port whose fc_rport we should try to unblock 14128c2ecf20Sopenharmony_ci */ 14138c2ecf20Sopenharmony_cistatic void zfcp_erp_try_rport_unblock(struct zfcp_port *port) 14148c2ecf20Sopenharmony_ci{ 14158c2ecf20Sopenharmony_ci unsigned long flags; 14168c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = port->adapter; 14178c2ecf20Sopenharmony_ci int port_status; 14188c2ecf20Sopenharmony_ci struct Scsi_Host *shost = adapter->scsi_host; 14198c2ecf20Sopenharmony_ci struct scsi_device *sdev; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 14228c2ecf20Sopenharmony_ci port_status = atomic_read(&port->status); 14238c2ecf20Sopenharmony_ci if ((port_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 || 14248c2ecf20Sopenharmony_ci (port_status & (ZFCP_STATUS_COMMON_ERP_INUSE | 14258c2ecf20Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED)) != 0) { 14268c2ecf20Sopenharmony_ci /* new ERP of severity >= port triggered elsewhere meanwhile or 14278c2ecf20Sopenharmony_ci * local link down (adapter erp_failed but not clear unblock) 14288c2ecf20Sopenharmony_ci */ 14298c2ecf20Sopenharmony_ci zfcp_dbf_rec_run_lvl(4, "ertru_p", &port->erp_action); 14308c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 14318c2ecf20Sopenharmony_ci return; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci spin_lock(shost->host_lock); 14348c2ecf20Sopenharmony_ci __shost_for_each_device(sdev, shost) { 14358c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev); 14368c2ecf20Sopenharmony_ci int lun_status; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci if (sdev->sdev_state == SDEV_DEL || 14398c2ecf20Sopenharmony_ci sdev->sdev_state == SDEV_CANCEL) 14408c2ecf20Sopenharmony_ci continue; 14418c2ecf20Sopenharmony_ci if (zsdev->port != port) 14428c2ecf20Sopenharmony_ci continue; 14438c2ecf20Sopenharmony_ci /* LUN under port of interest */ 14448c2ecf20Sopenharmony_ci lun_status = atomic_read(&zsdev->status); 14458c2ecf20Sopenharmony_ci if ((lun_status & ZFCP_STATUS_COMMON_ERP_FAILED) != 0) 14468c2ecf20Sopenharmony_ci continue; /* unblock rport despite failed LUNs */ 14478c2ecf20Sopenharmony_ci /* LUN recovery not given up yet [maybe follow-up pending] */ 14488c2ecf20Sopenharmony_ci if ((lun_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 || 14498c2ecf20Sopenharmony_ci (lun_status & ZFCP_STATUS_COMMON_ERP_INUSE) != 0) { 14508c2ecf20Sopenharmony_ci /* LUN blocked: 14518c2ecf20Sopenharmony_ci * not yet unblocked [LUN recovery pending] 14528c2ecf20Sopenharmony_ci * or meanwhile blocked [new LUN recovery triggered] 14538c2ecf20Sopenharmony_ci */ 14548c2ecf20Sopenharmony_ci zfcp_dbf_rec_run_lvl(4, "ertru_l", &zsdev->erp_action); 14558c2ecf20Sopenharmony_ci spin_unlock(shost->host_lock); 14568c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 14578c2ecf20Sopenharmony_ci return; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci /* now port has no child or all children have completed recovery, 14618c2ecf20Sopenharmony_ci * and no ERP of severity >= port was meanwhile triggered elsewhere 14628c2ecf20Sopenharmony_ci */ 14638c2ecf20Sopenharmony_ci zfcp_scsi_schedule_rport_register(port); 14648c2ecf20Sopenharmony_ci spin_unlock(shost->host_lock); 14658c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_cistatic void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, 14698c2ecf20Sopenharmony_ci enum zfcp_erp_act_result result) 14708c2ecf20Sopenharmony_ci{ 14718c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = act->adapter; 14728c2ecf20Sopenharmony_ci struct zfcp_port *port = act->port; 14738c2ecf20Sopenharmony_ci struct scsi_device *sdev = act->sdev; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci switch (act->type) { 14768c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 14778c2ecf20Sopenharmony_ci if (!(act->status & ZFCP_STATUS_ERP_NO_REF)) 14788c2ecf20Sopenharmony_ci scsi_device_put(sdev); 14798c2ecf20Sopenharmony_ci zfcp_erp_try_rport_unblock(port); 14808c2ecf20Sopenharmony_ci break; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 14838c2ecf20Sopenharmony_ci /* This switch case might also happen after a forced reopen 14848c2ecf20Sopenharmony_ci * was successfully done and thus overwritten with a new 14858c2ecf20Sopenharmony_ci * non-forced reopen at `ersfs_2'. In this case, we must not 14868c2ecf20Sopenharmony_ci * do the clean-up of the non-forced version. 14878c2ecf20Sopenharmony_ci */ 14888c2ecf20Sopenharmony_ci if (act->step != ZFCP_ERP_STEP_UNINITIALIZED) 14898c2ecf20Sopenharmony_ci if (result == ZFCP_ERP_SUCCEEDED) 14908c2ecf20Sopenharmony_ci zfcp_erp_try_rport_unblock(port); 14918c2ecf20Sopenharmony_ci fallthrough; 14928c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 14938c2ecf20Sopenharmony_ci put_device(&port->dev); 14948c2ecf20Sopenharmony_ci break; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 14978c2ecf20Sopenharmony_ci if (result == ZFCP_ERP_SUCCEEDED) { 14988c2ecf20Sopenharmony_ci register_service_level(&adapter->service_level); 14998c2ecf20Sopenharmony_ci zfcp_fc_conditional_port_scan(adapter); 15008c2ecf20Sopenharmony_ci queue_work(adapter->work_queue, &adapter->ns_up_work); 15018c2ecf20Sopenharmony_ci } else 15028c2ecf20Sopenharmony_ci unregister_service_level(&adapter->service_level); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci kref_put(&adapter->ref, zfcp_adapter_release); 15058c2ecf20Sopenharmony_ci break; 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_do_action( 15108c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci switch (erp_action->type) { 15138c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 15148c2ecf20Sopenharmony_ci return zfcp_erp_adapter_strategy(erp_action); 15158c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 15168c2ecf20Sopenharmony_ci return zfcp_erp_port_forced_strategy(erp_action); 15178c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_PORT: 15188c2ecf20Sopenharmony_ci return zfcp_erp_port_strategy(erp_action); 15198c2ecf20Sopenharmony_ci case ZFCP_ERP_ACTION_REOPEN_LUN: 15208c2ecf20Sopenharmony_ci return zfcp_erp_lun_strategy(erp_action); 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci return ZFCP_ERP_FAILED; 15238c2ecf20Sopenharmony_ci} 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy( 15268c2ecf20Sopenharmony_ci struct zfcp_erp_action *erp_action) 15278c2ecf20Sopenharmony_ci{ 15288c2ecf20Sopenharmony_ci enum zfcp_erp_act_result result; 15298c2ecf20Sopenharmony_ci unsigned long flags; 15308c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = erp_action->adapter; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci kref_get(&adapter->ref); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 15358c2ecf20Sopenharmony_ci zfcp_erp_strategy_check_fsfreq(erp_action); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { 15388c2ecf20Sopenharmony_ci zfcp_erp_action_dequeue(erp_action); 15398c2ecf20Sopenharmony_ci result = ZFCP_ERP_DISMISSED; 15408c2ecf20Sopenharmony_ci goto unlock; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { 15448c2ecf20Sopenharmony_ci result = ZFCP_ERP_FAILED; 15458c2ecf20Sopenharmony_ci goto check_target; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci zfcp_erp_action_to_running(erp_action); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci /* no lock to allow for blocking operations */ 15518c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 15528c2ecf20Sopenharmony_ci result = zfcp_erp_strategy_do_action(erp_action); 15538c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) 15568c2ecf20Sopenharmony_ci result = ZFCP_ERP_CONTINUES; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci switch (result) { 15598c2ecf20Sopenharmony_ci case ZFCP_ERP_NOMEM: 15608c2ecf20Sopenharmony_ci if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { 15618c2ecf20Sopenharmony_ci ++adapter->erp_low_mem_count; 15628c2ecf20Sopenharmony_ci erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci if (adapter->erp_total_count == adapter->erp_low_mem_count) 15658c2ecf20Sopenharmony_ci _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1"); 15668c2ecf20Sopenharmony_ci else { 15678c2ecf20Sopenharmony_ci zfcp_erp_strategy_memwait(erp_action); 15688c2ecf20Sopenharmony_ci result = ZFCP_ERP_CONTINUES; 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci goto unlock; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci case ZFCP_ERP_CONTINUES: 15738c2ecf20Sopenharmony_ci if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { 15748c2ecf20Sopenharmony_ci --adapter->erp_low_mem_count; 15758c2ecf20Sopenharmony_ci erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci goto unlock; 15788c2ecf20Sopenharmony_ci case ZFCP_ERP_SUCCEEDED: 15798c2ecf20Sopenharmony_ci case ZFCP_ERP_FAILED: 15808c2ecf20Sopenharmony_ci case ZFCP_ERP_EXIT: 15818c2ecf20Sopenharmony_ci case ZFCP_ERP_DISMISSED: 15828c2ecf20Sopenharmony_ci /* NOP */ 15838c2ecf20Sopenharmony_ci break; 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_cicheck_target: 15878c2ecf20Sopenharmony_ci result = zfcp_erp_strategy_check_target(erp_action, result); 15888c2ecf20Sopenharmony_ci zfcp_erp_action_dequeue(erp_action); 15898c2ecf20Sopenharmony_ci result = zfcp_erp_strategy_statechange(erp_action, result); 15908c2ecf20Sopenharmony_ci if (result == ZFCP_ERP_EXIT) 15918c2ecf20Sopenharmony_ci goto unlock; 15928c2ecf20Sopenharmony_ci if (result == ZFCP_ERP_SUCCEEDED) 15938c2ecf20Sopenharmony_ci zfcp_erp_strategy_followup_success(erp_action); 15948c2ecf20Sopenharmony_ci if (result == ZFCP_ERP_FAILED) 15958c2ecf20Sopenharmony_ci zfcp_erp_strategy_followup_failed(erp_action); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci unlock: 15988c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (result != ZFCP_ERP_CONTINUES) 16018c2ecf20Sopenharmony_ci zfcp_erp_action_cleanup(erp_action, result); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci kref_put(&adapter->ref, zfcp_adapter_release); 16048c2ecf20Sopenharmony_ci return result; 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_cistatic int zfcp_erp_thread(void *data) 16088c2ecf20Sopenharmony_ci{ 16098c2ecf20Sopenharmony_ci struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; 16108c2ecf20Sopenharmony_ci struct zfcp_erp_action *act; 16118c2ecf20Sopenharmony_ci unsigned long flags; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci for (;;) { 16148c2ecf20Sopenharmony_ci wait_event_interruptible(adapter->erp_ready_wq, 16158c2ecf20Sopenharmony_ci !list_empty(&adapter->erp_ready_head) || 16168c2ecf20Sopenharmony_ci kthread_should_stop()); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci if (kthread_should_stop()) 16198c2ecf20Sopenharmony_ci break; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci write_lock_irqsave(&adapter->erp_lock, flags); 16228c2ecf20Sopenharmony_ci act = list_first_entry_or_null(&adapter->erp_ready_head, 16238c2ecf20Sopenharmony_ci struct zfcp_erp_action, list); 16248c2ecf20Sopenharmony_ci write_unlock_irqrestore(&adapter->erp_lock, flags); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (act) { 16278c2ecf20Sopenharmony_ci /* there is more to come after dismission, no notify */ 16288c2ecf20Sopenharmony_ci if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) 16298c2ecf20Sopenharmony_ci zfcp_erp_wakeup(adapter); 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci return 0; 16348c2ecf20Sopenharmony_ci} 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci/** 16378c2ecf20Sopenharmony_ci * zfcp_erp_thread_setup - Start ERP thread for adapter 16388c2ecf20Sopenharmony_ci * @adapter: Adapter to start the ERP thread for 16398c2ecf20Sopenharmony_ci * 16408c2ecf20Sopenharmony_ci * Return: 0 on success, or error code from kthread_run(). 16418c2ecf20Sopenharmony_ci */ 16428c2ecf20Sopenharmony_ciint zfcp_erp_thread_setup(struct zfcp_adapter *adapter) 16438c2ecf20Sopenharmony_ci{ 16448c2ecf20Sopenharmony_ci struct task_struct *thread; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s", 16478c2ecf20Sopenharmony_ci dev_name(&adapter->ccw_device->dev)); 16488c2ecf20Sopenharmony_ci if (IS_ERR(thread)) { 16498c2ecf20Sopenharmony_ci dev_err(&adapter->ccw_device->dev, 16508c2ecf20Sopenharmony_ci "Creating an ERP thread for the FCP device failed.\n"); 16518c2ecf20Sopenharmony_ci return PTR_ERR(thread); 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci adapter->erp_thread = thread; 16558c2ecf20Sopenharmony_ci return 0; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci/** 16598c2ecf20Sopenharmony_ci * zfcp_erp_thread_kill - Stop ERP thread. 16608c2ecf20Sopenharmony_ci * @adapter: Adapter where the ERP thread should be stopped. 16618c2ecf20Sopenharmony_ci * 16628c2ecf20Sopenharmony_ci * The caller of this routine ensures that the specified adapter has 16638c2ecf20Sopenharmony_ci * been shut down and that this operation has been completed. Thus, 16648c2ecf20Sopenharmony_ci * there are no pending erp_actions which would need to be handled 16658c2ecf20Sopenharmony_ci * here. 16668c2ecf20Sopenharmony_ci */ 16678c2ecf20Sopenharmony_civoid zfcp_erp_thread_kill(struct zfcp_adapter *adapter) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci kthread_stop(adapter->erp_thread); 16708c2ecf20Sopenharmony_ci adapter->erp_thread = NULL; 16718c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&adapter->erp_ready_head)); 16728c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&adapter->erp_running_head)); 16738c2ecf20Sopenharmony_ci} 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci/** 16768c2ecf20Sopenharmony_ci * zfcp_erp_wait - wait for completion of error recovery on an adapter 16778c2ecf20Sopenharmony_ci * @adapter: adapter for which to wait for completion of its error recovery 16788c2ecf20Sopenharmony_ci */ 16798c2ecf20Sopenharmony_civoid zfcp_erp_wait(struct zfcp_adapter *adapter) 16808c2ecf20Sopenharmony_ci{ 16818c2ecf20Sopenharmony_ci wait_event(adapter->erp_done_wqh, 16828c2ecf20Sopenharmony_ci !(atomic_read(&adapter->status) & 16838c2ecf20Sopenharmony_ci ZFCP_STATUS_ADAPTER_ERP_PENDING)); 16848c2ecf20Sopenharmony_ci} 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci/** 16878c2ecf20Sopenharmony_ci * zfcp_erp_set_adapter_status - set adapter status bits 16888c2ecf20Sopenharmony_ci * @adapter: adapter to change the status 16898c2ecf20Sopenharmony_ci * @mask: status bits to change 16908c2ecf20Sopenharmony_ci * 16918c2ecf20Sopenharmony_ci * Changes in common status bits are propagated to attached ports and LUNs. 16928c2ecf20Sopenharmony_ci */ 16938c2ecf20Sopenharmony_civoid zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask) 16948c2ecf20Sopenharmony_ci{ 16958c2ecf20Sopenharmony_ci struct zfcp_port *port; 16968c2ecf20Sopenharmony_ci struct scsi_device *sdev; 16978c2ecf20Sopenharmony_ci unsigned long flags; 16988c2ecf20Sopenharmony_ci u32 common_mask = mask & ZFCP_COMMON_FLAGS; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci atomic_or(mask, &adapter->status); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci if (!common_mask) 17038c2ecf20Sopenharmony_ci return; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci read_lock_irqsave(&adapter->port_list_lock, flags); 17068c2ecf20Sopenharmony_ci list_for_each_entry(port, &adapter->port_list, list) 17078c2ecf20Sopenharmony_ci atomic_or(common_mask, &port->status); 17088c2ecf20Sopenharmony_ci read_unlock_irqrestore(&adapter->port_list_lock, flags); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci /* 17118c2ecf20Sopenharmony_ci * if `scsi_host` is missing, xconfig/xport data has never completed 17128c2ecf20Sopenharmony_ci * yet, so we can't access it, but there are also no SDEVs yet 17138c2ecf20Sopenharmony_ci */ 17148c2ecf20Sopenharmony_ci if (adapter->scsi_host == NULL) 17158c2ecf20Sopenharmony_ci return; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci spin_lock_irqsave(adapter->scsi_host->host_lock, flags); 17188c2ecf20Sopenharmony_ci __shost_for_each_device(sdev, adapter->scsi_host) 17198c2ecf20Sopenharmony_ci atomic_or(common_mask, &sdev_to_zfcp(sdev)->status); 17208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags); 17218c2ecf20Sopenharmony_ci} 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci/** 17248c2ecf20Sopenharmony_ci * zfcp_erp_clear_adapter_status - clear adapter status bits 17258c2ecf20Sopenharmony_ci * @adapter: adapter to change the status 17268c2ecf20Sopenharmony_ci * @mask: status bits to change 17278c2ecf20Sopenharmony_ci * 17288c2ecf20Sopenharmony_ci * Changes in common status bits are propagated to attached ports and LUNs. 17298c2ecf20Sopenharmony_ci */ 17308c2ecf20Sopenharmony_civoid zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci struct zfcp_port *port; 17338c2ecf20Sopenharmony_ci struct scsi_device *sdev; 17348c2ecf20Sopenharmony_ci unsigned long flags; 17358c2ecf20Sopenharmony_ci u32 common_mask = mask & ZFCP_COMMON_FLAGS; 17368c2ecf20Sopenharmony_ci u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci atomic_andnot(mask, &adapter->status); 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (!common_mask) 17418c2ecf20Sopenharmony_ci return; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci if (clear_counter) 17448c2ecf20Sopenharmony_ci atomic_set(&adapter->erp_counter, 0); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci read_lock_irqsave(&adapter->port_list_lock, flags); 17478c2ecf20Sopenharmony_ci list_for_each_entry(port, &adapter->port_list, list) { 17488c2ecf20Sopenharmony_ci atomic_andnot(common_mask, &port->status); 17498c2ecf20Sopenharmony_ci if (clear_counter) 17508c2ecf20Sopenharmony_ci atomic_set(&port->erp_counter, 0); 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci read_unlock_irqrestore(&adapter->port_list_lock, flags); 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci /* 17558c2ecf20Sopenharmony_ci * if `scsi_host` is missing, xconfig/xport data has never completed 17568c2ecf20Sopenharmony_ci * yet, so we can't access it, but there are also no SDEVs yet 17578c2ecf20Sopenharmony_ci */ 17588c2ecf20Sopenharmony_ci if (adapter->scsi_host == NULL) 17598c2ecf20Sopenharmony_ci return; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci spin_lock_irqsave(adapter->scsi_host->host_lock, flags); 17628c2ecf20Sopenharmony_ci __shost_for_each_device(sdev, adapter->scsi_host) { 17638c2ecf20Sopenharmony_ci atomic_andnot(common_mask, &sdev_to_zfcp(sdev)->status); 17648c2ecf20Sopenharmony_ci if (clear_counter) 17658c2ecf20Sopenharmony_ci atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); 17668c2ecf20Sopenharmony_ci } 17678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags); 17688c2ecf20Sopenharmony_ci} 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci/** 17718c2ecf20Sopenharmony_ci * zfcp_erp_set_port_status - set port status bits 17728c2ecf20Sopenharmony_ci * @port: port to change the status 17738c2ecf20Sopenharmony_ci * @mask: status bits to change 17748c2ecf20Sopenharmony_ci * 17758c2ecf20Sopenharmony_ci * Changes in common status bits are propagated to attached LUNs. 17768c2ecf20Sopenharmony_ci */ 17778c2ecf20Sopenharmony_civoid zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci struct scsi_device *sdev; 17808c2ecf20Sopenharmony_ci u32 common_mask = mask & ZFCP_COMMON_FLAGS; 17818c2ecf20Sopenharmony_ci unsigned long flags; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci atomic_or(mask, &port->status); 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci if (!common_mask) 17868c2ecf20Sopenharmony_ci return; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); 17898c2ecf20Sopenharmony_ci __shost_for_each_device(sdev, port->adapter->scsi_host) 17908c2ecf20Sopenharmony_ci if (sdev_to_zfcp(sdev)->port == port) 17918c2ecf20Sopenharmony_ci atomic_or(common_mask, 17928c2ecf20Sopenharmony_ci &sdev_to_zfcp(sdev)->status); 17938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags); 17948c2ecf20Sopenharmony_ci} 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci/** 17978c2ecf20Sopenharmony_ci * zfcp_erp_clear_port_status - clear port status bits 17988c2ecf20Sopenharmony_ci * @port: adapter to change the status 17998c2ecf20Sopenharmony_ci * @mask: status bits to change 18008c2ecf20Sopenharmony_ci * 18018c2ecf20Sopenharmony_ci * Changes in common status bits are propagated to attached LUNs. 18028c2ecf20Sopenharmony_ci */ 18038c2ecf20Sopenharmony_civoid zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) 18048c2ecf20Sopenharmony_ci{ 18058c2ecf20Sopenharmony_ci struct scsi_device *sdev; 18068c2ecf20Sopenharmony_ci u32 common_mask = mask & ZFCP_COMMON_FLAGS; 18078c2ecf20Sopenharmony_ci u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; 18088c2ecf20Sopenharmony_ci unsigned long flags; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci atomic_andnot(mask, &port->status); 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci if (!common_mask) 18138c2ecf20Sopenharmony_ci return; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (clear_counter) 18168c2ecf20Sopenharmony_ci atomic_set(&port->erp_counter, 0); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); 18198c2ecf20Sopenharmony_ci __shost_for_each_device(sdev, port->adapter->scsi_host) 18208c2ecf20Sopenharmony_ci if (sdev_to_zfcp(sdev)->port == port) { 18218c2ecf20Sopenharmony_ci atomic_andnot(common_mask, 18228c2ecf20Sopenharmony_ci &sdev_to_zfcp(sdev)->status); 18238c2ecf20Sopenharmony_ci if (clear_counter) 18248c2ecf20Sopenharmony_ci atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags); 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci/** 18308c2ecf20Sopenharmony_ci * zfcp_erp_set_lun_status - set lun status bits 18318c2ecf20Sopenharmony_ci * @sdev: SCSI device / lun to set the status bits 18328c2ecf20Sopenharmony_ci * @mask: status bits to change 18338c2ecf20Sopenharmony_ci */ 18348c2ecf20Sopenharmony_civoid zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci atomic_or(mask, &zfcp_sdev->status); 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci/** 18428c2ecf20Sopenharmony_ci * zfcp_erp_clear_lun_status - clear lun status bits 18438c2ecf20Sopenharmony_ci * @sdev: SCSi device / lun to clear the status bits 18448c2ecf20Sopenharmony_ci * @mask: status bits to change 18458c2ecf20Sopenharmony_ci */ 18468c2ecf20Sopenharmony_civoid zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci atomic_andnot(mask, &zfcp_sdev->status); 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) 18538c2ecf20Sopenharmony_ci atomic_set(&zfcp_sdev->erp_counter, 0); 18548c2ecf20Sopenharmony_ci} 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci/** 18578c2ecf20Sopenharmony_ci * zfcp_erp_adapter_reset_sync() - Really reopen adapter and wait. 18588c2ecf20Sopenharmony_ci * @adapter: Pointer to zfcp_adapter to reopen. 18598c2ecf20Sopenharmony_ci * @dbftag: Trace tag string of length %ZFCP_DBF_TAG_LEN. 18608c2ecf20Sopenharmony_ci */ 18618c2ecf20Sopenharmony_civoid zfcp_erp_adapter_reset_sync(struct zfcp_adapter *adapter, char *dbftag) 18628c2ecf20Sopenharmony_ci{ 18638c2ecf20Sopenharmony_ci zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); 18648c2ecf20Sopenharmony_ci zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, dbftag); 18658c2ecf20Sopenharmony_ci zfcp_erp_wait(adapter); 18668c2ecf20Sopenharmony_ci} 1867