stat_work));
 }
 
+static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter)
+{
+       struct zfcp_port *port;
+
+       port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA,
+                                ZFCP_DID_DIRECTORY_SERVICE);
+       if (!port)
+               return -ENXIO;
+       zfcp_port_put(port);
+
+       return 0;
+}
+
 /*
  * Enqueues an adapter at the end of the adapter list in the driver data.
  * All adapter internal structures are set up.
        /* initialize lock of associated request queue */
        rwlock_init(&adapter->req_q.lock);
        INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
+       INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later);
 
        /* mark adapter unusable as long as sysfs registration is not complete */
        atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
 
        zfcp_data.adapters++;
 
+       zfcp_nameserver_enqueue(adapter);
+
        goto out;
 
  generic_services_failed:
        int retval = 0;
        unsigned long flags;
 
+       cancel_work_sync(&adapter->scan_work);
        cancel_work_sync(&adapter->stat_work);
        zfcp_adapter_scsi_unregister(adapter);
        device_unregister(&adapter->generic_services);
                        kfree(port);
                        return NULL;
                }
-               port->d_id = d_id;
                port->sysfs_device.parent = &adapter->generic_services;
        } else {
                snprintf(port->sysfs_device.bus_id,
                         BUS_ID_SIZE, "0x%016llx", wwpn);
                port->sysfs_device.parent = &adapter->ccw_device->dev;
        }
+
+       port->d_id = d_id;
+
        port->sysfs_device.release = zfcp_sysfs_port_release;
        dev_set_drvdata(&port->sysfs_device, port);
 
        device_unregister(&port->sysfs_device);
 }
 
-/* Enqueues a nameserver port */
-int
-zfcp_nameserver_enqueue(struct zfcp_adapter *adapter)
-{
-       struct zfcp_port *port;
-
-       port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA,
-                                ZFCP_DID_DIRECTORY_SERVICE);
-       if (!port)
-               return -ENXIO;
-       zfcp_port_put(port);
-
-       return 0;
-}
-
 void zfcp_sg_free_table(struct scatterlist *sg, int count)
 {
        int i;
 
        [145]   = "recovery action being processed",
        [146]   = "recovery action ready for next step",
        [147]   = "qdio error inbound",
+       [148]   = "nameserver needed for port scan",
+       [149]   = "port scan",
+       [150]   = "ptp attach",
+       [151]   = "port validation failed",
 };
 
 static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view,
 
 #define ZFCP_CT_DIRECTORY_SERVICE      0xFC
 #define ZFCP_CT_NAME_SERVER            0x02
 #define ZFCP_CT_SYNCHRONOUS            0x00
+#define ZFCP_CT_SCSI_FCP               0x08
+#define ZFCP_CT_UNABLE_TO_PERFORM_CMD  0x09
 #define ZFCP_CT_GID_PN                 0x0121
+#define ZFCP_CT_GPN_FT                 0x0172
 #define ZFCP_CT_MAX_SIZE               0x1020
 #define ZFCP_CT_ACCEPT                 0x8002
 #define ZFCP_CT_REJECT                 0x8001
 #define ZFCP_STATUS_COMMON_ERP_INUSE           0x01000000
 #define ZFCP_STATUS_COMMON_ACCESS_DENIED       0x00800000
 #define ZFCP_STATUS_COMMON_ACCESS_BOXED                0x00400000
+#define ZFCP_STATUS_COMMON_NOESC               0x00200000
 
 /* adapter status */
 #define ZFCP_STATUS_ADAPTER_QDIOUP             0x00000002
        struct fc_host_statistics *fc_stats;
        struct fsf_qtcb_bottom_port *stats_reset_data;
        unsigned long           stats_reset;
