Fix compilation error:
[obnox/wireshark/wip.git] / tap-scsistat.c
1 /* tap-scsistat.c       2010 Chris Costa and Cal Turney
2  *
3  * $Id$
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <stdio.h>
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #include <string.h>
35 #include <epan/packet_info.h>
36 #include <epan/epan.h>
37 #include <epan/stat_cmd_args.h>
38 #include <epan/tap.h>
39 #include <epan/conversation.h>
40 #include <epan/dissectors/packet-scsi.h>
41 #include <epan/dissectors/packet-fc.h>
42 #include <epan/dissectors/packet-scsi-sbc.h>
43 #include <epan/dissectors/packet-scsi-ssc.h>
44 #include <epan/dissectors/packet-scsi-smc.h>
45 #include <epan/dissectors/packet-scsi-osd.h>
46
47 static guint8 scsi_program=0;
48
49 /* used to keep track of statistics for a specific procedure */
50 typedef struct _scsi_procedure_t {
51         const char *proc;
52         int num;
53         nstime_t min;
54         nstime_t max;
55         nstime_t tot;
56 } scsi_procedure_t;
57
58 /* used to keep track of the statistics for an entire program interface */
59 typedef struct _scsistat_t {
60         guint8 cmdset;
61         char *filter;
62         const value_string *cdbnames;
63         const char *prog;
64 #define MAX_PROCEDURES 256
65         scsi_procedure_t *procedures;
66 } scsistat_t;
67
68 #define NANOSECS_PER_SEC 1000000000
69
70 static void
71 scsistat_reset(void *prs)
72 {
73         scsistat_t *rs=prs;
74         guint32 i;
75
76         for(i=0; i < MAX_PROCEDURES; i++) {
77                 rs->procedures[i].num=0;
78                 rs->procedures[i].min.secs=0;
79                 rs->procedures[i].min.nsecs=0;
80                 rs->procedures[i].max.secs=0;
81                 rs->procedures[i].max.nsecs=0;
82                 rs->procedures[i].tot.secs=0;
83                 rs->procedures[i].tot.nsecs=0;
84         }
85 }
86
87 static int
88 scsistat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
89 {
90         scsistat_t *rs = prs;
91         const scsi_task_data_t *ri = pri;
92         nstime_t delta;
93         scsi_procedure_t *rp;
94
95         /* we are only interested in response packets */
96         if(ri->type!=SCSI_PDU_TYPE_RSP) {
97                 return 0;
98         }
99         /* we are only interested in a specific commandset */
100         if( (!ri->itl) || ((ri->itl->cmdset&SCSI_CMDSET_MASK)!=rs->cmdset) ) {
101                 return 0;
102         }
103         /* check that the opcode looks sane */
104         if( (!ri->itlq) || (ri->itlq->scsi_opcode > 255) ) {
105                 return 0;
106         }
107
108         rp=&(rs->procedures[ri->itlq->scsi_opcode]);
109
110         /* calculate time delta between request and reply */
111         nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->itlq->fc_time);
112
113         if(rp->num==0) {
114                 rp->max.secs=delta.secs;
115                 rp->max.nsecs=delta.nsecs;
116         }
117         if(rp->num==0) {
118                 rp->min.secs= delta.secs;
119                 rp->min.nsecs=delta.nsecs;
120         }
121         if( (delta.secs  < rp->min.secs)
122         ||( (delta.secs == rp->min.secs)
123           &&(delta.nsecs < rp->min.nsecs) ) ) {
124                 rp->min.secs = delta.secs;
125                 rp->min.nsecs= delta.nsecs;
126         }
127         if( (delta.secs  > rp->max.secs)
128         ||( (delta.secs == rp->max.secs)
129           &&(delta.nsecs > rp->max.nsecs) ) ) {
130                 rp->max.secs = delta.secs;
131                 rp->max.nsecs= delta.nsecs;
132         }
133         rp->tot.secs  += delta.secs;
134         rp->tot.nsecs += delta.nsecs;
135         if(rp->tot.nsecs > NANOSECS_PER_SEC) {
136                 rp->tot.nsecs -= NANOSECS_PER_SEC;
137                 rp->tot.secs++;
138         }
139         rp->num++;
140         return 1;
141 }
142
143 static void
144 scsistat_draw(void *prs)
145 {
146         scsistat_t *rs=prs;
147         guint32 i;
148         guint64 td;
149
150         printf("\n");
151         printf("===========================================================\n");
152         printf("SCSI %s SRT Statistics:\n", rs->prog);
153         printf("Filter: %s\n", rs->filter?rs->filter:"");
154         printf("Procedure            Calls   Min SRT    Max SRT    Avg SRT\n");
155         for(i=0; i < MAX_PROCEDURES; i++) {
156                 if(rs->procedures[i].num==0) {
157                         continue;
158                 }
159                 /* scale it to units of 1us.*/
160                 td = ((guint64)(rs->procedures[i].tot.secs)) * NANOSECS_PER_SEC + rs->procedures[i].tot.nsecs;
161                 td = ((td / rs->procedures[i].num) + 500) / 1000;
162
163                 printf("%-19s %6d %3d.%06u %3d.%06u %3d.%06u \n",
164                         rs->procedures[i].proc,
165                         rs->procedures[i].num,
166                         (int)(rs->procedures[i].min.secs),
167                         (rs->procedures[i].min.nsecs+500)/1000,
168                         (int)(rs->procedures[i].max.secs),
169                         (rs->procedures[i].max.nsecs+500)/1000,
170                         (int)(td/1000000), (int)(td%1000000)
171                 );
172         }
173         printf("===========================================================\n");
174 }
175
176 static void
177 scsistat_init(const char *optarg, void* userdata _U_)
178 {
179         scsistat_t *rs;
180         guint32 i;
181         int program, pos;
182         const char *filter=NULL;
183         GString *error_string;
184
185         pos=0;
186         if(sscanf(optarg, "scsi,srt,%d,%n", &program, &pos)==1) {
187                 if(pos) {
188                         filter=optarg+pos;
189                 } else {
190                         filter=NULL;
191                 }
192         } else {
193                 fprintf(stderr, "tshark: invalid \"-z scsi,srt,<cmdset>[,<filter>]\" argument\n");
194                 exit(1);
195         }
196
197         scsi_program=program;
198         rs=g_malloc(sizeof(scsistat_t));
199         if(filter) {
200                 rs->filter=g_strdup(filter);
201         } else {
202                 rs->filter=NULL;
203         }
204         rs->cmdset=program;
205
206         switch(program) {
207                 case SCSI_DEV_SBC:
208                         rs->prog="SBC (disk)";
209                         rs->cdbnames=scsi_sbc_vals;
210                         break;
211                 case SCSI_DEV_SSC:
212                         rs->prog="SSC (tape)";
213                         rs->cdbnames=scsi_ssc_vals;
214                         break;
215                 case SCSI_DEV_CDROM:
216                         rs->prog="MMC (cd/dvd)";
217                         rs->cdbnames=scsi_mmc_vals;
218                         break;
219                 case SCSI_DEV_SMC:
220                         rs->prog="SMC (tape robot)";
221                         rs->cdbnames=scsi_smc_vals;
222                         break;
223                 case SCSI_DEV_OSD:
224                         rs->prog="OSD (object based)";
225                         rs->cdbnames=scsi_osd_vals;
226                         break;
227                 default:
228                         /* Default to the SBC (disk), since this is what EMC SCSI seem to always be */
229                         rs->cmdset=0;
230                         rs->prog="SBC (disk)";
231                         rs->cdbnames=scsi_sbc_vals;
232                         break;
233         }
234         rs->procedures=g_malloc(sizeof(scsi_procedure_t)*MAX_PROCEDURES);
235         for(i=0; i < MAX_PROCEDURES; i++) {
236                 rs->procedures[i].proc=val_to_str(i, rs->cdbnames, "Unknown-0x%02x");
237                 rs->procedures[i].num=0;
238                 rs->procedures[i].min.secs=0;
239                 rs->procedures[i].min.nsecs=0;
240                 rs->procedures[i].max.secs=0;
241                 rs->procedures[i].max.nsecs=0;
242                 rs->procedures[i].tot.secs=0;
243                 rs->procedures[i].tot.nsecs=0;
244         }
245         error_string=register_tap_listener("scsi", rs, filter, 0, scsistat_reset, scsistat_packet, scsistat_draw);
246         if(error_string) {
247                 /* error, we failed to attach to the tap. clean up */
248                 g_free(rs->procedures);
249                 g_free(rs->filter);
250                 g_free(rs);
251
252                 fprintf(stderr, "tshark: Couldn't register scsi,srt tap: %s\n",
253                         error_string->str);
254                 g_string_free(error_string, TRUE);
255                 exit(1);
256         }
257 }
258
259 void
260 register_tap_listener_scsistat(void)
261 {
262         register_stat_cmd_arg("scsi,srt,", scsistat_init, NULL);
263 }
264