diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_erp.c')
| -rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 1030 |
1 files changed, 484 insertions, 546 deletions
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index fdc9b4352a6..c82fe65c412 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -3,13 +3,15 @@ * * Error Recovery Procedures (ERP). * - * Copyright IBM Corporation 2002, 2009 + * Copyright IBM Corp. 2002, 2010 */ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/kthread.h> #include "zfcp_ext.h" +#include "zfcp_reqlist.h" #define ZFCP_MAX_ERPS 3 @@ -19,6 +21,7 @@ enum zfcp_erp_act_flags { ZFCP_STATUS_ERP_DISMISSING = 0x00100000, ZFCP_STATUS_ERP_DISMISSED = 0x00200000, ZFCP_STATUS_ERP_LOWMEM = 0x00400000, + ZFCP_STATUS_ERP_NO_REF = 0x00800000, }; enum zfcp_erp_steps { @@ -26,14 +29,13 @@ enum zfcp_erp_steps { ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001, ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, - ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400, ZFCP_ERP_STEP_PORT_OPENING = 0x0800, - ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, - ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, + ZFCP_ERP_STEP_LUN_CLOSING = 0x1000, + ZFCP_ERP_STEP_LUN_OPENING = 0x2000, }; enum zfcp_erp_act_type { - ZFCP_ERP_ACTION_REOPEN_UNIT = 1, + ZFCP_ERP_ACTION_REOPEN_LUN = 1, ZFCP_ERP_ACTION_REOPEN_PORT = 2, ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, @@ -55,9 +57,8 @@ enum zfcp_erp_act_result { static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) { - zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | mask, - ZFCP_CLEAR); + zfcp_erp_clear_adapter_status(adapter, + ZFCP_STATUS_COMMON_UNBLOCKED | mask); } static int zfcp_erp_action_exists(struct zfcp_erp_action *act) @@ -75,9 +76,9 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act) struct zfcp_adapter *adapter = act->adapter; list_move(&act->list, &act->adapter->erp_ready_head); - zfcp_rec_dbf_event_action("erardy1", act); - up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread("erardy2", adapter); + zfcp_dbf_rec_run("erardy1", act); + wake_up(&adapter->erp_ready_wq); + zfcp_dbf_rec_run("erardy2", act); } static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) @@ -87,21 +88,27 @@ static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) zfcp_erp_action_ready(act); } -static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) +static void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev) { - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE) - zfcp_erp_action_dismiss(&unit->erp_action); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE) + zfcp_erp_action_dismiss(&zfcp_sdev->erp_action); } static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) { - struct zfcp_unit *unit; + struct scsi_device *sdev; if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) zfcp_erp_action_dismiss(&port->erp_action); - else - list_for_each_entry(unit, &port->unit_list_head, list) - zfcp_erp_action_dismiss_unit(unit); + else { + spin_lock(port->adapter->scsi_host->host_lock); + __shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + zfcp_erp_action_dismiss_lun(sdev); + spin_unlock(port->adapter->scsi_host->host_lock); + } } static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) @@ -110,22 +117,27 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE) zfcp_erp_action_dismiss(&adapter->erp_action); - else - list_for_each_entry(port, &adapter->port_list_head, list) + else { + read_lock(&adapter->port_list_lock); + list_for_each_entry(port, &adapter->port_list, list) zfcp_erp_action_dismiss_port(port); + read_unlock(&adapter->port_list_lock); + } } static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit) + struct scsi_device *sdev) { int need = want; - int u_status, p_status, a_status; + int l_status, p_status, a_status; + struct zfcp_scsi_dev *zfcp_sdev; switch (want) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - u_status = atomic_read(&unit->status); - if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE) + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(sdev); + l_status = atomic_read(&zfcp_sdev->status); + if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE) return 0; p_status = atomic_read(&port->status); if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || @@ -134,15 +146,21 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) need = ZFCP_ERP_ACTION_REOPEN_PORT; /* fall through */ - case ZFCP_ERP_ACTION_REOPEN_PORT: case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: p_status = atomic_read(&port->status); + if (!(p_status & ZFCP_STATUS_COMMON_OPEN)) + need = ZFCP_ERP_ACTION_REOPEN_PORT; + /* fall through */ + case ZFCP_ERP_ACTION_REOPEN_PORT: + p_status = atomic_read(&port->status); if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE) return 0; a_status = atomic_read(&adapter->status); if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || a_status & ZFCP_STATUS_COMMON_ERP_FAILED) return 0; + if (p_status & ZFCP_STATUS_COMMON_NOESC) + return need; if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; /* fall through */ @@ -150,105 +168,116 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, a_status = atomic_read(&adapter->status); if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) return 0; + if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) && + !(a_status & ZFCP_STATUS_COMMON_OPEN)) + return 0; /* shutdown requested for closed adapter */ } return need; } -static struct zfcp_erp_action *zfcp_erp_setup_act(int need, +static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit) + struct scsi_device *sdev) { struct zfcp_erp_action *erp_action; - u32 status = 0; + struct zfcp_scsi_dev *zfcp_sdev; switch (need) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - zfcp_unit_get(unit); - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); - erp_action = &unit->erp_action; - if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(sdev); + if (!(act_status & ZFCP_STATUS_ERP_NO_REF)) + if (scsi_device_get(sdev)) + return NULL; + atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + &zfcp_sdev->status); + erp_action = &zfcp_sdev->erp_action; + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); + erp_action->port = port; + erp_action->sdev = sdev; + if (!(atomic_read(&zfcp_sdev->status) & + ZFCP_STATUS_COMMON_RUNNING)) + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; case ZFCP_ERP_ACTION_REOPEN_PORT: case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - zfcp_port_get(port); + if (!get_device(&port->dev)) + return NULL; zfcp_erp_action_dismiss_port(port); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); erp_action = &port->erp_action; + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); + erp_action->port = port; if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - zfcp_adapter_get(adapter); + kref_get(&adapter->ref); zfcp_erp_action_dismiss_adapter(adapter); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); erp_action = &adapter->erp_action; + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) - status = ZFCP_STATUS_ERP_CLOSE_ONLY; + act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; default: return NULL; } - memset(erp_action, 0, sizeof(struct zfcp_erp_action)); erp_action->adapter = adapter; - erp_action->port = port; - erp_action->unit = unit; erp_action->action = need; - erp_action->status = status; + erp_action->status = act_status; return erp_action; } static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, - struct zfcp_unit *unit, char *id, void *ref) + struct scsi_device *sdev, + char *id, u32 act_status) { int retval = 1, need; - struct zfcp_erp_action *act = NULL; + struct zfcp_erp_action *act; - if (!(atomic_read(&adapter->status) & - ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)) + if (!adapter->erp_thread) return -EIO; - need = zfcp_erp_required_act(want, adapter, port, unit); + need = zfcp_erp_required_act(want, adapter, port, sdev); if (!need) goto out; - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); - act = zfcp_erp_setup_act(need, adapter, port, unit); + act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev); if (!act) goto out; + atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); - up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread("eracte1", adapter); + wake_up(&adapter->erp_ready_wq); retval = 0; out: - zfcp_rec_dbf_event_trigger(id, ref, want, need, act, - adapter, port, unit); + zfcp_dbf_rec_trig(id, adapter, port, sdev, want, need); return retval; } static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, - int clear_mask, char *id, void *ref) + int clear_mask, char *id) { zfcp_erp_adapter_block(adapter, clear_mask); zfcp_scsi_schedule_rports_block(adapter); /* ensure propagation of failed status to new devices */ if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - zfcp_erp_adapter_failed(adapter, "erareo1", NULL); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED); return -EIO; } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, - adapter, NULL, NULL, id, ref); + adapter, NULL, NULL, id, 0); } /** @@ -256,18 +285,22 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, * @adapter: Adapter to reopen. * @clear: Status flags to clear. * @id: Id for debug trace event. - * @ref: Reference for debug trace event. */ -void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, - char *id, void *ref) +void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id) { unsigned long flags; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); - _zfcp_erp_adapter_reopen(adapter, clear, id, ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + zfcp_erp_adapter_block(adapter, clear); + zfcp_scsi_schedule_rports_block(adapter); + + write_lock_irqsave(&adapter->erp_lock, flags); + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED); + else + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, + NULL, NULL, id, 0); + write_unlock_irqrestore(&adapter->erp_lock, flags); } /** @@ -275,13 +308,12 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, * @adapter: Adapter to shut down. * @clear: Status flags to clear. * @id: Id for debug trace event. - * @ref: Reference for debug trace event. */ void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, - char *id, void *ref) + char *id) { int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; - zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); + zfcp_erp_adapter_reopen(adapter, clear | flags, id); } /** @@ -289,38 +321,21 @@ void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, * @port: Port to shut down. * @clear: Status flags to clear. * @id: Id for debug trace event. - * @ref: Reference for debug trace event. - */ -void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id, - void *ref) -{ - int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; - zfcp_erp_port_reopen(port, clear | flags, id, ref); -} - -/** - * zfcp_erp_unit_shutdown - Shutdown unit - * @unit: Unit to shut down. - * @clear: Status flags to clear. - * @id: Id for debug trace event. - * @ref: Reference for debug trace event. */ -void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id, - void *ref) +void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id) { int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; - zfcp_erp_unit_reopen(unit, clear | flags, id, ref); + zfcp_erp_port_reopen(port, clear | flags, id); } static void zfcp_erp_port_block(struct zfcp_port *port, int clear) { - zfcp_erp_modify_port_status(port, "erpblk1", NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | clear, - ZFCP_CLEAR); + zfcp_erp_clear_port_status(port, + ZFCP_STATUS_COMMON_UNBLOCKED | clear); } -static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, - int clear, char *id, void *ref) +static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, + char *id) { zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); @@ -329,168 +344,197 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, return; zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, - port->adapter, port, NULL, id, ref); + port->adapter, port, NULL, id, 0); } /** * zfcp_erp_port_forced_reopen - Forced close of port and open again * @port: Port to force close and to reopen. + * @clear: Status flags to clear. * @id: Id for debug trace event. - * @ref: Reference for debug trace event. */ -void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id, - void *ref) +void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id) { unsigned long flags; struct zfcp_adapter *adapter = port->adapter; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); - _zfcp_erp_port_forced_reopen(port, clear, id, ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_lock_irqsave(&adapter->erp_lock, flags); + _zfcp_erp_port_forced_reopen(port, clear, id); + write_unlock_irqrestore(&adapter->erp_lock, flags); } -static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, - void *ref) +static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id) { zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { /* ensure propagation of failed status to new devices */ - zfcp_erp_port_failed(port, "erpreo1", NULL); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); return -EIO; } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, - port->adapter, port, NULL, id, ref); + port->adapter, port, NULL, id, 0); } /** * zfcp_erp_port_reopen - trigger remote port recovery * @port: port to recover * @clear_mask: flags in port status to be cleared + * @id: Id for debug trace event. * * Returns 0 if recovery has been triggered, < 0 if not. */ -int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref) +int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id) { - unsigned long flags; int retval; + unsigned long flags; struct zfcp_adapter *adapter = port->adapter; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); - retval = _zfcp_erp_port_reopen(port, clear, id, ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_lock_irqsave(&adapter->erp_lock, flags); + retval = _zfcp_erp_port_reopen(port, clear, id); + write_unlock_irqrestore(&adapter->erp_lock, flags); return retval; } -static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) +static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask) { - zfcp_erp_modify_unit_status(unit, "erublk1", NULL, - ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, - ZFCP_CLEAR); + zfcp_erp_clear_lun_status(sdev, + ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask); } -static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, - void *ref) +static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, + u32 act_status) { - struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; - zfcp_erp_unit_block(unit, clear); + zfcp_erp_lun_block(sdev, clear); - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) return; - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, - adapter, unit->port, unit, id, ref); + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter, + zfcp_sdev->port, sdev, id, act_status); } /** - * zfcp_erp_unit_reopen - initiate reopen of a unit - * @unit: unit to be reopened - * @clear_mask: specifies flags in unit status to be cleared + * zfcp_erp_lun_reopen - initiate reopen of a LUN + * @sdev: SCSI device / LUN to be reopened + * @clear_mask: specifies flags in LUN status to be cleared + * @id: Id for debug trace event. + * * Return: 0 on success, < 0 on error */ -void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, - void *ref) +void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id) { unsigned long flags; - struct zfcp_port *port = unit->port; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_port *port = zfcp_sdev->port; struct zfcp_adapter *adapter = port->adapter; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); - _zfcp_erp_unit_reopen(unit, clear, id, ref); - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_lock_irqsave(&adapter->erp_lock, flags); + _zfcp_erp_lun_reopen(sdev, clear, id, 0); + write_unlock_irqrestore(&adapter->erp_lock, flags); } -static int status_change_set(unsigned long mask, atomic_t *status) +/** + * zfcp_erp_lun_shutdown - Shutdown LUN + * @sdev: SCSI device / LUN to shut down. + * @clear: Status flags to clear. + * @id: Id for debug trace event. + */ +void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id) { - return (atomic_read(status) ^ mask) & mask; + int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; + zfcp_erp_lun_reopen(sdev, clear | flags, id); } -static int status_change_clear(unsigned long mask, atomic_t *status) +/** + * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion + * @sdev: SCSI device / LUN to shut down. + * @id: Id for debug trace event. + * + * Do not acquire a reference for the LUN when creating the ERP + * action. It is safe, because this function waits for the ERP to + * complete first. This allows to shutdown the LUN, even when the SCSI + * device is in the state SDEV_DEL when scsi_device_get will fail. + */ +void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id) { - return atomic_read(status) & mask; + unsigned long flags; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_port *port = zfcp_sdev->port; + struct zfcp_adapter *adapter = port->adapter; + int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; + + write_lock_irqsave(&adapter->erp_lock, flags); + _zfcp_erp_lun_reopen(sdev, clear, id, ZFCP_STATUS_ERP_NO_REF); + write_unlock_irqrestore(&adapter->erp_lock, flags); + + zfcp_erp_wait(adapter); +} + +static int status_change_set(unsigned long mask, atomic_t *status) +{ + return (atomic_read(status) ^ mask) & mask; } static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) - zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter); + zfcp_dbf_rec_run("eraubl1", &adapter->erp_action); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); } static void zfcp_erp_port_unblock(struct zfcp_port *port) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) - zfcp_rec_dbf_event_port("erpubl1", NULL, port); + zfcp_dbf_rec_run("erpubl1", &port->erp_action); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); } -static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) +static void zfcp_erp_lun_unblock(struct scsi_device *sdev) { - if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) - zfcp_rec_dbf_event_unit("eruubl1", NULL, unit); - atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status)) + zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action); + atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); } static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) { list_move(&erp_action->list, &erp_action->adapter->erp_running_head); - zfcp_rec_dbf_event_action("erator1", erp_action); + zfcp_dbf_rec_run("erator1", erp_action); } static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) { struct zfcp_adapter *adapter = act->adapter; + struct zfcp_fsf_req *req; - if (!act->fsf_req) + if (!act->fsf_req_id) return; - spin_lock(&adapter->req_list_lock); - if (zfcp_reqlist_find_safe(adapter, act->fsf_req) && - act->fsf_req->erp_action == act) { + spin_lock(&adapter->req_list->lock); + req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id); + if (req && req->erp_action == act) { if (act->status & (ZFCP_STATUS_ERP_DISMISSED | ZFCP_STATUS_ERP_TIMEDOUT)) { - act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; - zfcp_rec_dbf_event_action("erscf_1", act); - act->fsf_req->erp_action = NULL; + req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; + zfcp_dbf_rec_run("erscf_1", act); + req->erp_action = NULL; } if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) - zfcp_rec_dbf_event_action("erscf_2", act); - if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | - ZFCP_STATUS_FSFREQ_DISMISSED)) - act->fsf_req = NULL; + zfcp_dbf_rec_run("erscf_2", act); + if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) + act->fsf_req_id = 0; } else - act->fsf_req = NULL; - spin_unlock(&adapter->req_list_lock); + act->fsf_req_id = 0; + spin_unlock(&adapter->req_list->lock); } /** @@ -536,57 +580,57 @@ static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) } static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, - int clear, char *id, void *ref) + int clear, char *id) { struct zfcp_port *port; - list_for_each_entry(port, &adapter->port_list_head, list) - _zfcp_erp_port_reopen(port, clear, id, ref); + read_lock(&adapter->port_list_lock); + list_for_each_entry(port, &adapter->port_list, list) + _zfcp_erp_port_reopen(port, clear, id); + read_unlock(&adapter->port_list_lock); } -static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, - char *id, void *ref) +static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear, + char *id) { - struct zfcp_unit *unit; + struct scsi_device *sdev; - list_for_each_entry(unit, &port->unit_list_head, list) - _zfcp_erp_unit_reopen(unit, clear, id, ref); + spin_lock(port->adapter->scsi_host->host_lock); + __shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + _zfcp_erp_lun_reopen(sdev, clear, id, 0); + spin_unlock(port->adapter->scsi_host->host_lock); } -static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act) +static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) { - struct zfcp_adapter *adapter = act->adapter; - struct zfcp_port *port = act->port; - struct zfcp_unit *unit = act->unit; - u32 status = act->status; - - /* initiate follow-up actions depending on success of finished action */ switch (act->action) { - case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - if (status == ZFCP_ERP_SUCCEEDED) - _zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL); - else - _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL); + _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1"); break; - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - if (status == ZFCP_ERP_SUCCEEDED) - _zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL); - else - _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL); + _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2"); break; - case ZFCP_ERP_ACTION_REOPEN_PORT: - if (status == ZFCP_ERP_SUCCEEDED) - _zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL); - else - _zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL); + _zfcp_erp_port_reopen(act->port, 0, "ersff_3"); + break; + case ZFCP_ERP_ACTION_REOPEN_LUN: + _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0); break; + } +} - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if (status != ZFCP_ERP_SUCCEEDED) - _zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL); +static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) +{ + switch (act->action) { + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1"); + break; + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + _zfcp_erp_port_reopen(act->port, 0, "ersfs_2"); + break; + case ZFCP_ERP_ACTION_REOPEN_PORT: + _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3"); break; } } @@ -595,25 +639,14 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) { unsigned long flags; - read_lock_irqsave(&zfcp_data.config_lock, flags); - read_lock(&adapter->erp_lock); + read_lock_irqsave(&adapter->erp_lock, flags); if (list_empty(&adapter->erp_ready_head) && list_empty(&adapter->erp_running_head)) { atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); wake_up(&adapter->erp_done_wqh); } - read_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); -} - -static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) -{ - if (zfcp_qdio_open(act->adapter)) - return ZFCP_ERP_FAILED; - init_waitqueue_head(&act->adapter->request_wq); - atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); - return ZFCP_ERP_SUCCEEDED; + read_unlock_irqrestore(&adapter->erp_lock, flags); } static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) @@ -623,7 +656,7 @@ static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) adapter->peer_d_id); if (IS_ERR(port)) /* error or port already attached */ return; - _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL); + _zfcp_erp_port_reopen(port, 0, "ereptp1"); } static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) @@ -646,9 +679,8 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) return ZFCP_ERP_FAILED; } - zfcp_rec_dbf_event_thread_lock("erasfx1", adapter); - down(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock("erasfx2", adapter); + wait_event(adapter->erp_ready_wq, + !list_empty(&adapter->erp_ready_head)); if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) break; @@ -687,9 +719,10 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) if (ret) return ZFCP_ERP_FAILED; - zfcp_rec_dbf_event_thread_lock("erasox1", adapter); - down(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock("erasox2", adapter); + zfcp_dbf_rec_run("erasox1", act); + wait_event(adapter->erp_ready_wq, + !list_empty(&adapter->erp_ready_head)); + zfcp_dbf_rec_run("erasox2", act); if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) return ZFCP_ERP_FAILED; @@ -704,7 +737,15 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act) if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) return ZFCP_ERP_FAILED; - atomic_set(&act->adapter->stat_miss, 16); + if (mempool_resize(act->adapter->pool.sr_data, + act->adapter->stat_read_buf_num, GFP_KERNEL)) + return ZFCP_ERP_FAILED; + + if (mempool_resize(act->adapter->pool.status_read_req, + act->adapter->stat_read_buf_num, GFP_KERNEL)) + return ZFCP_ERP_FAILED; + + atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num); if (zfcp_status_read_refill(act->adapter)) return ZFCP_ERP_FAILED; @@ -716,13 +757,12 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) struct zfcp_adapter *adapter = act->adapter; /* close queues to ensure that buffers are not accessed by adapter */ - zfcp_qdio_close(adapter); + zfcp_qdio_close(adapter->qdio); zfcp_fsf_req_dismiss_all(adapter); adapter->fsf_req_seq_no = 0; - zfcp_fc_wka_port_force_offline(&adapter->nsp); - /* all ports and units are closed */ - zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, - ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); + zfcp_fc_wka_ports_force_offline(adapter->gs); + /* all ports and LUNs are closed */ + zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN); atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); @@ -732,7 +772,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act) { struct zfcp_adapter *adapter = act->adapter; - if (zfcp_erp_adapter_strategy_open_qdio(act)) { + if (zfcp_qdio_open(adapter->qdio)) { atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); @@ -801,7 +841,7 @@ static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) return ZFCP_ERP_FAILED; case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: - if (status & ZFCP_STATUS_PORT_PHYS_OPEN) + if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN)) return ZFCP_ERP_SUCCEEDED; } return ZFCP_ERP_FAILED; @@ -839,28 +879,13 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) struct zfcp_port *port = act->port; if (port->wwpn != adapter->peer_wwpn) { - zfcp_erp_port_failed(port, "eroptp1", NULL); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); return ZFCP_ERP_FAILED; } port->d_id = adapter->peer_d_id; return zfcp_erp_port_strategy_open_port(act); } -void zfcp_erp_port_strategy_open_lookup(struct work_struct *work) -{ - int retval; - struct zfcp_port *port = container_of(work, struct zfcp_port, - gid_pn_work); - - retval = zfcp_fc_ns_gid_pn(&port->erp_action); - if (retval == -ENOMEM) - zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM); - port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; - if (retval) - zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED); - zfcp_port_put(port); -} - static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) { struct zfcp_adapter *adapter = act->adapter; @@ -874,28 +899,25 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) return zfcp_erp_open_ptp_port(act); if (!port->d_id) { - zfcp_port_get(port); - if (!queue_work(zfcp_data.work_queue, - &port->gid_pn_work)) - zfcp_port_put(port); - return ZFCP_ERP_CONTINUES; + zfcp_fc_trigger_did_lookup(port); + return ZFCP_ERP_EXIT; } - case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: - if (!port->d_id) - return ZFCP_ERP_FAILED; return zfcp_erp_port_strategy_open_port(act); case ZFCP_ERP_STEP_PORT_OPENING: /* D_ID might have changed during open */ if (p_status & ZFCP_STATUS_COMMON_OPEN) { - if (port->d_id) - return ZFCP_ERP_SUCCEEDED; - else { - act->step = ZFCP_ERP_STEP_PORT_CLOSING; - return ZFCP_ERP_CONTINUES; + if (!port->d_id) { + zfcp_fc_trigger_did_lookup(port); + return ZFCP_ERP_EXIT; } - /* fall through otherwise */ + return ZFCP_ERP_SUCCEEDED; + } + if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { + port->d_id = 0; + return ZFCP_ERP_FAILED; } + /* fall through otherwise */ } return ZFCP_ERP_FAILED; } @@ -903,19 +925,21 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) { struct zfcp_port *port = erp_action->port; + int p_status = atomic_read(&port->status); - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) + if ((p_status & ZFCP_STATUS_COMMON_NOESC) && + !(p_status & ZFCP_STATUS_COMMON_OPEN)) goto close_init_done; switch (erp_action->step) { case ZFCP_ERP_STEP_UNINITIALIZED: zfcp_erp_port_strategy_clearstati(port); - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) + if (p_status & ZFCP_STATUS_COMMON_OPEN) return zfcp_erp_port_strategy_close(erp_action); break; case ZFCP_ERP_STEP_PORT_CLOSING: - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) + if (p_status & ZFCP_STATUS_COMMON_OPEN) return ZFCP_ERP_FAILED; break; } @@ -927,82 +951,86 @@ close_init_done: return zfcp_erp_port_strategy_open_common(erp_action); } -static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) +static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev) { - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_UNIT_SHARED | - ZFCP_STATUS_UNIT_READONLY, - &unit->status); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + + atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, + &zfcp_sdev->status); } -static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) +static int zfcp_erp_lun_strategy_close(struct zfcp_erp_action *erp_action) { - int retval = zfcp_fsf_close_unit(erp_action); + int retval = zfcp_fsf_close_lun(erp_action); if (retval == -ENOMEM) return ZFCP_ERP_NOMEM; - erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; + erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING; if (retval) return ZFCP_ERP_FAILED; return ZFCP_ERP_CONTINUES; } -static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) +static int zfcp_erp_lun_strategy_open(struct zfcp_erp_action *erp_action) { - int retval = zfcp_fsf_open_unit(erp_action); + int retval = zfcp_fsf_open_lun(erp_action); if (retval == -ENOMEM) return ZFCP_ERP_NOMEM; - erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; + erp_action->step = ZFCP_ERP_STEP_LUN_OPENING; if (retval) return ZFCP_ERP_FAILED; return ZFCP_ERP_CONTINUES; } -static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) +static int zfcp_erp_lun_strategy(struct zfcp_erp_action *erp_action) { - struct zfcp_unit *unit = erp_action->unit; + struct scsi_device *sdev = erp_action->sdev; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); switch (erp_action->step) { case ZFCP_ERP_STEP_UNINITIALIZED: - zfcp_erp_unit_strategy_clearstati(unit); - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) - return zfcp_erp_unit_strategy_close(erp_action); + zfcp_erp_lun_strategy_clearstati(sdev); + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) + return zfcp_erp_lun_strategy_close(erp_action); /* already closed, fall through */ - case ZFCP_ERP_STEP_UNIT_CLOSING: - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) + case ZFCP_ERP_STEP_LUN_CLOSING: + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) return ZFCP_ERP_FAILED; if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) return ZFCP_ERP_EXIT; - return zfcp_erp_unit_strategy_open(erp_action); + return zfcp_erp_lun_strategy_open(erp_action); - case ZFCP_ERP_STEP_UNIT_OPENING: - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) + case ZFCP_ERP_STEP_LUN_OPENING: + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN) return ZFCP_ERP_SUCCEEDED; } return ZFCP_ERP_FAILED; } -static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) +static int zfcp_erp_strategy_check_lun(struct scsi_device *sdev, int result) { + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + switch (result) { case ZFCP_ERP_SUCCEEDED : - atomic_set(&unit->erp_counter, 0); - zfcp_erp_unit_unblock(unit); + atomic_set(&zfcp_sdev->erp_counter, 0); + zfcp_erp_lun_unblock(sdev); break; case ZFCP_ERP_FAILED : - atomic_inc(&unit->erp_counter); - if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) { - dev_err(&unit->port->adapter->ccw_device->dev, - "ERP failed for unit 0x%016Lx on " + atomic_inc(&zfcp_sdev->erp_counter); + if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) { + dev_err(&zfcp_sdev->port->adapter->ccw_device->dev, + "ERP failed for LUN 0x%016Lx on " "port 0x%016Lx\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "erusck1", NULL); + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED); } break; } - if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - zfcp_erp_unit_block(unit, 0); + if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { + zfcp_erp_lun_block(sdev, 0); result = ZFCP_ERP_EXIT; } return result; @@ -1026,7 +1054,8 @@ static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) dev_err(&port->adapter->ccw_device->dev, "ERP failed for remote port 0x%016Lx\n", (unsigned long long)port->wwpn); - zfcp_erp_port_failed(port, "erpsck1", NULL); + zfcp_erp_set_port_status(port, + ZFCP_STATUS_COMMON_ERP_FAILED); } break; } @@ -1053,7 +1082,8 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, dev_err(&adapter->ccw_device->dev, "ERP cannot recover an error " "on the FCP device\n"); - zfcp_erp_adapter_failed(adapter, "erasck1", NULL); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_ERP_FAILED); } break; } @@ -1070,12 +1100,12 @@ static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, { struct zfcp_adapter *adapter = erp_action->adapter; struct zfcp_port *port = erp_action->port; - struct zfcp_unit *unit = erp_action->unit; + struct scsi_device *sdev = erp_action->sdev; switch (erp_action->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - result = zfcp_erp_strategy_check_unit(unit, result); + case ZFCP_ERP_ACTION_REOPEN_LUN: + result = zfcp_erp_strategy_check_lun(sdev, result); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: @@ -1110,7 +1140,8 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) int action = act->action; struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; - struct zfcp_unit *unit = act->unit; + struct scsi_device *sdev = act->sdev; + struct zfcp_scsi_dev *zfcp_sdev; u32 erp_status = act->status; switch (action) { @@ -1118,7 +1149,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { _zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "ersscg1", NULL); + "ersscg1"); return ZFCP_ERP_EXIT; } break; @@ -1128,16 +1159,17 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) if (zfcp_erp_strat_change_det(&port->status, erp_status)) { _zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, - "ersscg2", NULL); + "ersscg2"); return ZFCP_ERP_EXIT; } break; - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { - _zfcp_erp_unit_reopen(unit, - ZFCP_STATUS_COMMON_ERP_FAILED, - "ersscg3", NULL); + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(sdev); + if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) { + _zfcp_erp_lun_reopen(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED, + "ersscg3", 0); return ZFCP_ERP_EXIT; } break; @@ -1148,6 +1180,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_scsi_dev *zfcp_sdev; adapter->erp_total_count--; if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { @@ -1156,12 +1189,13 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) } list_del(&erp_action->list); - zfcp_rec_dbf_event_action("eractd1", erp_action); + zfcp_dbf_rec_run("eractd1", erp_action); switch (erp_action->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: + case ZFCP_ERP_ACTION_REOPEN_LUN: + zfcp_sdev = sdev_to_zfcp(erp_action->sdev); atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, - &erp_action->unit->status); + &zfcp_sdev->status); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: @@ -1181,33 +1215,31 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) { struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; - struct zfcp_unit *unit = act->unit; + struct scsi_device *sdev = act->sdev; switch (act->action) { - case ZFCP_ERP_ACTION_REOPEN_UNIT: - if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { - zfcp_unit_get(unit); - if (scsi_queue_work(unit->port->adapter->scsi_host, - &unit->scsi_work) <= 0) - zfcp_unit_put(unit); - } - zfcp_unit_put(unit); + case ZFCP_ERP_ACTION_REOPEN_LUN: + if (!(act->status & ZFCP_STATUS_ERP_NO_REF)) + scsi_device_put(sdev); break; - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: if (result == ZFCP_ERP_SUCCEEDED) zfcp_scsi_schedule_rport_register(port); - zfcp_port_put(port); + /* fall through */ + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + put_device(&port->dev); break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (result == ZFCP_ERP_SUCCEEDED) { register_service_level(&adapter->service_level); - schedule_work(&adapter->scan_work); + zfcp_fc_conditional_port_scan(adapter); + queue_work(adapter->work_queue, &adapter->ns_up_work); } else unregister_service_level(&adapter->service_level); - zfcp_adapter_put(adapter); + + kref_put(&adapter->ref, zfcp_adapter_release); break; } } @@ -1221,8 +1253,8 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) return zfcp_erp_port_forced_strategy(erp_action); case ZFCP_ERP_ACTION_REOPEN_PORT: return zfcp_erp_port_strategy(erp_action); - case ZFCP_ERP_ACTION_REOPEN_UNIT: - return zfcp_erp_unit_strategy(erp_action); + case ZFCP_ERP_ACTION_REOPEN_LUN: + return zfcp_erp_lun_strategy(erp_action); } return ZFCP_ERP_FAILED; } @@ -1230,12 +1262,12 @@ static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) { int retval; - struct zfcp_adapter *adapter = erp_action->adapter; unsigned long flags; + struct zfcp_adapter *adapter = erp_action->adapter; - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); + kref_get(&adapter->ref); + write_lock_irqsave(&adapter->erp_lock, flags); zfcp_erp_strategy_check_fsfreq(erp_action); if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { @@ -1244,14 +1276,17 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) goto unlock; } + if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { + retval = ZFCP_ERP_FAILED; + goto check_target; + } + zfcp_erp_action_to_running(erp_action); /* no lock to allow for blocking operations */ - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_unlock_irqrestore(&adapter->erp_lock, flags); retval = zfcp_erp_strategy_do_action(erp_action); - read_lock_irqsave(&zfcp_data.config_lock, flags); - write_lock(&adapter->erp_lock); + write_lock_irqsave(&adapter->erp_lock, flags); if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) retval = ZFCP_ERP_CONTINUES; @@ -1263,7 +1298,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; } if (adapter->erp_total_count == adapter->erp_low_mem_count) - _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL); + _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1"); else { zfcp_erp_strategy_memwait(erp_action); retval = ZFCP_ERP_CONTINUES; @@ -1278,20 +1313,24 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) goto unlock; } +check_target: retval = zfcp_erp_strategy_check_target(erp_action, retval); zfcp_erp_action_dequeue(erp_action); retval = zfcp_erp_strategy_statechange(erp_action, retval); if (retval == ZFCP_ERP_EXIT) goto unlock; - zfcp_erp_strategy_followup_actions(erp_action); + if (retval == ZFCP_ERP_SUCCEEDED) + zfcp_erp_strategy_followup_success(erp_action); + if (retval == ZFCP_ERP_FAILED) + zfcp_erp_strategy_followup_failed(erp_action); unlock: - write_unlock(&adapter->erp_lock); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + write_unlock_irqrestore(&adapter->erp_lock, flags); if (retval != ZFCP_ERP_CONTINUES) zfcp_erp_action_cleanup(erp_action, retval); + kref_put(&adapter->ref, zfcp_adapter_release); return retval; } @@ -1301,20 +1340,14 @@ static int zfcp_erp_thread(void *data) struct list_head *next; struct zfcp_erp_action *act; unsigned long flags; - int ignore; - daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); - /* Block all signals */ - siginitsetinv(¤t->blocked, 0); - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - wake_up(&adapter->erp_thread_wqh); + for (;;) { + wait_event_interruptible(adapter->erp_ready_wq, + !list_empty(&adapter->erp_ready_head) || + kthread_should_stop()); - while (!(atomic_read(&adapter->status) & - ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { - - zfcp_rec_dbf_event_thread_lock("erthrd1", adapter); - ignore = down_interruptible(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock("erthrd2", adapter); + if (kthread_should_stop()) + break; write_lock_irqsave(&adapter->erp_lock, flags); next = adapter->erp_ready_head.next; @@ -1329,9 +1362,6 @@ static int zfcp_erp_thread(void *data) } } - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - wake_up(&adapter->erp_thread_wqh); - return 0; } @@ -1343,18 +1373,17 @@ static int zfcp_erp_thread(void *data) */ int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) { - int retval; + struct task_struct *thread; - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); - if (retval < 0) { + thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s", + dev_name(&adapter->ccw_device->dev)); + if (IS_ERR(thread)) { dev_err(&adapter->ccw_device->dev, "Creating an ERP thread for the FCP device failed.\n"); - return retval; + return PTR_ERR(thread); } - wait_event(adapter->erp_thread_wqh, - atomic_read(&adapter->status) & - ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); + + adapter->erp_thread = thread; return 0; } @@ -1369,52 +1398,10 @@ int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) */ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) { - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); - up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock("erthrk1", adapter); - - wait_event(adapter->erp_thread_wqh, - !(atomic_read(&adapter->status) & - ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)); - - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, - &adapter->status); -} - -/** - * zfcp_erp_adapter_failed - Set adapter status to failed. - * @adapter: Failed adapter. - * @id: Event id for debug trace. - * @ref: Reference for debug trace. - */ -void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref) -{ - zfcp_erp_modify_adapter_status(adapter, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); -} - -/** - * zfcp_erp_port_failed - Set port status to failed. - * @port: Failed port. - * @id: Event id for debug trace. - * @ref: Reference for debug trace. - */ -void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref) -{ - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); -} - -/** - * zfcp_erp_unit_failed - Set unit status to failed. - * @unit: Failed unit. - * @id: Event id for debug trace. - * @ref: Reference for debug trace. - */ -void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref) -{ - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); + kthread_stop(adapter->erp_thread); + adapter->erp_thread = NULL; + WARN_ON(!list_empty(&adapter->erp_ready_head)); + WARN_ON(!list_empty(&adapter->erp_running_head)); } /** @@ -1429,207 +1416,158 @@ void zfcp_erp_wait(struct zfcp_adapter *adapter) } /** - * zfcp_erp_modify_adapter_status - change adapter status bits + * zfcp_erp_set_adapter_status - set adapter status bits * @adapter: adapter to change the status - * @id: id for the debug trace - * @ref: reference for the debug trace * @mask: status bits to change - * @set_or_clear: ZFCP_SET or ZFCP_CLEAR * - * Changes in common status bits are propagated to attached ports and units. + * Changes in common status bits are propagated to attached ports and LUNs. */ -void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, - void *ref, u32 mask, int set_or_clear) +void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask) { struct zfcp_port *port; + struct scsi_device *sdev; + unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; - if (set_or_clear == ZFCP_SET) { - if (status_change_set(mask, &adapter->status)) - zfcp_rec_dbf_event_adapter(id, ref, adapter); - atomic_set_mask(mask, &adapter->status); - } else { - if (status_change_clear(mask, &adapter->status)) - zfcp_rec_dbf_event_adapter(id, ref, adapter); - atomic_clear_mask(mask, &adapter->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) - atomic_set(&adapter->erp_counter, 0); - } + atomic_set_mask(mask, &adapter->status); + + if (!common_mask) + return; - if (common_mask) - list_for_each_entry(port, &adapter->port_list_head, list) - zfcp_erp_modify_port_status(port, id, ref, common_mask, - set_or_clear); + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) + atomic_set_mask(common_mask, &port->status); + read_unlock_irqrestore(&adapter->port_list_lock, flags); + + spin_lock_irqsave(adapter->scsi_host->host_lock, flags); + __shost_for_each_device(sdev, adapter->scsi_host) + atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status); + spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags); } /** - * zfcp_erp_modify_port_status - change port status bits - * @port: port to change the status bits - * @id: id for the debug trace - * @ref: reference for the debug trace + * zfcp_erp_clear_adapter_status - clear adapter status bits + * @adapter: adapter to change the status * @mask: status bits to change - * @set_or_clear: ZFCP_SET or ZFCP_CLEAR * - * Changes in common status bits are propagated to attached units. + * Changes in common status bits are propagated to attached ports and LUNs. */ -void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, - u32 mask, int set_or_clear) +void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) { - struct zfcp_unit *unit; + struct zfcp_port *port; + struct scsi_device *sdev; + unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; + u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; + + atomic_clear_mask(mask, &adapter->status); + + if (!common_mask) + return; - if (set_or_clear == ZFCP_SET) { - if (status_change_set(mask, &port->status)) - zfcp_rec_dbf_event_port(id, ref, port); - atomic_set_mask(mask, &port->status); - } else { - if (status_change_clear(mask, &port->status)) - zfcp_rec_dbf_event_port(id, ref, port); - atomic_clear_mask(mask, &port->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) + if (clear_counter) + atomic_set(&adapter->erp_counter, 0); + + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) { + atomic_clear_mask(common_mask, &port->status); + if (clear_counter) atomic_set(&port->erp_counter, 0); } + read_unlock_irqrestore(&adapter->port_list_lock, flags); - if (common_mask) - list_for_each_entry(unit, &port->unit_list_head, list) - zfcp_erp_modify_unit_status(unit, id, ref, common_mask, - set_or_clear); -} - -/** - * zfcp_erp_modify_unit_status - change unit status bits - * @unit: unit to change the status bits - * @id: id for the debug trace - * @ref: reference for the debug trace - * @mask: status bits to change - * @set_or_clear: ZFCP_SET or ZFCP_CLEAR - */ -void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, - u32 mask, int set_or_clear) -{ - if (set_or_clear == ZFCP_SET) { - if (status_change_set(mask, &unit->status)) - zfcp_rec_dbf_event_unit(id, ref, unit); - atomic_set_mask(mask, &unit->status); - } else { - if (status_change_clear(mask, &unit->status)) - zfcp_rec_dbf_event_unit(id, ref, unit); - atomic_clear_mask(mask, &unit->status); - if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { - atomic_set(&unit->erp_counter, 0); - } + spin_lock_irqsave(adapter->scsi_host->host_lock, flags); + __shost_for_each_device(sdev, adapter->scsi_host) { + atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status); + if (clear_counter) + atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); } + spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags); } /** - * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP - * @port: The "boxed" port. - * @id: The debug trace id. - * @id: Reference for the debug trace. + * zfcp_erp_set_port_status - set port status bits + * @port: port to change the status + * @mask: status bits to change + * + * Changes in common status bits are propagated to attached LUNs. */ -void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref) +void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask) { + struct scsi_device *sdev; + u32 common_mask = mask & ZFCP_COMMON_FLAGS; unsigned long flags; - read_lock_irqsave(&zfcp_data.config_lock, flags); - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); -} + atomic_set_mask(mask, &port->status); -/** - * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP - * @port: The "boxed" unit. - * @id: The debug trace id. - * @id: Reference for the debug trace. - */ -void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref) -{ - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); - zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); + if (!common_mask) + return; + + spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); + __shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + atomic_set_mask(common_mask, + &sdev_to_zfcp(sdev)->status); + spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags); } /** - * zfcp_erp_port_access_denied - Adapter denied access to port. - * @port: port where access has been denied - * @id: id for debug trace - * @ref: reference for debug trace + * zfcp_erp_clear_port_status - clear port status bits + * @port: adapter to change the status + * @mask: status bits to change * - * Since the adapter has denied access, stop using the port and the - * attached units. + * Changes in common status bits are propagated to attached LUNs. */ -void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref) +void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) { + struct scsi_device *sdev; + u32 common_mask = mask & ZFCP_COMMON_FLAGS; + u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; unsigned long flags; - read_lock_irqsave(&zfcp_data.config_lock, flags); - zfcp_erp_modify_port_status(port, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED | - ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); -} - -/** - * zfcp_erp_unit_access_denied - Adapter denied access to unit. - * @unit: unit where access has been denied - * @id: id for debug trace - * @ref: reference for debug trace - * - * Since the adapter has denied access, stop using the unit. - */ -void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref) -{ - zfcp_erp_modify_unit_status(unit, id, ref, - ZFCP_STATUS_COMMON_ERP_FAILED | - ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); -} + atomic_clear_mask(mask, &port->status); -static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id, - void *ref) -{ - int status = atomic_read(&unit->status); - if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_COMMON_ACCESS_BOXED))) + if (!common_mask) return; - zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); + if (clear_counter) + atomic_set(&port->erp_counter, 0); + + spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); + __shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) { + atomic_clear_mask(common_mask, + &sdev_to_zfcp(sdev)->status); + if (clear_counter) + atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); + } + spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags); } -static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id, - void *ref) +/** + * zfcp_erp_set_lun_status - set lun status bits + * @sdev: SCSI device / lun to set the status bits + * @mask: status bits to change + */ +void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask) { - struct zfcp_unit *unit; - int status = atomic_read(&port->status); - - if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_COMMON_ACCESS_BOXED))) { - list_for_each_entry(unit, &port->unit_list_head, list) - zfcp_erp_unit_access_changed(unit, id, ref); - return; - } + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); + atomic_set_mask(mask, &zfcp_sdev->status); } /** - * zfcp_erp_adapter_access_changed - Process change in adapter ACT - * @adapter: Adapter where the Access Control Table (ACT) changed - * @id: Id for debug trace - * @ref: Reference for debug trace + * zfcp_erp_clear_lun_status - clear lun status bits + * @sdev: SCSi device / lun to clear the status bits + * @mask: status bits to change */ -void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id, - void *ref) +void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask) { - struct zfcp_port *port; - unsigned long flags; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) - return; + atomic_clear_mask(mask, &zfcp_sdev->status); - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) - zfcp_erp_port_access_changed(port, id, ref); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) + atomic_set(&zfcp_sdev->erp_counter, 0); } + |