+       struct work_struct      scan_work;
 };
 
 /*
 
                zfcp_erp_port_unblock(port);
                break;
        case ZFCP_ERP_FAILED :
+               if (atomic_test_mask(ZFCP_STATUS_COMMON_NOESC, &port->status)) {
+                       zfcp_erp_port_block(port, 0);
+                       result = ZFCP_ERP_EXIT;
+               }
                atomic_inc(&port->erp_counter);
                if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS)
                        zfcp_erp_port_failed(port, 22, NULL);
                goto failed_openfcp;
 
        atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &erp_action->adapter->status);
+       schedule_work(&erp_action->adapter->scan_work);
        goto out;
 
  close_only:
        return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action);
 }
 
+static void zfcp_erp_open_ptp_port(struct zfcp_adapter *adapter)
+{
+       struct zfcp_port *port;
+       port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
+                                adapter->peer_d_id);
+       if (!port) /* error or port already attached */
+               return;
+       zfcp_erp_port_reopen_internal(port, 0, 150, NULL);
+}
+
 static int
 zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
 {
-       int retval = ZFCP_ERP_SUCCEEDED;
        int retries;
        int sleep = ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP;
        struct zfcp_adapter *adapter = erp_action->adapter;
                zfcp_erp_action_to_running(erp_action);
                write_unlock_irq(&adapter->erp_lock);
                if (zfcp_fsf_exchange_config_data(erp_action)) {
-                       retval = ZFCP_ERP_FAILED;
-                       break;
+                       atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
+                                         &adapter->status);
+                       return ZFCP_ERP_FAILED;
                }
 
                /*
 
        if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
                              &adapter->status))
-               retval = ZFCP_ERP_FAILED;
+               return ZFCP_ERP_FAILED;
 
-       return retval;
+       if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
+               zfcp_erp_open_ptp_port(adapter);
+
+       return ZFCP_ERP_SUCCEEDED;
 }
 
 static int
                        retval = zfcp_erp_port_strategy_open_port(erp_action);
                        break;
                }
-               if (!(adapter->nameserver_port)) {
-                       retval = zfcp_nameserver_enqueue(adapter);
-                       if (retval != 0) {
-                               dev_err(&adapter->ccw_device->dev,
-                                       "Nameserver port unavailable.\n");
-                               retval = ZFCP_ERP_FAILED;
-                               break;
-                       }
+
+               if (!adapter->nameserver_port) {
+                       dev_err(&adapter->ccw_device->dev,
+                               "Nameserver port unavailable.\n");
+                       retval = ZFCP_ERP_FAILED;
+                       break;
                }
                if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
                                      &adapter->nameserver_port->status)) {
 
 extern void   zfcp_port_dequeue(struct zfcp_port *);
 extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t);
 extern void   zfcp_unit_dequeue(struct zfcp_unit *);
+extern int zfcp_scan_ports(struct zfcp_adapter *);
+extern void _zfcp_scan_ports_later(struct work_struct *work);
 
 /******************************* S/390 IO ************************************/
 extern int  zfcp_ccw_register(void);
 extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *);
 extern void  zfcp_test_link(struct zfcp_port *);
 
-extern int  zfcp_nameserver_enqueue(struct zfcp_adapter *);
-
 /******************************* SCSI ****************************************/
 extern int  zfcp_adapter_scsi_register(struct zfcp_adapter *);
 extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
 
 
 #include "zfcp_ext.h"
 
+struct ct_iu_gpn_ft_req {
+       struct ct_hdr header;
+       u8 flags;
+       u8 domain_id_scope;
+       u8 area_id_scope;
+       u8 fc4_type;
+} __attribute__ ((packed));
+
+struct gpn_ft_resp_acc {
+       u8 control;
+       u8 port_id[3];
+       u8 reserved[4];
+       u64 wwpn;
+} __attribute__ ((packed));
+
+#define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \
+                               / sizeof(struct gpn_ft_resp_acc))
+#define ZFCP_GPN_FT_BUFFERS 4
+#define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1)
+
+struct ct_iu_gpn_ft_resp {
+       struct ct_hdr header;
+       struct gpn_ft_resp_acc accept[ZFCP_GPN_FT_ENTRIES];
+} __attribute__ ((packed));
+
+struct zfcp_gpn_ft {
+       struct zfcp_send_ct ct;
+       struct scatterlist sg_req;
+       struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS];
+};
+
 static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
                                   struct fcp_rscn_element *elem)
 {
                }
                _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element);
        }
+       schedule_work(&fsf_req->adapter->scan_work);
 }
 
 static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn)
        zfcp_port_put(port);
        zfcp_erp_port_forced_reopen(port, 0, 65, NULL);
 }
