Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixe…
Browse files Browse the repository at this point in the history
…s-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6: (23 commits)
  [SCSI] sd: Avoid sending extended inquiry to legacy devices
  [SCSI] libsas: fix wide port hotplug issues
  [SCSI] libfc: fix a circular locking warning during sending RRQ
  [SCSI] qla4xxx: Remove hiwat code so scsi eh does not get escalated when we can make progress
  [SCSI] qla4xxx: Fix srb lookup in qla4xxx_eh_device_reset
  [SCSI] qla4xxx: Fix Driver Fault Recovery Completion
  [SCSI] qla4xxx: add timeout handler
  [SCSI] qla4xxx: Correct Extended Sense Data Errors
  [SCSI] libiscsi: disable bh in and abort handler.
  [SCSI] zfcp: Fix tracing of request id for abort requests
  [SCSI] zfcp: Fix wka port processing
  [SCSI] zfcp: avoid double notify in lowmem scenario
  [SCSI] zfcp: Add port only once to FC transport class
  [SCSI] zfcp: Recover from stalled outbound queue
  [SCSI] zfcp: Fix erp escalation procedure
  [SCSI] zfcp: Fix logic for physical port close
  [SCSI] zfcp: Use -EIO for SBAL allocation failures
  [SCSI] zfcp: Use unchained mode for small ct and els requests
  [SCSI] zfcp: Use correct flags for zfcp_erp_notify
  [SCSI] zfcp: Return -ENOMEM for allocation failures in zfcp_fsf
  ...
  • Loading branch information
Linus Torvalds committed Aug 4, 2009
2 parents c71c090 + ffd4bc2 commit 2edb389
Show file tree
Hide file tree
Showing 18 changed files with 465 additions and 273 deletions.
68 changes: 36 additions & 32 deletions drivers/s390/scsi/zfcp_erp.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,40 +553,35 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
_zfcp_erp_unit_reopen(unit, clear, id, ref);
}

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", NULL);
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", NULL);
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", NULL);
break;

case ZFCP_ERP_ACTION_REOPEN_UNIT:
if (status != ZFCP_ERP_SUCCEEDED)
_zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL);
_zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
break;
}
}

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", NULL);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
_zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT:
_zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
break;
}
}
Expand Down Expand Up @@ -801,7 +796,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;
Expand Down Expand Up @@ -853,11 +848,17 @@ void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
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);
if (!retval) {
port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
goto out;
}
if (retval == -ENOMEM) {
zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM);
goto out;
}
/* all other error condtions */
zfcp_erp_notify(&port->erp_action, 0);
out:
zfcp_port_put(port);
}

Expand Down Expand Up @@ -1289,7 +1290,10 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *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);
Expand Down
8 changes: 3 additions & 5 deletions drivers/s390/scsi/zfcp_fc.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,9 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)

mutex_unlock(&wka_port->mutex);

wait_event_timeout(
wka_port->completion_wq,
wka_port->status == ZFCP_WKA_PORT_ONLINE ||
wka_port->status == ZFCP_WKA_PORT_OFFLINE,
HZ >> 1);
wait_event(wka_port->completion_wq,
wka_port->status == ZFCP_WKA_PORT_ONLINE ||
wka_port->status == ZFCP_WKA_PORT_OFFLINE);

if (wka_port->status == ZFCP_WKA_PORT_ONLINE) {
atomic_inc(&wka_port->refcount);
Expand Down
56 changes: 38 additions & 18 deletions drivers/s390/scsi/zfcp_fsf.c
Original file line number Diff line number Diff line change
Expand Up @@ -670,8 +670,11 @@ static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
zfcp_fsf_sbal_check(adapter), 5 * HZ);
if (ret > 0)
return 0;
if (!ret)
if (!ret) {
atomic_inc(&adapter->qdio_outb_full);
/* assume hanging outbound queue, try queue recovery */
zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL);
}

spin_lock_bh(&adapter->req_q_lock);
return -EIO;
Expand Down Expand Up @@ -722,7 +725,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
req = zfcp_fsf_alloc_qtcb(pool);

if (unlikely(!req))
return ERR_PTR(-EIO);
return ERR_PTR(-ENOMEM);

if (adapter->req_no == 0)
adapter->req_no++;
Expand Down Expand Up @@ -1010,6 +1013,23 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
send_ct->handler(send_ct->handler_data);
}

static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
struct scatterlist *sg_req,
struct scatterlist *sg_resp)
{
sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
sbale[2].addr = sg_virt(sg_req);
sbale[2].length = sg_req->length;
sbale[3].addr = sg_virt(sg_resp);
sbale[3].length = sg_resp->length;
sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
}

