summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ibmvscsi
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-12-30 17:43:10 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2008-12-30 17:43:10 -0800
commit590cf28580c999c8ba70dc39b40bab09d69e2630 (patch)
tree22b9aa4b148bea8a310b760521d1032eef7d743f /drivers/scsi/ibmvscsi
parentf54a6ec0fd85002d94d05b4bb679508eeb066683 (diff)
parentfb5edd020fa0fbe991f4a473611ad530d2237425 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (104 commits) [SCSI] fcoe: fix configuration problems [SCSI] cxgb3i: fix select/depend problem [SCSI] fcoe: fix incorrect use of struct module [SCSI] cxgb3i: remove use of skb->sp [SCSI] cxgb3i: Add cxgb3i iSCSI driver. [SCSI] zfcp: Remove unnecessary warning message [SCSI] zfcp: Add support for unchained FSF requests [SCSI] zfcp: Remove busid macro [SCSI] zfcp: remove DID_DID flag [SCSI] zfcp: Simplify mask lookups for incoming RSCNs [SCSI] zfcp: Remove initial device data from zfcp_data [SCSI] zfcp: fix compile warning [SCSI] zfcp: Remove adapter list [SCSI] zfcp: Simplify SBAL allocation to fix sparse warnings [SCSI] zfcp: register with SCSI layer on ccw registration [SCSI] zfcp: Fix message line break [SCSI] qla2xxx: changes in multiq code [SCSI] eata: fix the data buffer accessors conversion regression [SCSI] ibmvfc: Improve async event handling [SCSI] lpfc : correct printk types on PPC compiles ...
Diffstat (limited to 'drivers/scsi/ibmvscsi')
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c293
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h32
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c4
3 files changed, 216 insertions, 113 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 7650707a40d..44f202f3310 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -121,6 +121,7 @@ static const struct {
{ IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" },
{ IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" },
{ IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" },
+ { IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" },
{ IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" },
{ IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" },
@@ -278,13 +279,6 @@ static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd)
rsp->data.info.rsp_code))
return DID_ERROR << 16;
- if (!vfc_cmd->status) {
- if (rsp->flags & FCP_RESID_OVER)
- return rsp->scsi_status | (DID_ERROR << 16);
- else
- return rsp->scsi_status | (DID_OK << 16);
- }
-
err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error);
if (err >= 0)
return rsp->scsi_status | (cmd_status[err].result << 16);
@@ -503,6 +497,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
case IBMVFC_HOST_ACTION_INIT:
case IBMVFC_HOST_ACTION_TGT_DEL:
case IBMVFC_HOST_ACTION_QUERY_TGTS:
+ case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
case IBMVFC_HOST_ACTION_TGT_ADD:
case IBMVFC_HOST_ACTION_NONE:
default:
@@ -566,7 +561,7 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost, int relogin)
struct ibmvfc_target *tgt;
if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) {
- if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) {
+ if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) {
dev_err(vhost->dev,
"Host initialization retries exceeded. Taking adapter offline\n");
ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
@@ -765,6 +760,9 @@ static void ibmvfc_scsi_eh_done(struct ibmvfc_event *evt)
cmnd->scsi_done(cmnd);
}
+ if (evt->eh_comp)
+ complete(evt->eh_comp);
+
ibmvfc_free_event(evt);
}
@@ -847,11 +845,12 @@ static void ibmvfc_reset_host(struct ibmvfc_host *vhost)
static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
{
if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) {
- if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) {
+ vhost->delay_init = 1;
+ if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) {
dev_err(vhost->dev,
"Host initialization retries exceeded. Taking adapter offline\n");
ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
- } else if (vhost->init_retries == IBMVFC_MAX_INIT_RETRIES)
+ } else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES)
__ibmvfc_reset_host(vhost);
else
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
@@ -1252,6 +1251,7 @@ static void ibmvfc_init_event(struct ibmvfc_event *evt,
evt->sync_iu = NULL;
evt->crq.format = format;
evt->done = done;
+ evt->eh_comp = NULL;
}
/**
@@ -1381,6 +1381,8 @@ static int ibmvfc_send_event(struct ibmvfc_event *evt,
add_timer(&evt->timer);
}
+ mb();
+
if ((rc = ibmvfc_send_crq(vhost, crq_as_u64[0], crq_as_u64[1]))) {
list_del(&evt->queue);
del_timer(&evt->timer);
@@ -1477,6 +1479,11 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt)
sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len;
if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8)
memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len);
+ if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED))
+ ibmvfc_reinit_host(evt->vhost);
+
+ if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER)))
+ cmnd->result = (DID_ERROR << 16);
ibmvfc_log_error(evt);
}
@@ -1489,6 +1496,9 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt)
cmnd->scsi_done(cmnd);
}
+ if (evt->eh_comp)
+ complete(evt->eh_comp);
+
ibmvfc_free_event(evt);
}
@@ -1627,7 +1637,7 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc)
struct ibmvfc_host *vhost = shost_priv(sdev->host);
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
struct ibmvfc_cmd *tmf;
- struct ibmvfc_event *evt;
+ struct ibmvfc_event *evt = NULL;
union ibmvfc_iu rsp_iu;
struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp;
int rsp_rc = -EBUSY;
@@ -1789,7 +1799,8 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev)
static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
{
struct ibmvfc_host *vhost = shost_priv(sdev->host);
- struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+ struct scsi_target *starget = scsi_target(sdev);
+ struct fc_rport *rport = starget_to_rport(starget);
struct ibmvfc_tmf *tmf;
struct ibmvfc_event *evt, *found_evt;
union ibmvfc_iu rsp;
@@ -1827,7 +1838,7 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
int_to_scsilun(sdev->lun, &tmf->lun);
tmf->flags = (type | IBMVFC_TMF_LUA_VALID);
tmf->cancel_key = (unsigned long)sdev->hostdata;
- tmf->my_cancel_key = (IBMVFC_TMF_CANCEL_KEY | (unsigned long)sdev->hostdata);
+ tmf->my_cancel_key = (unsigned long)starget->hostdata;
evt->sync_iu = &rsp;
init_completion(&evt->comp);
@@ -1859,6 +1870,91 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
}
/**
+ * ibmvfc_match_target - Match function for specified target
+ * @evt: ibmvfc event struct
+ * @device: device to match (starget)
+ *
+ * Returns:
+ * 1 if event matches starget / 0 if event does not match starget
+ **/
+static int ibmvfc_match_target(struct ibmvfc_event *evt, void *device)
+{
+ if (evt->cmnd && scsi_target(evt->cmnd->device) == device)
+ return 1;
+ return 0;
+}
+
+/**
+ * ibmvfc_match_lun - Match function for specified LUN
+ * @evt: ibmvfc event struct
+ * @device: device to match (sdev)
+ *
+ * Returns:
+ * 1 if event matches sdev / 0 if event does not match sdev
+ **/
+static int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device)
+{
+ if (evt->cmnd && evt->cmnd->device == device)
+ return 1;
+ return 0;
+}
+
+/**
+ * ibmvfc_wait_for_ops - Wait for ops to complete
+ * @vhost: ibmvfc host struct
+ * @device: device to match (starget or sdev)
+ * @match: match function
+ *
+ * Returns:
+ * SUCCESS / FAILED
+ **/
+static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device,
+ int (*match) (struct ibmvfc_event *, void *))
+{
+ struct ibmvfc_event *evt;
+ DECLARE_COMPLETION_ONSTACK(comp);
+ int wait;
+ unsigned long flags;
+ signed long timeout = init_timeout * HZ;
+
+ ENTER;
+ do {
+ wait = 0;
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ list_for_each_entry(evt, &vhost->sent, queue) {
+ if (match(evt, device)) {
+ evt->eh_comp = &comp;
+ wait++;
+ }
+ }
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+
+ if (wait) {
+ timeout = wait_for_completion_timeout(&comp, timeout);
+
+ if (!timeout) {
+ wait = 0;
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ list_for_each_entry(evt, &vhost->sent, queue) {
+ if (match(evt, device)) {
+ evt->eh_comp = NULL;
+ wait++;
+ }
+ }
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ if (wait)
+ dev_err(vhost->dev, "Timed out waiting for aborted commands\n");
+ LEAVE;
+ return wait ? FAILED : SUCCESS;
+ }
+ }
+ } while (wait);
+
+ LEAVE;
+ return SUCCESS;
+}
+
+/**
* ibmvfc_eh_abort_handler - Abort a command
* @cmd: scsi command to abort
*
@@ -1867,29 +1963,21 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
**/
static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd)
{
- struct ibmvfc_host *vhost = shost_priv(cmd->device->host);
- struct ibmvfc_event *evt, *pos;
+ struct scsi_device *sdev = cmd->device;
+ struct ibmvfc_host *vhost = shost_priv(sdev->host);
int cancel_rc, abort_rc;
- unsigned long flags;
+ int rc = FAILED;
ENTER;
ibmvfc_wait_while_resetting(vhost);
- cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_ABORT_TASK_SET);
- abort_rc = ibmvfc_abort_task_set(cmd->device);
+ cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET);
+ abort_rc = ibmvfc_abort_task_set(sdev);
- if (!cancel_rc && !abort_rc) {
- spin_lock_irqsave(vhost->host->host_lock, flags);
- list_for_each_entry_safe(evt, pos, &vhost->sent, queue) {
- if (evt->cmnd && evt->cmnd->device == cmd->device)
- ibmvfc_fail_request(evt, DID_ABORT);
- }
- spin_unlock_irqrestore(vhost->host->host_lock, flags);
- LEAVE;
- return SUCCESS;
- }
+ if (!cancel_rc && !abort_rc)
+ rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun);
LEAVE;
- return FAILED;
+ return rc;
}
/**
@@ -1901,29 +1989,21 @@ static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd)
**/
static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd)
{
- struct ibmvfc_host *vhost = shost_priv(cmd->device->host);
- struct ibmvfc_event *evt, *pos;
+ struct scsi_device *sdev = cmd->device;
+ struct ibmvfc_host *vhost = shost_priv(sdev->host);
int cancel_rc, reset_rc;
- unsigned long flags;
+ int rc = FAILED;
ENTER;
ibmvfc_wait_while_resetting(vhost);
- cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_LUN_RESET);
- reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_LUN_RESET, "LUN");
+ cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET);
+ reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN");
- if (!cancel_rc && !reset_rc) {
- spin_lock_irqsave(vhost->host->host_lock, flags);
- list_for_each_entry_safe(evt, pos, &vhost->sent, queue) {
- if (evt->cmnd && evt->cmnd->device == cmd->device)
- ibmvfc_fail_request(evt, DID_ABORT);
- }
- spin_unlock_irqrestore(vhost->host->host_lock, flags);
- LEAVE;
- return SUCCESS;
- }
+ if (!cancel_rc && !reset_rc)
+ rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun);
LEAVE;
- return FAILED;
+ return rc;
}
/**
@@ -1959,31 +2039,23 @@ static void ibmvfc_dev_abort_all(struct scsi_device *sdev, void *data)
**/
static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd)
{
- struct ibmvfc_host *vhost = shost_priv(cmd->device->host);
- struct scsi_target *starget = scsi_target(cmd->device);
- struct ibmvfc_event *evt, *pos;
+ struct scsi_device *sdev = cmd->device;
+ struct ibmvfc_host *vhost = shost_priv(sdev->host);
+ struct scsi_target *starget = scsi_target(sdev);
int reset_rc;
+ int rc = FAILED;
unsigned long cancel_rc = 0;
- unsigned long flags;
ENTER;
ibmvfc_wait_while_resetting(vhost);
starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all);
- reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_TARGET_RESET, "target");
+ reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target");
- if (!cancel_rc && !reset_rc) {
- spin_lock_irqsave(vhost->host->host_lock, flags);
- list_for_each_entry_safe(evt, pos, &vhost->sent, queue) {
- if (evt->cmnd && scsi_target(evt->cmnd->device) == starget)
- ibmvfc_fail_request(evt, DID_ABORT);
- }
- spin_unlock_irqrestore(vhost->host->host_lock, flags);
- LEAVE;
- return SUCCESS;
- }
+ if (!cancel_rc && !reset_rc)
+ rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target);
LEAVE;
- return FAILED;
+ return rc;
}
/**
@@ -2013,23 +2085,18 @@ static void ibmvfc_terminate_rport_io(struct fc_rport *rport)
struct scsi_target *starget = to_scsi_target(&rport->dev);
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
struct ibmvfc_host *vhost = shost_priv(shost);
- struct ibmvfc_event *evt, *pos;
unsigned long cancel_rc = 0;
unsigned long abort_rc = 0;
- unsigned long flags;
+ int rc = FAILED;
ENTER;
starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all);
starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all);
- if (!cancel_rc && !abort_rc) {
- spin_lock_irqsave(shost->host_lock, flags);
- list_for_each_entry_safe(evt, pos, &vhost->sent, queue) {
- if (evt->cmnd && scsi_target(evt->cmnd->device) == starget)
- ibmvfc_fail_request(evt, DID_ABORT);
- }
- spin_unlock_irqrestore(shost->host_lock, flags);
- } else
+ if (!cancel_rc && !abort_rc)
+ rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target);
+
+ if (rc == FAILED)
ibmvfc_issue_fc_host_lip(shost);
LEAVE;
}
@@ -2089,15 +2156,17 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
case IBMVFC_AE_LINK_UP:
case IBMVFC_AE_RESUME:
vhost->events_to_log |= IBMVFC_AE_LINKUP;
- ibmvfc_init_host(vhost, 1);
+ vhost->delay_init = 1;
+ __ibmvfc_reset_host(vhost);
break;
case IBMVFC_AE_SCN_FABRIC:
+ case IBMVFC_AE_SCN_DOMAIN:
vhost->events_to_log |= IBMVFC_AE_RSCN;
- ibmvfc_init_host(vhost, 1);
+ vhost->delay_init = 1;
+ __ibmvfc_reset_host(vhost);
break;
case IBMVFC_AE_SCN_NPORT:
case IBMVFC_AE_SCN_GROUP:
- case IBMVFC_AE_SCN_DOMAIN:
vhost->events_to_log |= IBMVFC_AE_RSCN;
case IBMVFC_AE_ELS_LOGO:
case IBMVFC_AE_ELS_PRLO:
@@ -2263,6 +2332,28 @@ static int ibmvfc_slave_alloc(struct scsi_device *sdev)
}
/**
+ * ibmvfc_target_alloc - Setup the target's task set value
+ * @starget: struct scsi_target
+ *
+ * Set the target's task set value so that error handling works as
+ * expected.
+ *
+ * Returns:
+ * 0 on success / -ENXIO if device does not exist
+ **/
+static int ibmvfc_target_alloc(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct ibmvfc_host *vhost = shost_priv(shost);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ starget->hostdata = (void *)(unsigned long)vhost->task_set++;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return 0;
+}
+
+/**
* ibmvfc_slave_configure - Configure the device
* @sdev: struct scsi_device device to configure
*
@@ -2541,6 +2632,7 @@ static struct scsi_host_template driver_template = {
.eh_host_reset_handler = ibmvfc_eh_host_reset_handler,
.slave_alloc = ibmvfc_slave_alloc,
.slave_configure = ibmvfc_slave_configure,
+ .target_alloc = ibmvfc_target_alloc,
.scan_finished = ibmvfc_scan_finished,
.change_queue_depth = ibmvfc_change_queue_depth,
.change_queue_type = ibmvfc_change_queue_type,
@@ -2637,7 +2729,7 @@ static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance)
} else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
vio_disable_interrupts(vdev);
ibmvfc_handle_async(async, vhost);
- crq->valid = 0;
+ async->valid = 0;
} else
done = 1;
}
@@ -2669,7 +2761,7 @@ static void ibmvfc_init_tgt(struct ibmvfc_target *tgt,
static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
void (*job_step) (struct ibmvfc_target *))
{
- if (++tgt->init_retries > IBMVFC_MAX_INIT_RETRIES) {
+ if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
wake_up(&tgt->vhost->work_wait_q);
} else
@@ -2708,6 +2800,8 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
rsp->status, rsp->error, status);
if (ibmvfc_retry_cmd(rsp->status, rsp->error))
ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
+ else
+ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
break;
};
@@ -2802,6 +2896,8 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt)
if (ibmvfc_retry_cmd(rsp->status, rsp->error))
ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
+ else
+ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
break;
};
@@ -3093,6 +3189,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
else if (ibmvfc_retry_cmd(rsp->status, rsp->error))
ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target);
+ else
+ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
break;
};
@@ -3423,6 +3521,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
case IBMVFC_HOST_ACTION_ALLOC_TGTS:
case IBMVFC_HOST_ACTION_TGT_ADD:
case IBMVFC_HOST_ACTION_TGT_DEL:
+ case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
case IBMVFC_HOST_ACTION_QUERY:
default:
break;
@@ -3519,7 +3618,13 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
break;
case IBMVFC_HOST_ACTION_INIT:
BUG_ON(vhost->state != IBMVFC_INITIALIZING);
- vhost->job_step(vhost);
+ if (vhost->delay_init) {
+ vhost->delay_init = 0;
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ ssleep(15);
+ return;
+ } else
+ vhost->job_step(vhost);
break;
case IBMVFC_HOST_ACTION_QUERY:
list_for_each_entry(tgt, &vhost->targets, queue)
@@ -3538,6 +3643,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL);
break;
case IBMVFC_HOST_ACTION_TGT_DEL:
+ case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
list_for_each_entry(tgt, &vhost->targets, queue) {
if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
tgt_dbg(tgt, "Deleting rport\n");
@@ -3553,8 +3659,17 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
}
if (vhost->state == IBMVFC_INITIALIZING) {
- ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
- vhost->job_step = ibmvfc_discover_targets;
+ if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) {
+ ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE);
+ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD);
+ vhost->init_retries = 0;
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ scsi_unblock_requests(vhost->host);
+ return;
+ } else {
+ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
+ vhost->job_step = ibmvfc_discover_targets;
+ }
} else {
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
spin_unlock_irqrestore(vhost->host->host_lock, flags);
@@ -3577,14 +3692,8 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
}
}
- if (!ibmvfc_dev_init_to_do(vhost)) {
- ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE);
- ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD);
- vhost->init_retries = 0;
- spin_unlock_irqrestore(vhost->host->host_lock, flags);
- scsi_unblock_requests(vhost->host);
- return;
- }
+ if (!ibmvfc_dev_init_to_do(vhost))
+ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED);
break;
case IBMVFC_HOST_ACTION_TGT_ADD:
list_for_each_entry(tgt, &vhost->targets, queue) {
@@ -3592,16 +3701,6 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
spin_unlock_irqrestore(vhost->host->host_lock, flags);
ibmvfc_tgt_add_rport(tgt);
return;
- } else if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
- tgt_dbg(tgt, "Deleting rport\n");
- rport = tgt->rport;
- tgt->rport = NULL;
- list_del(&tgt->queue);
- spin_unlock_irqrestore(vhost->host->host_lock, flags);
- if (rport)
- fc_remote_port_delete(rport);
- kref_put(&tgt->kref, ibmvfc_release_tgt);
- return;
}
}
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index fb3177ab669..babdf3db59d 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -29,11 +29,11 @@
#include "viosrp.h"
#define IBMVFC_NAME "ibmvfc"
-#define IBMVFC_DRIVER_VERSION "1.0.2"
-#define IBMVFC_DRIVER_DATE "(August 14, 2008)"
+#define IBMVFC_DRIVER_VERSION "1.0.4"
+#define IBMVFC_DRIVER_DATE "(November 14, 2008)"
#define IBMVFC_DEFAULT_TIMEOUT 15
-#define IBMVFC_INIT_TIMEOUT 30
+#define IBMVFC_INIT_TIMEOUT 120
#define IBMVFC_MAX_REQUESTS_DEFAULT 100
#define IBMVFC_DEBUG 0
@@ -43,7 +43,8 @@
#define IBMVFC_MAX_DISC_THREADS 4
#define IBMVFC_TGT_MEMPOOL_SZ 64
#define IBMVFC_MAX_CMDS_PER_LUN 64
-#define IBMVFC_MAX_INIT_RETRIES 3
+#define IBMVFC_MAX_HOST_INIT_RETRIES 6
+#define IBMVFC_MAX_TGT_INIT_RETRIES 3
#define IBMVFC_DEV_LOSS_TMO (5 * 60)
#define IBMVFC_DEFAULT_LOG_LEVEL 2
#define IBMVFC_MAX_CDB_LEN 16
@@ -109,6 +110,7 @@ enum ibmvfc_vios_errors {
IBMVFC_TRANS_CANCELLED = 0x0006,
IBMVFC_TRANS_CANCELLED_IMPLICIT = 0x0007,
IBMVFC_INSUFFICIENT_RESOURCE = 0x0008,
+ IBMVFC_PLOGI_REQUIRED = 0x0010,
IBMVFC_COMMAND_FAILED = 0x8000,
};
@@ -337,7 +339,6 @@ struct ibmvfc_tmf {
#define IBMVFC_TMF_LUA_VALID 0x40
u32 cancel_key;
u32 my_cancel_key;
-#define IBMVFC_TMF_CANCEL_KEY 0x80000000
u32 pad;
u64 reserved[2];
}__attribute__((packed, aligned (8)));
@@ -524,10 +525,10 @@ enum ibmvfc_async_event {
};
struct ibmvfc_crq {
- u8 valid;
- u8 format;
+ volatile u8 valid;
+ volatile u8 format;
u8 reserved[6];
- u64 ioba;
+ volatile u64 ioba;
}__attribute__((packed, aligned (8)));
struct ibmvfc_crq_queue {
@@ -537,13 +538,13 @@ struct ibmvfc_crq_queue {
};
struct ibmvfc_async_crq {
- u8 valid;
+ volatile u8 valid;
u8 pad[3];
u32 pad2;
- u64 event;
- u64 scsi_id;
- u64 wwpn;
- u64 node_name;
+ volatile u64 event;
+ volatile u64 scsi_id;
+ volatile u64 wwpn;
+ volatile u64 node_name;
u64 reserved;
}__attribute__((packed, aligned (8)));
@@ -606,6 +607,7 @@ struct ibmvfc_event {
struct srp_direct_buf *ext_list;
dma_addr_t ext_list_token;
struct completion comp;
+ struct completion *eh_comp;
struct timer_list timer;
};
@@ -626,6 +628,7 @@ enum ibmvfc_host_action {
IBMVFC_HOST_ACTION_TGT_DEL,
IBMVFC_HOST_ACTION_ALLOC_TGTS,
IBMVFC_HOST_ACTION_TGT_INIT,
+ IBMVFC_HOST_ACTION_TGT_DEL_FAILED,
IBMVFC_HOST_ACTION_TGT_ADD,
};
@@ -671,6 +674,7 @@ struct ibmvfc_host {
int discovery_threads;
int client_migrated;
int reinit;
+ int delay_init;
int events_to_log;
#define IBMVFC_AE_LINKUP 0x0001
#define IBMVFC_AE_LINKDOWN 0x0002
@@ -700,7 +704,7 @@ struct ibmvfc_host {
#define ibmvfc_log(vhost, level, ...) \
do { \
- if (level >= (vhost)->log_level) \
+ if ((vhost)->log_level >= level) \
dev_err((vhost)->dev, ##__VA_ARGS__); \
} while (0)
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 6cad1758243..868d35ea01b 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -107,7 +107,7 @@ module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(max_channel, "Largest channel value");
module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
-module_param_named(max_requests, max_requests, int, S_IRUGO | S_IWUSR);
+module_param_named(max_requests, max_requests, int, S_IRUGO);
MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
/* ------------------------------------------------------------
@@ -1657,7 +1657,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
vdev->dev.driver_data = NULL;
- driver_template.can_queue = max_requests;
+ driver_template.can_queue = max_requests - 2;
host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
if (!host) {
dev_err(&vdev->dev, "couldn't allocate host data\n");