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