aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ibmvscsi
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2009-05-28 17:17:29 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-06-08 14:07:44 -0400
commit79111d0899a122fa3cf0a2921292c3e6a25452d0 (patch)
tree73300ac26b25f515e2c04aa04f50cc9664886441 /drivers/scsi/ibmvscsi
parent43c8da907ccc656935d1085701f4db83385d8a59 (diff)
[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: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/ibmvscsi')
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c97
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h12
2 files changed, 105 insertions, 4 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 76ae266b07c4..6eb3b75eec93 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -143,6 +143,7 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *);
143static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); 143static void ibmvfc_tgt_send_prli(struct ibmvfc_target *);
144static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); 144static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *);
145static void ibmvfc_tgt_query_target(struct ibmvfc_target *); 145static void ibmvfc_tgt_query_target(struct ibmvfc_target *);
146static void ibmvfc_npiv_logout(struct ibmvfc_host *);
146 147
147static const char *unknown_error = "unknown error"; 148static const char *unknown_error = "unknown error";
148 149
@@ -477,6 +478,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
477 if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) 478 if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT)
478 vhost->action = action; 479 vhost->action = action;
479 break; 480 break;
481 case IBMVFC_HOST_ACTION_LOGO_WAIT:
482 if (vhost->action == IBMVFC_HOST_ACTION_LOGO)
483 vhost->action = action;
484 break;
480 case IBMVFC_HOST_ACTION_INIT_WAIT: 485 case IBMVFC_HOST_ACTION_INIT_WAIT:
481 if (vhost->action == IBMVFC_HOST_ACTION_INIT) 486 if (vhost->action == IBMVFC_HOST_ACTION_INIT)
482 vhost->action = action; 487 vhost->action = action;
@@ -496,6 +501,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
496 if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS) 501 if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)
497 vhost->action = action; 502 vhost->action = action;
498 break; 503 break;
504 case IBMVFC_HOST_ACTION_LOGO:
499 case IBMVFC_HOST_ACTION_INIT: 505 case IBMVFC_HOST_ACTION_INIT:
500 case IBMVFC_HOST_ACTION_TGT_DEL: 506 case IBMVFC_HOST_ACTION_TGT_DEL:
501 case IBMVFC_HOST_ACTION_QUERY_TGTS: 507 case IBMVFC_HOST_ACTION_QUERY_TGTS:
@@ -647,6 +653,7 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
647 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); 653 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
648 654
649 vhost->state = IBMVFC_NO_CRQ; 655 vhost->state = IBMVFC_NO_CRQ;
656 vhost->logged_in = 0;
650 dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); 657 dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL);
651 free_page((unsigned long)crq->msgs); 658 free_page((unsigned long)crq->msgs);
652} 659}
@@ -693,6 +700,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
693 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); 700 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
694 701
695 vhost->state = IBMVFC_NO_CRQ; 702 vhost->state = IBMVFC_NO_CRQ;
703 vhost->logged_in = 0;
696 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); 704 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
697 705
698 /* Clean out the queue */ 706 /* Clean out the queue */
@@ -808,10 +816,10 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code)
808} 816}
809 817
810/** 818/**
811 * __ibmvfc_reset_host - Reset the connection to the server (no locking) 819 * ibmvfc_hard_reset_host - Reset the connection to the server by breaking the CRQ
812 * @vhost: struct ibmvfc host to reset 820 * @vhost: struct ibmvfc host to reset
813 **/ 821 **/
814static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) 822static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)
815{ 823{
816 int rc; 824 int rc;
817 825
@@ -827,9 +835,25 @@ static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
827} 835}
828 836
829/** 837/**
830 * ibmvfc_reset_host - Reset the connection to the server 838 * __ibmvfc_reset_host - Reset the connection to the server (no locking)
831 * @vhost: struct ibmvfc host to reset 839 * @vhost: struct ibmvfc host to reset
832 **/ 840 **/
841static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
842{
843 if (vhost->logged_in && vhost->action != IBMVFC_HOST_ACTION_LOGO_WAIT &&
844 !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
845 scsi_block_requests(vhost->host);
846 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO);
847 vhost->job_step = ibmvfc_npiv_logout;
848 wake_up(&vhost->work_wait_q);
849 } else
850 ibmvfc_hard_reset_host(vhost);
851}
852
853/**
854 * ibmvfc_reset_host - Reset the connection to the server
855 * @vhost: ibmvfc host struct
856 **/
833static void ibmvfc_reset_host(struct ibmvfc_host *vhost) 857static void ibmvfc_reset_host(struct ibmvfc_host *vhost)
834{ 858{
835 unsigned long flags; 859 unsigned long flags;
@@ -2230,6 +2254,7 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
2230 return; 2254 return;
2231 case IBMVFC_CRQ_XPORT_EVENT: 2255 case IBMVFC_CRQ_XPORT_EVENT:
2232 vhost->state = IBMVFC_NO_CRQ; 2256 vhost->state = IBMVFC_NO_CRQ;
2257 vhost->logged_in = 0;
2233 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); 2258 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
2234 if (crq->format == IBMVFC_PARTITION_MIGRATED) { 2259 if (crq->format == IBMVFC_PARTITION_MIGRATED) {
2235 /* We need to re-setup the interpartition connection */ 2260 /* We need to re-setup the interpartition connection */
@@ -3554,6 +3579,7 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
3554 return; 3579 return;
3555 } 3580 }
3556 3581
3582 vhost->logged_in = 1;
3557 npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS); 3583 npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS);
3558 dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n", 3584 dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n",
3559 rsp->partition_name, rsp->device_name, rsp->port_loc_code, 3585 rsp->partition_name, rsp->device_name, rsp->port_loc_code,
@@ -3612,6 +3638,65 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *vhost)
3612}; 3638};
3613 3639
3614/** 3640/**
3641 * ibmvfc_npiv_logout_done - Completion handler for NPIV Logout
3642 * @vhost: ibmvfc host struct
3643 *
3644 **/
3645static void ibmvfc_npiv_logout_done(struct ibmvfc_event *evt)
3646{
3647 struct ibmvfc_host *vhost = evt->vhost;
3648 u32 mad_status = evt->xfer_iu->npiv_logout.common.status;
3649
3650 ibmvfc_free_event(evt);
3651
3652 switch (mad_status) {
3653 case IBMVFC_MAD_SUCCESS:
3654 if (list_empty(&vhost->sent) &&
3655 vhost->action == IBMVFC_HOST_ACTION_LOGO_WAIT) {
3656 ibmvfc_init_host(vhost, 0);
3657 return;
3658 }
3659 break;
3660 case IBMVFC_MAD_FAILED:
3661 case IBMVFC_MAD_NOT_SUPPORTED:
3662 case IBMVFC_MAD_CRQ_ERROR:
3663 case IBMVFC_MAD_DRIVER_FAILED:
3664 default:
3665 ibmvfc_dbg(vhost, "NPIV Logout failed. 0x%X\n", mad_status);
3666 break;
3667 }
3668
3669 ibmvfc_hard_reset_host(vhost);
3670}
3671
3672/**
3673 * ibmvfc_npiv_logout - Issue an NPIV Logout
3674 * @vhost: ibmvfc host struct
3675 *
3676 **/
3677static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost)
3678{
3679 struct ibmvfc_npiv_logout_mad *mad;
3680 struct ibmvfc_event *evt;
3681
3682 evt = ibmvfc_get_event(vhost);
3683 ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT);
3684
3685 mad = &evt->iu.npiv_logout;
3686 memset(mad, 0, sizeof(*mad));
3687 mad->common.version = 1;
3688 mad->common.opcode = IBMVFC_NPIV_LOGOUT;
3689 mad->common.length = sizeof(struct ibmvfc_npiv_logout_mad);
3690
3691 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO_WAIT);
3692
3693 if (!ibmvfc_send_event(evt, vhost, default_timeout))
3694 ibmvfc_dbg(vhost, "Sent NPIV logout\n");
3695 else
3696 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
3697}
3698
3699/**
3615 * ibmvfc_dev_init_to_do - Is there target initialization work to do? 3700 * ibmvfc_dev_init_to_do - Is there target initialization work to do?
3616 * @vhost: ibmvfc host struct 3701 * @vhost: ibmvfc host struct
3617 * 3702 *
@@ -3647,6 +3732,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
3647 switch (vhost->action) { 3732 switch (vhost->action) {
3648 case IBMVFC_HOST_ACTION_NONE: 3733 case IBMVFC_HOST_ACTION_NONE:
3649 case IBMVFC_HOST_ACTION_INIT_WAIT: 3734 case IBMVFC_HOST_ACTION_INIT_WAIT:
3735 case IBMVFC_HOST_ACTION_LOGO_WAIT:
3650 return 0; 3736 return 0;
3651 case IBMVFC_HOST_ACTION_TGT_INIT: 3737 case IBMVFC_HOST_ACTION_TGT_INIT:
3652 case IBMVFC_HOST_ACTION_QUERY_TGTS: 3738 case IBMVFC_HOST_ACTION_QUERY_TGTS:
@@ -3659,6 +3745,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
3659 if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) 3745 if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT)
3660 return 0; 3746 return 0;
3661 return 1; 3747 return 1;
3748 case IBMVFC_HOST_ACTION_LOGO:
3662 case IBMVFC_HOST_ACTION_INIT: 3749 case IBMVFC_HOST_ACTION_INIT:
3663 case IBMVFC_HOST_ACTION_ALLOC_TGTS: 3750 case IBMVFC_HOST_ACTION_ALLOC_TGTS:
3664 case IBMVFC_HOST_ACTION_TGT_DEL: 3751 case IBMVFC_HOST_ACTION_TGT_DEL:
@@ -3765,8 +3852,12 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
3765 vhost->events_to_log = 0; 3852 vhost->events_to_log = 0;
3766 switch (vhost->action) { 3853 switch (vhost->action) {
3767 case IBMVFC_HOST_ACTION_NONE: 3854 case IBMVFC_HOST_ACTION_NONE:
3855 case IBMVFC_HOST_ACTION_LOGO_WAIT:
3768 case IBMVFC_HOST_ACTION_INIT_WAIT: 3856 case IBMVFC_HOST_ACTION_INIT_WAIT:
3769 break; 3857 break;
3858 case IBMVFC_HOST_ACTION_LOGO:
3859 vhost->job_step(vhost);
3860 break;
3770 case IBMVFC_HOST_ACTION_INIT: 3861 case IBMVFC_HOST_ACTION_INIT:
3771 BUG_ON(vhost->state != IBMVFC_INITIALIZING); 3862 BUG_ON(vhost->state != IBMVFC_INITIALIZING);
3772 if (vhost->delay_init) { 3863 if (vhost->delay_init) {
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 3a6a725fd396..6adaad80565d 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -57,9 +57,10 @@
57 * Ensure we have resources for ERP and initialization: 57 * Ensure we have resources for ERP and initialization:
58 * 1 for ERP 58 * 1 for ERP
59 * 1 for initialization 59 * 1 for initialization
60 * 1 for NPIV Logout
60 * 2 for each discovery thread 61 * 2 for each discovery thread
61 */ 62 */
62#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + (disc_threads * 2)) 63#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + 1 + (disc_threads * 2))
63 64
64#define IBMVFC_MAD_SUCCESS 0x00 65#define IBMVFC_MAD_SUCCESS 0x00
65#define IBMVFC_MAD_NOT_SUPPORTED 0xF1 66#define IBMVFC_MAD_NOT_SUPPORTED 0xF1
@@ -127,6 +128,7 @@ enum ibmvfc_mad_types {
127 IBMVFC_IMPLICIT_LOGOUT = 0x0040, 128 IBMVFC_IMPLICIT_LOGOUT = 0x0040,
128 IBMVFC_PASSTHRU = 0x0200, 129 IBMVFC_PASSTHRU = 0x0200,
129 IBMVFC_TMF_MAD = 0x0100, 130 IBMVFC_TMF_MAD = 0x0100,
131 IBMVFC_NPIV_LOGOUT = 0x0800,
130}; 132};
131 133
132struct ibmvfc_mad_common { 134struct ibmvfc_mad_common {
@@ -143,6 +145,10 @@ struct ibmvfc_npiv_login_mad {
143 struct srp_direct_buf buffer; 145 struct srp_direct_buf buffer;
144}__attribute__((packed, aligned (8))); 146}__attribute__((packed, aligned (8)));
145 147
148struct ibmvfc_npiv_logout_mad {
149 struct ibmvfc_mad_common common;
150}__attribute__((packed, aligned (8)));
151
146#define IBMVFC_MAX_NAME 256 152#define IBMVFC_MAX_NAME 256
147 153
148struct ibmvfc_npiv_login { 154struct ibmvfc_npiv_login {
@@ -561,6 +567,7 @@ struct ibmvfc_async_crq_queue {
561union ibmvfc_iu { 567union ibmvfc_iu {
562 struct ibmvfc_mad_common mad_common; 568 struct ibmvfc_mad_common mad_common;
563 struct ibmvfc_npiv_login_mad npiv_login; 569 struct ibmvfc_npiv_login_mad npiv_login;
570 struct ibmvfc_npiv_logout_mad npiv_logout;
564 struct ibmvfc_discover_targets discover_targets; 571 struct ibmvfc_discover_targets discover_targets;
565 struct ibmvfc_port_login plogi; 572 struct ibmvfc_port_login plogi;
566 struct ibmvfc_process_login prli; 573 struct ibmvfc_process_login prli;
@@ -627,6 +634,8 @@ struct ibmvfc_event_pool {
627 634
628enum ibmvfc_host_action { 635enum ibmvfc_host_action {
629 IBMVFC_HOST_ACTION_NONE = 0, 636 IBMVFC_HOST_ACTION_NONE = 0,
637 IBMVFC_HOST_ACTION_LOGO,
638 IBMVFC_HOST_ACTION_LOGO_WAIT,
630 IBMVFC_HOST_ACTION_INIT, 639 IBMVFC_HOST_ACTION_INIT,
631 IBMVFC_HOST_ACTION_INIT_WAIT, 640 IBMVFC_HOST_ACTION_INIT_WAIT,
632 IBMVFC_HOST_ACTION_QUERY, 641 IBMVFC_HOST_ACTION_QUERY,
@@ -682,6 +691,7 @@ struct ibmvfc_host {
682 int reinit; 691 int reinit;
683 int delay_init; 692 int delay_init;
684 int scan_complete; 693 int scan_complete;
694 int logged_in;
685 int events_to_log; 695 int events_to_log;
686#define IBMVFC_AE_LINKUP 0x0001 696#define IBMVFC_AE_LINKUP 0x0001
687#define IBMVFC_AE_LINKDOWN 0x0002 697#define IBMVFC_AE_LINKDOWN 0x0002