Whamcloud - gitweb
- mxlnd updates from upstream.
[fs/lustre-release.git] / lnet / klnds / mxlnd / mxlnd.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2004 Cluster File Systems, Inc.
5  *   Author: Eric Barton <eric@bartonsoftware.com>
6  * Copyright (C) 2006 Myricom, Inc.
7  *   Author: Scott Atchley <atchley at myri.com>
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include "mxlnd.h"
26
27 lnd_t the_kmxlnd = {
28         .lnd_type       = MXLND,
29         .lnd_startup    = mxlnd_startup,
30         .lnd_shutdown   = mxlnd_shutdown,
31         .lnd_ctl        = mxlnd_ctl,
32         .lnd_send       = mxlnd_send,
33         .lnd_recv       = mxlnd_recv,
34 };
35
36 kmx_data_t               kmxlnd_data;
37
38 /**
39  * mxlnd_ctx_free - free ctx struct
40  * @ctx - a kmx_peer pointer
41  *
42  * The calling function should remove the ctx from the ctx list first
43  * then free it.
44  */
45 void
46 mxlnd_ctx_free(struct kmx_ctx *ctx)
47 {
48         if (ctx == NULL) return;
49
50         if (ctx->mxc_page != NULL) {
51                 __free_page(ctx->mxc_page);
52                 spin_lock(&kmxlnd_data.kmx_global_lock);
53                 kmxlnd_data.kmx_mem_used -= MXLND_EAGER_SIZE;
54                 spin_unlock(&kmxlnd_data.kmx_global_lock);
55         }
56
57         if (ctx->mxc_seg_list != NULL) {
58                 LASSERT(ctx->mxc_nseg > 0);
59                 MXLND_FREE(ctx->mxc_seg_list, ctx->mxc_nseg * sizeof(mx_ksegment_t));
60         }
61
62         MXLND_FREE (ctx, sizeof (*ctx));
63         return;
64 }
65
66 /**
67  * mxlnd_ctx_alloc - allocate and initialize a new ctx struct
68  * @ctxp - address of a kmx_ctx pointer
69  *
70  * Returns 0 on success and -EINVAL, -ENOMEM on failure
71  */
72 int
73 mxlnd_ctx_alloc(struct kmx_ctx **ctxp, enum kmx_req_type type)
74 {
75         int             ret     = 0;
76         struct kmx_ctx  *ctx    = NULL;
77
78         if (ctxp == NULL) return -EINVAL;
79
80         MXLND_ALLOC(ctx, sizeof (*ctx));
81         if (ctx == NULL) {
82                 CDEBUG(D_NETERROR, "Cannot allocate ctx\n");
83                 return -ENOMEM;
84         }
85         memset(ctx, 0, sizeof(*ctx));
86         spin_lock_init(&ctx->mxc_lock);
87
88         ctx->mxc_type = type;
89         ctx->mxc_page = alloc_page (GFP_KERNEL);
90         if (ctx->mxc_page == NULL) {
91                 CDEBUG(D_NETERROR, "Can't allocate page\n");
92                 ret = -ENOMEM;
93                 goto failed;
94         }
95         spin_lock(&kmxlnd_data.kmx_global_lock);
96         kmxlnd_data.kmx_mem_used += MXLND_EAGER_SIZE;
97         spin_unlock(&kmxlnd_data.kmx_global_lock);
98         ctx->mxc_msg = (struct kmx_msg *)((char *)page_address(ctx->mxc_page));
99         ctx->mxc_seg.segment_ptr = MX_PA_TO_U64(lnet_page2phys(ctx->mxc_page));
100         ctx->mxc_state = MXLND_CTX_IDLE;
101
102         *ctxp = ctx;
103         return 0;
104
105 failed:
106         mxlnd_ctx_free(ctx);
107         return ret;
108 }
109
110 /**
111  * mxlnd_ctx_init - reset ctx struct to the default values
112  * @ctx - a kmx_ctx pointer
113  */
114 void
115 mxlnd_ctx_init(struct kmx_ctx *ctx)
116 {
117         if (ctx == NULL) return;
118
119         /* do not change mxc_type */
120         ctx->mxc_incarnation = 0;
121         ctx->mxc_deadline = 0;
122         ctx->mxc_state = MXLND_CTX_IDLE;
123         /* ignore mxc_global_list */
124         if (ctx->mxc_list.next != NULL && !list_empty(&ctx->mxc_list)) {
125                 if (ctx->mxc_peer != NULL) spin_lock(&ctx->mxc_lock);
126                 list_del_init(&ctx->mxc_list);
127                 if (ctx->mxc_peer != NULL) spin_unlock(&ctx->mxc_lock);
128         }
129         /* ignore mxc_rx_list */
130         /* ignore mxc_lock */
131         ctx->mxc_nid = 0;
132         ctx->mxc_peer = NULL;
133         ctx->mxc_conn = NULL;
134         /* ignore mxc_msg */
135         /* ignore mxc_page */
136         ctx->mxc_lntmsg[0] = NULL;
137         ctx->mxc_lntmsg[1] = NULL;
138         ctx->mxc_msg_type = 0;
139         ctx->mxc_cookie = 0LL;
140         ctx->mxc_match = 0LL;
141         /* ctx->mxc_seg.segment_ptr points to mxc_page */
142         ctx->mxc_seg.segment_length = 0;
143         if (ctx->mxc_seg_list != NULL) {
144                 LASSERT(ctx->mxc_nseg > 0);
145                 MXLND_FREE(ctx->mxc_seg_list, ctx->mxc_nseg * sizeof(mx_ksegment_t));
146         }
147         ctx->mxc_seg_list = NULL;
148         ctx->mxc_nseg = 0;
149         ctx->mxc_nob = 0;
150         ctx->mxc_mxreq = NULL;
151         memset(&ctx->mxc_status, 0, sizeof(mx_status_t));
152         /* ctx->mxc_get */
153         /* ctx->mxc_put */
154
155         ctx->mxc_msg->mxm_type = 0;
156         ctx->mxc_msg->mxm_credits = 0;
157         ctx->mxc_msg->mxm_nob = 0;
158         ctx->mxc_msg->mxm_seq = 0;
159
160         return;
161 }
162
163 /**
164  * mxlnd_free_txs - free kmx_txs and associated pages
165  *
166  * Called from mxlnd_shutdown()
167  */
168 void
169 mxlnd_free_txs(void)
170 {
171         struct kmx_ctx          *tx     = NULL;
172         struct kmx_ctx          *next   = NULL;
173
174         list_for_each_entry_safe(tx, next, &kmxlnd_data.kmx_txs, mxc_global_list) {
175                 list_del_init(&tx->mxc_global_list);
176                 mxlnd_ctx_free(tx);
177         }
178         return;
179 }
180
181 /**
182  * mxlnd_init_txs - allocate tx descriptors then stash on txs and idle tx lists
183  *
184  * Called from mxlnd_startup()
185  * returns 0 on success, else -ENOMEM
186  */
187 int
188 mxlnd_init_txs(void)
189 {
190         int             ret     = 0;
191         int             i       = 0;
192         struct kmx_ctx  *tx      = NULL;
193
194         for (i = 0; i < *kmxlnd_tunables.kmx_ntx; i++) {
195                 ret = mxlnd_ctx_alloc(&tx, MXLND_REQ_TX);
196                 if (ret != 0) {
197                         mxlnd_free_txs();
198                         return ret;
199                 }
200                 mxlnd_ctx_init(tx);
201                 /* in startup(), no locks required */
202                 list_add_tail(&tx->mxc_global_list, &kmxlnd_data.kmx_txs);
203                 list_add_tail(&tx->mxc_list, &kmxlnd_data.kmx_tx_idle);
204         }
205         return 0;
206 }
207
208 /**
209  * mxlnd_free_rxs - free initial kmx_rx descriptors and associated pages
210  *
211  * Called from mxlnd_shutdown()
212  */
213 void
214 mxlnd_free_rxs(void)
215 {
216         struct kmx_ctx          *rx     = NULL;
217         struct kmx_ctx          *next   = NULL;
218
219         list_for_each_entry_safe(rx, next, &kmxlnd_data.kmx_rxs, mxc_global_list) {
220                 list_del_init(&rx->mxc_global_list);
221                 mxlnd_ctx_free(rx);
222         }
223         return;
224 }
225
226 /**
227  * mxlnd_init_rxs - allocate initial rx descriptors 
228  *
229  * Called from startup(). We create MXLND_MAX_PEERS plus MXLND_NTX
230  * rx descriptors. We create one for each potential peer to handle 
231  * the initial connect request. We create on for each tx in case the 
232  * send requires a non-eager receive.
233  *
234  * Returns 0 on success, else -ENOMEM
235  */
236 int
237 mxlnd_init_rxs(void)
238 {
239         int             ret     = 0;
240         int             i       = 0;
241         struct kmx_ctx  *rx      = NULL;
242
243         for (i = 0; i < (*kmxlnd_tunables.kmx_ntx + *kmxlnd_tunables.kmx_max_peers); i++) {
244                 ret = mxlnd_ctx_alloc(&rx, MXLND_REQ_RX);
245                 if (ret != 0) {
246                         mxlnd_free_rxs();
247                         return ret;
248                 }
249                 mxlnd_ctx_init(rx);
250                 /* in startup(), no locks required */
251                 list_add_tail(&rx->mxc_global_list, &kmxlnd_data.kmx_rxs);
252                 list_add_tail(&rx->mxc_list, &kmxlnd_data.kmx_rx_idle);
253         }
254         return 0;
255 }
256
257 /**
258  * mxlnd_free_peers - free peers
259  *
260  * Called from mxlnd_shutdown()
261  */
262 void
263 mxlnd_free_peers(void)
264 {
265         int                      i      = 0;
266         struct kmx_peer         *peer   = NULL;
267         struct kmx_peer         *next   = NULL;
268
269         for (i = 0; i < MXLND_HASH_SIZE; i++) {
270                 list_for_each_entry_safe(peer, next, &kmxlnd_data.kmx_peers[i], mxp_peers) {
271                         list_del_init(&peer->mxp_peers);
272                         if (peer->mxp_conn) mxlnd_conn_decref(peer->mxp_conn);
273                         mxlnd_peer_decref(peer);
274                 }
275         }
276 }
277
278 int
279 mxlnd_host_alloc(struct kmx_host **hostp)
280 {
281         struct kmx_host *host   = NULL;
282
283         MXLND_ALLOC(host, sizeof (*host));
284         if (host == NULL) {
285                 CDEBUG(D_NETERROR, "Cannot allocate host\n");
286                 return -1;
287         }
288         memset(host, 0, sizeof(*host));
289         spin_lock_init(&host->mxh_lock);
290
291         *hostp = host;
292
293         return 0;
294 }
295
296 void
297 mxlnd_host_free(struct kmx_host *host)
298 {
299         if (host == NULL) return;
300
301         if (host->mxh_hostname != NULL)
302                 MXLND_FREE(host->mxh_hostname, strlen(host->mxh_hostname) + 1);
303
304         MXLND_FREE(host, sizeof(*host));
305         return;
306 }
307
308 /**
309  * mxlnd_free_hosts - free kmx_hosts
310  *
311  * Called from mxlnd_shutdown()
312  */
313 void
314 mxlnd_free_hosts(void)
315 {
316         struct kmx_host         *host   = NULL;
317         struct kmx_host         *next   = NULL;
318
319         list_for_each_entry_safe(host, next, &kmxlnd_data.kmx_hosts, mxh_list) {
320                 list_del_init(&host->mxh_list);
321                 mxlnd_host_free(host);
322         }
323         return;
324 }
325
326 #define xstr(s) #s
327 #define str(s) xstr(s)
328 #define MXLND_MAX_BOARD 4       /* we expect hosts to have fewer NICs than this */
329 #define MXLND_MAX_EP_ID 16      /* we expect hosts to have less than this endpoints */
330
331 /* this parses a line that consists of:
332  * 
333  * IP              HOSTNAME           BOARD        ENDPOINT ID
334  * 169.192.0.113   mds01              0            3
335  * 
336  * By default MX uses the alias (short hostname). If you override
337  * it using mx_hostname to use the FQDN or some other name, the hostname
338  * here must match exactly.
339  */
340
341 /* MX_MAX_HOSTNAME_LEN = 80. See myriexpress.h */
342 int
343 mxlnd_parse_line(char *line)
344 {
345         int             i               = 0;
346         int             ret             = 0;
347         int             len             = 0;
348         u32             ip[4]           = { 0, 0, 0, 0 };
349         char            hostname[MX_MAX_HOSTNAME_LEN];
350         u32             board           = -1;
351         u32             ep_id           = -1;
352         struct kmx_host *host           = NULL;
353
354         if (line == NULL) return -1;
355
356         len = strlen(line);
357
358         if (len == 0) return -1;
359
360         /* convert tabs to spaces */
361         for (i = 0; i < len; i++) {
362                 if (line[i] == '\t') line[i] = ' ';
363         }
364
365         memset(&hostname, 0 , sizeof(hostname));
366         ret = sscanf(line, "%d.%d.%d.%d %" str(MX_MAX_HOSTNAME_LEN) "s %d %d", 
367                      &ip[0], &ip[1], &ip[2], &ip[3], hostname, &board, &ep_id);
368
369         if (ret != 7) {
370                 return -1;
371         }
372
373         /* check for valid values */
374         /* we assume a valid IP address (all <= 255), number of NICs,
375          * and number of endpoint IDs */
376         if (ip[0] > 255 || ip [1] > 255 || ip[2] > 255 || ip[3] > 255 ||
377             board > MXLND_MAX_BOARD || ep_id > MXLND_MAX_EP_ID) {
378                 CDEBUG(D_NETERROR, "Illegal value in \"%s\". Ignoring "
379                                    "this host.\n", line);
380                 return -1;
381         }
382
383         ret = mxlnd_host_alloc(&host);
384         if (ret != 0) return -1;
385
386         host->mxh_addr = ((ip[0]<<24)|(ip[1]<<16)|(ip[2]<<8)|ip[3]);
387         len = strlen(hostname);
388         MXLND_ALLOC(host->mxh_hostname, len + 1);
389         if (host->mxh_hostname == NULL) {
390                 mxlnd_host_free(host);
391                 return -ENOMEM;
392         }
393         memset(host->mxh_hostname, 0, len + 1);
394         strncpy(host->mxh_hostname, hostname, len);
395         host->mxh_board = board;
396         host->mxh_ep_id = ep_id;
397
398         spin_lock(&kmxlnd_data.kmx_hosts_lock);
399         list_add_tail(&host->mxh_list, &kmxlnd_data.kmx_hosts);
400         spin_unlock(&kmxlnd_data.kmx_hosts_lock);
401
402         return 0;
403 }
404
405 void
406 mxlnd_print_hosts(void)
407 {
408 #if MXLND_DEBUG
409         struct kmx_host         *host   = NULL;
410
411         list_for_each_entry(host, &kmxlnd_data.kmx_hosts, mxh_list) {
412                 int             ip[4];
413                 u32             addr    = host->mxh_addr;
414
415                 ip[0] = (addr >> 24) & 0xff;
416                 ip[1] = (addr >> 16) & 0xff;
417                 ip[2] = (addr >>  8) & 0xff;
418                 ip[3] = addr & 0xff;
419                 CDEBUG(D_NET, "\tip= %d.%d.%d.%d\n\thost= %s\n\tboard= %d\n\tep_id= %d\n\n",
420                             ip[0], ip[1], ip[2], ip[3],
421                             host->mxh_hostname, host->mxh_board, host->mxh_ep_id);
422         }
423 #endif
424         return;
425 }
426
427 #define MXLND_BUFSIZE (PAGE_SIZE - 1)
428
429 int
430 mxlnd_parse_hosts(char *filename)
431 {
432         int             ret             = 0;
433         s32             size            = 0;
434         s32             bufsize         = MXLND_BUFSIZE;
435         s32             allocd          = 0;
436         loff_t          offset          = 0;
437         struct file     *filp           = NULL;
438         struct inode    *inode          = NULL;
439         char            *buf            = NULL;
440         s32             buf_off         = 0;
441         char            *sep            = NULL;
442         char            *line           = NULL;
443
444         if (filename == NULL) return -1;
445
446         filp = filp_open(filename, O_RDONLY, 0);
447         if (IS_ERR(filp)) {
448                 CERROR("filp_open() failed for %s\n", filename);
449                 return -1;
450         }
451
452         inode = filp->f_dentry->d_inode;
453         if (!S_ISREG(inode->i_mode)) {
454                 CERROR("%s is not a regular file\n", filename);
455                 return -1;
456         }
457
458         size = (s32) inode->i_size;
459         if (size < MXLND_BUFSIZE) bufsize = size;
460         allocd = bufsize;
461         MXLND_ALLOC(buf, allocd + 1);
462         if (buf == NULL) {
463                 CERROR("Cannot allocate buf\n");
464                 filp_close(filp, current->files);
465                 return -1;
466         }
467
468         while (offset < size) {
469                 memset(buf, 0, bufsize + 1);
470                 ret = kernel_read(filp, (unsigned long) offset, buf, (unsigned long) bufsize);
471                 if (ret < 0) {
472                         CDEBUG(D_NETERROR, "kernel_read() returned %d - closing %s\n", ret, filename);
473                         filp_close(filp, current->files);
474                         MXLND_FREE(buf, allocd + 1);
475                         return -1;
476                 }
477
478                 if (ret < bufsize) bufsize = ret;
479                 buf_off = 0;
480                 while (buf_off < bufsize) {
481                         sep = strchr(buf + buf_off, '\n');
482                         if (sep != NULL) {
483                                 /* we have a line */
484                                 line = buf + buf_off;
485                                 *sep = '\0';
486                                 ret = mxlnd_parse_line(line);
487                                 if (ret != 0 && strlen(line) != 0) {
488                                         CDEBUG(D_NETERROR, "Failed to parse \"%s\". Ignoring this host.\n", line);
489                                 }
490                                 buf_off += strlen(line) + 1;
491                         } else {
492                                 /* last line or we need to read more */
493                                 line = buf + buf_off;
494                                 ret = mxlnd_parse_line(line);
495                                 if (ret != 0) {
496                                         bufsize -= strlen(line) + 1;
497                                 }
498                                 buf_off += strlen(line) + 1;
499                         }
500                 }
501                 offset += bufsize;
502                 bufsize = MXLND_BUFSIZE;
503         }
504
505         MXLND_FREE(buf, allocd + 1);
506         filp_close(filp, current->files);
507         mxlnd_print_hosts();
508
509         return 0;
510 }
511
512 /**
513  * mxlnd_init_mx - open the endpoint, set out ID, register the EAGER callback
514  * @ni - the network interface
515  *
516  * Returns 0 on success, -1 on failure
517  */
518 int
519 mxlnd_init_mx(lnet_ni_t *ni)
520 {
521         int                     ret     = 0;
522         int                     found   = 0;
523         mx_return_t             mxret;
524         mx_endpoint_addr_t      addr;
525         u32                     board   = *kmxlnd_tunables.kmx_board;
526         u32                     ep_id   = *kmxlnd_tunables.kmx_ep_id;
527         u64                     nic_id  = 0LL;
528         struct kmx_host         *host   = NULL;
529
530         mxret = mx_init();
531         if (mxret != MX_SUCCESS) {
532                 CERROR("mx_init() failed with %s (%d)\n", mx_strerror(mxret), mxret);
533                 return -1;
534         }
535
536         ret = mxlnd_parse_hosts(*kmxlnd_tunables.kmx_hosts);
537         if (ret != 0) {
538                 if (*kmxlnd_tunables.kmx_hosts != NULL) {
539                         CERROR("mxlnd_parse_hosts(%s) failed\n", *kmxlnd_tunables.kmx_hosts);
540                 }
541                 mx_finalize();
542                 return -1;
543         }
544
545         list_for_each_entry(host, &kmxlnd_data.kmx_hosts, mxh_list) {
546                 if (strcmp(host->mxh_hostname, system_utsname.nodename) == 0) {
547                         /* override the defaults and module parameters with 
548                          * the info from the hosts file */
549                         board = host->mxh_board;
550                         ep_id = host->mxh_ep_id;
551                         kmxlnd_data.kmx_localhost = host;
552                         CDEBUG(D_NET, "my hostname is %s board %d ep_id %d\n", kmxlnd_data.kmx_localhost->mxh_hostname, kmxlnd_data.kmx_localhost->mxh_board, kmxlnd_data.kmx_localhost->mxh_ep_id);
553                         found = 1;
554                         break;
555                 }
556         }
557
558         if (found == 0) {
559                 CERROR("no host entry found for localhost\n");
560                 mx_finalize();
561                 return -1;
562         }
563
564         mxret = mx_open_endpoint(board, ep_id, MXLND_MSG_MAGIC, 
565                                  NULL, 0, &kmxlnd_data.kmx_endpt);
566         if (mxret != MX_SUCCESS) {
567                 CERROR("mx_open_endpoint() failed with %d\n", mxret);
568                 mx_finalize();
569                 return -1;
570         }
571
572         mx_get_endpoint_addr(kmxlnd_data.kmx_endpt, &addr);
573         mx_decompose_endpoint_addr(addr, &nic_id, &ep_id);
574
575         LASSERT(host != NULL);
576         ni->ni_nid = LNET_MKNID(LNET_NIDNET(ni->ni_nid), host->mxh_addr);
577
578         CDEBUG(D_NET, "My NID is 0x%llx\n", ni->ni_nid);
579
580         /* this will catch all unexpected receives. */
581         mxret = mx_register_unexp_handler(kmxlnd_data.kmx_endpt,
582                                           (mx_unexp_handler_t) mxlnd_unexpected_recv,
583                                           NULL);
584         if (mxret != MX_SUCCESS) {
585                 CERROR("mx_register_unexp_callback() failed with %s\n", 
586                          mx_strerror(mxret));
587                 mx_close_endpoint(kmxlnd_data.kmx_endpt);
588                 mx_finalize();
589                 return -1;
590         }
591         mxret = mx_set_request_timeout(kmxlnd_data.kmx_endpt, NULL, MXLND_COMM_TIMEOUT/HZ*1000);
592         if (mxret != MX_SUCCESS) {
593                 CERROR("mx_set_request_timeout() failed with %s\n", 
594                         mx_strerror(mxret));
595                 mx_close_endpoint(kmxlnd_data.kmx_endpt);
596                 mx_finalize();
597                 return -1;
598         }
599         return 0;
600 }
601
602
603 /**
604  * mxlnd_thread_start - spawn a kernel thread with this function
605  * @fn - function pointer
606  * @arg - pointer to the parameter data
607  *
608  * Returns 0 on success and a negative value on failure
609  */
610 int
611 mxlnd_thread_start(int (*fn)(void *arg), void *arg)
612 {
613         int     pid = 0;
614         int     i   = (int) ((long) arg);
615
616         atomic_inc(&kmxlnd_data.kmx_nthreads);
617         init_completion(&kmxlnd_data.kmx_completions[i]);
618
619         pid = kernel_thread (fn, arg, 0);
620         if (pid < 0) {
621                 CERROR("kernel_thread() failed with %d\n", pid);
622                 atomic_dec(&kmxlnd_data.kmx_nthreads);
623         }
624         return pid;
625 }
626
627 /**
628  * mxlnd_thread_stop - decrement thread counter
629  *
630  * The thread returns 0 when it detects shutdown.
631  * We are simply decrementing the thread counter.
632  */
633 void
634 mxlnd_thread_stop(long id)
635 {
636         int     i       = (int) id;
637         atomic_dec (&kmxlnd_data.kmx_nthreads);
638         complete(&kmxlnd_data.kmx_completions[i]);
639 }
640
641 /**
642  * mxlnd_shutdown - stop IO, clean up state
643  * @ni - LNET interface handle
644  *
645  * No calls to the LND should be made after calling this function.
646  */
647 void
648 mxlnd_shutdown (lnet_ni_t *ni)
649 {
650         int     i               = 0;
651         int     nthreads        = 2 + *kmxlnd_tunables.kmx_n_waitd;
652
653         LASSERT (ni == kmxlnd_data.kmx_ni);
654         LASSERT (ni->ni_data == &kmxlnd_data);
655         CDEBUG(D_NET, "in shutdown()\n");
656
657         CDEBUG(D_MALLOC, "before MXLND cleanup: libcfs_kmemory %d "
658                          "kmx_mem_used %ld\n", atomic_read (&libcfs_kmemory), 
659                          kmxlnd_data.kmx_mem_used);
660
661         switch (kmxlnd_data.kmx_init) {
662
663         case MXLND_INIT_ALL:
664
665                 CDEBUG(D_NET, "setting shutdown = 1\n");
666                 /* set shutdown and wakeup request_waitds */
667                 kmxlnd_data.kmx_shutdown = 1;
668                 mb();
669                 mx_wakeup(kmxlnd_data.kmx_endpt);
670                 up(&kmxlnd_data.kmx_tx_queue_sem);
671                 mxlnd_sleep(2 * HZ);
672
673                 /* fall through */
674
675         case MXLND_INIT_THREADS:
676
677                 CDEBUG(D_NET, "waiting on threads\n");
678                 /* wait for threads to complete */
679                 for (i = 0; i < nthreads; i++) {
680                         wait_for_completion(&kmxlnd_data.kmx_completions[i]);
681                 }
682                 LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
683
684                 CDEBUG(D_NET, "freeing completions\n");
685                 MXLND_FREE(kmxlnd_data.kmx_completions, 
686                             MXLND_NCOMPLETIONS * sizeof(struct completion));
687
688                 /* fall through */
689
690         case MXLND_INIT_MX:
691
692                 CDEBUG(D_NET, "stopping mx\n");
693
694                 /* wakeup waiters if they missed the above.
695                  * close endpoint to stop all traffic.
696                  * this will cancel and cleanup all requests, etc. */
697
698                 mx_wakeup(kmxlnd_data.kmx_endpt);
699                 mx_close_endpoint(kmxlnd_data.kmx_endpt);
700                 mx_finalize();
701
702                 CDEBUG(D_NET, "mxlnd_free_hosts();\n");
703                 mxlnd_free_hosts();
704
705                 /* fall through */
706
707         case MXLND_INIT_RXS:
708
709                 CDEBUG(D_NET, "freeing rxs\n");
710
711                 /* free all rxs and associated pages */
712                 mxlnd_free_rxs();
713
714                 /* fall through */
715
716         case MXLND_INIT_TXS:
717
718                 CDEBUG(D_NET, "freeing txs\n");
719
720                 /* free all txs and associated pages */
721                 mxlnd_free_txs();
722
723                 /* fall through */
724
725         case MXLND_INIT_DATA:
726
727                 CDEBUG(D_NET, "freeing peers\n");
728
729                 /* free peer list */
730                 mxlnd_free_peers();
731
732                 /* fall through */
733
734         case MXLND_INIT_NOTHING:
735                 break;
736         }
737         CDEBUG(D_NET, "shutdown complete\n");
738
739         CDEBUG(D_MALLOC, "after MXLND cleanup: libcfs_kmemory %d "
740                          "kmx_mem_used %ld\n", atomic_read (&libcfs_kmemory), 
741                          kmxlnd_data.kmx_mem_used);
742
743         kmxlnd_data.kmx_init = MXLND_INIT_NOTHING;
744         PORTAL_MODULE_UNUSE;
745         return;
746 }
747
748 /**
749  * mxlnd_startup - initialize state, open an endpoint, start IO
750  * @ni - LNET interface handle
751  *
752  * Initialize state, open an endpoint, start monitoring threads.
753  * Should only be called once.
754  */
755 int
756 mxlnd_startup (lnet_ni_t *ni)
757 {
758         int             i               = 0;
759         int             ret             = 0;
760         int             nthreads        = 2; /* for timeoutd and tx_queued */
761         struct timeval  tv;
762
763         LASSERT (ni->ni_lnd == &the_kmxlnd);
764
765         if (kmxlnd_data.kmx_init != MXLND_INIT_NOTHING) {
766                 CERROR("Only 1 instance supported\n");
767                 return -EPERM;
768         }
769         CDEBUG(D_MALLOC, "before MXLND startup: libcfs_kmemory %d "
770                          "kmx_mem_used %ld\n", atomic_read (&libcfs_kmemory), 
771                          kmxlnd_data.kmx_mem_used);
772
773         /* reserve 1/2 of tx for connect request messages */
774         ni->ni_maxtxcredits = *kmxlnd_tunables.kmx_ntx / 2;
775         ni->ni_peertxcredits = *kmxlnd_tunables.kmx_credits;
776         if (ni->ni_maxtxcredits < ni->ni_peertxcredits)
777                 ni->ni_maxtxcredits = ni->ni_peertxcredits;
778
779         PORTAL_MODULE_USE;
780         memset (&kmxlnd_data, 0, sizeof (kmxlnd_data));
781
782         kmxlnd_data.kmx_ni = ni;
783         ni->ni_data = &kmxlnd_data;
784
785         do_gettimeofday(&tv);
786         kmxlnd_data.kmx_incarnation = (((__u64)tv.tv_sec) * 1000000) + tv.tv_usec;
787         CDEBUG(D_NET, "my incarnation is %lld\n", kmxlnd_data.kmx_incarnation);
788
789         spin_lock_init (&kmxlnd_data.kmx_global_lock);
790
791         INIT_LIST_HEAD (&kmxlnd_data.kmx_conn_req);
792         spin_lock_init (&kmxlnd_data.kmx_conn_lock);
793         sema_init(&kmxlnd_data.kmx_conn_sem, 0);
794
795         INIT_LIST_HEAD (&kmxlnd_data.kmx_hosts);
796         spin_lock_init (&kmxlnd_data.kmx_hosts_lock);
797
798         for (i = 0; i < MXLND_HASH_SIZE; i++) {
799                 INIT_LIST_HEAD (&kmxlnd_data.kmx_peers[i]);
800         }
801         rwlock_init (&kmxlnd_data.kmx_peers_lock);
802
803         INIT_LIST_HEAD (&kmxlnd_data.kmx_txs);
804         INIT_LIST_HEAD (&kmxlnd_data.kmx_tx_idle);
805         spin_lock_init (&kmxlnd_data.kmx_tx_idle_lock);
806         kmxlnd_data.kmx_tx_next_cookie = 1;
807         INIT_LIST_HEAD (&kmxlnd_data.kmx_tx_queue);
808         spin_lock_init (&kmxlnd_data.kmx_tx_queue_lock);
809         sema_init(&kmxlnd_data.kmx_tx_queue_sem, 0);
810
811         INIT_LIST_HEAD (&kmxlnd_data.kmx_rxs);
812         spin_lock_init (&kmxlnd_data.kmx_rxs_lock);
813         INIT_LIST_HEAD (&kmxlnd_data.kmx_rx_idle);
814         spin_lock_init (&kmxlnd_data.kmx_rx_idle_lock);
815
816         kmxlnd_data.kmx_init = MXLND_INIT_DATA;
817         /*****************************************************/
818
819         ret = mxlnd_init_txs();
820         if (ret != 0) {
821                 CERROR("Can't alloc tx descs: %d\n", ret);
822                 goto failed;
823         }
824         kmxlnd_data.kmx_init = MXLND_INIT_TXS;
825         /*****************************************************/
826
827         ret = mxlnd_init_rxs();
828         if (ret != 0) {
829                 CERROR("Can't alloc rx descs: %d\n", ret);
830                 goto failed;
831         }
832         kmxlnd_data.kmx_init = MXLND_INIT_RXS;
833         /*****************************************************/
834
835         ret = mxlnd_init_mx(ni);
836         if (ret != 0) {
837                 CERROR("Can't init mx\n");
838                 goto failed;
839         }
840
841         kmxlnd_data.kmx_init = MXLND_INIT_MX;
842         /*****************************************************/
843
844         /* start threads */
845
846         nthreads += *kmxlnd_tunables.kmx_n_waitd;
847         MXLND_ALLOC (kmxlnd_data.kmx_completions,
848                      nthreads * sizeof(struct completion));
849         if (kmxlnd_data.kmx_completions == NULL) {
850                 CERROR("failed to alloc kmxlnd_data.kmx_completions\n");
851                 goto failed;
852         }
853         memset(kmxlnd_data.kmx_completions, 0, 
854                nthreads * sizeof(struct completion));
855
856         {
857                 CDEBUG(D_NET, "using %d %s in mx_wait_any()\n",
858                         *kmxlnd_tunables.kmx_n_waitd, 
859                         *kmxlnd_tunables.kmx_n_waitd == 1 ? "thread" : "threads");
860
861                 for (i = 0; i < *kmxlnd_tunables.kmx_n_waitd; i++) {
862                         ret = mxlnd_thread_start(mxlnd_request_waitd, (void*)((long)i));
863                         if (ret < 0) {
864                                 CERROR("Starting mxlnd_request_waitd[%d] failed with %d\n", i, ret);
865                                 kmxlnd_data.kmx_shutdown = 1;
866                                 mx_wakeup(kmxlnd_data.kmx_endpt);
867                                 for (--i; i >= 0; i--) {
868                                         wait_for_completion(&kmxlnd_data.kmx_completions[i]);
869                                 }
870                                 LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
871                                 MXLND_FREE(kmxlnd_data.kmx_completions, 
872                                         MXLND_NCOMPLETIONS * sizeof(struct completion));
873
874                                 goto failed;
875                         }
876                 }
877                 ret = mxlnd_thread_start(mxlnd_tx_queued, (void*)((long)i++));
878                 if (ret < 0) {
879                         CERROR("Starting mxlnd_tx_queued failed with %d\n", ret);
880                         kmxlnd_data.kmx_shutdown = 1;
881                         mx_wakeup(kmxlnd_data.kmx_endpt);
882                         for (--i; i >= 0; i--) {
883                                 wait_for_completion(&kmxlnd_data.kmx_completions[i]);
884                         }
885                         LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
886                         MXLND_FREE(kmxlnd_data.kmx_completions, 
887                                 MXLND_NCOMPLETIONS * sizeof(struct completion));
888                         goto failed;
889                 }
890                 ret = mxlnd_thread_start(mxlnd_timeoutd, (void*)((long)i++));
891                 if (ret < 0) {
892                         CERROR("Starting mxlnd_timeoutd failed with %d\n", ret);
893                         kmxlnd_data.kmx_shutdown = 1;
894                         mx_wakeup(kmxlnd_data.kmx_endpt);
895                         up(&kmxlnd_data.kmx_tx_queue_sem);
896                         for (--i; i >= 0; i--) {
897                                 wait_for_completion(&kmxlnd_data.kmx_completions[i]);
898                         }
899                         LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
900                         MXLND_FREE(kmxlnd_data.kmx_completions, 
901                                 MXLND_NCOMPLETIONS * sizeof(struct completion));
902                         goto failed;
903                 }
904         }
905
906         kmxlnd_data.kmx_init = MXLND_INIT_THREADS;
907         /*****************************************************/
908
909         kmxlnd_data.kmx_init = MXLND_INIT_ALL;
910         CDEBUG(D_MALLOC, "startup complete (kmx_mem_used %ld)\n", kmxlnd_data.kmx_mem_used);
911
912         return 0;
913 failed:
914         CERROR("mxlnd_startup failed\n");
915         mxlnd_shutdown(ni);
916         return (-ENETDOWN);
917 }
918
919 static int mxlnd_init(void)
920 {
921         lnet_register_lnd(&the_kmxlnd);
922         return 0;
923 }
924
925 static void mxlnd_exit(void)
926 {
927         lnet_unregister_lnd(&the_kmxlnd);
928         return;
929 }
930
931 module_init(mxlnd_init);
932 module_exit(mxlnd_exit);
933
934 MODULE_LICENSE("GPL");
935 MODULE_AUTHOR("Myricom, Inc. - help@myri.com");
936 MODULE_DESCRIPTION("Kernel MyrinetExpress LND");
937 MODULE_VERSION("0.5.0");