diff options
author | Brian King <brking@linux.vnet.ibm.com> | 2009-05-28 17:17:29 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-06-08 14:07:44 -0400 |
commit | 79111d0899a122fa3cf0a2921292c3e6a25452d0 (patch) | |
tree | 73300ac26b25f515e2c04aa04f50cc9664886441 /drivers/scsi/ibmvscsi | |
parent | 43c8da907ccc656935d1085701f4db83385d8a59 (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.c | 97 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.h | 12 |
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 *); | |||
143 | static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); | 143 | static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); |
144 | static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); | 144 | static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); |
145 | static void ibmvfc_tgt_query_target(struct ibmvfc_target *); | 145 | static void ibmvfc_tgt_query_target(struct ibmvfc_target *); |
146 | static void ibmvfc_npiv_logout(struct ibmvfc_host *); | ||
146 | 147 | ||
147 | static const char *unknown_error = "unknown error"; | 148 | static 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 | **/ |
814 | static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) | 822 | static 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 | **/ |
841 | static 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 | **/ | ||
833 | static void ibmvfc_reset_host(struct ibmvfc_host *vhost) | 857 | static 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 | **/ | ||
3645 | static 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 | **/ | ||
3677 | static 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 | ||
132 | struct ibmvfc_mad_common { | 134 | struct 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 | ||
148 | struct 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 | ||
148 | struct ibmvfc_npiv_login { | 154 | struct ibmvfc_npiv_login { |
@@ -561,6 +567,7 @@ struct ibmvfc_async_crq_queue { | |||
561 | union ibmvfc_iu { | 567 | union 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 | ||
628 | enum ibmvfc_host_action { | 635 | enum 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 |