diff options
Diffstat (limited to 'drivers/scsi/ibmvscsi/ibmvfc.c')
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 60 |
1 files changed, 41 insertions, 19 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 715c34904e3e..bee1bec49c09 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -655,8 +655,10 @@ static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) **/ static void ibmvfc_del_tgt(struct ibmvfc_target *tgt) { - if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT)) + if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT)) { tgt->job_step = ibmvfc_tgt_implicit_logout_and_del; + tgt->init_retries = 0; + } wake_up(&tgt->vhost->work_wait_q); } @@ -4300,9 +4302,10 @@ static void ibmvfc_tgt_move_login_done(struct ibmvfc_event *evt) ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); switch (status) { case IBMVFC_MAD_SUCCESS: - tgt_dbg(tgt, "Move Login succeeded for old scsi_id: %llX\n", tgt->old_scsi_id); + tgt_dbg(tgt, "Move Login succeeded for new scsi_id: %llX\n", tgt->new_scsi_id); tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name); tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name); + tgt->scsi_id = tgt->new_scsi_id; tgt->ids.port_id = tgt->scsi_id; memcpy(&tgt->service_parms, &rsp->service_parms, sizeof(tgt->service_parms)); @@ -4320,8 +4323,8 @@ static void ibmvfc_tgt_move_login_done(struct ibmvfc_event *evt) level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_move_login); tgt_log(tgt, level, - "Move Login failed: old scsi_id: %llX, flags:%x, vios_flags:%x, rc=0x%02X\n", - tgt->old_scsi_id, be32_to_cpu(rsp->flags), be16_to_cpu(rsp->vios_flags), + "Move Login failed: new scsi_id: %llX, flags:%x, vios_flags:%x, rc=0x%02X\n", + tgt->new_scsi_id, be32_to_cpu(rsp->flags), be16_to_cpu(rsp->vios_flags), status); break; } @@ -4358,8 +4361,8 @@ static void ibmvfc_tgt_move_login(struct ibmvfc_target *tgt) move->common.opcode = cpu_to_be32(IBMVFC_MOVE_LOGIN); move->common.length = cpu_to_be16(sizeof(*move)); - move->old_scsi_id = cpu_to_be64(tgt->old_scsi_id); - move->new_scsi_id = cpu_to_be64(tgt->scsi_id); + move->old_scsi_id = cpu_to_be64(tgt->scsi_id); + move->new_scsi_id = cpu_to_be64(tgt->new_scsi_id); move->wwpn = cpu_to_be64(tgt->wwpn); move->node_name = cpu_to_be64(tgt->ids.node_name); @@ -4368,7 +4371,7 @@ static void ibmvfc_tgt_move_login(struct ibmvfc_target *tgt) ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); kref_put(&tgt->kref, ibmvfc_release_tgt); } else - tgt_dbg(tgt, "Sent Move Login for old scsi_id: %llX\n", tgt->old_scsi_id); + tgt_dbg(tgt, "Sent Move Login for new scsi_id: %llX\n", tgt->new_scsi_id); } /** @@ -4728,20 +4731,25 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, * and it failed for some reason, such as there being I/O * pending to the target. In this case, we will have already * deleted the rport from the FC transport so we do a move - * login, which works even with I/O pending, as it will cancel - * any active commands. + * login, which works even with I/O pending, however, if + * there is still I/O pending, it will stay outstanding, so + * we only do this if fast fail is disabled for the rport, + * otherwise we let terminate_rport_io clean up the port + * before we login at the new location. */ if (wtgt->action == IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT) { - /* - * Do a move login here. The old target is no longer - * known to the transport layer We don't use the - * normal ibmvfc_set_tgt_action to set this, as we - * don't normally want to allow this state change. - */ - wtgt->old_scsi_id = wtgt->scsi_id; - wtgt->scsi_id = scsi_id; - wtgt->action = IBMVFC_TGT_ACTION_INIT; - ibmvfc_init_tgt(wtgt, ibmvfc_tgt_move_login); + if (wtgt->move_login) { + /* + * Do a move login here. The old target is no longer + * known to the transport layer We don't use the + * normal ibmvfc_set_tgt_action to set this, as we + * don't normally want to allow this state change. + */ + wtgt->new_scsi_id = scsi_id; + wtgt->action = IBMVFC_TGT_ACTION_INIT; + wtgt->init_retries = 0; + ibmvfc_init_tgt(wtgt, ibmvfc_tgt_move_login); + } goto unlock_out; } else { tgt_err(wtgt, "Unexpected target state: %d, %p\n", @@ -5332,6 +5340,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) tgt_dbg(tgt, "Deleting rport with outstanding I/O\n"); ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT); tgt->rport = NULL; + tgt->init_retries = 0; spin_unlock_irqrestore(vhost->host->host_lock, flags); fc_remote_port_delete(rport); return; @@ -5486,7 +5495,20 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) tgt_dbg(tgt, "Deleting rport with I/O outstanding\n"); rport = tgt->rport; tgt->rport = NULL; + tgt->init_retries = 0; ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT); + + /* + * If fast fail is enabled, we wait for it to fire and then clean up + * the old port, since we expect the fast fail timer to clean up the + * outstanding I/O faster than waiting for normal command timeouts. + * However, if fast fail is disabled, any I/O outstanding to the + * rport LUNs will stay outstanding indefinitely, since the EH handlers + * won't get invoked for I/O's timing out. If this is a NPIV failover + * scenario, the better alternative is to use the move login. + */ + if (rport && rport->fast_io_fail_tmo == -1) + tgt->move_login = 1; spin_unlock_irqrestore(vhost->host->host_lock, flags); if (rport) fc_remote_port_delete(rport); |