Commit 63caf367 authored by Christof Schmitt's avatar Christof Schmitt Committed by James Bottomley

[SCSI] zfcp: Improve reliability of SCSI eh handlers in zfcp

When the SCSI midlayer is running error recovery, the low-level error
recovery in zfcp could be running and preventing the SCSI midlayer to
issue error recovery requests. To avoid unnecessary error recovery
escalation, wait for the zfcp erp to finish and retry if necessary.

While reworking the SCSI eh handlers, alsa cleanup the code and
simplify the interface from zfcp_scsi to the fsf layer.
Acked-by: default avatarSwen Schillig <swen@vnet.ibm.com>
Signed-off-by: default avatarChristof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 92cab0d9
...@@ -586,9 +586,6 @@ struct zfcp_fsf_req_qtcb { ...@@ -586,9 +586,6 @@ struct zfcp_fsf_req_qtcb {
/********************** ZFCP SPECIFIC DEFINES ********************************/ /********************** ZFCP SPECIFIC DEFINES ********************************/
#define ZFCP_REQ_AUTO_CLEANUP 0x00000002
#define ZFCP_REQ_NO_QTCB 0x00000008
#define ZFCP_SET 0x00000100 #define ZFCP_SET 0x00000100
#define ZFCP_CLEAR 0x00000200 #define ZFCP_CLEAR 0x00000200
......
...@@ -125,16 +125,13 @@ extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); ...@@ -125,16 +125,13 @@ extern int zfcp_status_read_refill(struct zfcp_adapter *adapter);
extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *,
struct zfcp_erp_action *); struct zfcp_erp_action *);
extern int zfcp_fsf_send_els(struct zfcp_send_els *); extern int zfcp_fsf_send_els(struct zfcp_send_els *);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *,
struct zfcp_unit *, struct scsi_cmnd *);
struct scsi_cmnd *, int, int);
extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *); extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *);
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *, extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8);
struct zfcp_unit *, u8, int);
extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long,
struct zfcp_adapter *, struct zfcp_unit *);
struct zfcp_unit *, int);
/* zfcp_qdio.c */ /* zfcp_qdio.c */
extern int zfcp_qdio_allocate(struct zfcp_adapter *); extern int zfcp_qdio_allocate(struct zfcp_adapter *);
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#include <linux/blktrace_api.h> #include <linux/blktrace_api.h>
#include "zfcp_ext.h" #include "zfcp_ext.h"
#define ZFCP_REQ_AUTO_CLEANUP 0x00000002
#define ZFCP_REQ_NO_QTCB 0x00000008
static void zfcp_fsf_request_timeout_handler(unsigned long data) static void zfcp_fsf_request_timeout_handler(unsigned long data)
{ {
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
...@@ -913,27 +916,22 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) ...@@ -913,27 +916,22 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
/** /**
* zfcp_fsf_abort_fcp_command - abort running SCSI command * zfcp_fsf_abort_fcp_command - abort running SCSI command
* @old_req_id: unsigned long * @old_req_id: unsigned long
* @adapter: pointer to struct zfcp_adapter
* @unit: pointer to struct zfcp_unit * @unit: pointer to struct zfcp_unit
* @req_flags: integer specifying the request flags
* Returns: pointer to struct zfcp_fsf_req * Returns: pointer to struct zfcp_fsf_req
*
* FIXME(design): should be watched by a timeout !!!
*/ */
struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
struct zfcp_adapter *adapter, struct zfcp_unit *unit)
struct zfcp_unit *unit,
int req_flags)
{ {
struct qdio_buffer_element *sbale; struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL; struct zfcp_fsf_req *req = NULL;
struct zfcp_adapter *adapter = unit->port->adapter;
spin_lock_bh(&adapter->req_q_lock); spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter)) if (zfcp_fsf_req_sbal_get(adapter))
goto out; goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
req_flags, adapter->pool.fsf_req_abort); 0, adapter->pool.fsf_req_abort);
if (IS_ERR(req)) { if (IS_ERR(req)) {
req = NULL; req = NULL;
goto out; goto out;
...@@ -2309,21 +2307,17 @@ static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl) ...@@ -2309,21 +2307,17 @@ static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl)
/** /**
* zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
* @adapter: adapter where scsi command is issued
* @unit: unit where command is sent to * @unit: unit where command is sent to
* @scsi_cmnd: scsi command to be sent * @scsi_cmnd: scsi command to be sent
* @timer: timer to be started when request is initiated
* @req_flags: flags for fsf_request
*/ */
int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
struct zfcp_unit *unit, struct scsi_cmnd *scsi_cmnd)
struct scsi_cmnd *scsi_cmnd,
int use_timer, int req_flags)
{ {
struct zfcp_fsf_req *req; struct zfcp_fsf_req *req;
struct fcp_cmnd_iu *fcp_cmnd_iu; struct fcp_cmnd_iu *fcp_cmnd_iu;
unsigned int sbtype; unsigned int sbtype;
int real_bytes, retval = -EIO; int real_bytes, retval = -EIO;
struct zfcp_adapter *adapter = unit->port->adapter;
if (unlikely(!(atomic_read(&unit->status) & if (unlikely(!(atomic_read(&unit->status) &
ZFCP_STATUS_COMMON_UNBLOCKED))) ZFCP_STATUS_COMMON_UNBLOCKED)))
...@@ -2332,7 +2326,8 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ...@@ -2332,7 +2326,8 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
spin_lock(&adapter->req_q_lock); spin_lock(&adapter->req_q_lock);
if (!zfcp_fsf_sbal_available(adapter)) if (!zfcp_fsf_sbal_available(adapter))
goto out; goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND,
ZFCP_REQ_AUTO_CLEANUP,
adapter->pool.fsf_req_scsi); adapter->pool.fsf_req_scsi);
if (IS_ERR(req)) { if (IS_ERR(req)) {
retval = PTR_ERR(req); retval = PTR_ERR(req);
...@@ -2414,9 +2409,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ...@@ -2414,9 +2409,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes);
if (use_timer)
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
retval = zfcp_fsf_req_send(req); retval = zfcp_fsf_req_send(req);
if (unlikely(retval)) if (unlikely(retval))
goto failed_scsi_cmnd; goto failed_scsi_cmnd;
...@@ -2434,19 +2426,16 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ...@@ -2434,19 +2426,16 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
/** /**
* zfcp_fsf_send_fcp_ctm - send SCSI task management command * zfcp_fsf_send_fcp_ctm - send SCSI task management command
* @adapter: pointer to struct zfcp-adapter
* @unit: pointer to struct zfcp_unit * @unit: pointer to struct zfcp_unit
* @tm_flags: unsigned byte for task management flags * @tm_flags: unsigned byte for task management flags
* @req_flags: int request flags
* Returns: on success pointer to struct fsf_req, NULL otherwise * Returns: on success pointer to struct fsf_req, NULL otherwise
*/ */
struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter, struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
struct zfcp_unit *unit,
u8 tm_flags, int req_flags)
{ {
struct qdio_buffer_element *sbale; struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL; struct zfcp_fsf_req *req = NULL;
struct fcp_cmnd_iu *fcp_cmnd_iu; struct fcp_cmnd_iu *fcp_cmnd_iu;
struct zfcp_adapter *adapter = unit->port->adapter;
if (unlikely(!(atomic_read(&unit->status) & if (unlikely(!(atomic_read(&unit->status) &
ZFCP_STATUS_COMMON_UNBLOCKED))) ZFCP_STATUS_COMMON_UNBLOCKED)))
...@@ -2455,7 +2444,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter, ...@@ -2455,7 +2444,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
spin_lock_bh(&adapter->req_q_lock); spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter)) if (zfcp_fsf_req_sbal_get(adapter))
goto out; goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, 0,
adapter->pool.fsf_req_scsi); adapter->pool.fsf_req_scsi);
if (IS_ERR(req)) { if (IS_ERR(req)) {
req = NULL; req = NULL;
......
...@@ -87,8 +87,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, ...@@ -87,8 +87,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
return 0;; return 0;;
} }
ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0, ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
ZFCP_REQ_AUTO_CLEANUP);
if (unlikely(ret == -EBUSY)) if (unlikely(ret == -EBUSY))
return SCSI_MLQUEUE_DEVICE_BUSY; return SCSI_MLQUEUE_DEVICE_BUSY;
else if (unlikely(ret < 0)) else if (unlikely(ret < 0))
...@@ -145,79 +144,91 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) ...@@ -145,79 +144,91 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdp)
static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{ {
struct Scsi_Host *scsi_host; struct Scsi_Host *scsi_host = scpnt->device->host;
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter =
struct zfcp_unit *unit; (struct zfcp_adapter *) scsi_host->hostdata[0];
struct zfcp_fsf_req *fsf_req; struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_fsf_req *old_req, *abrt_req;
unsigned long flags; unsigned long flags;
unsigned long old_req_id = (unsigned long) scpnt->host_scribble; unsigned long old_req_id = (unsigned long) scpnt->host_scribble;
int retval = SUCCESS; int retval = SUCCESS;
int retry = 3;
scsi_host = scpnt->device->host;
adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
unit = scpnt->device->hostdata;
/* avoid race condition between late normal completion and abort */ /* avoid race condition between late normal completion and abort */
write_lock_irqsave(&adapter->abort_lock, flags); write_lock_irqsave(&adapter->abort_lock, flags);
/* Check whether corresponding fsf_req is still pending */
spin_lock(&adapter->req_list_lock); spin_lock(&adapter->req_list_lock);
fsf_req = zfcp_reqlist_find(adapter, old_req_id); old_req = zfcp_reqlist_find(adapter, old_req_id);
spin_unlock(&adapter->req_list_lock); spin_unlock(&adapter->req_list_lock);
if (!fsf_req) { if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags); write_unlock_irqrestore(&adapter->abort_lock, flags);
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL,
return retval; old_req_id);
return SUCCESS;
} }
fsf_req->data = NULL; old_req->data = NULL;
/* don't access old fsf_req after releasing the abort_lock */ /* don't access old fsf_req after releasing the abort_lock */
write_unlock_irqrestore(&adapter->abort_lock, flags); write_unlock_irqrestore(&adapter->abort_lock, flags);
fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0); while (retry--) {
if (!fsf_req) { abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit);
zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, if (abrt_req)
old_req_id); break;
retval = FAILED;
return retval; zfcp_erp_wait(adapter);
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
old_req_id);
return SUCCESS;
}
} }
if (!abrt_req)
return FAILED;
__wait_event(fsf_req->completion_wq, wait_event(abrt_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0); zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0);
} else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0); zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0);
} else { else {
zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0); zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0);
retval = FAILED; retval = FAILED;
} }
zfcp_fsf_req_free(fsf_req); zfcp_fsf_req_free(abrt_req);
return retval; return retval;
} }
static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
struct scsi_cmnd *scpnt)
{ {
struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_adapter *adapter = unit->port->adapter; struct zfcp_adapter *adapter = unit->port->adapter;
struct zfcp_fsf_req *fsf_req; struct zfcp_fsf_req *fsf_req;
int retval = SUCCESS; int retval = SUCCESS;
int retry = 3;
/* issue task management function */
fsf_req = zfcp_fsf_send_fcp_ctm(adapter, unit, tm_flags, 0); while (retry--) {
if (!fsf_req) { fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags);
zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); if (fsf_req)
return FAILED; break;
zfcp_erp_wait(adapter);
if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit,
scpnt);
return SUCCESS;
}
} }
if (!fsf_req)
return FAILED;
__wait_event(fsf_req->completion_wq, wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
/*
* check completion status of task management function
*/
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt);
retval = FAILED; retval = FAILED;
...@@ -228,39 +239,24 @@ static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, ...@@ -228,39 +239,24 @@ static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags,
zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt);
zfcp_fsf_req_free(fsf_req); zfcp_fsf_req_free(fsf_req);
return retval; return retval;
} }
static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{ {
struct zfcp_unit *unit = scpnt->device->hostdata; return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET);
if (!unit) {
WARN_ON(1);
return SUCCESS;
}
return zfcp_task_mgmt_function(unit, FCP_LOGICAL_UNIT_RESET, scpnt);
} }
static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt)
{ {
struct zfcp_unit *unit = scpnt->device->hostdata; return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET);
if (!unit) {
WARN_ON(1);
return SUCCESS;
}
return zfcp_task_mgmt_function(unit, FCP_TARGET_RESET, scpnt);
} }
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{ {
struct zfcp_unit *unit; struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter = unit->port->adapter;
unit = scpnt->device->hostdata;
adapter = unit->port->adapter;
zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment