]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/ibmvscsi/ibmvfc.c
powerpc: Cleanup from l64 to ll64 change drivers/scsi
[linux-2.6-omap-h63xx.git] / drivers / scsi / ibmvscsi / ibmvfc.c
index 7650707a40defc4f7a032a4972cad4afabd99af9..91ef669d98f64583e94fb9d57c4e855679cc680b 100644 (file)
@@ -101,7 +101,7 @@ static const struct {
        { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_ESTABLISH, DID_ERROR, 1, 1, "unable to establish" },
        { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_FAULT, DID_OK, 1, 0, "transport fault" },
        { IBMVFC_FABRIC_MAPPED, IBMVFC_CMD_TIMEOUT, DID_TIME_OUT, 1, 1, "command timeout" },
-       { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_NO_CONNECT, 1, 1, "network down" },
+       { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_TRANSPORT_DISRUPTED, 1, 1, "network down" },
        { IBMVFC_FABRIC_MAPPED, IBMVFC_HW_FAILURE, DID_ERROR, 1, 1, "hardware failure" },
        { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DOWN_ERR, DID_REQUEUE, 0, 0, "link down" },
        { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DEAD_ERR, DID_ERROR, 0, 0, "link dead" },
@@ -115,12 +115,13 @@ static const struct {
 
        { IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" },
        { IBMVFC_VIOS_FAILURE, IBMVFC_SW_FAILURE, DID_ERROR, 0, 1, "software failure" },
-       { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ABORT, 0, 1, "invalid parameter" },
-       { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ABORT, 0, 1, "missing parameter" },
+       { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ERROR, 0, 1, "invalid parameter" },
+       { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ERROR, 0, 1, "missing parameter" },
        { IBMVFC_VIOS_FAILURE, IBMVFC_HOST_IO_BUS, DID_ERROR, 1, 1, "host I/O bus failure" },
-       { 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_TRANS_CANCELLED, DID_ERROR, 0, 1, "transaction cancelled" },
+       { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ERROR, 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);
@@ -934,7 +933,7 @@ static void ibmvfc_get_host_speed(struct Scsi_Host *shost)
                        fc_host_speed(shost) = FC_PORTSPEED_16GBIT;
                        break;
                default:
-                       ibmvfc_log(vhost, 3, "Unknown port speed: %ld Gbit\n",
+                       ibmvfc_log(vhost, 3, "Unknown port speed: %lld Gbit\n",
                                   vhost->login_buf->resp.link_speed / 100);
                        fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
                        break;
@@ -1146,10 +1145,10 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
        login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs);
        strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME);
        strncpy(login_info->device_name,
-               vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME);
+               dev_name(&vhost->host->shost_gendev), IBMVFC_MAX_NAME);
 
        location = of_get_property(of_node, "ibm,loc-code", NULL);
-       location = location ? location : vhost->dev->bus_id;
+       location = location ? location : dev_name(vhost->dev);
        strncpy(login_info->drc_name, location, IBMVFC_MAX_NAME);
 }
 
@@ -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);
@@ -1858,6 +1869,91 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
        return 0;
 }
 
+/**
+ * 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;
 }
@@ -2082,22 +2149,24 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
 {
        const char *desc = ibmvfc_get_ae_desc(crq->event);
 
-       ibmvfc_log(vhost, 3, "%s event received. scsi_id: %lx, wwpn: %lx,"
-                  " node_name: %lx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name);
+       ibmvfc_log(vhost, 3, "%s event received. scsi_id: %llx, wwpn: %llx,"
+                  " node_name: %llx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name);
 
        switch (crq->event) {
        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:
@@ -2115,7 +2184,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
                ibmvfc_link_down(vhost, IBMVFC_HALTED);
                break;
        default:
-               dev_err(vhost->dev, "Unknown async event received: %ld\n", crq->event);
+               dev_err(vhost->dev, "Unknown async event received: %lld\n", crq->event);
                break;
        };
 }
@@ -2192,13 +2261,13 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
         * actually sent
         */
        if (unlikely(!ibmvfc_valid_event(&vhost->pool, evt))) {
-               dev_err(vhost->dev, "Returned correlation_token 0x%08lx is invalid!\n",
+               dev_err(vhost->dev, "Returned correlation_token 0x%08llx is invalid!\n",
                        crq->ioba);
                return;
        }
 
        if (unlikely(atomic_read(&evt->free))) {
-               dev_err(vhost->dev, "Received duplicate correlation_token 0x%08lx!\n",
+               dev_err(vhost->dev, "Received duplicate correlation_token 0x%08llx!\n",
                        crq->ioba);
                return;
        }
@@ -2262,6 +2331,28 @@ static int ibmvfc_slave_alloc(struct scsi_device *sdev)
        return 0;
 }
 
+/**
+ * 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;
        };
 
@@ -3161,7 +3259,7 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id)
 
        tgt = mempool_alloc(vhost->tgt_pool, GFP_KERNEL);
        if (!tgt) {
-               dev_err(vhost->dev, "Target allocation failure for scsi id %08lx\n",
+               dev_err(vhost->dev, "Target allocation failure for scsi id %08llx\n",
                        scsi_id);
                return -ENOMEM;
        }
@@ -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;
                        }
                }