diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 36 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 5 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 42 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 248 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 3 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs_adapter.c | 25 |
8 files changed, 336 insertions, 31 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 47739f4f6709..2bd80fdcceff 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -568,6 +568,19 @@ static void _zfcp_status_read_scheduler(struct work_struct *work) | |||
568 | stat_work)); | 568 | stat_work)); |
569 | } | 569 | } |
570 | 570 | ||
571 | static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) | ||
572 | { | ||
573 | struct zfcp_port *port; | ||
574 | |||
575 | port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, | ||
576 | ZFCP_DID_DIRECTORY_SERVICE); | ||
577 | if (!port) | ||
578 | return -ENXIO; | ||
579 | zfcp_port_put(port); | ||
580 | |||
581 | return 0; | ||
582 | } | ||
583 | |||
571 | /* | 584 | /* |
572 | * Enqueues an adapter at the end of the adapter list in the driver data. | 585 | * Enqueues an adapter at the end of the adapter list in the driver data. |
573 | * All adapter internal structures are set up. | 586 | * All adapter internal structures are set up. |
@@ -648,6 +661,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
648 | /* initialize lock of associated request queue */ | 661 | /* initialize lock of associated request queue */ |
649 | rwlock_init(&adapter->req_q.lock); | 662 | rwlock_init(&adapter->req_q.lock); |
650 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | 663 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); |
664 | INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later); | ||
651 | 665 | ||
652 | /* mark adapter unusable as long as sysfs registration is not complete */ | 666 | /* mark adapter unusable as long as sysfs registration is not complete */ |
653 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 667 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); |
@@ -673,6 +687,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
673 | 687 | ||
674 | zfcp_data.adapters++; | 688 | zfcp_data.adapters++; |
675 | 689 | ||
690 | zfcp_nameserver_enqueue(adapter); | ||
691 | |||
676 | goto out; | 692 | goto out; |
677 | 693 | ||
678 | generic_services_failed: | 694 | generic_services_failed: |
@@ -704,6 +720,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
704 | int retval = 0; | 720 | int retval = 0; |
705 | unsigned long flags; | 721 | unsigned long flags; |
706 | 722 | ||
723 | cancel_work_sync(&adapter->scan_work); | ||
707 | cancel_work_sync(&adapter->stat_work); | 724 | cancel_work_sync(&adapter->stat_work); |
708 | zfcp_adapter_scsi_unregister(adapter); | 725 | zfcp_adapter_scsi_unregister(adapter); |
709 | device_unregister(&adapter->generic_services); | 726 | device_unregister(&adapter->generic_services); |
@@ -816,13 +833,15 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, | |||
816 | kfree(port); | 833 | kfree(port); |
817 | return NULL; | 834 | return NULL; |
818 | } | 835 | } |
819 | port->d_id = d_id; | ||
820 | port->sysfs_device.parent = &adapter->generic_services; | 836 | port->sysfs_device.parent = &adapter->generic_services; |
821 | } else { | 837 | } else { |
822 | snprintf(port->sysfs_device.bus_id, | 838 | snprintf(port->sysfs_device.bus_id, |
823 | BUS_ID_SIZE, "0x%016llx", wwpn); | 839 | BUS_ID_SIZE, "0x%016llx", wwpn); |
824 | port->sysfs_device.parent = &adapter->ccw_device->dev; | 840 | port->sysfs_device.parent = &adapter->ccw_device->dev; |
825 | } | 841 | } |
842 | |||
843 | port->d_id = d_id; | ||
844 | |||
826 | port->sysfs_device.release = zfcp_sysfs_port_release; | 845 | port->sysfs_device.release = zfcp_sysfs_port_release; |
827 | dev_set_drvdata(&port->sysfs_device, port); | 846 | dev_set_drvdata(&port->sysfs_device, port); |
828 | 847 | ||
@@ -873,21 +892,6 @@ zfcp_port_dequeue(struct zfcp_port *port) | |||
873 | device_unregister(&port->sysfs_device); | 892 | device_unregister(&port->sysfs_device); |
874 | } | 893 | } |
875 | 894 | ||
876 | /* Enqueues a nameserver port */ | ||
877 | int | ||
878 | zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) | ||
879 | { | ||
880 | struct zfcp_port *port; | ||
881 | |||
882 | port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, | ||
883 | ZFCP_DID_DIRECTORY_SERVICE); | ||
884 | if (!port) | ||
885 | return -ENXIO; | ||
886 | zfcp_port_put(port); | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | void zfcp_sg_free_table(struct scatterlist *sg, int count) | 895 | void zfcp_sg_free_table(struct scatterlist *sg, int count) |
892 | { | 896 | { |
893 | int i; | 897 | int i; |
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 7c72f502eb0f..3e9f0abb22f9 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -596,6 +596,10 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
596 | [145] = "recovery action being processed", | 596 | [145] = "recovery action being processed", |
597 | [146] = "recovery action ready for next step", | 597 | [146] = "recovery action ready for next step", |
598 | [147] = "qdio error inbound", | 598 | [147] = "qdio error inbound", |
599 | [148] = "nameserver needed for port scan", | ||
600 | [149] = "port scan", | ||
601 | [150] = "ptp attach", | ||
602 | [151] = "port validation failed", | ||
599 | }; | 603 | }; |
600 | 604 | ||
601 | static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, | 605 | static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 73425dbb2be8..1e837d46ea74 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -282,7 +282,10 @@ struct zfcp_rc_entry { | |||
282 | #define ZFCP_CT_DIRECTORY_SERVICE 0xFC | 282 | #define ZFCP_CT_DIRECTORY_SERVICE 0xFC |
283 | #define ZFCP_CT_NAME_SERVER 0x02 | 283 | #define ZFCP_CT_NAME_SERVER 0x02 |
284 | #define ZFCP_CT_SYNCHRONOUS 0x00 | 284 | #define ZFCP_CT_SYNCHRONOUS 0x00 |
285 | #define ZFCP_CT_SCSI_FCP 0x08 | ||
286 | #define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 | ||
285 | #define ZFCP_CT_GID_PN 0x0121 | 287 | #define ZFCP_CT_GID_PN 0x0121 |
288 | #define ZFCP_CT_GPN_FT 0x0172 | ||
286 | #define ZFCP_CT_MAX_SIZE 0x1020 | 289 | #define ZFCP_CT_MAX_SIZE 0x1020 |
287 | #define ZFCP_CT_ACCEPT 0x8002 | 290 | #define ZFCP_CT_ACCEPT 0x8002 |
288 | #define ZFCP_CT_REJECT 0x8001 | 291 | #define ZFCP_CT_REJECT 0x8001 |
@@ -311,6 +314,7 @@ struct zfcp_rc_entry { | |||
311 | #define ZFCP_STATUS_COMMON_ERP_INUSE 0x01000000 | 314 | #define ZFCP_STATUS_COMMON_ERP_INUSE 0x01000000 |
312 | #define ZFCP_STATUS_COMMON_ACCESS_DENIED 0x00800000 | 315 | #define ZFCP_STATUS_COMMON_ACCESS_DENIED 0x00800000 |
313 | #define ZFCP_STATUS_COMMON_ACCESS_BOXED 0x00400000 | 316 | #define ZFCP_STATUS_COMMON_ACCESS_BOXED 0x00400000 |
317 | #define ZFCP_STATUS_COMMON_NOESC 0x00200000 | ||
314 | 318 | ||
315 | /* adapter status */ | 319 | /* adapter status */ |
316 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 | 320 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 |
@@ -629,6 +633,7 @@ struct zfcp_adapter { | |||
629 | struct fc_host_statistics *fc_stats; | 633 | struct fc_host_statistics *fc_stats; |
630 | struct fsf_qtcb_bottom_port *stats_reset_data; | 634 | struct fsf_qtcb_bottom_port *stats_reset_data; |
631 | unsigned long stats_reset; | 635 | unsigned long stats_reset; |
636 | struct work_struct scan_work; | ||
632 | }; | 637 | }; |
633 | 638 | ||
634 | /* | 639 | /* |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c06156b288ea..9b9c999cf39f 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -1199,6 +1199,10 @@ zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) | |||
1199 | zfcp_erp_port_unblock(port); | 1199 | zfcp_erp_port_unblock(port); |
1200 | break; | 1200 | break; |
1201 | case ZFCP_ERP_FAILED : | 1201 | case ZFCP_ERP_FAILED : |
1202 | if (atomic_test_mask(ZFCP_STATUS_COMMON_NOESC, &port->status)) { | ||
1203 | zfcp_erp_port_block(port, 0); | ||
1204 | result = ZFCP_ERP_EXIT; | ||
1205 | } | ||
1202 | atomic_inc(&port->erp_counter); | 1206 | atomic_inc(&port->erp_counter); |
1203 | if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) | 1207 | if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) |
1204 | zfcp_erp_port_failed(port, 22, NULL); | 1208 | zfcp_erp_port_failed(port, 22, NULL); |
@@ -1607,6 +1611,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) | |||
1607 | goto failed_openfcp; | 1611 | goto failed_openfcp; |
1608 | 1612 | ||
1609 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &erp_action->adapter->status); | 1613 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &erp_action->adapter->status); |
1614 | schedule_work(&erp_action->adapter->scan_work); | ||
1610 | goto out; | 1615 | goto out; |
1611 | 1616 | ||
1612 | close_only: | 1617 | close_only: |
@@ -1665,10 +1670,19 @@ zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action) | |||
1665 | return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); | 1670 | return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); |
1666 | } | 1671 | } |
1667 | 1672 | ||
1673 | static void zfcp_erp_open_ptp_port(struct zfcp_adapter *adapter) | ||
1674 | { | ||
1675 | struct zfcp_port *port; | ||
1676 | port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, | ||
1677 | adapter->peer_d_id); | ||
1678 | if (!port) /* error or port already attached */ | ||
1679 | return; | ||
1680 | zfcp_erp_port_reopen_internal(port, 0, 150, NULL); | ||
1681 | } | ||
1682 | |||
1668 | static int | 1683 | static int |
1669 | zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) | 1684 | zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) |
1670 | { | 1685 | { |
1671 | int retval = ZFCP_ERP_SUCCEEDED; | ||
1672 | int retries; | 1686 | int retries; |
1673 | int sleep = ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP; | 1687 | int sleep = ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP; |
1674 | struct zfcp_adapter *adapter = erp_action->adapter; | 1688 | struct zfcp_adapter *adapter = erp_action->adapter; |
@@ -1682,8 +1696,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) | |||
1682 | zfcp_erp_action_to_running(erp_action); | 1696 | zfcp_erp_action_to_running(erp_action); |
1683 | write_unlock_irq(&adapter->erp_lock); | 1697 | write_unlock_irq(&adapter->erp_lock); |
1684 | if (zfcp_fsf_exchange_config_data(erp_action)) { | 1698 | if (zfcp_fsf_exchange_config_data(erp_action)) { |
1685 | retval = ZFCP_ERP_FAILED; | 1699 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, |
1686 | break; | 1700 | &adapter->status); |
1701 | return ZFCP_ERP_FAILED; | ||
1687 | } | 1702 | } |
1688 | 1703 | ||
1689 | /* | 1704 | /* |
@@ -1719,9 +1734,12 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) | |||
1719 | 1734 | ||
1720 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | 1735 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, |
1721 | &adapter->status)) | 1736 | &adapter->status)) |
1722 | retval = ZFCP_ERP_FAILED; | 1737 | return ZFCP_ERP_FAILED; |
1723 | 1738 | ||
1724 | return retval; | 1739 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) |
1740 | zfcp_erp_open_ptp_port(adapter); | ||
1741 | |||
1742 | return ZFCP_ERP_SUCCEEDED; | ||
1725 | } | 1743 | } |
1726 | 1744 | ||
1727 | static int | 1745 | static int |
@@ -1899,14 +1917,12 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) | |||
1899 | retval = zfcp_erp_port_strategy_open_port(erp_action); | 1917 | retval = zfcp_erp_port_strategy_open_port(erp_action); |
1900 | break; | 1918 | break; |
1901 | } | 1919 | } |
1902 | if (!(adapter->nameserver_port)) { | 1920 | |
1903 | retval = zfcp_nameserver_enqueue(adapter); | 1921 | if (!adapter->nameserver_port) { |
1904 | if (retval != 0) { | 1922 | dev_err(&adapter->ccw_device->dev, |
1905 | dev_err(&adapter->ccw_device->dev, | 1923 | "Nameserver port unavailable.\n"); |
1906 | "Nameserver port unavailable.\n"); | 1924 | retval = ZFCP_ERP_FAILED; |
1907 | retval = ZFCP_ERP_FAILED; | 1925 | break; |
1908 | break; | ||
1909 | } | ||
1910 | } | 1926 | } |
1911 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 1927 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, |
1912 | &adapter->nameserver_port->status)) { | 1928 | &adapter->nameserver_port->status)) { |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 9aa412bd6637..c3b51338abfa 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -37,6 +37,8 @@ extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, | |||
37 | extern void zfcp_port_dequeue(struct zfcp_port *); | 37 | extern void zfcp_port_dequeue(struct zfcp_port *); |
38 | extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); | 38 | extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); |
39 | extern void zfcp_unit_dequeue(struct zfcp_unit *); | 39 | extern void zfcp_unit_dequeue(struct zfcp_unit *); |
40 | extern int zfcp_scan_ports(struct zfcp_adapter *); | ||
41 | extern void _zfcp_scan_ports_later(struct work_struct *work); | ||
40 | 42 | ||
41 | /******************************* S/390 IO ************************************/ | 43 | /******************************* S/390 IO ************************************/ |
42 | extern int zfcp_ccw_register(void); | 44 | extern int zfcp_ccw_register(void); |
@@ -97,8 +99,6 @@ extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *); | |||
97 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | 99 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); |
98 | extern void zfcp_test_link(struct zfcp_port *); | 100 | extern void zfcp_test_link(struct zfcp_port *); |
99 | 101 | ||
100 | extern int zfcp_nameserver_enqueue(struct zfcp_adapter *); | ||
101 | |||
102 | /******************************* SCSI ****************************************/ | 102 | /******************************* SCSI ****************************************/ |
103 | extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); | 103 | extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); |
104 | extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); | 104 | extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index bb07c3bf2258..aa2d9a668d17 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -8,6 +8,37 @@ | |||
8 | 8 | ||
9 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
10 | 10 | ||
11 | struct ct_iu_gpn_ft_req { | ||
12 | struct ct_hdr header; | ||
13 | u8 flags; | ||
14 | u8 domain_id_scope; | ||
15 | u8 area_id_scope; | ||
16 | u8 fc4_type; | ||
17 | } __attribute__ ((packed)); | ||
18 | |||
19 | struct gpn_ft_resp_acc { | ||
20 | u8 control; | ||
21 | u8 port_id[3]; | ||
22 | u8 reserved[4]; | ||
23 | u64 wwpn; | ||
24 | } __attribute__ ((packed)); | ||
25 | |||
26 | #define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \ | ||
27 | / sizeof(struct gpn_ft_resp_acc)) | ||
28 | #define ZFCP_GPN_FT_BUFFERS 4 | ||
29 | #define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) | ||
30 | |||
31 | struct ct_iu_gpn_ft_resp { | ||
32 | struct ct_hdr header; | ||
33 | struct gpn_ft_resp_acc accept[ZFCP_GPN_FT_ENTRIES]; | ||
34 | } __attribute__ ((packed)); | ||
35 | |||
36 | struct zfcp_gpn_ft { | ||
37 | struct zfcp_send_ct ct; | ||
38 | struct scatterlist sg_req; | ||
39 | struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS]; | ||
40 | }; | ||
41 | |||
11 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, | 42 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, |
12 | struct fcp_rscn_element *elem) | 43 | struct fcp_rscn_element *elem) |
13 | { | 44 | { |
@@ -68,6 +99,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) | |||
68 | } | 99 | } |
69 | _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); | 100 | _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); |
70 | } | 101 | } |
102 | schedule_work(&fsf_req->adapter->scan_work); | ||
71 | } | 103 | } |
72 | 104 | ||
73 | static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn) | 105 | static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn) |
@@ -303,3 +335,219 @@ void zfcp_test_link(struct zfcp_port *port) | |||
303 | zfcp_port_put(port); | 335 | zfcp_port_put(port); |
304 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | 336 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); |
305 | } | 337 | } |
338 | |||
339 | static int zfcp_scan_get_nameserver(struct zfcp_adapter *adapter) | ||
340 | { | ||
341 | int ret; | ||
342 | |||
343 | if (!adapter->nameserver_port) | ||
344 | return -EINTR; | ||
345 | |||
346 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
347 | &adapter->nameserver_port->status)) { | ||
348 | ret = zfcp_erp_port_reopen(adapter->nameserver_port, 0, 148, | ||
349 | NULL); | ||
350 | if (ret) | ||
351 | return ret; | ||
352 | zfcp_erp_wait(adapter); | ||
353 | zfcp_port_put(adapter->nameserver_port); | ||
354 | } | ||
355 | return !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
356 | &adapter->nameserver_port->status); | ||
357 | } | ||
358 | |||
359 | static void zfcp_gpn_ft_handler(unsigned long _done) | ||
360 | { | ||
361 | complete((struct completion *)_done); | ||
362 | } | ||
363 | |||
364 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft) | ||
365 | { | ||
366 | struct scatterlist *sg = &gpn_ft->sg_req; | ||
367 | |||
368 | kfree(sg_virt(sg)); /* free request buffer */ | ||
369 | zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS); | ||
370 | |||
371 | kfree(gpn_ft); | ||
372 | } | ||
373 | |||
374 | static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) | ||
375 | { | ||
376 | struct zfcp_gpn_ft *gpn_ft; | ||
377 | struct ct_iu_gpn_ft_req *req; | ||
378 | |||
379 | gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL); | ||
380 | if (!gpn_ft) | ||
381 | return NULL; | ||
382 | |||
383 | req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL); | ||
384 | if (!req) { | ||
385 | kfree(gpn_ft); | ||
386 | gpn_ft = NULL; | ||
387 | goto out; | ||
388 | } | ||
389 | sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); | ||
390 | |||
391 | if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) { | ||
392 | zfcp_free_sg_env(gpn_ft); | ||
393 | gpn_ft = NULL; | ||
394 | } | ||
395 | out: | ||
396 | return gpn_ft; | ||
397 | } | ||
398 | |||
399 | |||
400 | static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | ||
401 | struct zfcp_adapter *adapter) | ||
402 | { | ||
403 | struct zfcp_send_ct *ct = &gpn_ft->ct; | ||
404 | struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); | ||
405 | struct completion done; | ||
406 | int ret; | ||
407 | |||
408 | /* prepare CT IU for GPN_FT */ | ||
409 | req->header.revision = ZFCP_CT_REVISION; | ||
410 | req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; | ||
411 | req->header.gs_subtype = ZFCP_CT_NAME_SERVER; | ||
412 | req->header.options = ZFCP_CT_SYNCHRONOUS; | ||
413 | req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; | ||
414 | req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) * | ||
415 | (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2; | ||
416 | req->flags = 0; | ||
417 | req->domain_id_scope = 0; | ||
418 | req->area_id_scope = 0; | ||
419 | req->fc4_type = ZFCP_CT_SCSI_FCP; | ||
420 | |||
421 | /* prepare zfcp_send_ct */ | ||
422 | ct->port = adapter->nameserver_port; | ||
423 | ct->handler = zfcp_gpn_ft_handler; | ||
424 | ct->handler_data = (unsigned long)&done; | ||
425 | ct->timeout = 10; | ||
426 | ct->req = &gpn_ft->sg_req; | ||
427 | ct->resp = gpn_ft->sg_resp; | ||
428 | ct->req_count = 1; | ||
429 | ct->resp_count = ZFCP_GPN_FT_BUFFERS; | ||
430 | |||
431 | init_completion(&done); | ||
432 | ret = zfcp_fsf_send_ct(ct, NULL, NULL); | ||
433 | if (!ret) | ||
434 | wait_for_completion(&done); | ||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | static void zfcp_validate_port(struct zfcp_port *port) | ||
439 | { | ||
440 | struct zfcp_adapter *adapter = port->adapter; | ||
441 | |||
442 | atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); | ||
443 | |||
444 | if (port == adapter->nameserver_port) | ||
445 | return; | ||
446 | if ((port->supported_classes != 0) || (port->units != 0)) { | ||
447 | zfcp_port_put(port); | ||
448 | return; | ||
449 | } | ||
450 | zfcp_erp_port_shutdown(port, 0, 151, NULL); | ||
451 | zfcp_erp_wait(adapter); | ||
452 | zfcp_port_put(port); | ||
453 | zfcp_port_dequeue(port); | ||
454 | } | ||
455 | |||
456 | static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) | ||
457 | { | ||
458 | struct zfcp_send_ct *ct = &gpn_ft->ct; | ||
459 | struct scatterlist *sg = gpn_ft->sg_resp; | ||
460 | struct ct_hdr *hdr = sg_virt(sg); | ||
461 | struct gpn_ft_resp_acc *acc = sg_virt(sg); | ||
462 | struct zfcp_adapter *adapter = ct->port->adapter; | ||
463 | struct zfcp_port *port, *tmp; | ||
464 | u32 d_id; | ||
465 | int ret = 0, x; | ||
466 | |||
467 | if (ct->status) | ||
468 | return -EIO; | ||
469 | |||
470 | if (hdr->cmd_rsp_code != ZFCP_CT_ACCEPT) { | ||
471 | if (hdr->reason_code == ZFCP_CT_UNABLE_TO_PERFORM_CMD) | ||
472 | return -EAGAIN; /* might be a temporary condition */ | ||
473 | return -EIO; | ||
474 | } | ||
475 | |||
476 | if (hdr->max_res_size) | ||
477 | return -E2BIG; | ||
478 | |||
479 | down(&zfcp_data.config_sema); | ||
480 | |||
481 | /* first entry is the header */ | ||
482 | for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES; x++) { | ||
483 | if (x % (ZFCP_GPN_FT_ENTRIES + 1)) | ||
484 | acc++; | ||
485 | else | ||
486 | acc = sg_virt(++sg); | ||
487 | |||
488 | d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 | | ||
489 | acc->port_id[2]; | ||
490 | |||
491 | /* skip the adapter's port and known remote ports */ | ||
492 | if (acc->wwpn == fc_host_port_name(adapter->scsi_host) || | ||
493 | zfcp_get_port_by_did(adapter, d_id)) | ||
494 | continue; | ||
495 | |||
496 | port = zfcp_port_enqueue(adapter, acc->wwpn, | ||
497 | ZFCP_STATUS_PORT_DID_DID | | ||
498 | ZFCP_STATUS_COMMON_NOESC, d_id); | ||
499 | if (port) | ||
500 | zfcp_erp_port_reopen(port, 0, 149, NULL); | ||
501 | else | ||
502 | ret = -ENOMEM; | ||
503 | if (acc->control & 0x80) /* last entry */ | ||
504 | break; | ||
505 | } | ||
506 | |||
507 | zfcp_erp_wait(adapter); | ||
508 | list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list) | ||
509 | zfcp_validate_port(port); | ||
510 | up(&zfcp_data.config_sema); | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | /** | ||
515 | * zfcp_scan_ports - scan remote ports and attach new ports | ||
516 | * @adapter: pointer to struct zfcp_adapter | ||
517 | */ | ||
518 | int zfcp_scan_ports(struct zfcp_adapter *adapter) | ||
519 | { | ||
520 | int ret, i; | ||
521 | struct zfcp_gpn_ft *gpn_ft; | ||
522 | |||
523 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) | ||
524 | return 0; | ||
525 | |||
526 | ret = zfcp_scan_get_nameserver(adapter); | ||
527 | if (ret) | ||
528 | return ret; | ||
529 | |||
530 | gpn_ft = zfcp_alloc_sg_env(); | ||
531 | if (!gpn_ft) | ||
532 | return -ENOMEM; | ||
533 | |||
534 | for (i = 0; i < 3; i++) { | ||
535 | ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); | ||
536 | if (!ret) { | ||
537 | ret = zfcp_scan_eval_gpn_ft(gpn_ft); | ||
538 | if (ret == -EAGAIN) | ||
539 | ssleep(1); | ||
540 | else | ||
541 | break; | ||
542 | } | ||
543 | } | ||
544 | zfcp_free_sg_env(gpn_ft); | ||
545 | |||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | |||
550 | void _zfcp_scan_ports_later(struct work_struct *work) | ||
551 | { | ||
552 | zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); | ||
553 | } | ||
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 01ed5fb46c44..243e792f2407 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -874,6 +874,9 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) | |||
874 | if (status_buffer->status_subtype & | 874 | if (status_buffer->status_subtype & |
875 | FSF_STATUS_READ_SUB_ACT_UPDATED) | 875 | FSF_STATUS_READ_SUB_ACT_UPDATED) |
876 | zfcp_erp_adapter_access_changed(adapter, 135, fsf_req); | 876 | zfcp_erp_adapter_access_changed(adapter, 135, fsf_req); |
877 | if (status_buffer->status_subtype & | ||
878 | FSF_STATUS_READ_SUB_INCOMING_ELS) | ||
879 | schedule_work(&adapter->scan_work); | ||
877 | break; | 880 | break; |
878 | 881 | ||
879 | case FSF_STATUS_READ_CFDC_UPDATED: | 882 | case FSF_STATUS_READ_CFDC_UPDATED: |
diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c index 1f2a8c21b731..a4cae60f69d4 100644 --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c +++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c | |||
@@ -85,6 +85,30 @@ zfcp_sysfs_port_add_store(struct device *dev, struct device_attribute *attr, con | |||
85 | static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store); | 85 | static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store); |
86 | 86 | ||
87 | /** | 87 | /** |
88 | * zfcp_sysfs_port_rescan - trigger manual port rescan | ||
89 | * @dev: pointer to belonging device | ||
90 | * @attr: pointer to struct device_attribute | ||
91 | * @buf: pointer to input buffer | ||
92 | * @count: number of bytes in buffer | ||
93 | */ | ||
94 | static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, | ||
95 | struct device_attribute *attr, | ||
96 | const char *buf, size_t count) | ||
97 | { | ||
98 | struct zfcp_adapter *adapter; | ||
99 | int ret; | ||
100 | |||
101 | adapter = dev_get_drvdata(dev); | ||
102 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) | ||
103 | return -EBUSY; | ||
104 | |||
105 | ret = zfcp_scan_ports(adapter); | ||
106 | |||
107 | return ret ? ret : (ssize_t) count; | ||
108 | } | ||
109 | static DEVICE_ATTR(port_rescan, S_IWUSR, NULL, zfcp_sysfs_port_rescan_store); | ||
110 | |||
111 | /** | ||
88 | * zfcp_sysfs_port_remove_store - remove a port from sysfs tree | 112 | * zfcp_sysfs_port_remove_store - remove a port from sysfs tree |
89 | * @dev: pointer to belonging device | 113 | * @dev: pointer to belonging device |
90 | * @buf: pointer to input buffer | 114 | * @buf: pointer to input buffer |
@@ -214,6 +238,7 @@ static struct attribute *zfcp_adapter_attrs[] = { | |||
214 | &dev_attr_in_recovery.attr, | 238 | &dev_attr_in_recovery.attr, |
215 | &dev_attr_port_remove.attr, | 239 | &dev_attr_port_remove.attr, |
216 | &dev_attr_port_add.attr, | 240 | &dev_attr_port_add.attr, |
241 | &dev_attr_port_rescan.attr, | ||
217 | &dev_attr_peer_wwnn.attr, | 242 | &dev_attr_peer_wwnn.attr, |
218 | &dev_attr_peer_wwpn.attr, | 243 | &dev_attr_peer_wwpn.attr, |
219 | &dev_attr_peer_d_id.attr, | 244 | &dev_attr_peer_d_id.attr, |