diff options
author | Lalit Chandivade <lalit.chandivade@qlogic.com> | 2013-11-22 05:28:18 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-12-19 23:56:25 -0500 |
commit | 6fa7c554386d391d1d0f46bc298e57d2eda76e78 (patch) | |
tree | 01d32a0e0c5bc5660bc0a48079f42b9c3aec02e1 | |
parent | df86f771578209599acc871a03f02346c8d7885b (diff) |
[SCSI] scsi_transport_iscsi: Add host statistics support
Add transport_iscsi hooks to get aggregate host statistics.
The statistics include MAC, TCP/IP & iSCSI statistics.
Signed-off-by: Lalit Chandivade <lalit.chandivade@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 70 | ||||
-rw-r--r-- | include/scsi/iscsi_if.h | 112 | ||||
-rw-r--r-- | include/scsi/scsi_transport_iscsi.h | 1 |
3 files changed, 183 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 9477f84c83a6..4cf918a9fc6f 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -3416,6 +3416,73 @@ exit_logout_sid: | |||
3416 | } | 3416 | } |
3417 | 3417 | ||
3418 | static int | 3418 | static int |
3419 | iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) | ||
3420 | { | ||
3421 | struct iscsi_uevent *ev = nlmsg_data(nlh); | ||
3422 | struct Scsi_Host *shost = NULL; | ||
3423 | struct iscsi_internal *priv; | ||
3424 | struct sk_buff *skbhost_stats; | ||
3425 | struct nlmsghdr *nlhhost_stats; | ||
3426 | struct iscsi_uevent *evhost_stats; | ||
3427 | int host_stats_size = 0; | ||
3428 | int len, err = 0; | ||
3429 | char *buf; | ||
3430 | |||
3431 | if (!transport->get_host_stats) | ||
3432 | return -EINVAL; | ||
3433 | |||
3434 | priv = iscsi_if_transport_lookup(transport); | ||
3435 | if (!priv) | ||
3436 | return -EINVAL; | ||
3437 | |||
3438 | host_stats_size = sizeof(struct iscsi_offload_host_stats); | ||
3439 | len = nlmsg_total_size(sizeof(*ev) + host_stats_size); | ||
3440 | |||
3441 | shost = scsi_host_lookup(ev->u.get_host_stats.host_no); | ||
3442 | if (!shost) { | ||
3443 | pr_err("%s: failed. Cound not find host no %u\n", | ||
3444 | __func__, ev->u.get_host_stats.host_no); | ||
3445 | return -ENODEV; | ||
3446 | } | ||
3447 | |||
3448 | do { | ||
3449 | int actual_size; | ||
3450 | |||
3451 | skbhost_stats = alloc_skb(len, GFP_KERNEL); | ||
3452 | if (!skbhost_stats) { | ||
3453 | pr_err("cannot deliver host stats: OOM\n"); | ||
3454 | err = -ENOMEM; | ||
3455 | goto exit_host_stats; | ||
3456 | } | ||
3457 | |||
3458 | nlhhost_stats = __nlmsg_put(skbhost_stats, 0, 0, 0, | ||
3459 | (len - sizeof(*nlhhost_stats)), 0); | ||
3460 | evhost_stats = nlmsg_data(nlhhost_stats); | ||
3461 | memset(evhost_stats, 0, sizeof(*evhost_stats)); | ||
3462 | evhost_stats->transport_handle = iscsi_handle(transport); | ||
3463 | evhost_stats->type = nlh->nlmsg_type; | ||
3464 | evhost_stats->u.get_host_stats.host_no = | ||
3465 | ev->u.get_host_stats.host_no; | ||
3466 | buf = (char *)((char *)evhost_stats + sizeof(*evhost_stats)); | ||
3467 | memset(buf, 0, host_stats_size); | ||
3468 | |||
3469 | err = transport->get_host_stats(shost, buf, host_stats_size); | ||
3470 | |||
3471 | actual_size = nlmsg_total_size(sizeof(*ev) + host_stats_size); | ||
3472 | skb_trim(skbhost_stats, NLMSG_ALIGN(actual_size)); | ||
3473 | nlhhost_stats->nlmsg_len = actual_size; | ||
3474 | |||
3475 | err = iscsi_multicast_skb(skbhost_stats, ISCSI_NL_GRP_ISCSID, | ||
3476 | GFP_KERNEL); | ||
3477 | } while (err < 0 && err != -ECONNREFUSED); | ||
3478 | |||
3479 | exit_host_stats: | ||
3480 | scsi_host_put(shost); | ||
3481 | return err; | ||
3482 | } | ||
3483 | |||
3484 | |||
3485 | static int | ||
3419 | iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) | 3486 | iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) |
3420 | { | 3487 | { |
3421 | int err = 0; | 3488 | int err = 0; |
@@ -3594,6 +3661,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) | |||
3594 | err = iscsi_set_chap(transport, ev, | 3661 | err = iscsi_set_chap(transport, ev, |
3595 | nlmsg_attrlen(nlh, sizeof(*ev))); | 3662 | nlmsg_attrlen(nlh, sizeof(*ev))); |
3596 | break; | 3663 | break; |
3664 | case ISCSI_UEVENT_GET_HOST_STATS: | ||
3665 | err = iscsi_get_host_stats(transport, nlh); | ||
3666 | break; | ||
3597 | default: | 3667 | default: |
3598 | err = -ENOSYS; | 3668 | err = -ENOSYS; |
3599 | break; | 3669 | break; |
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index a572083c77cb..3851a737c429 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h | |||
@@ -70,6 +70,7 @@ enum iscsi_uevent_e { | |||
70 | ISCSI_UEVENT_LOGOUT_FLASHNODE = UEVENT_BASE + 29, | 70 | ISCSI_UEVENT_LOGOUT_FLASHNODE = UEVENT_BASE + 29, |
71 | ISCSI_UEVENT_LOGOUT_FLASHNODE_SID = UEVENT_BASE + 30, | 71 | ISCSI_UEVENT_LOGOUT_FLASHNODE_SID = UEVENT_BASE + 30, |
72 | ISCSI_UEVENT_SET_CHAP = UEVENT_BASE + 31, | 72 | ISCSI_UEVENT_SET_CHAP = UEVENT_BASE + 31, |
73 | ISCSI_UEVENT_GET_HOST_STATS = UEVENT_BASE + 32, | ||
73 | 74 | ||
74 | /* up events */ | 75 | /* up events */ |
75 | ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, | 76 | ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, |
@@ -242,6 +243,9 @@ struct iscsi_uevent { | |||
242 | uint32_t host_no; | 243 | uint32_t host_no; |
243 | uint32_t sid; | 244 | uint32_t sid; |
244 | } logout_flashnode_sid; | 245 | } logout_flashnode_sid; |
246 | struct msg_get_host_stats { | ||
247 | uint32_t host_no; | ||
248 | } get_host_stats; | ||
245 | } u; | 249 | } u; |
246 | union { | 250 | union { |
247 | /* messages k -> u */ | 251 | /* messages k -> u */ |
@@ -845,4 +849,112 @@ struct iscsi_chap_rec { | |||
845 | uint8_t password_length; | 849 | uint8_t password_length; |
846 | }; | 850 | }; |
847 | 851 | ||
852 | #define ISCSI_HOST_STATS_CUSTOM_MAX 32 | ||
853 | #define ISCSI_HOST_STATS_CUSTOM_DESC_MAX 64 | ||
854 | struct iscsi_host_stats_custom { | ||
855 | char desc[ISCSI_HOST_STATS_CUSTOM_DESC_MAX]; | ||
856 | uint64_t value; | ||
857 | }; | ||
858 | |||
859 | /* struct iscsi_offload_host_stats: Host statistics, | ||
860 | * Include statistics for MAC, IP, TCP & iSCSI. | ||
861 | */ | ||
862 | struct iscsi_offload_host_stats { | ||
863 | /* MAC */ | ||
864 | uint64_t mactx_frames; | ||
865 | uint64_t mactx_bytes; | ||
866 | uint64_t mactx_multicast_frames; | ||
867 | uint64_t mactx_broadcast_frames; | ||
868 | uint64_t mactx_pause_frames; | ||
869 | uint64_t mactx_control_frames; | ||
870 | uint64_t mactx_deferral; | ||
871 | uint64_t mactx_excess_deferral; | ||
872 | uint64_t mactx_late_collision; | ||
873 | uint64_t mactx_abort; | ||
874 | uint64_t mactx_single_collision; | ||
875 | uint64_t mactx_multiple_collision; | ||
876 | uint64_t mactx_collision; | ||
877 | uint64_t mactx_frames_dropped; | ||
878 | uint64_t mactx_jumbo_frames; | ||
879 | uint64_t macrx_frames; | ||
880 | uint64_t macrx_bytes; | ||
881 | uint64_t macrx_unknown_control_frames; | ||
882 | uint64_t macrx_pause_frames; | ||
883 | uint64_t macrx_control_frames; | ||
884 | uint64_t macrx_dribble; | ||
885 | uint64_t macrx_frame_length_error; | ||
886 | uint64_t macrx_jabber; | ||
887 | uint64_t macrx_carrier_sense_error; | ||
888 | uint64_t macrx_frame_discarded; | ||
889 | uint64_t macrx_frames_dropped; | ||
890 | uint64_t mac_crc_error; | ||
891 | uint64_t mac_encoding_error; | ||
892 | uint64_t macrx_length_error_large; | ||
893 | uint64_t macrx_length_error_small; | ||
894 | uint64_t macrx_multicast_frames; | ||
895 | uint64_t macrx_broadcast_frames; | ||
896 | /* IP */ | ||
897 | uint64_t iptx_packets; | ||
898 | uint64_t iptx_bytes; | ||
899 | uint64_t iptx_fragments; | ||
900 | uint64_t iprx_packets; | ||
901 | uint64_t iprx_bytes; | ||
902 | uint64_t iprx_fragments; | ||
903 | uint64_t ip_datagram_reassembly; | ||
904 | uint64_t ip_invalid_address_error; | ||
905 | uint64_t ip_error_packets; | ||
906 | uint64_t ip_fragrx_overlap; | ||
907 | uint64_t ip_fragrx_outoforder; | ||
908 | uint64_t ip_datagram_reassembly_timeout; | ||
909 | uint64_t ipv6tx_packets; | ||
910 | uint64_t ipv6tx_bytes; | ||
911 | uint64_t ipv6tx_fragments; | ||
912 | uint64_t ipv6rx_packets; | ||
913 | uint64_t ipv6rx_bytes; | ||
914 | uint64_t ipv6rx_fragments; | ||
915 | uint64_t ipv6_datagram_reassembly; | ||
916 | uint64_t ipv6_invalid_address_error; | ||
917 | uint64_t ipv6_error_packets; | ||
918 | uint64_t ipv6_fragrx_overlap; | ||
919 | uint64_t ipv6_fragrx_outoforder; | ||
920 | uint64_t ipv6_datagram_reassembly_timeout; | ||
921 | /* TCP */ | ||
922 | uint64_t tcptx_segments; | ||
923 | uint64_t tcptx_bytes; | ||
924 | uint64_t tcprx_segments; | ||
925 | uint64_t tcprx_byte; | ||
926 | uint64_t tcp_duplicate_ack_retx; | ||
927 | uint64_t tcp_retx_timer_expired; | ||
928 | uint64_t tcprx_duplicate_ack; | ||
929 | uint64_t tcprx_pure_ackr; | ||
930 | uint64_t tcptx_delayed_ack; | ||
931 | uint64_t tcptx_pure_ack; | ||
932 | uint64_t tcprx_segment_error; | ||
933 | uint64_t tcprx_segment_outoforder; | ||
934 | uint64_t tcprx_window_probe; | ||
935 | uint64_t tcprx_window_update; | ||
936 | uint64_t tcptx_window_probe_persist; | ||
937 | /* ECC */ | ||
938 | uint64_t ecc_error_correction; | ||
939 | /* iSCSI */ | ||
940 | uint64_t iscsi_pdu_tx; | ||
941 | uint64_t iscsi_data_bytes_tx; | ||
942 | uint64_t iscsi_pdu_rx; | ||
943 | uint64_t iscsi_data_bytes_rx; | ||
944 | uint64_t iscsi_io_completed; | ||
945 | uint64_t iscsi_unexpected_io_rx; | ||
946 | uint64_t iscsi_format_error; | ||
947 | uint64_t iscsi_hdr_digest_error; | ||
948 | uint64_t iscsi_data_digest_error; | ||
949 | uint64_t iscsi_sequence_error; | ||
950 | /* | ||
951 | * iSCSI Custom Host Statistics support, i.e. Transport could | ||
952 | * extend existing host statistics with its own specific statistics | ||
953 | * up to ISCSI_HOST_STATS_CUSTOM_MAX | ||
954 | */ | ||
955 | uint32_t custom_length; | ||
956 | struct iscsi_host_stats_custom custom[0] | ||
957 | __aligned(sizeof(uint64_t)); | ||
958 | }; | ||
959 | |||
848 | #endif | 960 | #endif |
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 2ac11feab6f3..88640a47216c 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h | |||
@@ -166,6 +166,7 @@ struct iscsi_transport { | |||
166 | int (*logout_flashnode) (struct iscsi_bus_flash_session *fnode_sess, | 166 | int (*logout_flashnode) (struct iscsi_bus_flash_session *fnode_sess, |
167 | struct iscsi_bus_flash_conn *fnode_conn); | 167 | struct iscsi_bus_flash_conn *fnode_conn); |
168 | int (*logout_flashnode_sid) (struct iscsi_cls_session *cls_sess); | 168 | int (*logout_flashnode_sid) (struct iscsi_cls_session *cls_sess); |
169 | int (*get_host_stats) (struct Scsi_Host *shost, char *buf, int len); | ||
169 | }; | 170 | }; |
170 | 171 | ||
171 | /* | 172 | /* |