Skip to content

Commit

Permalink
[SCSI] zfcp: Improve reliability of SCSI eh handlers in zfcp
Browse files Browse the repository at this point in the history
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: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
  • Loading branch information
Christof Schmitt authored and James Bottomley committed Mar 12, 2009
1 parent 92cab0d commit 63caf36
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 99 deletions.
3 changes: 0 additions & 3 deletions drivers/s390/scsi/zfcp_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,9 +586,6 @@ struct zfcp_fsf_req_qtcb {

/********************** ZFCP SPECIFIC DEFINES ********************************/

#define ZFCP_REQ_AUTO_CLEANUP 0x00000002
#define ZFCP_REQ_NO_QTCB 0x00000008

#define ZFCP_SET 0x00000100
#define ZFCP_CLEAR 0x00000200

Expand Down
11 changes: 4 additions & 7 deletions drivers/s390/scsi/zfcp_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *,
struct zfcp_erp_action *);
extern int zfcp_fsf_send_els(struct zfcp_send_els *);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
struct zfcp_unit *,
struct scsi_cmnd *, int, int);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *,
struct scsi_cmnd *);
extern void zfcp_fsf_req_complete(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 *,
struct zfcp_unit *, u8, int);
extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8);
extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long,
struct zfcp_adapter *,
struct zfcp_unit *, int);
struct zfcp_unit *);

/* zfcp_qdio.c */
extern int zfcp_qdio_allocate(struct zfcp_adapter *);
Expand Down
39 changes: 14 additions & 25 deletions drivers/s390/scsi/zfcp_fsf.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include <linux/blktrace_api.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)
{
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
Expand Down Expand Up @@ -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
* @old_req_id: unsigned long
* @adapter: pointer to struct zfcp_adapter
* @unit: pointer to struct zfcp_unit
* @req_flags: integer specifying the request flags
* 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_adapter *adapter,
struct zfcp_unit *unit,
int req_flags)
struct zfcp_unit *unit)
{
struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL;
struct zfcp_adapter *adapter = unit->port->adapter;

spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
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)) {
req = NULL;
goto out;
Expand Down Expand Up @@ -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)
* @adapter: adapter where scsi command is issued
* @unit: unit where command is sent to
* @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,
struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd,
int use_timer, int req_flags)
int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd)
{
struct zfcp_fsf_req *req;
struct fcp_cmnd_iu *fcp_cmnd_iu;
unsigned int sbtype;
int real_bytes, retval = -EIO;
struct zfcp_adapter *adapter = unit->port->adapter;

if (unlikely(!(atomic_read(&unit->status) &
ZFCP_STATUS_COMMON_UNBLOCKED)))
Expand All @@ -2332,7 +2326,8 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
spin_lock(&adapter->req_q_lock);
if (!zfcp_fsf_sbal_available(adapter))
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);
if (IS_ERR(req)) {
retval = PTR_ERR(req);
Expand Down Expand Up @@ -2414,9 +2409,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,

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);
if (unlikely(retval))
goto failed_scsi_cmnd;
Expand All @@ -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
* @adapter: pointer to struct zfcp-adapter
* @unit: pointer to struct zfcp_unit
* @tm_flags: unsigned byte for task management flags
* @req_flags: int request flags
* 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_unit *unit,
u8 tm_flags, int req_flags)
struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
{
struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL;
struct fcp_cmnd_iu *fcp_cmnd_iu;
struct zfcp_adapter *adapter = unit->port->adapter;

if (unlikely(!(atomic_read(&unit->status) &
ZFCP_STATUS_COMMON_UNBLOCKED)))
Expand All @@ -2455,7 +2444,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
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);
if (IS_ERR(req)) {
req = NULL;
Expand Down
124 changes: 60 additions & 64 deletions drivers/s390/scsi/zfcp_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
return 0;;
}

ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0,
ZFCP_REQ_AUTO_CLEANUP);
ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
if (unlikely(ret == -EBUSY))
return SCSI_MLQUEUE_DEVICE_BUSY;
else if (unlikely(ret < 0))
Expand Down Expand Up @@ -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)
{
struct Scsi_Host *scsi_host;
struct zfcp_adapter *adapter;
struct zfcp_unit *unit;
struct zfcp_fsf_req *fsf_req;
struct Scsi_Host *scsi_host = scpnt->device->host;
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) scsi_host->hostdata[0];
struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_fsf_req *old_req, *abrt_req;
unsigned long flags;
unsigned long old_req_id = (unsigned long) scpnt->host_scribble;
int retval = SUCCESS;

scsi_host = scpnt->device->host;
adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
unit = scpnt->device->hostdata;
int retry = 3;

/* avoid race condition between late normal completion and abort */
write_lock_irqsave(&adapter->abort_lock, flags);

/* Check whether corresponding fsf_req is still pending */
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);
if (!fsf_req) {
if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0);
return retval;
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL,
old_req_id);
return SUCCESS;
}
fsf_req->data = NULL;
old_req->data = NULL;

/* don't access old fsf_req after releasing the abort_lock */
write_unlock_irqrestore(&adapter->abort_lock, flags);

fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0);
if (!fsf_req) {
zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
old_req_id);
retval = FAILED;
return retval;
while (retry--) {
abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit);
if (abrt_req)
break;

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,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
wait_event(abrt_req->completion_wq,
abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);

if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0);
} else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0);
} else {
zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0);
if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0);
else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0);
else {
zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0);
retval = FAILED;
}
zfcp_fsf_req_free(fsf_req);

zfcp_fsf_req_free(abrt_req);
return retval;
}

static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags,
struct scsi_cmnd *scpnt)
static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
{
struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_adapter *adapter = unit->port->adapter;
struct zfcp_fsf_req *fsf_req;
int retval = SUCCESS;

/* issue task management function */
fsf_req = zfcp_fsf_send_fcp_ctm(adapter, unit, tm_flags, 0);
if (!fsf_req) {
zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt);
return FAILED;
int retry = 3;

while (retry--) {
fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags);
if (fsf_req)
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,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);

/*
* check completion status of task management function
*/
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt);
retval = FAILED;
Expand All @@ -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_fsf_req_free(fsf_req);

return retval;
}

static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{
struct zfcp_unit *unit = scpnt->device->hostdata;

if (!unit) {
WARN_ON(1);
return SUCCESS;
}
return zfcp_task_mgmt_function(unit, FCP_LOGICAL_UNIT_RESET, scpnt);
return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET);
}

static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt)
{
struct zfcp_unit *unit = scpnt->device->hostdata;

if (!unit) {
WARN_ON(1);
return SUCCESS;
}
return zfcp_task_mgmt_function(unit, FCP_TARGET_RESET, scpnt);
return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET);
}

static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
struct zfcp_unit *unit = scpnt->device->hostdata;
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_wait(adapter);

Expand Down

0 comments on commit 63caf36

Please sign in to comment.