diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 90 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.h | 21 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 194 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 16 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 11 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.h | 22 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 61 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.h | 6 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 141 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 5 |
10 files changed, 400 insertions, 167 deletions
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 18c4f933e8b9..3b368fcf13f4 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -285,6 +285,8 @@ void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter, struct list_head *entry; unsigned long flags; + lockdep_assert_held(&adapter->erp_lock); + if (unlikely(!debug_level_enabled(dbf->rec, level))) return; @@ -599,16 +601,18 @@ void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf) } /** - * zfcp_dbf_scsi - trace event for scsi commands - * @tag: identifier for event - * @sc: pointer to struct scsi_cmnd - * @fsf: pointer to struct zfcp_fsf_req + * zfcp_dbf_scsi_common() - Common trace event helper for scsi. + * @tag: Identifier for event. + * @level: trace level of event. + * @sdev: Pointer to SCSI device as context for this event. + * @sc: Pointer to SCSI command, or NULL with task management function (TMF). + * @fsf: Pointer to FSF request, or NULL. */ -void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc, - struct zfcp_fsf_req *fsf) +void zfcp_dbf_scsi_common(char *tag, int level, struct scsi_device *sdev, + struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf) { struct zfcp_adapter *adapter = - (struct zfcp_adapter *) sc->device->host->hostdata[0]; + (struct zfcp_adapter *) sdev->host->hostdata[0]; struct zfcp_dbf *dbf = adapter->dbf; struct zfcp_dbf_scsi *rec = &dbf->scsi_buf; struct fcp_resp_with_ext *fcp_rsp; @@ -620,16 +624,28 @@ void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc, memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); rec->id = ZFCP_DBF_SCSI_CMND; - rec->scsi_result = sc->result; - rec->scsi_retries = sc->retries; - rec->scsi_allowed = sc->allowed; - rec->scsi_id = sc->device->id; - rec->scsi_lun = (u32)sc->device->lun; - rec->scsi_lun_64_hi = (u32)(sc->device->lun >> 32); - rec->host_scribble = (unsigned long)sc->host_scribble; - - memcpy(rec->scsi_opcode, sc->cmnd, - min((int)sc->cmd_len, ZFCP_DBF_SCSI_OPCODE)); + if (sc) { + rec->scsi_result = sc->result; + rec->scsi_retries = sc->retries; + rec->scsi_allowed = sc->allowed; + rec->scsi_id = sc->device->id; + rec->scsi_lun = (u32)sc->device->lun; + rec->scsi_lun_64_hi = (u32)(sc->device->lun >> 32); + rec->host_scribble = (unsigned long)sc->host_scribble; + + memcpy(rec->scsi_opcode, sc->cmnd, + min_t(int, sc->cmd_len, ZFCP_DBF_SCSI_OPCODE)); + } else { + rec->scsi_result = ~0; + rec->scsi_retries = ~0; + rec->scsi_allowed = ~0; + rec->scsi_id = sdev->id; + rec->scsi_lun = (u32)sdev->lun; + rec->scsi_lun_64_hi = (u32)(sdev->lun >> 32); + rec->host_scribble = ~0; + + memset(rec->scsi_opcode, 0xff, ZFCP_DBF_SCSI_OPCODE); + } if (fsf) { rec->fsf_req_id = fsf->req_id; @@ -664,6 +680,46 @@ void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc, spin_unlock_irqrestore(&dbf->scsi_lock, flags); } +/** + * zfcp_dbf_scsi_eh() - Trace event for special cases of scsi_eh callbacks. + * @tag: Identifier for event. + * @adapter: Pointer to zfcp adapter as context for this event. + * @scsi_id: SCSI ID/target to indicate scope of task management function (TMF). + * @ret: Return value of calling function. + * + * This SCSI trace variant does not depend on any of: + * scsi_cmnd, zfcp_fsf_req, scsi_device. + */ +void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter, + unsigned int scsi_id, int ret) +{ + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_dbf_scsi *rec = &dbf->scsi_buf; + unsigned long flags; + static int const level = 1; + + if (unlikely(!debug_level_enabled(adapter->dbf->scsi, level))) + return; + + spin_lock_irqsave(&dbf->scsi_lock, flags); + memset(rec, 0, sizeof(*rec)); + + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + rec->id = ZFCP_DBF_SCSI_CMND; + rec->scsi_result = ret; /* re-use field, int is 4 bytes and fits */ + rec->scsi_retries = ~0; + rec->scsi_allowed = ~0; + rec->fcp_rsp_info = ~0; + rec->scsi_id = scsi_id; + rec->scsi_lun = (u32)ZFCP_DBF_INVALID_LUN; + rec->scsi_lun_64_hi = (u32)(ZFCP_DBF_INVALID_LUN >> 32); + rec->host_scribble = ~0; + memset(rec->scsi_opcode, 0xff, ZFCP_DBF_SCSI_OPCODE); + + debug_event(dbf->scsi, level, rec, sizeof(*rec)); + spin_unlock_irqrestore(&dbf->scsi_lock, flags); +} + static debug_info_t *zfcp_dbf_reg(const char *name, int size, int rec_size) { struct debug_info *d; diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index e2a973cd2573..d116c07ed77a 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -359,7 +359,7 @@ void _zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *scmd, scmd->device->host->hostdata[0]; if (debug_level_enabled(adapter->dbf->scsi, level)) - zfcp_dbf_scsi(tag, level, scmd, req); + zfcp_dbf_scsi_common(tag, level, scmd->device, scmd, req); } /** @@ -402,16 +402,23 @@ void zfcp_dbf_scsi_abort(char *tag, struct scsi_cmnd *scmd, } /** - * zfcp_dbf_scsi_devreset - trace event for Logical Unit or Target Reset - * @tag: tag indicating success or failure of reset operation - * @scmnd: SCSI command which caused this error recovery - * @flag: indicates type of reset (Target Reset, Logical Unit Reset) + * zfcp_dbf_scsi_devreset() - Trace event for Logical Unit or Target Reset. + * @tag: Tag indicating success or failure of reset operation. + * @sdev: Pointer to SCSI device as context for this event. + * @flag: Indicates type of reset (Target Reset, Logical Unit Reset). + * @fsf_req: Pointer to FSF request representing the TMF, or NULL. */ static inline -void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag, +void zfcp_dbf_scsi_devreset(char *tag, struct scsi_device *sdev, u8 flag, struct zfcp_fsf_req *fsf_req) { + struct zfcp_adapter *adapter = (struct zfcp_adapter *) + sdev->host->hostdata[0]; char tmp_tag[ZFCP_DBF_TAG_LEN]; + static int const level = 1; + + if (unlikely(!debug_level_enabled(adapter->dbf->scsi, level))) + return; if (flag == FCP_TMF_TGT_RESET) memcpy(tmp_tag, "tr_", 3); @@ -419,7 +426,7 @@ void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag, memcpy(tmp_tag, "lr_", 3); memcpy(&tmp_tag[3], tag, 4); - _zfcp_dbf_scsi(tmp_tag, 1, scmnd, fsf_req); + zfcp_dbf_scsi_common(tmp_tag, level, sdev, NULL, fsf_req); } /** diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 1d91a32db08e..e7e6b63905e2 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -19,7 +19,6 @@ enum zfcp_erp_act_flags { ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000, ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000, - ZFCP_STATUS_ERP_DISMISSING = 0x00100000, ZFCP_STATUS_ERP_DISMISSED = 0x00200000, ZFCP_STATUS_ERP_LOWMEM = 0x00400000, ZFCP_STATUS_ERP_NO_REF = 0x00800000, @@ -27,7 +26,6 @@ enum zfcp_erp_act_flags { enum zfcp_erp_steps { ZFCP_ERP_STEP_UNINITIALIZED = 0x0000, - ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001, ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, ZFCP_ERP_STEP_PORT_OPENING = 0x0800, @@ -35,16 +33,28 @@ enum zfcp_erp_steps { ZFCP_ERP_STEP_LUN_OPENING = 0x2000, }; +/** + * enum zfcp_erp_act_type - Type of ERP action object. + * @ZFCP_ERP_ACTION_REOPEN_LUN: LUN recovery. + * @ZFCP_ERP_ACTION_REOPEN_PORT: Port recovery. + * @ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: Forced port recovery. + * @ZFCP_ERP_ACTION_REOPEN_ADAPTER: Adapter recovery. + * @ZFCP_ERP_ACTION_NONE: Eyecatcher pseudo flag to bitwise or-combine with + * either of the first four enum values. + * Used to indicate that an ERP action could not be + * set up despite a detected need for some recovery. + * @ZFCP_ERP_ACTION_FAILED: Eyecatcher pseudo flag to bitwise or-combine with + * either of the first four enum values. + * Used to indicate that ERP not needed because + * the object has ZFCP_STATUS_COMMON_ERP_FAILED. + */ enum zfcp_erp_act_type { 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, -}; - -enum zfcp_erp_act_state { - ZFCP_ERP_ACTION_RUNNING = 1, - ZFCP_ERP_ACTION_READY = 2, + ZFCP_ERP_ACTION_NONE = 0xc0, + ZFCP_ERP_ACTION_FAILED = 0xe0, }; enum zfcp_erp_act_result { @@ -62,14 +72,14 @@ static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) ZFCP_STATUS_COMMON_UNBLOCKED | mask); } -static int zfcp_erp_action_exists(struct zfcp_erp_action *act) +static bool zfcp_erp_action_is_running(struct zfcp_erp_action *act) { struct zfcp_erp_action *curr_act; list_for_each_entry(curr_act, &act->adapter->erp_running_head, list) if (act == curr_act) - return ZFCP_ERP_ACTION_RUNNING; - return 0; + return true; + return false; } static void zfcp_erp_action_ready(struct zfcp_erp_action *act) @@ -85,7 +95,7 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act) static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) { act->status |= ZFCP_STATUS_ERP_DISMISSED; - if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING) + if (zfcp_erp_action_is_running(act)) zfcp_erp_action_ready(act); } @@ -126,6 +136,49 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) } } +static int zfcp_erp_handle_failed(int want, struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct scsi_device *sdev) +{ + int need = want; + struct zfcp_scsi_dev *zsdev; + + switch (want) { + case ZFCP_ERP_ACTION_REOPEN_LUN: + zsdev = sdev_to_zfcp(sdev); + if (atomic_read(&zsdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + need = 0; + break; + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + need = 0; + break; + case ZFCP_ERP_ACTION_REOPEN_PORT: + if (atomic_read(&port->status) & + ZFCP_STATUS_COMMON_ERP_FAILED) { + need = 0; + /* ensure propagation of failed status to new devices */ + zfcp_erp_set_port_status( + port, ZFCP_STATUS_COMMON_ERP_FAILED); + } + break; + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + if (atomic_read(&adapter->status) & + ZFCP_STATUS_COMMON_ERP_FAILED) { + need = 0; + /* ensure propagation of failed status to new devices */ + zfcp_erp_set_adapter_status( + adapter, ZFCP_STATUS_COMMON_ERP_FAILED); + } + break; + default: + need = 0; + break; + } + + return need; +} + static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, struct scsi_device *sdev) @@ -241,48 +294,70 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, return erp_action; } -static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, - struct zfcp_port *port, - struct scsi_device *sdev, - char *id, u32 act_status) +static void zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct scsi_device *sdev, + char *id, u32 act_status) { - int retval = 1, need; + int need; struct zfcp_erp_action *act; - if (!adapter->erp_thread) - return -EIO; + need = zfcp_erp_handle_failed(want, adapter, port, sdev); + if (!need) { + need = ZFCP_ERP_ACTION_FAILED; /* marker for trace */ + goto out; + } + + if (!adapter->erp_thread) { + need = ZFCP_ERP_ACTION_NONE; /* marker for trace */ + goto out; + } need = zfcp_erp_required_act(want, adapter, port, sdev); if (!need) goto out; act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev); - if (!act) + if (!act) { + need |= ZFCP_ERP_ACTION_NONE; /* marker for trace */ goto out; + } atomic_or(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); wake_up(&adapter->erp_ready_wq); - retval = 0; out: zfcp_dbf_rec_trig(id, adapter, port, sdev, want, need); - return retval; } -static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, +void zfcp_erp_port_forced_no_port_dbf(char *id, struct zfcp_adapter *adapter, + u64 port_name, u32 port_id) +{ + unsigned long flags; + static /* don't waste stack */ struct zfcp_port tmpport; + + write_lock_irqsave(&adapter->erp_lock, flags); + /* Stand-in zfcp port with fields just good enough for + * zfcp_dbf_rec_trig() and zfcp_dbf_set_common(). + * Under lock because tmpport is static. + */ + atomic_set(&tmpport.status, -1); /* unknown */ + tmpport.wwpn = port_name; + tmpport.d_id = port_id; + zfcp_dbf_rec_trig(id, adapter, &tmpport, NULL, + ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, + ZFCP_ERP_ACTION_NONE); + write_unlock_irqrestore(&adapter->erp_lock, flags); +} + +static void _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, 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_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, 0); + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, + adapter, NULL, NULL, id, 0); } /** @@ -299,12 +374,8 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id) 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); + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, + NULL, NULL, id, 0); write_unlock_irqrestore(&adapter->erp_lock, flags); } @@ -345,9 +416,6 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - return; - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, port->adapter, port, NULL, id, 0); } @@ -368,19 +436,13 @@ void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id) write_unlock_irqrestore(&adapter->erp_lock, flags); } -static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id) +static void _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_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, 0); + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, + port->adapter, port, NULL, id, 0); } /** @@ -388,20 +450,15 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id) * @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 zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id) { - int retval; unsigned long flags; struct zfcp_adapter *adapter = port->adapter; write_lock_irqsave(&adapter->erp_lock, flags); - retval = _zfcp_erp_port_reopen(port, clear, id); + _zfcp_erp_port_reopen(port, clear, id); write_unlock_irqrestore(&adapter->erp_lock, flags); - - return retval; } static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask) @@ -418,9 +475,6 @@ static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, zfcp_erp_lun_block(sdev, clear); - if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - return; - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter, zfcp_sdev->port, sdev, id, act_status); } @@ -482,21 +536,23 @@ void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id) zfcp_erp_wait(adapter); } -static int status_change_set(unsigned long mask, atomic_t *status) +static int zfcp_erp_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)) + if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, + &adapter->status)) zfcp_dbf_rec_run("eraubl1", &adapter->erp_action); atomic_or(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)) + if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, + &port->status)) zfcp_dbf_rec_run("erpubl1", &port->erp_action); atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); } @@ -505,7 +561,8 @@ static void zfcp_erp_lun_unblock(struct scsi_device *sdev) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status)) + if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, + &zfcp_sdev->status)) zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action); atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); } @@ -553,7 +610,7 @@ void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) unsigned long flags; write_lock_irqsave(&adapter->erp_lock, flags); - if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { + if (zfcp_erp_action_is_running(erp_action)) { erp_action->status |= set_mask; zfcp_erp_action_ready(erp_action); } @@ -1634,3 +1691,14 @@ void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask) atomic_set(&zfcp_sdev->erp_counter, 0); } +/** + * zfcp_erp_adapter_reset_sync() - Really reopen adapter and wait. + * @adapter: Pointer to zfcp_adapter to reopen. + * @id: Trace tag string of length %ZFCP_DBF_TAG_LEN. + */ +void zfcp_erp_adapter_reset_sync(struct zfcp_adapter *adapter, char *id) +{ + zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); + zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, id); + zfcp_erp_wait(adapter); +} diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index e5eed8aac0ce..bd0c5a9f04cb 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -50,17 +50,23 @@ extern void zfcp_dbf_hba_basic(char *, struct zfcp_adapter *); extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); -extern void zfcp_dbf_scsi(char *, int, struct scsi_cmnd *, - struct zfcp_fsf_req *); +extern void zfcp_dbf_scsi_common(char *tag, int level, struct scsi_device *sdev, + struct scsi_cmnd *sc, + struct zfcp_fsf_req *fsf); +extern void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter, + unsigned int scsi_id, int ret); /* zfcp_erp.c */ extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32); extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32); +extern void zfcp_erp_port_forced_no_port_dbf(char *id, + struct zfcp_adapter *adapter, + u64 port_name, u32 port_id); extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *); extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *); extern void zfcp_erp_set_port_status(struct zfcp_port *, u32); extern void zfcp_erp_clear_port_status(struct zfcp_port *, u32); -extern int zfcp_erp_port_reopen(struct zfcp_port *, int, char *); +extern void zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id); extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *); extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *); extern void zfcp_erp_set_lun_status(struct scsi_device *, u32); @@ -73,6 +79,7 @@ extern void zfcp_erp_thread_kill(struct zfcp_adapter *); extern void zfcp_erp_wait(struct zfcp_adapter *); extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long); extern void zfcp_erp_timeout_handler(struct timer_list *t); +extern void zfcp_erp_adapter_reset_sync(struct zfcp_adapter *adapter, char *id); /* zfcp_fc.c */ extern struct kmem_cache *zfcp_fc_req_cache; @@ -120,7 +127,8 @@ extern int zfcp_fsf_send_els(struct zfcp_adapter *, u32, struct zfcp_fsf_ct_els *, unsigned int); extern int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); -extern struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *, u8); +extern struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_device *sdev, + u8 tm_flags); extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *); extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 6162cf57a20a..f6c415d6ef48 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -111,11 +111,10 @@ void zfcp_fc_post_event(struct work_struct *work) list_for_each_entry_safe(event, tmp, &tmp_lh, list) { fc_host_post_event(adapter->scsi_host, fc_get_event_number(), - event->code, event->data); + event->code, event->data); list_del(&event->list); kfree(event); } - } /** @@ -126,7 +125,7 @@ void zfcp_fc_post_event(struct work_struct *work) * @event_data: The event data (e.g. n_port page in case of els) */ void zfcp_fc_enqueue_event(struct zfcp_adapter *adapter, - enum fc_host_event_code event_code, u32 event_data) + enum fc_host_event_code event_code, u32 event_data) { struct zfcp_fc_event *event; @@ -425,6 +424,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work) struct zfcp_port *port = container_of(work, struct zfcp_port, gid_pn_work); + set_worker_desc("zgidpn%16llx", port->wwpn); /* < WORKER_DESC_LEN=24 */ ret = zfcp_fc_ns_gid_pn(port); if (ret) { /* could not issue gid_pn for some reason */ @@ -559,6 +559,7 @@ void zfcp_fc_link_test_work(struct work_struct *work) container_of(work, struct zfcp_port, test_link_work); int retval; + set_worker_desc("zadisc%16llx", port->wwpn); /* < WORKER_DESC_LEN=24 */ get_device(&port->dev); port->rport_task = RPORT_DEL; zfcp_scsi_rport_work(&port->rport_work); @@ -596,7 +597,7 @@ void zfcp_fc_test_link(struct zfcp_port *port) put_device(&port->dev); } -static struct zfcp_fc_req *zfcp_alloc_sg_env(int buf_num) +static struct zfcp_fc_req *zfcp_fc_alloc_sg_env(int buf_num) { struct zfcp_fc_req *fc_req; @@ -748,7 +749,7 @@ void zfcp_fc_scan_ports(struct work_struct *work) if (zfcp_fc_wka_port_get(&adapter->gs->ds)) return; - fc_req = zfcp_alloc_sg_env(buf_num); + fc_req = zfcp_fc_alloc_sg_env(buf_num); if (!fc_req) goto out; diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 6a397ddaadf0..3cd74729cfb9 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -207,21 +207,14 @@ struct zfcp_fc_wka_ports { * zfcp_fc_scsi_to_fcp - setup FCP command with data from scsi_cmnd * @fcp: fcp_cmnd to setup * @scsi: scsi_cmnd where to get LUN, task attributes/flags and CDB - * @tm: task management flags to setup task management command */ static inline -void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi, - u8 tm_flags) +void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi) { u32 datalen; int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun); - if (unlikely(tm_flags)) { - fcp->fc_tm_flags = tm_flags; - return; - } - fcp->fc_pri_ta = FCP_PTA_SIMPLE; if (scsi->sc_data_direction == DMA_FROM_DEVICE) @@ -241,6 +234,19 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi, } /** + * zfcp_fc_fcp_tm() - Setup FCP command as task management command. + * @fcp: Pointer to FCP_CMND IU to set up. + * @dev: Pointer to SCSI_device where to send the task management command. + * @tm_flags: Task management flags to setup tm command. + */ +static inline +void zfcp_fc_fcp_tm(struct fcp_cmnd *fcp, struct scsi_device *dev, u8 tm_flags) +{ + int_to_scsilun(dev->lun, (struct scsi_lun *) &fcp->fc_lun); + fcp->fc_tm_flags = tm_flags; +} + +/** * zfcp_fc_evap_fcp_rsp - evaluate FCP RSP IU and update scsi_cmnd accordingly * @fcp_rsp: FCP RSP IU to evaluate * @scsi: SCSI command where to update status and sense buffer diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index b12cb81ad8a2..3c86e27f094d 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -4,7 +4,7 @@ * * Implementation of FSF commands. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ #define KMSG_COMPONENT "zfcp" @@ -437,6 +437,9 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) #define ZFCP_FSF_PORTSPEED_10GBIT (1 << 3) #define ZFCP_FSF_PORTSPEED_8GBIT (1 << 4) #define ZFCP_FSF_PORTSPEED_16GBIT (1 << 5) +#define ZFCP_FSF_PORTSPEED_32GBIT (1 << 6) +#define ZFCP_FSF_PORTSPEED_64GBIT (1 << 7) +#define ZFCP_FSF_PORTSPEED_128GBIT (1 << 8) #define ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED (1 << 15) static u32 zfcp_fsf_convert_portspeed(u32 fsf_speed) @@ -454,6 +457,12 @@ static u32 zfcp_fsf_convert_portspeed(u32 fsf_speed) fdmi_speed |= FC_PORTSPEED_8GBIT; if (fsf_speed & ZFCP_FSF_PORTSPEED_16GBIT) fdmi_speed |= FC_PORTSPEED_16GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_32GBIT) + fdmi_speed |= FC_PORTSPEED_32GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_64GBIT) + fdmi_speed |= FC_PORTSPEED_64GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_128GBIT) + fdmi_speed |= FC_PORTSPEED_128GBIT; if (fsf_speed & ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED) fdmi_speed |= FC_PORTSPEED_NOT_NEGOTIATED; return fdmi_speed; @@ -662,7 +671,7 @@ static struct zfcp_fsf_req *zfcp_fsf_alloc(mempool_t *pool) return req; } -static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool) +static struct fsf_qtcb *zfcp_fsf_qtcb_alloc(mempool_t *pool) { struct fsf_qtcb *qtcb; @@ -701,9 +710,10 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) { if (likely(pool)) - req->qtcb = zfcp_qtcb_alloc(adapter->pool.qtcb_pool); + req->qtcb = zfcp_fsf_qtcb_alloc( + adapter->pool.qtcb_pool); else - req->qtcb = zfcp_qtcb_alloc(NULL); + req->qtcb = zfcp_fsf_qtcb_alloc(NULL); if (unlikely(!req->qtcb)) { zfcp_fsf_req_free(req); @@ -2036,10 +2046,14 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) sizeof(blktrc)); } -static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) +/** + * zfcp_fsf_fcp_handler_common() - FCP response handler common to I/O and TMF. + * @req: Pointer to FSF request. + * @sdev: Pointer to SCSI device as request context. + */ +static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req, + struct scsi_device *sdev) { - struct scsi_cmnd *scmnd = req->data; - struct scsi_device *sdev = scmnd->device; struct zfcp_scsi_dev *zfcp_sdev; struct fsf_qtcb_header *header = &req->qtcb->header; @@ -2051,7 +2065,7 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_HANDLE_MISMATCH: case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1"); + zfcp_erp_adapter_reopen(req->adapter, 0, "fssfch1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_FCPLUN_NOT_VALID: @@ -2069,8 +2083,7 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) req->qtcb->bottom.io.data_direction, (unsigned long long)zfcp_scsi_dev_lun(sdev), (unsigned long long)zfcp_sdev->port->wwpn); - zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, - "fssfch3"); + zfcp_erp_adapter_shutdown(req->adapter, 0, "fssfch3"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_CMND_LENGTH_NOT_VALID: @@ -2080,8 +2093,7 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) req->qtcb->bottom.io.fcp_cmnd_length, (unsigned long long)zfcp_scsi_dev_lun(sdev), (unsigned long long)zfcp_sdev->port->wwpn); - zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, - "fssfch4"); + zfcp_erp_adapter_shutdown(req->adapter, 0, "fssfch4"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: @@ -2120,7 +2132,7 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req) return; } - zfcp_fsf_fcp_handler_common(req); + zfcp_fsf_fcp_handler_common(req, scpnt->device); if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED); @@ -2258,7 +2270,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) BUILD_BUG_ON(sizeof(struct fcp_cmnd) > FSF_FCP_CMND_SIZE); fcp_cmnd = &req->qtcb->bottom.io.fcp_cmnd.iu; - zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd, 0); + zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd); if ((scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) && scsi_prot_sg_count(scsi_cmnd)) { @@ -2297,10 +2309,11 @@ out: static void zfcp_fsf_fcp_task_mgmt_handler(struct zfcp_fsf_req *req) { + struct scsi_device *sdev = req->data; struct fcp_resp_with_ext *fcp_rsp; struct fcp_resp_rsp_info *rsp_info; - zfcp_fsf_fcp_handler_common(req); + zfcp_fsf_fcp_handler_common(req, sdev); fcp_rsp = &req->qtcb->bottom.io.fcp_rsp.iu; rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; @@ -2311,17 +2324,18 @@ static void zfcp_fsf_fcp_task_mgmt_handler(struct zfcp_fsf_req *req) } /** - * zfcp_fsf_fcp_task_mgmt - send SCSI task management command - * @scmnd: SCSI command to send the task management command for - * @tm_flags: unsigned byte for task management flags - * Returns: on success pointer to struct fsf_req, NULL otherwise + * zfcp_fsf_fcp_task_mgmt() - Send SCSI task management command (TMF). + * @sdev: Pointer to SCSI device to send the task management command to. + * @tm_flags: Unsigned byte for task management flags. + * + * Return: On success pointer to struct zfcp_fsf_req, %NULL otherwise. */ -struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd, +struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_device *sdev, u8 tm_flags) { struct zfcp_fsf_req *req = NULL; struct fcp_cmnd *fcp_cmnd; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio; if (unlikely(!(atomic_read(&zfcp_sdev->status) & @@ -2341,7 +2355,8 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd, goto out; } - req->data = scmnd; + req->data = sdev; + req->handler = zfcp_fsf_fcp_task_mgmt_handler; req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; req->qtcb->header.port_handle = zfcp_sdev->port->handle; @@ -2352,7 +2367,7 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd, zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); fcp_cmnd = &req->qtcb->bottom.io.fcp_cmnd.iu; - zfcp_fc_scsi_to_fcp(fcp_cmnd, scmnd, tm_flags); + zfcp_fc_fcp_tm(fcp_cmnd, sdev, tm_flags); zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); if (!zfcp_fsf_req_send(req)) diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 4baca67aba6d..535628b92f0a 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -4,7 +4,7 @@ * * Interface to the FSF support functions. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ #ifndef FSF_H @@ -356,7 +356,7 @@ struct fsf_qtcb_bottom_config { u32 adapter_features; u32 connection_features; u32 fc_topology; - u32 fc_link_speed; + u32 fc_link_speed; /* one of ZFCP_FSF_PORTSPEED_* */ u32 adapter_type; u8 res0; u8 peer_d_id[3]; @@ -382,7 +382,7 @@ struct fsf_qtcb_bottom_port { u32 class_of_service; /* should be 0x00000006 for class 2 and 3 */ u8 supported_fc4_types[32]; /* should be 0x00000100 for scsi fcp */ u8 active_fc4_types[32]; - u32 supported_speed; /* 0x0001 for 1 GBit/s or 0x0002 for 2 GBit/s */ + u32 supported_speed; /* any combination of ZFCP_FSF_PORTSPEED_* */ u32 maximum_frame_size; /* fixed value of 2112 */ u64 seconds_since_last_reset; u64 tx_frames; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 22f9562f415c..a8efcb330bc1 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -181,6 +181,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) if (abrt_req) break; + zfcp_dbf_scsi_abort("abrt_wt", scpnt, NULL); zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); if (ret) { @@ -264,44 +265,52 @@ static void zfcp_scsi_forget_cmnds(struct zfcp_scsi_dev *zsdev, u8 tm_flags) write_unlock_irqrestore(&adapter->abort_lock, flags); } -static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) +/** + * zfcp_scsi_task_mgmt_function() - Send a task management function (sync). + * @sdev: Pointer to SCSI device to send the task management command to. + * @tm_flags: Task management flags, + * here we only handle %FCP_TMF_TGT_RESET or %FCP_TMF_LUN_RESET. + */ +static int zfcp_scsi_task_mgmt_function(struct scsi_device *sdev, u8 tm_flags) { - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); struct zfcp_fsf_req *fsf_req = NULL; int retval = SUCCESS, ret; int retry = 3; while (retry--) { - fsf_req = zfcp_fsf_fcp_task_mgmt(scpnt, tm_flags); + fsf_req = zfcp_fsf_fcp_task_mgmt(sdev, tm_flags); if (fsf_req) break; + zfcp_dbf_scsi_devreset("wait", sdev, tm_flags, NULL); zfcp_erp_wait(adapter); - ret = fc_block_scsi_eh(scpnt); + ret = fc_block_rport(rport); if (ret) { - zfcp_dbf_scsi_devreset("fiof", scpnt, tm_flags, NULL); + zfcp_dbf_scsi_devreset("fiof", sdev, tm_flags, NULL); return ret; } if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { - zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags, NULL); + zfcp_dbf_scsi_devreset("nres", sdev, tm_flags, NULL); return SUCCESS; } } if (!fsf_req) { - zfcp_dbf_scsi_devreset("reqf", scpnt, tm_flags, NULL); + zfcp_dbf_scsi_devreset("reqf", sdev, tm_flags, NULL); return FAILED; } wait_for_completion(&fsf_req->completion); if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { - zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags, fsf_req); + zfcp_dbf_scsi_devreset("fail", sdev, tm_flags, fsf_req); retval = FAILED; } else { - zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags, fsf_req); + zfcp_dbf_scsi_devreset("okay", sdev, tm_flags, fsf_req); zfcp_scsi_forget_cmnds(zfcp_sdev, tm_flags); } @@ -311,27 +320,81 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) { - return zfcp_task_mgmt_function(scpnt, FCP_TMF_LUN_RESET); + struct scsi_device *sdev = scpnt->device; + + return zfcp_scsi_task_mgmt_function(sdev, FCP_TMF_LUN_RESET); } static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) { - return zfcp_task_mgmt_function(scpnt, FCP_TMF_TGT_RESET); + struct scsi_target *starget = scsi_target(scpnt->device); + struct fc_rport *rport = starget_to_rport(starget); + struct Scsi_Host *shost = rport_to_shost(rport); + struct scsi_device *sdev = NULL, *tmp_sdev; + struct zfcp_adapter *adapter = + (struct zfcp_adapter *)shost->hostdata[0]; + int ret; + + shost_for_each_device(tmp_sdev, shost) { + if (tmp_sdev->id == starget->id) { + sdev = tmp_sdev; + break; + } + } + if (!sdev) { + ret = FAILED; + zfcp_dbf_scsi_eh("tr_nosd", adapter, starget->id, ret); + return ret; + } + + ret = zfcp_scsi_task_mgmt_function(sdev, FCP_TMF_TGT_RESET); + + /* release reference from above shost_for_each_device */ + if (sdev) + scsi_device_put(tmp_sdev); + + return ret; } static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; - int ret; + int ret = SUCCESS, fc_ret; zfcp_erp_adapter_reopen(adapter, 0, "schrh_1"); zfcp_erp_wait(adapter); - ret = fc_block_scsi_eh(scpnt); - if (ret) + fc_ret = fc_block_scsi_eh(scpnt); + if (fc_ret) + ret = fc_ret; + + zfcp_dbf_scsi_eh("schrh_r", adapter, ~0, ret); + return ret; +} + +/** + * zfcp_scsi_sysfs_host_reset() - Support scsi_host sysfs attribute host_reset. + * @shost: Pointer to Scsi_Host to perform action on. + * @reset_type: We support %SCSI_ADAPTER_RESET but not %SCSI_FIRMWARE_RESET. + * + * Return: 0 on %SCSI_ADAPTER_RESET, -%EOPNOTSUPP otherwise. + * + * This is similar to zfcp_sysfs_adapter_failed_store(). + */ +static int zfcp_scsi_sysfs_host_reset(struct Scsi_Host *shost, int reset_type) +{ + struct zfcp_adapter *adapter = + (struct zfcp_adapter *)shost->hostdata[0]; + int ret = 0; + + if (reset_type != SCSI_ADAPTER_RESET) { + ret = -EOPNOTSUPP; + zfcp_dbf_scsi_eh("scshr_n", adapter, ~0, ret); return ret; + } - return SUCCESS; + zfcp_erp_adapter_reset_sync(adapter, "scshr_y"); + return ret; } struct scsi_transport_template *zfcp_scsi_transport_template; @@ -349,6 +412,7 @@ static struct scsi_host_template zfcp_scsi_host_template = { .slave_configure = zfcp_scsi_slave_configure, .slave_destroy = zfcp_scsi_slave_destroy, .change_queue_depth = scsi_change_queue_depth, + .host_reset = zfcp_scsi_sysfs_host_reset, .proc_name = "zfcp", .can_queue = 4096, .this_id = -1, @@ -363,6 +427,7 @@ static struct scsi_host_template zfcp_scsi_host_template = { .shost_attrs = zfcp_sysfs_shost_attrs, .sdev_attrs = zfcp_sysfs_sdev_attrs, .track_queue_depth = 1, + .supported_mode = MODE_INITIATOR, }; /** @@ -430,7 +495,7 @@ void zfcp_scsi_adapter_unregister(struct zfcp_adapter *adapter) } static struct fc_host_statistics* -zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) +zfcp_scsi_init_fc_host_stats(struct zfcp_adapter *adapter) { struct fc_host_statistics *fc_stats; @@ -444,9 +509,9 @@ zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) return adapter->fc_stats; } -static void zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, - struct fsf_qtcb_bottom_port *data, - struct fsf_qtcb_bottom_port *old) +static void zfcp_scsi_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, + struct fsf_qtcb_bottom_port *data, + struct fsf_qtcb_bottom_port *old) { fc_stats->seconds_since_last_reset = data->seconds_since_last_reset - old->seconds_since_last_reset; @@ -477,8 +542,8 @@ static void zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb; } -static void zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, - struct fsf_qtcb_bottom_port *data) +static void zfcp_scsi_set_fc_host_stats(struct fc_host_statistics *fc_stats, + struct fsf_qtcb_bottom_port *data) { fc_stats->seconds_since_last_reset = data->seconds_since_last_reset; fc_stats->tx_frames = data->tx_frames; @@ -502,7 +567,8 @@ static void zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, fc_stats->fcp_output_megabytes = data->output_mb; } -static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host) +static struct fc_host_statistics * +zfcp_scsi_get_fc_host_stats(struct Scsi_Host *host) { struct zfcp_adapter *adapter; struct fc_host_statistics *fc_stats; @@ -510,7 +576,7 @@ static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host) int ret; adapter = (struct zfcp_adapter *)host->hostdata[0]; - fc_stats = zfcp_init_fc_host_stats(adapter); + fc_stats = zfcp_scsi_init_fc_host_stats(adapter); if (!fc_stats) return NULL; @@ -527,16 +593,16 @@ static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host) if (adapter->stats_reset && ((jiffies/HZ - adapter->stats_reset) < data->seconds_since_last_reset)) - zfcp_adjust_fc_host_stats(fc_stats, data, - adapter->stats_reset_data); + zfcp_scsi_adjust_fc_host_stats(fc_stats, data, + adapter->stats_reset_data); else - zfcp_set_fc_host_stats(fc_stats, data); + zfcp_scsi_set_fc_host_stats(fc_stats, data); kfree(data); return fc_stats; } -static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost) +static void zfcp_scsi_reset_fc_host_stats(struct Scsi_Host *shost) { struct zfcp_adapter *adapter; struct fsf_qtcb_bottom_port *data; @@ -558,7 +624,7 @@ static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost) } } -static void zfcp_get_host_port_state(struct Scsi_Host *shost) +static void zfcp_scsi_get_host_port_state(struct Scsi_Host *shost) { struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0]; @@ -575,7 +641,8 @@ static void zfcp_get_host_port_state(struct Scsi_Host *shost) fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; } -static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) +static void zfcp_scsi_set_rport_dev_loss_tmo(struct fc_rport *rport, + u32 timeout) { rport->dev_loss_tmo = timeout; } @@ -602,6 +669,11 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) if (port) { zfcp_erp_port_forced_reopen(port, 0, "sctrpi1"); put_device(&port->dev); + } else { + zfcp_erp_port_forced_no_port_dbf( + "sctrpin", adapter, + rport->port_name /* zfcp_scsi_rport_register */, + rport->port_id /* zfcp_scsi_rport_register */); } } @@ -687,6 +759,9 @@ void zfcp_scsi_rport_work(struct work_struct *work) struct zfcp_port *port = container_of(work, struct zfcp_port, rport_work); + set_worker_desc("zrp%c-%16llx", + (port->rport_task == RPORT_ADD) ? 'a' : 'd', + port->wwpn); /* < WORKER_DESC_LEN=24 */ while (port->rport_task) { if (port->rport_task == RPORT_ADD) { port->rport_task = RPORT_NONE; @@ -761,10 +836,10 @@ struct fc_function_template zfcp_transport_functions = { .show_host_supported_speeds = 1, .show_host_maxframe_size = 1, .show_host_serial_number = 1, - .get_fc_host_stats = zfcp_get_fc_host_stats, - .reset_fc_host_stats = zfcp_reset_fc_host_stats, - .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, - .get_host_port_state = zfcp_get_host_port_state, + .get_fc_host_stats = zfcp_scsi_get_fc_host_stats, + .reset_fc_host_stats = zfcp_scsi_reset_fc_host_stats, + .set_rport_dev_loss_tmo = zfcp_scsi_set_rport_dev_loss_tmo, + .get_host_port_state = zfcp_scsi_get_host_port_state, .terminate_rport_io = zfcp_scsi_terminate_rport_io, .show_host_port_state = 1, .show_host_active_fc4s = 1, diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 3ac823f2540f..b277be6f7611 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -200,10 +200,7 @@ static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev, goto out; } - zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); - zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "syafai2"); - zfcp_erp_wait(adapter); + zfcp_erp_adapter_reset_sync(adapter, "syafai2"); out: zfcp_ccw_adapter_put(adapter); return retval ? retval : (ssize_t) count; |