Whamcloud - gitweb
LU-1419 lnet: Add support for Cray's Gemini interconnect
[fs/lustre-release.git] / lnet / klnds / gnilnd / gnilnd_proc.c
1 /*
2  * Copyright (C) 2009-2012 Cray, Inc.
3  *
4  *   Author: Nic Henke <nic@cray.com>
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 /* this code liberated and modified from lnet/lnet/router_proc.c */
23
24 #define DEBUG_SUBSYSTEM S_LND
25 #include "gnilnd.h"
26 #include <linux/seq_file.h>
27
28 #define GNILND_PROC_STATS       "stats"
29 #define GNILND_PROC_MDD         "mdd"
30 #define GNILND_PROC_SMSG        "smsg"
31 #define GNILND_PROC_CONN        "conn"
32 #define GNILND_PROC_PEER        "peer"
33 #define GNILND_PROC_CKSUM_TEST  "cksum_test"
34
35 static int
36 _kgnilnd_proc_run_cksum_test(int caseno, int nloops, int nob)
37 {
38         lnet_kiov_t              *src, *dest;
39         struct timespec          begin, end, diff;
40         int                      niov;
41         int                      i = 0, j = 0, n;
42         __u16                    cksum, cksum2;
43         __u64                    mbytes;
44
45         LIBCFS_ALLOC(src, LNET_MAX_IOV * sizeof(lnet_kiov_t));
46         LIBCFS_ALLOC(dest, LNET_MAX_IOV * sizeof(lnet_kiov_t));
47
48         if (src == NULL || dest == NULL) {
49                 CERROR("couldn't allocate iovs\n");
50                 GOTO(unwind, -ENOMEM);
51         }
52
53         for (i = 0; i < LNET_MAX_IOV; i++) {
54                 src[i].kiov_offset = 0;
55                 src[i].kiov_len = CFS_PAGE_SIZE;
56                 src[i].kiov_page = cfs_alloc_page(CFS_ALLOC_STD|CFS_ALLOC_ZERO);
57
58                 if (src[i].kiov_page == NULL) {
59                         CERROR("couldn't allocate page %d\n", i);
60                         GOTO(unwind, -ENOMEM);
61                 }
62
63                 dest[i].kiov_offset = 0;
64                 dest[i].kiov_len = CFS_PAGE_SIZE;
65                 dest[i].kiov_page = cfs_alloc_page(CFS_ALLOC_STD|CFS_ALLOC_ZERO);
66
67                 if (dest[i].kiov_page == NULL) {
68                         CERROR("couldn't allocate page %d\n", i);
69                         GOTO(unwind, -ENOMEM);
70                 }
71         }
72
73         /* add extra 2 pages - one for offset of src, 2nd to allow dest offset */
74         niov = (nob / PAGE_SIZE) + 2;
75         if (niov > LNET_MAX_IOV) {
76                 CERROR("bytes %d too large, requires niov %d > %d\n",
77                         nob, niov, LNET_MAX_IOV);
78                 GOTO(unwind, -E2BIG);
79         }
80
81         /* setup real data */
82         src[0].kiov_offset = 317;
83         dest[0].kiov_offset = 592;
84         switch (caseno) {
85         default:
86                 /* odd -> even */
87                 break;
88         case 1:
89                 /* odd -> odd */
90                 dest[0].kiov_offset -= 1;
91                 break;
92         case 2:
93                 /* even -> even */
94                 src[0].kiov_offset += 1;
95                 break;
96         case 3:
97                 /* even -> odd */
98                 src[0].kiov_offset += 1;
99                 dest[0].kiov_offset -= 1;
100         }
101         src[0].kiov_len = PAGE_SIZE - src[0].kiov_offset;
102         dest[0].kiov_len = PAGE_SIZE - dest[0].kiov_offset;
103
104         for (i = 0; i < niov; i++) {
105                 memset(page_address(src[i].kiov_page) + src[i].kiov_offset,
106                        0xf0 + i, src[i].kiov_len);
107         }
108
109         lnet_copy_kiov2kiov(niov, dest, 0, niov, src, 0, nob);
110
111         getnstimeofday(&begin);
112
113         for (n = 0; n < nloops; n++) {
114                 CDEBUG(D_BUFFS, "case %d loop %d src %d dest %d nob %d niov %d\n",
115                        caseno, n, src[0].kiov_offset, dest[0].kiov_offset, nob, niov);
116                 cksum = kgnilnd_cksum_kiov(niov, src, 0, nob - n, 1);
117                 cksum2 = kgnilnd_cksum_kiov(niov, dest, 0, nob - n, 1);
118
119                 if (cksum != cksum2) {
120                         CERROR("case %d loop %d different checksums %x expected %x\n",
121                                j, n, cksum2, cksum);
122                         GOTO(unwind, -ENOKEY);
123                 }
124         }
125
126         getnstimeofday(&end);
127
128         mbytes = (nloops * nob * 2) / (1024*1024);
129
130         diff = kgnilnd_ts_sub(end, begin);
131
132         LCONSOLE_INFO("running "LPD64"MB took %ld.%ld seconds\n",
133                       mbytes, diff.tv_sec, diff.tv_nsec);
134
135 unwind:
136         CDEBUG(D_NET, "freeing %d pages\n", i);
137         for (i -= 1; i >= 0; i--) {
138                 if (src[i].kiov_page != NULL) {
139                         cfs_free_page(src[i].kiov_page);
140                 }
141                 if (dest[i].kiov_page != NULL) {
142                         cfs_free_page(dest[i].kiov_page);
143                 }
144         }
145
146         if (src != NULL)
147                 LIBCFS_FREE(src, LNET_MAX_IOV * sizeof(lnet_kiov_t));
148         if (dest != NULL)
149                 LIBCFS_FREE(dest, LNET_MAX_IOV * sizeof(lnet_kiov_t));
150         return 0;
151 }
152
153 static int
154 kgnilnd_proc_cksum_test_write(struct file *file, const char *ubuffer,
155                               unsigned long count, void *data)
156 {
157         char                    dummy[256 + 1] = { '\0' };
158         int                     testno, nloops, nbytes;
159         int                     rc;
160
161         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
162                 CERROR("can't run cksum test, kgnilnd is not initialized yet\n");
163                 return -ENOSYS;
164         }
165
166         if (count >= sizeof(dummy) || count == 0)
167                 return -EINVAL;
168
169         if (copy_from_user(dummy, ubuffer, count))
170                 return -EFAULT;
171
172         if (sscanf(dummy, "%d:%d:%d", &testno, &nloops, &nbytes) == 3) {
173                 rc = _kgnilnd_proc_run_cksum_test(testno, nloops, nbytes);
174                 if (rc < 0) {
175                         RETURN(rc);
176                 } else {
177                         /* spurious, but lets us know the parse was ok */
178                         RETURN(count);
179                 }
180         }
181         RETURN(count);
182 }
183
184 static int
185 kgnilnd_proc_stats_read(char *page, char **start, off_t off,
186                              int count, int *eof, void *data)
187 {
188         kgn_device_t           *dev;
189         struct timeval          now;
190         int                     rc;
191
192         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
193                 rc = sprintf(page,
194                         "kgnilnd is not initialized yet\n");
195                 return rc;
196         }
197
198         /* only do the first device */
199         dev = &kgnilnd_data.kgn_devices[0];
200
201         /* sampling is racy, but so is reading this file! */
202         smp_rmb();
203         do_gettimeofday(&now);
204
205         rc = sprintf(page, "time: %lu.%lu\n"
206                            "ntx: %d\n"
207                            "npeers: %d\n"
208                            "nconns: %d\n"
209                            "nEPs: %d\n"
210                            "ndgrams: %d\n"
211                            "nfmablk: %d\n"
212                            "n_mdd: %d\n"
213                            "n_mdd_held: %d\n"
214                            "GART map bytes: %ld\n"
215                            "TX queued maps: %d\n"
216                            "TX phys nmaps: %d\n"
217                            "TX phys bytes: %lu\n"
218                            "TX virt nmaps: %d\n"
219                            "TX virt bytes: "LPU64"\n"
220                            "RDMAQ bytes_auth: %ld\n"
221                            "RDMAQ bytes_left: %ld\n"
222                            "RDMAQ nstalls: %d\n"
223                            "dev mutex delay: %ld\n"
224                            "dev n_yield: %d\n"
225                            "dev n_schedule: %d\n"
226                            "SMSG fast_try: %d\n"
227                            "SMSG fast_ok: %d\n"
228                            "SMSG fast_block: %d\n"
229                            "SMSG ntx: %d\n"
230                            "SMSG tx_bytes: %ld\n"
231                            "SMSG nrx: %d\n"
232                            "SMSG rx_bytes: %ld\n"
233                            "RDMA ntx: %d\n"
234                            "RDMA tx_bytes: %ld\n"
235                            "RDMA nrx: %d\n"
236                            "RDMA rx_bytes: %ld\n"
237                            "VMAP short: %d\n"
238                            "VMAP cksum: %d\n"
239                            "KMAP short: %d\n",
240                 now.tv_sec, now.tv_usec,
241                 atomic_read(&kgnilnd_data.kgn_ntx),
242                 atomic_read(&kgnilnd_data.kgn_npeers),
243                 atomic_read(&kgnilnd_data.kgn_nconns),
244                 atomic_read(&dev->gnd_neps),
245                 atomic_read(&dev->gnd_ndgrams),
246                 atomic_read(&dev->gnd_nfmablk),
247                 atomic_read(&dev->gnd_n_mdd), atomic_read(&dev->gnd_n_mdd_held),
248                 atomic64_read(&dev->gnd_nbytes_map),
249                 atomic_read(&dev->gnd_nq_map),
250                 dev->gnd_map_nphys, dev->gnd_map_physnop * PAGE_SIZE,
251                 dev->gnd_map_nvirt, dev->gnd_map_virtnob,
252                 atomic64_read(&dev->gnd_rdmaq_bytes_out),
253                 atomic64_read(&dev->gnd_rdmaq_bytes_ok),
254                 atomic_read(&dev->gnd_rdmaq_nstalls),
255                 dev->gnd_mutex_delay,
256                 atomic_read(&dev->gnd_n_yield), atomic_read(&dev->gnd_n_schedule),
257                 atomic_read(&dev->gnd_fast_try), atomic_read(&dev->gnd_fast_ok),
258                 atomic_read(&dev->gnd_fast_block),
259                 atomic_read(&dev->gnd_short_ntx), atomic64_read(&dev->gnd_short_txbytes),
260                 atomic_read(&dev->gnd_short_nrx), atomic64_read(&dev->gnd_short_rxbytes),
261                 atomic_read(&dev->gnd_rdma_ntx), atomic64_read(&dev->gnd_rdma_txbytes),
262                 atomic_read(&dev->gnd_rdma_nrx), atomic64_read(&dev->gnd_rdma_rxbytes),
263                 atomic_read(&kgnilnd_data.kgn_nvmap_short),
264                 atomic_read(&kgnilnd_data.kgn_nvmap_cksum),
265                 atomic_read(&kgnilnd_data.kgn_nkmap_short));
266
267         return rc;
268 }
269
270 static int
271 kgnilnd_proc_stats_write(struct file *file, const char *ubuffer,
272                      unsigned long count, void *data)
273 {
274         kgn_device_t           *dev;
275
276         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
277                 CERROR("kgnilnd is not initialized for stats write\n");
278                 return -EINVAL;
279         }
280
281         /* only do the first device */
282         dev = &kgnilnd_data.kgn_devices[0];
283
284         atomic_set(&dev->gnd_short_ntx, 0);
285         atomic_set(&dev->gnd_short_nrx, 0);
286         atomic64_set(&dev->gnd_short_txbytes, 0);
287         atomic64_set(&dev->gnd_short_rxbytes, 0);
288         atomic_set(&dev->gnd_rdma_ntx, 0);
289         atomic_set(&dev->gnd_rdma_nrx, 0);
290         atomic_set(&dev->gnd_fast_ok, 0);
291         atomic_set(&dev->gnd_fast_try, 0);
292         atomic_set(&dev->gnd_fast_block, 0);
293         atomic64_set(&dev->gnd_rdma_txbytes, 0);
294         atomic64_set(&dev->gnd_rdma_rxbytes, 0);
295         atomic_set(&dev->gnd_rdmaq_nstalls, 0);
296         set_mb(dev->gnd_mutex_delay, 0);
297         atomic_set(&dev->gnd_n_yield, 0);
298         atomic_set(&dev->gnd_n_schedule, 0);
299         atomic_set(&kgnilnd_data.kgn_nvmap_short, 0);
300         atomic_set(&kgnilnd_data.kgn_nvmap_cksum, 0);
301         atomic_set(&kgnilnd_data.kgn_nkmap_short, 0);
302         /* sampling is racy, but so is writing this file! */
303         smp_wmb();
304         return count;
305 }
306
307 typedef struct {
308         kgn_device_t           *gmdd_dev;
309         kgn_tx_t               *gmdd_tx;
310         loff_t                  gmdd_off;
311 } kgn_mdd_seq_iter_t;
312
313 int
314 kgnilnd_mdd_seq_seek(kgn_mdd_seq_iter_t *gseq, loff_t off)
315 {
316         kgn_tx_t                *tx;
317         struct list_head        *r;
318         loff_t                  here;
319         int                     rc = 0;
320
321         if (off == 0) {
322                 gseq->gmdd_tx = NULL;
323                 gseq->gmdd_off = 0;
324                 return 0;
325         }
326
327         tx = gseq->gmdd_tx;
328
329         if (tx == NULL || gseq->gmdd_off > off) {
330                 /* search from start */
331                 r = gseq->gmdd_dev->gnd_map_list.next;
332                 here = 1;
333         } else {
334                 /* continue current search */
335                 r = &tx->tx_map_list;
336                 here = gseq->gmdd_off;
337         }
338
339         gseq->gmdd_off = off;
340
341         while (r != &gseq->gmdd_dev->gnd_map_list) {
342                 kgn_tx_t      *t;
343
344                 t = list_entry(r, kgn_tx_t, tx_map_list);
345
346                 if (here == off) {
347                         gseq->gmdd_tx = t;
348                         rc = 0;
349                         goto out;
350                 }
351                 r = r->next;
352                 here++;
353         }
354
355         gseq->gmdd_tx = NULL;
356         rc = -ENOENT;
357 out:
358         return rc;
359 }
360
361 static void *
362 kgnilnd_mdd_seq_start(struct seq_file *s, loff_t *pos)
363 {
364
365         kgn_mdd_seq_iter_t      *gseq;
366         int                      rc;
367
368         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
369                 return NULL;
370         }
371
372         LIBCFS_ALLOC(gseq, sizeof(*gseq));
373         if (gseq == NULL) {
374                 CERROR("could not allocate mdd sequence iterator\n");
375                 return NULL;
376         }
377
378         /* only doing device 0 for now */
379         gseq->gmdd_dev = &kgnilnd_data.kgn_devices[0];
380         gseq->gmdd_tx = NULL;
381
382         /* need to lock map while we poke - huge disturbance
383          * but without it, no way to get the data printed */
384         spin_lock(&gseq->gmdd_dev->gnd_map_lock);
385
386         /* set private to gseq for stop */
387         s->private = gseq;
388
389         rc = kgnilnd_mdd_seq_seek(gseq, *pos);
390         if (rc == 0)
391                 return gseq;
392         else
393                 return NULL;
394 }
395
396 static void
397 kgnilnd_mdd_seq_stop(struct seq_file *s, void *iter)
398 {
399         kgn_mdd_seq_iter_t     *gseq = s->private;
400
401         if (gseq != NULL) {
402                 spin_unlock(&gseq->gmdd_dev->gnd_map_lock);
403                 LIBCFS_FREE(gseq, sizeof(*gseq));
404         }
405 }
406
407 static void *
408 kgnilnd_mdd_seq_next(struct seq_file *s, void *iter, loff_t *pos)
409 {
410         kgn_mdd_seq_iter_t     *gseq = iter;
411         int                     rc;
412         loff_t                  next = *pos + 1;
413
414         rc = kgnilnd_mdd_seq_seek(gseq, next);
415         if (rc != 0) {
416                 return NULL;
417         }
418         *pos = next;
419         return gseq;
420 }
421
422 static int
423 kgnilnd_mdd_seq_show(struct seq_file *s, void *iter)
424 {
425         kgn_mdd_seq_iter_t     *gseq = iter;
426         kgn_tx_t               *tx;
427         __u64                   nob;
428         __u32                   physnop;
429         int                     id;
430         int                     buftype;
431         gni_mem_handle_t        hndl;
432
433         if (gseq->gmdd_off == 0) {
434                 seq_printf(s, "%s %22s %16s %8s %8s %37s\n",
435                         "tx", "tx_id", "nob", "physnop",
436                         "buftype", "mem handle");
437                 return 0;
438         }
439
440         tx = gseq->gmdd_tx;
441         LASSERT(tx != NULL);
442
443         id = tx->tx_id.txe_smsg_id;
444         nob = tx->tx_nob;
445         physnop = tx->tx_phys_npages;
446         buftype = tx->tx_buftype;
447         hndl.qword1 = tx->tx_map_key.qword1;
448         hndl.qword2 = tx->tx_map_key.qword2;
449
450         seq_printf(s, "%p %x %16"LPF64"u %8d %#8x "LPX64"."LPX64"x\n",
451                 tx, id, nob, physnop, buftype,
452                 hndl.qword1, hndl.qword2);
453
454         return 0;
455 }
456
457 static struct seq_operations kgn_mdd_sops = {
458         .start = kgnilnd_mdd_seq_start,
459         .stop  = kgnilnd_mdd_seq_stop,
460         .next  = kgnilnd_mdd_seq_next,
461         .show  = kgnilnd_mdd_seq_show,
462
463 };
464
465 static int
466 kgnilnd_mdd_seq_open(struct inode *inode, struct file *file)
467 {
468         struct seq_file       *sf;
469         int                    rc;
470
471         rc = seq_open(file, &kgn_mdd_sops);
472         if (rc == 0) {
473                 sf = file->private_data;
474
475                 /* NULL means we've not yet open() */
476                 sf->private = NULL;
477         }
478         return rc;
479 }
480
481 static struct file_operations kgn_mdd_fops = {
482         .owner   = THIS_MODULE,
483         .open    = kgnilnd_mdd_seq_open,
484         .read    = seq_read,
485         .llseek  = seq_lseek,
486         .release = seq_release,
487 };
488
489 typedef struct {
490         __u64                   gsmsg_version;
491         kgn_device_t           *gsmsg_dev;
492         kgn_fma_memblock_t     *gsmsg_fmablk;
493         loff_t                  gsmsg_off;
494 } kgn_smsg_seq_iter_t;
495
496 int
497 kgnilnd_smsg_seq_seek(kgn_smsg_seq_iter_t *gseq, loff_t off)
498 {
499         kgn_fma_memblock_t             *fmablk;
500         kgn_device_t                   *dev;
501         struct list_head               *r;
502         loff_t                          here;
503         int                             rc = 0;
504
505         /* offset 0 is the header, so we start real entries at
506          * here == off == 1 */
507         if (off == 0) {
508                 gseq->gsmsg_fmablk = NULL;
509                 gseq->gsmsg_off = 0;
510                 return 0;
511         }
512
513         fmablk = gseq->gsmsg_fmablk;
514         dev = gseq->gsmsg_dev;
515
516         spin_lock(&dev->gnd_fmablk_lock);
517
518         if (fmablk != NULL &&
519                 gseq->gsmsg_version != atomic_read(&dev->gnd_fmablk_vers)) {
520                 /* list changed */
521                 rc = -ESTALE;
522                 goto out;
523         }
524
525         if (fmablk == NULL || gseq->gsmsg_off > off) {
526                 /* search from start */
527                 r = dev->gnd_fma_buffs.next;
528                 here = 1;
529         } else {
530                 /* continue current search */
531                 r = &fmablk->gnm_bufflist;
532                 here = gseq->gsmsg_off;
533         }
534
535         gseq->gsmsg_version = atomic_read(&dev->gnd_fmablk_vers);
536         gseq->gsmsg_off = off;
537
538         while (r != &dev->gnd_fma_buffs) {
539                 kgn_fma_memblock_t      *t;
540
541                 t = list_entry(r, kgn_fma_memblock_t, gnm_bufflist);
542
543                 if (here == off) {
544                         gseq->gsmsg_fmablk = t;
545                         rc = 0;
546                         goto out;
547                 }
548                 r = r->next;
549                 here++;
550         }
551
552         gseq->gsmsg_fmablk = NULL;
553         rc = -ENOENT;
554 out:
555         spin_unlock(&dev->gnd_fmablk_lock);
556         return rc;
557 }
558
559 static void *
560 kgnilnd_smsg_seq_start(struct seq_file *s, loff_t *pos)
561 {
562
563         kgn_smsg_seq_iter_t     *gseq;
564         int                      rc;
565
566         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
567                 return NULL;
568         }
569
570         LIBCFS_ALLOC(gseq, sizeof(*gseq));
571         if (gseq == NULL) {
572                 CERROR("could not allocate smsg sequence iterator\n");
573                 return NULL;
574         }
575
576         /* only doing device 0 for now */
577         gseq->gsmsg_dev = &kgnilnd_data.kgn_devices[0];
578         gseq->gsmsg_fmablk = NULL;
579         rc = kgnilnd_smsg_seq_seek(gseq, *pos);
580         if (rc == 0)
581                 return gseq;
582
583         LIBCFS_FREE(gseq, sizeof(*gseq));
584         return NULL;
585 }
586
587 static void
588 kgnilnd_smsg_seq_stop(struct seq_file *s, void *iter)
589 {
590         kgn_smsg_seq_iter_t     *gseq = iter;
591
592         if (gseq != NULL)
593                 LIBCFS_FREE(gseq, sizeof(*gseq));
594 }
595
596 static void *
597 kgnilnd_smsg_seq_next(struct seq_file *s, void *iter, loff_t *pos)
598 {
599         kgn_smsg_seq_iter_t    *gseq = iter;
600         int                     rc;
601         loff_t                  next = *pos + 1;
602
603         rc = kgnilnd_smsg_seq_seek(gseq, next);
604         if (rc != 0) {
605                 LIBCFS_FREE(gseq, sizeof(*gseq));
606                 return NULL;
607         }
608         *pos = next;
609         return gseq;
610 }
611
612 static int
613 kgnilnd_smsg_seq_show(struct seq_file *s, void *iter)
614 {
615         kgn_smsg_seq_iter_t    *gseq = iter;
616         kgn_fma_memblock_t     *fmablk;
617         kgn_device_t           *dev;
618         int                     avail_mboxs, held_mboxs, num_mboxs;
619         unsigned int            blk_size;
620         int                     live;
621         kgn_fmablk_state_t      state;
622         gni_mem_handle_t        hndl;
623
624         if (gseq->gsmsg_off == 0) {
625                 seq_printf(s, "%5s %4s %6s/%5s/%5s %9s %18s %37s\n",
626                         "blk#", "type", "avail", "held", "total", "size",
627                         "fmablk", "mem handle");
628                 return 0;
629         }
630
631         fmablk = gseq->gsmsg_fmablk;
632         dev = gseq->gsmsg_dev;
633         LASSERT(fmablk != NULL);
634
635         spin_lock(&dev->gnd_fmablk_lock);
636
637         if (gseq->gsmsg_version != atomic_read(&dev->gnd_fmablk_vers)) {
638                 /* list changed */
639                 spin_unlock(&dev->gnd_fmablk_lock);
640                 return -ESTALE;
641         }
642
643         live = fmablk->gnm_hold_timeout == 0;
644         /* none are available if it isn't live... */
645         avail_mboxs = live ? fmablk->gnm_avail_mboxs : 0;
646         held_mboxs = fmablk->gnm_held_mboxs;
647         num_mboxs = fmablk->gnm_num_mboxs;
648         blk_size = fmablk->gnm_blk_size;
649         state = fmablk->gnm_state;
650         hndl.qword1 = fmablk->gnm_hndl.qword1;
651         hndl.qword2 = fmablk->gnm_hndl.qword2;
652
653         spin_unlock(&dev->gnd_fmablk_lock);
654
655         if (live) {
656                 seq_printf(s, "%5d %4s %6d/%5d/%5d %9d %18p   "LPX64"."LPX64"\n",
657                            (int) gseq->gsmsg_off, kgnilnd_fmablk_state2str(state),
658                            avail_mboxs, held_mboxs, num_mboxs, blk_size,
659                            fmablk, hndl.qword1, hndl.qword2);
660         } else {
661                 seq_printf(s, "%5d %4s %6d/%5d/%5d %9d %18p %37s\n",
662                            (int) gseq->gsmsg_off, kgnilnd_fmablk_state2str(state),
663                            avail_mboxs, held_mboxs, num_mboxs, blk_size,
664                            fmablk, "PURGATORY.HOLD");
665         }
666
667         return 0;
668 }
669
670 static struct seq_operations kgn_smsg_sops = {
671         .start = kgnilnd_smsg_seq_start,
672         .stop  = kgnilnd_smsg_seq_stop,
673         .next  = kgnilnd_smsg_seq_next,
674         .show  = kgnilnd_smsg_seq_show,
675
676 };
677
678 static int
679 kgnilnd_smsg_seq_open(struct inode *inode, struct file *file)
680 {
681         struct proc_dir_entry *dp = PDE(inode);
682         struct seq_file       *sf;
683         int                    rc;
684
685         rc = seq_open(file, &kgn_smsg_sops);
686         if (rc == 0) {
687                 sf = file->private_data;
688                 sf->private = dp->data;
689         }
690
691         return rc;
692 }
693
694 static struct file_operations kgn_smsg_fops = {
695         .owner   = THIS_MODULE,
696         .open    = kgnilnd_smsg_seq_open,
697         .read    = seq_read,
698         .llseek  = seq_lseek,
699         .release = seq_release,
700 };
701
702 typedef struct {
703         __u64                   gconn_version;
704         struct list_head       *gconn_list;
705         kgn_conn_t             *gconn_conn;
706         loff_t                  gconn_off;
707         int                     gconn_hashidx;
708 } kgn_conn_seq_iter_t;
709
710 int
711 kgnilnd_conn_seq_seek(kgn_conn_seq_iter_t *gseq, loff_t off)
712 {
713         struct list_head       *list, *tmp;
714         loff_t                  here = 0;
715         int                     rc = 0;
716
717         if (off == 0) {
718                 gseq->gconn_hashidx = 0;
719                 gseq->gconn_list = NULL;
720         }
721
722         if (off > atomic_read(&kgnilnd_data.kgn_nconns)) {
723                 gseq->gconn_list = NULL;
724                 rc = -ENOENT;
725         }
726
727         read_lock(&kgnilnd_data.kgn_peer_conn_lock);
728         if (gseq->gconn_list != NULL &&
729                 gseq->gconn_version != kgnilnd_data.kgn_conn_version) {
730                 /* list changed */
731                 rc = -ESTALE;
732                 goto out;
733         }
734
735         if ((gseq->gconn_list == NULL) ||
736                 (gseq->gconn_off > off) ||
737                 (gseq->gconn_hashidx >= *kgnilnd_tunables.kgn_peer_hash_size)) {
738                 /* search from start */
739                 gseq->gconn_hashidx = 0;
740                 list = &kgnilnd_data.kgn_conns[gseq->gconn_hashidx];
741                 here = 0;
742         } else {
743                 /* continue current search */
744                 list = gseq->gconn_list;
745         }
746
747         gseq->gconn_version = kgnilnd_data.kgn_conn_version;
748         gseq->gconn_off = off;
749
750 start_list:
751
752         list_for_each(tmp, list) {
753                 if (here == off) {
754                         kgn_conn_t *conn;
755                         conn = list_entry(tmp, kgn_conn_t, gnc_hashlist);
756                         gseq->gconn_conn = conn;
757                         rc = 0;
758                         goto out;
759                 }
760                 here++;
761         }
762         /* if we got through this hash bucket with 'off' still to go, try next*/
763         gseq->gconn_hashidx++;
764         if ((here <= off) &&
765                 (gseq->gconn_hashidx < *kgnilnd_tunables.kgn_peer_hash_size)) {
766                 list = &kgnilnd_data.kgn_conns[gseq->gconn_hashidx];
767                 goto start_list;
768         }
769
770         gseq->gconn_list = NULL;
771         rc = -ENOENT;
772 out:
773         read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
774         return rc;
775 }
776
777 static void *
778 kgnilnd_conn_seq_start(struct seq_file *s, loff_t *pos)
779 {
780
781         kgn_conn_seq_iter_t     *gseq;
782         int                      rc;
783
784         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
785                 return NULL;
786         }
787
788         LIBCFS_ALLOC(gseq, sizeof(*gseq));
789         if (gseq == NULL) {
790                 CERROR("could not allocate conn sequence iterator\n");
791                 return NULL;
792         }
793
794         /* only doing device 0 for now */
795         gseq->gconn_list = NULL;
796         rc = kgnilnd_conn_seq_seek(gseq, *pos);
797         if (rc == 0)
798                 return gseq;
799
800         LIBCFS_FREE(gseq, sizeof(*gseq));
801         return NULL;
802 }
803
804 static void
805 kgnilnd_conn_seq_stop(struct seq_file *s, void *iter)
806 {
807         kgn_conn_seq_iter_t     *gseq = iter;
808
809         if (gseq != NULL)
810                 LIBCFS_FREE(gseq, sizeof(*gseq));
811 }
812
813 static void *
814 kgnilnd_conn_seq_next(struct seq_file *s, void *iter, loff_t *pos)
815 {
816         kgn_conn_seq_iter_t    *gseq = iter;
817         int                     rc;
818         loff_t                  next = *pos + 1;
819
820         rc = kgnilnd_conn_seq_seek(gseq, next);
821         if (rc != 0) {
822                 LIBCFS_FREE(gseq, sizeof(*gseq));
823                 return NULL;
824         }
825         *pos = next;
826         return gseq;
827 }
828
829 static int
830 kgnilnd_conn_seq_show(struct seq_file *s, void *iter)
831 {
832         kgn_conn_seq_iter_t    *gseq = iter;
833         kgn_peer_t             *peer = NULL;
834         kgn_conn_t             *conn;
835
836         /* there is no header data for conns, so offset 0 is the first
837          * real entry. */
838
839         conn = gseq->gconn_conn;
840         LASSERT(conn != NULL);
841
842         read_lock(&kgnilnd_data.kgn_peer_conn_lock);
843         if (gseq->gconn_list != NULL &&
844                 gseq->gconn_version != kgnilnd_data.kgn_conn_version) {
845                 /* list changed */
846                 read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
847                 return -ESTALE;
848         }
849
850         /* instead of saving off the data, just refcount */
851         kgnilnd_conn_addref(conn);
852         if (conn->gnc_peer) {
853                 /* don't use link - after unlock it could get nuked */
854                 peer = conn->gnc_peer;
855                 kgnilnd_peer_addref(peer);
856         }
857
858         read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
859
860         seq_printf(s, "%p->%s [%d] q %d/%d/%d "
861                 "tx sq %u %dms/%dms "
862                 "rx sq %u %dms/%dms "
863                 "noop r/s %d/%d w/s/cq %lds/%lds/%lds "
864                 "sched a/d %lds/%lds "
865                 "tx_re "LPD64" TO %ds %s\n",
866                 conn, peer ? libcfs_nid2str(peer->gnp_nid) : "<?>",
867                 atomic_read(&conn->gnc_refcount),
868                 kgnilnd_count_list(&conn->gnc_fmaq),
869                 atomic_read(&conn->gnc_nlive_fma),
870                 atomic_read(&conn->gnc_nlive_rdma),
871                 conn->gnc_tx_seq,
872                 jiffies_to_msecs(jiffies - conn->gnc_last_tx),
873                 jiffies_to_msecs(jiffies - conn->gnc_last_tx_cq),
874                 conn->gnc_rx_seq,
875                 jiffies_to_msecs(jiffies - conn->gnc_last_rx),
876                 jiffies_to_msecs(jiffies - conn->gnc_last_rx_cq),
877                 atomic_read(&conn->gnc_reaper_noop),
878                 atomic_read(&conn->gnc_sched_noop),
879                 cfs_duration_sec(jiffies - conn->gnc_last_noop_want),
880                 cfs_duration_sec(jiffies - conn->gnc_last_noop_sent),
881                 cfs_duration_sec(jiffies - conn->gnc_last_noop_cq),
882                 cfs_duration_sec(jiffies - conn->gnc_last_sched_ask),
883                 cfs_duration_sec(jiffies - conn->gnc_last_sched_do),
884                 conn->gnc_tx_retrans, conn->gnc_timeout,
885                 kgnilnd_conn_state2str(conn));
886
887         if (peer)
888                 kgnilnd_peer_decref(peer);
889         kgnilnd_conn_decref(conn);
890
891         return 0;
892 }
893
894 static struct seq_operations kgn_conn_sops = {
895         .start = kgnilnd_conn_seq_start,
896         .stop  = kgnilnd_conn_seq_stop,
897         .next  = kgnilnd_conn_seq_next,
898         .show  = kgnilnd_conn_seq_show,
899
900 };
901
902 static int
903 kgnilnd_conn_seq_open(struct inode *inode, struct file *file)
904 {
905         struct proc_dir_entry *dp = PDE(inode);
906         struct seq_file       *sf;
907         int                    rc;
908
909         rc = seq_open(file, &kgn_conn_sops);
910         if (rc == 0) {
911                 sf = file->private_data;
912                 sf->private = dp->data;
913         }
914
915         return rc;
916 }
917
918 static struct file_operations kgn_conn_fops = {
919         .owner   = THIS_MODULE,
920         .open    = kgnilnd_conn_seq_open,
921         .read    = seq_read,
922         .llseek  = seq_lseek,
923         .release = seq_release,
924 };
925
926 typedef struct {
927         __u64                   gpeer_version;
928         struct list_head       *gpeer_list;
929         kgn_peer_t             *gpeer_peer;
930         loff_t                  gpeer_off;
931         int                     gpeer_hashidx;
932 } kgn_peer_seq_iter_t;
933
934 int
935 kgnilnd_peer_seq_seek(kgn_peer_seq_iter_t *gseq, loff_t off)
936 {
937         struct list_head       *list, *tmp;
938         loff_t                  here = 0;
939         int                     rc = 0;
940
941         if (off == 0) {
942                 gseq->gpeer_hashidx = 0;
943                 gseq->gpeer_list = NULL;
944         }
945
946         if (off > atomic_read(&kgnilnd_data.kgn_npeers)) {
947                 gseq->gpeer_list = NULL;
948                 rc = -ENOENT;
949         }
950
951         read_lock(&kgnilnd_data.kgn_peer_conn_lock);
952         if (gseq->gpeer_list != NULL &&
953                 gseq->gpeer_version != kgnilnd_data.kgn_peer_version) {
954                 /* list changed */
955                 rc = -ESTALE;
956                 goto out;
957         }
958
959         if ((gseq->gpeer_list == NULL) ||
960                 (gseq->gpeer_off > off) ||
961                 (gseq->gpeer_hashidx >= *kgnilnd_tunables.kgn_peer_hash_size)) {
962                 /* search from start */
963                 gseq->gpeer_hashidx = 0;
964                 list = &kgnilnd_data.kgn_peers[gseq->gpeer_hashidx];
965                 here = 0;
966         } else {
967                 /* continue current search */
968                 list = gseq->gpeer_list;
969         }
970
971         gseq->gpeer_version = kgnilnd_data.kgn_peer_version;
972         gseq->gpeer_off = off;
973
974 start_list:
975
976         list_for_each(tmp, list) {
977                 if (here == off) {
978                         kgn_peer_t *peer;
979                         peer = list_entry(tmp, kgn_peer_t, gnp_list);
980                         gseq->gpeer_peer = peer;
981                         rc = 0;
982                         goto out;
983                 }
984                 here++;
985         }
986         /* if we got through this hash bucket with 'off' still to go, try next*/
987         gseq->gpeer_hashidx++;
988         if ((here <= off) &&
989                 (gseq->gpeer_hashidx < *kgnilnd_tunables.kgn_peer_hash_size)) {
990                 list = &kgnilnd_data.kgn_peers[gseq->gpeer_hashidx];
991                 goto start_list;
992         }
993
994         gseq->gpeer_list = NULL;
995         rc = -ENOENT;
996 out:
997         read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
998         return rc;
999 }
1000
1001 static void *
1002 kgnilnd_peer_seq_start(struct seq_file *s, loff_t *pos)
1003 {
1004
1005         kgn_peer_seq_iter_t     *gseq;
1006         int                      rc;
1007
1008         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
1009                 return NULL;
1010         }
1011
1012         LIBCFS_ALLOC(gseq, sizeof(*gseq));
1013         if (gseq == NULL) {
1014                 CERROR("could not allocate peer sequence iterator\n");
1015                 return NULL;
1016         }
1017
1018         /* only doing device 0 for now */
1019         gseq->gpeer_list = NULL;
1020         rc = kgnilnd_peer_seq_seek(gseq, *pos);
1021         if (rc == 0)
1022                 return gseq;
1023
1024         LIBCFS_FREE(gseq, sizeof(*gseq));
1025         return NULL;
1026 }
1027
1028 static void
1029 kgnilnd_peer_seq_stop(struct seq_file *s, void *iter)
1030 {
1031         kgn_peer_seq_iter_t     *gseq = iter;
1032
1033         if (gseq != NULL)
1034                 LIBCFS_FREE(gseq, sizeof(*gseq));
1035 }
1036
1037 static void *
1038 kgnilnd_peer_seq_next(struct seq_file *s, void *iter, loff_t *pos)
1039 {
1040         kgn_peer_seq_iter_t    *gseq = iter;
1041         int                     rc;
1042         loff_t                  next = *pos + 1;
1043
1044         rc = kgnilnd_peer_seq_seek(gseq, next);
1045         if (rc != 0) {
1046                 LIBCFS_FREE(gseq, sizeof(*gseq));
1047                 return NULL;
1048         }
1049         *pos = next;
1050         return gseq;
1051 }
1052
1053 static int
1054 kgnilnd_peer_seq_show(struct seq_file *s, void *iter)
1055 {
1056         kgn_peer_seq_iter_t    *gseq = iter;
1057         kgn_peer_t             *peer;
1058         kgn_conn_t             *conn;
1059         char                   conn_str;
1060         int                    purg_count = 0;
1061         /* there is no header data for peers, so offset 0 is the first
1062          * real entry. */
1063
1064         peer = gseq->gpeer_peer;
1065         LASSERT(peer != NULL);
1066
1067         read_lock(&kgnilnd_data.kgn_peer_conn_lock);
1068         if (gseq->gpeer_list != NULL &&
1069                 gseq->gpeer_version != kgnilnd_data.kgn_peer_version) {
1070                 /* list changed */
1071                 read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
1072                 return -ESTALE;
1073         }
1074
1075         /* instead of saving off the data, just refcount */
1076         kgnilnd_peer_addref(peer);
1077         conn = kgnilnd_find_conn_locked(peer);
1078
1079         if (peer->gnp_connecting) {
1080                 conn_str = 'S';
1081         } else if (conn != NULL) {
1082                 conn_str = 'C';
1083         } else {
1084                 conn_str = 'D';
1085         }
1086
1087         list_for_each_entry(conn, &peer->gnp_conns, gnc_list) {
1088                 if (conn->gnc_in_purgatory) {
1089                         purg_count++;
1090                 }
1091         }
1092
1093         read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
1094
1095         seq_printf(s, "%p->%s [%d] NIC 0x%x q %d conn %c purg %d "
1096                 "last %d@%dms dgram %d@%dms "
1097                 "reconn %dms to %lus \n",
1098                 peer, libcfs_nid2str(peer->gnp_nid),
1099                 atomic_read(&peer->gnp_refcount),
1100                 peer->gnp_host_id,
1101                 kgnilnd_count_list(&peer->gnp_tx_queue),
1102                 conn_str,
1103                 purg_count,
1104                 peer->gnp_last_errno,
1105                 jiffies_to_msecs(jiffies - peer->gnp_last_alive),
1106                 peer->gnp_last_dgram_errno,
1107                 jiffies_to_msecs(jiffies - peer->gnp_last_dgram_time),
1108                 peer->gnp_reconnect_interval != 0
1109                         ? jiffies_to_msecs(jiffies - peer->gnp_reconnect_time)
1110                         : 0,
1111                 peer->gnp_reconnect_interval);
1112
1113         kgnilnd_peer_decref(peer);
1114
1115         return 0;
1116 }
1117
1118 static struct seq_operations kgn_peer_sops = {
1119         .start = kgnilnd_peer_seq_start,
1120         .stop  = kgnilnd_peer_seq_stop,
1121         .next  = kgnilnd_peer_seq_next,
1122         .show  = kgnilnd_peer_seq_show,
1123 };
1124
1125 static int
1126 kgnilnd_peer_seq_open(struct inode *inode, struct file *file)
1127 {
1128         struct proc_dir_entry *dp = PDE(inode);
1129         struct seq_file       *sf;
1130         int                    rc;
1131
1132         rc = seq_open(file, &kgn_peer_sops);
1133         if (rc == 0) {
1134                 sf = file->private_data;
1135                 sf->private = dp->data;
1136         }
1137
1138         return rc;
1139 }
1140
1141 static struct file_operations kgn_peer_fops = {
1142         .owner   = THIS_MODULE,
1143         .open    = kgnilnd_peer_seq_open,
1144         .read    = seq_read,
1145         .llseek  = seq_lseek,
1146         .release = seq_release,
1147 };
1148
1149 static struct proc_dir_entry *kgn_proc_root;
1150
1151 void
1152 kgnilnd_proc_init(void)
1153 {
1154         struct proc_dir_entry *pde;
1155         int             rc = 0;
1156         ENTRY;
1157
1158         /* setup dir */
1159         kgn_proc_root = proc_mkdir(libcfs_lnd2modname(GNILND), NULL);
1160         if (kgn_proc_root == NULL) {
1161                 CERROR("couldn't create proc dir %s\n",
1162                         libcfs_lnd2modname(GNILND));
1163                 return;
1164         }
1165
1166         /* Initialize CKSUM_TEST */
1167         pde = create_proc_entry(GNILND_PROC_CKSUM_TEST, 0200, kgn_proc_root);
1168         if (pde == NULL) {
1169                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_CKSUM_TEST);
1170                 rc = -ENOENT;
1171                 GOTO(remove_dir, rc);
1172         }
1173
1174         pde->data = NULL;
1175         pde->write_proc = kgnilnd_proc_cksum_test_write;
1176
1177         /* Initialize STATS */
1178         pde = create_proc_entry(GNILND_PROC_STATS, 0644, kgn_proc_root);
1179         if (pde == NULL) {
1180                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_STATS);
1181                 rc = -ENOENT;
1182                 GOTO(remove_test, rc);
1183         }
1184
1185         pde->data = NULL;
1186         pde->read_proc = kgnilnd_proc_stats_read;
1187         pde->write_proc = kgnilnd_proc_stats_write;
1188
1189         /* Initialize MDD */
1190         pde = create_proc_entry(GNILND_PROC_MDD, 0444, kgn_proc_root);
1191         if (pde == NULL) {
1192                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_MDD);
1193                 rc = -ENOENT;
1194                 GOTO(remove_stats, rc);
1195         }
1196
1197         pde->data = NULL;
1198         pde->proc_fops = &kgn_mdd_fops;
1199
1200         /* Initialize SMSG */
1201         pde = create_proc_entry(GNILND_PROC_SMSG, 0444, kgn_proc_root);
1202         if (pde == NULL) {
1203                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_SMSG);
1204                 rc = -ENOENT;
1205                 GOTO(remove_mdd, rc);
1206         }
1207
1208         pde->data = NULL;
1209         pde->proc_fops = &kgn_smsg_fops;
1210
1211         /* Initialize CONN */
1212         pde = create_proc_entry(GNILND_PROC_CONN, 0444, kgn_proc_root);
1213         if (pde == NULL) {
1214                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_CONN);
1215                 rc = -ENOENT;
1216                 GOTO(remove_smsg, rc);
1217         }
1218
1219         pde->data = NULL;
1220         pde->proc_fops = &kgn_conn_fops;
1221
1222         /* Initialize PEER */
1223         pde = create_proc_entry(GNILND_PROC_PEER, 0444, kgn_proc_root);
1224         if (pde == NULL) {
1225                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_PEER);
1226                 rc = -ENOENT;
1227                 GOTO(remove_conn, rc);
1228         }
1229
1230         pde->data = NULL;
1231         pde->proc_fops = &kgn_peer_fops;
1232         RETURN_EXIT;
1233
1234 remove_conn:
1235         remove_proc_entry(GNILND_PROC_CONN, kgn_proc_root);
1236 remove_smsg:
1237         remove_proc_entry(GNILND_PROC_SMSG, kgn_proc_root);
1238 remove_mdd:
1239         remove_proc_entry(GNILND_PROC_MDD, kgn_proc_root);
1240 remove_stats:
1241         remove_proc_entry(GNILND_PROC_STATS, kgn_proc_root);
1242 remove_test:
1243         remove_proc_entry(GNILND_PROC_CKSUM_TEST, kgn_proc_root);
1244 remove_dir:
1245         remove_proc_entry(kgn_proc_root->name, NULL);
1246
1247         RETURN_EXIT;
1248 }
1249
1250 void
1251 kgnilnd_proc_fini(void)
1252 {
1253         remove_proc_entry(GNILND_PROC_PEER, kgn_proc_root);
1254         remove_proc_entry(GNILND_PROC_CONN, kgn_proc_root);
1255         remove_proc_entry(GNILND_PROC_MDD, kgn_proc_root);
1256         remove_proc_entry(GNILND_PROC_SMSG, kgn_proc_root);
1257         remove_proc_entry(GNILND_PROC_STATS, kgn_proc_root);
1258         remove_proc_entry(GNILND_PROC_CKSUM_TEST, kgn_proc_root);
1259         remove_proc_entry(kgn_proc_root->name, NULL);
1260 }