Commit ed830385 authored by Brian King's avatar Brian King Committed by Martin K. Petersen

scsi: ibmvfc: Avoid loss of all paths during SVC node reboot

When an SVC node goes down as part of a node reboot, its WWPNs are moved to
the remaining node. When the node is back online, its WWPNs are moved
back. The result is that the WWPN moves from one NPort_ID to another, then
back again.  The ibmvfc driver was forcing the old port to be removed, but
not sending an implicit logout. When the WWPN showed up at the new
location, the PLOGI failed as there was already a login established for the
old scsi id. The patch below fixes this by ensuring we always send an
implicit logout for any scsi id associated with an rport prior to calling
fc_remote_port_delete.

Link: https://lore.kernel.org/r/1582767943-16611-1-git-send-email-brking@linux.vnet.ibm.comSigned-off-by: default avatarBrian King <brking@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 5febf6d6
...@@ -133,6 +133,7 @@ static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); ...@@ -133,6 +133,7 @@ static void ibmvfc_tgt_send_prli(struct ibmvfc_target *);
static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *);
static void ibmvfc_tgt_query_target(struct ibmvfc_target *); static void ibmvfc_tgt_query_target(struct ibmvfc_target *);
static void ibmvfc_npiv_logout(struct ibmvfc_host *); static void ibmvfc_npiv_logout(struct ibmvfc_host *);
static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *);
static const char *unknown_error = "unknown error"; static const char *unknown_error = "unknown error";
...@@ -413,22 +414,44 @@ static const char *ibmvfc_get_fc_type(u16 status) ...@@ -413,22 +414,44 @@ static const char *ibmvfc_get_fc_type(u16 status)
* @tgt: ibmvfc target struct * @tgt: ibmvfc target struct
* @action: action to perform * @action: action to perform
* *
* Returns:
* 0 if action changed / non-zero if not changed
**/ **/
static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, static int ibmvfc_set_tgt_action(struct ibmvfc_target *tgt,
enum ibmvfc_target_action action) enum ibmvfc_target_action action)
{ {
int rc = -EINVAL;
switch (tgt->action) { switch (tgt->action) {
case IBMVFC_TGT_ACTION_LOGOUT_RPORT:
if (action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT ||
action == IBMVFC_TGT_ACTION_DEL_RPORT) {
tgt->action = action;
rc = 0;
}
break;
case IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT:
if (action == IBMVFC_TGT_ACTION_DEL_RPORT) {
tgt->action = action;
rc = 0;
}
break;
case IBMVFC_TGT_ACTION_DEL_RPORT: case IBMVFC_TGT_ACTION_DEL_RPORT:
if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) {
tgt->action = action; tgt->action = action;
rc = 0;
}
case IBMVFC_TGT_ACTION_DELETED_RPORT: case IBMVFC_TGT_ACTION_DELETED_RPORT:
break; break;
default: default:
if (action == IBMVFC_TGT_ACTION_DEL_RPORT) if (action >= IBMVFC_TGT_ACTION_LOGOUT_RPORT)
tgt->add_rport = 0; tgt->add_rport = 0;
tgt->action = action; tgt->action = action;
rc = 0;
break; break;
} }
return rc;
} }
/** /**
...@@ -536,6 +559,19 @@ static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) ...@@ -536,6 +559,19 @@ static void ibmvfc_reinit_host(struct ibmvfc_host *vhost)
wake_up(&vhost->work_wait_q); wake_up(&vhost->work_wait_q);
} }
/**
* ibmvfc_del_tgt - Schedule cleanup and removal of the target
* @tgt: ibmvfc target struct
* @job_step: job step to perform
*
**/
static void ibmvfc_del_tgt(struct ibmvfc_target *tgt)
{
if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT))
tgt->job_step = ibmvfc_tgt_implicit_logout_and_del;
wake_up(&tgt->vhost->work_wait_q);
}
/** /**
* ibmvfc_link_down - Handle a link down event from the adapter * ibmvfc_link_down - Handle a link down event from the adapter
* @vhost: ibmvfc host struct * @vhost: ibmvfc host struct
...@@ -550,7 +586,7 @@ static void ibmvfc_link_down(struct ibmvfc_host *vhost, ...@@ -550,7 +586,7 @@ static void ibmvfc_link_down(struct ibmvfc_host *vhost,
ENTER; ENTER;
scsi_block_requests(vhost->host); scsi_block_requests(vhost->host);
list_for_each_entry(tgt, &vhost->targets, queue) list_for_each_entry(tgt, &vhost->targets, queue)
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
ibmvfc_set_host_state(vhost, state); ibmvfc_set_host_state(vhost, state);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL);
vhost->events_to_log |= IBMVFC_AE_LINKDOWN; vhost->events_to_log |= IBMVFC_AE_LINKDOWN;
...@@ -583,7 +619,7 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost) ...@@ -583,7 +619,7 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost)
vhost->async_crq.cur = 0; vhost->async_crq.cur = 0;
list_for_each_entry(tgt, &vhost->targets, queue) list_for_each_entry(tgt, &vhost->targets, queue)
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
scsi_block_requests(vhost->host); scsi_block_requests(vhost->host);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
vhost->job_step = ibmvfc_npiv_login; vhost->job_step = ibmvfc_npiv_login;
...@@ -1500,7 +1536,7 @@ static void ibmvfc_relogin(struct scsi_device *sdev) ...@@ -1500,7 +1536,7 @@ static void ibmvfc_relogin(struct scsi_device *sdev)
list_for_each_entry(tgt, &vhost->targets, queue) { list_for_each_entry(tgt, &vhost->targets, queue) {
if (rport == tgt->rport) { if (rport == tgt->rport) {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
break; break;
} }
} }
...@@ -2686,7 +2722,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, ...@@ -2686,7 +2722,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
if (tgt->need_login && be64_to_cpu(crq->event) == IBMVFC_AE_ELS_LOGO) if (tgt->need_login && be64_to_cpu(crq->event) == IBMVFC_AE_ELS_LOGO)
tgt->logo_rcvd = 1; tgt->logo_rcvd = 1;
if (!tgt->need_login || be64_to_cpu(crq->event) == IBMVFC_AE_ELS_PLOGI) { if (!tgt->need_login || be64_to_cpu(crq->event) == IBMVFC_AE_ELS_PLOGI) {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
ibmvfc_reinit_host(vhost); ibmvfc_reinit_host(vhost);
} }
} }
...@@ -3220,8 +3256,8 @@ static void ibmvfc_tasklet(void *data) ...@@ -3220,8 +3256,8 @@ static void ibmvfc_tasklet(void *data)
static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, static void ibmvfc_init_tgt(struct ibmvfc_target *tgt,
void (*job_step) (struct ibmvfc_target *)) void (*job_step) (struct ibmvfc_target *))
{ {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT); if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT))
tgt->job_step = job_step; tgt->job_step = job_step;
wake_up(&tgt->vhost->work_wait_q); wake_up(&tgt->vhost->work_wait_q);
} }
...@@ -3237,7 +3273,7 @@ static int ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, ...@@ -3237,7 +3273,7 @@ static int ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
void (*job_step) (struct ibmvfc_target *)) void (*job_step) (struct ibmvfc_target *))
{ {
if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) { if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
wake_up(&tgt->vhost->work_wait_q); wake_up(&tgt->vhost->work_wait_q);
return 0; return 0;
} else } else
...@@ -3312,13 +3348,13 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) ...@@ -3312,13 +3348,13 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
tgt->add_rport = 1; tgt->add_rport = 1;
} else } else
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
} else if (prli_rsp[index].retry) } else if (prli_rsp[index].retry)
ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
else else
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
} else } else
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
break; break;
case IBMVFC_MAD_DRIVER_FAILED: case IBMVFC_MAD_DRIVER_FAILED:
break; break;
...@@ -3335,7 +3371,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) ...@@ -3335,7 +3371,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)))
level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
else else
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n", tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n",
ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
...@@ -3434,7 +3470,7 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) ...@@ -3434,7 +3470,7 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt)
if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)))
level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
else else
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
...@@ -3515,33 +3551,28 @@ static void ibmvfc_tgt_implicit_logout_done(struct ibmvfc_event *evt) ...@@ -3515,33 +3551,28 @@ static void ibmvfc_tgt_implicit_logout_done(struct ibmvfc_event *evt)
break; break;
} }
if (vhost->action == IBMVFC_HOST_ACTION_TGT_INIT) ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi);
ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi);
else if (vhost->action == IBMVFC_HOST_ACTION_QUERY_TGTS &&
tgt->scsi_id != tgt->new_scsi_id)
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
kref_put(&tgt->kref, ibmvfc_release_tgt); kref_put(&tgt->kref, ibmvfc_release_tgt);
wake_up(&vhost->work_wait_q); wake_up(&vhost->work_wait_q);
} }
/** /**
* ibmvfc_tgt_implicit_logout - Initiate an Implicit Logout for specified target * __ibmvfc_tgt_get_implicit_logout_evt - Allocate and init an event for implicit logout
* @tgt: ibmvfc target struct * @tgt: ibmvfc target struct
* *
* Returns:
* Allocated and initialized ibmvfc_event struct
**/ **/
static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) static struct ibmvfc_event *__ibmvfc_tgt_get_implicit_logout_evt(struct ibmvfc_target *tgt,
void (*done) (struct ibmvfc_event *))
{ {
struct ibmvfc_implicit_logout *mad; struct ibmvfc_implicit_logout *mad;
struct ibmvfc_host *vhost = tgt->vhost; struct ibmvfc_host *vhost = tgt->vhost;
struct ibmvfc_event *evt; struct ibmvfc_event *evt;
if (vhost->discovery_threads >= disc_threads)
return;
kref_get(&tgt->kref); kref_get(&tgt->kref);
evt = ibmvfc_get_event(vhost); evt = ibmvfc_get_event(vhost);
vhost->discovery_threads++; ibmvfc_init_event(evt, done, IBMVFC_MAD_FORMAT);
ibmvfc_init_event(evt, ibmvfc_tgt_implicit_logout_done, IBMVFC_MAD_FORMAT);
evt->tgt = tgt; evt->tgt = tgt;
mad = &evt->iu.implicit_logout; mad = &evt->iu.implicit_logout;
memset(mad, 0, sizeof(*mad)); memset(mad, 0, sizeof(*mad));
...@@ -3549,6 +3580,25 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) ...@@ -3549,6 +3580,25 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
mad->common.opcode = cpu_to_be32(IBMVFC_IMPLICIT_LOGOUT); mad->common.opcode = cpu_to_be32(IBMVFC_IMPLICIT_LOGOUT);
mad->common.length = cpu_to_be16(sizeof(*mad)); mad->common.length = cpu_to_be16(sizeof(*mad));
mad->old_scsi_id = cpu_to_be64(tgt->scsi_id); mad->old_scsi_id = cpu_to_be64(tgt->scsi_id);
return evt;
}
/**
* ibmvfc_tgt_implicit_logout - Initiate an Implicit Logout for specified target
* @tgt: ibmvfc target struct
*
**/
static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
{
struct ibmvfc_host *vhost = tgt->vhost;
struct ibmvfc_event *evt;
if (vhost->discovery_threads >= disc_threads)
return;
vhost->discovery_threads++;
evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt,
ibmvfc_tgt_implicit_logout_done);
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
if (ibmvfc_send_event(evt, vhost, default_timeout)) { if (ibmvfc_send_event(evt, vhost, default_timeout)) {
...@@ -3559,6 +3609,53 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) ...@@ -3559,6 +3609,53 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
tgt_dbg(tgt, "Sent Implicit Logout\n"); tgt_dbg(tgt, "Sent Implicit Logout\n");
} }
/**
* ibmvfc_tgt_implicit_logout_and_del_done - Completion handler for Implicit Logout MAD
* @evt: ibmvfc event struct
*
**/
static void ibmvfc_tgt_implicit_logout_and_del_done(struct ibmvfc_event *evt)
{
struct ibmvfc_target *tgt = evt->tgt;
struct ibmvfc_host *vhost = evt->vhost;
struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru;
u32 status = be16_to_cpu(mad->common.status);
vhost->discovery_threads--;
ibmvfc_free_event(evt);
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
tgt_dbg(tgt, "Implicit Logout %s\n", (status == IBMVFC_MAD_SUCCESS) ? "succeeded" : "failed");
kref_put(&tgt->kref, ibmvfc_release_tgt);
wake_up(&vhost->work_wait_q);
}
/**
* ibmvfc_tgt_implicit_logout_and_del - Initiate an Implicit Logout for specified target
* @tgt: ibmvfc target struct
*
**/
static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *tgt)
{
struct ibmvfc_host *vhost = tgt->vhost;
struct ibmvfc_event *evt;
if (vhost->discovery_threads >= disc_threads)
return NULL;
vhost->discovery_threads++;
evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt,
ibmvfc_tgt_implicit_logout_and_del_done);
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT);
if (ibmvfc_send_event(evt, vhost, default_timeout)) {
vhost->discovery_threads--;
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
kref_put(&tgt->kref, ibmvfc_release_tgt);
} else
tgt_dbg(tgt, "Sent Implicit Logout\n");
}
/** /**
* ibmvfc_adisc_needs_plogi - Does device need PLOGI? * ibmvfc_adisc_needs_plogi - Does device need PLOGI?
* @mad: ibmvfc passthru mad struct * @mad: ibmvfc passthru mad struct
...@@ -3600,13 +3697,13 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) ...@@ -3600,13 +3697,13 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt)
case IBMVFC_MAD_SUCCESS: case IBMVFC_MAD_SUCCESS:
tgt_dbg(tgt, "ADISC succeeded\n"); tgt_dbg(tgt, "ADISC succeeded\n");
if (ibmvfc_adisc_needs_plogi(mad, tgt)) if (ibmvfc_adisc_needs_plogi(mad, tgt))
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
break; break;
case IBMVFC_MAD_DRIVER_FAILED: case IBMVFC_MAD_DRIVER_FAILED:
break; break;
case IBMVFC_MAD_FAILED: case IBMVFC_MAD_FAILED:
default: default:
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
fc_reason = (be32_to_cpu(mad->fc_iu.response[1]) & 0x00ff0000) >> 16; fc_reason = (be32_to_cpu(mad->fc_iu.response[1]) & 0x00ff0000) >> 16;
fc_explain = (be32_to_cpu(mad->fc_iu.response[1]) & 0x0000ff00) >> 8; fc_explain = (be32_to_cpu(mad->fc_iu.response[1]) & 0x0000ff00) >> 8;
tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
...@@ -3799,9 +3896,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) ...@@ -3799,9 +3896,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
switch (status) { switch (status) {
case IBMVFC_MAD_SUCCESS: case IBMVFC_MAD_SUCCESS:
tgt_dbg(tgt, "Query Target succeeded\n"); tgt_dbg(tgt, "Query Target succeeded\n");
tgt->new_scsi_id = be64_to_cpu(rsp->scsi_id);
if (be64_to_cpu(rsp->scsi_id) != tgt->scsi_id) if (be64_to_cpu(rsp->scsi_id) != tgt->scsi_id)
ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); ibmvfc_del_tgt(tgt);
else else
ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc); ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc);
break; break;
...@@ -3815,11 +3911,11 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) ...@@ -3815,11 +3911,11 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
if ((be16_to_cpu(rsp->status) & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED && if ((be16_to_cpu(rsp->status) & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED &&
be16_to_cpu(rsp->error) == IBMVFC_UNABLE_TO_PERFORM_REQ && be16_to_cpu(rsp->error) == IBMVFC_UNABLE_TO_PERFORM_REQ &&
be16_to_cpu(rsp->fc_explain) == IBMVFC_PORT_NAME_NOT_REG) be16_to_cpu(rsp->fc_explain) == IBMVFC_PORT_NAME_NOT_REG)
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) else if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)))
level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target);
else else
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ibmvfc_del_tgt(tgt);
tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
...@@ -3896,7 +3992,6 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) ...@@ -3896,7 +3992,6 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id)
tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO); tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO);
memset(tgt, 0, sizeof(*tgt)); memset(tgt, 0, sizeof(*tgt));
tgt->scsi_id = scsi_id; tgt->scsi_id = scsi_id;
tgt->new_scsi_id = scsi_id;
tgt->vhost = vhost; tgt->vhost = vhost;
tgt->need_login = 1; tgt->need_login = 1;
tgt->cancel_key = vhost->task_set++; tgt->cancel_key = vhost->task_set++;
...@@ -4188,6 +4283,25 @@ static int ibmvfc_dev_init_to_do(struct ibmvfc_host *vhost) ...@@ -4188,6 +4283,25 @@ static int ibmvfc_dev_init_to_do(struct ibmvfc_host *vhost)
return 0; return 0;
} }
/**
* ibmvfc_dev_logo_to_do - Is there target logout work to do?
* @vhost: ibmvfc host struct
*
* Returns:
* 1 if work to do / 0 if not
**/
static int ibmvfc_dev_logo_to_do(struct ibmvfc_host *vhost)
{
struct ibmvfc_target *tgt;
list_for_each_entry(tgt, &vhost->targets, queue) {
if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT ||
tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT)
return 1;
}
return 0;
}
/** /**
* __ibmvfc_work_to_do - Is there task level work to do? (no locking) * __ibmvfc_work_to_do - Is there task level work to do? (no locking)
* @vhost: ibmvfc host struct * @vhost: ibmvfc host struct
...@@ -4217,11 +4331,20 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) ...@@ -4217,11 +4331,20 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT)
return 0; return 0;
return 1; return 1;
case IBMVFC_HOST_ACTION_TGT_DEL:
case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
if (vhost->discovery_threads == disc_threads)
return 0;
list_for_each_entry(tgt, &vhost->targets, queue)
if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT)
return 1;
list_for_each_entry(tgt, &vhost->targets, queue)
if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT)
return 0;
return 1;
case IBMVFC_HOST_ACTION_LOGO: case IBMVFC_HOST_ACTION_LOGO:
case IBMVFC_HOST_ACTION_INIT: case IBMVFC_HOST_ACTION_INIT:
case IBMVFC_HOST_ACTION_ALLOC_TGTS: case IBMVFC_HOST_ACTION_ALLOC_TGTS:
case IBMVFC_HOST_ACTION_TGT_DEL:
case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
case IBMVFC_HOST_ACTION_QUERY: case IBMVFC_HOST_ACTION_QUERY:
case IBMVFC_HOST_ACTION_RESET: case IBMVFC_HOST_ACTION_RESET:
case IBMVFC_HOST_ACTION_REENABLE: case IBMVFC_HOST_ACTION_REENABLE:
...@@ -4390,6 +4513,18 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) ...@@ -4390,6 +4513,18 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
break; break;
case IBMVFC_HOST_ACTION_TGT_DEL: case IBMVFC_HOST_ACTION_TGT_DEL:
case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
list_for_each_entry(tgt, &vhost->targets, queue) {
if (tgt->action == IBMVFC_TGT_ACTION_LOGOUT_RPORT) {
tgt->job_step(tgt);
break;
}
}
if (ibmvfc_dev_logo_to_do(vhost)) {
spin_unlock_irqrestore(vhost->host->host_lock, flags);
return;
}
list_for_each_entry(tgt, &vhost->targets, queue) { list_for_each_entry(tgt, &vhost->targets, queue) {
if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
tgt_dbg(tgt, "Deleting rport\n"); tgt_dbg(tgt, "Deleting rport\n");
......
...@@ -596,6 +596,8 @@ enum ibmvfc_target_action { ...@@ -596,6 +596,8 @@ enum ibmvfc_target_action {
IBMVFC_TGT_ACTION_NONE = 0, IBMVFC_TGT_ACTION_NONE = 0,
IBMVFC_TGT_ACTION_INIT, IBMVFC_TGT_ACTION_INIT,
IBMVFC_TGT_ACTION_INIT_WAIT, IBMVFC_TGT_ACTION_INIT_WAIT,
IBMVFC_TGT_ACTION_LOGOUT_RPORT,
IBMVFC_TGT_ACTION_LOGOUT_RPORT_WAIT,
IBMVFC_TGT_ACTION_DEL_RPORT, IBMVFC_TGT_ACTION_DEL_RPORT,
IBMVFC_TGT_ACTION_DELETED_RPORT, IBMVFC_TGT_ACTION_DELETED_RPORT,
}; };
...@@ -604,7 +606,6 @@ struct ibmvfc_target { ...@@ -604,7 +606,6 @@ struct ibmvfc_target {
struct list_head queue; struct list_head queue;
struct ibmvfc_host *vhost; struct ibmvfc_host *vhost;
u64 scsi_id; u64 scsi_id;
u64 new_scsi_id;
struct fc_rport *rport; struct fc_rport *rport;
int target_id; int target_id;
enum ibmvfc_target_action action; enum ibmvfc_target_action action;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment