11da177e4SLinus Torvalds /* 2553448f6SChristof Schmitt * zfcp device driver 31da177e4SLinus Torvalds * 4553448f6SChristof Schmitt * Error Recovery Procedures (ERP). 51da177e4SLinus Torvalds * 6a2fa0aedSChristof Schmitt * Copyright IBM Corporation 2002, 2009 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 9ecf39d42SChristof Schmitt #define KMSG_COMPONENT "zfcp" 10ecf39d42SChristof Schmitt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 11ecf39d42SChristof Schmitt 121da177e4SLinus Torvalds #include "zfcp_ext.h" 131da177e4SLinus Torvalds 14287ac01aSChristof Schmitt #define ZFCP_MAX_ERPS 3 151da177e4SLinus Torvalds 16287ac01aSChristof Schmitt enum zfcp_erp_act_flags { 17287ac01aSChristof Schmitt ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000, 18287ac01aSChristof Schmitt ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000, 19287ac01aSChristof Schmitt ZFCP_STATUS_ERP_DISMISSING = 0x00100000, 20287ac01aSChristof Schmitt ZFCP_STATUS_ERP_DISMISSED = 0x00200000, 21287ac01aSChristof Schmitt ZFCP_STATUS_ERP_LOWMEM = 0x00400000, 22287ac01aSChristof Schmitt }; 231da177e4SLinus Torvalds 24287ac01aSChristof Schmitt enum zfcp_erp_steps { 25287ac01aSChristof Schmitt ZFCP_ERP_STEP_UNINITIALIZED = 0x0000, 26287ac01aSChristof Schmitt ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001, 27287ac01aSChristof Schmitt ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, 28287ac01aSChristof Schmitt ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, 29287ac01aSChristof Schmitt ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400, 30287ac01aSChristof Schmitt ZFCP_ERP_STEP_PORT_OPENING = 0x0800, 31287ac01aSChristof Schmitt ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, 32287ac01aSChristof Schmitt ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, 33287ac01aSChristof Schmitt }; 341da177e4SLinus Torvalds 35287ac01aSChristof Schmitt enum zfcp_erp_act_type { 36287ac01aSChristof Schmitt ZFCP_ERP_ACTION_REOPEN_UNIT = 1, 37287ac01aSChristof Schmitt ZFCP_ERP_ACTION_REOPEN_PORT = 2, 38287ac01aSChristof Schmitt ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, 39287ac01aSChristof Schmitt ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, 40287ac01aSChristof Schmitt }; 411da177e4SLinus Torvalds 42287ac01aSChristof Schmitt enum zfcp_erp_act_state { 43287ac01aSChristof Schmitt ZFCP_ERP_ACTION_RUNNING = 1, 44287ac01aSChristof Schmitt ZFCP_ERP_ACTION_READY = 2, 45287ac01aSChristof Schmitt }; 461da177e4SLinus Torvalds 47287ac01aSChristof Schmitt enum zfcp_erp_act_result { 48287ac01aSChristof Schmitt ZFCP_ERP_SUCCEEDED = 0, 49287ac01aSChristof Schmitt ZFCP_ERP_FAILED = 1, 50287ac01aSChristof Schmitt ZFCP_ERP_CONTINUES = 2, 51287ac01aSChristof Schmitt ZFCP_ERP_EXIT = 3, 52287ac01aSChristof Schmitt ZFCP_ERP_DISMISSED = 4, 53287ac01aSChristof Schmitt ZFCP_ERP_NOMEM = 5, 54287ac01aSChristof Schmitt }; 551da177e4SLinus Torvalds 56287ac01aSChristof Schmitt static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) 572abbe866SAndreas Herrmann { 585ffd51a5SSwen Schillig zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL, 59287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_UNBLOCKED | mask, 60287ac01aSChristof Schmitt ZFCP_CLEAR); 612abbe866SAndreas Herrmann } 621da177e4SLinus Torvalds 63287ac01aSChristof Schmitt static int zfcp_erp_action_exists(struct zfcp_erp_action *act) 641da177e4SLinus Torvalds { 65287ac01aSChristof Schmitt struct zfcp_erp_action *curr_act; 66287ac01aSChristof Schmitt 67287ac01aSChristof Schmitt list_for_each_entry(curr_act, &act->adapter->erp_running_head, list) 68287ac01aSChristof Schmitt if (act == curr_act) 69287ac01aSChristof Schmitt return ZFCP_ERP_ACTION_RUNNING; 70287ac01aSChristof Schmitt return 0; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 73287ac01aSChristof Schmitt static void zfcp_erp_action_ready(struct zfcp_erp_action *act) 741da177e4SLinus Torvalds { 75287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 76287ac01aSChristof Schmitt 77287ac01aSChristof Schmitt list_move(&act->list, &act->adapter->erp_ready_head); 785ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("erardy1", act); 79287ac01aSChristof Schmitt up(&adapter->erp_ready_sem); 805ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread("erardy2", adapter); 811da177e4SLinus Torvalds } 821da177e4SLinus Torvalds 83287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) 84287ac01aSChristof Schmitt { 85287ac01aSChristof Schmitt act->status |= ZFCP_STATUS_ERP_DISMISSED; 86287ac01aSChristof Schmitt if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING) 87287ac01aSChristof Schmitt zfcp_erp_action_ready(act); 88287ac01aSChristof Schmitt } 89287ac01aSChristof Schmitt 90287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) 91287ac01aSChristof Schmitt { 92287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE) 93287ac01aSChristof Schmitt zfcp_erp_action_dismiss(&unit->erp_action); 94287ac01aSChristof Schmitt } 95287ac01aSChristof Schmitt 96287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) 97287ac01aSChristof Schmitt { 98287ac01aSChristof Schmitt struct zfcp_unit *unit; 99287ac01aSChristof Schmitt 100287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) 101287ac01aSChristof Schmitt zfcp_erp_action_dismiss(&port->erp_action); 102287ac01aSChristof Schmitt else 103287ac01aSChristof Schmitt list_for_each_entry(unit, &port->unit_list_head, list) 104287ac01aSChristof Schmitt zfcp_erp_action_dismiss_unit(unit); 105287ac01aSChristof Schmitt } 106287ac01aSChristof Schmitt 107287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) 108287ac01aSChristof Schmitt { 109287ac01aSChristof Schmitt struct zfcp_port *port; 110287ac01aSChristof Schmitt 111287ac01aSChristof Schmitt if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE) 112287ac01aSChristof Schmitt zfcp_erp_action_dismiss(&adapter->erp_action); 113287ac01aSChristof Schmitt else 114287ac01aSChristof Schmitt list_for_each_entry(port, &adapter->port_list_head, list) 115287ac01aSChristof Schmitt zfcp_erp_action_dismiss_port(port); 116287ac01aSChristof Schmitt } 117287ac01aSChristof Schmitt 118287ac01aSChristof Schmitt static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, 119287ac01aSChristof Schmitt struct zfcp_port *port, 120287ac01aSChristof Schmitt struct zfcp_unit *unit) 121287ac01aSChristof Schmitt { 122287ac01aSChristof Schmitt int need = want; 123287ac01aSChristof Schmitt int u_status, p_status, a_status; 124287ac01aSChristof Schmitt 125287ac01aSChristof Schmitt switch (want) { 126287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 127287ac01aSChristof Schmitt u_status = atomic_read(&unit->status); 128287ac01aSChristof Schmitt if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE) 129287ac01aSChristof Schmitt return 0; 130287ac01aSChristof Schmitt p_status = atomic_read(&port->status); 131287ac01aSChristof Schmitt if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || 132287ac01aSChristof Schmitt p_status & ZFCP_STATUS_COMMON_ERP_FAILED) 133287ac01aSChristof Schmitt return 0; 134287ac01aSChristof Schmitt if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) 135287ac01aSChristof Schmitt need = ZFCP_ERP_ACTION_REOPEN_PORT; 136287ac01aSChristof Schmitt /* fall through */ 137287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 138287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 139287ac01aSChristof Schmitt p_status = atomic_read(&port->status); 140287ac01aSChristof Schmitt if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE) 141287ac01aSChristof Schmitt return 0; 142287ac01aSChristof Schmitt a_status = atomic_read(&adapter->status); 143287ac01aSChristof Schmitt if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || 144287ac01aSChristof Schmitt a_status & ZFCP_STATUS_COMMON_ERP_FAILED) 145287ac01aSChristof Schmitt return 0; 146287ac01aSChristof Schmitt if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) 147287ac01aSChristof Schmitt need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; 148287ac01aSChristof Schmitt /* fall through */ 149287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 150287ac01aSChristof Schmitt a_status = atomic_read(&adapter->status); 151287ac01aSChristof Schmitt if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) 152287ac01aSChristof Schmitt return 0; 153287ac01aSChristof Schmitt } 154287ac01aSChristof Schmitt 155287ac01aSChristof Schmitt return need; 156287ac01aSChristof Schmitt } 157287ac01aSChristof Schmitt 158287ac01aSChristof Schmitt static struct zfcp_erp_action *zfcp_erp_setup_act(int need, 159287ac01aSChristof Schmitt struct zfcp_adapter *adapter, 160287ac01aSChristof Schmitt struct zfcp_port *port, 161287ac01aSChristof Schmitt struct zfcp_unit *unit) 162287ac01aSChristof Schmitt { 163287ac01aSChristof Schmitt struct zfcp_erp_action *erp_action; 164287ac01aSChristof Schmitt u32 status = 0; 165287ac01aSChristof Schmitt 166287ac01aSChristof Schmitt switch (need) { 167287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 168287ac01aSChristof Schmitt zfcp_unit_get(unit); 169287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); 170287ac01aSChristof Schmitt erp_action = &unit->erp_action; 171287ac01aSChristof Schmitt if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) 172287ac01aSChristof Schmitt status = ZFCP_STATUS_ERP_CLOSE_ONLY; 173287ac01aSChristof Schmitt break; 174287ac01aSChristof Schmitt 175287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 176287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 177287ac01aSChristof Schmitt zfcp_port_get(port); 178287ac01aSChristof Schmitt zfcp_erp_action_dismiss_port(port); 179287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); 180287ac01aSChristof Schmitt erp_action = &port->erp_action; 181287ac01aSChristof Schmitt if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) 182287ac01aSChristof Schmitt status = ZFCP_STATUS_ERP_CLOSE_ONLY; 183287ac01aSChristof Schmitt break; 184287ac01aSChristof Schmitt 185287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 186287ac01aSChristof Schmitt zfcp_adapter_get(adapter); 187287ac01aSChristof Schmitt zfcp_erp_action_dismiss_adapter(adapter); 188287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); 189287ac01aSChristof Schmitt erp_action = &adapter->erp_action; 190287ac01aSChristof Schmitt if (!(atomic_read(&adapter->status) & 191287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_RUNNING)) 192287ac01aSChristof Schmitt status = ZFCP_STATUS_ERP_CLOSE_ONLY; 193287ac01aSChristof Schmitt break; 194287ac01aSChristof Schmitt 195287ac01aSChristof Schmitt default: 196287ac01aSChristof Schmitt return NULL; 197287ac01aSChristof Schmitt } 198287ac01aSChristof Schmitt 199287ac01aSChristof Schmitt memset(erp_action, 0, sizeof(struct zfcp_erp_action)); 200287ac01aSChristof Schmitt erp_action->adapter = adapter; 201287ac01aSChristof Schmitt erp_action->port = port; 202287ac01aSChristof Schmitt erp_action->unit = unit; 203287ac01aSChristof Schmitt erp_action->action = need; 204287ac01aSChristof Schmitt erp_action->status = status; 205287ac01aSChristof Schmitt 206287ac01aSChristof Schmitt return erp_action; 207287ac01aSChristof Schmitt } 208287ac01aSChristof Schmitt 209287ac01aSChristof Schmitt static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, 210287ac01aSChristof Schmitt struct zfcp_port *port, 2115ffd51a5SSwen Schillig struct zfcp_unit *unit, char *id, void *ref) 212287ac01aSChristof Schmitt { 213287ac01aSChristof Schmitt int retval = 1, need; 214287ac01aSChristof Schmitt struct zfcp_erp_action *act = NULL; 215287ac01aSChristof Schmitt 216287ac01aSChristof Schmitt if (!(atomic_read(&adapter->status) & 217287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)) 218287ac01aSChristof Schmitt return -EIO; 219287ac01aSChristof Schmitt 220287ac01aSChristof Schmitt need = zfcp_erp_required_act(want, adapter, port, unit); 221287ac01aSChristof Schmitt if (!need) 222287ac01aSChristof Schmitt goto out; 223287ac01aSChristof Schmitt 224287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); 225287ac01aSChristof Schmitt act = zfcp_erp_setup_act(need, adapter, port, unit); 226287ac01aSChristof Schmitt if (!act) 227287ac01aSChristof Schmitt goto out; 228287ac01aSChristof Schmitt ++adapter->erp_total_count; 229287ac01aSChristof Schmitt list_add_tail(&act->list, &adapter->erp_ready_head); 230287ac01aSChristof Schmitt up(&adapter->erp_ready_sem); 2315ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread("eracte1", adapter); 232287ac01aSChristof Schmitt retval = 0; 233287ac01aSChristof Schmitt out: 234287ac01aSChristof Schmitt zfcp_rec_dbf_event_trigger(id, ref, want, need, act, 235287ac01aSChristof Schmitt adapter, port, unit); 236287ac01aSChristof Schmitt return retval; 237287ac01aSChristof Schmitt } 238287ac01aSChristof Schmitt 239287ac01aSChristof Schmitt static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, 2405ffd51a5SSwen Schillig int clear_mask, char *id, void *ref) 2411da177e4SLinus Torvalds { 2421da177e4SLinus Torvalds zfcp_erp_adapter_block(adapter, clear_mask); 243a2fa0aedSChristof Schmitt zfcp_scsi_schedule_rports_block(adapter); 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds /* ensure propagation of failed status to new devices */ 246287ac01aSChristof Schmitt if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 2475ffd51a5SSwen Schillig zfcp_erp_adapter_failed(adapter, "erareo1", NULL); 248287ac01aSChristof Schmitt return -EIO; 2491da177e4SLinus Torvalds } 250287ac01aSChristof Schmitt return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, 2519467a9b3SMartin Peschke adapter, NULL, NULL, id, ref); 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds /** 255287ac01aSChristof Schmitt * zfcp_erp_adapter_reopen - Reopen adapter. 256287ac01aSChristof Schmitt * @adapter: Adapter to reopen. 257287ac01aSChristof Schmitt * @clear: Status flags to clear. 258287ac01aSChristof Schmitt * @id: Id for debug trace event. 259287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 2601da177e4SLinus Torvalds */ 261287ac01aSChristof Schmitt void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, 2625ffd51a5SSwen Schillig char *id, void *ref) 263287ac01aSChristof Schmitt { 264287ac01aSChristof Schmitt unsigned long flags; 265287ac01aSChristof Schmitt 266287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 267287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 268287ac01aSChristof Schmitt _zfcp_erp_adapter_reopen(adapter, clear, id, ref); 269287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 270287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 271287ac01aSChristof Schmitt } 272287ac01aSChristof Schmitt 273287ac01aSChristof Schmitt /** 274287ac01aSChristof Schmitt * zfcp_erp_adapter_shutdown - Shutdown adapter. 275287ac01aSChristof Schmitt * @adapter: Adapter to shut down. 276287ac01aSChristof Schmitt * @clear: Status flags to clear. 277287ac01aSChristof Schmitt * @id: Id for debug trace event. 278287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 279287ac01aSChristof Schmitt */ 280287ac01aSChristof Schmitt void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, 2815ffd51a5SSwen Schillig char *id, void *ref) 282287ac01aSChristof Schmitt { 283287ac01aSChristof Schmitt int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 284287ac01aSChristof Schmitt zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); 285287ac01aSChristof Schmitt } 286287ac01aSChristof Schmitt 287287ac01aSChristof Schmitt /** 288287ac01aSChristof Schmitt * zfcp_erp_port_shutdown - Shutdown port 289287ac01aSChristof Schmitt * @port: Port to shut down. 290287ac01aSChristof Schmitt * @clear: Status flags to clear. 291287ac01aSChristof Schmitt * @id: Id for debug trace event. 292287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 293287ac01aSChristof Schmitt */ 2945ffd51a5SSwen Schillig void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id, 2955ffd51a5SSwen Schillig void *ref) 296287ac01aSChristof Schmitt { 297287ac01aSChristof Schmitt int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 298287ac01aSChristof Schmitt zfcp_erp_port_reopen(port, clear | flags, id, ref); 299287ac01aSChristof Schmitt } 300287ac01aSChristof Schmitt 301287ac01aSChristof Schmitt /** 302287ac01aSChristof Schmitt * zfcp_erp_unit_shutdown - Shutdown unit 303287ac01aSChristof Schmitt * @unit: Unit to shut down. 304287ac01aSChristof Schmitt * @clear: Status flags to clear. 305287ac01aSChristof Schmitt * @id: Id for debug trace event. 306287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 307287ac01aSChristof Schmitt */ 3085ffd51a5SSwen Schillig void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id, 3095ffd51a5SSwen Schillig void *ref) 310287ac01aSChristof Schmitt { 311287ac01aSChristof Schmitt int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 312287ac01aSChristof Schmitt zfcp_erp_unit_reopen(unit, clear | flags, id, ref); 313287ac01aSChristof Schmitt } 314287ac01aSChristof Schmitt 315287ac01aSChristof Schmitt static void zfcp_erp_port_block(struct zfcp_port *port, int clear) 316287ac01aSChristof Schmitt { 3175ffd51a5SSwen Schillig zfcp_erp_modify_port_status(port, "erpblk1", NULL, 318287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_UNBLOCKED | clear, 319287ac01aSChristof Schmitt ZFCP_CLEAR); 320287ac01aSChristof Schmitt } 321287ac01aSChristof Schmitt 322287ac01aSChristof Schmitt static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, 3235ffd51a5SSwen Schillig int clear, char *id, void *ref) 324287ac01aSChristof Schmitt { 325287ac01aSChristof Schmitt zfcp_erp_port_block(port, clear); 326a2fa0aedSChristof Schmitt zfcp_scsi_schedule_rport_block(port); 327287ac01aSChristof Schmitt 328287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) 329287ac01aSChristof Schmitt return; 330287ac01aSChristof Schmitt 331287ac01aSChristof Schmitt zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, 332287ac01aSChristof Schmitt port->adapter, port, NULL, id, ref); 333287ac01aSChristof Schmitt } 334287ac01aSChristof Schmitt 335287ac01aSChristof Schmitt /** 336287ac01aSChristof Schmitt * zfcp_erp_port_forced_reopen - Forced close of port and open again 337287ac01aSChristof Schmitt * @port: Port to force close and to reopen. 338287ac01aSChristof Schmitt * @id: Id for debug trace event. 339287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 340287ac01aSChristof Schmitt */ 3415ffd51a5SSwen Schillig void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id, 3421f6f7129SMartin Peschke void *ref) 3431da177e4SLinus Torvalds { 3441da177e4SLinus Torvalds unsigned long flags; 3451da177e4SLinus Torvalds struct zfcp_adapter *adapter = port->adapter; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 3481da177e4SLinus Torvalds write_lock(&adapter->erp_lock); 349287ac01aSChristof Schmitt _zfcp_erp_port_forced_reopen(port, clear, id, ref); 350287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 351287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 352287ac01aSChristof Schmitt } 353287ac01aSChristof Schmitt 3545ffd51a5SSwen Schillig static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, 355287ac01aSChristof Schmitt void *ref) 356287ac01aSChristof Schmitt { 357287ac01aSChristof Schmitt zfcp_erp_port_block(port, clear); 358a2fa0aedSChristof Schmitt zfcp_scsi_schedule_rport_block(port); 359287ac01aSChristof Schmitt 360287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 361287ac01aSChristof Schmitt /* ensure propagation of failed status to new devices */ 3625ffd51a5SSwen Schillig zfcp_erp_port_failed(port, "erpreo1", NULL); 363287ac01aSChristof Schmitt return -EIO; 364287ac01aSChristof Schmitt } 365287ac01aSChristof Schmitt 366287ac01aSChristof Schmitt return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, 367287ac01aSChristof Schmitt port->adapter, port, NULL, id, ref); 368287ac01aSChristof Schmitt } 369287ac01aSChristof Schmitt 370287ac01aSChristof Schmitt /** 371287ac01aSChristof Schmitt * zfcp_erp_port_reopen - trigger remote port recovery 372287ac01aSChristof Schmitt * @port: port to recover 373287ac01aSChristof Schmitt * @clear_mask: flags in port status to be cleared 374287ac01aSChristof Schmitt * 375287ac01aSChristof Schmitt * Returns 0 if recovery has been triggered, < 0 if not. 376287ac01aSChristof Schmitt */ 3775ffd51a5SSwen Schillig int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref) 378287ac01aSChristof Schmitt { 379287ac01aSChristof Schmitt unsigned long flags; 380287ac01aSChristof Schmitt int retval; 381287ac01aSChristof Schmitt struct zfcp_adapter *adapter = port->adapter; 382287ac01aSChristof Schmitt 383287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 384287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 385287ac01aSChristof Schmitt retval = _zfcp_erp_port_reopen(port, clear, id, ref); 3861da177e4SLinus Torvalds write_unlock(&adapter->erp_lock); 3871da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds return retval; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 392287ac01aSChristof Schmitt static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) 3931da177e4SLinus Torvalds { 3945ffd51a5SSwen Schillig zfcp_erp_modify_unit_status(unit, "erublk1", NULL, 395287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, 396287ac01aSChristof Schmitt ZFCP_CLEAR); 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds 3995ffd51a5SSwen Schillig static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, 400287ac01aSChristof Schmitt void *ref) 401287ac01aSChristof Schmitt { 402287ac01aSChristof Schmitt struct zfcp_adapter *adapter = unit->port->adapter; 403287ac01aSChristof Schmitt 404287ac01aSChristof Schmitt zfcp_erp_unit_block(unit, clear); 405287ac01aSChristof Schmitt 406287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) 407287ac01aSChristof Schmitt return; 408287ac01aSChristof Schmitt 409287ac01aSChristof Schmitt zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, 4109467a9b3SMartin Peschke adapter, unit->port, unit, id, ref); 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds /** 4141da177e4SLinus Torvalds * zfcp_erp_unit_reopen - initiate reopen of a unit 4151da177e4SLinus Torvalds * @unit: unit to be reopened 4161da177e4SLinus Torvalds * @clear_mask: specifies flags in unit status to be cleared 4171da177e4SLinus Torvalds * Return: 0 on success, < 0 on error 4181da177e4SLinus Torvalds */ 4195ffd51a5SSwen Schillig void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, 4205ffd51a5SSwen Schillig void *ref) 4211da177e4SLinus Torvalds { 4221da177e4SLinus Torvalds unsigned long flags; 423287ac01aSChristof Schmitt struct zfcp_port *port = unit->port; 424287ac01aSChristof Schmitt struct zfcp_adapter *adapter = port->adapter; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 4271da177e4SLinus Torvalds write_lock(&adapter->erp_lock); 428287ac01aSChristof Schmitt _zfcp_erp_unit_reopen(unit, clear, id, ref); 4291da177e4SLinus Torvalds write_unlock(&adapter->erp_lock); 4301da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 433287ac01aSChristof Schmitt static int status_change_set(unsigned long mask, atomic_t *status) 4341da177e4SLinus Torvalds { 435287ac01aSChristof Schmitt return (atomic_read(status) ^ mask) & mask; 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 438287ac01aSChristof Schmitt static int status_change_clear(unsigned long mask, atomic_t *status) 439698ec016SMartin Peschke { 440287ac01aSChristof Schmitt return atomic_read(status) & mask; 441698ec016SMartin Peschke } 442698ec016SMartin Peschke 443f6c0e7a7SAndreas Herrmann static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) 4441da177e4SLinus Torvalds { 445287ac01aSChristof Schmitt if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) 4465ffd51a5SSwen Schillig zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter); 447287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 450287ac01aSChristof Schmitt static void zfcp_erp_port_unblock(struct zfcp_port *port) 4511da177e4SLinus Torvalds { 452287ac01aSChristof Schmitt if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) 4535ffd51a5SSwen Schillig zfcp_rec_dbf_event_port("erpubl1", NULL, port); 454287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds 457287ac01aSChristof Schmitt static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) 4581da177e4SLinus Torvalds { 459287ac01aSChristof Schmitt if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) 4605ffd51a5SSwen Schillig zfcp_rec_dbf_event_unit("eruubl1", NULL, unit); 461287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 464287ac01aSChristof Schmitt static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) 4651da177e4SLinus Torvalds { 466287ac01aSChristof Schmitt list_move(&erp_action->list, &erp_action->adapter->erp_running_head); 4675ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("erator1", erp_action); 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 470287ac01aSChristof Schmitt static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) 4711da177e4SLinus Torvalds { 472287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 4731da177e4SLinus Torvalds 474287ac01aSChristof Schmitt if (!act->fsf_req) 475287ac01aSChristof Schmitt return; 4761da177e4SLinus Torvalds 477fea9d6c7SVolker Sameske spin_lock(&adapter->req_list_lock); 478287ac01aSChristof Schmitt if (zfcp_reqlist_find_safe(adapter, act->fsf_req) && 479287ac01aSChristof Schmitt act->fsf_req->erp_action == act) { 480287ac01aSChristof Schmitt if (act->status & (ZFCP_STATUS_ERP_DISMISSED | 4811da177e4SLinus Torvalds ZFCP_STATUS_ERP_TIMEDOUT)) { 482287ac01aSChristof Schmitt act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; 4835ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("erscf_1", act); 4847ea633ffSMartin Petermann act->fsf_req->erp_action = NULL; 4851da177e4SLinus Torvalds } 486287ac01aSChristof Schmitt if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) 4875ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("erscf_2", act); 488287ac01aSChristof Schmitt if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | 489287ac01aSChristof Schmitt ZFCP_STATUS_FSFREQ_DISMISSED)) 490287ac01aSChristof Schmitt act->fsf_req = NULL; 491287ac01aSChristof Schmitt } else 492287ac01aSChristof Schmitt act->fsf_req = NULL; 493fea9d6c7SVolker Sameske spin_unlock(&adapter->req_list_lock); 494507e4969SMartin Peschke } 4951da177e4SLinus Torvalds 496f6c0e7a7SAndreas Herrmann /** 497287ac01aSChristof Schmitt * zfcp_erp_notify - Trigger ERP action. 498287ac01aSChristof Schmitt * @erp_action: ERP action to continue. 499287ac01aSChristof Schmitt * @set_mask: ERP action status flags to set. 5001da177e4SLinus Torvalds */ 501287ac01aSChristof Schmitt void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) 5021da177e4SLinus Torvalds { 503287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 504287ac01aSChristof Schmitt unsigned long flags; 505287ac01aSChristof Schmitt 506287ac01aSChristof Schmitt write_lock_irqsave(&adapter->erp_lock, flags); 5071da177e4SLinus Torvalds if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { 5081da177e4SLinus Torvalds erp_action->status |= set_mask; 5091da177e4SLinus Torvalds zfcp_erp_action_ready(erp_action); 510f6c0e7a7SAndreas Herrmann } 5111da177e4SLinus Torvalds write_unlock_irqrestore(&adapter->erp_lock, flags); 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 514f6c0e7a7SAndreas Herrmann /** 515287ac01aSChristof Schmitt * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request 516287ac01aSChristof Schmitt * @data: ERP action (from timer data) 5171da177e4SLinus Torvalds */ 518287ac01aSChristof Schmitt void zfcp_erp_timeout_handler(unsigned long data) 5191da177e4SLinus Torvalds { 520287ac01aSChristof Schmitt struct zfcp_erp_action *act = (struct zfcp_erp_action *) data; 521287ac01aSChristof Schmitt zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT); 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds 524287ac01aSChristof Schmitt static void zfcp_erp_memwait_handler(unsigned long data) 5251da177e4SLinus Torvalds { 526287ac01aSChristof Schmitt zfcp_erp_notify((struct zfcp_erp_action *)data, 0); 5271da177e4SLinus Torvalds } 5281da177e4SLinus Torvalds 529287ac01aSChristof Schmitt static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) 5301da177e4SLinus Torvalds { 5311da177e4SLinus Torvalds init_timer(&erp_action->timer); 5321da177e4SLinus Torvalds erp_action->timer.function = zfcp_erp_memwait_handler; 5331da177e4SLinus Torvalds erp_action->timer.data = (unsigned long) erp_action; 534287ac01aSChristof Schmitt erp_action->timer.expires = jiffies + HZ; 5351da177e4SLinus Torvalds add_timer(&erp_action->timer); 536287ac01aSChristof Schmitt } 537287ac01aSChristof Schmitt 538287ac01aSChristof Schmitt static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, 5395ffd51a5SSwen Schillig int clear, char *id, void *ref) 540287ac01aSChristof Schmitt { 541287ac01aSChristof Schmitt struct zfcp_port *port; 542287ac01aSChristof Schmitt 543287ac01aSChristof Schmitt list_for_each_entry(port, &adapter->port_list_head, list) 544287ac01aSChristof Schmitt _zfcp_erp_port_reopen(port, clear, id, ref); 545287ac01aSChristof Schmitt } 546287ac01aSChristof Schmitt 5475ffd51a5SSwen Schillig static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, 5485ffd51a5SSwen Schillig char *id, void *ref) 549287ac01aSChristof Schmitt { 550287ac01aSChristof Schmitt struct zfcp_unit *unit; 551287ac01aSChristof Schmitt 552287ac01aSChristof Schmitt list_for_each_entry(unit, &port->unit_list_head, list) 553287ac01aSChristof Schmitt _zfcp_erp_unit_reopen(unit, clear, id, ref); 554287ac01aSChristof Schmitt } 555287ac01aSChristof Schmitt 55685600f7fSChristof Schmitt static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) 557287ac01aSChristof Schmitt { 558287ac01aSChristof Schmitt switch (act->action) { 559287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 56085600f7fSChristof Schmitt _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL); 561287ac01aSChristof Schmitt break; 562287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 56385600f7fSChristof Schmitt _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL); 564287ac01aSChristof Schmitt break; 565287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 56685600f7fSChristof Schmitt _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); 567287ac01aSChristof Schmitt break; 568287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 56985600f7fSChristof Schmitt _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL); 57085600f7fSChristof Schmitt break; 57185600f7fSChristof Schmitt } 57285600f7fSChristof Schmitt } 57385600f7fSChristof Schmitt 57485600f7fSChristof Schmitt static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) 57585600f7fSChristof Schmitt { 57685600f7fSChristof Schmitt switch (act->action) { 57785600f7fSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 57885600f7fSChristof Schmitt _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL); 57985600f7fSChristof Schmitt break; 58085600f7fSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 58185600f7fSChristof Schmitt _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL); 58285600f7fSChristof Schmitt break; 58385600f7fSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 58485600f7fSChristof Schmitt _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL); 585287ac01aSChristof Schmitt break; 586287ac01aSChristof Schmitt } 587287ac01aSChristof Schmitt } 588287ac01aSChristof Schmitt 589287ac01aSChristof Schmitt static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) 590287ac01aSChristof Schmitt { 591287ac01aSChristof Schmitt unsigned long flags; 592287ac01aSChristof Schmitt 593287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 594287ac01aSChristof Schmitt read_lock(&adapter->erp_lock); 595287ac01aSChristof Schmitt if (list_empty(&adapter->erp_ready_head) && 596287ac01aSChristof Schmitt list_empty(&adapter->erp_running_head)) { 597287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, 598287ac01aSChristof Schmitt &adapter->status); 599287ac01aSChristof Schmitt wake_up(&adapter->erp_done_wqh); 600287ac01aSChristof Schmitt } 601287ac01aSChristof Schmitt read_unlock(&adapter->erp_lock); 602287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 603287ac01aSChristof Schmitt } 604287ac01aSChristof Schmitt 605287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) 606287ac01aSChristof Schmitt { 607287ac01aSChristof Schmitt if (zfcp_qdio_open(act->adapter)) 608287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 609287ac01aSChristof Schmitt init_waitqueue_head(&act->adapter->request_wq); 610287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); 611287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 612287ac01aSChristof Schmitt } 613287ac01aSChristof Schmitt 614287ac01aSChristof Schmitt static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) 615287ac01aSChristof Schmitt { 616287ac01aSChristof Schmitt struct zfcp_port *port; 617287ac01aSChristof Schmitt port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, 618287ac01aSChristof Schmitt adapter->peer_d_id); 619287ac01aSChristof Schmitt if (IS_ERR(port)) /* error or port already attached */ 620287ac01aSChristof Schmitt return; 6215ffd51a5SSwen Schillig _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL); 622287ac01aSChristof Schmitt } 623287ac01aSChristof Schmitt 624287ac01aSChristof Schmitt static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) 625287ac01aSChristof Schmitt { 626287ac01aSChristof Schmitt int retries; 627287ac01aSChristof Schmitt int sleep = 1; 628287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 629287ac01aSChristof Schmitt 630287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); 631287ac01aSChristof Schmitt 632287ac01aSChristof Schmitt for (retries = 7; retries; retries--) { 633287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, 634287ac01aSChristof Schmitt &adapter->status); 635287ac01aSChristof Schmitt write_lock_irq(&adapter->erp_lock); 636287ac01aSChristof Schmitt zfcp_erp_action_to_running(erp_action); 637287ac01aSChristof Schmitt write_unlock_irq(&adapter->erp_lock); 638287ac01aSChristof Schmitt if (zfcp_fsf_exchange_config_data(erp_action)) { 639287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, 640287ac01aSChristof Schmitt &adapter->status); 641287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 642287ac01aSChristof Schmitt } 643287ac01aSChristof Schmitt 6445ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erasfx1", adapter); 645287ac01aSChristof Schmitt down(&adapter->erp_ready_sem); 6465ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erasfx2", adapter); 647287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) 648287ac01aSChristof Schmitt break; 649287ac01aSChristof Schmitt 650287ac01aSChristof Schmitt if (!(atomic_read(&adapter->status) & 651287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_HOST_CON_INIT)) 652287ac01aSChristof Schmitt break; 653287ac01aSChristof Schmitt 654287ac01aSChristof Schmitt ssleep(sleep); 655287ac01aSChristof Schmitt sleep *= 2; 656287ac01aSChristof Schmitt } 657287ac01aSChristof Schmitt 658287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, 659287ac01aSChristof Schmitt &adapter->status); 660287ac01aSChristof Schmitt 661287ac01aSChristof Schmitt if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK)) 662287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 663287ac01aSChristof Schmitt 664287ac01aSChristof Schmitt if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) 665287ac01aSChristof Schmitt zfcp_erp_enqueue_ptp_port(adapter); 666287ac01aSChristof Schmitt 667287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 668287ac01aSChristof Schmitt } 669287ac01aSChristof Schmitt 670287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) 671287ac01aSChristof Schmitt { 672287ac01aSChristof Schmitt int ret; 673287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 674287ac01aSChristof Schmitt 675287ac01aSChristof Schmitt write_lock_irq(&adapter->erp_lock); 676287ac01aSChristof Schmitt zfcp_erp_action_to_running(act); 677287ac01aSChristof Schmitt write_unlock_irq(&adapter->erp_lock); 678287ac01aSChristof Schmitt 679287ac01aSChristof Schmitt ret = zfcp_fsf_exchange_port_data(act); 680287ac01aSChristof Schmitt if (ret == -EOPNOTSUPP) 681287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 682287ac01aSChristof Schmitt if (ret) 683287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 684287ac01aSChristof Schmitt 6855ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erasox1", adapter); 686287ac01aSChristof Schmitt down(&adapter->erp_ready_sem); 6875ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erasox2", adapter); 688287ac01aSChristof Schmitt if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) 689287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 690287ac01aSChristof Schmitt 691287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 692287ac01aSChristof Schmitt } 693287ac01aSChristof Schmitt 694287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act) 695287ac01aSChristof Schmitt { 696287ac01aSChristof Schmitt if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED) 697287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 698287ac01aSChristof Schmitt 699287ac01aSChristof Schmitt if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) 700287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 701287ac01aSChristof Schmitt 702287ac01aSChristof Schmitt atomic_set(&act->adapter->stat_miss, 16); 703287ac01aSChristof Schmitt if (zfcp_status_read_refill(act->adapter)) 704287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 705287ac01aSChristof Schmitt 706287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 707287ac01aSChristof Schmitt } 708287ac01aSChristof Schmitt 709cf13c082SSwen Schillig static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) 710287ac01aSChristof Schmitt { 711287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 712287ac01aSChristof Schmitt 713287ac01aSChristof Schmitt /* close queues to ensure that buffers are not accessed by adapter */ 714287ac01aSChristof Schmitt zfcp_qdio_close(adapter); 715287ac01aSChristof Schmitt zfcp_fsf_req_dismiss_all(adapter); 716287ac01aSChristof Schmitt adapter->fsf_req_seq_no = 0; 7179d544f2bSSven Schuetz zfcp_fc_wka_port_force_offline(&adapter->gs->ds); 718287ac01aSChristof Schmitt /* all ports and units are closed */ 7195ffd51a5SSwen Schillig zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, 720287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); 721cf13c082SSwen Schillig 722cf13c082SSwen Schillig atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | 723cf13c082SSwen Schillig ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); 724cf13c082SSwen Schillig } 725cf13c082SSwen Schillig 726cf13c082SSwen Schillig static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act) 727cf13c082SSwen Schillig { 728cf13c082SSwen Schillig struct zfcp_adapter *adapter = act->adapter; 729cf13c082SSwen Schillig 730cf13c082SSwen Schillig if (zfcp_erp_adapter_strategy_open_qdio(act)) { 731287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | 73244cc76f2SSwen Schillig ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, 733cf13c082SSwen Schillig &adapter->status); 734cf13c082SSwen Schillig return ZFCP_ERP_FAILED; 735cf13c082SSwen Schillig } 736cf13c082SSwen Schillig 737cf13c082SSwen Schillig if (zfcp_erp_adapter_strategy_open_fsf(act)) { 738cf13c082SSwen Schillig zfcp_erp_adapter_strategy_close(act); 739cf13c082SSwen Schillig return ZFCP_ERP_FAILED; 740cf13c082SSwen Schillig } 741cf13c082SSwen Schillig 742cf13c082SSwen Schillig atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status); 743cf13c082SSwen Schillig 744cf13c082SSwen Schillig return ZFCP_ERP_SUCCEEDED; 745287ac01aSChristof Schmitt } 746287ac01aSChristof Schmitt 747287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act) 748287ac01aSChristof Schmitt { 749cf13c082SSwen Schillig struct zfcp_adapter *adapter = act->adapter; 750287ac01aSChristof Schmitt 751cf13c082SSwen Schillig if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) { 752cf13c082SSwen Schillig zfcp_erp_adapter_strategy_close(act); 753287ac01aSChristof Schmitt if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 754287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 755cf13c082SSwen Schillig } 756287ac01aSChristof Schmitt 757cf13c082SSwen Schillig if (zfcp_erp_adapter_strategy_open(act)) { 758287ac01aSChristof Schmitt ssleep(8); 759cf13c082SSwen Schillig return ZFCP_ERP_FAILED; 760cf13c082SSwen Schillig } 7611da177e4SLinus Torvalds 762cf13c082SSwen Schillig return ZFCP_ERP_SUCCEEDED; 7631da177e4SLinus Torvalds } 7641da177e4SLinus Torvalds 765287ac01aSChristof Schmitt static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act) 7661da177e4SLinus Torvalds { 767287ac01aSChristof Schmitt int retval; 768287ac01aSChristof Schmitt 769287ac01aSChristof Schmitt retval = zfcp_fsf_close_physical_port(act); 770287ac01aSChristof Schmitt if (retval == -ENOMEM) 771287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 772287ac01aSChristof Schmitt act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; 773287ac01aSChristof Schmitt if (retval) 774287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 775287ac01aSChristof Schmitt 776287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 7771da177e4SLinus Torvalds } 7781da177e4SLinus Torvalds 779287ac01aSChristof Schmitt static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) 7801da177e4SLinus Torvalds { 781a5b11ddaSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status); 782287ac01aSChristof Schmitt } 7831da177e4SLinus Torvalds 784287ac01aSChristof Schmitt static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) 785287ac01aSChristof Schmitt { 786287ac01aSChristof Schmitt struct zfcp_port *port = erp_action->port; 787287ac01aSChristof Schmitt int status = atomic_read(&port->status); 788287ac01aSChristof Schmitt 789287ac01aSChristof Schmitt switch (erp_action->step) { 790287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 791287ac01aSChristof Schmitt zfcp_erp_port_strategy_clearstati(port); 792287ac01aSChristof Schmitt if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) && 793287ac01aSChristof Schmitt (status & ZFCP_STATUS_COMMON_OPEN)) 794287ac01aSChristof Schmitt return zfcp_erp_port_forced_strategy_close(erp_action); 7951da177e4SLinus Torvalds else 796287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 797287ac01aSChristof Schmitt 798287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: 799ddb3e0c1SChristof Schmitt if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN)) 800287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 801287ac01aSChristof Schmitt } 802287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 8031da177e4SLinus Torvalds } 8041da177e4SLinus Torvalds 805287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) 8061da177e4SLinus Torvalds { 807287ac01aSChristof Schmitt int retval; 8081da177e4SLinus Torvalds 809287ac01aSChristof Schmitt retval = zfcp_fsf_close_port(erp_action); 810287ac01aSChristof Schmitt if (retval == -ENOMEM) 811287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 812287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; 813287ac01aSChristof Schmitt if (retval) 814287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 815287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 8161da177e4SLinus Torvalds } 8171da177e4SLinus Torvalds 818287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) 819287ac01aSChristof Schmitt { 820287ac01aSChristof Schmitt int retval; 821287ac01aSChristof Schmitt 822287ac01aSChristof Schmitt retval = zfcp_fsf_open_port(erp_action); 823287ac01aSChristof Schmitt if (retval == -ENOMEM) 824287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 825287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; 826287ac01aSChristof Schmitt if (retval) 827287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 828287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 829287ac01aSChristof Schmitt } 830287ac01aSChristof Schmitt 831287ac01aSChristof Schmitt static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) 832287ac01aSChristof Schmitt { 833287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 834287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 835287ac01aSChristof Schmitt 836287ac01aSChristof Schmitt if (port->wwpn != adapter->peer_wwpn) { 8375ffd51a5SSwen Schillig zfcp_erp_port_failed(port, "eroptp1", NULL); 838287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 839287ac01aSChristof Schmitt } 840287ac01aSChristof Schmitt port->d_id = adapter->peer_d_id; 841287ac01aSChristof Schmitt return zfcp_erp_port_strategy_open_port(act); 842287ac01aSChristof Schmitt } 843287ac01aSChristof Schmitt 8445ab944f9SSwen Schillig void zfcp_erp_port_strategy_open_lookup(struct work_struct *work) 8455ab944f9SSwen Schillig { 8465ab944f9SSwen Schillig int retval; 8475ab944f9SSwen Schillig struct zfcp_port *port = container_of(work, struct zfcp_port, 8485ab944f9SSwen Schillig gid_pn_work); 8495ab944f9SSwen Schillig 8505ab944f9SSwen Schillig retval = zfcp_fc_ns_gid_pn(&port->erp_action); 8515ab944f9SSwen Schillig if (retval == -ENOMEM) 852688a1820SChristof Schmitt zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM); 8535ab944f9SSwen Schillig port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; 8545ab944f9SSwen Schillig if (retval) 855688a1820SChristof Schmitt zfcp_erp_notify(&port->erp_action, 0); 856947a9acaSSwen Schillig zfcp_port_put(port); 8575ab944f9SSwen Schillig } 8585ab944f9SSwen Schillig 859287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) 860287ac01aSChristof Schmitt { 861287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 862287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 863287ac01aSChristof Schmitt int p_status = atomic_read(&port->status); 864287ac01aSChristof Schmitt 865287ac01aSChristof Schmitt switch (act->step) { 866287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 867287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: 868287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PORT_CLOSING: 869287ac01aSChristof Schmitt if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) 870287ac01aSChristof Schmitt return zfcp_erp_open_ptp_port(act); 871b98478d7SChristof Schmitt if (!port->d_id) { 872947a9acaSSwen Schillig zfcp_port_get(port); 873947a9acaSSwen Schillig if (!queue_work(zfcp_data.work_queue, 874947a9acaSSwen Schillig &port->gid_pn_work)) 875947a9acaSSwen Schillig zfcp_port_put(port); 876287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 877287ac01aSChristof Schmitt } 878dceab655SChristof Schmitt /* fall through */ 879287ac01aSChristof Schmitt case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: 880a5b11ddaSChristof Schmitt if (!port->d_id) 881287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 882287ac01aSChristof Schmitt return zfcp_erp_port_strategy_open_port(act); 883287ac01aSChristof Schmitt 884287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PORT_OPENING: 885287ac01aSChristof Schmitt /* D_ID might have changed during open */ 8865ab944f9SSwen Schillig if (p_status & ZFCP_STATUS_COMMON_OPEN) { 887b98478d7SChristof Schmitt if (port->d_id) 888287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 8895ab944f9SSwen Schillig else { 8905ab944f9SSwen Schillig act->step = ZFCP_ERP_STEP_PORT_CLOSING; 8915ab944f9SSwen Schillig return ZFCP_ERP_CONTINUES; 8925ab944f9SSwen Schillig } 893287ac01aSChristof Schmitt } 894ea460a81SSwen Schillig if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { 895ea460a81SSwen Schillig port->d_id = 0; 896ea460a81SSwen Schillig _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL); 897ea460a81SSwen Schillig return ZFCP_ERP_EXIT; 898ea460a81SSwen Schillig } 899ea460a81SSwen Schillig /* fall through otherwise */ 900287ac01aSChristof Schmitt } 9015ab944f9SSwen Schillig return ZFCP_ERP_FAILED; 902287ac01aSChristof Schmitt } 903287ac01aSChristof Schmitt 904287ac01aSChristof Schmitt static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) 905287ac01aSChristof Schmitt { 906287ac01aSChristof Schmitt struct zfcp_port *port = erp_action->port; 907287ac01aSChristof Schmitt 9085ab944f9SSwen Schillig if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) 9095ab944f9SSwen Schillig goto close_init_done; 9105ab944f9SSwen Schillig 911287ac01aSChristof Schmitt switch (erp_action->step) { 912287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 913287ac01aSChristof Schmitt zfcp_erp_port_strategy_clearstati(port); 914287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) 915287ac01aSChristof Schmitt return zfcp_erp_port_strategy_close(erp_action); 916287ac01aSChristof Schmitt break; 917287ac01aSChristof Schmitt 918287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PORT_CLOSING: 919287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) 920287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 921287ac01aSChristof Schmitt break; 922287ac01aSChristof Schmitt } 9235ab944f9SSwen Schillig 9245ab944f9SSwen Schillig close_init_done: 925287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 926287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 927287ac01aSChristof Schmitt 9285ab944f9SSwen Schillig return zfcp_erp_port_strategy_open_common(erp_action); 929287ac01aSChristof Schmitt } 930287ac01aSChristof Schmitt 931287ac01aSChristof Schmitt static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) 932287ac01aSChristof Schmitt { 93344cc76f2SSwen Schillig atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | 934287ac01aSChristof Schmitt ZFCP_STATUS_UNIT_SHARED | 935287ac01aSChristof Schmitt ZFCP_STATUS_UNIT_READONLY, 936287ac01aSChristof Schmitt &unit->status); 937287ac01aSChristof Schmitt } 938287ac01aSChristof Schmitt 939287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) 940287ac01aSChristof Schmitt { 941287ac01aSChristof Schmitt int retval = zfcp_fsf_close_unit(erp_action); 942287ac01aSChristof Schmitt if (retval == -ENOMEM) 943287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 944287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; 945287ac01aSChristof Schmitt if (retval) 946287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 947287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 948287ac01aSChristof Schmitt } 949287ac01aSChristof Schmitt 950287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) 951287ac01aSChristof Schmitt { 952287ac01aSChristof Schmitt int retval = zfcp_fsf_open_unit(erp_action); 953287ac01aSChristof Schmitt if (retval == -ENOMEM) 954287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 955287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; 956287ac01aSChristof Schmitt if (retval) 957287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 958287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 959287ac01aSChristof Schmitt } 960287ac01aSChristof Schmitt 961287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) 962287ac01aSChristof Schmitt { 963287ac01aSChristof Schmitt struct zfcp_unit *unit = erp_action->unit; 964287ac01aSChristof Schmitt 965287ac01aSChristof Schmitt switch (erp_action->step) { 966287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 967287ac01aSChristof Schmitt zfcp_erp_unit_strategy_clearstati(unit); 968287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) 969287ac01aSChristof Schmitt return zfcp_erp_unit_strategy_close(erp_action); 970287ac01aSChristof Schmitt /* already closed, fall through */ 971287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNIT_CLOSING: 972287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) 973287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 974287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 975287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 976287ac01aSChristof Schmitt return zfcp_erp_unit_strategy_open(erp_action); 977287ac01aSChristof Schmitt 978287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNIT_OPENING: 979287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) 980287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 981287ac01aSChristof Schmitt } 982287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 983287ac01aSChristof Schmitt } 984287ac01aSChristof Schmitt 985287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) 986287ac01aSChristof Schmitt { 987287ac01aSChristof Schmitt switch (result) { 988287ac01aSChristof Schmitt case ZFCP_ERP_SUCCEEDED : 989287ac01aSChristof Schmitt atomic_set(&unit->erp_counter, 0); 990287ac01aSChristof Schmitt zfcp_erp_unit_unblock(unit); 991287ac01aSChristof Schmitt break; 992287ac01aSChristof Schmitt case ZFCP_ERP_FAILED : 993287ac01aSChristof Schmitt atomic_inc(&unit->erp_counter); 994ff3b24faSChristof Schmitt if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) { 995ff3b24faSChristof Schmitt dev_err(&unit->port->adapter->ccw_device->dev, 996ff3b24faSChristof Schmitt "ERP failed for unit 0x%016Lx on " 997ff3b24faSChristof Schmitt "port 0x%016Lx\n", 9987ba58c9cSSwen Schillig (unsigned long long)unit->fcp_lun, 9997ba58c9cSSwen Schillig (unsigned long long)unit->port->wwpn); 10005ffd51a5SSwen Schillig zfcp_erp_unit_failed(unit, "erusck1", NULL); 1001ff3b24faSChristof Schmitt } 1002287ac01aSChristof Schmitt break; 1003287ac01aSChristof Schmitt } 1004287ac01aSChristof Schmitt 1005287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 1006287ac01aSChristof Schmitt zfcp_erp_unit_block(unit, 0); 1007287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1008287ac01aSChristof Schmitt } 1009287ac01aSChristof Schmitt return result; 1010287ac01aSChristof Schmitt } 1011287ac01aSChristof Schmitt 1012287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) 1013287ac01aSChristof Schmitt { 1014287ac01aSChristof Schmitt switch (result) { 1015287ac01aSChristof Schmitt case ZFCP_ERP_SUCCEEDED : 1016287ac01aSChristof Schmitt atomic_set(&port->erp_counter, 0); 1017287ac01aSChristof Schmitt zfcp_erp_port_unblock(port); 1018287ac01aSChristof Schmitt break; 1019287ac01aSChristof Schmitt 1020287ac01aSChristof Schmitt case ZFCP_ERP_FAILED : 1021287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) { 1022287ac01aSChristof Schmitt zfcp_erp_port_block(port, 0); 1023287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1024287ac01aSChristof Schmitt } 1025287ac01aSChristof Schmitt atomic_inc(&port->erp_counter); 1026ff3b24faSChristof Schmitt if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) { 1027ff3b24faSChristof Schmitt dev_err(&port->adapter->ccw_device->dev, 1028ff3b24faSChristof Schmitt "ERP failed for remote port 0x%016Lx\n", 10297ba58c9cSSwen Schillig (unsigned long long)port->wwpn); 10305ffd51a5SSwen Schillig zfcp_erp_port_failed(port, "erpsck1", NULL); 1031ff3b24faSChristof Schmitt } 1032287ac01aSChristof Schmitt break; 1033287ac01aSChristof Schmitt } 1034287ac01aSChristof Schmitt 1035287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 1036287ac01aSChristof Schmitt zfcp_erp_port_block(port, 0); 1037287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1038287ac01aSChristof Schmitt } 1039287ac01aSChristof Schmitt return result; 1040287ac01aSChristof Schmitt } 1041287ac01aSChristof Schmitt 1042287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, 1043287ac01aSChristof Schmitt int result) 1044287ac01aSChristof Schmitt { 1045287ac01aSChristof Schmitt switch (result) { 1046287ac01aSChristof Schmitt case ZFCP_ERP_SUCCEEDED : 1047287ac01aSChristof Schmitt atomic_set(&adapter->erp_counter, 0); 1048287ac01aSChristof Schmitt zfcp_erp_adapter_unblock(adapter); 1049287ac01aSChristof Schmitt break; 1050287ac01aSChristof Schmitt 1051287ac01aSChristof Schmitt case ZFCP_ERP_FAILED : 1052287ac01aSChristof Schmitt atomic_inc(&adapter->erp_counter); 1053ff3b24faSChristof Schmitt if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) { 1054ff3b24faSChristof Schmitt dev_err(&adapter->ccw_device->dev, 1055ff3b24faSChristof Schmitt "ERP cannot recover an error " 1056ff3b24faSChristof Schmitt "on the FCP device\n"); 10575ffd51a5SSwen Schillig zfcp_erp_adapter_failed(adapter, "erasck1", NULL); 1058ff3b24faSChristof Schmitt } 1059287ac01aSChristof Schmitt break; 1060287ac01aSChristof Schmitt } 1061287ac01aSChristof Schmitt 1062287ac01aSChristof Schmitt if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 1063287ac01aSChristof Schmitt zfcp_erp_adapter_block(adapter, 0); 1064287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1065287ac01aSChristof Schmitt } 1066287ac01aSChristof Schmitt return result; 1067287ac01aSChristof Schmitt } 1068287ac01aSChristof Schmitt 1069287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, 1070287ac01aSChristof Schmitt int result) 10711da177e4SLinus Torvalds { 10721da177e4SLinus Torvalds struct zfcp_adapter *adapter = erp_action->adapter; 10731da177e4SLinus Torvalds struct zfcp_port *port = erp_action->port; 10741da177e4SLinus Torvalds struct zfcp_unit *unit = erp_action->unit; 10751da177e4SLinus Torvalds 10761da177e4SLinus Torvalds switch (erp_action->action) { 10771da177e4SLinus Torvalds 10781da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_UNIT: 10791da177e4SLinus Torvalds result = zfcp_erp_strategy_check_unit(unit, result); 10801da177e4SLinus Torvalds break; 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 10831da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT: 10841da177e4SLinus Torvalds result = zfcp_erp_strategy_check_port(port, result); 10851da177e4SLinus Torvalds break; 10861da177e4SLinus Torvalds 10871da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 10881da177e4SLinus Torvalds result = zfcp_erp_strategy_check_adapter(adapter, result); 10891da177e4SLinus Torvalds break; 10901da177e4SLinus Torvalds } 10911da177e4SLinus Torvalds return result; 10921da177e4SLinus Torvalds } 10931da177e4SLinus Torvalds 1094287ac01aSChristof Schmitt static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status) 10951da177e4SLinus Torvalds { 1096287ac01aSChristof Schmitt int status = atomic_read(target_status); 10971da177e4SLinus Torvalds 1098287ac01aSChristof Schmitt if ((status & ZFCP_STATUS_COMMON_RUNNING) && 1099287ac01aSChristof Schmitt (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) 1100287ac01aSChristof Schmitt return 1; /* take it online */ 1101287ac01aSChristof Schmitt 1102287ac01aSChristof Schmitt if (!(status & ZFCP_STATUS_COMMON_RUNNING) && 1103287ac01aSChristof Schmitt !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) 1104287ac01aSChristof Schmitt return 1; /* take it offline */ 1105287ac01aSChristof Schmitt 1106287ac01aSChristof Schmitt return 0; 1107287ac01aSChristof Schmitt } 1108287ac01aSChristof Schmitt 1109287ac01aSChristof Schmitt static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) 1110287ac01aSChristof Schmitt { 1111287ac01aSChristof Schmitt int action = act->action; 1112287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 1113287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 1114287ac01aSChristof Schmitt struct zfcp_unit *unit = act->unit; 1115287ac01aSChristof Schmitt u32 erp_status = act->status; 1116287ac01aSChristof Schmitt 1117287ac01aSChristof Schmitt switch (action) { 11181da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1119287ac01aSChristof Schmitt if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { 1120287ac01aSChristof Schmitt _zfcp_erp_adapter_reopen(adapter, 11219467a9b3SMartin Peschke ZFCP_STATUS_COMMON_ERP_FAILED, 11225ffd51a5SSwen Schillig "ersscg1", NULL); 1123287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 11241da177e4SLinus Torvalds } 11251da177e4SLinus Torvalds break; 11261da177e4SLinus Torvalds 11271da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 11281da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT: 1129287ac01aSChristof Schmitt if (zfcp_erp_strat_change_det(&port->status, erp_status)) { 1130287ac01aSChristof Schmitt _zfcp_erp_port_reopen(port, 11319467a9b3SMartin Peschke ZFCP_STATUS_COMMON_ERP_FAILED, 11325ffd51a5SSwen Schillig "ersscg2", NULL); 1133287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 11341da177e4SLinus Torvalds } 11351da177e4SLinus Torvalds break; 11361da177e4SLinus Torvalds 11371da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_UNIT: 1138287ac01aSChristof Schmitt if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { 1139287ac01aSChristof Schmitt _zfcp_erp_unit_reopen(unit, 11409467a9b3SMartin Peschke ZFCP_STATUS_COMMON_ERP_FAILED, 11415ffd51a5SSwen Schillig "ersscg3", NULL); 1142287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 11431da177e4SLinus Torvalds } 11441da177e4SLinus Torvalds break; 11451da177e4SLinus Torvalds } 1146287ac01aSChristof Schmitt return ret; 11471da177e4SLinus Torvalds } 11481da177e4SLinus Torvalds 1149287ac01aSChristof Schmitt static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) 11501da177e4SLinus Torvalds { 1151287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 1152287ac01aSChristof Schmitt 1153287ac01aSChristof Schmitt adapter->erp_total_count--; 1154287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { 1155287ac01aSChristof Schmitt adapter->erp_low_mem_count--; 1156287ac01aSChristof Schmitt erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; 11571da177e4SLinus Torvalds } 11581da177e4SLinus Torvalds 1159287ac01aSChristof Schmitt list_del(&erp_action->list); 11605ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("eractd1", erp_action); 11611da177e4SLinus Torvalds 1162287ac01aSChristof Schmitt switch (erp_action->action) { 1163287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 1164287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, 1165287ac01aSChristof Schmitt &erp_action->unit->status); 11661da177e4SLinus Torvalds break; 1167287ac01aSChristof Schmitt 1168287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1169287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 1170287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, 1171287ac01aSChristof Schmitt &erp_action->port->status); 11721da177e4SLinus Torvalds break; 1173287ac01aSChristof Schmitt 1174287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1175287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, 1176287ac01aSChristof Schmitt &erp_action->adapter->status); 11771da177e4SLinus Torvalds break; 11781da177e4SLinus Torvalds } 11791da177e4SLinus Torvalds } 11801da177e4SLinus Torvalds 1181287ac01aSChristof Schmitt static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) 1182287ac01aSChristof Schmitt { 1183287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 1184287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 1185287ac01aSChristof Schmitt struct zfcp_unit *unit = act->unit; 1186287ac01aSChristof Schmitt 1187287ac01aSChristof Schmitt switch (act->action) { 1188287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 1189a2fa0aedSChristof Schmitt if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { 119092d5193bSSwen Schillig zfcp_unit_get(unit); 119192d5193bSSwen Schillig if (scsi_queue_work(unit->port->adapter->scsi_host, 119292d5193bSSwen Schillig &unit->scsi_work) <= 0) 119392d5193bSSwen Schillig zfcp_unit_put(unit); 1194287ac01aSChristof Schmitt } 1195287ac01aSChristof Schmitt zfcp_unit_put(unit); 1196287ac01aSChristof Schmitt break; 1197287ac01aSChristof Schmitt 1198287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1199287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 1200a2fa0aedSChristof Schmitt if (result == ZFCP_ERP_SUCCEEDED) 1201a2fa0aedSChristof Schmitt zfcp_scsi_schedule_rport_register(port); 12021da177e4SLinus Torvalds zfcp_port_put(port); 12031da177e4SLinus Torvalds break; 1204287ac01aSChristof Schmitt 12051da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1206a2fa0aedSChristof Schmitt if (result == ZFCP_ERP_SUCCEEDED) { 1207bd43a42bSChristof Schmitt register_service_level(&adapter->service_level); 1208fca55b6fSSwen Schillig schedule_work(&adapter->scan_work); 1209a2fa0aedSChristof Schmitt } else 1210a2fa0aedSChristof Schmitt unregister_service_level(&adapter->service_level); 12111da177e4SLinus Torvalds zfcp_adapter_put(adapter); 12121da177e4SLinus Torvalds break; 12131da177e4SLinus Torvalds } 12141da177e4SLinus Torvalds } 12151da177e4SLinus Torvalds 1216287ac01aSChristof Schmitt static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) 1217287ac01aSChristof Schmitt { 1218287ac01aSChristof Schmitt switch (erp_action->action) { 1219287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1220287ac01aSChristof Schmitt return zfcp_erp_adapter_strategy(erp_action); 1221287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1222287ac01aSChristof Schmitt return zfcp_erp_port_forced_strategy(erp_action); 1223287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 1224287ac01aSChristof Schmitt return zfcp_erp_port_strategy(erp_action); 1225287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 1226287ac01aSChristof Schmitt return zfcp_erp_unit_strategy(erp_action); 1227287ac01aSChristof Schmitt } 1228287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 1229287ac01aSChristof Schmitt } 12301da177e4SLinus Torvalds 1231287ac01aSChristof Schmitt static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) 1232287ac01aSChristof Schmitt { 1233287ac01aSChristof Schmitt int retval; 1234287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 1235287ac01aSChristof Schmitt unsigned long flags; 1236287ac01aSChristof Schmitt 1237287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 1238287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 1239287ac01aSChristof Schmitt 1240287ac01aSChristof Schmitt zfcp_erp_strategy_check_fsfreq(erp_action); 1241287ac01aSChristof Schmitt 1242287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { 1243287ac01aSChristof Schmitt zfcp_erp_action_dequeue(erp_action); 1244287ac01aSChristof Schmitt retval = ZFCP_ERP_DISMISSED; 1245287ac01aSChristof Schmitt goto unlock; 1246287ac01aSChristof Schmitt } 1247287ac01aSChristof Schmitt 1248287ac01aSChristof Schmitt zfcp_erp_action_to_running(erp_action); 1249287ac01aSChristof Schmitt 1250287ac01aSChristof Schmitt /* no lock to allow for blocking operations */ 1251287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 1252287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 1253287ac01aSChristof Schmitt retval = zfcp_erp_strategy_do_action(erp_action); 1254287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 1255287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 1256287ac01aSChristof Schmitt 1257287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) 1258287ac01aSChristof Schmitt retval = ZFCP_ERP_CONTINUES; 1259287ac01aSChristof Schmitt 1260287ac01aSChristof Schmitt switch (retval) { 1261287ac01aSChristof Schmitt case ZFCP_ERP_NOMEM: 1262287ac01aSChristof Schmitt if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { 1263287ac01aSChristof Schmitt ++adapter->erp_low_mem_count; 1264287ac01aSChristof Schmitt erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; 1265287ac01aSChristof Schmitt } 1266287ac01aSChristof Schmitt if (adapter->erp_total_count == adapter->erp_low_mem_count) 12675ffd51a5SSwen Schillig _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL); 1268287ac01aSChristof Schmitt else { 1269287ac01aSChristof Schmitt zfcp_erp_strategy_memwait(erp_action); 1270287ac01aSChristof Schmitt retval = ZFCP_ERP_CONTINUES; 1271287ac01aSChristof Schmitt } 1272287ac01aSChristof Schmitt goto unlock; 1273287ac01aSChristof Schmitt 1274287ac01aSChristof Schmitt case ZFCP_ERP_CONTINUES: 1275287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { 1276287ac01aSChristof Schmitt --adapter->erp_low_mem_count; 1277287ac01aSChristof Schmitt erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; 1278287ac01aSChristof Schmitt } 1279287ac01aSChristof Schmitt goto unlock; 1280287ac01aSChristof Schmitt } 1281287ac01aSChristof Schmitt 1282287ac01aSChristof Schmitt retval = zfcp_erp_strategy_check_target(erp_action, retval); 1283287ac01aSChristof Schmitt zfcp_erp_action_dequeue(erp_action); 1284287ac01aSChristof Schmitt retval = zfcp_erp_strategy_statechange(erp_action, retval); 1285287ac01aSChristof Schmitt if (retval == ZFCP_ERP_EXIT) 1286287ac01aSChristof Schmitt goto unlock; 128785600f7fSChristof Schmitt if (retval == ZFCP_ERP_SUCCEEDED) 128885600f7fSChristof Schmitt zfcp_erp_strategy_followup_success(erp_action); 128985600f7fSChristof Schmitt if (retval == ZFCP_ERP_FAILED) 129085600f7fSChristof Schmitt zfcp_erp_strategy_followup_failed(erp_action); 1291287ac01aSChristof Schmitt 1292287ac01aSChristof Schmitt unlock: 1293287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 1294287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 1295287ac01aSChristof Schmitt 1296287ac01aSChristof Schmitt if (retval != ZFCP_ERP_CONTINUES) 1297287ac01aSChristof Schmitt zfcp_erp_action_cleanup(erp_action, retval); 1298287ac01aSChristof Schmitt 1299287ac01aSChristof Schmitt return retval; 1300287ac01aSChristof Schmitt } 1301287ac01aSChristof Schmitt 1302287ac01aSChristof Schmitt static int zfcp_erp_thread(void *data) 1303287ac01aSChristof Schmitt { 1304287ac01aSChristof Schmitt struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; 1305287ac01aSChristof Schmitt struct list_head *next; 1306287ac01aSChristof Schmitt struct zfcp_erp_action *act; 1307287ac01aSChristof Schmitt unsigned long flags; 130806499facSHeiko Carstens int ignore; 1309287ac01aSChristof Schmitt 1310b9d3aed7SCornelia Huck daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); 1311287ac01aSChristof Schmitt /* Block all signals */ 1312287ac01aSChristof Schmitt siginitsetinv(¤t->blocked, 0); 1313287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); 1314287ac01aSChristof Schmitt wake_up(&adapter->erp_thread_wqh); 1315287ac01aSChristof Schmitt 1316287ac01aSChristof Schmitt while (!(atomic_read(&adapter->status) & 1317287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { 131894ab4b38SSwen Schillig 131994ab4b38SSwen Schillig zfcp_rec_dbf_event_thread_lock("erthrd1", adapter); 132094ab4b38SSwen Schillig ignore = down_interruptible(&adapter->erp_ready_sem); 132194ab4b38SSwen Schillig zfcp_rec_dbf_event_thread_lock("erthrd2", adapter); 132294ab4b38SSwen Schillig 1323287ac01aSChristof Schmitt write_lock_irqsave(&adapter->erp_lock, flags); 1324287ac01aSChristof Schmitt next = adapter->erp_ready_head.next; 1325287ac01aSChristof Schmitt write_unlock_irqrestore(&adapter->erp_lock, flags); 1326287ac01aSChristof Schmitt 1327287ac01aSChristof Schmitt if (next != &adapter->erp_ready_head) { 1328287ac01aSChristof Schmitt act = list_entry(next, struct zfcp_erp_action, list); 1329287ac01aSChristof Schmitt 1330287ac01aSChristof Schmitt /* there is more to come after dismission, no notify */ 1331287ac01aSChristof Schmitt if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) 1332287ac01aSChristof Schmitt zfcp_erp_wakeup(adapter); 1333287ac01aSChristof Schmitt } 1334287ac01aSChristof Schmitt } 1335287ac01aSChristof Schmitt 1336287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); 1337287ac01aSChristof Schmitt wake_up(&adapter->erp_thread_wqh); 1338287ac01aSChristof Schmitt 1339287ac01aSChristof Schmitt return 0; 1340287ac01aSChristof Schmitt } 1341287ac01aSChristof Schmitt 1342287ac01aSChristof Schmitt /** 1343287ac01aSChristof Schmitt * zfcp_erp_thread_setup - Start ERP thread for adapter 1344287ac01aSChristof Schmitt * @adapter: Adapter to start the ERP thread for 1345287ac01aSChristof Schmitt * 1346287ac01aSChristof Schmitt * Returns 0 on success or error code from kernel_thread() 1347287ac01aSChristof Schmitt */ 1348287ac01aSChristof Schmitt int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) 1349287ac01aSChristof Schmitt { 1350287ac01aSChristof Schmitt int retval; 1351287ac01aSChristof Schmitt 1352287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); 1353287ac01aSChristof Schmitt retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); 1354287ac01aSChristof Schmitt if (retval < 0) { 1355287ac01aSChristof Schmitt dev_err(&adapter->ccw_device->dev, 1356ff3b24faSChristof Schmitt "Creating an ERP thread for the FCP device failed.\n"); 1357287ac01aSChristof Schmitt return retval; 1358287ac01aSChristof Schmitt } 1359287ac01aSChristof Schmitt wait_event(adapter->erp_thread_wqh, 1360287ac01aSChristof Schmitt atomic_read(&adapter->status) & 1361287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); 1362287ac01aSChristof Schmitt return 0; 1363287ac01aSChristof Schmitt } 1364287ac01aSChristof Schmitt 1365287ac01aSChristof Schmitt /** 1366287ac01aSChristof Schmitt * zfcp_erp_thread_kill - Stop ERP thread. 1367287ac01aSChristof Schmitt * @adapter: Adapter where the ERP thread should be stopped. 1368287ac01aSChristof Schmitt * 1369287ac01aSChristof Schmitt * The caller of this routine ensures that the specified adapter has 1370287ac01aSChristof Schmitt * been shut down and that this operation has been completed. Thus, 1371287ac01aSChristof Schmitt * there are no pending erp_actions which would need to be handled 1372287ac01aSChristof Schmitt * here. 1373287ac01aSChristof Schmitt */ 1374287ac01aSChristof Schmitt void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) 1375287ac01aSChristof Schmitt { 1376287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); 1377287ac01aSChristof Schmitt up(&adapter->erp_ready_sem); 13785ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erthrk1", adapter); 1379287ac01aSChristof Schmitt 1380287ac01aSChristof Schmitt wait_event(adapter->erp_thread_wqh, 1381287ac01aSChristof Schmitt !(atomic_read(&adapter->status) & 1382287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)); 1383287ac01aSChristof Schmitt 1384287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, 1385287ac01aSChristof Schmitt &adapter->status); 1386287ac01aSChristof Schmitt } 1387287ac01aSChristof Schmitt 1388287ac01aSChristof Schmitt /** 1389287ac01aSChristof Schmitt * zfcp_erp_adapter_failed - Set adapter status to failed. 1390287ac01aSChristof Schmitt * @adapter: Failed adapter. 1391287ac01aSChristof Schmitt * @id: Event id for debug trace. 1392287ac01aSChristof Schmitt * @ref: Reference for debug trace. 1393287ac01aSChristof Schmitt */ 13945ffd51a5SSwen Schillig void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref) 1395287ac01aSChristof Schmitt { 1396287ac01aSChristof Schmitt zfcp_erp_modify_adapter_status(adapter, id, ref, 1397287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); 1398287ac01aSChristof Schmitt } 1399287ac01aSChristof Schmitt 1400287ac01aSChristof Schmitt /** 1401287ac01aSChristof Schmitt * zfcp_erp_port_failed - Set port status to failed. 1402287ac01aSChristof Schmitt * @port: Failed port. 1403287ac01aSChristof Schmitt * @id: Event id for debug trace. 1404287ac01aSChristof Schmitt * @ref: Reference for debug trace. 1405287ac01aSChristof Schmitt */ 14065ffd51a5SSwen Schillig void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref) 1407287ac01aSChristof Schmitt { 1408287ac01aSChristof Schmitt zfcp_erp_modify_port_status(port, id, ref, 1409287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); 1410287ac01aSChristof Schmitt } 1411287ac01aSChristof Schmitt 1412287ac01aSChristof Schmitt /** 1413287ac01aSChristof Schmitt * zfcp_erp_unit_failed - Set unit status to failed. 1414287ac01aSChristof Schmitt * @unit: Failed unit. 1415287ac01aSChristof Schmitt * @id: Event id for debug trace. 1416287ac01aSChristof Schmitt * @ref: Reference for debug trace. 1417287ac01aSChristof Schmitt */ 14185ffd51a5SSwen Schillig void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref) 1419287ac01aSChristof Schmitt { 1420287ac01aSChristof Schmitt zfcp_erp_modify_unit_status(unit, id, ref, 1421287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); 1422287ac01aSChristof Schmitt } 1423287ac01aSChristof Schmitt 1424287ac01aSChristof Schmitt /** 1425287ac01aSChristof Schmitt * zfcp_erp_wait - wait for completion of error recovery on an adapter 1426287ac01aSChristof Schmitt * @adapter: adapter for which to wait for completion of its error recovery 1427287ac01aSChristof Schmitt */ 1428287ac01aSChristof Schmitt void zfcp_erp_wait(struct zfcp_adapter *adapter) 1429287ac01aSChristof Schmitt { 1430287ac01aSChristof Schmitt wait_event(adapter->erp_done_wqh, 1431287ac01aSChristof Schmitt !(atomic_read(&adapter->status) & 1432287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_PENDING)); 1433287ac01aSChristof Schmitt } 1434287ac01aSChristof Schmitt 1435287ac01aSChristof Schmitt /** 1436287ac01aSChristof Schmitt * zfcp_erp_modify_adapter_status - change adapter status bits 1437287ac01aSChristof Schmitt * @adapter: adapter to change the status 1438287ac01aSChristof Schmitt * @id: id for the debug trace 1439287ac01aSChristof Schmitt * @ref: reference for the debug trace 1440287ac01aSChristof Schmitt * @mask: status bits to change 1441287ac01aSChristof Schmitt * @set_or_clear: ZFCP_SET or ZFCP_CLEAR 1442287ac01aSChristof Schmitt * 1443287ac01aSChristof Schmitt * Changes in common status bits are propagated to attached ports and units. 1444287ac01aSChristof Schmitt */ 14455ffd51a5SSwen Schillig void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, 1446287ac01aSChristof Schmitt void *ref, u32 mask, int set_or_clear) 14471da177e4SLinus Torvalds { 14481da177e4SLinus Torvalds struct zfcp_port *port; 1449287ac01aSChristof Schmitt u32 common_mask = mask & ZFCP_COMMON_FLAGS; 14501da177e4SLinus Torvalds 1451287ac01aSChristof Schmitt if (set_or_clear == ZFCP_SET) { 1452287ac01aSChristof Schmitt if (status_change_set(mask, &adapter->status)) 1453287ac01aSChristof Schmitt zfcp_rec_dbf_event_adapter(id, ref, adapter); 1454287ac01aSChristof Schmitt atomic_set_mask(mask, &adapter->status); 1455287ac01aSChristof Schmitt } else { 1456287ac01aSChristof Schmitt if (status_change_clear(mask, &adapter->status)) 1457287ac01aSChristof Schmitt zfcp_rec_dbf_event_adapter(id, ref, adapter); 1458287ac01aSChristof Schmitt atomic_clear_mask(mask, &adapter->status); 1459287ac01aSChristof Schmitt if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) 1460287ac01aSChristof Schmitt atomic_set(&adapter->erp_counter, 0); 14611da177e4SLinus Torvalds } 14621da177e4SLinus Torvalds 1463287ac01aSChristof Schmitt if (common_mask) 1464287ac01aSChristof Schmitt list_for_each_entry(port, &adapter->port_list_head, list) 1465287ac01aSChristof Schmitt zfcp_erp_modify_port_status(port, id, ref, common_mask, 1466287ac01aSChristof Schmitt set_or_clear); 1467287ac01aSChristof Schmitt } 1468287ac01aSChristof Schmitt 1469287ac01aSChristof Schmitt /** 1470287ac01aSChristof Schmitt * zfcp_erp_modify_port_status - change port status bits 1471287ac01aSChristof Schmitt * @port: port to change the status bits 1472287ac01aSChristof Schmitt * @id: id for the debug trace 1473287ac01aSChristof Schmitt * @ref: reference for the debug trace 1474287ac01aSChristof Schmitt * @mask: status bits to change 1475287ac01aSChristof Schmitt * @set_or_clear: ZFCP_SET or ZFCP_CLEAR 1476287ac01aSChristof Schmitt * 1477287ac01aSChristof Schmitt * Changes in common status bits are propagated to attached units. 1478287ac01aSChristof Schmitt */ 14795ffd51a5SSwen Schillig void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, 1480287ac01aSChristof Schmitt u32 mask, int set_or_clear) 14811da177e4SLinus Torvalds { 14821da177e4SLinus Torvalds struct zfcp_unit *unit; 1483287ac01aSChristof Schmitt u32 common_mask = mask & ZFCP_COMMON_FLAGS; 14841da177e4SLinus Torvalds 1485287ac01aSChristof Schmitt if (set_or_clear == ZFCP_SET) { 1486287ac01aSChristof Schmitt if (status_change_set(mask, &port->status)) 1487287ac01aSChristof Schmitt zfcp_rec_dbf_event_port(id, ref, port); 1488287ac01aSChristof Schmitt atomic_set_mask(mask, &port->status); 1489287ac01aSChristof Schmitt } else { 1490287ac01aSChristof Schmitt if (status_change_clear(mask, &port->status)) 1491287ac01aSChristof Schmitt zfcp_rec_dbf_event_port(id, ref, port); 1492287ac01aSChristof Schmitt atomic_clear_mask(mask, &port->status); 1493287ac01aSChristof Schmitt if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) 1494287ac01aSChristof Schmitt atomic_set(&port->erp_counter, 0); 1495287ac01aSChristof Schmitt } 1496287ac01aSChristof Schmitt 1497287ac01aSChristof Schmitt if (common_mask) 14981da177e4SLinus Torvalds list_for_each_entry(unit, &port->unit_list_head, list) 1499287ac01aSChristof Schmitt zfcp_erp_modify_unit_status(unit, id, ref, common_mask, 1500287ac01aSChristof Schmitt set_or_clear); 15011da177e4SLinus Torvalds } 15021da177e4SLinus Torvalds 1503287ac01aSChristof Schmitt /** 1504287ac01aSChristof Schmitt * zfcp_erp_modify_unit_status - change unit status bits 1505287ac01aSChristof Schmitt * @unit: unit to change the status bits 1506287ac01aSChristof Schmitt * @id: id for the debug trace 1507287ac01aSChristof Schmitt * @ref: reference for the debug trace 1508287ac01aSChristof Schmitt * @mask: status bits to change 1509287ac01aSChristof Schmitt * @set_or_clear: ZFCP_SET or ZFCP_CLEAR 1510287ac01aSChristof Schmitt */ 15115ffd51a5SSwen Schillig void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, 1512287ac01aSChristof Schmitt u32 mask, int set_or_clear) 15131da177e4SLinus Torvalds { 1514287ac01aSChristof Schmitt if (set_or_clear == ZFCP_SET) { 1515287ac01aSChristof Schmitt if (status_change_set(mask, &unit->status)) 1516287ac01aSChristof Schmitt zfcp_rec_dbf_event_unit(id, ref, unit); 1517287ac01aSChristof Schmitt atomic_set_mask(mask, &unit->status); 1518287ac01aSChristof Schmitt } else { 1519287ac01aSChristof Schmitt if (status_change_clear(mask, &unit->status)) 1520287ac01aSChristof Schmitt zfcp_rec_dbf_event_unit(id, ref, unit); 1521287ac01aSChristof Schmitt atomic_clear_mask(mask, &unit->status); 1522287ac01aSChristof Schmitt if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { 1523287ac01aSChristof Schmitt atomic_set(&unit->erp_counter, 0); 1524287ac01aSChristof Schmitt } 1525287ac01aSChristof Schmitt } 15261da177e4SLinus Torvalds } 15271da177e4SLinus Torvalds 1528287ac01aSChristof Schmitt /** 1529287ac01aSChristof Schmitt * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP 1530287ac01aSChristof Schmitt * @port: The "boxed" port. 1531287ac01aSChristof Schmitt * @id: The debug trace id. 1532287ac01aSChristof Schmitt * @id: Reference for the debug trace. 1533287ac01aSChristof Schmitt */ 15345ffd51a5SSwen Schillig void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref) 1535d736a27bSAndreas Herrmann { 1536d736a27bSAndreas Herrmann unsigned long flags; 1537d736a27bSAndreas Herrmann 1538d736a27bSAndreas Herrmann read_lock_irqsave(&zfcp_data.config_lock, flags); 1539698ec016SMartin Peschke zfcp_erp_modify_port_status(port, id, ref, 1540698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); 1541d736a27bSAndreas Herrmann read_unlock_irqrestore(&zfcp_data.config_lock, flags); 15429467a9b3SMartin Peschke zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1543d736a27bSAndreas Herrmann } 1544d736a27bSAndreas Herrmann 1545287ac01aSChristof Schmitt /** 1546287ac01aSChristof Schmitt * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP 1547287ac01aSChristof Schmitt * @port: The "boxed" unit. 1548287ac01aSChristof Schmitt * @id: The debug trace id. 1549287ac01aSChristof Schmitt * @id: Reference for the debug trace. 1550287ac01aSChristof Schmitt */ 15515ffd51a5SSwen Schillig void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref) 1552d736a27bSAndreas Herrmann { 1553698ec016SMartin Peschke zfcp_erp_modify_unit_status(unit, id, ref, 1554698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); 15559467a9b3SMartin Peschke zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1556d736a27bSAndreas Herrmann } 1557d736a27bSAndreas Herrmann 1558287ac01aSChristof Schmitt /** 1559287ac01aSChristof Schmitt * zfcp_erp_port_access_denied - Adapter denied access to port. 1560287ac01aSChristof Schmitt * @port: port where access has been denied 1561287ac01aSChristof Schmitt * @id: id for debug trace 1562287ac01aSChristof Schmitt * @ref: reference for debug trace 1563287ac01aSChristof Schmitt * 1564287ac01aSChristof Schmitt * Since the adapter has denied access, stop using the port and the 1565287ac01aSChristof Schmitt * attached units. 1566287ac01aSChristof Schmitt */ 15675ffd51a5SSwen Schillig void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref) 15681da177e4SLinus Torvalds { 15691da177e4SLinus Torvalds unsigned long flags; 15701da177e4SLinus Torvalds 15711da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 1572698ec016SMartin Peschke zfcp_erp_modify_port_status(port, id, ref, 1573d736a27bSAndreas Herrmann ZFCP_STATUS_COMMON_ERP_FAILED | 1574698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); 15751da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 15761da177e4SLinus Torvalds } 15771da177e4SLinus Torvalds 1578287ac01aSChristof Schmitt /** 1579287ac01aSChristof Schmitt * zfcp_erp_unit_access_denied - Adapter denied access to unit. 1580287ac01aSChristof Schmitt * @unit: unit where access has been denied 1581287ac01aSChristof Schmitt * @id: id for debug trace 1582287ac01aSChristof Schmitt * @ref: reference for debug trace 1583287ac01aSChristof Schmitt * 1584287ac01aSChristof Schmitt * Since the adapter has denied access, stop using the unit. 1585287ac01aSChristof Schmitt */ 15865ffd51a5SSwen Schillig void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref) 15871da177e4SLinus Torvalds { 1588698ec016SMartin Peschke zfcp_erp_modify_unit_status(unit, id, ref, 1589d736a27bSAndreas Herrmann ZFCP_STATUS_COMMON_ERP_FAILED | 1590698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); 15911da177e4SLinus Torvalds } 15921da177e4SLinus Torvalds 15935ffd51a5SSwen Schillig static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id, 1594287ac01aSChristof Schmitt void *ref) 1595287ac01aSChristof Schmitt { 1596287ac01aSChristof Schmitt int status = atomic_read(&unit->status); 1597287ac01aSChristof Schmitt if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | 1598287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ACCESS_BOXED))) 1599287ac01aSChristof Schmitt return; 1600287ac01aSChristof Schmitt 1601287ac01aSChristof Schmitt zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1602287ac01aSChristof Schmitt } 1603287ac01aSChristof Schmitt 16045ffd51a5SSwen Schillig static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id, 1605287ac01aSChristof Schmitt void *ref) 1606287ac01aSChristof Schmitt { 1607287ac01aSChristof Schmitt struct zfcp_unit *unit; 1608287ac01aSChristof Schmitt int status = atomic_read(&port->status); 1609287ac01aSChristof Schmitt 1610287ac01aSChristof Schmitt if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | 1611287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ACCESS_BOXED))) { 1612287ac01aSChristof Schmitt list_for_each_entry(unit, &port->unit_list_head, list) 1613287ac01aSChristof Schmitt zfcp_erp_unit_access_changed(unit, id, ref); 1614287ac01aSChristof Schmitt return; 1615287ac01aSChristof Schmitt } 1616287ac01aSChristof Schmitt 1617287ac01aSChristof Schmitt zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1618287ac01aSChristof Schmitt } 1619287ac01aSChristof Schmitt 1620287ac01aSChristof Schmitt /** 1621287ac01aSChristof Schmitt * zfcp_erp_adapter_access_changed - Process change in adapter ACT 1622287ac01aSChristof Schmitt * @adapter: Adapter where the Access Control Table (ACT) changed 1623287ac01aSChristof Schmitt * @id: Id for debug trace 1624287ac01aSChristof Schmitt * @ref: Reference for debug trace 1625287ac01aSChristof Schmitt */ 16265ffd51a5SSwen Schillig void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id, 16271f6f7129SMartin Peschke void *ref) 16281da177e4SLinus Torvalds { 16291da177e4SLinus Torvalds struct zfcp_port *port; 16301da177e4SLinus Torvalds unsigned long flags; 16311da177e4SLinus Torvalds 1632aef4a983SMaxim Shchetynin if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) 1633aef4a983SMaxim Shchetynin return; 1634aef4a983SMaxim Shchetynin 16351da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 16361da177e4SLinus Torvalds list_for_each_entry(port, &adapter->port_list_head, list) 16379467a9b3SMartin Peschke zfcp_erp_port_access_changed(port, id, ref); 16381da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 16391da177e4SLinus Torvalds } 1640