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 556287ac01aSChristof Schmitt static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act) 557287ac01aSChristof Schmitt { 558287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 559287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 560287ac01aSChristof Schmitt struct zfcp_unit *unit = act->unit; 561287ac01aSChristof Schmitt u32 status = act->status; 562287ac01aSChristof Schmitt 563287ac01aSChristof Schmitt /* initiate follow-up actions depending on success of finished action */ 564287ac01aSChristof Schmitt switch (act->action) { 565287ac01aSChristof Schmitt 566287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 567287ac01aSChristof Schmitt if (status == ZFCP_ERP_SUCCEEDED) 5685ffd51a5SSwen Schillig _zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL); 569287ac01aSChristof Schmitt else 5705ffd51a5SSwen Schillig _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL); 571287ac01aSChristof Schmitt break; 572287ac01aSChristof Schmitt 573287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 574287ac01aSChristof Schmitt if (status == ZFCP_ERP_SUCCEEDED) 5755ffd51a5SSwen Schillig _zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL); 576287ac01aSChristof Schmitt else 5775ffd51a5SSwen Schillig _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL); 578287ac01aSChristof Schmitt break; 579287ac01aSChristof Schmitt 580287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 581287ac01aSChristof Schmitt if (status == ZFCP_ERP_SUCCEEDED) 5825ffd51a5SSwen Schillig _zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL); 583287ac01aSChristof Schmitt else 5845ffd51a5SSwen Schillig _zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL); 585287ac01aSChristof Schmitt break; 586287ac01aSChristof Schmitt 587287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 588287ac01aSChristof Schmitt if (status != ZFCP_ERP_SUCCEEDED) 5895ffd51a5SSwen Schillig _zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL); 590287ac01aSChristof Schmitt break; 591287ac01aSChristof Schmitt } 592287ac01aSChristof Schmitt } 593287ac01aSChristof Schmitt 594287ac01aSChristof Schmitt static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) 595287ac01aSChristof Schmitt { 596287ac01aSChristof Schmitt unsigned long flags; 597287ac01aSChristof Schmitt 598287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 599287ac01aSChristof Schmitt read_lock(&adapter->erp_lock); 600287ac01aSChristof Schmitt if (list_empty(&adapter->erp_ready_head) && 601287ac01aSChristof Schmitt list_empty(&adapter->erp_running_head)) { 602287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, 603287ac01aSChristof Schmitt &adapter->status); 604287ac01aSChristof Schmitt wake_up(&adapter->erp_done_wqh); 605287ac01aSChristof Schmitt } 606287ac01aSChristof Schmitt read_unlock(&adapter->erp_lock); 607287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 608287ac01aSChristof Schmitt } 609287ac01aSChristof Schmitt 610287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) 611287ac01aSChristof Schmitt { 612287ac01aSChristof Schmitt if (zfcp_qdio_open(act->adapter)) 613287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 614287ac01aSChristof Schmitt init_waitqueue_head(&act->adapter->request_wq); 615287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); 616287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 617287ac01aSChristof Schmitt } 618287ac01aSChristof Schmitt 619287ac01aSChristof Schmitt static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) 620287ac01aSChristof Schmitt { 621287ac01aSChristof Schmitt struct zfcp_port *port; 622287ac01aSChristof Schmitt port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, 623287ac01aSChristof Schmitt adapter->peer_d_id); 624287ac01aSChristof Schmitt if (IS_ERR(port)) /* error or port already attached */ 625287ac01aSChristof Schmitt return; 6265ffd51a5SSwen Schillig _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL); 627287ac01aSChristof Schmitt } 628287ac01aSChristof Schmitt 629287ac01aSChristof Schmitt static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) 630287ac01aSChristof Schmitt { 631287ac01aSChristof Schmitt int retries; 632287ac01aSChristof Schmitt int sleep = 1; 633287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 634287ac01aSChristof Schmitt 635287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); 636287ac01aSChristof Schmitt 637287ac01aSChristof Schmitt for (retries = 7; retries; retries--) { 638287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, 639287ac01aSChristof Schmitt &adapter->status); 640287ac01aSChristof Schmitt write_lock_irq(&adapter->erp_lock); 641287ac01aSChristof Schmitt zfcp_erp_action_to_running(erp_action); 642287ac01aSChristof Schmitt write_unlock_irq(&adapter->erp_lock); 643287ac01aSChristof Schmitt if (zfcp_fsf_exchange_config_data(erp_action)) { 644287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, 645287ac01aSChristof Schmitt &adapter->status); 646287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 647287ac01aSChristof Schmitt } 648287ac01aSChristof Schmitt 6495ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erasfx1", adapter); 650287ac01aSChristof Schmitt down(&adapter->erp_ready_sem); 6515ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erasfx2", adapter); 652287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) 653287ac01aSChristof Schmitt break; 654287ac01aSChristof Schmitt 655287ac01aSChristof Schmitt if (!(atomic_read(&adapter->status) & 656287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_HOST_CON_INIT)) 657287ac01aSChristof Schmitt break; 658287ac01aSChristof Schmitt 659287ac01aSChristof Schmitt ssleep(sleep); 660287ac01aSChristof Schmitt sleep *= 2; 661287ac01aSChristof Schmitt } 662287ac01aSChristof Schmitt 663287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, 664287ac01aSChristof Schmitt &adapter->status); 665287ac01aSChristof Schmitt 666287ac01aSChristof Schmitt if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK)) 667287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 668287ac01aSChristof Schmitt 669287ac01aSChristof Schmitt if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) 670287ac01aSChristof Schmitt zfcp_erp_enqueue_ptp_port(adapter); 671287ac01aSChristof Schmitt 672287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 673287ac01aSChristof Schmitt } 674287ac01aSChristof Schmitt 675287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) 676287ac01aSChristof Schmitt { 677287ac01aSChristof Schmitt int ret; 678287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 679287ac01aSChristof Schmitt 680287ac01aSChristof Schmitt write_lock_irq(&adapter->erp_lock); 681287ac01aSChristof Schmitt zfcp_erp_action_to_running(act); 682287ac01aSChristof Schmitt write_unlock_irq(&adapter->erp_lock); 683287ac01aSChristof Schmitt 684287ac01aSChristof Schmitt ret = zfcp_fsf_exchange_port_data(act); 685287ac01aSChristof Schmitt if (ret == -EOPNOTSUPP) 686287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 687287ac01aSChristof Schmitt if (ret) 688287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 689287ac01aSChristof Schmitt 6905ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erasox1", adapter); 691287ac01aSChristof Schmitt down(&adapter->erp_ready_sem); 6925ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erasox2", adapter); 693287ac01aSChristof Schmitt if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) 694287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 695287ac01aSChristof Schmitt 696287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 697287ac01aSChristof Schmitt } 698287ac01aSChristof Schmitt 699287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act) 700287ac01aSChristof Schmitt { 701287ac01aSChristof Schmitt if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED) 702287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 703287ac01aSChristof Schmitt 704287ac01aSChristof Schmitt if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) 705287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 706287ac01aSChristof Schmitt 707287ac01aSChristof Schmitt atomic_set(&act->adapter->stat_miss, 16); 708287ac01aSChristof Schmitt if (zfcp_status_read_refill(act->adapter)) 709287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 710287ac01aSChristof Schmitt 711287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 712287ac01aSChristof Schmitt } 713287ac01aSChristof Schmitt 714cf13c082SSwen Schillig static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) 715287ac01aSChristof Schmitt { 716287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 717287ac01aSChristof Schmitt 718287ac01aSChristof Schmitt /* close queues to ensure that buffers are not accessed by adapter */ 719287ac01aSChristof Schmitt zfcp_qdio_close(adapter); 720287ac01aSChristof Schmitt zfcp_fsf_req_dismiss_all(adapter); 721287ac01aSChristof Schmitt adapter->fsf_req_seq_no = 0; 722828bc121SSwen Schillig zfcp_fc_wka_port_force_offline(&adapter->nsp); 723287ac01aSChristof Schmitt /* all ports and units are closed */ 7245ffd51a5SSwen Schillig zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, 725287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); 726cf13c082SSwen Schillig 727cf13c082SSwen Schillig atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | 728cf13c082SSwen Schillig ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); 729cf13c082SSwen Schillig } 730cf13c082SSwen Schillig 731cf13c082SSwen Schillig static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act) 732cf13c082SSwen Schillig { 733cf13c082SSwen Schillig struct zfcp_adapter *adapter = act->adapter; 734cf13c082SSwen Schillig 735cf13c082SSwen Schillig if (zfcp_erp_adapter_strategy_open_qdio(act)) { 736287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | 73744cc76f2SSwen Schillig ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, 738cf13c082SSwen Schillig &adapter->status); 739cf13c082SSwen Schillig return ZFCP_ERP_FAILED; 740cf13c082SSwen Schillig } 741cf13c082SSwen Schillig 742cf13c082SSwen Schillig if (zfcp_erp_adapter_strategy_open_fsf(act)) { 743cf13c082SSwen Schillig zfcp_erp_adapter_strategy_close(act); 744cf13c082SSwen Schillig return ZFCP_ERP_FAILED; 745cf13c082SSwen Schillig } 746cf13c082SSwen Schillig 747cf13c082SSwen Schillig atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status); 748cf13c082SSwen Schillig 749cf13c082SSwen Schillig return ZFCP_ERP_SUCCEEDED; 750287ac01aSChristof Schmitt } 751287ac01aSChristof Schmitt 752287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act) 753287ac01aSChristof Schmitt { 754cf13c082SSwen Schillig struct zfcp_adapter *adapter = act->adapter; 755287ac01aSChristof Schmitt 756cf13c082SSwen Schillig if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) { 757cf13c082SSwen Schillig zfcp_erp_adapter_strategy_close(act); 758287ac01aSChristof Schmitt if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 759287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 760cf13c082SSwen Schillig } 761287ac01aSChristof Schmitt 762cf13c082SSwen Schillig if (zfcp_erp_adapter_strategy_open(act)) { 763287ac01aSChristof Schmitt ssleep(8); 764cf13c082SSwen Schillig return ZFCP_ERP_FAILED; 765cf13c082SSwen Schillig } 7661da177e4SLinus Torvalds 767cf13c082SSwen Schillig return ZFCP_ERP_SUCCEEDED; 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds 770287ac01aSChristof Schmitt static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act) 7711da177e4SLinus Torvalds { 772287ac01aSChristof Schmitt int retval; 773287ac01aSChristof Schmitt 774287ac01aSChristof Schmitt retval = zfcp_fsf_close_physical_port(act); 775287ac01aSChristof Schmitt if (retval == -ENOMEM) 776287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 777287ac01aSChristof Schmitt act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; 778287ac01aSChristof Schmitt if (retval) 779287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 780287ac01aSChristof Schmitt 781287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 7821da177e4SLinus Torvalds } 7831da177e4SLinus Torvalds 784287ac01aSChristof Schmitt static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) 7851da177e4SLinus Torvalds { 786a5b11ddaSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status); 787287ac01aSChristof Schmitt } 7881da177e4SLinus Torvalds 789287ac01aSChristof Schmitt static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) 790287ac01aSChristof Schmitt { 791287ac01aSChristof Schmitt struct zfcp_port *port = erp_action->port; 792287ac01aSChristof Schmitt int status = atomic_read(&port->status); 793287ac01aSChristof Schmitt 794287ac01aSChristof Schmitt switch (erp_action->step) { 795287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 796287ac01aSChristof Schmitt zfcp_erp_port_strategy_clearstati(port); 797287ac01aSChristof Schmitt if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) && 798287ac01aSChristof Schmitt (status & ZFCP_STATUS_COMMON_OPEN)) 799287ac01aSChristof Schmitt return zfcp_erp_port_forced_strategy_close(erp_action); 8001da177e4SLinus Torvalds else 801287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 802287ac01aSChristof Schmitt 803287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: 804287ac01aSChristof Schmitt if (status & ZFCP_STATUS_PORT_PHYS_OPEN) 805287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 806287ac01aSChristof Schmitt } 807287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 8081da177e4SLinus Torvalds } 8091da177e4SLinus Torvalds 810287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) 8111da177e4SLinus Torvalds { 812287ac01aSChristof Schmitt int retval; 8131da177e4SLinus Torvalds 814287ac01aSChristof Schmitt retval = zfcp_fsf_close_port(erp_action); 815287ac01aSChristof Schmitt if (retval == -ENOMEM) 816287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 817287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; 818287ac01aSChristof Schmitt if (retval) 819287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 820287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 8211da177e4SLinus Torvalds } 8221da177e4SLinus Torvalds 823287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) 824287ac01aSChristof Schmitt { 825287ac01aSChristof Schmitt int retval; 826287ac01aSChristof Schmitt 827287ac01aSChristof Schmitt retval = zfcp_fsf_open_port(erp_action); 828287ac01aSChristof Schmitt if (retval == -ENOMEM) 829287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 830287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; 831287ac01aSChristof Schmitt if (retval) 832287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 833287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 834287ac01aSChristof Schmitt } 835287ac01aSChristof Schmitt 836287ac01aSChristof Schmitt static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) 837287ac01aSChristof Schmitt { 838287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 839287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 840287ac01aSChristof Schmitt 841287ac01aSChristof Schmitt if (port->wwpn != adapter->peer_wwpn) { 8425ffd51a5SSwen Schillig zfcp_erp_port_failed(port, "eroptp1", NULL); 843287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 844287ac01aSChristof Schmitt } 845287ac01aSChristof Schmitt port->d_id = adapter->peer_d_id; 846287ac01aSChristof Schmitt return zfcp_erp_port_strategy_open_port(act); 847287ac01aSChristof Schmitt } 848287ac01aSChristof Schmitt 8495ab944f9SSwen Schillig void zfcp_erp_port_strategy_open_lookup(struct work_struct *work) 8505ab944f9SSwen Schillig { 8515ab944f9SSwen Schillig int retval; 8525ab944f9SSwen Schillig struct zfcp_port *port = container_of(work, struct zfcp_port, 8535ab944f9SSwen Schillig gid_pn_work); 8545ab944f9SSwen Schillig 8555ab944f9SSwen Schillig retval = zfcp_fc_ns_gid_pn(&port->erp_action); 8565ab944f9SSwen Schillig if (retval == -ENOMEM) 8575ab944f9SSwen Schillig zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM); 8585ab944f9SSwen Schillig port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; 8595ab944f9SSwen Schillig if (retval) 8605ab944f9SSwen Schillig zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED); 861947a9acaSSwen Schillig zfcp_port_put(port); 8625ab944f9SSwen Schillig } 8635ab944f9SSwen Schillig 864287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) 865287ac01aSChristof Schmitt { 866287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 867287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 868287ac01aSChristof Schmitt int p_status = atomic_read(&port->status); 869287ac01aSChristof Schmitt 870287ac01aSChristof Schmitt switch (act->step) { 871287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 872287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: 873287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PORT_CLOSING: 874287ac01aSChristof Schmitt if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) 875287ac01aSChristof Schmitt return zfcp_erp_open_ptp_port(act); 876b98478d7SChristof Schmitt if (!port->d_id) { 877947a9acaSSwen Schillig zfcp_port_get(port); 878947a9acaSSwen Schillig if (!queue_work(zfcp_data.work_queue, 879947a9acaSSwen Schillig &port->gid_pn_work)) 880947a9acaSSwen Schillig zfcp_port_put(port); 881287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 882287ac01aSChristof Schmitt } 883dceab655SChristof Schmitt /* fall through */ 884287ac01aSChristof Schmitt case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: 885a5b11ddaSChristof Schmitt if (!port->d_id) 886287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 887287ac01aSChristof Schmitt return zfcp_erp_port_strategy_open_port(act); 888287ac01aSChristof Schmitt 889287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PORT_OPENING: 890287ac01aSChristof Schmitt /* D_ID might have changed during open */ 8915ab944f9SSwen Schillig if (p_status & ZFCP_STATUS_COMMON_OPEN) { 892b98478d7SChristof Schmitt if (port->d_id) 893287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 8945ab944f9SSwen Schillig else { 8955ab944f9SSwen Schillig act->step = ZFCP_ERP_STEP_PORT_CLOSING; 8965ab944f9SSwen Schillig return ZFCP_ERP_CONTINUES; 8975ab944f9SSwen Schillig } 898287ac01aSChristof Schmitt } 899ea460a81SSwen Schillig if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { 900ea460a81SSwen Schillig port->d_id = 0; 901ea460a81SSwen Schillig _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL); 902ea460a81SSwen Schillig return ZFCP_ERP_EXIT; 903ea460a81SSwen Schillig } 904ea460a81SSwen Schillig /* fall through otherwise */ 905287ac01aSChristof Schmitt } 9065ab944f9SSwen Schillig return ZFCP_ERP_FAILED; 907287ac01aSChristof Schmitt } 908287ac01aSChristof Schmitt 909287ac01aSChristof Schmitt static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) 910287ac01aSChristof Schmitt { 911287ac01aSChristof Schmitt struct zfcp_port *port = erp_action->port; 912287ac01aSChristof Schmitt 9135ab944f9SSwen Schillig if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) 9145ab944f9SSwen Schillig goto close_init_done; 9155ab944f9SSwen Schillig 916287ac01aSChristof Schmitt switch (erp_action->step) { 917287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 918287ac01aSChristof Schmitt zfcp_erp_port_strategy_clearstati(port); 919287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) 920287ac01aSChristof Schmitt return zfcp_erp_port_strategy_close(erp_action); 921287ac01aSChristof Schmitt break; 922287ac01aSChristof Schmitt 923287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PORT_CLOSING: 924287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) 925287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 926287ac01aSChristof Schmitt break; 927287ac01aSChristof Schmitt } 9285ab944f9SSwen Schillig 9295ab944f9SSwen Schillig close_init_done: 930287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 931287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 932287ac01aSChristof Schmitt 9335ab944f9SSwen Schillig return zfcp_erp_port_strategy_open_common(erp_action); 934287ac01aSChristof Schmitt } 935287ac01aSChristof Schmitt 936287ac01aSChristof Schmitt static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) 937287ac01aSChristof Schmitt { 93844cc76f2SSwen Schillig atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | 939287ac01aSChristof Schmitt ZFCP_STATUS_UNIT_SHARED | 940287ac01aSChristof Schmitt ZFCP_STATUS_UNIT_READONLY, 941287ac01aSChristof Schmitt &unit->status); 942287ac01aSChristof Schmitt } 943287ac01aSChristof Schmitt 944287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) 945287ac01aSChristof Schmitt { 946287ac01aSChristof Schmitt int retval = zfcp_fsf_close_unit(erp_action); 947287ac01aSChristof Schmitt if (retval == -ENOMEM) 948287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 949287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; 950287ac01aSChristof Schmitt if (retval) 951287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 952287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 953287ac01aSChristof Schmitt } 954287ac01aSChristof Schmitt 955287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) 956287ac01aSChristof Schmitt { 957287ac01aSChristof Schmitt int retval = zfcp_fsf_open_unit(erp_action); 958287ac01aSChristof Schmitt if (retval == -ENOMEM) 959287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 960287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; 961287ac01aSChristof Schmitt if (retval) 962287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 963287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 964287ac01aSChristof Schmitt } 965287ac01aSChristof Schmitt 966287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) 967287ac01aSChristof Schmitt { 968287ac01aSChristof Schmitt struct zfcp_unit *unit = erp_action->unit; 969287ac01aSChristof Schmitt 970287ac01aSChristof Schmitt switch (erp_action->step) { 971287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 972287ac01aSChristof Schmitt zfcp_erp_unit_strategy_clearstati(unit); 973287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) 974287ac01aSChristof Schmitt return zfcp_erp_unit_strategy_close(erp_action); 975287ac01aSChristof Schmitt /* already closed, fall through */ 976287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNIT_CLOSING: 977287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) 978287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 979287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 980287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 981287ac01aSChristof Schmitt return zfcp_erp_unit_strategy_open(erp_action); 982287ac01aSChristof Schmitt 983287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNIT_OPENING: 984287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) 985287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 986287ac01aSChristof Schmitt } 987287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 988287ac01aSChristof Schmitt } 989287ac01aSChristof Schmitt 990287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) 991287ac01aSChristof Schmitt { 992287ac01aSChristof Schmitt switch (result) { 993287ac01aSChristof Schmitt case ZFCP_ERP_SUCCEEDED : 994287ac01aSChristof Schmitt atomic_set(&unit->erp_counter, 0); 995287ac01aSChristof Schmitt zfcp_erp_unit_unblock(unit); 996287ac01aSChristof Schmitt break; 997287ac01aSChristof Schmitt case ZFCP_ERP_FAILED : 998287ac01aSChristof Schmitt atomic_inc(&unit->erp_counter); 999ff3b24faSChristof Schmitt if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) { 1000ff3b24faSChristof Schmitt dev_err(&unit->port->adapter->ccw_device->dev, 1001ff3b24faSChristof Schmitt "ERP failed for unit 0x%016Lx on " 1002ff3b24faSChristof Schmitt "port 0x%016Lx\n", 10037ba58c9cSSwen Schillig (unsigned long long)unit->fcp_lun, 10047ba58c9cSSwen Schillig (unsigned long long)unit->port->wwpn); 10055ffd51a5SSwen Schillig zfcp_erp_unit_failed(unit, "erusck1", NULL); 1006ff3b24faSChristof Schmitt } 1007287ac01aSChristof Schmitt break; 1008287ac01aSChristof Schmitt } 1009287ac01aSChristof Schmitt 1010287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 1011287ac01aSChristof Schmitt zfcp_erp_unit_block(unit, 0); 1012287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1013287ac01aSChristof Schmitt } 1014287ac01aSChristof Schmitt return result; 1015287ac01aSChristof Schmitt } 1016287ac01aSChristof Schmitt 1017287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) 1018287ac01aSChristof Schmitt { 1019287ac01aSChristof Schmitt switch (result) { 1020287ac01aSChristof Schmitt case ZFCP_ERP_SUCCEEDED : 1021287ac01aSChristof Schmitt atomic_set(&port->erp_counter, 0); 1022287ac01aSChristof Schmitt zfcp_erp_port_unblock(port); 1023287ac01aSChristof Schmitt break; 1024287ac01aSChristof Schmitt 1025287ac01aSChristof Schmitt case ZFCP_ERP_FAILED : 1026287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) { 1027287ac01aSChristof Schmitt zfcp_erp_port_block(port, 0); 1028287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1029287ac01aSChristof Schmitt } 1030287ac01aSChristof Schmitt atomic_inc(&port->erp_counter); 1031ff3b24faSChristof Schmitt if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) { 1032ff3b24faSChristof Schmitt dev_err(&port->adapter->ccw_device->dev, 1033ff3b24faSChristof Schmitt "ERP failed for remote port 0x%016Lx\n", 10347ba58c9cSSwen Schillig (unsigned long long)port->wwpn); 10355ffd51a5SSwen Schillig zfcp_erp_port_failed(port, "erpsck1", NULL); 1036ff3b24faSChristof Schmitt } 1037287ac01aSChristof Schmitt break; 1038287ac01aSChristof Schmitt } 1039287ac01aSChristof Schmitt 1040287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 1041287ac01aSChristof Schmitt zfcp_erp_port_block(port, 0); 1042287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1043287ac01aSChristof Schmitt } 1044287ac01aSChristof Schmitt return result; 1045287ac01aSChristof Schmitt } 1046287ac01aSChristof Schmitt 1047287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, 1048287ac01aSChristof Schmitt int result) 1049287ac01aSChristof Schmitt { 1050287ac01aSChristof Schmitt switch (result) { 1051287ac01aSChristof Schmitt case ZFCP_ERP_SUCCEEDED : 1052287ac01aSChristof Schmitt atomic_set(&adapter->erp_counter, 0); 1053287ac01aSChristof Schmitt zfcp_erp_adapter_unblock(adapter); 1054287ac01aSChristof Schmitt break; 1055287ac01aSChristof Schmitt 1056287ac01aSChristof Schmitt case ZFCP_ERP_FAILED : 1057287ac01aSChristof Schmitt atomic_inc(&adapter->erp_counter); 1058ff3b24faSChristof Schmitt if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) { 1059ff3b24faSChristof Schmitt dev_err(&adapter->ccw_device->dev, 1060ff3b24faSChristof Schmitt "ERP cannot recover an error " 1061ff3b24faSChristof Schmitt "on the FCP device\n"); 10625ffd51a5SSwen Schillig zfcp_erp_adapter_failed(adapter, "erasck1", NULL); 1063ff3b24faSChristof Schmitt } 1064287ac01aSChristof Schmitt break; 1065287ac01aSChristof Schmitt } 1066287ac01aSChristof Schmitt 1067287ac01aSChristof Schmitt if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 1068287ac01aSChristof Schmitt zfcp_erp_adapter_block(adapter, 0); 1069287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1070287ac01aSChristof Schmitt } 1071287ac01aSChristof Schmitt return result; 1072287ac01aSChristof Schmitt } 1073287ac01aSChristof Schmitt 1074287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, 1075287ac01aSChristof Schmitt int result) 10761da177e4SLinus Torvalds { 10771da177e4SLinus Torvalds struct zfcp_adapter *adapter = erp_action->adapter; 10781da177e4SLinus Torvalds struct zfcp_port *port = erp_action->port; 10791da177e4SLinus Torvalds struct zfcp_unit *unit = erp_action->unit; 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds switch (erp_action->action) { 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_UNIT: 10841da177e4SLinus Torvalds result = zfcp_erp_strategy_check_unit(unit, result); 10851da177e4SLinus Torvalds break; 10861da177e4SLinus Torvalds 10871da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 10881da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT: 10891da177e4SLinus Torvalds result = zfcp_erp_strategy_check_port(port, result); 10901da177e4SLinus Torvalds break; 10911da177e4SLinus Torvalds 10921da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 10931da177e4SLinus Torvalds result = zfcp_erp_strategy_check_adapter(adapter, result); 10941da177e4SLinus Torvalds break; 10951da177e4SLinus Torvalds } 10961da177e4SLinus Torvalds return result; 10971da177e4SLinus Torvalds } 10981da177e4SLinus Torvalds 1099287ac01aSChristof Schmitt static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status) 11001da177e4SLinus Torvalds { 1101287ac01aSChristof Schmitt int status = atomic_read(target_status); 11021da177e4SLinus Torvalds 1103287ac01aSChristof Schmitt if ((status & ZFCP_STATUS_COMMON_RUNNING) && 1104287ac01aSChristof Schmitt (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) 1105287ac01aSChristof Schmitt return 1; /* take it online */ 1106287ac01aSChristof Schmitt 1107287ac01aSChristof Schmitt if (!(status & ZFCP_STATUS_COMMON_RUNNING) && 1108287ac01aSChristof Schmitt !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) 1109287ac01aSChristof Schmitt return 1; /* take it offline */ 1110287ac01aSChristof Schmitt 1111287ac01aSChristof Schmitt return 0; 1112287ac01aSChristof Schmitt } 1113287ac01aSChristof Schmitt 1114287ac01aSChristof Schmitt static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) 1115287ac01aSChristof Schmitt { 1116287ac01aSChristof Schmitt int action = act->action; 1117287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 1118287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 1119287ac01aSChristof Schmitt struct zfcp_unit *unit = act->unit; 1120287ac01aSChristof Schmitt u32 erp_status = act->status; 1121287ac01aSChristof Schmitt 1122287ac01aSChristof Schmitt switch (action) { 11231da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1124287ac01aSChristof Schmitt if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { 1125287ac01aSChristof Schmitt _zfcp_erp_adapter_reopen(adapter, 11269467a9b3SMartin Peschke ZFCP_STATUS_COMMON_ERP_FAILED, 11275ffd51a5SSwen Schillig "ersscg1", NULL); 1128287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 11291da177e4SLinus Torvalds } 11301da177e4SLinus Torvalds break; 11311da177e4SLinus Torvalds 11321da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 11331da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT: 1134287ac01aSChristof Schmitt if (zfcp_erp_strat_change_det(&port->status, erp_status)) { 1135287ac01aSChristof Schmitt _zfcp_erp_port_reopen(port, 11369467a9b3SMartin Peschke ZFCP_STATUS_COMMON_ERP_FAILED, 11375ffd51a5SSwen Schillig "ersscg2", NULL); 1138287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 11391da177e4SLinus Torvalds } 11401da177e4SLinus Torvalds break; 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_UNIT: 1143287ac01aSChristof Schmitt if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { 1144287ac01aSChristof Schmitt _zfcp_erp_unit_reopen(unit, 11459467a9b3SMartin Peschke ZFCP_STATUS_COMMON_ERP_FAILED, 11465ffd51a5SSwen Schillig "ersscg3", NULL); 1147287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 11481da177e4SLinus Torvalds } 11491da177e4SLinus Torvalds break; 11501da177e4SLinus Torvalds } 1151287ac01aSChristof Schmitt return ret; 11521da177e4SLinus Torvalds } 11531da177e4SLinus Torvalds 1154287ac01aSChristof Schmitt static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) 11551da177e4SLinus Torvalds { 1156287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 1157287ac01aSChristof Schmitt 1158287ac01aSChristof Schmitt adapter->erp_total_count--; 1159287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { 1160287ac01aSChristof Schmitt adapter->erp_low_mem_count--; 1161287ac01aSChristof Schmitt erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; 11621da177e4SLinus Torvalds } 11631da177e4SLinus Torvalds 1164287ac01aSChristof Schmitt list_del(&erp_action->list); 11655ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("eractd1", erp_action); 11661da177e4SLinus Torvalds 1167287ac01aSChristof Schmitt switch (erp_action->action) { 1168287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 1169287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, 1170287ac01aSChristof Schmitt &erp_action->unit->status); 11711da177e4SLinus Torvalds break; 1172287ac01aSChristof Schmitt 1173287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1174287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 1175287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, 1176287ac01aSChristof Schmitt &erp_action->port->status); 11771da177e4SLinus Torvalds break; 1178287ac01aSChristof Schmitt 1179287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1180287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, 1181287ac01aSChristof Schmitt &erp_action->adapter->status); 11821da177e4SLinus Torvalds break; 11831da177e4SLinus Torvalds } 11841da177e4SLinus Torvalds } 11851da177e4SLinus Torvalds 1186287ac01aSChristof Schmitt static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) 1187287ac01aSChristof Schmitt { 1188287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 1189287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 1190287ac01aSChristof Schmitt struct zfcp_unit *unit = act->unit; 1191287ac01aSChristof Schmitt 1192287ac01aSChristof Schmitt switch (act->action) { 1193287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 1194a2fa0aedSChristof Schmitt if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { 119592d5193bSSwen Schillig zfcp_unit_get(unit); 119692d5193bSSwen Schillig if (scsi_queue_work(unit->port->adapter->scsi_host, 119792d5193bSSwen Schillig &unit->scsi_work) <= 0) 119892d5193bSSwen Schillig zfcp_unit_put(unit); 1199287ac01aSChristof Schmitt } 1200287ac01aSChristof Schmitt zfcp_unit_put(unit); 1201287ac01aSChristof Schmitt break; 1202287ac01aSChristof Schmitt 1203287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1204287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 1205a2fa0aedSChristof Schmitt if (result == ZFCP_ERP_SUCCEEDED) 1206a2fa0aedSChristof Schmitt zfcp_scsi_schedule_rport_register(port); 12071da177e4SLinus Torvalds zfcp_port_put(port); 12081da177e4SLinus Torvalds break; 1209287ac01aSChristof Schmitt 12101da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1211a2fa0aedSChristof Schmitt if (result == ZFCP_ERP_SUCCEEDED) { 1212bd43a42bSChristof Schmitt register_service_level(&adapter->service_level); 1213fca55b6fSSwen Schillig schedule_work(&adapter->scan_work); 1214a2fa0aedSChristof Schmitt } else 1215a2fa0aedSChristof Schmitt unregister_service_level(&adapter->service_level); 12161da177e4SLinus Torvalds zfcp_adapter_put(adapter); 12171da177e4SLinus Torvalds break; 12181da177e4SLinus Torvalds } 12191da177e4SLinus Torvalds } 12201da177e4SLinus Torvalds 1221287ac01aSChristof Schmitt static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) 1222287ac01aSChristof Schmitt { 1223287ac01aSChristof Schmitt switch (erp_action->action) { 1224287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1225287ac01aSChristof Schmitt return zfcp_erp_adapter_strategy(erp_action); 1226287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1227287ac01aSChristof Schmitt return zfcp_erp_port_forced_strategy(erp_action); 1228287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 1229287ac01aSChristof Schmitt return zfcp_erp_port_strategy(erp_action); 1230287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 1231287ac01aSChristof Schmitt return zfcp_erp_unit_strategy(erp_action); 1232287ac01aSChristof Schmitt } 1233287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 1234287ac01aSChristof Schmitt } 12351da177e4SLinus Torvalds 1236287ac01aSChristof Schmitt static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) 1237287ac01aSChristof Schmitt { 1238287ac01aSChristof Schmitt int retval; 1239287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 1240287ac01aSChristof Schmitt unsigned long flags; 1241287ac01aSChristof Schmitt 1242287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 1243287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 1244287ac01aSChristof Schmitt 1245287ac01aSChristof Schmitt zfcp_erp_strategy_check_fsfreq(erp_action); 1246287ac01aSChristof Schmitt 1247287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { 1248287ac01aSChristof Schmitt zfcp_erp_action_dequeue(erp_action); 1249287ac01aSChristof Schmitt retval = ZFCP_ERP_DISMISSED; 1250287ac01aSChristof Schmitt goto unlock; 1251287ac01aSChristof Schmitt } 1252287ac01aSChristof Schmitt 1253287ac01aSChristof Schmitt zfcp_erp_action_to_running(erp_action); 1254287ac01aSChristof Schmitt 1255287ac01aSChristof Schmitt /* no lock to allow for blocking operations */ 1256287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 1257287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 1258287ac01aSChristof Schmitt retval = zfcp_erp_strategy_do_action(erp_action); 1259287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 1260287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 1261287ac01aSChristof Schmitt 1262287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) 1263287ac01aSChristof Schmitt retval = ZFCP_ERP_CONTINUES; 1264287ac01aSChristof Schmitt 1265287ac01aSChristof Schmitt switch (retval) { 1266287ac01aSChristof Schmitt case ZFCP_ERP_NOMEM: 1267287ac01aSChristof Schmitt if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { 1268287ac01aSChristof Schmitt ++adapter->erp_low_mem_count; 1269287ac01aSChristof Schmitt erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; 1270287ac01aSChristof Schmitt } 1271287ac01aSChristof Schmitt if (adapter->erp_total_count == adapter->erp_low_mem_count) 12725ffd51a5SSwen Schillig _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL); 1273287ac01aSChristof Schmitt else { 1274287ac01aSChristof Schmitt zfcp_erp_strategy_memwait(erp_action); 1275287ac01aSChristof Schmitt retval = ZFCP_ERP_CONTINUES; 1276287ac01aSChristof Schmitt } 1277287ac01aSChristof Schmitt goto unlock; 1278287ac01aSChristof Schmitt 1279287ac01aSChristof Schmitt case ZFCP_ERP_CONTINUES: 1280287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { 1281287ac01aSChristof Schmitt --adapter->erp_low_mem_count; 1282287ac01aSChristof Schmitt erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; 1283287ac01aSChristof Schmitt } 1284287ac01aSChristof Schmitt goto unlock; 1285287ac01aSChristof Schmitt } 1286287ac01aSChristof Schmitt 1287287ac01aSChristof Schmitt retval = zfcp_erp_strategy_check_target(erp_action, retval); 1288287ac01aSChristof Schmitt zfcp_erp_action_dequeue(erp_action); 1289287ac01aSChristof Schmitt retval = zfcp_erp_strategy_statechange(erp_action, retval); 1290287ac01aSChristof Schmitt if (retval == ZFCP_ERP_EXIT) 1291287ac01aSChristof Schmitt goto unlock; 1292287ac01aSChristof Schmitt zfcp_erp_strategy_followup_actions(erp_action); 1293287ac01aSChristof Schmitt 1294287ac01aSChristof Schmitt unlock: 1295287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 1296287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 1297287ac01aSChristof Schmitt 1298287ac01aSChristof Schmitt if (retval != ZFCP_ERP_CONTINUES) 1299287ac01aSChristof Schmitt zfcp_erp_action_cleanup(erp_action, retval); 1300287ac01aSChristof Schmitt 1301287ac01aSChristof Schmitt return retval; 1302287ac01aSChristof Schmitt } 1303287ac01aSChristof Schmitt 1304287ac01aSChristof Schmitt static int zfcp_erp_thread(void *data) 1305287ac01aSChristof Schmitt { 1306287ac01aSChristof Schmitt struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; 1307287ac01aSChristof Schmitt struct list_head *next; 1308287ac01aSChristof Schmitt struct zfcp_erp_action *act; 1309287ac01aSChristof Schmitt unsigned long flags; 131006499facSHeiko Carstens int ignore; 1311287ac01aSChristof Schmitt 1312b9d3aed7SCornelia Huck daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); 1313287ac01aSChristof Schmitt /* Block all signals */ 1314287ac01aSChristof Schmitt siginitsetinv(¤t->blocked, 0); 1315287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); 1316287ac01aSChristof Schmitt wake_up(&adapter->erp_thread_wqh); 1317287ac01aSChristof Schmitt 1318287ac01aSChristof Schmitt while (!(atomic_read(&adapter->status) & 1319287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { 132094ab4b38SSwen Schillig 132194ab4b38SSwen Schillig zfcp_rec_dbf_event_thread_lock("erthrd1", adapter); 132294ab4b38SSwen Schillig ignore = down_interruptible(&adapter->erp_ready_sem); 132394ab4b38SSwen Schillig zfcp_rec_dbf_event_thread_lock("erthrd2", adapter); 132494ab4b38SSwen Schillig 1325287ac01aSChristof Schmitt write_lock_irqsave(&adapter->erp_lock, flags); 1326287ac01aSChristof Schmitt next = adapter->erp_ready_head.next; 1327287ac01aSChristof Schmitt write_unlock_irqrestore(&adapter->erp_lock, flags); 1328287ac01aSChristof Schmitt 1329287ac01aSChristof Schmitt if (next != &adapter->erp_ready_head) { 1330287ac01aSChristof Schmitt act = list_entry(next, struct zfcp_erp_action, list); 1331287ac01aSChristof Schmitt 1332287ac01aSChristof Schmitt /* there is more to come after dismission, no notify */ 1333287ac01aSChristof Schmitt if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) 1334287ac01aSChristof Schmitt zfcp_erp_wakeup(adapter); 1335287ac01aSChristof Schmitt } 1336287ac01aSChristof Schmitt } 1337287ac01aSChristof Schmitt 1338287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); 1339287ac01aSChristof Schmitt wake_up(&adapter->erp_thread_wqh); 1340287ac01aSChristof Schmitt 1341287ac01aSChristof Schmitt return 0; 1342287ac01aSChristof Schmitt } 1343287ac01aSChristof Schmitt 1344287ac01aSChristof Schmitt /** 1345287ac01aSChristof Schmitt * zfcp_erp_thread_setup - Start ERP thread for adapter 1346287ac01aSChristof Schmitt * @adapter: Adapter to start the ERP thread for 1347287ac01aSChristof Schmitt * 1348287ac01aSChristof Schmitt * Returns 0 on success or error code from kernel_thread() 1349287ac01aSChristof Schmitt */ 1350287ac01aSChristof Schmitt int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) 1351287ac01aSChristof Schmitt { 1352287ac01aSChristof Schmitt int retval; 1353287ac01aSChristof Schmitt 1354287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); 1355287ac01aSChristof Schmitt retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); 1356287ac01aSChristof Schmitt if (retval < 0) { 1357287ac01aSChristof Schmitt dev_err(&adapter->ccw_device->dev, 1358ff3b24faSChristof Schmitt "Creating an ERP thread for the FCP device failed.\n"); 1359287ac01aSChristof Schmitt return retval; 1360287ac01aSChristof Schmitt } 1361287ac01aSChristof Schmitt wait_event(adapter->erp_thread_wqh, 1362287ac01aSChristof Schmitt atomic_read(&adapter->status) & 1363287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); 1364287ac01aSChristof Schmitt return 0; 1365287ac01aSChristof Schmitt } 1366287ac01aSChristof Schmitt 1367287ac01aSChristof Schmitt /** 1368287ac01aSChristof Schmitt * zfcp_erp_thread_kill - Stop ERP thread. 1369287ac01aSChristof Schmitt * @adapter: Adapter where the ERP thread should be stopped. 1370287ac01aSChristof Schmitt * 1371287ac01aSChristof Schmitt * The caller of this routine ensures that the specified adapter has 1372287ac01aSChristof Schmitt * been shut down and that this operation has been completed. Thus, 1373287ac01aSChristof Schmitt * there are no pending erp_actions which would need to be handled 1374287ac01aSChristof Schmitt * here. 1375287ac01aSChristof Schmitt */ 1376287ac01aSChristof Schmitt void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) 1377287ac01aSChristof Schmitt { 1378287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); 1379287ac01aSChristof Schmitt up(&adapter->erp_ready_sem); 13805ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erthrk1", adapter); 1381287ac01aSChristof Schmitt 1382287ac01aSChristof Schmitt wait_event(adapter->erp_thread_wqh, 1383287ac01aSChristof Schmitt !(atomic_read(&adapter->status) & 1384287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)); 1385287ac01aSChristof Schmitt 1386287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, 1387287ac01aSChristof Schmitt &adapter->status); 1388287ac01aSChristof Schmitt } 1389287ac01aSChristof Schmitt 1390287ac01aSChristof Schmitt /** 1391287ac01aSChristof Schmitt * zfcp_erp_adapter_failed - Set adapter status to failed. 1392287ac01aSChristof Schmitt * @adapter: Failed adapter. 1393287ac01aSChristof Schmitt * @id: Event id for debug trace. 1394287ac01aSChristof Schmitt * @ref: Reference for debug trace. 1395287ac01aSChristof Schmitt */ 13965ffd51a5SSwen Schillig void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref) 1397287ac01aSChristof Schmitt { 1398287ac01aSChristof Schmitt zfcp_erp_modify_adapter_status(adapter, id, ref, 1399287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); 1400287ac01aSChristof Schmitt } 1401287ac01aSChristof Schmitt 1402287ac01aSChristof Schmitt /** 1403287ac01aSChristof Schmitt * zfcp_erp_port_failed - Set port status to failed. 1404287ac01aSChristof Schmitt * @port: Failed port. 1405287ac01aSChristof Schmitt * @id: Event id for debug trace. 1406287ac01aSChristof Schmitt * @ref: Reference for debug trace. 1407287ac01aSChristof Schmitt */ 14085ffd51a5SSwen Schillig void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref) 1409287ac01aSChristof Schmitt { 1410287ac01aSChristof Schmitt zfcp_erp_modify_port_status(port, id, ref, 1411287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); 1412287ac01aSChristof Schmitt } 1413287ac01aSChristof Schmitt 1414287ac01aSChristof Schmitt /** 1415287ac01aSChristof Schmitt * zfcp_erp_unit_failed - Set unit status to failed. 1416287ac01aSChristof Schmitt * @unit: Failed unit. 1417287ac01aSChristof Schmitt * @id: Event id for debug trace. 1418287ac01aSChristof Schmitt * @ref: Reference for debug trace. 1419287ac01aSChristof Schmitt */ 14205ffd51a5SSwen Schillig void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref) 1421287ac01aSChristof Schmitt { 1422287ac01aSChristof Schmitt zfcp_erp_modify_unit_status(unit, id, ref, 1423287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); 1424287ac01aSChristof Schmitt } 1425287ac01aSChristof Schmitt 1426287ac01aSChristof Schmitt /** 1427287ac01aSChristof Schmitt * zfcp_erp_wait - wait for completion of error recovery on an adapter 1428287ac01aSChristof Schmitt * @adapter: adapter for which to wait for completion of its error recovery 1429287ac01aSChristof Schmitt */ 1430287ac01aSChristof Schmitt void zfcp_erp_wait(struct zfcp_adapter *adapter) 1431287ac01aSChristof Schmitt { 1432287ac01aSChristof Schmitt wait_event(adapter->erp_done_wqh, 1433287ac01aSChristof Schmitt !(atomic_read(&adapter->status) & 1434287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_PENDING)); 1435287ac01aSChristof Schmitt } 1436287ac01aSChristof Schmitt 1437287ac01aSChristof Schmitt /** 1438287ac01aSChristof Schmitt * zfcp_erp_modify_adapter_status - change adapter status bits 1439287ac01aSChristof Schmitt * @adapter: adapter to change the status 1440287ac01aSChristof Schmitt * @id: id for the debug trace 1441287ac01aSChristof Schmitt * @ref: reference for the debug trace 1442287ac01aSChristof Schmitt * @mask: status bits to change 1443287ac01aSChristof Schmitt * @set_or_clear: ZFCP_SET or ZFCP_CLEAR 1444287ac01aSChristof Schmitt * 1445287ac01aSChristof Schmitt * Changes in common status bits are propagated to attached ports and units. 1446287ac01aSChristof Schmitt */ 14475ffd51a5SSwen Schillig void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, 1448287ac01aSChristof Schmitt void *ref, u32 mask, int set_or_clear) 14491da177e4SLinus Torvalds { 14501da177e4SLinus Torvalds struct zfcp_port *port; 1451287ac01aSChristof Schmitt u32 common_mask = mask & ZFCP_COMMON_FLAGS; 14521da177e4SLinus Torvalds 1453287ac01aSChristof Schmitt if (set_or_clear == ZFCP_SET) { 1454287ac01aSChristof Schmitt if (status_change_set(mask, &adapter->status)) 1455287ac01aSChristof Schmitt zfcp_rec_dbf_event_adapter(id, ref, adapter); 1456287ac01aSChristof Schmitt atomic_set_mask(mask, &adapter->status); 1457287ac01aSChristof Schmitt } else { 1458287ac01aSChristof Schmitt if (status_change_clear(mask, &adapter->status)) 1459287ac01aSChristof Schmitt zfcp_rec_dbf_event_adapter(id, ref, adapter); 1460287ac01aSChristof Schmitt atomic_clear_mask(mask, &adapter->status); 1461287ac01aSChristof Schmitt if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) 1462287ac01aSChristof Schmitt atomic_set(&adapter->erp_counter, 0); 14631da177e4SLinus Torvalds } 14641da177e4SLinus Torvalds 1465287ac01aSChristof Schmitt if (common_mask) 1466287ac01aSChristof Schmitt list_for_each_entry(port, &adapter->port_list_head, list) 1467287ac01aSChristof Schmitt zfcp_erp_modify_port_status(port, id, ref, common_mask, 1468287ac01aSChristof Schmitt set_or_clear); 1469287ac01aSChristof Schmitt } 1470287ac01aSChristof Schmitt 1471287ac01aSChristof Schmitt /** 1472287ac01aSChristof Schmitt * zfcp_erp_modify_port_status - change port status bits 1473287ac01aSChristof Schmitt * @port: port to change the status bits 1474287ac01aSChristof Schmitt * @id: id for the debug trace 1475287ac01aSChristof Schmitt * @ref: reference for the debug trace 1476287ac01aSChristof Schmitt * @mask: status bits to change 1477287ac01aSChristof Schmitt * @set_or_clear: ZFCP_SET or ZFCP_CLEAR 1478287ac01aSChristof Schmitt * 1479287ac01aSChristof Schmitt * Changes in common status bits are propagated to attached units. 1480287ac01aSChristof Schmitt */ 14815ffd51a5SSwen Schillig void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, 1482287ac01aSChristof Schmitt u32 mask, int set_or_clear) 14831da177e4SLinus Torvalds { 14841da177e4SLinus Torvalds struct zfcp_unit *unit; 1485287ac01aSChristof Schmitt u32 common_mask = mask & ZFCP_COMMON_FLAGS; 14861da177e4SLinus Torvalds 1487287ac01aSChristof Schmitt if (set_or_clear == ZFCP_SET) { 1488287ac01aSChristof Schmitt if (status_change_set(mask, &port->status)) 1489287ac01aSChristof Schmitt zfcp_rec_dbf_event_port(id, ref, port); 1490287ac01aSChristof Schmitt atomic_set_mask(mask, &port->status); 1491287ac01aSChristof Schmitt } else { 1492287ac01aSChristof Schmitt if (status_change_clear(mask, &port->status)) 1493287ac01aSChristof Schmitt zfcp_rec_dbf_event_port(id, ref, port); 1494287ac01aSChristof Schmitt atomic_clear_mask(mask, &port->status); 1495287ac01aSChristof Schmitt if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) 1496287ac01aSChristof Schmitt atomic_set(&port->erp_counter, 0); 1497287ac01aSChristof Schmitt } 1498287ac01aSChristof Schmitt 1499287ac01aSChristof Schmitt if (common_mask) 15001da177e4SLinus Torvalds list_for_each_entry(unit, &port->unit_list_head, list) 1501287ac01aSChristof Schmitt zfcp_erp_modify_unit_status(unit, id, ref, common_mask, 1502287ac01aSChristof Schmitt set_or_clear); 15031da177e4SLinus Torvalds } 15041da177e4SLinus Torvalds 1505287ac01aSChristof Schmitt /** 1506287ac01aSChristof Schmitt * zfcp_erp_modify_unit_status - change unit status bits 1507287ac01aSChristof Schmitt * @unit: unit to change the status bits 1508287ac01aSChristof Schmitt * @id: id for the debug trace 1509287ac01aSChristof Schmitt * @ref: reference for the debug trace 1510287ac01aSChristof Schmitt * @mask: status bits to change 1511287ac01aSChristof Schmitt * @set_or_clear: ZFCP_SET or ZFCP_CLEAR 1512287ac01aSChristof Schmitt */ 15135ffd51a5SSwen Schillig void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, 1514287ac01aSChristof Schmitt u32 mask, int set_or_clear) 15151da177e4SLinus Torvalds { 1516287ac01aSChristof Schmitt if (set_or_clear == ZFCP_SET) { 1517287ac01aSChristof Schmitt if (status_change_set(mask, &unit->status)) 1518287ac01aSChristof Schmitt zfcp_rec_dbf_event_unit(id, ref, unit); 1519287ac01aSChristof Schmitt atomic_set_mask(mask, &unit->status); 1520287ac01aSChristof Schmitt } else { 1521287ac01aSChristof Schmitt if (status_change_clear(mask, &unit->status)) 1522287ac01aSChristof Schmitt zfcp_rec_dbf_event_unit(id, ref, unit); 1523287ac01aSChristof Schmitt atomic_clear_mask(mask, &unit->status); 1524287ac01aSChristof Schmitt if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { 1525287ac01aSChristof Schmitt atomic_set(&unit->erp_counter, 0); 1526287ac01aSChristof Schmitt } 1527287ac01aSChristof Schmitt } 15281da177e4SLinus Torvalds } 15291da177e4SLinus Torvalds 1530287ac01aSChristof Schmitt /** 1531287ac01aSChristof Schmitt * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP 1532287ac01aSChristof Schmitt * @port: The "boxed" port. 1533287ac01aSChristof Schmitt * @id: The debug trace id. 1534287ac01aSChristof Schmitt * @id: Reference for the debug trace. 1535287ac01aSChristof Schmitt */ 15365ffd51a5SSwen Schillig void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref) 1537d736a27bSAndreas Herrmann { 1538d736a27bSAndreas Herrmann unsigned long flags; 1539d736a27bSAndreas Herrmann 1540d736a27bSAndreas Herrmann read_lock_irqsave(&zfcp_data.config_lock, flags); 1541698ec016SMartin Peschke zfcp_erp_modify_port_status(port, id, ref, 1542698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); 1543d736a27bSAndreas Herrmann read_unlock_irqrestore(&zfcp_data.config_lock, flags); 15449467a9b3SMartin Peschke zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1545d736a27bSAndreas Herrmann } 1546d736a27bSAndreas Herrmann 1547287ac01aSChristof Schmitt /** 1548287ac01aSChristof Schmitt * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP 1549287ac01aSChristof Schmitt * @port: The "boxed" unit. 1550287ac01aSChristof Schmitt * @id: The debug trace id. 1551287ac01aSChristof Schmitt * @id: Reference for the debug trace. 1552287ac01aSChristof Schmitt */ 15535ffd51a5SSwen Schillig void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref) 1554d736a27bSAndreas Herrmann { 1555698ec016SMartin Peschke zfcp_erp_modify_unit_status(unit, id, ref, 1556698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); 15579467a9b3SMartin Peschke zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1558d736a27bSAndreas Herrmann } 1559d736a27bSAndreas Herrmann 1560287ac01aSChristof Schmitt /** 1561287ac01aSChristof Schmitt * zfcp_erp_port_access_denied - Adapter denied access to port. 1562287ac01aSChristof Schmitt * @port: port where access has been denied 1563287ac01aSChristof Schmitt * @id: id for debug trace 1564287ac01aSChristof Schmitt * @ref: reference for debug trace 1565287ac01aSChristof Schmitt * 1566287ac01aSChristof Schmitt * Since the adapter has denied access, stop using the port and the 1567287ac01aSChristof Schmitt * attached units. 1568287ac01aSChristof Schmitt */ 15695ffd51a5SSwen Schillig void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref) 15701da177e4SLinus Torvalds { 15711da177e4SLinus Torvalds unsigned long flags; 15721da177e4SLinus Torvalds 15731da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 1574698ec016SMartin Peschke zfcp_erp_modify_port_status(port, id, ref, 1575d736a27bSAndreas Herrmann ZFCP_STATUS_COMMON_ERP_FAILED | 1576698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); 15771da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 15781da177e4SLinus Torvalds } 15791da177e4SLinus Torvalds 1580287ac01aSChristof Schmitt /** 1581287ac01aSChristof Schmitt * zfcp_erp_unit_access_denied - Adapter denied access to unit. 1582287ac01aSChristof Schmitt * @unit: unit where access has been denied 1583287ac01aSChristof Schmitt * @id: id for debug trace 1584287ac01aSChristof Schmitt * @ref: reference for debug trace 1585287ac01aSChristof Schmitt * 1586287ac01aSChristof Schmitt * Since the adapter has denied access, stop using the unit. 1587287ac01aSChristof Schmitt */ 15885ffd51a5SSwen Schillig void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref) 15891da177e4SLinus Torvalds { 1590698ec016SMartin Peschke zfcp_erp_modify_unit_status(unit, id, ref, 1591d736a27bSAndreas Herrmann ZFCP_STATUS_COMMON_ERP_FAILED | 1592698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); 15931da177e4SLinus Torvalds } 15941da177e4SLinus Torvalds 15955ffd51a5SSwen Schillig static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id, 1596287ac01aSChristof Schmitt void *ref) 1597287ac01aSChristof Schmitt { 1598287ac01aSChristof Schmitt int status = atomic_read(&unit->status); 1599287ac01aSChristof Schmitt if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | 1600287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ACCESS_BOXED))) 1601287ac01aSChristof Schmitt return; 1602287ac01aSChristof Schmitt 1603287ac01aSChristof Schmitt zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1604287ac01aSChristof Schmitt } 1605287ac01aSChristof Schmitt 16065ffd51a5SSwen Schillig static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id, 1607287ac01aSChristof Schmitt void *ref) 1608287ac01aSChristof Schmitt { 1609287ac01aSChristof Schmitt struct zfcp_unit *unit; 1610287ac01aSChristof Schmitt int status = atomic_read(&port->status); 1611287ac01aSChristof Schmitt 1612287ac01aSChristof Schmitt if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | 1613287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ACCESS_BOXED))) { 1614287ac01aSChristof Schmitt list_for_each_entry(unit, &port->unit_list_head, list) 1615287ac01aSChristof Schmitt zfcp_erp_unit_access_changed(unit, id, ref); 1616287ac01aSChristof Schmitt return; 1617287ac01aSChristof Schmitt } 1618287ac01aSChristof Schmitt 1619287ac01aSChristof Schmitt zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1620287ac01aSChristof Schmitt } 1621287ac01aSChristof Schmitt 1622287ac01aSChristof Schmitt /** 1623287ac01aSChristof Schmitt * zfcp_erp_adapter_access_changed - Process change in adapter ACT 1624287ac01aSChristof Schmitt * @adapter: Adapter where the Access Control Table (ACT) changed 1625287ac01aSChristof Schmitt * @id: Id for debug trace 1626287ac01aSChristof Schmitt * @ref: Reference for debug trace 1627287ac01aSChristof Schmitt */ 16285ffd51a5SSwen Schillig void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id, 16291f6f7129SMartin Peschke void *ref) 16301da177e4SLinus Torvalds { 16311da177e4SLinus Torvalds struct zfcp_port *port; 16321da177e4SLinus Torvalds unsigned long flags; 16331da177e4SLinus Torvalds 1634aef4a983SMaxim Shchetynin if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) 1635aef4a983SMaxim Shchetynin return; 1636aef4a983SMaxim Shchetynin 16371da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 16381da177e4SLinus Torvalds list_for_each_entry(port, &adapter->port_list_head, list) 16399467a9b3SMartin Peschke zfcp_erp_port_access_changed(port, id, ref); 16401da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 16411da177e4SLinus Torvalds } 1642