diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_fc.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 185 |
1 files changed, 175 insertions, 10 deletions
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 35493a82d2a8..2f0705d76b72 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -120,14 +120,13 @@ static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port) | |||
120 | schedule_delayed_work(&wka_port->work, HZ / 100); | 120 | schedule_delayed_work(&wka_port->work, HZ / 100); |
121 | } | 121 | } |
122 | 122 | ||
123 | void zfcp_fc_nameserver_init(struct zfcp_adapter *adapter) | 123 | static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id, |
124 | struct zfcp_adapter *adapter) | ||
124 | { | 125 | { |
125 | struct zfcp_wka_port *wka_port = &adapter->nsp; | ||
126 | |||
127 | init_waitqueue_head(&wka_port->completion_wq); | 126 | init_waitqueue_head(&wka_port->completion_wq); |
128 | 127 | ||
129 | wka_port->adapter = adapter; | 128 | wka_port->adapter = adapter; |
130 | wka_port->d_id = ZFCP_DID_DIRECTORY_SERVICE; | 129 | wka_port->d_id = d_id; |
131 | 130 | ||
132 | wka_port->status = ZFCP_WKA_PORT_OFFLINE; | 131 | wka_port->status = ZFCP_WKA_PORT_OFFLINE; |
133 | atomic_set(&wka_port->refcount, 0); | 132 | atomic_set(&wka_port->refcount, 0); |
@@ -143,6 +142,17 @@ void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) | |||
143 | mutex_unlock(&wka->mutex); | 142 | mutex_unlock(&wka->mutex); |
144 | } | 143 | } |
145 | 144 | ||
145 | void zfcp_fc_wka_ports_init(struct zfcp_adapter *adapter) | ||
146 | { | ||
147 | struct zfcp_wka_ports *gs = adapter->gs; | ||
148 | |||
149 | zfcp_fc_wka_port_init(&gs->ms, FC_FID_MGMT_SERV, adapter); | ||
150 | zfcp_fc_wka_port_init(&gs->ts, FC_FID_TIME_SERV, adapter); | ||
151 | zfcp_fc_wka_port_init(&gs->ds, FC_FID_DIR_SERV, adapter); | ||
152 | zfcp_fc_wka_port_init(&gs->as, FC_FID_ALIASES, adapter); | ||
153 | zfcp_fc_wka_port_init(&gs->ks, FC_FID_SEC_KEY, adapter); | ||
154 | } | ||
155 | |||
146 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, | 156 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, |
147 | struct fcp_rscn_element *elem) | 157 | struct fcp_rscn_element *elem) |
148 | { | 158 | { |
@@ -282,7 +292,7 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, | |||
282 | 292 | ||
283 | /* setup parameters for send generic command */ | 293 | /* setup parameters for send generic command */ |
284 | gid_pn->port = erp_action->port; | 294 | gid_pn->port = erp_action->port; |
285 | gid_pn->ct.wka_port = &adapter->nsp; | 295 | gid_pn->ct.wka_port = &adapter->gs->ds; |
286 | gid_pn->ct.handler = zfcp_fc_ns_handler; | 296 | gid_pn->ct.handler = zfcp_fc_ns_handler; |
287 | gid_pn->ct.handler_data = (unsigned long) &compl_rec; | 297 | gid_pn->ct.handler_data = (unsigned long) &compl_rec; |
288 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | 298 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; |
@@ -329,13 +339,13 @@ int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action) | |||
329 | 339 | ||
330 | memset(gid_pn, 0, sizeof(*gid_pn)); | 340 | memset(gid_pn, 0, sizeof(*gid_pn)); |
331 | 341 | ||
332 | ret = zfcp_wka_port_get(&adapter->nsp); | 342 | ret = zfcp_wka_port_get(&adapter->gs->ds); |
333 | if (ret) | 343 | if (ret) |
334 | goto out; | 344 | goto out; |
335 | 345 | ||
336 | ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn); | 346 | ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn); |
337 | 347 | ||
338 | zfcp_wka_port_put(&adapter->nsp); | 348 | zfcp_wka_port_put(&adapter->gs->ds); |
339 | out: | 349 | out: |
340 | mempool_free(gid_pn, adapter->pool.data_gid_pn); | 350 | mempool_free(gid_pn, adapter->pool.data_gid_pn); |
341 | return ret; | 351 | return ret; |
@@ -525,7 +535,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | |||
525 | req->fc4_type = ZFCP_CT_SCSI_FCP; | 535 | req->fc4_type = ZFCP_CT_SCSI_FCP; |
526 | 536 | ||
527 | /* prepare zfcp_send_ct */ | 537 | /* prepare zfcp_send_ct */ |
528 | ct->wka_port = &adapter->nsp; | 538 | ct->wka_port = &adapter->gs->ds; |
529 | ct->handler = zfcp_fc_ns_handler; | 539 | ct->handler = zfcp_fc_ns_handler; |
530 | ct->handler_data = (unsigned long)&compl_rec; | 540 | ct->handler_data = (unsigned long)&compl_rec; |
531 | ct->timeout = 10; | 541 | ct->timeout = 10; |
@@ -644,7 +654,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) | |||
644 | fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) | 654 | fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) |
645 | return 0; | 655 | return 0; |
646 | 656 | ||
647 | ret = zfcp_wka_port_get(&adapter->nsp); | 657 | ret = zfcp_wka_port_get(&adapter->gs->ds); |
648 | if (ret) | 658 | if (ret) |
649 | return ret; | 659 | return ret; |
650 | 660 | ||
@@ -666,7 +676,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) | |||
666 | } | 676 | } |
667 | zfcp_free_sg_env(gpn_ft, buf_num); | 677 | zfcp_free_sg_env(gpn_ft, buf_num); |
668 | out: | 678 | out: |
669 | zfcp_wka_port_put(&adapter->nsp); | 679 | zfcp_wka_port_put(&adapter->gs->ds); |
670 | return ret; | 680 | return ret; |
671 | } | 681 | } |
672 | 682 | ||
@@ -675,3 +685,158 @@ void _zfcp_scan_ports_later(struct work_struct *work) | |||
675 | { | 685 | { |
676 | zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); | 686 | zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); |
677 | } | 687 | } |
688 | |||
689 | struct zfcp_els_fc_job { | ||
690 | struct zfcp_send_els els; | ||
691 | struct fc_bsg_job *job; | ||
692 | }; | ||
693 | |||
694 | static void zfcp_fc_generic_els_handler(unsigned long data) | ||
695 | { | ||
696 | struct zfcp_els_fc_job *els_fc_job = (struct zfcp_els_fc_job *) data; | ||
697 | struct fc_bsg_job *job = els_fc_job->job; | ||
698 | struct fc_bsg_reply *reply = job->reply; | ||
699 | |||
700 | if (els_fc_job->els.status) { | ||
701 | /* request rejected or timed out */ | ||
702 | reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_REJECT; | ||
703 | goto out; | ||
704 | } | ||
705 | |||
706 | reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; | ||
707 | reply->reply_payload_rcv_len = job->reply_payload.payload_len; | ||
708 | |||
709 | out: | ||
710 | job->state_flags = FC_RQST_STATE_DONE; | ||
711 | job->job_done(job); | ||
712 | kfree(els_fc_job); | ||
713 | } | ||
714 | |||
715 | int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) | ||
716 | { | ||
717 | struct zfcp_els_fc_job *els_fc_job; | ||
718 | struct fc_rport *rport = job->rport; | ||
719 | struct Scsi_Host *shost; | ||
720 | struct zfcp_adapter *adapter; | ||
721 | struct zfcp_port *port; | ||
722 | u8 *port_did; | ||
723 | |||
724 | shost = rport ? rport_to_shost(rport) : job->shost; | ||
725 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; | ||
726 | |||
727 | if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN)) | ||
728 | return -EINVAL; | ||
729 | |||
730 | els_fc_job = kzalloc(sizeof(struct zfcp_els_fc_job), GFP_KERNEL); | ||
731 | if (!els_fc_job) | ||
732 | return -ENOMEM; | ||
733 | |||
734 | els_fc_job->els.adapter = adapter; | ||
735 | if (rport) { | ||
736 | read_lock_irq(&zfcp_data.config_lock); | ||
737 | port = rport->dd_data; | ||
738 | if (port) | ||
739 | els_fc_job->els.d_id = port->d_id; | ||
740 | read_unlock_irq(&zfcp_data.config_lock); | ||
741 | if (!port) { | ||
742 | kfree(els_fc_job); | ||
743 | return -EINVAL; | ||
744 | } | ||
745 | } else { | ||
746 | port_did = job->request->rqst_data.h_els.port_id; | ||
747 | els_fc_job->els.d_id = (port_did[0] << 16) + | ||
748 | (port_did[1] << 8) + port_did[2]; | ||
749 | } | ||
750 | |||
751 | els_fc_job->els.req = job->request_payload.sg_list; | ||
752 | els_fc_job->els.resp = job->reply_payload.sg_list; | ||
753 | els_fc_job->els.handler = zfcp_fc_generic_els_handler; | ||
754 | els_fc_job->els.handler_data = (unsigned long) els_fc_job; | ||
755 | els_fc_job->job = job; | ||
756 | |||
757 | return zfcp_fsf_send_els(&els_fc_job->els); | ||
758 | } | ||
759 | |||
760 | struct zfcp_ct_fc_job { | ||
761 | struct zfcp_send_ct ct; | ||
762 | struct fc_bsg_job *job; | ||
763 | }; | ||
764 | |||
765 | static void zfcp_fc_generic_ct_handler(unsigned long data) | ||
766 | { | ||
767 | struct zfcp_ct_fc_job *ct_fc_job = (struct zfcp_ct_fc_job *) data; | ||
768 | struct fc_bsg_job *job = ct_fc_job->job; | ||
769 | |||
770 | job->reply->reply_data.ctels_reply.status = ct_fc_job->ct.status ? | ||
771 | FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK; | ||
772 | job->reply->reply_payload_rcv_len = job->reply_payload.payload_len; | ||
773 | job->state_flags = FC_RQST_STATE_DONE; | ||
774 | job->job_done(job); | ||
775 | |||
776 | zfcp_wka_port_put(ct_fc_job->ct.wka_port); | ||
777 | |||
778 | kfree(ct_fc_job); | ||
779 | } | ||
780 | |||
781 | int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) | ||
782 | { | ||
783 | int ret; | ||
784 | u8 gs_type; | ||
785 | struct fc_rport *rport = job->rport; | ||
786 | struct Scsi_Host *shost; | ||
787 | struct zfcp_adapter *adapter; | ||
788 | struct zfcp_ct_fc_job *ct_fc_job; | ||
789 | u32 preamble_word1; | ||
790 | |||
791 | shost = rport ? rport_to_shost(rport) : job->shost; | ||
792 | |||
793 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; | ||
794 | if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN)) | ||
795 | return -EINVAL; | ||
796 | |||
797 | ct_fc_job = kzalloc(sizeof(struct zfcp_ct_fc_job), GFP_KERNEL); | ||
798 | if (!ct_fc_job) | ||
799 | return -ENOMEM; | ||
800 | |||
801 | preamble_word1 = job->request->rqst_data.r_ct.preamble_word1; | ||
802 | gs_type = (preamble_word1 & 0xff000000) >> 24; | ||
803 | |||
804 | switch (gs_type) { | ||
805 | case FC_FST_ALIAS: | ||
806 | ct_fc_job->ct.wka_port = &adapter->gs->as; | ||
807 | break; | ||
808 | case FC_FST_MGMT: | ||
809 | ct_fc_job->ct.wka_port = &adapter->gs->ms; | ||
810 | break; | ||
811 | case FC_FST_TIME: | ||
812 | ct_fc_job->ct.wka_port = &adapter->gs->ts; | ||
813 | break; | ||
814 | case FC_FST_DIR: | ||
815 | ct_fc_job->ct.wka_port = &adapter->gs->ds; | ||
816 | break; | ||
817 | default: | ||
818 | kfree(ct_fc_job); | ||
819 | return -EINVAL; /* no such service */ | ||
820 | } | ||
821 | |||
822 | ret = zfcp_wka_port_get(ct_fc_job->ct.wka_port); | ||
823 | if (ret) { | ||
824 | kfree(ct_fc_job); | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | ct_fc_job->ct.req = job->request_payload.sg_list; | ||
829 | ct_fc_job->ct.resp = job->reply_payload.sg_list; | ||
830 | ct_fc_job->ct.timeout = ZFCP_FSF_REQUEST_TIMEOUT; | ||
831 | ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler; | ||
832 | ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job; | ||
833 | ct_fc_job->ct.completion = NULL; | ||
834 | ct_fc_job->job = job; | ||
835 | |||
836 | ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL, NULL); | ||
837 | if (ret) { | ||
838 | kfree(ct_fc_job); | ||
839 | zfcp_wka_port_put(ct_fc_job->ct.wka_port); | ||
840 | } | ||
841 | return ret; | ||
842 | } | ||