patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / s390 / net / qeth_proc.c
1 /*
2  *
3  * linux/drivers/s390/net/qeth_fs.c ($Revision: 1.10 $)
4  *
5  * Linux on zSeries OSA Express and HiperSockets support
6  * This file contains code related to procfs.
7  *
8  * Copyright 2000,2003 IBM Corporation
9  *
10  * Author(s): Thomas Spatzier <tspat@de.ibm.com>
11  *
12  */
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/proc_fs.h>
16 #include <linux/seq_file.h>
17 #include <linux/list.h>
18 #include <linux/rwsem.h>
19
20 #include "qeth.h"
21 #include "qeth_mpc.h"
22 #include "qeth_fs.h"
23
24 const char *VERSION_QETH_PROC_C = "$Revision: 1.10 $";
25
26 /***** /proc/qeth *****/
27 #define QETH_PROCFILE_NAME "qeth"
28 static struct proc_dir_entry *qeth_procfile;
29
30 static void *
31 qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
32 {
33         struct list_head *next_card = NULL;
34         int i = 0;
35
36         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
37
38         if (*offset == 0)
39                 return SEQ_START_TOKEN;
40
41         /* get card at pos *offset */
42         list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices)
43                 if (++i == *offset)
44                         return next_card;
45
46         return NULL;
47 }
48
49 static void
50 qeth_procfile_seq_stop(struct seq_file *s, void* it)
51 {
52         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
53 }
54
55 static void *
56 qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
57 {
58         struct list_head *next_card = NULL;
59         struct list_head *current_card;
60
61         if (it == SEQ_START_TOKEN) {
62                 next_card = qeth_ccwgroup_driver.driver.devices.next;
63                 if (next_card->next == next_card) /* list empty */
64                         return NULL;
65                 (*offset)++;
66         } else {
67                 current_card = (struct list_head *)it;
68                 if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
69                         return NULL; /* end of list reached */
70                 next_card = current_card->next;
71                 (*offset)++;
72         }
73
74         return next_card;
75 }
76
77 static inline const char *
78 qeth_get_router_str(struct qeth_card *card, int ipv)
79 {
80         int routing_type = 0;
81
82         if (ipv == 4){
83                 routing_type = card->options.route4.type;
84         } else {
85 #ifdef CONFIG_QETH_IPV6
86                 routing_type = card->options.route6.type;
87 #else
88                 return "n/a";
89 #endif /* CONFIG_QETH_IPV6 */
90         }
91
92         if (routing_type == PRIMARY_ROUTER)
93                 return "pri";
94         else if (routing_type == SECONDARY_ROUTER)
95                 return "sec";
96         else if (routing_type == MULTICAST_ROUTER) {
97                 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
98                         return "mc+";
99                 return "mc";
100         } else if (routing_type == PRIMARY_CONNECTOR) {
101                 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
102                         return "p+c";
103                 return "p.c";
104         } else if (routing_type == SECONDARY_CONNECTOR) {
105                 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
106                         return "s+c";
107                 return "s.c";
108         } else if (routing_type == NO_ROUTER)
109                 return "no";
110         else
111                 return "unk";
112 }
113
114 static int
115 qeth_procfile_seq_show(struct seq_file *s, void *it)
116 {
117         struct device *device;
118         struct qeth_card *card;
119         char tmp[12]; /* for qeth_get_prioq_str */
120
121         if (it == SEQ_START_TOKEN){
122                 seq_printf(s, "devices                    CHPID interface  "
123                               "cardtype       port chksum prio-q'ing rtr4 "
124                               "rtr6 fsz   cnt\n");
125                 seq_printf(s, "-------------------------- ----- ---------- "
126                               "-------------- ---- ------ ---------- ---- "
127                               "---- ----- -----\n");
128         } else {
129                 device = list_entry(it, struct device, driver_list);
130                 card = device->driver_data;
131                 seq_printf(s, "%s/%s/%s x%02X   %-10s %-14s %-4i ",
132                                 CARD_RDEV_ID(card),
133                                 CARD_WDEV_ID(card),
134                                 CARD_DDEV_ID(card),
135                                 card->info.chpid,
136                                 card->info.if_name,
137                                 qeth_get_cardname_short(card),
138                                 card->info.portno);
139                 if (card->lan_online)
140                         seq_printf(s, "%-6s %-10s %-4s %-4s %-5s %-5i\n",
141                                         qeth_get_checksum_str(card),
142                                         qeth_get_prioq_str(card, tmp),
143                                         qeth_get_router_str(card, 4),
144                                         qeth_get_router_str(card, 6),
145                                         qeth_get_bufsize_str(card),
146                                         card->qdio.in_buf_pool.buf_count);
147                 else
148                         seq_printf(s, "  +++ LAN OFFLINE +++\n");
149         }
150         return 0;
151 }
152
153 static struct seq_operations qeth_procfile_seq_ops = {
154         .start = qeth_procfile_seq_start,
155         .stop  = qeth_procfile_seq_stop,
156         .next  = qeth_procfile_seq_next,
157         .show  = qeth_procfile_seq_show,
158 };
159
160 static int
161 qeth_procfile_open(struct inode *inode, struct file *file)
162 {
163         return seq_open(file, &qeth_procfile_seq_ops);
164 }
165
166 static struct file_operations qeth_procfile_fops = {
167         .owner   = THIS_MODULE,
168         .open    = qeth_procfile_open,
169         .read    = seq_read,
170         .llseek  = seq_lseek,
171         .release = seq_release,
172 };
173
174 /***** /proc/qeth_perf *****/
175 #define QETH_PERF_PROCFILE_NAME "qeth_perf"
176 static struct proc_dir_entry *qeth_perf_procfile;
177
178 #ifdef CONFIG_QETH_PERF_STATS
179
180 static void *
181 qeth_perf_procfile_seq_start(struct seq_file *s, loff_t *offset)
182 {
183         struct list_head *next_card = NULL;
184         int i = 0;
185
186         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
187         /* get card at pos *offset */
188         list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
189                 if (i == *offset)
190                         return next_card;
191                 i++;
192         }
193         return NULL;
194 }
195
196 static void
197 qeth_perf_procfile_seq_stop(struct seq_file *s, void* it)
198 {
199         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
200 }
201
202 static void *
203 qeth_perf_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
204 {
205         struct list_head *current_card = (struct list_head *)it;
206
207         if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
208                 return NULL; /* end of list reached */
209         (*offset)++;
210         return current_card->next;
211 }
212
213 static int
214 qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
215 {
216         struct device *device;
217         struct qeth_card *card;
218
219         device = list_entry(it, struct device, driver_list);
220         card = device->driver_data;
221         seq_printf(s, "For card with devnos %s/%s/%s (%s):\n",
222                         CARD_RDEV_ID(card),
223                         CARD_WDEV_ID(card),
224                         CARD_DDEV_ID(card),
225                         card->info.if_name
226                   );
227         seq_printf(s, "  Skb's/buffers received                 : %li/%i\n"
228                       "  Skb's/buffers sent                     : %li/%i\n\n",
229                         card->stats.rx_packets, card->perf_stats.bufs_rec,
230                         card->stats.tx_packets, card->perf_stats.bufs_sent
231                   );
232         seq_printf(s, "  Skb's/buffers sent without packing     : %li/%i\n"
233                       "  Skb's/buffers sent with packing        : %i/%i\n\n",
234                    card->stats.tx_packets - card->perf_stats.skbs_sent_pack,
235                    card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack,
236                    card->perf_stats.skbs_sent_pack,
237                    card->perf_stats.bufs_sent_pack
238                   );
239         seq_printf(s, "  Packing state changes no pkg.->packing : %i/%i\n"
240                       "  Watermarks L/H                         : %i/%i\n"
241                       "  Current buffer usage (outbound q's)    : "
242                       "%i/%i/%i/%i\n\n",
243                         card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
244                         QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK,
245                         atomic_read(&card->qdio.out_qs[0]->used_buffers),
246                         (card->qdio.no_out_queues > 1)?
247                                 atomic_read(&card->qdio.out_qs[1]->used_buffers)
248                                 : 0,
249                         (card->qdio.no_out_queues > 2)?
250                                 atomic_read(&card->qdio.out_qs[2]->used_buffers)
251                                 : 0,
252                         (card->qdio.no_out_queues > 3)?
253                                 atomic_read(&card->qdio.out_qs[3]->used_buffers)
254                                 : 0
255                   );
256         seq_printf(s, "  Inbound handler time (in us)           : %i\n"
257                       "  Inbound handler count                  : %i\n"
258                       "  Inbound do_QDIO time (in us)           : %i\n"
259                       "  Inbound do_QDIO count                  : %i\n\n"
260                       "  Outbound handler time (in us)          : %i\n"
261                       "  Outbound handler count                 : %i\n\n"
262                       "  Outbound time (in us, incl QDIO)       : %i\n"
263                       "  Outbound count                         : %i\n"
264                       "  Outbound do_QDIO time (in us)          : %i\n"
265                       "  Outbound do_QDIO count                 : %i\n",
266                         card->perf_stats.inbound_time,
267                         card->perf_stats.inbound_cnt,
268                         card->perf_stats.inbound_do_qdio_time,
269                         card->perf_stats.inbound_do_qdio_cnt,
270                         card->perf_stats.outbound_handler_time,
271                         card->perf_stats.outbound_handler_cnt,
272                         card->perf_stats.outbound_time,
273                         card->perf_stats.outbound_cnt,
274                         card->perf_stats.outbound_do_qdio_time,
275                         card->perf_stats.outbound_do_qdio_cnt
276                   );
277
278         return 0;
279 }
280
281 static struct seq_operations qeth_perf_procfile_seq_ops = {
282         .start = qeth_perf_procfile_seq_start,
283         .stop  = qeth_perf_procfile_seq_stop,
284         .next  = qeth_perf_procfile_seq_next,
285         .show  = qeth_perf_procfile_seq_show,
286 };
287
288 static int
289 qeth_perf_procfile_open(struct inode *inode, struct file *file)
290 {
291         return seq_open(file, &qeth_perf_procfile_seq_ops);
292 }
293
294 static struct file_operations qeth_perf_procfile_fops = {
295         .owner   = THIS_MODULE,
296         .open    = qeth_perf_procfile_open,
297         .read    = seq_read,
298         .llseek  = seq_lseek,
299         .release = seq_release,
300 };
301
302 #define qeth_perf_procfile_created qeth_perf_procfile
303 #else
304 #define qeth_perf_procfile_created 1
305 #endif /* CONFIG_QETH_PERF_STATS */
306
307 /***** /proc/qeth_ipa_takeover *****/
308 #define QETH_IPATO_PROCFILE_NAME "qeth_ipa_takeover"
309 static struct proc_dir_entry *qeth_ipato_procfile;
310
311 static void *
312 qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset)
313 {
314         struct list_head *next_card = NULL;
315         int i = 0;
316
317         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
318         /* TODO: finish this */
319         /*
320          * maybe SEQ_SATRT_TOKEN can be returned for offset 0
321          * output driver settings then;
322          * else output setting for respective card
323          */
324         /* get card at pos *offset */
325         list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
326                 if (i == *offset)
327                         return next_card;
328                 i++;
329         }
330         return NULL;
331 }
332
333 static void
334 qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it)
335 {
336         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
337 }
338
339 static void *
340 qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
341 {
342         struct list_head *current_card = (struct list_head *)it;
343
344         /* TODO: finish this */
345         /*
346          * maybe SEQ_SATRT_TOKEN can be returned for offset 0
347          * output driver settings then;
348          * else output setting for respective card
349          */
350         if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
351                 return NULL; /* end of list reached */
352         (*offset)++;
353         return current_card->next;
354 }
355
356 static int
357 qeth_ipato_procfile_seq_show(struct seq_file *s, void *it)
358 {
359         struct device *device;
360         struct qeth_card *card;
361
362         /* TODO: finish this */
363         /*
364          * maybe SEQ_SATRT_TOKEN can be returned for offset 0
365          * output driver settings then;
366          * else output setting for respective card
367          */
368         device = list_entry(it, struct device, driver_list);
369         card = device->driver_data;
370
371         return 0;
372 }
373
374 static struct seq_operations qeth_ipato_procfile_seq_ops = {
375         .start = qeth_ipato_procfile_seq_start,
376         .stop  = qeth_ipato_procfile_seq_stop,
377         .next  = qeth_ipato_procfile_seq_next,
378         .show  = qeth_ipato_procfile_seq_show,
379 };
380
381 static int
382 qeth_ipato_procfile_open(struct inode *inode, struct file *file)
383 {
384         return seq_open(file, &qeth_ipato_procfile_seq_ops);
385 }
386
387 static struct file_operations qeth_ipato_procfile_fops = {
388         .owner   = THIS_MODULE,
389         .open    = qeth_ipato_procfile_open,
390         .read    = seq_read,
391         .llseek  = seq_lseek,
392         .release = seq_release,
393 };
394
395 int __init
396 qeth_create_procfs_entries(void)
397 {
398         qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME,
399                                            S_IFREG | 0444, NULL);
400         if (qeth_procfile)
401                 qeth_procfile->proc_fops = &qeth_procfile_fops;
402
403 #ifdef CONFIG_QETH_PERF_STATS
404         qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
405                                            S_IFREG | 0444, NULL);
406         if (qeth_perf_procfile)
407                 qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
408 #endif /* CONFIG_QETH_PERF_STATS */
409
410         qeth_ipato_procfile = create_proc_entry(QETH_IPATO_PROCFILE_NAME,
411                                            S_IFREG | 0444, NULL);
412         if (qeth_ipato_procfile)
413                 qeth_ipato_procfile->proc_fops = &qeth_ipato_procfile_fops;
414
415         if (qeth_procfile &&
416             qeth_ipato_procfile &&
417             qeth_perf_procfile_created)
418                 return 0;
419         else
420                 return -ENOMEM;
421 }
422
423 void __exit
424 qeth_remove_procfs_entries(void)
425 {
426         if (qeth_procfile)
427                 remove_proc_entry(QETH_PROCFILE_NAME, NULL);
428         if (qeth_perf_procfile)
429                 remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL);
430         if (qeth_ipato_procfile)
431                 remove_proc_entry(QETH_IPATO_PROCFILE_NAME, NULL);
432 }
433
434
435 /* ONLY FOR DEVELOPMENT! -> make it as module */
436 /*
437 static void
438 qeth_create_sysfs_entries(void)
439 {
440         struct device *dev;
441
442         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
443
444         list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
445                         driver_list)
446                 qeth_create_device_attributes(dev);
447
448         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
449 }
450
451 static void
452 qeth_remove_sysfs_entries(void)
453 {
454         struct device *dev;
455
456         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
457
458         list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
459                         driver_list)
460                 qeth_remove_device_attributes(dev);
461
462         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
463 }
464
465 static int __init
466 qeth_fs_init(void)
467 {
468         printk(KERN_INFO "qeth_fs_init\n");
469         qeth_create_procfs_entries();
470         qeth_create_sysfs_entries();
471
472         return 0;
473 }
474
475 static void __exit
476 qeth_fs_exit(void)
477 {
478         printk(KERN_INFO "qeth_fs_exit\n");
479         qeth_remove_procfs_entries();
480         qeth_remove_sysfs_entries();
481 }
482
483
484 module_init(qeth_fs_init);
485 module_exit(qeth_fs_exit);
486
487 MODULE_LICENSE("GPL");
488 */