+
+static int zfcp_scan_get_nameserver(struct zfcp_adapter *adapter)
+{
+       int ret;
+
+       if (!adapter->nameserver_port)
+               return -EINTR;
+
+       if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+                              &adapter->nameserver_port->status)) {
+               ret = zfcp_erp_port_reopen(adapter->nameserver_port, 0, 148,
+                                          NULL);
+               if (ret)
+                       return ret;
+               zfcp_erp_wait(adapter);
+               zfcp_port_put(adapter->nameserver_port);
+       }
+       return !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+                                 &adapter->nameserver_port->status);
+}
+
+static void zfcp_gpn_ft_handler(unsigned long _done)
+{
+       complete((struct completion *)_done);
+}
+
+static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft)
+{
+       struct scatterlist *sg = &gpn_ft->sg_req;
+
+       kfree(sg_virt(sg)); /* free request buffer */
+       zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS);
+
+       kfree(gpn_ft);
+}
+
+static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void)
+{
+       struct zfcp_gpn_ft *gpn_ft;
+       struct ct_iu_gpn_ft_req *req;
+
+       gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL);
+       if (!gpn_ft)
+               return NULL;
+
+       req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL);
+       if (!req) {
+               kfree(gpn_ft);
+               gpn_ft = NULL;
+               goto out;
+       }
+       sg_init_one(&gpn_ft->sg_req, req, sizeof(*req));
+
+       if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) {
+               zfcp_free_sg_env(gpn_ft);
+               gpn_ft = NULL;
+       }
+out:
+       return gpn_ft;
+}
+
+
+static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
+                                 struct zfcp_adapter *adapter)
+{
+       struct zfcp_send_ct *ct = &gpn_ft->ct;
+       struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
+       struct completion done;
+       int ret;
+
+       /* prepare CT IU for GPN_FT */
+       req->header.revision = ZFCP_CT_REVISION;
+       req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE;
+       req->header.gs_subtype = ZFCP_CT_NAME_SERVER;
+       req->header.options = ZFCP_CT_SYNCHRONOUS;
+       req->header.cmd_rsp_code = ZFCP_CT_GPN_FT;
+       req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) *
+                                       (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2;
+       req->flags = 0;
+       req->domain_id_scope = 0;
+       req->area_id_scope = 0;
+       req->fc4_type = ZFCP_CT_SCSI_FCP;
+
+       /* prepare zfcp_send_ct */
+       ct->port = adapter->nameserver_port;
+       ct->handler = zfcp_gpn_ft_handler;
+       ct->handler_data = (unsigned long)&done;
+       ct->timeout = 10;
+       ct->req = &gpn_ft->sg_req;
+       ct->resp = gpn_ft->sg_resp;
+       ct->req_count = 1;
+       ct->resp_count = ZFCP_GPN_FT_BUFFERS;
+
+       init_completion(&done);
+       ret = zfcp_fsf_send_ct(ct, NULL, NULL);
+       if (!ret)
+               wait_for_completion(&done);
+       return ret;
+}
+
+static void zfcp_validate_port(struct zfcp_port *port)
+{
+       struct zfcp_adapter *adapter = port->adapter;
+
+       atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status);
+
+       if (port == adapter->nameserver_port)
+               return;
+       if ((port->supported_classes != 0) || (port->units != 0)) {
+               zfcp_port_put(port);
+               return;
+       }
+       zfcp_erp_port_shutdown(port, 0, 151, NULL);
+       zfcp_erp_wait(adapter);
+       zfcp_port_put(port);
+       zfcp_port_dequeue(port);
+}
+
+static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft)
+{
+       struct zfcp_send_ct *ct = &gpn_ft->ct;
+       struct scatterlist *sg = gpn_ft->sg_resp;
+       struct ct_hdr *hdr = sg_virt(sg);
+       struct gpn_ft_resp_acc *acc = sg_virt(sg);
+       struct zfcp_adapter *adapter = ct->port->adapter;
+       struct zfcp_port *port, *tmp;
+       u32 d_id;
+       int ret = 0, x;
+
+       if (ct->status)
+               return -EIO;
+
+       if (hdr->cmd_rsp_code != ZFCP_CT_ACCEPT) {
+               if (hdr->reason_code == ZFCP_CT_UNABLE_TO_PERFORM_CMD)
+                       return -EAGAIN; /* might be a temporary condition */
+               return -EIO;
+       }
+
+       if (hdr->max_res_size)
+               return -E2BIG;
+
+       down(&zfcp_data.config_sema);
+
+       /* first entry is the header */
+       for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES; x++) {
+               if (x % (ZFCP_GPN_FT_ENTRIES + 1))
+                       acc++;
+               else
+                       acc = sg_virt(++sg);
+
+               d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 |
+                      acc->port_id[2];
+
+               /* skip the adapter's port and known remote ports */
+               if (acc->wwpn == fc_host_port_name(adapter->scsi_host) ||
+                    zfcp_get_port_by_did(adapter, d_id))
+                       continue;
+
+               port = zfcp_port_enqueue(adapter, acc->wwpn,
+                                        ZFCP_STATUS_PORT_DID_DID |
+                                        ZFCP_STATUS_COMMON_NOESC, d_id);
+               if (port)
+                       zfcp_erp_port_reopen(port, 0, 149, NULL);
+               else
+                       ret = -ENOMEM;
+               if (acc->control & 0x80) /* last entry */
+                       break;
+       }
+
+       zfcp_erp_wait(adapter);
+       list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list)
+               zfcp_validate_port(port);
+       up(&zfcp_data.config_sema);
+       return ret;
+}
+
+/**
+ * zfcp_scan_ports - scan remote ports and attach new ports
+ * @adapter: pointer to struct zfcp_adapter
+ */
+int zfcp_scan_ports(struct zfcp_adapter *adapter)
+{
+       int ret, i;
+       struct zfcp_gpn_ft *gpn_ft;
+
+       if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT)
+               return 0;
+
+       ret = zfcp_scan_get_nameserver(adapter);
+       if (ret)
+               return ret;
+
+       gpn_ft = zfcp_alloc_sg_env();
+       if (!gpn_ft)
+               return -ENOMEM;
+
+       for (i = 0; i < 3; i++) {
+               ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter);
+               if (!ret) {
+                       ret = zfcp_scan_eval_gpn_ft(gpn_ft);
+                       if (ret == -EAGAIN)
+                               ssleep(1);
+                       else
+                               break;
+               }
+       }
+       zfcp_free_sg_env(gpn_ft);
+
+       return ret;
+}
+
+
+void _zfcp_scan_ports_later(struct work_struct *work)
+{
+       zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work));
+}
 
                if (status_buffer->status_subtype &
                    FSF_STATUS_READ_SUB_ACT_UPDATED)
                        zfcp_erp_adapter_access_changed(adapter, 135, fsf_req);
