diff options
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 8 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 20 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 44 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.h | 11 |
4 files changed, 82 insertions, 1 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 8c7e2b778ef1..d23027a2f2f0 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -847,6 +847,14 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) | |||
847 | /* mark unit unusable as long as sysfs registration is not complete */ | 847 | /* mark unit unusable as long as sysfs registration is not complete */ |
848 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | 848 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); |
849 | 849 | ||
850 | spin_lock_init(&unit->latencies.lock); | ||
851 | unit->latencies.write.channel.min = 0xFFFFFFFF; | ||
852 | unit->latencies.write.fabric.min = 0xFFFFFFFF; | ||
853 | unit->latencies.read.channel.min = 0xFFFFFFFF; | ||
854 | unit->latencies.read.fabric.min = 0xFFFFFFFF; | ||
855 | unit->latencies.cmd.channel.min = 0xFFFFFFFF; | ||
856 | unit->latencies.cmd.fabric.min = 0xFFFFFFFF; | ||
857 | |||
850 | if (device_register(&unit->sysfs_device)) { | 858 | if (device_register(&unit->sysfs_device)) { |
851 | kfree(unit); | 859 | kfree(unit); |
852 | return NULL; | 860 | return NULL; |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index bda8c77b22da..306fcd0cae31 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -708,6 +708,24 @@ struct zfcp_erp_action { | |||
708 | struct timer_list timer; | 708 | struct timer_list timer; |
709 | }; | 709 | }; |
710 | 710 | ||
711 | struct fsf_latency_record { | ||
712 | u32 min; | ||
713 | u32 max; | ||
714 | u64 sum; | ||
715 | }; | ||
716 | |||
717 | struct latency_cont { | ||
718 | struct fsf_latency_record channel; | ||
719 | struct fsf_latency_record fabric; | ||
720 | u64 counter; | ||
721 | }; | ||
722 | |||
723 | struct zfcp_latencies { | ||
724 | struct latency_cont read; | ||
725 | struct latency_cont write; | ||
726 | struct latency_cont cmd; | ||
727 | spinlock_t lock; | ||
728 | }; | ||
711 | 729 | ||
712 | struct zfcp_adapter { | 730 | struct zfcp_adapter { |
713 | struct list_head list; /* list of adapters */ | 731 | struct list_head list; /* list of adapters */ |
@@ -723,6 +741,7 @@ struct zfcp_adapter { | |||
723 | u32 adapter_features; /* FCP channel features */ | 741 | u32 adapter_features; /* FCP channel features */ |
724 | u32 connection_features; /* host connection features */ | 742 | u32 connection_features; /* host connection features */ |
725 | u32 hardware_version; /* of FCP channel */ | 743 | u32 hardware_version; /* of FCP channel */ |
744 | u16 timer_ticks; /* time int for a tick */ | ||
726 | struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ | 745 | struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ |
727 | struct list_head port_list_head; /* remote port list */ | 746 | struct list_head port_list_head; /* remote port list */ |
728 | struct list_head port_remove_lh; /* head of ports to be | 747 | struct list_head port_remove_lh; /* head of ports to be |
@@ -822,6 +841,7 @@ struct zfcp_unit { | |||
822 | struct scsi_device *device; /* scsi device struct pointer */ | 841 | struct scsi_device *device; /* scsi device struct pointer */ |
823 | struct zfcp_erp_action erp_action; /* pending error recovery */ | 842 | struct zfcp_erp_action erp_action; /* pending error recovery */ |
824 | atomic_t erp_counter; | 843 | atomic_t erp_counter; |
844 | struct zfcp_latencies latencies; | ||
825 | }; | 845 | }; |
826 | 846 | ||
827 | /* FSF request */ | 847 | /* FSF request */ |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index b2ea4ea051f5..1e7136483c1b 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -2005,6 +2005,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) | |||
2005 | fc_host_supported_classes(shost) = | 2005 | fc_host_supported_classes(shost) = |
2006 | FC_COS_CLASS2 | FC_COS_CLASS3; | 2006 | FC_COS_CLASS2 | FC_COS_CLASS3; |
2007 | adapter->hydra_version = bottom->adapter_type; | 2007 | adapter->hydra_version = bottom->adapter_type; |
2008 | adapter->timer_ticks = bottom->timer_interval; | ||
2008 | if (fc_host_permanent_port_name(shost) == -1) | 2009 | if (fc_host_permanent_port_name(shost) == -1) |
2009 | fc_host_permanent_port_name(shost) = | 2010 | fc_host_permanent_port_name(shost) = |
2010 | fc_host_port_name(shost); | 2011 | fc_host_port_name(shost); |
@@ -3649,6 +3650,46 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, | |||
3649 | return fsf_req; | 3650 | return fsf_req; |
3650 | } | 3651 | } |
3651 | 3652 | ||
3653 | static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat) | ||
3654 | { | ||
3655 | lat_rec->sum += lat; | ||
3656 | if (lat_rec->min > lat) | ||
3657 | lat_rec->min = lat; | ||
3658 | if (lat_rec->max < lat) | ||
3659 | lat_rec->max = lat; | ||
3660 | } | ||
3661 | |||
3662 | static void zfcp_fsf_req_latency(struct zfcp_fsf_req *fsf_req) | ||
3663 | { | ||
3664 | struct fsf_qual_latency_info *lat_inf; | ||
3665 | struct latency_cont *lat; | ||
3666 | struct zfcp_unit *unit; | ||
3667 | unsigned long flags; | ||
3668 | |||
3669 | lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info; | ||
3670 | unit = fsf_req->unit; | ||
3671 | |||
3672 | switch (fsf_req->qtcb->bottom.io.data_direction) { | ||
3673 | case FSF_DATADIR_READ: | ||
3674 | lat = &unit->latencies.read; | ||
3675 | break; | ||
3676 | case FSF_DATADIR_WRITE: | ||
3677 | lat = &unit->latencies.write; | ||
3678 | break; | ||
3679 | case FSF_DATADIR_CMND: | ||
3680 | lat = &unit->latencies.cmd; | ||
3681 | break; | ||
3682 | default: | ||
3683 | return; | ||
3684 | } | ||
3685 | |||
3686 | spin_lock_irqsave(&unit->latencies.lock, flags); | ||
3687 | zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat); | ||
3688 | zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat); | ||
3689 | lat->counter++; | ||
3690 | spin_unlock_irqrestore(&unit->latencies.lock, flags); | ||
3691 | } | ||
3692 | |||
3652 | /* | 3693 | /* |
3653 | * function: zfcp_fsf_send_fcp_command_handler | 3694 | * function: zfcp_fsf_send_fcp_command_handler |
3654 | * | 3695 | * |
@@ -3922,6 +3963,9 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) | |||
3922 | fcp_rsp_iu->fcp_sns_len); | 3963 | fcp_rsp_iu->fcp_sns_len); |
3923 | } | 3964 | } |
3924 | 3965 | ||
3966 | if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) | ||
3967 | zfcp_fsf_req_latency(fsf_req); | ||
3968 | |||
3925 | /* check FCP_RSP_INFO */ | 3969 | /* check FCP_RSP_INFO */ |
3926 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { | 3970 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { |
3927 | ZFCP_LOG_DEBUG("rsp_len is valid\n"); | 3971 | ZFCP_LOG_DEBUG("rsp_len is valid\n"); |
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 099970b27001..8b1a7d9c840f 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h | |||
@@ -323,11 +323,18 @@ struct fsf_link_down_info { | |||
323 | u8 vendor_specific_code; | 323 | u8 vendor_specific_code; |
324 | } __attribute__ ((packed)); | 324 | } __attribute__ ((packed)); |
325 | 325 | ||
326 | struct fsf_qual_latency_info { | ||
327 | u32 channel_lat; | ||
328 | u32 fabric_lat; | ||
329 | u8 res1[8]; | ||
330 | } __attribute__ ((packed)); | ||
331 | |||
326 | union fsf_prot_status_qual { | 332 | union fsf_prot_status_qual { |
327 | u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)]; | 333 | u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)]; |
328 | struct fsf_qual_version_error version_error; | 334 | struct fsf_qual_version_error version_error; |
329 | struct fsf_qual_sequence_error sequence_error; | 335 | struct fsf_qual_sequence_error sequence_error; |
330 | struct fsf_link_down_info link_down_info; | 336 | struct fsf_link_down_info link_down_info; |
337 | struct fsf_qual_latency_info latency_info; | ||
331 | } __attribute__ ((packed)); | 338 | } __attribute__ ((packed)); |
332 | 339 | ||
333 | struct fsf_qtcb_prefix { | 340 | struct fsf_qtcb_prefix { |
@@ -437,7 +444,9 @@ struct fsf_qtcb_bottom_config { | |||
437 | u32 fc_link_speed; | 444 | u32 fc_link_speed; |
438 | u32 adapter_type; | 445 | u32 adapter_type; |
439 | u32 peer_d_id; | 446 | u32 peer_d_id; |
440 | u8 res2[12]; | 447 | u8 res1[2]; |
448 | u16 timer_interval; | ||
449 | u8 res2[8]; | ||
441 | u32 s_id; | 450 | u32 s_id; |
442 | struct fsf_nport_serv_param nport_serv_param; | 451 | struct fsf_nport_serv_param nport_serv_param; |
443 | u8 reserved_nport_serv_param[16]; | 452 | u8 reserved_nport_serv_param[16]; |