[SCSI] zfcp: Simplify latency lock handling
[linux-2.6-block.git] / drivers / s390 / scsi / zfcp_fsf.c
index dc0367690405e864538d33b0d96f088b0047e80a..cce698114b0b723f23c9f561e90de3c8134afbc8 100644 (file)
@@ -6,6 +6,9 @@
  * Copyright IBM Corporation 2002, 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/blktrace_api.h>
 #include "zfcp_ext.h"
 
@@ -641,38 +644,38 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
        }
 }
 
-static int zfcp_fsf_sbal_check(struct zfcp_adapter *adapter)
+static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter)
 {
-       struct zfcp_qdio_queue *req_q = &adapter->req_q;
-
-       spin_lock_bh(&adapter->req_q_lock);
-       if (atomic_read(&req_q->count))
+       if (atomic_read(&adapter->req_q.count) > 0)
                return 1;
-       spin_unlock_bh(&adapter->req_q_lock);
+       atomic_inc(&adapter->qdio_outb_full);
        return 0;
 }
 
-static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter)
-{
-       unsigned int count = atomic_read(&adapter->req_q.count);
-       if (!count)
-               atomic_inc(&adapter->qdio_outb_full);
-       return count > 0;
-}
-
 static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
+       __releases(&adapter->req_q_lock)
+       __acquires(&adapter->req_q_lock)
 {
+       struct zfcp_qdio_queue *req_q = &adapter->req_q;
        long ret;
 
+       if (atomic_read(&req_q->count) <= -REQUEST_LIST_SIZE)
+               return -EIO;
+       if (atomic_read(&req_q->count) > 0)
+               return 0;
+
+       atomic_dec(&req_q->count);
        spin_unlock_bh(&adapter->req_q_lock);
        ret = wait_event_interruptible_timeout(adapter->request_wq,
-                                       zfcp_fsf_sbal_check(adapter), 5 * HZ);
+                                       atomic_read(&req_q->count) >= 0,
+                                       5 * HZ);
+       spin_lock_bh(&adapter->req_q_lock);
+       atomic_inc(&req_q->count);
+
        if (ret > 0)
                return 0;
        if (!ret)
                atomic_inc(&adapter->qdio_outb_full);
-
-       spin_lock_bh(&adapter->req_q_lock);
        return -EIO;
 }
 
@@ -1010,12 +1013,29 @@ skip_fsfstatus:
                send_ct->handler(send_ct->handler_data);
 }
 
-static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req,
-                               struct scatterlist *sg_req,
-                               struct scatterlist *sg_resp, int max_sbals)
+static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
+                                      struct scatterlist *sg_req,
+                                      struct scatterlist *sg_resp,
+                                      int max_sbals)
 {
+       struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(req);
+       u32 feat = req->adapter->adapter_features;
        int bytes;
 
+       if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
+               if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE ||
+                   !sg_is_last(sg_req) || !sg_is_last(sg_resp))
+                       return -EOPNOTSUPP;
+
+               sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
+               sbale[2].addr   = sg_virt(sg_req);
+               sbale[2].length = sg_req->length;
+               sbale[3].addr   = sg_virt(sg_resp);
+               sbale[3].length = sg_resp->length;
+               sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+               return 0;
+       }
+
        bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
                                        sg_req, max_sbals);
        if (bytes <= 0)
@@ -1057,8 +1077,8 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
                goto out;
        }
 
-       ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp,
-                                  FSF_MAX_SBALS_PER_REQ);
+       ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp,
+                                         FSF_MAX_SBALS_PER_REQ);
        if (ret)
                goto failed_send;
 
@@ -1168,7 +1188,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els)
                goto out;
        }
 
-       ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2);
+       ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2);
 
        if (ret)
                goto failed_send;
@@ -1403,13 +1423,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
                switch (header->fsf_status_qual.word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
-                       req->status |= ZFCP_STATUS_FSFREQ_ERROR;
-                       break;
                case FSF_SQ_NO_RETRY_POSSIBLE:
-                       dev_warn(&req->adapter->ccw_device->dev,
-                                "Remote port 0x%016Lx could not be opened\n",
-                                (unsigned long long)port->wwpn);
-                       zfcp_erp_port_failed(port, 32, req);
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
                }
@@ -1437,10 +1451,10 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
                 * Alternately, an ADISC/PDISC ELS should suffice, as well.
                 */
                plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
-               if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) {
+               if (req->qtcb->bottom.support.els1_length >=
+                   FSF_PLOGI_MIN_LEN) {
                        if (plogi->serv_param.wwpn != port->wwpn)
-                               atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID,
-                                                 &port->status);
+                               port->d_id = 0;
                        else {
                                port->wwnn = plogi->serv_param.wwnn;
                                zfcp_fc_plogi_evaluate(port, plogi);
@@ -1698,7 +1712,7 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
        struct zfcp_unit *unit;
 
        if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
-               goto skip_fsfstatus;
+               return;
 
        switch (header->fsf_status) {
        case FSF_PORT_HANDLE_NOT_VALID:
@@ -1738,8 +1752,6 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
                                          &unit->status);
                break;
        }
-skip_fsfstatus:
-       atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status);
 }
 
 /**
@@ -1775,8 +1787,6 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
        req->erp_action = erp_action;
        req->handler = zfcp_fsf_close_physical_port_handler;
        erp_action->fsf_req = req;
-       atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
-                       &erp_action->port->status);
 
        zfcp_fsf_start_erp_timer(req);
        retval = zfcp_fsf_req_send(req);
@@ -1904,7 +1914,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
                                dev_err(&adapter->ccw_device->dev,
                                        "Shared read-write access not "
                                        "supported (unit 0x%016Lx, port "
-                                       "0x%016Lx\n)",
+                                       "0x%016Lx)\n",
                                        (unsigned long long)unit->fcp_lun,
                                        (unsigned long long)unit->port->wwpn);
                                zfcp_erp_unit_failed(unit, 36, req);
@@ -2059,7 +2069,6 @@ static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
        struct fsf_qual_latency_info *lat_inf;
        struct latency_cont *lat;
        struct zfcp_unit *unit = req->unit;
-       unsigned long flags;
 
        lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info;
 
@@ -2077,11 +2086,11 @@ static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req)
                return;
        }
 
-       spin_lock_irqsave(&unit->latencies.lock, flags);
+       spin_lock(&unit->latencies.lock);
        zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat);
        zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat);
        lat->counter++;
-       spin_unlock_irqrestore(&unit->latencies.lock, flags);
+       spin_unlock(&unit->latencies.lock);
 }
 
 #ifdef CONFIG_BLK_DEV_IO_TRACE
@@ -2133,7 +2142,6 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
 
        if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) {
                set_host_byte(scpnt, DID_SOFT_ERROR);
-               set_driver_byte(scpnt, SUGGEST_RETRY);
                goto skip_fsfstatus;
        }