--- /dev/null
+Subject: ibmvfc oops while processing async events
+From: Brian King <brking@us.ibm.com>
+Date: Thu Nov 20 13:43:45 2008 +0100:
+References: bnc#445541
+
+While running error injection (port disable/enable loop) during
+I/O stress, the following oops occurred:
+
+cpu 0x0: Vector: 300 (Data Access) at [c00000000f4cbb10]
+ pc: d0000000000c5c44: .ibmvfc_interrupt+0x1a4/0x1f8 [ibmvfc]
+ lr: d0000000000c5c44: .ibmvfc_interrupt+0x1a4/0x1f8 [ibmvfc]
+ sp: c00000000f4cbd90
+ msr: 8000000000009032
+ dar: 0
+ dsisr: 42000000
+ current = 0xc00000001dee77a0
+ paca = 0xc000000000a92c80
+
+There is a window in the ibmvfc interrupt handler. If, while
+processing an interrupt, after processing both the regular crq
+and the async crq, an async event is added to the async crq, we
+will oops when we process the async queue a second time, due to
+an obvious bug in the code.
+
+Signed-off-by: Brian King <brking@us.ibm.com>
+Acked-by: Hannes Reinecke <hare@suse.de>
+
+---
+ drivers/scsi/ibmvscsi/ibmvfc.c | 266 +++++++++++++++++++++++++++--------------
+ drivers/scsi/ibmvscsi/ibmvfc.h | 26 ++--
+ 2 files changed, 191 insertions(+), 101 deletions(-)
+
+--- 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
+ 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(struc
+ 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:
+@@ -765,6 +760,9 @@ static void ibmvfc_scsi_eh_done(struct i
+ cmnd->scsi_done(cmnd);
+ }
+
++ if (evt->eh_comp)
++ complete(evt->eh_comp);
++
+ ibmvfc_free_event(evt);
+ }
+
+@@ -1253,6 +1251,7 @@ static void ibmvfc_init_event(struct ibm
+ evt->sync_iu = NULL;
+ evt->crq.format = format;
+ evt->done = done;
++ evt->eh_comp = NULL;
+ }
+
+ /**
+@@ -1478,6 +1477,11 @@ static void ibmvfc_scsi_done(struct ibmv
+ 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);
+ }
+@@ -1490,6 +1494,9 @@ static void ibmvfc_scsi_done(struct ibmv
+ cmnd->scsi_done(cmnd);
+ }
+
++ if (evt->eh_comp)
++ complete(evt->eh_comp);
++
+ ibmvfc_free_event(evt);
+ }
+
+@@ -1628,7 +1635,7 @@ static int ibmvfc_reset_device(struct sc
+ 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;
+@@ -1790,7 +1797,8 @@ static int ibmvfc_abort_task_set(struct
+ 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;
+@@ -1828,7 +1836,7 @@ static int ibmvfc_cancel_all(struct scsi
+ 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);
+@@ -1860,6 +1868,91 @@ static int ibmvfc_cancel_all(struct scsi
+ }
+
+ /**
++ * 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 = ∁
++ 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
+ *
+@@ -1868,29 +1961,21 @@ static int ibmvfc_cancel_all(struct scsi
+ **/
+ 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;
+ }
+
+ /**
+@@ -1902,29 +1987,21 @@ static int ibmvfc_eh_abort_handler(struc
+ **/
+ 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;
+ }
+
+ /**
+@@ -1960,31 +2037,23 @@ static void ibmvfc_dev_abort_all(struct
+ **/
+ 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;
+ }
+
+ /**
+@@ -2014,23 +2083,18 @@ static void ibmvfc_terminate_rport_io(st
+ 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;
+ }
+@@ -2266,6 +2330,28 @@ static int ibmvfc_slave_alloc(struct scs
+ }
+
+ /**
++ * 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
+ *
+@@ -2544,6 +2630,7 @@ static struct scsi_host_template driver_
+ .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,
+@@ -2640,7 +2727,7 @@ static irqreturn_t ibmvfc_interrupt(int
+ } 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;
+ }
+@@ -2711,6 +2798,8 @@ static void ibmvfc_tgt_prli_done(struct
+ 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;
+ };
+
+@@ -2805,6 +2894,8 @@ static void ibmvfc_tgt_plogi_done(struct
+
+ 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;
+ };
+
+@@ -3096,6 +3187,8 @@ static void ibmvfc_tgt_query_target_done
+ 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;
+ };
+
+@@ -3426,6 +3519,7 @@ static int __ibmvfc_work_to_do(struct ib
+ 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;
+@@ -3547,6 +3641,7 @@ static void ibmvfc_do_work(struct ibmvfc
+ 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");
+@@ -3562,8 +3657,17 @@ static void ibmvfc_do_work(struct ibmvfc
+ }
+
+ 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);
+@@ -3586,14 +3690,8 @@ static void ibmvfc_do_work(struct ibmvfc
+ }
+ }
+
+- 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) {
+@@ -3601,16 +3699,6 @@ static void ibmvfc_do_work(struct ibmvfc
+ 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;
+ }
+ }
+
+--- a/drivers/scsi/ibmvscsi/ibmvfc.h
++++ b/drivers/scsi/ibmvscsi/ibmvfc.h
+@@ -29,8 +29,8 @@
+ #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 120
+@@ -110,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,
+ };
+
+@@ -338,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)));
+@@ -525,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 {
+@@ -538,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)));
+
+@@ -607,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;
+ };
+
+@@ -627,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,
+ };
+
+@@ -702,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)
+