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_PORT_OPENING = 0x0800, 30287ac01aSChristof Schmitt ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, 31287ac01aSChristof Schmitt ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, 32287ac01aSChristof Schmitt }; 331da177e4SLinus Torvalds 34287ac01aSChristof Schmitt enum zfcp_erp_act_type { 35287ac01aSChristof Schmitt ZFCP_ERP_ACTION_REOPEN_UNIT = 1, 36287ac01aSChristof Schmitt ZFCP_ERP_ACTION_REOPEN_PORT = 2, 37287ac01aSChristof Schmitt ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, 38287ac01aSChristof Schmitt ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, 39287ac01aSChristof Schmitt }; 401da177e4SLinus Torvalds 41287ac01aSChristof Schmitt enum zfcp_erp_act_state { 42287ac01aSChristof Schmitt ZFCP_ERP_ACTION_RUNNING = 1, 43287ac01aSChristof Schmitt ZFCP_ERP_ACTION_READY = 2, 44287ac01aSChristof Schmitt }; 451da177e4SLinus Torvalds 46287ac01aSChristof Schmitt enum zfcp_erp_act_result { 47287ac01aSChristof Schmitt ZFCP_ERP_SUCCEEDED = 0, 48287ac01aSChristof Schmitt ZFCP_ERP_FAILED = 1, 49287ac01aSChristof Schmitt ZFCP_ERP_CONTINUES = 2, 50287ac01aSChristof Schmitt ZFCP_ERP_EXIT = 3, 51287ac01aSChristof Schmitt ZFCP_ERP_DISMISSED = 4, 52287ac01aSChristof Schmitt ZFCP_ERP_NOMEM = 5, 53287ac01aSChristof Schmitt }; 541da177e4SLinus Torvalds 55287ac01aSChristof Schmitt static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) 562abbe866SAndreas Herrmann { 575ffd51a5SSwen Schillig zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL, 58287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_UNBLOCKED | mask, 59287ac01aSChristof Schmitt ZFCP_CLEAR); 602abbe866SAndreas Herrmann } 611da177e4SLinus Torvalds 62287ac01aSChristof Schmitt static int zfcp_erp_action_exists(struct zfcp_erp_action *act) 631da177e4SLinus Torvalds { 64287ac01aSChristof Schmitt struct zfcp_erp_action *curr_act; 65287ac01aSChristof Schmitt 66287ac01aSChristof Schmitt list_for_each_entry(curr_act, &act->adapter->erp_running_head, list) 67287ac01aSChristof Schmitt if (act == curr_act) 68287ac01aSChristof Schmitt return ZFCP_ERP_ACTION_RUNNING; 69287ac01aSChristof Schmitt return 0; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 72287ac01aSChristof Schmitt static void zfcp_erp_action_ready(struct zfcp_erp_action *act) 731da177e4SLinus Torvalds { 74287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 75287ac01aSChristof Schmitt 76287ac01aSChristof Schmitt list_move(&act->list, &act->adapter->erp_ready_head); 775ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("erardy1", act); 78287ac01aSChristof Schmitt up(&adapter->erp_ready_sem); 795ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread("erardy2", adapter); 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 82287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) 83287ac01aSChristof Schmitt { 84287ac01aSChristof Schmitt act->status |= ZFCP_STATUS_ERP_DISMISSED; 85287ac01aSChristof Schmitt if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING) 86287ac01aSChristof Schmitt zfcp_erp_action_ready(act); 87287ac01aSChristof Schmitt } 88287ac01aSChristof Schmitt 89287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) 90287ac01aSChristof Schmitt { 91287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE) 92287ac01aSChristof Schmitt zfcp_erp_action_dismiss(&unit->erp_action); 93287ac01aSChristof Schmitt } 94287ac01aSChristof Schmitt 95287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) 96287ac01aSChristof Schmitt { 97287ac01aSChristof Schmitt struct zfcp_unit *unit; 98287ac01aSChristof Schmitt 99287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) 100287ac01aSChristof Schmitt zfcp_erp_action_dismiss(&port->erp_action); 101287ac01aSChristof Schmitt else 102287ac01aSChristof Schmitt list_for_each_entry(unit, &port->unit_list_head, list) 103287ac01aSChristof Schmitt zfcp_erp_action_dismiss_unit(unit); 104287ac01aSChristof Schmitt } 105287ac01aSChristof Schmitt 106287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) 107287ac01aSChristof Schmitt { 108287ac01aSChristof Schmitt struct zfcp_port *port; 109287ac01aSChristof Schmitt 110287ac01aSChristof Schmitt if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE) 111287ac01aSChristof Schmitt zfcp_erp_action_dismiss(&adapter->erp_action); 112287ac01aSChristof Schmitt else 113287ac01aSChristof Schmitt list_for_each_entry(port, &adapter->port_list_head, list) 114287ac01aSChristof Schmitt zfcp_erp_action_dismiss_port(port); 115287ac01aSChristof Schmitt } 116287ac01aSChristof Schmitt 117287ac01aSChristof Schmitt static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, 118287ac01aSChristof Schmitt struct zfcp_port *port, 119287ac01aSChristof Schmitt struct zfcp_unit *unit) 120287ac01aSChristof Schmitt { 121287ac01aSChristof Schmitt int need = want; 122287ac01aSChristof Schmitt int u_status, p_status, a_status; 123287ac01aSChristof Schmitt 124287ac01aSChristof Schmitt switch (want) { 125287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 126287ac01aSChristof Schmitt u_status = atomic_read(&unit->status); 127287ac01aSChristof Schmitt if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE) 128287ac01aSChristof Schmitt return 0; 129287ac01aSChristof Schmitt p_status = atomic_read(&port->status); 130287ac01aSChristof Schmitt if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || 131287ac01aSChristof Schmitt p_status & ZFCP_STATUS_COMMON_ERP_FAILED) 132287ac01aSChristof Schmitt return 0; 133287ac01aSChristof Schmitt if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) 134287ac01aSChristof Schmitt need = ZFCP_ERP_ACTION_REOPEN_PORT; 135287ac01aSChristof Schmitt /* fall through */ 136287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 137287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 138287ac01aSChristof Schmitt p_status = atomic_read(&port->status); 139287ac01aSChristof Schmitt if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE) 140287ac01aSChristof Schmitt return 0; 141287ac01aSChristof Schmitt a_status = atomic_read(&adapter->status); 142287ac01aSChristof Schmitt if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || 143287ac01aSChristof Schmitt a_status & ZFCP_STATUS_COMMON_ERP_FAILED) 144287ac01aSChristof Schmitt return 0; 145287ac01aSChristof Schmitt if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) 146287ac01aSChristof Schmitt need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; 147287ac01aSChristof Schmitt /* fall through */ 148287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 149287ac01aSChristof Schmitt a_status = atomic_read(&adapter->status); 150287ac01aSChristof Schmitt if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) 151287ac01aSChristof Schmitt return 0; 152287ac01aSChristof Schmitt } 153287ac01aSChristof Schmitt 154287ac01aSChristof Schmitt return need; 155287ac01aSChristof Schmitt } 156287ac01aSChristof Schmitt 157287ac01aSChristof Schmitt static struct zfcp_erp_action *zfcp_erp_setup_act(int need, 158287ac01aSChristof Schmitt struct zfcp_adapter *adapter, 159287ac01aSChristof Schmitt struct zfcp_port *port, 160287ac01aSChristof Schmitt struct zfcp_unit *unit) 161287ac01aSChristof Schmitt { 162287ac01aSChristof Schmitt struct zfcp_erp_action *erp_action; 163287ac01aSChristof Schmitt u32 status = 0; 164287ac01aSChristof Schmitt 165287ac01aSChristof Schmitt switch (need) { 166287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 167287ac01aSChristof Schmitt zfcp_unit_get(unit); 168287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); 169287ac01aSChristof Schmitt erp_action = &unit->erp_action; 170287ac01aSChristof Schmitt if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) 171287ac01aSChristof Schmitt status = ZFCP_STATUS_ERP_CLOSE_ONLY; 172287ac01aSChristof Schmitt break; 173287ac01aSChristof Schmitt 174287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 175287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 176287ac01aSChristof Schmitt zfcp_port_get(port); 177287ac01aSChristof Schmitt zfcp_erp_action_dismiss_port(port); 178287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); 179287ac01aSChristof Schmitt erp_action = &port->erp_action; 180287ac01aSChristof Schmitt if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) 181287ac01aSChristof Schmitt status = ZFCP_STATUS_ERP_CLOSE_ONLY; 182287ac01aSChristof Schmitt break; 183287ac01aSChristof Schmitt 184287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 185287ac01aSChristof Schmitt zfcp_adapter_get(adapter); 186287ac01aSChristof Schmitt zfcp_erp_action_dismiss_adapter(adapter); 187287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); 188287ac01aSChristof Schmitt erp_action = &adapter->erp_action; 189287ac01aSChristof Schmitt if (!(atomic_read(&adapter->status) & 190287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_RUNNING)) 191287ac01aSChristof Schmitt status = ZFCP_STATUS_ERP_CLOSE_ONLY; 192287ac01aSChristof Schmitt break; 193287ac01aSChristof Schmitt 194287ac01aSChristof Schmitt default: 195287ac01aSChristof Schmitt return NULL; 196287ac01aSChristof Schmitt } 197287ac01aSChristof Schmitt 198287ac01aSChristof Schmitt memset(erp_action, 0, sizeof(struct zfcp_erp_action)); 199287ac01aSChristof Schmitt erp_action->adapter = adapter; 200287ac01aSChristof Schmitt erp_action->port = port; 201287ac01aSChristof Schmitt erp_action->unit = unit; 202287ac01aSChristof Schmitt erp_action->action = need; 203287ac01aSChristof Schmitt erp_action->status = status; 204287ac01aSChristof Schmitt 205287ac01aSChristof Schmitt return erp_action; 206287ac01aSChristof Schmitt } 207287ac01aSChristof Schmitt 208287ac01aSChristof Schmitt static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, 209287ac01aSChristof Schmitt struct zfcp_port *port, 2105ffd51a5SSwen Schillig struct zfcp_unit *unit, char *id, void *ref) 211287ac01aSChristof Schmitt { 212287ac01aSChristof Schmitt int retval = 1, need; 213287ac01aSChristof Schmitt struct zfcp_erp_action *act = NULL; 214287ac01aSChristof Schmitt 215287ac01aSChristof Schmitt if (!(atomic_read(&adapter->status) & 216287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)) 217287ac01aSChristof Schmitt return -EIO; 218287ac01aSChristof Schmitt 219287ac01aSChristof Schmitt need = zfcp_erp_required_act(want, adapter, port, unit); 220287ac01aSChristof Schmitt if (!need) 221287ac01aSChristof Schmitt goto out; 222287ac01aSChristof Schmitt 223287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); 224287ac01aSChristof Schmitt act = zfcp_erp_setup_act(need, adapter, port, unit); 225287ac01aSChristof Schmitt if (!act) 226287ac01aSChristof Schmitt goto out; 227287ac01aSChristof Schmitt ++adapter->erp_total_count; 228287ac01aSChristof Schmitt list_add_tail(&act->list, &adapter->erp_ready_head); 229287ac01aSChristof Schmitt up(&adapter->erp_ready_sem); 2305ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread("eracte1", adapter); 231287ac01aSChristof Schmitt retval = 0; 232287ac01aSChristof Schmitt out: 233287ac01aSChristof Schmitt zfcp_rec_dbf_event_trigger(id, ref, want, need, act, 234287ac01aSChristof Schmitt adapter, port, unit); 235287ac01aSChristof Schmitt return retval; 236287ac01aSChristof Schmitt } 237287ac01aSChristof Schmitt 238287ac01aSChristof Schmitt static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, 2395ffd51a5SSwen Schillig int clear_mask, char *id, void *ref) 2401da177e4SLinus Torvalds { 2411da177e4SLinus Torvalds zfcp_erp_adapter_block(adapter, clear_mask); 242a2fa0aedSChristof Schmitt zfcp_scsi_schedule_rports_block(adapter); 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds /* ensure propagation of failed status to new devices */ 245287ac01aSChristof Schmitt if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 2465ffd51a5SSwen Schillig zfcp_erp_adapter_failed(adapter, "erareo1", NULL); 247287ac01aSChristof Schmitt return -EIO; 2481da177e4SLinus Torvalds } 249287ac01aSChristof Schmitt return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, 2509467a9b3SMartin Peschke adapter, NULL, NULL, id, ref); 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds /** 254287ac01aSChristof Schmitt * zfcp_erp_adapter_reopen - Reopen adapter. 255287ac01aSChristof Schmitt * @adapter: Adapter to reopen. 256287ac01aSChristof Schmitt * @clear: Status flags to clear. 257287ac01aSChristof Schmitt * @id: Id for debug trace event. 258287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 2591da177e4SLinus Torvalds */ 260287ac01aSChristof Schmitt void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, 2615ffd51a5SSwen Schillig char *id, void *ref) 262287ac01aSChristof Schmitt { 263287ac01aSChristof Schmitt unsigned long flags; 264287ac01aSChristof Schmitt 265287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 266287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 267287ac01aSChristof Schmitt _zfcp_erp_adapter_reopen(adapter, clear, id, ref); 268287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 269287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 270287ac01aSChristof Schmitt } 271287ac01aSChristof Schmitt 272287ac01aSChristof Schmitt /** 273287ac01aSChristof Schmitt * zfcp_erp_adapter_shutdown - Shutdown adapter. 274287ac01aSChristof Schmitt * @adapter: Adapter to shut down. 275287ac01aSChristof Schmitt * @clear: Status flags to clear. 276287ac01aSChristof Schmitt * @id: Id for debug trace event. 277287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 278287ac01aSChristof Schmitt */ 279287ac01aSChristof Schmitt void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, 2805ffd51a5SSwen Schillig char *id, void *ref) 281287ac01aSChristof Schmitt { 282287ac01aSChristof Schmitt int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 283287ac01aSChristof Schmitt zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); 284287ac01aSChristof Schmitt } 285287ac01aSChristof Schmitt 286287ac01aSChristof Schmitt /** 287287ac01aSChristof Schmitt * zfcp_erp_port_shutdown - Shutdown port 288287ac01aSChristof Schmitt * @port: Port to shut down. 289287ac01aSChristof Schmitt * @clear: Status flags to clear. 290287ac01aSChristof Schmitt * @id: Id for debug trace event. 291287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 292287ac01aSChristof Schmitt */ 2935ffd51a5SSwen Schillig void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id, 2945ffd51a5SSwen Schillig void *ref) 295287ac01aSChristof Schmitt { 296287ac01aSChristof Schmitt int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 297287ac01aSChristof Schmitt zfcp_erp_port_reopen(port, clear | flags, id, ref); 298287ac01aSChristof Schmitt } 299287ac01aSChristof Schmitt 300287ac01aSChristof Schmitt /** 301287ac01aSChristof Schmitt * zfcp_erp_unit_shutdown - Shutdown unit 302287ac01aSChristof Schmitt * @unit: Unit to shut down. 303287ac01aSChristof Schmitt * @clear: Status flags to clear. 304287ac01aSChristof Schmitt * @id: Id for debug trace event. 305287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 306287ac01aSChristof Schmitt */ 3075ffd51a5SSwen Schillig void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id, 3085ffd51a5SSwen Schillig void *ref) 309287ac01aSChristof Schmitt { 310287ac01aSChristof Schmitt int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; 311287ac01aSChristof Schmitt zfcp_erp_unit_reopen(unit, clear | flags, id, ref); 312287ac01aSChristof Schmitt } 313287ac01aSChristof Schmitt 314287ac01aSChristof Schmitt static void zfcp_erp_port_block(struct zfcp_port *port, int clear) 315287ac01aSChristof Schmitt { 3165ffd51a5SSwen Schillig zfcp_erp_modify_port_status(port, "erpblk1", NULL, 317287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_UNBLOCKED | clear, 318287ac01aSChristof Schmitt ZFCP_CLEAR); 319287ac01aSChristof Schmitt } 320287ac01aSChristof Schmitt 321287ac01aSChristof Schmitt static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, 3225ffd51a5SSwen Schillig int clear, char *id, void *ref) 323287ac01aSChristof Schmitt { 324287ac01aSChristof Schmitt zfcp_erp_port_block(port, clear); 325a2fa0aedSChristof Schmitt zfcp_scsi_schedule_rport_block(port); 326287ac01aSChristof Schmitt 327287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) 328287ac01aSChristof Schmitt return; 329287ac01aSChristof Schmitt 330287ac01aSChristof Schmitt zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, 331287ac01aSChristof Schmitt port->adapter, port, NULL, id, ref); 332287ac01aSChristof Schmitt } 333287ac01aSChristof Schmitt 334287ac01aSChristof Schmitt /** 335287ac01aSChristof Schmitt * zfcp_erp_port_forced_reopen - Forced close of port and open again 336287ac01aSChristof Schmitt * @port: Port to force close and to reopen. 337287ac01aSChristof Schmitt * @id: Id for debug trace event. 338287ac01aSChristof Schmitt * @ref: Reference for debug trace event. 339287ac01aSChristof Schmitt */ 3405ffd51a5SSwen Schillig void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id, 3411f6f7129SMartin Peschke void *ref) 3421da177e4SLinus Torvalds { 3431da177e4SLinus Torvalds unsigned long flags; 3441da177e4SLinus Torvalds struct zfcp_adapter *adapter = port->adapter; 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 3471da177e4SLinus Torvalds write_lock(&adapter->erp_lock); 348287ac01aSChristof Schmitt _zfcp_erp_port_forced_reopen(port, clear, id, ref); 349287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 350287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 351287ac01aSChristof Schmitt } 352287ac01aSChristof Schmitt 3535ffd51a5SSwen Schillig static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, 354287ac01aSChristof Schmitt void *ref) 355287ac01aSChristof Schmitt { 356287ac01aSChristof Schmitt zfcp_erp_port_block(port, clear); 357a2fa0aedSChristof Schmitt zfcp_scsi_schedule_rport_block(port); 358287ac01aSChristof Schmitt 359287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 360287ac01aSChristof Schmitt /* ensure propagation of failed status to new devices */ 3615ffd51a5SSwen Schillig zfcp_erp_port_failed(port, "erpreo1", NULL); 362287ac01aSChristof Schmitt return -EIO; 363287ac01aSChristof Schmitt } 364287ac01aSChristof Schmitt 365287ac01aSChristof Schmitt return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, 366287ac01aSChristof Schmitt port->adapter, port, NULL, id, ref); 367287ac01aSChristof Schmitt } 368287ac01aSChristof Schmitt 369287ac01aSChristof Schmitt /** 370287ac01aSChristof Schmitt * zfcp_erp_port_reopen - trigger remote port recovery 371287ac01aSChristof Schmitt * @port: port to recover 372287ac01aSChristof Schmitt * @clear_mask: flags in port status to be cleared 373287ac01aSChristof Schmitt * 374287ac01aSChristof Schmitt * Returns 0 if recovery has been triggered, < 0 if not. 375287ac01aSChristof Schmitt */ 3765ffd51a5SSwen Schillig int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref) 377287ac01aSChristof Schmitt { 378287ac01aSChristof Schmitt unsigned long flags; 379287ac01aSChristof Schmitt int retval; 380287ac01aSChristof Schmitt struct zfcp_adapter *adapter = port->adapter; 381287ac01aSChristof Schmitt 382287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 383287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 384287ac01aSChristof Schmitt retval = _zfcp_erp_port_reopen(port, clear, id, ref); 3851da177e4SLinus Torvalds write_unlock(&adapter->erp_lock); 3861da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds return retval; 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds 391287ac01aSChristof Schmitt static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) 3921da177e4SLinus Torvalds { 3935ffd51a5SSwen Schillig zfcp_erp_modify_unit_status(unit, "erublk1", NULL, 394287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, 395287ac01aSChristof Schmitt ZFCP_CLEAR); 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds 3985ffd51a5SSwen Schillig static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, 399287ac01aSChristof Schmitt void *ref) 400287ac01aSChristof Schmitt { 401287ac01aSChristof Schmitt struct zfcp_adapter *adapter = unit->port->adapter; 402287ac01aSChristof Schmitt 403287ac01aSChristof Schmitt zfcp_erp_unit_block(unit, clear); 404287ac01aSChristof Schmitt 405287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) 406287ac01aSChristof Schmitt return; 407287ac01aSChristof Schmitt 408287ac01aSChristof Schmitt zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, 4099467a9b3SMartin Peschke adapter, unit->port, unit, id, ref); 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds /** 4131da177e4SLinus Torvalds * zfcp_erp_unit_reopen - initiate reopen of a unit 4141da177e4SLinus Torvalds * @unit: unit to be reopened 4151da177e4SLinus Torvalds * @clear_mask: specifies flags in unit status to be cleared 4161da177e4SLinus Torvalds * Return: 0 on success, < 0 on error 4171da177e4SLinus Torvalds */ 4185ffd51a5SSwen Schillig void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, 4195ffd51a5SSwen Schillig void *ref) 4201da177e4SLinus Torvalds { 4211da177e4SLinus Torvalds unsigned long flags; 422287ac01aSChristof Schmitt struct zfcp_port *port = unit->port; 423287ac01aSChristof Schmitt struct zfcp_adapter *adapter = port->adapter; 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 4261da177e4SLinus Torvalds write_lock(&adapter->erp_lock); 427287ac01aSChristof Schmitt _zfcp_erp_unit_reopen(unit, clear, id, ref); 4281da177e4SLinus Torvalds write_unlock(&adapter->erp_lock); 4291da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds 432287ac01aSChristof Schmitt static int status_change_set(unsigned long mask, atomic_t *status) 4331da177e4SLinus Torvalds { 434287ac01aSChristof Schmitt return (atomic_read(status) ^ mask) & mask; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds 437287ac01aSChristof Schmitt static int status_change_clear(unsigned long mask, atomic_t *status) 438698ec016SMartin Peschke { 439287ac01aSChristof Schmitt return atomic_read(status) & mask; 440698ec016SMartin Peschke } 441698ec016SMartin Peschke 442f6c0e7a7SAndreas Herrmann static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) 4431da177e4SLinus Torvalds { 444287ac01aSChristof Schmitt if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) 4455ffd51a5SSwen Schillig zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter); 446287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds 449287ac01aSChristof Schmitt static void zfcp_erp_port_unblock(struct zfcp_port *port) 4501da177e4SLinus Torvalds { 451287ac01aSChristof Schmitt if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) 4525ffd51a5SSwen Schillig zfcp_rec_dbf_event_port("erpubl1", NULL, port); 453287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds 456287ac01aSChristof Schmitt static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) 4571da177e4SLinus Torvalds { 458287ac01aSChristof Schmitt if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) 4595ffd51a5SSwen Schillig zfcp_rec_dbf_event_unit("eruubl1", NULL, unit); 460287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds 463287ac01aSChristof Schmitt static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) 4641da177e4SLinus Torvalds { 465287ac01aSChristof Schmitt list_move(&erp_action->list, &erp_action->adapter->erp_running_head); 4665ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("erator1", erp_action); 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 469287ac01aSChristof Schmitt static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) 4701da177e4SLinus Torvalds { 471287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 4721da177e4SLinus Torvalds 473287ac01aSChristof Schmitt if (!act->fsf_req) 474287ac01aSChristof Schmitt return; 4751da177e4SLinus Torvalds 476fea9d6c7SVolker Sameske spin_lock(&adapter->req_list_lock); 477287ac01aSChristof Schmitt if (zfcp_reqlist_find_safe(adapter, act->fsf_req) && 478287ac01aSChristof Schmitt act->fsf_req->erp_action == act) { 479287ac01aSChristof Schmitt if (act->status & (ZFCP_STATUS_ERP_DISMISSED | 4801da177e4SLinus Torvalds ZFCP_STATUS_ERP_TIMEDOUT)) { 481287ac01aSChristof Schmitt act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; 4825ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("erscf_1", act); 4837ea633ffSMartin Petermann act->fsf_req->erp_action = NULL; 4841da177e4SLinus Torvalds } 485287ac01aSChristof Schmitt if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) 4865ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("erscf_2", act); 487058b8647SSwen Schillig if (act->fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) 488287ac01aSChristof Schmitt act->fsf_req = NULL; 489287ac01aSChristof Schmitt } else 490287ac01aSChristof Schmitt act->fsf_req = NULL; 491fea9d6c7SVolker Sameske spin_unlock(&adapter->req_list_lock); 492507e4969SMartin Peschke } 4931da177e4SLinus Torvalds 494f6c0e7a7SAndreas Herrmann /** 495287ac01aSChristof Schmitt * zfcp_erp_notify - Trigger ERP action. 496287ac01aSChristof Schmitt * @erp_action: ERP action to continue. 497287ac01aSChristof Schmitt * @set_mask: ERP action status flags to set. 4981da177e4SLinus Torvalds */ 499287ac01aSChristof Schmitt void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) 5001da177e4SLinus Torvalds { 501287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 502287ac01aSChristof Schmitt unsigned long flags; 503287ac01aSChristof Schmitt 504287ac01aSChristof Schmitt write_lock_irqsave(&adapter->erp_lock, flags); 5051da177e4SLinus Torvalds if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { 5061da177e4SLinus Torvalds erp_action->status |= set_mask; 5071da177e4SLinus Torvalds zfcp_erp_action_ready(erp_action); 508f6c0e7a7SAndreas Herrmann } 5091da177e4SLinus Torvalds write_unlock_irqrestore(&adapter->erp_lock, flags); 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds 512f6c0e7a7SAndreas Herrmann /** 513287ac01aSChristof Schmitt * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request 514287ac01aSChristof Schmitt * @data: ERP action (from timer data) 5151da177e4SLinus Torvalds */ 516287ac01aSChristof Schmitt void zfcp_erp_timeout_handler(unsigned long data) 5171da177e4SLinus Torvalds { 518287ac01aSChristof Schmitt struct zfcp_erp_action *act = (struct zfcp_erp_action *) data; 519287ac01aSChristof Schmitt zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT); 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds 522287ac01aSChristof Schmitt static void zfcp_erp_memwait_handler(unsigned long data) 5231da177e4SLinus Torvalds { 524287ac01aSChristof Schmitt zfcp_erp_notify((struct zfcp_erp_action *)data, 0); 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds 527287ac01aSChristof Schmitt static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) 5281da177e4SLinus Torvalds { 5291da177e4SLinus Torvalds init_timer(&erp_action->timer); 5301da177e4SLinus Torvalds erp_action->timer.function = zfcp_erp_memwait_handler; 5311da177e4SLinus Torvalds erp_action->timer.data = (unsigned long) erp_action; 532287ac01aSChristof Schmitt erp_action->timer.expires = jiffies + HZ; 5331da177e4SLinus Torvalds add_timer(&erp_action->timer); 534287ac01aSChristof Schmitt } 535287ac01aSChristof Schmitt 536287ac01aSChristof Schmitt static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, 5375ffd51a5SSwen Schillig int clear, char *id, void *ref) 538287ac01aSChristof Schmitt { 539287ac01aSChristof Schmitt struct zfcp_port *port; 540287ac01aSChristof Schmitt 541287ac01aSChristof Schmitt list_for_each_entry(port, &adapter->port_list_head, list) 542287ac01aSChristof Schmitt _zfcp_erp_port_reopen(port, clear, id, ref); 543287ac01aSChristof Schmitt } 544287ac01aSChristof Schmitt 5455ffd51a5SSwen Schillig static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, 5465ffd51a5SSwen Schillig char *id, void *ref) 547287ac01aSChristof Schmitt { 548287ac01aSChristof Schmitt struct zfcp_unit *unit; 549287ac01aSChristof Schmitt 550287ac01aSChristof Schmitt list_for_each_entry(unit, &port->unit_list_head, list) 551287ac01aSChristof Schmitt _zfcp_erp_unit_reopen(unit, clear, id, ref); 552287ac01aSChristof Schmitt } 553287ac01aSChristof Schmitt 55485600f7fSChristof Schmitt static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) 555287ac01aSChristof Schmitt { 556287ac01aSChristof Schmitt switch (act->action) { 557287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 55885600f7fSChristof Schmitt _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL); 559287ac01aSChristof Schmitt break; 560287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 56185600f7fSChristof Schmitt _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL); 562287ac01aSChristof Schmitt break; 563287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 56485600f7fSChristof Schmitt _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); 565287ac01aSChristof Schmitt break; 566287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 56785600f7fSChristof Schmitt _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL); 56885600f7fSChristof Schmitt break; 56985600f7fSChristof Schmitt } 57085600f7fSChristof Schmitt } 57185600f7fSChristof Schmitt 57285600f7fSChristof Schmitt static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) 57385600f7fSChristof Schmitt { 57485600f7fSChristof Schmitt switch (act->action) { 57585600f7fSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 57685600f7fSChristof Schmitt _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL); 57785600f7fSChristof Schmitt break; 57885600f7fSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 57985600f7fSChristof Schmitt _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL); 58085600f7fSChristof Schmitt break; 58185600f7fSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 58285600f7fSChristof Schmitt _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL); 583287ac01aSChristof Schmitt break; 584287ac01aSChristof Schmitt } 585287ac01aSChristof Schmitt } 586287ac01aSChristof Schmitt 587287ac01aSChristof Schmitt static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) 588287ac01aSChristof Schmitt { 589287ac01aSChristof Schmitt unsigned long flags; 590287ac01aSChristof Schmitt 591287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 592287ac01aSChristof Schmitt read_lock(&adapter->erp_lock); 593287ac01aSChristof Schmitt if (list_empty(&adapter->erp_ready_head) && 594287ac01aSChristof Schmitt list_empty(&adapter->erp_running_head)) { 595287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, 596287ac01aSChristof Schmitt &adapter->status); 597287ac01aSChristof Schmitt wake_up(&adapter->erp_done_wqh); 598287ac01aSChristof Schmitt } 599287ac01aSChristof Schmitt read_unlock(&adapter->erp_lock); 600287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 601287ac01aSChristof Schmitt } 602287ac01aSChristof Schmitt 603287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) 604287ac01aSChristof Schmitt { 605564e1c86SSwen Schillig struct zfcp_qdio *qdio = act->adapter->qdio; 606564e1c86SSwen Schillig 607564e1c86SSwen Schillig if (zfcp_qdio_open(qdio)) 608287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 609564e1c86SSwen Schillig init_waitqueue_head(&qdio->req_q_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 */ 714564e1c86SSwen Schillig zfcp_qdio_close(adapter->qdio); 715287ac01aSChristof Schmitt zfcp_fsf_req_dismiss_all(adapter); 716287ac01aSChristof Schmitt adapter->fsf_req_seq_no = 0; 71755c770faSChristof Schmitt zfcp_fc_wka_ports_force_offline(adapter->gs); 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 844287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) 845287ac01aSChristof Schmitt { 846287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 847287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 848287ac01aSChristof Schmitt int p_status = atomic_read(&port->status); 849287ac01aSChristof Schmitt 850287ac01aSChristof Schmitt switch (act->step) { 851287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 852287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: 853287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PORT_CLOSING: 854287ac01aSChristof Schmitt if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) 855287ac01aSChristof Schmitt return zfcp_erp_open_ptp_port(act); 856b98478d7SChristof Schmitt if (!port->d_id) { 857947a9acaSSwen Schillig zfcp_port_get(port); 8584544683aSSwen Schillig if (!queue_work(adapter->work_queue, 859947a9acaSSwen Schillig &port->gid_pn_work)) 860947a9acaSSwen Schillig zfcp_port_put(port); 861799b76d0SChristof Schmitt return ZFCP_ERP_EXIT; 862287ac01aSChristof Schmitt } 863287ac01aSChristof Schmitt return zfcp_erp_port_strategy_open_port(act); 864287ac01aSChristof Schmitt 865287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PORT_OPENING: 866287ac01aSChristof Schmitt /* D_ID might have changed during open */ 8675ab944f9SSwen Schillig if (p_status & ZFCP_STATUS_COMMON_OPEN) { 868b98478d7SChristof Schmitt if (port->d_id) 869287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 8705ab944f9SSwen Schillig else { 8715ab944f9SSwen Schillig act->step = ZFCP_ERP_STEP_PORT_CLOSING; 8725ab944f9SSwen Schillig return ZFCP_ERP_CONTINUES; 8735ab944f9SSwen Schillig } 874287ac01aSChristof Schmitt } 875ea460a81SSwen Schillig if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { 876ea460a81SSwen Schillig port->d_id = 0; 877ea460a81SSwen Schillig _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL); 878ea460a81SSwen Schillig return ZFCP_ERP_EXIT; 879ea460a81SSwen Schillig } 880ea460a81SSwen Schillig /* fall through otherwise */ 881287ac01aSChristof Schmitt } 8825ab944f9SSwen Schillig return ZFCP_ERP_FAILED; 883287ac01aSChristof Schmitt } 884287ac01aSChristof Schmitt 885287ac01aSChristof Schmitt static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) 886287ac01aSChristof Schmitt { 887287ac01aSChristof Schmitt struct zfcp_port *port = erp_action->port; 888287ac01aSChristof Schmitt 8895ab944f9SSwen Schillig if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) 8905ab944f9SSwen Schillig goto close_init_done; 8915ab944f9SSwen Schillig 892287ac01aSChristof Schmitt switch (erp_action->step) { 893287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 894287ac01aSChristof Schmitt zfcp_erp_port_strategy_clearstati(port); 895287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) 896287ac01aSChristof Schmitt return zfcp_erp_port_strategy_close(erp_action); 897287ac01aSChristof Schmitt break; 898287ac01aSChristof Schmitt 899287ac01aSChristof Schmitt case ZFCP_ERP_STEP_PORT_CLOSING: 900287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) 901287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 902287ac01aSChristof Schmitt break; 903287ac01aSChristof Schmitt } 9045ab944f9SSwen Schillig 9055ab944f9SSwen Schillig close_init_done: 906287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 907287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 908287ac01aSChristof Schmitt 9095ab944f9SSwen Schillig return zfcp_erp_port_strategy_open_common(erp_action); 910287ac01aSChristof Schmitt } 911287ac01aSChristof Schmitt 912287ac01aSChristof Schmitt static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) 913287ac01aSChristof Schmitt { 91444cc76f2SSwen Schillig atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | 915287ac01aSChristof Schmitt ZFCP_STATUS_UNIT_SHARED | 916287ac01aSChristof Schmitt ZFCP_STATUS_UNIT_READONLY, 917287ac01aSChristof Schmitt &unit->status); 918287ac01aSChristof Schmitt } 919287ac01aSChristof Schmitt 920287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) 921287ac01aSChristof Schmitt { 922287ac01aSChristof Schmitt int retval = zfcp_fsf_close_unit(erp_action); 923287ac01aSChristof Schmitt if (retval == -ENOMEM) 924287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 925287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; 926287ac01aSChristof Schmitt if (retval) 927287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 928287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 929287ac01aSChristof Schmitt } 930287ac01aSChristof Schmitt 931287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) 932287ac01aSChristof Schmitt { 933287ac01aSChristof Schmitt int retval = zfcp_fsf_open_unit(erp_action); 934287ac01aSChristof Schmitt if (retval == -ENOMEM) 935287ac01aSChristof Schmitt return ZFCP_ERP_NOMEM; 936287ac01aSChristof Schmitt erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; 937287ac01aSChristof Schmitt if (retval) 938287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 939287ac01aSChristof Schmitt return ZFCP_ERP_CONTINUES; 940287ac01aSChristof Schmitt } 941287ac01aSChristof Schmitt 942287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) 943287ac01aSChristof Schmitt { 944287ac01aSChristof Schmitt struct zfcp_unit *unit = erp_action->unit; 945287ac01aSChristof Schmitt 946287ac01aSChristof Schmitt switch (erp_action->step) { 947287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNINITIALIZED: 948287ac01aSChristof Schmitt zfcp_erp_unit_strategy_clearstati(unit); 949287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) 950287ac01aSChristof Schmitt return zfcp_erp_unit_strategy_close(erp_action); 951287ac01aSChristof Schmitt /* already closed, fall through */ 952287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNIT_CLOSING: 953287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) 954287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 955287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) 956287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 957287ac01aSChristof Schmitt return zfcp_erp_unit_strategy_open(erp_action); 958287ac01aSChristof Schmitt 959287ac01aSChristof Schmitt case ZFCP_ERP_STEP_UNIT_OPENING: 960287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) 961287ac01aSChristof Schmitt return ZFCP_ERP_SUCCEEDED; 962287ac01aSChristof Schmitt } 963287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 964287ac01aSChristof Schmitt } 965287ac01aSChristof Schmitt 966287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) 967287ac01aSChristof Schmitt { 968287ac01aSChristof Schmitt switch (result) { 969287ac01aSChristof Schmitt case ZFCP_ERP_SUCCEEDED : 970287ac01aSChristof Schmitt atomic_set(&unit->erp_counter, 0); 971287ac01aSChristof Schmitt zfcp_erp_unit_unblock(unit); 972287ac01aSChristof Schmitt break; 973287ac01aSChristof Schmitt case ZFCP_ERP_FAILED : 974287ac01aSChristof Schmitt atomic_inc(&unit->erp_counter); 975ff3b24faSChristof Schmitt if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) { 976ff3b24faSChristof Schmitt dev_err(&unit->port->adapter->ccw_device->dev, 977ff3b24faSChristof Schmitt "ERP failed for unit 0x%016Lx on " 978ff3b24faSChristof Schmitt "port 0x%016Lx\n", 9797ba58c9cSSwen Schillig (unsigned long long)unit->fcp_lun, 9807ba58c9cSSwen Schillig (unsigned long long)unit->port->wwpn); 9815ffd51a5SSwen Schillig zfcp_erp_unit_failed(unit, "erusck1", NULL); 982ff3b24faSChristof Schmitt } 983287ac01aSChristof Schmitt break; 984287ac01aSChristof Schmitt } 985287ac01aSChristof Schmitt 986287ac01aSChristof Schmitt if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 987287ac01aSChristof Schmitt zfcp_erp_unit_block(unit, 0); 988287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 989287ac01aSChristof Schmitt } 990287ac01aSChristof Schmitt return result; 991287ac01aSChristof Schmitt } 992287ac01aSChristof Schmitt 993287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) 994287ac01aSChristof Schmitt { 995287ac01aSChristof Schmitt switch (result) { 996287ac01aSChristof Schmitt case ZFCP_ERP_SUCCEEDED : 997287ac01aSChristof Schmitt atomic_set(&port->erp_counter, 0); 998287ac01aSChristof Schmitt zfcp_erp_port_unblock(port); 999287ac01aSChristof Schmitt break; 1000287ac01aSChristof Schmitt 1001287ac01aSChristof Schmitt case ZFCP_ERP_FAILED : 1002287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) { 1003287ac01aSChristof Schmitt zfcp_erp_port_block(port, 0); 1004287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1005287ac01aSChristof Schmitt } 1006287ac01aSChristof Schmitt atomic_inc(&port->erp_counter); 1007ff3b24faSChristof Schmitt if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) { 1008ff3b24faSChristof Schmitt dev_err(&port->adapter->ccw_device->dev, 1009ff3b24faSChristof Schmitt "ERP failed for remote port 0x%016Lx\n", 10107ba58c9cSSwen Schillig (unsigned long long)port->wwpn); 10115ffd51a5SSwen Schillig zfcp_erp_port_failed(port, "erpsck1", NULL); 1012ff3b24faSChristof Schmitt } 1013287ac01aSChristof Schmitt break; 1014287ac01aSChristof Schmitt } 1015287ac01aSChristof Schmitt 1016287ac01aSChristof Schmitt if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 1017287ac01aSChristof Schmitt zfcp_erp_port_block(port, 0); 1018287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1019287ac01aSChristof Schmitt } 1020287ac01aSChristof Schmitt return result; 1021287ac01aSChristof Schmitt } 1022287ac01aSChristof Schmitt 1023287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, 1024287ac01aSChristof Schmitt int result) 1025287ac01aSChristof Schmitt { 1026287ac01aSChristof Schmitt switch (result) { 1027287ac01aSChristof Schmitt case ZFCP_ERP_SUCCEEDED : 1028287ac01aSChristof Schmitt atomic_set(&adapter->erp_counter, 0); 1029287ac01aSChristof Schmitt zfcp_erp_adapter_unblock(adapter); 1030287ac01aSChristof Schmitt break; 1031287ac01aSChristof Schmitt 1032287ac01aSChristof Schmitt case ZFCP_ERP_FAILED : 1033287ac01aSChristof Schmitt atomic_inc(&adapter->erp_counter); 1034ff3b24faSChristof Schmitt if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) { 1035ff3b24faSChristof Schmitt dev_err(&adapter->ccw_device->dev, 1036ff3b24faSChristof Schmitt "ERP cannot recover an error " 1037ff3b24faSChristof Schmitt "on the FCP device\n"); 10385ffd51a5SSwen Schillig zfcp_erp_adapter_failed(adapter, "erasck1", NULL); 1039ff3b24faSChristof Schmitt } 1040287ac01aSChristof Schmitt break; 1041287ac01aSChristof Schmitt } 1042287ac01aSChristof Schmitt 1043287ac01aSChristof Schmitt if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { 1044287ac01aSChristof Schmitt zfcp_erp_adapter_block(adapter, 0); 1045287ac01aSChristof Schmitt result = ZFCP_ERP_EXIT; 1046287ac01aSChristof Schmitt } 1047287ac01aSChristof Schmitt return result; 1048287ac01aSChristof Schmitt } 1049287ac01aSChristof Schmitt 1050287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, 1051287ac01aSChristof Schmitt int result) 10521da177e4SLinus Torvalds { 10531da177e4SLinus Torvalds struct zfcp_adapter *adapter = erp_action->adapter; 10541da177e4SLinus Torvalds struct zfcp_port *port = erp_action->port; 10551da177e4SLinus Torvalds struct zfcp_unit *unit = erp_action->unit; 10561da177e4SLinus Torvalds 10571da177e4SLinus Torvalds switch (erp_action->action) { 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_UNIT: 10601da177e4SLinus Torvalds result = zfcp_erp_strategy_check_unit(unit, result); 10611da177e4SLinus Torvalds break; 10621da177e4SLinus Torvalds 10631da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 10641da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT: 10651da177e4SLinus Torvalds result = zfcp_erp_strategy_check_port(port, result); 10661da177e4SLinus Torvalds break; 10671da177e4SLinus Torvalds 10681da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 10691da177e4SLinus Torvalds result = zfcp_erp_strategy_check_adapter(adapter, result); 10701da177e4SLinus Torvalds break; 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds return result; 10731da177e4SLinus Torvalds } 10741da177e4SLinus Torvalds 1075287ac01aSChristof Schmitt static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status) 10761da177e4SLinus Torvalds { 1077287ac01aSChristof Schmitt int status = atomic_read(target_status); 10781da177e4SLinus Torvalds 1079287ac01aSChristof Schmitt if ((status & ZFCP_STATUS_COMMON_RUNNING) && 1080287ac01aSChristof Schmitt (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) 1081287ac01aSChristof Schmitt return 1; /* take it online */ 1082287ac01aSChristof Schmitt 1083287ac01aSChristof Schmitt if (!(status & ZFCP_STATUS_COMMON_RUNNING) && 1084287ac01aSChristof Schmitt !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) 1085287ac01aSChristof Schmitt return 1; /* take it offline */ 1086287ac01aSChristof Schmitt 1087287ac01aSChristof Schmitt return 0; 1088287ac01aSChristof Schmitt } 1089287ac01aSChristof Schmitt 1090287ac01aSChristof Schmitt static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) 1091287ac01aSChristof Schmitt { 1092287ac01aSChristof Schmitt int action = act->action; 1093287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 1094287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 1095287ac01aSChristof Schmitt struct zfcp_unit *unit = act->unit; 1096287ac01aSChristof Schmitt u32 erp_status = act->status; 1097287ac01aSChristof Schmitt 1098287ac01aSChristof Schmitt switch (action) { 10991da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1100287ac01aSChristof Schmitt if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { 1101287ac01aSChristof Schmitt _zfcp_erp_adapter_reopen(adapter, 11029467a9b3SMartin Peschke ZFCP_STATUS_COMMON_ERP_FAILED, 11035ffd51a5SSwen Schillig "ersscg1", NULL); 1104287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 11051da177e4SLinus Torvalds } 11061da177e4SLinus Torvalds break; 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 11091da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_PORT: 1110287ac01aSChristof Schmitt if (zfcp_erp_strat_change_det(&port->status, erp_status)) { 1111287ac01aSChristof Schmitt _zfcp_erp_port_reopen(port, 11129467a9b3SMartin Peschke ZFCP_STATUS_COMMON_ERP_FAILED, 11135ffd51a5SSwen Schillig "ersscg2", NULL); 1114287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 11151da177e4SLinus Torvalds } 11161da177e4SLinus Torvalds break; 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_UNIT: 1119287ac01aSChristof Schmitt if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { 1120287ac01aSChristof Schmitt _zfcp_erp_unit_reopen(unit, 11219467a9b3SMartin Peschke ZFCP_STATUS_COMMON_ERP_FAILED, 11225ffd51a5SSwen Schillig "ersscg3", NULL); 1123287ac01aSChristof Schmitt return ZFCP_ERP_EXIT; 11241da177e4SLinus Torvalds } 11251da177e4SLinus Torvalds break; 11261da177e4SLinus Torvalds } 1127287ac01aSChristof Schmitt return ret; 11281da177e4SLinus Torvalds } 11291da177e4SLinus Torvalds 1130287ac01aSChristof Schmitt static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) 11311da177e4SLinus Torvalds { 1132287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 1133287ac01aSChristof Schmitt 1134287ac01aSChristof Schmitt adapter->erp_total_count--; 1135287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { 1136287ac01aSChristof Schmitt adapter->erp_low_mem_count--; 1137287ac01aSChristof Schmitt erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; 11381da177e4SLinus Torvalds } 11391da177e4SLinus Torvalds 1140287ac01aSChristof Schmitt list_del(&erp_action->list); 11415ffd51a5SSwen Schillig zfcp_rec_dbf_event_action("eractd1", erp_action); 11421da177e4SLinus Torvalds 1143287ac01aSChristof Schmitt switch (erp_action->action) { 1144287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 1145287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, 1146287ac01aSChristof Schmitt &erp_action->unit->status); 11471da177e4SLinus Torvalds break; 1148287ac01aSChristof Schmitt 1149287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1150287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 1151287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, 1152287ac01aSChristof Schmitt &erp_action->port->status); 11531da177e4SLinus Torvalds break; 1154287ac01aSChristof Schmitt 1155287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1156287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, 1157287ac01aSChristof Schmitt &erp_action->adapter->status); 11581da177e4SLinus Torvalds break; 11591da177e4SLinus Torvalds } 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds 1162287ac01aSChristof Schmitt static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) 1163287ac01aSChristof Schmitt { 1164287ac01aSChristof Schmitt struct zfcp_adapter *adapter = act->adapter; 1165287ac01aSChristof Schmitt struct zfcp_port *port = act->port; 1166287ac01aSChristof Schmitt struct zfcp_unit *unit = act->unit; 1167287ac01aSChristof Schmitt 1168287ac01aSChristof Schmitt switch (act->action) { 1169287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 1170a2fa0aedSChristof Schmitt if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { 117192d5193bSSwen Schillig zfcp_unit_get(unit); 117292d5193bSSwen Schillig if (scsi_queue_work(unit->port->adapter->scsi_host, 117392d5193bSSwen Schillig &unit->scsi_work) <= 0) 117492d5193bSSwen Schillig zfcp_unit_put(unit); 1175287ac01aSChristof Schmitt } 1176287ac01aSChristof Schmitt zfcp_unit_put(unit); 1177287ac01aSChristof Schmitt break; 1178287ac01aSChristof Schmitt 1179287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1180287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 1181a2fa0aedSChristof Schmitt if (result == ZFCP_ERP_SUCCEEDED) 1182a2fa0aedSChristof Schmitt zfcp_scsi_schedule_rport_register(port); 11831da177e4SLinus Torvalds zfcp_port_put(port); 11841da177e4SLinus Torvalds break; 1185287ac01aSChristof Schmitt 11861da177e4SLinus Torvalds case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1187a2fa0aedSChristof Schmitt if (result == ZFCP_ERP_SUCCEEDED) { 1188bd43a42bSChristof Schmitt register_service_level(&adapter->service_level); 1189fca55b6fSSwen Schillig schedule_work(&adapter->scan_work); 1190a2fa0aedSChristof Schmitt } else 1191a2fa0aedSChristof Schmitt unregister_service_level(&adapter->service_level); 11921da177e4SLinus Torvalds zfcp_adapter_put(adapter); 11931da177e4SLinus Torvalds break; 11941da177e4SLinus Torvalds } 11951da177e4SLinus Torvalds } 11961da177e4SLinus Torvalds 1197287ac01aSChristof Schmitt static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) 1198287ac01aSChristof Schmitt { 1199287ac01aSChristof Schmitt switch (erp_action->action) { 1200287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_ADAPTER: 1201287ac01aSChristof Schmitt return zfcp_erp_adapter_strategy(erp_action); 1202287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: 1203287ac01aSChristof Schmitt return zfcp_erp_port_forced_strategy(erp_action); 1204287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_PORT: 1205287ac01aSChristof Schmitt return zfcp_erp_port_strategy(erp_action); 1206287ac01aSChristof Schmitt case ZFCP_ERP_ACTION_REOPEN_UNIT: 1207287ac01aSChristof Schmitt return zfcp_erp_unit_strategy(erp_action); 1208287ac01aSChristof Schmitt } 1209287ac01aSChristof Schmitt return ZFCP_ERP_FAILED; 1210287ac01aSChristof Schmitt } 12111da177e4SLinus Torvalds 1212287ac01aSChristof Schmitt static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) 1213287ac01aSChristof Schmitt { 1214287ac01aSChristof Schmitt int retval; 1215287ac01aSChristof Schmitt struct zfcp_adapter *adapter = erp_action->adapter; 1216287ac01aSChristof Schmitt unsigned long flags; 1217287ac01aSChristof Schmitt 1218287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 1219287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 1220287ac01aSChristof Schmitt 1221287ac01aSChristof Schmitt zfcp_erp_strategy_check_fsfreq(erp_action); 1222287ac01aSChristof Schmitt 1223287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { 1224287ac01aSChristof Schmitt zfcp_erp_action_dequeue(erp_action); 1225287ac01aSChristof Schmitt retval = ZFCP_ERP_DISMISSED; 1226287ac01aSChristof Schmitt goto unlock; 1227287ac01aSChristof Schmitt } 1228287ac01aSChristof Schmitt 1229287ac01aSChristof Schmitt zfcp_erp_action_to_running(erp_action); 1230287ac01aSChristof Schmitt 1231287ac01aSChristof Schmitt /* no lock to allow for blocking operations */ 1232287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 1233287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 1234287ac01aSChristof Schmitt retval = zfcp_erp_strategy_do_action(erp_action); 1235287ac01aSChristof Schmitt read_lock_irqsave(&zfcp_data.config_lock, flags); 1236287ac01aSChristof Schmitt write_lock(&adapter->erp_lock); 1237287ac01aSChristof Schmitt 1238287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) 1239287ac01aSChristof Schmitt retval = ZFCP_ERP_CONTINUES; 1240287ac01aSChristof Schmitt 1241287ac01aSChristof Schmitt switch (retval) { 1242287ac01aSChristof Schmitt case ZFCP_ERP_NOMEM: 1243287ac01aSChristof Schmitt if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { 1244287ac01aSChristof Schmitt ++adapter->erp_low_mem_count; 1245287ac01aSChristof Schmitt erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; 1246287ac01aSChristof Schmitt } 1247287ac01aSChristof Schmitt if (adapter->erp_total_count == adapter->erp_low_mem_count) 12485ffd51a5SSwen Schillig _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL); 1249287ac01aSChristof Schmitt else { 1250287ac01aSChristof Schmitt zfcp_erp_strategy_memwait(erp_action); 1251287ac01aSChristof Schmitt retval = ZFCP_ERP_CONTINUES; 1252287ac01aSChristof Schmitt } 1253287ac01aSChristof Schmitt goto unlock; 1254287ac01aSChristof Schmitt 1255287ac01aSChristof Schmitt case ZFCP_ERP_CONTINUES: 1256287ac01aSChristof Schmitt if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { 1257287ac01aSChristof Schmitt --adapter->erp_low_mem_count; 1258287ac01aSChristof Schmitt erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; 1259287ac01aSChristof Schmitt } 1260287ac01aSChristof Schmitt goto unlock; 1261287ac01aSChristof Schmitt } 1262287ac01aSChristof Schmitt 1263287ac01aSChristof Schmitt retval = zfcp_erp_strategy_check_target(erp_action, retval); 1264287ac01aSChristof Schmitt zfcp_erp_action_dequeue(erp_action); 1265287ac01aSChristof Schmitt retval = zfcp_erp_strategy_statechange(erp_action, retval); 1266287ac01aSChristof Schmitt if (retval == ZFCP_ERP_EXIT) 1267287ac01aSChristof Schmitt goto unlock; 126885600f7fSChristof Schmitt if (retval == ZFCP_ERP_SUCCEEDED) 126985600f7fSChristof Schmitt zfcp_erp_strategy_followup_success(erp_action); 127085600f7fSChristof Schmitt if (retval == ZFCP_ERP_FAILED) 127185600f7fSChristof Schmitt zfcp_erp_strategy_followup_failed(erp_action); 1272287ac01aSChristof Schmitt 1273287ac01aSChristof Schmitt unlock: 1274287ac01aSChristof Schmitt write_unlock(&adapter->erp_lock); 1275287ac01aSChristof Schmitt read_unlock_irqrestore(&zfcp_data.config_lock, flags); 1276287ac01aSChristof Schmitt 1277287ac01aSChristof Schmitt if (retval != ZFCP_ERP_CONTINUES) 1278287ac01aSChristof Schmitt zfcp_erp_action_cleanup(erp_action, retval); 1279287ac01aSChristof Schmitt 1280287ac01aSChristof Schmitt return retval; 1281287ac01aSChristof Schmitt } 1282287ac01aSChristof Schmitt 1283287ac01aSChristof Schmitt static int zfcp_erp_thread(void *data) 1284287ac01aSChristof Schmitt { 1285287ac01aSChristof Schmitt struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; 1286287ac01aSChristof Schmitt struct list_head *next; 1287287ac01aSChristof Schmitt struct zfcp_erp_action *act; 1288287ac01aSChristof Schmitt unsigned long flags; 128906499facSHeiko Carstens int ignore; 1290287ac01aSChristof Schmitt 1291b9d3aed7SCornelia Huck daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); 1292287ac01aSChristof Schmitt /* Block all signals */ 1293287ac01aSChristof Schmitt siginitsetinv(¤t->blocked, 0); 1294287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); 1295287ac01aSChristof Schmitt wake_up(&adapter->erp_thread_wqh); 1296287ac01aSChristof Schmitt 1297287ac01aSChristof Schmitt while (!(atomic_read(&adapter->status) & 1298287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { 129994ab4b38SSwen Schillig 130094ab4b38SSwen Schillig zfcp_rec_dbf_event_thread_lock("erthrd1", adapter); 130194ab4b38SSwen Schillig ignore = down_interruptible(&adapter->erp_ready_sem); 130294ab4b38SSwen Schillig zfcp_rec_dbf_event_thread_lock("erthrd2", adapter); 130394ab4b38SSwen Schillig 1304287ac01aSChristof Schmitt write_lock_irqsave(&adapter->erp_lock, flags); 1305287ac01aSChristof Schmitt next = adapter->erp_ready_head.next; 1306287ac01aSChristof Schmitt write_unlock_irqrestore(&adapter->erp_lock, flags); 1307287ac01aSChristof Schmitt 1308287ac01aSChristof Schmitt if (next != &adapter->erp_ready_head) { 1309287ac01aSChristof Schmitt act = list_entry(next, struct zfcp_erp_action, list); 1310287ac01aSChristof Schmitt 1311287ac01aSChristof Schmitt /* there is more to come after dismission, no notify */ 1312287ac01aSChristof Schmitt if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) 1313287ac01aSChristof Schmitt zfcp_erp_wakeup(adapter); 1314287ac01aSChristof Schmitt } 1315287ac01aSChristof Schmitt } 1316287ac01aSChristof Schmitt 1317287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); 1318287ac01aSChristof Schmitt wake_up(&adapter->erp_thread_wqh); 1319287ac01aSChristof Schmitt 1320287ac01aSChristof Schmitt return 0; 1321287ac01aSChristof Schmitt } 1322287ac01aSChristof Schmitt 1323287ac01aSChristof Schmitt /** 1324287ac01aSChristof Schmitt * zfcp_erp_thread_setup - Start ERP thread for adapter 1325287ac01aSChristof Schmitt * @adapter: Adapter to start the ERP thread for 1326287ac01aSChristof Schmitt * 1327287ac01aSChristof Schmitt * Returns 0 on success or error code from kernel_thread() 1328287ac01aSChristof Schmitt */ 1329287ac01aSChristof Schmitt int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) 1330287ac01aSChristof Schmitt { 1331287ac01aSChristof Schmitt int retval; 1332287ac01aSChristof Schmitt 1333287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); 1334287ac01aSChristof Schmitt retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); 1335287ac01aSChristof Schmitt if (retval < 0) { 1336287ac01aSChristof Schmitt dev_err(&adapter->ccw_device->dev, 1337ff3b24faSChristof Schmitt "Creating an ERP thread for the FCP device failed.\n"); 1338287ac01aSChristof Schmitt return retval; 1339287ac01aSChristof Schmitt } 1340287ac01aSChristof Schmitt wait_event(adapter->erp_thread_wqh, 1341287ac01aSChristof Schmitt atomic_read(&adapter->status) & 1342287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); 1343287ac01aSChristof Schmitt return 0; 1344287ac01aSChristof Schmitt } 1345287ac01aSChristof Schmitt 1346287ac01aSChristof Schmitt /** 1347287ac01aSChristof Schmitt * zfcp_erp_thread_kill - Stop ERP thread. 1348287ac01aSChristof Schmitt * @adapter: Adapter where the ERP thread should be stopped. 1349287ac01aSChristof Schmitt * 1350287ac01aSChristof Schmitt * The caller of this routine ensures that the specified adapter has 1351287ac01aSChristof Schmitt * been shut down and that this operation has been completed. Thus, 1352287ac01aSChristof Schmitt * there are no pending erp_actions which would need to be handled 1353287ac01aSChristof Schmitt * here. 1354287ac01aSChristof Schmitt */ 1355287ac01aSChristof Schmitt void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) 1356287ac01aSChristof Schmitt { 1357287ac01aSChristof Schmitt atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); 1358287ac01aSChristof Schmitt up(&adapter->erp_ready_sem); 13595ffd51a5SSwen Schillig zfcp_rec_dbf_event_thread_lock("erthrk1", adapter); 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 1365287ac01aSChristof Schmitt atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, 1366287ac01aSChristof Schmitt &adapter->status); 1367287ac01aSChristof Schmitt } 1368287ac01aSChristof Schmitt 1369287ac01aSChristof Schmitt /** 1370287ac01aSChristof Schmitt * zfcp_erp_adapter_failed - Set adapter status to failed. 1371287ac01aSChristof Schmitt * @adapter: Failed adapter. 1372287ac01aSChristof Schmitt * @id: Event id for debug trace. 1373287ac01aSChristof Schmitt * @ref: Reference for debug trace. 1374287ac01aSChristof Schmitt */ 13755ffd51a5SSwen Schillig void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref) 1376287ac01aSChristof Schmitt { 1377287ac01aSChristof Schmitt zfcp_erp_modify_adapter_status(adapter, id, ref, 1378287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); 1379287ac01aSChristof Schmitt } 1380287ac01aSChristof Schmitt 1381287ac01aSChristof Schmitt /** 1382287ac01aSChristof Schmitt * zfcp_erp_port_failed - Set port status to failed. 1383287ac01aSChristof Schmitt * @port: Failed port. 1384287ac01aSChristof Schmitt * @id: Event id for debug trace. 1385287ac01aSChristof Schmitt * @ref: Reference for debug trace. 1386287ac01aSChristof Schmitt */ 13875ffd51a5SSwen Schillig void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref) 1388287ac01aSChristof Schmitt { 1389287ac01aSChristof Schmitt zfcp_erp_modify_port_status(port, id, ref, 1390287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); 1391287ac01aSChristof Schmitt } 1392287ac01aSChristof Schmitt 1393287ac01aSChristof Schmitt /** 1394287ac01aSChristof Schmitt * zfcp_erp_unit_failed - Set unit status to failed. 1395287ac01aSChristof Schmitt * @unit: Failed unit. 1396287ac01aSChristof Schmitt * @id: Event id for debug trace. 1397287ac01aSChristof Schmitt * @ref: Reference for debug trace. 1398287ac01aSChristof Schmitt */ 13995ffd51a5SSwen Schillig void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref) 1400287ac01aSChristof Schmitt { 1401287ac01aSChristof Schmitt zfcp_erp_modify_unit_status(unit, id, ref, 1402287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); 1403287ac01aSChristof Schmitt } 1404287ac01aSChristof Schmitt 1405287ac01aSChristof Schmitt /** 1406287ac01aSChristof Schmitt * zfcp_erp_wait - wait for completion of error recovery on an adapter 1407287ac01aSChristof Schmitt * @adapter: adapter for which to wait for completion of its error recovery 1408287ac01aSChristof Schmitt */ 1409287ac01aSChristof Schmitt void zfcp_erp_wait(struct zfcp_adapter *adapter) 1410287ac01aSChristof Schmitt { 1411287ac01aSChristof Schmitt wait_event(adapter->erp_done_wqh, 1412287ac01aSChristof Schmitt !(atomic_read(&adapter->status) & 1413287ac01aSChristof Schmitt ZFCP_STATUS_ADAPTER_ERP_PENDING)); 1414287ac01aSChristof Schmitt } 1415287ac01aSChristof Schmitt 1416287ac01aSChristof Schmitt /** 1417287ac01aSChristof Schmitt * zfcp_erp_modify_adapter_status - change adapter status bits 1418287ac01aSChristof Schmitt * @adapter: adapter to change the status 1419287ac01aSChristof Schmitt * @id: id for the debug trace 1420287ac01aSChristof Schmitt * @ref: reference for the debug trace 1421287ac01aSChristof Schmitt * @mask: status bits to change 1422287ac01aSChristof Schmitt * @set_or_clear: ZFCP_SET or ZFCP_CLEAR 1423287ac01aSChristof Schmitt * 1424287ac01aSChristof Schmitt * Changes in common status bits are propagated to attached ports and units. 1425287ac01aSChristof Schmitt */ 14265ffd51a5SSwen Schillig void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, 1427287ac01aSChristof Schmitt void *ref, u32 mask, int set_or_clear) 14281da177e4SLinus Torvalds { 14291da177e4SLinus Torvalds struct zfcp_port *port; 1430287ac01aSChristof Schmitt u32 common_mask = mask & ZFCP_COMMON_FLAGS; 14311da177e4SLinus Torvalds 1432287ac01aSChristof Schmitt if (set_or_clear == ZFCP_SET) { 1433287ac01aSChristof Schmitt if (status_change_set(mask, &adapter->status)) 1434287ac01aSChristof Schmitt zfcp_rec_dbf_event_adapter(id, ref, adapter); 1435287ac01aSChristof Schmitt atomic_set_mask(mask, &adapter->status); 1436287ac01aSChristof Schmitt } else { 1437287ac01aSChristof Schmitt if (status_change_clear(mask, &adapter->status)) 1438287ac01aSChristof Schmitt zfcp_rec_dbf_event_adapter(id, ref, adapter); 1439287ac01aSChristof Schmitt atomic_clear_mask(mask, &adapter->status); 1440287ac01aSChristof Schmitt if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) 1441287ac01aSChristof Schmitt atomic_set(&adapter->erp_counter, 0); 14421da177e4SLinus Torvalds } 14431da177e4SLinus Torvalds 1444287ac01aSChristof Schmitt if (common_mask) 1445287ac01aSChristof Schmitt list_for_each_entry(port, &adapter->port_list_head, list) 1446287ac01aSChristof Schmitt zfcp_erp_modify_port_status(port, id, ref, common_mask, 1447287ac01aSChristof Schmitt set_or_clear); 1448287ac01aSChristof Schmitt } 1449287ac01aSChristof Schmitt 1450287ac01aSChristof Schmitt /** 1451287ac01aSChristof Schmitt * zfcp_erp_modify_port_status - change port status bits 1452287ac01aSChristof Schmitt * @port: port to change the status bits 1453287ac01aSChristof Schmitt * @id: id for the debug trace 1454287ac01aSChristof Schmitt * @ref: reference for the debug trace 1455287ac01aSChristof Schmitt * @mask: status bits to change 1456287ac01aSChristof Schmitt * @set_or_clear: ZFCP_SET or ZFCP_CLEAR 1457287ac01aSChristof Schmitt * 1458287ac01aSChristof Schmitt * Changes in common status bits are propagated to attached units. 1459287ac01aSChristof Schmitt */ 14605ffd51a5SSwen Schillig void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, 1461287ac01aSChristof Schmitt u32 mask, int set_or_clear) 14621da177e4SLinus Torvalds { 14631da177e4SLinus Torvalds struct zfcp_unit *unit; 1464287ac01aSChristof Schmitt u32 common_mask = mask & ZFCP_COMMON_FLAGS; 14651da177e4SLinus Torvalds 1466287ac01aSChristof Schmitt if (set_or_clear == ZFCP_SET) { 1467287ac01aSChristof Schmitt if (status_change_set(mask, &port->status)) 1468287ac01aSChristof Schmitt zfcp_rec_dbf_event_port(id, ref, port); 1469287ac01aSChristof Schmitt atomic_set_mask(mask, &port->status); 1470287ac01aSChristof Schmitt } else { 1471287ac01aSChristof Schmitt if (status_change_clear(mask, &port->status)) 1472287ac01aSChristof Schmitt zfcp_rec_dbf_event_port(id, ref, port); 1473287ac01aSChristof Schmitt atomic_clear_mask(mask, &port->status); 1474287ac01aSChristof Schmitt if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) 1475287ac01aSChristof Schmitt atomic_set(&port->erp_counter, 0); 1476287ac01aSChristof Schmitt } 1477287ac01aSChristof Schmitt 1478287ac01aSChristof Schmitt if (common_mask) 14791da177e4SLinus Torvalds list_for_each_entry(unit, &port->unit_list_head, list) 1480287ac01aSChristof Schmitt zfcp_erp_modify_unit_status(unit, id, ref, common_mask, 1481287ac01aSChristof Schmitt set_or_clear); 14821da177e4SLinus Torvalds } 14831da177e4SLinus Torvalds 1484287ac01aSChristof Schmitt /** 1485287ac01aSChristof Schmitt * zfcp_erp_modify_unit_status - change unit status bits 1486287ac01aSChristof Schmitt * @unit: unit to change the status bits 1487287ac01aSChristof Schmitt * @id: id for the debug trace 1488287ac01aSChristof Schmitt * @ref: reference for the debug trace 1489287ac01aSChristof Schmitt * @mask: status bits to change 1490287ac01aSChristof Schmitt * @set_or_clear: ZFCP_SET or ZFCP_CLEAR 1491287ac01aSChristof Schmitt */ 14925ffd51a5SSwen Schillig void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, 1493287ac01aSChristof Schmitt u32 mask, int set_or_clear) 14941da177e4SLinus Torvalds { 1495287ac01aSChristof Schmitt if (set_or_clear == ZFCP_SET) { 1496287ac01aSChristof Schmitt if (status_change_set(mask, &unit->status)) 1497287ac01aSChristof Schmitt zfcp_rec_dbf_event_unit(id, ref, unit); 1498287ac01aSChristof Schmitt atomic_set_mask(mask, &unit->status); 1499287ac01aSChristof Schmitt } else { 1500287ac01aSChristof Schmitt if (status_change_clear(mask, &unit->status)) 1501287ac01aSChristof Schmitt zfcp_rec_dbf_event_unit(id, ref, unit); 1502287ac01aSChristof Schmitt atomic_clear_mask(mask, &unit->status); 1503287ac01aSChristof Schmitt if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { 1504287ac01aSChristof Schmitt atomic_set(&unit->erp_counter, 0); 1505287ac01aSChristof Schmitt } 1506287ac01aSChristof Schmitt } 15071da177e4SLinus Torvalds } 15081da177e4SLinus Torvalds 1509287ac01aSChristof Schmitt /** 1510287ac01aSChristof Schmitt * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP 1511287ac01aSChristof Schmitt * @port: The "boxed" port. 1512287ac01aSChristof Schmitt * @id: The debug trace id. 1513287ac01aSChristof Schmitt * @id: Reference for the debug trace. 1514287ac01aSChristof Schmitt */ 15155ffd51a5SSwen Schillig void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref) 1516d736a27bSAndreas Herrmann { 1517d736a27bSAndreas Herrmann unsigned long flags; 1518d736a27bSAndreas Herrmann 1519d736a27bSAndreas Herrmann read_lock_irqsave(&zfcp_data.config_lock, flags); 1520698ec016SMartin Peschke zfcp_erp_modify_port_status(port, id, ref, 1521698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); 1522d736a27bSAndreas Herrmann read_unlock_irqrestore(&zfcp_data.config_lock, flags); 15239467a9b3SMartin Peschke zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1524d736a27bSAndreas Herrmann } 1525d736a27bSAndreas Herrmann 1526287ac01aSChristof Schmitt /** 1527287ac01aSChristof Schmitt * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP 1528287ac01aSChristof Schmitt * @port: The "boxed" unit. 1529287ac01aSChristof Schmitt * @id: The debug trace id. 1530287ac01aSChristof Schmitt * @id: Reference for the debug trace. 1531287ac01aSChristof Schmitt */ 15325ffd51a5SSwen Schillig void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref) 1533d736a27bSAndreas Herrmann { 1534698ec016SMartin Peschke zfcp_erp_modify_unit_status(unit, id, ref, 1535698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); 15369467a9b3SMartin Peschke zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1537d736a27bSAndreas Herrmann } 1538d736a27bSAndreas Herrmann 1539287ac01aSChristof Schmitt /** 1540287ac01aSChristof Schmitt * zfcp_erp_port_access_denied - Adapter denied access to port. 1541287ac01aSChristof Schmitt * @port: port where access has been denied 1542287ac01aSChristof Schmitt * @id: id for debug trace 1543287ac01aSChristof Schmitt * @ref: reference for debug trace 1544287ac01aSChristof Schmitt * 1545287ac01aSChristof Schmitt * Since the adapter has denied access, stop using the port and the 1546287ac01aSChristof Schmitt * attached units. 1547287ac01aSChristof Schmitt */ 15485ffd51a5SSwen Schillig void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref) 15491da177e4SLinus Torvalds { 15501da177e4SLinus Torvalds unsigned long flags; 15511da177e4SLinus Torvalds 15521da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 1553698ec016SMartin Peschke zfcp_erp_modify_port_status(port, id, ref, 1554d736a27bSAndreas Herrmann ZFCP_STATUS_COMMON_ERP_FAILED | 1555698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); 15561da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 15571da177e4SLinus Torvalds } 15581da177e4SLinus Torvalds 1559287ac01aSChristof Schmitt /** 1560287ac01aSChristof Schmitt * zfcp_erp_unit_access_denied - Adapter denied access to unit. 1561287ac01aSChristof Schmitt * @unit: unit where access has been denied 1562287ac01aSChristof Schmitt * @id: id for debug trace 1563287ac01aSChristof Schmitt * @ref: reference for debug trace 1564287ac01aSChristof Schmitt * 1565287ac01aSChristof Schmitt * Since the adapter has denied access, stop using the unit. 1566287ac01aSChristof Schmitt */ 15675ffd51a5SSwen Schillig void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref) 15681da177e4SLinus Torvalds { 1569698ec016SMartin Peschke zfcp_erp_modify_unit_status(unit, id, ref, 1570d736a27bSAndreas Herrmann ZFCP_STATUS_COMMON_ERP_FAILED | 1571698ec016SMartin Peschke ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); 15721da177e4SLinus Torvalds } 15731da177e4SLinus Torvalds 15745ffd51a5SSwen Schillig static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id, 1575287ac01aSChristof Schmitt void *ref) 1576287ac01aSChristof Schmitt { 1577287ac01aSChristof Schmitt int status = atomic_read(&unit->status); 1578287ac01aSChristof Schmitt if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | 1579287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ACCESS_BOXED))) 1580287ac01aSChristof Schmitt return; 1581287ac01aSChristof Schmitt 1582287ac01aSChristof Schmitt zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1583287ac01aSChristof Schmitt } 1584287ac01aSChristof Schmitt 15855ffd51a5SSwen Schillig static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id, 1586287ac01aSChristof Schmitt void *ref) 1587287ac01aSChristof Schmitt { 1588287ac01aSChristof Schmitt struct zfcp_unit *unit; 1589287ac01aSChristof Schmitt int status = atomic_read(&port->status); 1590287ac01aSChristof Schmitt 1591287ac01aSChristof Schmitt if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | 1592287ac01aSChristof Schmitt ZFCP_STATUS_COMMON_ACCESS_BOXED))) { 1593287ac01aSChristof Schmitt list_for_each_entry(unit, &port->unit_list_head, list) 1594287ac01aSChristof Schmitt zfcp_erp_unit_access_changed(unit, id, ref); 1595287ac01aSChristof Schmitt return; 1596287ac01aSChristof Schmitt } 1597287ac01aSChristof Schmitt 1598287ac01aSChristof Schmitt zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); 1599287ac01aSChristof Schmitt } 1600287ac01aSChristof Schmitt 1601287ac01aSChristof Schmitt /** 1602287ac01aSChristof Schmitt * zfcp_erp_adapter_access_changed - Process change in adapter ACT 1603287ac01aSChristof Schmitt * @adapter: Adapter where the Access Control Table (ACT) changed 1604287ac01aSChristof Schmitt * @id: Id for debug trace 1605287ac01aSChristof Schmitt * @ref: Reference for debug trace 1606287ac01aSChristof Schmitt */ 16075ffd51a5SSwen Schillig void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id, 16081f6f7129SMartin Peschke void *ref) 16091da177e4SLinus Torvalds { 16101da177e4SLinus Torvalds struct zfcp_port *port; 16111da177e4SLinus Torvalds unsigned long flags; 16121da177e4SLinus Torvalds 1613aef4a983SMaxim Shchetynin if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) 1614aef4a983SMaxim Shchetynin return; 1615aef4a983SMaxim Shchetynin 16161da177e4SLinus Torvalds read_lock_irqsave(&zfcp_data.config_lock, flags); 16171da177e4SLinus Torvalds list_for_each_entry(port, &adapter->port_list_head, list) 16189467a9b3SMartin Peschke zfcp_erp_port_access_changed(port, id, ref); 16191da177e4SLinus Torvalds read_unlock_irqrestore(&zfcp_data.config_lock, flags); 16201da177e4SLinus Torvalds } 1621