]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/s390/scsi/zfcp_fc.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
[mirror_ubuntu-bionic-kernel.git] / drivers / s390 / scsi / zfcp_fc.c
index eabdfe24456e4056585769bf09fbe4d4af7e849f..e8d032b9dfbd2a54668658a88db23b7ef76e4364 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Fibre Channel related functions for the zfcp device driver.
  *
- * Copyright IBM Corporation 2008
+ * Copyright IBM Corporation 2008, 2009
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -94,12 +94,16 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
 
 static void zfcp_wka_port_offline(struct work_struct *work)
 {
-       struct delayed_work *dw = container_of(work, struct delayed_work, work);
+       struct delayed_work *dw = to_delayed_work(work);
        struct zfcp_wka_port *wka_port =
                        container_of(dw, struct zfcp_wka_port, work);
 
-       wait_event(wka_port->completion_wq,
-                       atomic_read(&wka_port->refcount) == 0);
+       /* Don't wait forvever. If the wka_port is too busy take it offline
+          through a new call later */
+       if (!wait_event_timeout(wka_port->completion_wq,
+                               atomic_read(&wka_port->refcount) == 0,
+                               HZ >> 1))
+               return;
 
        mutex_lock(&wka_port->mutex);
        if ((atomic_read(&wka_port->refcount) != 0) ||
@@ -145,16 +149,10 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
        struct zfcp_port *port;
 
        read_lock_irqsave(&zfcp_data.config_lock, flags);
-       list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) {
-               if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_PHYS_OPEN))
-                       /* Try to connect to unused ports anyway. */
-                       zfcp_erp_port_reopen(port,
-                                            ZFCP_STATUS_COMMON_ERP_FAILED,
-                                            82, fsf_req);
-               else if ((port->d_id & range) == (elem->nport_did & range))
-                       /* Check connection status for connected ports */
+       list_for_each_entry(port, &fsf_req->adapter->port_list_head, list)
+               if ((port->d_id & range) == (elem->nport_did & range))
                        zfcp_test_link(port);
-       }
+
        read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
@@ -196,7 +194,7 @@ static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)
        read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 
        if (port && (port->wwpn == wwpn))
-               zfcp_erp_port_forced_reopen(port, 0, 83, req);
+               zfcp_erp_port_forced_reopen(port, 0, "fciwwp1", req);
 }
 
 static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req)
@@ -259,10 +257,9 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data)
 
        if (ct->status)
                return;
-       if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) {
-               atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
+       if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT)
                return;
-       }
+
        /* paranoia */
        if (ct_iu_req->wwpn != port->wwpn)
                return;
@@ -375,16 +372,22 @@ static void zfcp_fc_adisc_handler(unsigned long data)
 
        if (adisc->els.status) {
                /* request rejected or timed out */
-               zfcp_erp_port_forced_reopen(port, 0, 63, NULL);
+               zfcp_erp_port_forced_reopen(port, 0, "fcadh_1", NULL);
                goto out;
        }
 
        if (!port->wwnn)
                port->wwnn = ls_adisc->wwnn;
 
-       if (port->wwpn != ls_adisc->wwpn)
-               zfcp_erp_port_reopen(port, 0, 64, NULL);
+       if ((port->wwpn != ls_adisc->wwpn) ||
+           !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) {
+               zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
+                                    "fcadh_2", NULL);
+               goto out;
+       }
 
+       /* port is good, unblock rport without going through erp */
+       zfcp_scsi_schedule_rport_register(port);
  out:
        zfcp_port_put(port);
        kfree(adisc);
@@ -422,6 +425,31 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
        return zfcp_fsf_send_els(&adisc->els);
 }
 
+void zfcp_fc_link_test_work(struct work_struct *work)
+{
+       struct zfcp_port *port =
+               container_of(work, struct zfcp_port, test_link_work);
+       int retval;
+
+       if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_UNBLOCKED)) {
+               zfcp_port_put(port);
+               return; /* port erp is running and will update rport status */
+       }
+
+       zfcp_port_get(port);
+       port->rport_task = RPORT_DEL;
+       zfcp_scsi_rport_work(&port->rport_work);
+
+       retval = zfcp_fc_adisc(port);
+       if (retval == 0)
+               return;
+
+       /* send of ADISC was not possible */
+       zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
+
+       zfcp_port_put(port);
+}
+
 /**
  * zfcp_test_link - lightweight link test procedure
  * @port: port to be tested
@@ -432,17 +460,9 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
  */
 void zfcp_test_link(struct zfcp_port *port)
 {
-       int retval;
-
        zfcp_port_get(port);
-       retval = zfcp_fc_adisc(port);
-       if (retval == 0)
-               return;
-
-       /* send of ADISC was not possible */
-       zfcp_port_put(port);
-       if (retval != -EBUSY)
-               zfcp_erp_port_forced_reopen(port, 0, 65, NULL);
+       if (!queue_work(zfcp_data.work_queue, &port->test_link_work))
+               zfcp_port_put(port);
 }
 
 static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num)
@@ -529,7 +549,7 @@ static void zfcp_validate_port(struct zfcp_port *port)
                zfcp_port_put(port);
                return;
        }
-       zfcp_erp_port_shutdown(port, 0, 151, NULL);
+       zfcp_erp_port_shutdown(port, 0, "fcpval1", NULL);
        zfcp_erp_wait(adapter);
        zfcp_port_put(port);
        zfcp_port_dequeue(port);
@@ -592,7 +612,7 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
                if (IS_ERR(port))
                        ret = PTR_ERR(port);
                else
-                       zfcp_erp_port_reopen(port, 0, 149, NULL);
+                       zfcp_erp_port_reopen(port, 0, "fcegpf1", NULL);
        }
 
        zfcp_erp_wait(adapter);