+               if (status_buffer->status_subtype &
+                   FSF_STATUS_READ_SUB_INCOMING_ELS)
+                       schedule_work(&adapter->scan_work);
                break;
 
        case FSF_STATUS_READ_CFDC_UPDATED:
 
 
 static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store);
 
+/**
+ * zfcp_sysfs_port_rescan - trigger manual port rescan
+ * @dev: pointer to belonging device
+ * @attr: pointer to struct device_attribute
+ * @buf: pointer to input buffer
+ * @count: number of bytes in buffer
+ */
+static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
+                                           struct device_attribute *attr,
+                                           const char *buf, size_t count)
+{
+       struct zfcp_adapter *adapter;
+       int ret;
+
+       adapter = dev_get_drvdata(dev);
+       if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status))
+               return -EBUSY;
+
+       ret = zfcp_scan_ports(adapter);
+
+       return ret ? ret : (ssize_t) count;
+}
+static DEVICE_ATTR(port_rescan, S_IWUSR, NULL, zfcp_sysfs_port_rescan_store);
+
 /**
  * zfcp_sysfs_port_remove_store - remove a port from sysfs tree
  * @dev: pointer to belonging device
        &dev_attr_in_recovery.attr,
        &dev_attr_port_remove.attr,
        &dev_attr_port_add.attr,
+       &dev_attr_port_rescan.attr,
        &dev_attr_peer_wwnn.attr,
        &dev_attr_peer_wwpn.attr,
        &dev_attr_peer_d_id.attr,