aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_fc.c
diff options
context:
space:
mode:
authorSven Schuetz <sven@linux.vnet.ibm.com>2009-04-06 12:31:47 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-06-12 15:20:05 -0400
commit9d544f2b9bd4a0f7ba2784cc47e3591667a7b8d4 (patch)
tree5497f9b83aaa2e17da5d6ef0901de0c731e7b8a3 /drivers/s390/scsi/zfcp_fc.c
parent9e4f5e29610162fd426366f3b29e3cc6e575b858 (diff)
[SCSI] zfcp: Add FC pass-through support
Provide the ability to do fibre channel requests from the userspace to our zfcp driver. Patch builds upon extension to the fibre channel tranport class by James Smart and Seokmann Ju. See here http://marc.info/?l=linux-scsi&m=123808882309133&w=2 Signed-off-by: Sven Schuetz <sven@linux.vnet.ibm.com> Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/s390/scsi/zfcp_fc.c')
-rw-r--r--drivers/s390/scsi/zfcp_fc.c188
1 files changed, 178 insertions, 10 deletions
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index bb2752b4130f..da10e0df6879 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
123void zfcp_fc_nameserver_init(struct zfcp_adapter *adapter) 123static 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
145void 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
146static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, 156static 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);
339out: 349out:
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);
668out: 678out:
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,161 @@ 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
689struct zfcp_els_fc_job {
690 struct zfcp_send_els els;
691 struct fc_bsg_job *job;
692};
693
694static 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 = blk_rq_bytes(job->req->next_rq);
708
709out:
710 job->state_flags = FC_RQST_STATE_DONE;
711 job->job_done(job);
712 kfree(els_fc_job);
713}
714
715int 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 zfcp_port_get(port);
740 read_unlock_irq(&zfcp_data.config_lock);
741 if (!port) {
742 kfree(els_fc_job);
743 return -EINVAL;
744 }
745 els_fc_job->els.port = port;
746 els_fc_job->els.d_id = port->d_id;
747 zfcp_port_put(port);
748 } else {
749 port_did = job->request->rqst_data.h_els.port_id;
750 els_fc_job->els.d_id = (port_did[0] << 16) +
751 (port_did[1] << 8) + port_did[2];
752 }
753
754 els_fc_job->els.req = job->request_payload.sg_list;
755 els_fc_job->els.resp = job->reply_payload.sg_list;
756 els_fc_job->els.handler = zfcp_fc_generic_els_handler;
757 els_fc_job->els.handler_data = (unsigned long) els_fc_job;
758 els_fc_job->job = job;
759
760 return zfcp_fsf_send_els(&els_fc_job->els);
761}
762
763struct zfcp_ct_fc_job {
764 struct zfcp_send_ct ct;
765 struct fc_bsg_job *job;
766};
767
768static void zfcp_fc_generic_ct_handler(unsigned long data)
769{
770 struct zfcp_ct_fc_job *ct_fc_job = (struct zfcp_ct_fc_job *) data;
771 struct fc_bsg_job *job = ct_fc_job->job;
772
773 job->reply->reply_data.ctels_reply.status = ct_fc_job->ct.status ?
774 FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK;
775 job->state_flags = FC_RQST_STATE_DONE;
776 job->reply->reply_payload_rcv_len = blk_rq_bytes(job->req->next_rq);
777 job->job_done(job);
778
779 zfcp_wka_port_put(ct_fc_job->ct.wka_port);
780
781 kfree(ct_fc_job);
782}
783
784int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job)
785{
786 int ret;
787 u8 gs_type;
788 struct fc_rport *rport = job->rport;
789 struct Scsi_Host *shost;
790 struct zfcp_adapter *adapter;
791 struct zfcp_ct_fc_job *ct_fc_job;
792 u32 preamble_word1;
793
794 shost = rport ? rport_to_shost(rport) : job->shost;
795
796 adapter = (struct zfcp_adapter *)shost->hostdata[0];
797 if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN))
798 return -EINVAL;
799
800 ct_fc_job = kzalloc(sizeof(struct zfcp_ct_fc_job), GFP_KERNEL);
801 if (!ct_fc_job)
802 return -ENOMEM;
803
804 preamble_word1 = job->request->rqst_data.r_ct.preamble_word1;
805 gs_type = (preamble_word1 & 0xff000000) >> 24;
806
807 switch (gs_type) {
808 case FC_FST_ALIAS:
809 ct_fc_job->ct.wka_port = &adapter->gs->as;
810 break;
811 case FC_FST_MGMT:
812 ct_fc_job->ct.wka_port = &adapter->gs->ms;
813 break;
814 case FC_FST_TIME:
815 ct_fc_job->ct.wka_port = &adapter->gs->ts;
816 break;
817 case FC_FST_DIR:
818 ct_fc_job->ct.wka_port = &adapter->gs->ds;
819 break;
820 default:
821 kfree(ct_fc_job);
822 return -EINVAL; /* no such service */
823 }
824
825 ret = zfcp_wka_port_get(ct_fc_job->ct.wka_port);
826 if (ret) {
827 kfree(ct_fc_job);
828 return ret;
829 }
830
831 ct_fc_job->ct.req = job->request_payload.sg_list;
832 ct_fc_job->ct.resp = job->reply_payload.sg_list;
833 ct_fc_job->ct.timeout = ZFCP_FSF_REQUEST_TIMEOUT;
834 ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler;
835 ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job;
836 ct_fc_job->ct.completion = NULL;
837 ct_fc_job->job = job;
838
839 ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL, NULL);
840 if (ret) {
841 kfree(ct_fc_job);
842 zfcp_wka_port_put(ct_fc_job->ct.wka_port);
843 }
844 return ret;
845}