]> err.no Git - linux-2.6/blobdiff - drivers/s390/scsi/zfcp_fsf.c
[SCSI] zfcp: Track fabric and channel latencies provided by FCP adapter
[linux-2.6] / drivers / s390 / scsi / zfcp_fsf.c
index b2ea4ea051f582009a9dace7d8f6a77109271f0c..1e7136483c1b24d3a49cfff235109adba06940a2 100644 (file)
@@ -2005,6 +2005,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
                fc_host_supported_classes(shost) =
                                FC_COS_CLASS2 | FC_COS_CLASS3;
                adapter->hydra_version = bottom->adapter_type;
+               adapter->timer_ticks = bottom->timer_interval;
                if (fc_host_permanent_port_name(shost) == -1)
                        fc_host_permanent_port_name(shost) =
                                fc_host_port_name(shost);
@@ -3649,6 +3650,46 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
        return fsf_req;
 }
 
+static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat)
+{
+       lat_rec->sum += lat;
+       if (lat_rec->min > lat)
+               lat_rec->min = lat;
+       if (lat_rec->max < lat)
+               lat_rec->max = lat;
+}
+
+static void zfcp_fsf_req_latency(struct zfcp_fsf_req *fsf_req)
+{
+       struct fsf_qual_latency_info *lat_inf;
+       struct latency_cont *lat;
+       struct zfcp_unit *unit;
+       unsigned long flags;
+
+       lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info;
+       unit = fsf_req->unit;
+
+       switch (fsf_req->qtcb->bottom.io.data_direction) {
+       case FSF_DATADIR_READ:
+               lat = &unit->latencies.read;
+               break;
+       case FSF_DATADIR_WRITE:
+               lat = &unit->latencies.write;
+               break;
+       case FSF_DATADIR_CMND:
+               lat = &unit->latencies.cmd;
+               break;
+       default:
+               return;
+       }
+
+       spin_lock_irqsave(&unit->latencies.lock, flags);
+       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);
+}
+
 /*
  * function:    zfcp_fsf_send_fcp_command_handler
  *
@@ -3922,6 +3963,9 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
                              fcp_rsp_iu->fcp_sns_len);
        }
 
+       if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)
+               zfcp_fsf_req_latency(fsf_req);
+
        /* check FCP_RSP_INFO */
        if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) {
                ZFCP_LOG_DEBUG("rsp_len is valid\n");