Commit 79111d08 authored by Brian King's avatar Brian King Committed by James Bottomley

[SCSI] ibmvfc: Add support for NPIV Logout

This patch adds support for a new command supported by the Virtual I/O
Server, NPIV Logout. The command will abort all outstanding commands
and log out of the fabric. Currently, the only way to do this is
by breaking the CRQ, which can take a fairly long time when lots of
commands are outstanding. The NPIV Logout commands provides a mechanism
to accomplish virtually the same function, but is much faster.
Signed-off-by: default avatarBrian King <brking@linux.vnet.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 43c8da90
...@@ -143,6 +143,7 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *); ...@@ -143,6 +143,7 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *);
static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); 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 const char *unknown_error = "unknown error"; static const char *unknown_error = "unknown error";
...@@ -477,6 +478,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, ...@@ -477,6 +478,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT)
vhost->action = action; vhost->action = action;
break; break;
case IBMVFC_HOST_ACTION_LOGO_WAIT:
if (vhost->action == IBMVFC_HOST_ACTION_LOGO)
vhost->action = action;
break;
case IBMVFC_HOST_ACTION_INIT_WAIT: case IBMVFC_HOST_ACTION_INIT_WAIT:
if (vhost->action == IBMVFC_HOST_ACTION_INIT) if (vhost->action == IBMVFC_HOST_ACTION_INIT)
vhost->action = action; vhost->action = action;
...@@ -496,6 +501,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, ...@@ -496,6 +501,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS) if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)
vhost->action = action; vhost->action = action;
break; break;
case IBMVFC_HOST_ACTION_LOGO:
case IBMVFC_HOST_ACTION_INIT: case IBMVFC_HOST_ACTION_INIT:
case IBMVFC_HOST_ACTION_TGT_DEL: case IBMVFC_HOST_ACTION_TGT_DEL:
case IBMVFC_HOST_ACTION_QUERY_TGTS: case IBMVFC_HOST_ACTION_QUERY_TGTS:
...@@ -647,6 +653,7 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) ...@@ -647,6 +653,7 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
vhost->state = IBMVFC_NO_CRQ; vhost->state = IBMVFC_NO_CRQ;
vhost->logged_in = 0;
dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL);
free_page((unsigned long)crq->msgs); free_page((unsigned long)crq->msgs);
} }
...@@ -693,6 +700,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) ...@@ -693,6 +700,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
vhost->state = IBMVFC_NO_CRQ; vhost->state = IBMVFC_NO_CRQ;
vhost->logged_in = 0;
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
/* Clean out the queue */ /* Clean out the queue */
...@@ -808,10 +816,10 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code) ...@@ -808,10 +816,10 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code)
} }
/** /**
* __ibmvfc_reset_host - Reset the connection to the server (no locking) * ibmvfc_hard_reset_host - Reset the connection to the server by breaking the CRQ
* @vhost: struct ibmvfc host to reset * @vhost: struct ibmvfc host to reset
**/ **/
static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)
{ {
int rc; int rc;
...@@ -827,9 +835,25 @@ static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) ...@@ -827,9 +835,25 @@ static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
} }
/** /**
* ibmvfc_reset_host - Reset the connection to the server * __ibmvfc_reset_host - Reset the connection to the server (no locking)
* @vhost: struct ibmvfc host to reset * @vhost: struct ibmvfc host to reset
**/ **/
static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
{
if (vhost->logged_in && vhost->action != IBMVFC_HOST_ACTION_LOGO_WAIT &&
!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
scsi_block_requests(vhost->host);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO);
vhost->job_step = ibmvfc_npiv_logout;
wake_up(&vhost->work_wait_q);
} else
ibmvfc_hard_reset_host(vhost);
}
/**
* ibmvfc_reset_host - Reset the connection to the server
* @vhost: ibmvfc host struct
**/
static void ibmvfc_reset_host(struct ibmvfc_host *vhost) static void ibmvfc_reset_host(struct ibmvfc_host *vhost)
{ {
unsigned long flags; unsigned long flags;
...@@ -2230,6 +2254,7 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost) ...@@ -2230,6 +2254,7 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
return; return;
case IBMVFC_CRQ_XPORT_EVENT: case IBMVFC_CRQ_XPORT_EVENT:
vhost->state = IBMVFC_NO_CRQ; vhost->state = IBMVFC_NO_CRQ;
vhost->logged_in = 0;
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
if (crq->format == IBMVFC_PARTITION_MIGRATED) { if (crq->format == IBMVFC_PARTITION_MIGRATED) {
/* We need to re-setup the interpartition connection */ /* We need to re-setup the interpartition connection */
...@@ -3554,6 +3579,7 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt) ...@@ -3554,6 +3579,7 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
return; return;
} }
vhost->logged_in = 1;
npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS); npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS);
dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n", dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n",
rsp->partition_name, rsp->device_name, rsp->port_loc_code, rsp->partition_name, rsp->device_name, rsp->port_loc_code,
...@@ -3611,6 +3637,65 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *vhost) ...@@ -3611,6 +3637,65 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *vhost)
ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
}; };
/**
* ibmvfc_npiv_logout_done - Completion handler for NPIV Logout
* @vhost: ibmvfc host struct
*
**/
static void ibmvfc_npiv_logout_done(struct ibmvfc_event *evt)
{
struct ibmvfc_host *vhost = evt->vhost;
u32 mad_status = evt->xfer_iu->npiv_logout.common.status;
ibmvfc_free_event(evt);
switch (mad_status) {
case IBMVFC_MAD_SUCCESS:
if (list_empty(&vhost->sent) &&
vhost->action == IBMVFC_HOST_ACTION_LOGO_WAIT) {
ibmvfc_init_host(vhost, 0);
return;
}
break;
case IBMVFC_MAD_FAILED:
case IBMVFC_MAD_NOT_SUPPORTED:
case IBMVFC_MAD_CRQ_ERROR:
case IBMVFC_MAD_DRIVER_FAILED:
default:
ibmvfc_dbg(vhost, "NPIV Logout failed. 0x%X\n", mad_status);
break;
}
ibmvfc_hard_reset_host(vhost);
}
/**
* ibmvfc_npiv_logout - Issue an NPIV Logout
* @vhost: ibmvfc host struct
*
**/
static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost)
{
struct ibmvfc_npiv_logout_mad *mad;
struct ibmvfc_event *evt;
evt = ibmvfc_get_event(vhost);
ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT);
mad = &evt->iu.npiv_logout;
memset(mad, 0, sizeof(*mad));
mad->common.version = 1;
mad->common.opcode = IBMVFC_NPIV_LOGOUT;
mad->common.length = sizeof(struct ibmvfc_npiv_logout_mad);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO_WAIT);
if (!ibmvfc_send_event(evt, vhost, default_timeout))
ibmvfc_dbg(vhost, "Sent NPIV logout\n");
else
ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
}
/** /**
* ibmvfc_dev_init_to_do - Is there target initialization work to do? * ibmvfc_dev_init_to_do - Is there target initialization work to do?
* @vhost: ibmvfc host struct * @vhost: ibmvfc host struct
...@@ -3647,6 +3732,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) ...@@ -3647,6 +3732,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
switch (vhost->action) { switch (vhost->action) {
case IBMVFC_HOST_ACTION_NONE: case IBMVFC_HOST_ACTION_NONE:
case IBMVFC_HOST_ACTION_INIT_WAIT: case IBMVFC_HOST_ACTION_INIT_WAIT:
case IBMVFC_HOST_ACTION_LOGO_WAIT:
return 0; return 0;
case IBMVFC_HOST_ACTION_TGT_INIT: case IBMVFC_HOST_ACTION_TGT_INIT:
case IBMVFC_HOST_ACTION_QUERY_TGTS: case IBMVFC_HOST_ACTION_QUERY_TGTS:
...@@ -3659,6 +3745,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) ...@@ -3659,6 +3745,7 @@ 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_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:
...@@ -3765,8 +3852,12 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) ...@@ -3765,8 +3852,12 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
vhost->events_to_log = 0; vhost->events_to_log = 0;
switch (vhost->action) { switch (vhost->action) {
case IBMVFC_HOST_ACTION_NONE: case IBMVFC_HOST_ACTION_NONE:
case IBMVFC_HOST_ACTION_LOGO_WAIT:
case IBMVFC_HOST_ACTION_INIT_WAIT: case IBMVFC_HOST_ACTION_INIT_WAIT:
break; break;
case IBMVFC_HOST_ACTION_LOGO:
vhost->job_step(vhost);
break;
case IBMVFC_HOST_ACTION_INIT: case IBMVFC_HOST_ACTION_INIT:
BUG_ON(vhost->state != IBMVFC_INITIALIZING); BUG_ON(vhost->state != IBMVFC_INITIALIZING);
if (vhost->delay_init) { if (vhost->delay_init) {
......
...@@ -57,9 +57,10 @@ ...@@ -57,9 +57,10 @@
* Ensure we have resources for ERP and initialization: * Ensure we have resources for ERP and initialization:
* 1 for ERP * 1 for ERP
* 1 for initialization * 1 for initialization
* 1 for NPIV Logout
* 2 for each discovery thread * 2 for each discovery thread
*/ */
#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + (disc_threads * 2)) #define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + 1 + (disc_threads * 2))
#define IBMVFC_MAD_SUCCESS 0x00 #define IBMVFC_MAD_SUCCESS 0x00
#define IBMVFC_MAD_NOT_SUPPORTED 0xF1 #define IBMVFC_MAD_NOT_SUPPORTED 0xF1
...@@ -127,6 +128,7 @@ enum ibmvfc_mad_types { ...@@ -127,6 +128,7 @@ enum ibmvfc_mad_types {
IBMVFC_IMPLICIT_LOGOUT = 0x0040, IBMVFC_IMPLICIT_LOGOUT = 0x0040,
IBMVFC_PASSTHRU = 0x0200, IBMVFC_PASSTHRU = 0x0200,
IBMVFC_TMF_MAD = 0x0100, IBMVFC_TMF_MAD = 0x0100,
IBMVFC_NPIV_LOGOUT = 0x0800,
}; };
struct ibmvfc_mad_common { struct ibmvfc_mad_common {
...@@ -143,6 +145,10 @@ struct ibmvfc_npiv_login_mad { ...@@ -143,6 +145,10 @@ struct ibmvfc_npiv_login_mad {
struct srp_direct_buf buffer; struct srp_direct_buf buffer;
}__attribute__((packed, aligned (8))); }__attribute__((packed, aligned (8)));
struct ibmvfc_npiv_logout_mad {
struct ibmvfc_mad_common common;
}__attribute__((packed, aligned (8)));
#define IBMVFC_MAX_NAME 256 #define IBMVFC_MAX_NAME 256
struct ibmvfc_npiv_login { struct ibmvfc_npiv_login {
...@@ -561,6 +567,7 @@ struct ibmvfc_async_crq_queue { ...@@ -561,6 +567,7 @@ struct ibmvfc_async_crq_queue {
union ibmvfc_iu { union ibmvfc_iu {
struct ibmvfc_mad_common mad_common; struct ibmvfc_mad_common mad_common;
struct ibmvfc_npiv_login_mad npiv_login; struct ibmvfc_npiv_login_mad npiv_login;
struct ibmvfc_npiv_logout_mad npiv_logout;
struct ibmvfc_discover_targets discover_targets; struct ibmvfc_discover_targets discover_targets;
struct ibmvfc_port_login plogi; struct ibmvfc_port_login plogi;
struct ibmvfc_process_login prli; struct ibmvfc_process_login prli;
...@@ -627,6 +634,8 @@ struct ibmvfc_event_pool { ...@@ -627,6 +634,8 @@ struct ibmvfc_event_pool {
enum ibmvfc_host_action { enum ibmvfc_host_action {
IBMVFC_HOST_ACTION_NONE = 0, IBMVFC_HOST_ACTION_NONE = 0,
IBMVFC_HOST_ACTION_LOGO,
IBMVFC_HOST_ACTION_LOGO_WAIT,
IBMVFC_HOST_ACTION_INIT, IBMVFC_HOST_ACTION_INIT,
IBMVFC_HOST_ACTION_INIT_WAIT, IBMVFC_HOST_ACTION_INIT_WAIT,
IBMVFC_HOST_ACTION_QUERY, IBMVFC_HOST_ACTION_QUERY,
...@@ -682,6 +691,7 @@ struct ibmvfc_host { ...@@ -682,6 +691,7 @@ struct ibmvfc_host {
int reinit; int reinit;
int delay_init; int delay_init;
int scan_complete; int scan_complete;
int logged_in;
int events_to_log; int events_to_log;
#define IBMVFC_AE_LINKUP 0x0001 #define IBMVFC_AE_LINKUP 0x0001
#define IBMVFC_AE_LINKDOWN 0x0002 #define IBMVFC_AE_LINKDOWN 0x0002
......
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