diff options
Diffstat (limited to 'drivers/s390')
| -rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 10 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 18 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 2 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 6 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 188 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 15 |
6 files changed, 219 insertions, 20 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 3ac27ee4739..2ccbd185a5f 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
| @@ -470,6 +470,12 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
| 470 | if (!adapter) | 470 | if (!adapter) |
| 471 | return -ENOMEM; | 471 | return -ENOMEM; |
| 472 | 472 | ||
| 473 | adapter->gs = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL); | ||
| 474 | if (!adapter->gs) { | ||
| 475 | kfree(adapter); | ||
| 476 | return -ENOMEM; | ||
| 477 | } | ||
| 478 | |||
| 473 | ccw_device->handler = NULL; | 479 | ccw_device->handler = NULL; |
| 474 | adapter->ccw_device = ccw_device; | 480 | adapter->ccw_device = ccw_device; |
| 475 | atomic_set(&adapter->refcount, 0); | 481 | atomic_set(&adapter->refcount, 0); |
| @@ -523,8 +529,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
| 523 | goto sysfs_failed; | 529 | goto sysfs_failed; |
| 524 | 530 | ||
| 525 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 531 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); |
| 526 | 532 | zfcp_fc_wka_ports_init(adapter); | |
| 527 | zfcp_fc_nameserver_init(adapter); | ||
| 528 | 533 | ||
| 529 | if (!zfcp_adapter_scsi_register(adapter)) | 534 | if (!zfcp_adapter_scsi_register(adapter)) |
| 530 | return 0; | 535 | return 0; |
| @@ -571,6 +576,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
| 571 | kfree(adapter->req_list); | 576 | kfree(adapter->req_list); |
| 572 | kfree(adapter->fc_stats); | 577 | kfree(adapter->fc_stats); |
| 573 | kfree(adapter->stats_reset_data); | 578 | kfree(adapter->stats_reset_data); |
| 579 | kfree(adapter->gs); | ||
| 574 | kfree(adapter); | 580 | kfree(adapter); |
| 575 | } | 581 | } |
| 576 | 582 | ||
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 2074d45dbf6..49d0532bca1 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | #include <linux/syscalls.h> | 22 | #include <linux/syscalls.h> |
| 23 | #include <linux/scatterlist.h> | 23 | #include <linux/scatterlist.h> |
| 24 | #include <linux/ioctl.h> | 24 | #include <linux/ioctl.h> |
| 25 | #include <scsi/fc/fc_fs.h> | ||
| 26 | #include <scsi/fc/fc_gs.h> | ||
| 25 | #include <scsi/scsi.h> | 27 | #include <scsi/scsi.h> |
| 26 | #include <scsi/scsi_tcq.h> | 28 | #include <scsi/scsi_tcq.h> |
| 27 | #include <scsi/scsi_cmnd.h> | 29 | #include <scsi/scsi_cmnd.h> |
| @@ -29,6 +31,7 @@ | |||
| 29 | #include <scsi/scsi_host.h> | 31 | #include <scsi/scsi_host.h> |
| 30 | #include <scsi/scsi_transport.h> | 32 | #include <scsi/scsi_transport.h> |
| 31 | #include <scsi/scsi_transport_fc.h> | 33 | #include <scsi/scsi_transport_fc.h> |
| 34 | #include <scsi/scsi_bsg_fc.h> | ||
| 32 | #include <asm/ccwdev.h> | 35 | #include <asm/ccwdev.h> |
| 33 | #include <asm/qdio.h> | 36 | #include <asm/qdio.h> |
| 34 | #include <asm/debug.h> | 37 | #include <asm/debug.h> |
| @@ -228,11 +231,6 @@ struct zfcp_ls_adisc { | |||
| 228 | 231 | ||
| 229 | /* FC-PH/FC-GS well-known address identifiers for generic services */ | 232 | /* FC-PH/FC-GS well-known address identifiers for generic services */ |
| 230 | #define ZFCP_DID_WKA 0xFFFFF0 | 233 | #define ZFCP_DID_WKA 0xFFFFF0 |
| 231 | #define ZFCP_DID_MANAGEMENT_SERVICE 0xFFFFFA | ||
| 232 | #define ZFCP_DID_TIME_SERVICE 0xFFFFFB | ||
| 233 | #define ZFCP_DID_DIRECTORY_SERVICE 0xFFFFFC | ||
| 234 | #define ZFCP_DID_ALIAS_SERVICE 0xFFFFF8 | ||
| 235 | #define ZFCP_DID_KEY_DISTRIBUTION_SERVICE 0xFFFFF7 | ||
| 236 | 234 | ||
| 237 | /* remote port status */ | 235 | /* remote port status */ |
| 238 | #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 | 236 | #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 |
| @@ -376,6 +374,14 @@ struct zfcp_wka_port { | |||
| 376 | struct delayed_work work; | 374 | struct delayed_work work; |
| 377 | }; | 375 | }; |
| 378 | 376 | ||
| 377 | struct zfcp_wka_ports { | ||
| 378 | struct zfcp_wka_port ms; /* management service */ | ||
| 379 | struct zfcp_wka_port ts; /* time service */ | ||
| 380 | struct zfcp_wka_port ds; /* directory service */ | ||
| 381 | struct zfcp_wka_port as; /* alias service */ | ||
| 382 | struct zfcp_wka_port ks; /* key distribution service */ | ||
| 383 | }; | ||
| 384 | |||
| 379 | struct zfcp_qdio_queue { | 385 | struct zfcp_qdio_queue { |
| 380 | struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; | 386 | struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; |
| 381 | u8 first; /* index of next free bfr in queue */ | 387 | u8 first; /* index of next free bfr in queue */ |
| @@ -461,7 +467,7 @@ struct zfcp_adapter { | |||
| 461 | actions */ | 467 | actions */ |
| 462 | u32 erp_low_mem_count; /* nr of erp actions waiting | 468 | u32 erp_low_mem_count; /* nr of erp actions waiting |
| 463 | for memory */ | 469 | for memory */ |
| 464 | struct zfcp_wka_port nsp; /* adapter's nameserver */ | 470 | struct zfcp_wka_ports *gs; /* generic services */ |
| 465 | debug_info_t *rec_dbf; | 471 | debug_info_t *rec_dbf; |
| 466 | debug_info_t *hba_dbf; | 472 | debug_info_t *hba_dbf; |
| 467 | debug_info_t *san_dbf; /* debug feature areas */ | 473 | debug_info_t *san_dbf; /* debug feature areas */ |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index e50ea465bc2..8030e25152f 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
| @@ -719,7 +719,7 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) | |||
| 719 | zfcp_qdio_close(adapter); | 719 | zfcp_qdio_close(adapter); |
| 720 | zfcp_fsf_req_dismiss_all(adapter); | 720 | zfcp_fsf_req_dismiss_all(adapter); |
| 721 | adapter->fsf_req_seq_no = 0; | 721 | adapter->fsf_req_seq_no = 0; |
| 722 | zfcp_fc_wka_port_force_offline(&adapter->nsp); | 722 | zfcp_fc_wka_port_force_offline(&adapter->gs->ds); |
| 723 | /* all ports and units are closed */ | 723 | /* all ports and units are closed */ |
| 724 | zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, | 724 | zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, |
| 725 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); | 725 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 120a9a1c81f..3044c601030 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
| @@ -106,8 +106,12 @@ extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); | |||
| 106 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | 106 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); |
| 107 | extern void zfcp_test_link(struct zfcp_port *); | 107 | extern void zfcp_test_link(struct zfcp_port *); |
| 108 | extern void zfcp_fc_link_test_work(struct work_struct *); | 108 | extern void zfcp_fc_link_test_work(struct work_struct *); |
| 109 | extern void zfcp_fc_nameserver_init(struct zfcp_adapter *); | ||
| 110 | extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); | 109 | extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); |
| 110 | extern void zfcp_fc_wka_ports_init(struct zfcp_adapter *); | ||
| 111 | extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *); | ||
| 112 | extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *); | ||
| 113 | extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); | ||
| 114 | |||
| 111 | 115 | ||
| 112 | /* zfcp_fsf.c */ | 116 | /* zfcp_fsf.c */ |
| 113 | extern int zfcp_fsf_open_port(struct zfcp_erp_action *); | 117 | extern int zfcp_fsf_open_port(struct zfcp_erp_action *); |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index bb2752b4130..da10e0df687 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,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 | |||
| 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 = blk_rq_bytes(job->req->next_rq); | ||
| 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 | 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 | |||
| 763 | struct zfcp_ct_fc_job { | ||
| 764 | struct zfcp_send_ct ct; | ||
| 765 | struct fc_bsg_job *job; | ||
| 766 | }; | ||
| 767 | |||
| 768 | static 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 | |||
| 784 | int 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 | } | ||
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 7d0da230eb6..967ede73f4c 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
| @@ -623,6 +623,20 @@ void zfcp_scsi_scan(struct work_struct *work) | |||
| 623 | zfcp_unit_put(unit); | 623 | zfcp_unit_put(unit); |
| 624 | } | 624 | } |
| 625 | 625 | ||
| 626 | static int zfcp_execute_fc_job(struct fc_bsg_job *job) | ||
| 627 | { | ||
| 628 | switch (job->request->msgcode) { | ||
| 629 | case FC_BSG_RPT_ELS: | ||
| 630 | case FC_BSG_HST_ELS_NOLOGIN: | ||
| 631 | return zfcp_fc_execute_els_fc_job(job); | ||
| 632 | case FC_BSG_RPT_CT: | ||
| 633 | case FC_BSG_HST_CT: | ||
| 634 | return zfcp_fc_execute_ct_fc_job(job); | ||
| 635 | default: | ||
| 636 | return -EINVAL; | ||
| 637 | } | ||
| 638 | } | ||
| 639 | |||
| 626 | struct fc_function_template zfcp_transport_functions = { | 640 | struct fc_function_template zfcp_transport_functions = { |
| 627 | .show_starget_port_id = 1, | 641 | .show_starget_port_id = 1, |
| 628 | .show_starget_port_name = 1, | 642 | .show_starget_port_name = 1, |
| @@ -644,6 +658,7 @@ struct fc_function_template zfcp_transport_functions = { | |||
| 644 | .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, | 658 | .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, |
| 645 | .terminate_rport_io = zfcp_scsi_terminate_rport_io, | 659 | .terminate_rport_io = zfcp_scsi_terminate_rport_io, |
| 646 | .show_host_port_state = 1, | 660 | .show_host_port_state = 1, |
| 661 | .bsg_request = zfcp_execute_fc_job, | ||
| 647 | /* no functions registered for following dynamic attributes but | 662 | /* no functions registered for following dynamic attributes but |
| 648 | directly set by LLDD */ | 663 | directly set by LLDD */ |
| 649 | .show_host_port_type = 1, | 664 | .show_host_port_type = 1, |