static int zfcp_fsf_one_sbal(struct scatterlist *sg)
{
return sg_is_last(sg) && sg->length <= PAGE_SIZE;
}

static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
struct scatterlist *sg_resp,
Expand All @@ -1020,30 +1040,30 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
int bytes;

if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE ||
!sg_is_last(sg_req) || !sg_is_last(sg_resp))
if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp))
return -EOPNOTSUPP;

sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
sbale[2].addr = sg_virt(sg_req);
sbale[2].length = sg_req->length;
sbale[3].addr = sg_virt(sg_resp);
sbale[3].length = sg_resp->length;
sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
return 0;
}

/* use single, unchained SBAL if it can hold the request */
if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) {
zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
return 0;
}

bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
sg_req, max_sbals);
if (bytes <= 0)
return -ENOMEM;
return -EIO;
req->qtcb->bottom.support.req_buf_length = bytes;
req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;

bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
sg_resp, max_sbals);
if (bytes <= 0)
return -ENOMEM;
return -EIO;
req->qtcb->bottom.support.resp_buf_length = bytes;

return 0;
Expand Down Expand Up @@ -1607,10 +1627,10 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
case FSF_ACCESS_DENIED:
wka_port->status = ZFCP_WKA_PORT_OFFLINE;
break;
case FSF_PORT_ALREADY_OPEN:
break;
case FSF_GOOD:
wka_port->handle = header->port_handle;
/* fall through */
case FSF_PORT_ALREADY_OPEN:
wka_port->status = ZFCP_WKA_PORT_ONLINE;
}
out:
Expand Down Expand Up @@ -1731,15 +1751,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
zfcp_fsf_access_denied_port(req, port);
break;
case FSF_PORT_BOXED:
zfcp_erp_port_boxed(port, "fscpph2", req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY;
/* can't use generic zfcp_erp_modify_port_status because
* ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
list_for_each_entry(unit, &port->unit_list_head, list)
atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
&unit->status);
zfcp_erp_port_boxed(port, "fscpph2", req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY;

break;
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (header->fsf_status_qual.word[0]) {
Expand Down Expand Up @@ -2541,7 +2562,6 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,
FSF_MAX_SBALS_PER_REQ);
if (bytes != ZFCP_CFDC_MAX_SIZE) {
retval = -ENOMEM;
zfcp_fsf_req_free(req);
goto out;
}
Expand Down
25 changes: 16 additions & 9 deletions drivers/s390/scsi/zfcp_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,20 +167,21 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
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;
unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
int retval = SUCCESS;
int retry = 3;
char *dbf_tag;

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

spin_lock(&adapter->req_list_lock);
old_req = zfcp_reqlist_find(adapter, old_req_id);
old_req = zfcp_reqlist_find(adapter, old_reqid);
spin_unlock(&adapter->req_list_lock);
if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL,
old_req_id);
old_reqid);
return FAILED; /* completion could be in progress */
}
old_req->data = NULL;
Expand All @@ -189,15 +190,15 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
write_unlock_irqrestore(&adapter->abort_lock, flags);

while (retry--) {
abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit);
abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, 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);
old_reqid);
return SUCCESS;
}
}
Expand All @@ -208,13 +209,14 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);

if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0);
dbf_tag = "okay";
else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0);
dbf_tag = "lte2";
else {
zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0);
dbf_tag = "fail";
retval = FAILED;
}
zfcp_scsi_dbf_event_abort(dbf_tag, adapter, scpnt, abrt_req, old_reqid);
zfcp_fsf_req_free(abrt_req);
return retval;
}
Expand Down Expand Up @@ -534,6 +536,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
struct fc_rport_identifiers ids;
struct fc_rport *rport;

if (port->rport)
return;

ids.node_name = port->wwnn;
ids.port_name = port->wwpn;
ids.port_id = port->d_id;
Expand All @@ -557,8 +562,10 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)
{
struct fc_rport *rport = port->rport;

if (rport)
if (rport) {
fc_remote_port_delete(rport);
port->rport = NULL;
}
}

void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
Expand Down
7 changes: 6 additions & 1 deletion drivers/s390/scsi/zfcp_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,14 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,
struct Scsi_Host *scsi_host = class_to_shost(dev);
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) scsi_host->hostdata[0];
u64 util;

spin_lock_bh(&adapter->qdio_stat_lock);
util = adapter->req_q_util;
spin_unlock_bh(&adapter->qdio_stat_lock);

return sprintf(buf, "%d %llu\n", atomic_read(&adapter->qdio_outb_full),
(unsigned long long)adapter->req_q_util);
(unsigned long long)util);
}
static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);

Expand Down
Loading

0 comments on commit 2edb389

Please sign in to comment.