diff options
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 120 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.h | 42 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 1 |
7 files changed, 169 insertions, 0 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 88691adc1283..645b0fcbb370 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -362,6 +362,7 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
362 | 362 | ||
363 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | 363 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); |
364 | INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports); | 364 | INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports); |
365 | INIT_WORK(&adapter->ns_up_work, zfcp_fc_sym_name_update); | ||
365 | 366 | ||
366 | if (zfcp_qdio_setup(adapter)) | 367 | if (zfcp_qdio_setup(adapter)) |
367 | goto failed; | 368 | goto failed; |
@@ -427,6 +428,7 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter) | |||
427 | 428 | ||
428 | cancel_work_sync(&adapter->scan_work); | 429 | cancel_work_sync(&adapter->scan_work); |
429 | cancel_work_sync(&adapter->stat_work); | 430 | cancel_work_sync(&adapter->stat_work); |
431 | cancel_work_sync(&adapter->ns_up_work); | ||
430 | zfcp_destroy_adapter_work_queue(adapter); | 432 | zfcp_destroy_adapter_work_queue(adapter); |
431 | 433 | ||
432 | zfcp_fc_wka_ports_force_offline(adapter->gs); | 434 | zfcp_fc_wka_ports_force_offline(adapter->gs); |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 1566208997b6..527ba48eea57 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -189,6 +189,7 @@ struct zfcp_adapter { | |||
189 | struct fsf_qtcb_bottom_port *stats_reset_data; | 189 | struct fsf_qtcb_bottom_port *stats_reset_data; |
190 | unsigned long stats_reset; | 190 | unsigned long stats_reset; |
191 | struct work_struct scan_work; | 191 | struct work_struct scan_work; |
192 | struct work_struct ns_up_work; | ||
192 | struct service_level service_level; | 193 | struct service_level service_level; |
193 | struct workqueue_struct *work_queue; | 194 | struct workqueue_struct *work_queue; |
194 | struct device_dma_parameters dma_parms; | 195 | struct device_dma_parameters dma_parms; |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 6c1cddf0d0a0..e1b4f800e226 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -1231,8 +1231,10 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | |||
1231 | if (result == ZFCP_ERP_SUCCEEDED) { | 1231 | if (result == ZFCP_ERP_SUCCEEDED) { |
1232 | register_service_level(&adapter->service_level); | 1232 | register_service_level(&adapter->service_level); |
1233 | queue_work(adapter->work_queue, &adapter->scan_work); | 1233 | queue_work(adapter->work_queue, &adapter->scan_work); |
1234 | queue_work(adapter->work_queue, &adapter->ns_up_work); | ||
1234 | } else | 1235 | } else |
1235 | unregister_service_level(&adapter->service_level); | 1236 | unregister_service_level(&adapter->service_level); |
1237 | |||
1236 | kref_put(&adapter->ref, zfcp_adapter_release); | 1238 | kref_put(&adapter->ref, zfcp_adapter_release); |
1237 | break; | 1239 | break; |
1238 | } | 1240 | } |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 410d9ddc175a..03627cfd81cd 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -96,6 +96,7 @@ extern int zfcp_fc_gs_setup(struct zfcp_adapter *); | |||
96 | extern void zfcp_fc_gs_destroy(struct zfcp_adapter *); | 96 | extern void zfcp_fc_gs_destroy(struct zfcp_adapter *); |
97 | extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *); | 97 | extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *); |
98 | extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *); | 98 | extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *); |
99 | extern void zfcp_fc_sym_name_update(struct work_struct *); | ||
99 | 100 | ||
100 | /* zfcp_fsf.c */ | 101 | /* zfcp_fsf.c */ |
101 | extern struct kmem_cache *zfcp_fsf_qtcb_cache; | 102 | extern struct kmem_cache *zfcp_fsf_qtcb_cache; |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index c839a3b6879d..297e6b71ce9c 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/utsname.h> | ||
14 | #include <scsi/fc/fc_els.h> | 15 | #include <scsi/fc/fc_els.h> |
15 | #include <scsi/libfc.h> | 16 | #include <scsi/libfc.h> |
16 | #include "zfcp_ext.h" | 17 | #include "zfcp_ext.h" |
@@ -696,6 +697,125 @@ out: | |||
696 | zfcp_fc_wka_port_put(&adapter->gs->ds); | 697 | zfcp_fc_wka_port_put(&adapter->gs->ds); |
697 | } | 698 | } |
698 | 699 | ||
700 | static int zfcp_fc_gspn(struct zfcp_adapter *adapter, | ||
701 | struct zfcp_fc_req *fc_req) | ||
702 | { | ||
703 | DECLARE_COMPLETION_ONSTACK(completion); | ||
704 | char devno[] = "DEVNO:"; | ||
705 | struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els; | ||
706 | struct zfcp_fc_gspn_req *gspn_req = &fc_req->u.gspn.req; | ||
707 | struct zfcp_fc_gspn_rsp *gspn_rsp = &fc_req->u.gspn.rsp; | ||
708 | int ret; | ||
709 | |||
710 | zfcp_fc_ct_ns_init(&gspn_req->ct_hdr, FC_NS_GSPN_ID, | ||
711 | FC_SYMBOLIC_NAME_SIZE); | ||
712 | hton24(gspn_req->gspn.fp_fid, fc_host_port_id(adapter->scsi_host)); | ||
713 | |||
714 | sg_init_one(&fc_req->sg_req, gspn_req, sizeof(*gspn_req)); | ||
715 | sg_init_one(&fc_req->sg_rsp, gspn_rsp, sizeof(*gspn_rsp)); | ||
716 | |||
717 | ct_els->handler = zfcp_fc_complete; | ||
718 | ct_els->handler_data = &completion; | ||
719 | ct_els->req = &fc_req->sg_req; | ||
720 | ct_els->resp = &fc_req->sg_rsp; | ||
721 | |||
722 | ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL, | ||
723 | ZFCP_FC_CTELS_TMO); | ||
724 | if (ret) | ||
725 | return ret; | ||
726 | |||
727 | wait_for_completion(&completion); | ||
728 | if (ct_els->status) | ||
729 | return ct_els->status; | ||
730 | |||
731 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_NPIV && | ||
732 | !(strstr(gspn_rsp->gspn.fp_name, devno))) | ||
733 | snprintf(fc_host_symbolic_name(adapter->scsi_host), | ||
734 | FC_SYMBOLIC_NAME_SIZE, "%s%s %s NAME: %s", | ||
735 | gspn_rsp->gspn.fp_name, devno, | ||
736 | dev_name(&adapter->ccw_device->dev), | ||
737 | init_utsname()->nodename); | ||
738 | else | ||
739 | strlcpy(fc_host_symbolic_name(adapter->scsi_host), | ||
740 | gspn_rsp->gspn.fp_name, FC_SYMBOLIC_NAME_SIZE); | ||
741 | |||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static void zfcp_fc_rspn(struct zfcp_adapter *adapter, | ||
746 | struct zfcp_fc_req *fc_req) | ||
747 | { | ||
748 | DECLARE_COMPLETION_ONSTACK(completion); | ||
749 | struct Scsi_Host *shost = adapter->scsi_host; | ||
750 | struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els; | ||
751 | struct zfcp_fc_rspn_req *rspn_req = &fc_req->u.rspn.req; | ||
752 | struct fc_ct_hdr *rspn_rsp = &fc_req->u.rspn.rsp; | ||
753 | int ret, len; | ||
754 | |||
755 | zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID, | ||
756 | FC_SYMBOLIC_NAME_SIZE); | ||
757 | hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost)); | ||
758 | len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost), | ||
759 | FC_SYMBOLIC_NAME_SIZE); | ||
760 | rspn_req->rspn.fr_name_len = len; | ||
761 | |||
762 | sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req)); | ||
763 | sg_init_one(&fc_req->sg_rsp, rspn_rsp, sizeof(*rspn_rsp)); | ||
764 | |||
765 | ct_els->handler = zfcp_fc_complete; | ||
766 | ct_els->handler_data = &completion; | ||
767 | ct_els->req = &fc_req->sg_req; | ||
768 | ct_els->resp = &fc_req->sg_rsp; | ||
769 | |||
770 | ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL, | ||
771 | ZFCP_FC_CTELS_TMO); | ||
772 | if (!ret) | ||
773 | wait_for_completion(&completion); | ||
774 | } | ||
775 | |||
776 | /** | ||
777 | * zfcp_fc_sym_name_update - Retrieve and update the symbolic port name | ||
778 | * @work: ns_up_work of the adapter where to update the symbolic port name | ||
779 | * | ||
780 | * Retrieve the current symbolic port name that may have been set by | ||
781 | * the hardware using the GSPN request and update the fc_host | ||
782 | * symbolic_name sysfs attribute. When running in NPIV mode (and hence | ||
783 | * the port name is unique for this system), update the symbolic port | ||
784 | * name to add Linux specific information and update the FC nameserver | ||
785 | * using the RSPN request. | ||
786 | */ | ||
787 | void zfcp_fc_sym_name_update(struct work_struct *work) | ||
788 | { | ||
789 | struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter, | ||
790 | ns_up_work); | ||
791 | int ret; | ||
792 | struct zfcp_fc_req *fc_req; | ||
793 | |||
794 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT && | ||
795 | fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) | ||
796 | return; | ||
797 | |||
798 | fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_KERNEL); | ||
799 | if (!fc_req) | ||
800 | return; | ||
801 | |||
802 | ret = zfcp_fc_wka_port_get(&adapter->gs->ds); | ||
803 | if (ret) | ||
804 | goto out_free; | ||
805 | |||
806 | ret = zfcp_fc_gspn(adapter, fc_req); | ||
807 | if (ret || fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) | ||
808 | goto out_ds_put; | ||
809 | |||
810 | memset(fc_req, 0, sizeof(*fc_req)); | ||
811 | zfcp_fc_rspn(adapter, fc_req); | ||
812 | |||
813 | out_ds_put: | ||
814 | zfcp_fc_wka_port_put(&adapter->gs->ds); | ||
815 | out_free: | ||
816 | kmem_cache_free(zfcp_fc_req_cache, fc_req); | ||
817 | } | ||
818 | |||
699 | static void zfcp_fc_ct_els_job_handler(void *data) | 819 | static void zfcp_fc_ct_els_job_handler(void *data) |
700 | { | 820 | { |
701 | struct fc_bsg_job *job = data; | 821 | struct fc_bsg_job *job = data; |
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 5243ce44aa42..4561f3bf7300 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h | |||
@@ -84,6 +84,40 @@ struct zfcp_fc_gpn_ft_req { | |||
84 | } __packed; | 84 | } __packed; |
85 | 85 | ||
86 | /** | 86 | /** |
87 | * struct zfcp_fc_gspn_req - container for ct header plus GSPN_ID request | ||
88 | * @ct_hdr: FC GS common transport header | ||
89 | * @gspn: GSPN_ID request | ||
90 | */ | ||
91 | struct zfcp_fc_gspn_req { | ||
92 | struct fc_ct_hdr ct_hdr; | ||
93 | struct fc_gid_pn_resp gspn; | ||
94 | } __packed; | ||
95 | |||
96 | /** | ||
97 | * struct zfcp_fc_gspn_rsp - container for ct header plus GSPN_ID response | ||
98 | * @ct_hdr: FC GS common transport header | ||
99 | * @gspn: GSPN_ID response | ||
100 | * @name: The name string of the GSPN_ID response | ||
101 | */ | ||
102 | struct zfcp_fc_gspn_rsp { | ||
103 | struct fc_ct_hdr ct_hdr; | ||
104 | struct fc_gspn_resp gspn; | ||
105 | char name[FC_SYMBOLIC_NAME_SIZE]; | ||
106 | } __packed; | ||
107 | |||
108 | /** | ||
109 | * struct zfcp_fc_rspn_req - container for ct header plus RSPN_ID request | ||
110 | * @ct_hdr: FC GS common transport header | ||
111 | * @rspn: RSPN_ID request | ||
112 | * @name: The name string of the RSPN_ID request | ||
113 | */ | ||
114 | struct zfcp_fc_rspn_req { | ||
115 | struct fc_ct_hdr ct_hdr; | ||
116 | struct fc_ns_rspn rspn; | ||
117 | char name[FC_SYMBOLIC_NAME_SIZE]; | ||
118 | } __packed; | ||
119 | |||
120 | /** | ||
87 | * struct zfcp_fc_req - Container for FC ELS and CT requests sent from zfcp | 121 | * struct zfcp_fc_req - Container for FC ELS and CT requests sent from zfcp |
88 | * @ct_els: data required for issuing fsf command | 122 | * @ct_els: data required for issuing fsf command |
89 | * @sg_req: scatterlist entry for request data | 123 | * @sg_req: scatterlist entry for request data |
@@ -107,6 +141,14 @@ struct zfcp_fc_req { | |||
107 | struct scatterlist sg_rsp2[ZFCP_FC_GPN_FT_NUM_BUFS - 1]; | 141 | struct scatterlist sg_rsp2[ZFCP_FC_GPN_FT_NUM_BUFS - 1]; |
108 | struct zfcp_fc_gpn_ft_req req; | 142 | struct zfcp_fc_gpn_ft_req req; |
109 | } gpn_ft; | 143 | } gpn_ft; |
144 | struct { | ||
145 | struct zfcp_fc_gspn_req req; | ||
146 | struct zfcp_fc_gspn_rsp rsp; | ||
147 | } gspn; | ||
148 | struct { | ||
149 | struct zfcp_fc_rspn_req req; | ||
150 | struct fc_ct_hdr rsp; | ||
151 | } rspn; | ||
110 | } u; | 152 | } u; |
111 | }; | 153 | }; |
112 | 154 | ||
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index dbba0827127f..2a4991d6d4d5 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -720,6 +720,7 @@ struct fc_function_template zfcp_transport_functions = { | |||
720 | /* no functions registered for following dynamic attributes but | 720 | /* no functions registered for following dynamic attributes but |
721 | directly set by LLDD */ | 721 | directly set by LLDD */ |
722 | .show_host_port_type = 1, | 722 | .show_host_port_type = 1, |
723 | .show_host_symbolic_name = 1, | ||
723 | .show_host_speed = 1, | 724 | .show_host_speed = 1, |
724 | .show_host_port_id = 1, | 725 | .show_host_port_id = 1, |
725 | .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els), | 726 | .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els), |