Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / s390 / net / qeth_proc.c
1 /*
2  *
3  * linux/drivers/s390/net/qeth_fs.c ($Revision: 1.13 $)
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.13 $";
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                                 QETH_CARD_IFNAME(card),
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                         QETH_CARD_IFNAME(card)
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, "  Skbs sent in SG mode                   : %i\n"
240                       "  Skb fragments sent in SG mode          : %i\n\n",
241                       card->perf_stats.sg_skbs_sent,
242                       card->perf_stats.sg_frags_sent);
243         seq_printf(s, "  large_send tx (in Kbytes)              : %i\n"
244                       "  large_send count                       : %i\n\n",
245                       card->perf_stats.large_send_bytes >> 10,
246                       card->perf_stats.large_send_cnt);
247         seq_printf(s, "  Packing state changes no pkg.->packing : %i/%i\n"
248                       "  Watermarks L/H                         : %i/%i\n"
249                       "  Current buffer usage (outbound q's)    : "
250                       "%i/%i/%i/%i\n\n",
251                         card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
252                         QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK,
253                         atomic_read(&card->qdio.out_qs[0]->used_buffers),
254                         (card->qdio.no_out_queues > 1)?
255                                 atomic_read(&card->qdio.out_qs[1]->used_buffers)
256                                 : 0,
257                         (card->qdio.no_out_queues > 2)?
258                                 atomic_read(&card->qdio.out_qs[2]->used_buffers)
259                                 : 0,
260                         (card->qdio.no_out_queues > 3)?
261                                 atomic_read(&card->qdio.out_qs[3]->used_buffers)
262                                 : 0
263                   );
264         seq_printf(s, "  Inbound handler time (in us)           : %i\n"
265                       "  Inbound handler count                  : %i\n"
266                       "  Inbound do_QDIO time (in us)           : %i\n"
267                       "  Inbound do_QDIO count                  : %i\n\n"
268                       "  Outbound handler time (in us)          : %i\n"
269                       "  Outbound handler count                 : %i\n\n"
270                       "  Outbound time (in us, incl QDIO)       : %i\n"
271                       "  Outbound count                         : %i\n"
272                       "  Outbound do_QDIO time (in us)          : %i\n"
273                       "  Outbound do_QDIO count                 : %i\n\n",
274                         card->perf_stats.inbound_time,
275                         card->perf_stats.inbound_cnt,
276                         card->perf_stats.inbound_do_qdio_time,
277                         card->perf_stats.inbound_do_qdio_cnt,
278                         card->perf_stats.outbound_handler_time,
279                         card->perf_stats.outbound_handler_cnt,
280                         card->perf_stats.outbound_time,
281                         card->perf_stats.outbound_cnt,
282                         card->perf_stats.outbound_do_qdio_time,
283                         card->perf_stats.outbound_do_qdio_cnt
284                   );
285         return 0;
286 }
287
288 static struct seq_operations qeth_perf_procfile_seq_ops = {
289         .start = qeth_perf_procfile_seq_start,
290         .stop  = qeth_perf_procfile_seq_stop,
291         .next  = qeth_perf_procfile_seq_next,
292         .show  = qeth_perf_procfile_seq_show,
293 };
294
295 static int
296 qeth_perf_procfile_open(struct inode *inode, struct file *file)
297 {
298         return seq_open(file, &qeth_perf_procfile_seq_ops);
299 }
300
301 static struct file_operations qeth_perf_procfile_fops = {
302         .owner   = THIS_MODULE,
303         .open    = qeth_perf_procfile_open,
304         .read    = seq_read,
305         .llseek  = seq_lseek,
306         .release = seq_release,
307 };
308
309 #define qeth_perf_procfile_created qeth_perf_procfile
310 #else
311 #define qeth_perf_procfile_created 1
312 #endif /* CONFIG_QETH_PERF_STATS */
313
314 /***** /proc/qeth_ipa_takeover *****/
315 #define QETH_IPATO_PROCFILE_NAME "qeth_ipa_takeover"
316 static struct proc_dir_entry *qeth_ipato_procfile;
317
318 static void *
319 qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset)
320 {
321         struct list_head *next_card = NULL;
322         int i = 0;
323
324         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
325         /* TODO: finish this */
326         /*
327          * maybe SEQ_SATRT_TOKEN can be returned for offset 0
328          * output driver settings then;
329          * else output setting for respective card
330          */
331         /* get card at pos *offset */
332         list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
333                 if (i == *offset)
334                         return next_card;
335                 i++;
336         }
337         return NULL;
338 }
339
340 static void
341 qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it)
342 {
343         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
344 }
345
346 static void *
347 qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
348 {
349         struct list_head *current_card = (struct list_head *)it;
350
351         /* TODO: finish this */
352         /*
353          * maybe SEQ_SATRT_TOKEN can be returned for offset 0
354          * output driver settings then;
355          * else output setting for respective card
356          */
357         if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
358                 return NULL; /* end of list reached */
359         (*offset)++;
360         return current_card->next;
361 }
362
363 static int
364 qeth_ipato_procfile_seq_show(struct seq_file *s, void *it)
365 {
366         struct device *device;
367         struct qeth_card *card;
368
369         /* TODO: finish this */
370         /*
371          * maybe SEQ_SATRT_TOKEN can be returned for offset 0
372          * output driver settings then;
373          * else output setting for respective card
374          */
375         device = list_entry(it, struct device, driver_list);
376         card = device->driver_data;
377
378         return 0;
379 }
380
381 static struct seq_operations qeth_ipato_procfile_seq_ops = {
382         .start = qeth_ipato_procfile_seq_start,
383         .stop  = qeth_ipato_procfile_seq_stop,
384         .next  = qeth_ipato_procfile_seq_next,
385         .show  = qeth_ipato_procfile_seq_show,
386 };
387
388 static int
389 qeth_ipato_procfile_open(struct inode *inode, struct file *file)
390 {
391         return seq_open(file, &qeth_ipato_procfile_seq_ops);
392 }
393
394 static struct file_operations qeth_ipato_procfile_fops = {
395         .owner   = THIS_MODULE,
396         .open    = qeth_ipato_procfile_open,
397         .read    = seq_read,
398         .llseek  = seq_lseek,
399         .release = seq_release,
400 };
401
402 int __init
403 qeth_create_procfs_entries(void)
404 {
405         qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME,
406                                            S_IFREG | 0444, NULL);
407         if (qeth_procfile)
408                 qeth_procfile->proc_fops = &qeth_procfile_fops;
409
410 #ifdef CONFIG_QETH_PERF_STATS
411         qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
412                                            S_IFREG | 0444, NULL);
413         if (qeth_perf_procfile)
414                 qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
415 #endif /* CONFIG_QETH_PERF_STATS */
416
417         qeth_ipato_procfile = create_proc_entry(QETH_IPATO_PROCFILE_NAME,
418                                            S_IFREG | 0444, NULL);
419         if (qeth_ipato_procfile)
420                 qeth_ipato_procfile->proc_fops = &qeth_ipato_procfile_fops;
421
422         if (qeth_procfile &&
423             qeth_ipato_procfile &&
424             qeth_perf_procfile_created)
425                 return 0;
426         else
427                 return -ENOMEM;
428 }
429
430 void __exit
431 qeth_remove_procfs_entries(void)
432 {
433         if (qeth_procfile)
434                 remove_proc_entry(QETH_PROCFILE_NAME, NULL);
435         if (qeth_perf_procfile)
436                 remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL);
437         if (qeth_ipato_procfile)
438                 remove_proc_entry(QETH_IPATO_PROCFILE_NAME, NULL);
439 }
440
441
442 /* ONLY FOR DEVELOPMENT! -> make it as module */
443 /*
444 static void
445 qeth_create_sysfs_entries(void)
446 {
447         struct device *dev;
448
449         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
450
451         list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
452                         driver_list)
453                 qeth_create_device_attributes(dev);
454
455         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
456 }
457
458 static void
459 qeth_remove_sysfs_entries(void)
460 {
461         struct device *dev;
462
463         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
464
465         list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
466                         driver_list)
467                 qeth_remove_device_attributes(dev);
468
469         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
470 }
471
472 static int __init
473 qeth_fs_init(void)
474 {
475         printk(KERN_INFO "qeth_fs_init\n");
476         qeth_create_procfs_entries();
477         qeth_create_sysfs_entries();
478
479         return 0;
480 }
481
482 static void __exit
483 qeth_fs_exit(void)
484 {
485         printk(KERN_INFO "qeth_fs_exit\n");
486         qeth_remove_procfs_entries();
487         qeth_remove_sysfs_entries();
488 }
489
490
491 module_init(qeth_fs_init);
492 module_exit(qeth_fs_exit);
493
494 MODULE_LICENSE("GPL");
495 */