Whamcloud - gitweb
7c94f937b56b8d79aca59a0420c746aa8777bdeb
[fs/lustre-release.git] / lnet / klnds / gmlnd / gmlnd_api.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2003 Los Alamos National Laboratory (LANL)
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 /*
23  *      Implements the API NAL functions
24  */
25
26 #include "gmnal.h"
27
28
29
30 gmnal_data_t    *global_nal_data = NULL;
31 #define         GLOBAL_NID_STR_LEN      16
32 char            global_nid_str[GLOBAL_NID_STR_LEN] = {0};
33
34 /*
35  *      Write the global nid /proc/sys/gmnal/globalnid
36  */
37 #define GMNAL_SYSCTL    201
38 #define GMNAL_SYSCTL_GLOBALNID  1
39
40 static ctl_table gmnal_sysctl_table[] = {
41         {GMNAL_SYSCTL_GLOBALNID, "globalnid",
42          global_nid_str, GLOBAL_NID_STR_LEN,
43          0444, NULL, &proc_dostring},
44         { 0 }
45 };
46
47
48 static ctl_table gmnalnal_top_sysctl_table[] = {
49         {GMNAL_SYSCTL, "gmnal", NULL, 0, 0555, gmnal_sysctl_table},
50         { 0 }
51 };
52
53
54
55
56
57
58 /*
59  *      gmnal_api_forward
60  *      This function takes a pack block of arguments from the NAL API
61  *      module and passes them to the NAL CB module. The CB module unpacks
62  *      the args and calls the appropriate function indicated by index.
63  *      Typically this function is used to pass args between kernel and use
64  *      space.
65  *      As lgmanl exists entirely in kernel, just pass the arg block directly 
66  *      to the NAL CB, buy passing the args to lib_dispatch
67  *      Arguments are
68  *      nal_t   nal     Our nal
69  *      int     index   the api function that initiated this call 
70  *      void    *args   packed block of function args
71  *      size_t  arg_len length of args block
72  *      void    *ret    A return value for the API NAL
73  *      size_t  ret_len Size of the return value
74  *      
75  */
76
77 int
78 gmnal_api_forward(nal_t *nal, int index, void *args, size_t arg_len,
79                 void *ret, size_t ret_len)
80 {
81
82         nal_cb_t        *nal_cb = NULL;
83         gmnal_data_t    *nal_data = NULL;
84
85
86
87
88
89         if (!nal || !args || (index < 0) || (arg_len < 0)) {
90                         CDEBUG(D_ERROR, "Bad args to gmnal_api_forward\n");
91                 return (PTL_FAIL);
92         }
93
94         if (ret && (ret_len <= 0)) {
95                 CDEBUG(D_ERROR, "Bad args to gmnal_api_forward\n");
96                 return (PTL_FAIL);
97         }
98
99
100         if (!nal->nal_data) {
101                 CDEBUG(D_ERROR, "bad nal, no nal data\n");      
102                 return (PTL_FAIL);
103         }
104         
105         nal_data = nal->nal_data;
106         CDEBUG(D_INFO, "nal_data is [%p]\n", nal_data); 
107
108         if (!nal_data->nal_cb) {
109                 CDEBUG(D_ERROR, "bad nal_data, no nal_cb\n");   
110                 return (PTL_FAIL);
111         }
112         
113         nal_cb = nal_data->nal_cb;
114         CDEBUG(D_INFO, "nal_cb is [%p]\n", nal_cb);     
115         
116         CDEBUG(D_PORTALS, "gmnal_api_forward calling lib_dispatch\n");
117         lib_dispatch(nal_cb, NULL, index, args, ret);
118         CDEBUG(D_PORTALS, "gmnal_api_forward returns from lib_dispatch\n");
119
120         return(PTL_OK);
121 }
122
123
124 /*
125  *      gmnal_api_shutdown
126  *      nal_refct == 0 => called on last matching PtlNIFini()
127  *      Close down this interface and free any resources associated with it
128  *      nal_t   nal     our nal to shutdown
129  */
130 void
131 gmnal_api_shutdown(nal_t *nal, int interface)
132 {
133         gmnal_data_t    *nal_data;
134         nal_cb_t        *nal_cb;
135
136         if (nal->nal_refct != 0)
137                 return;
138         
139         CDEBUG(D_TRACE, "gmnal_api_shutdown: nal_data [%p]\n", nal_data);
140
141         LASSERT(nal == global_nal_data->nal);
142         nal_data = nal->nal_data;
143         LASSERT(nal_data == global_nal_data);
144         nal_cb = nal_data->nal_cb;
145
146         /* Stop portals calling our ioctl handler */
147         libcfs_nal_cmd_unregister(GMNAL);
148
149         /* XXX for shutdown "under fire" we probably need to set a shutdown
150          * flag so when lib calls us we fail immediately and dont queue any
151          * more work but our threads can still call into lib OK.  THEN
152          * shutdown our threads, THEN lib_fini() */
153         lib_fini(nal_cb);
154
155         gmnal_stop_rxthread(nal_data);
156         gmnal_stop_ctthread(nal_data);
157         gmnal_free_txd(nal_data);
158         gmnal_free_srxd(nal_data);
159         GMNAL_GM_LOCK(nal_data);
160         gm_close(nal_data->gm_port);
161         gm_finalize();
162         GMNAL_GM_UNLOCK(nal_data);
163         if (nal_data->sysctl)
164                 unregister_sysctl_table (nal_data->sysctl);
165         PORTAL_FREE(nal, sizeof(nal_t));        
166         PORTAL_FREE(nal_data, sizeof(gmnal_data_t));    
167         PORTAL_FREE(nal_cb, sizeof(nal_cb_t));
168
169         global_nal_data = NULL;
170         PORTAL_MODULE_UNUSE;
171 }
172
173
174 /*
175  *      gmnal_api_validate
176  *      validate a user address for use in communications
177  *      There's nothing to be done here
178  */
179 int
180 gmnal_api_validate(nal_t *nal, void *base, size_t extent)
181 {
182
183         return(PTL_OK);
184 }
185
186
187
188 /*
189  *      gmnal_api_yield
190  *      Give up the processor
191  */
192 void
193 gmnal_api_yield(nal_t *nal, unsigned long *flags, int milliseconds)
194 {
195         CDEBUG(D_TRACE, "gmnal_api_yield : nal [%p]\n", nal);
196
197         if (milliseconds != 0) {
198                 CERROR("Blocking yield not implemented yet\n");
199                 LBUG();
200         }
201
202         our_cond_resched();
203         return;
204 }
205
206
207
208 /*
209  *      gmnal_api_lock
210  *      Take a threadsafe lock
211  */
212 void
213 gmnal_api_lock(nal_t *nal, unsigned long *flags)
214 {
215
216         gmnal_data_t    *nal_data;
217         nal_cb_t        *nal_cb;
218
219         nal_data = nal->nal_data;
220         nal_cb = nal_data->nal_cb;
221
222         nal_cb->cb_cli(nal_cb, flags);
223
224         return;
225 }
226
227 /*
228  *      gmnal_api_unlock
229  *      Release a threadsafe lock
230  */
231 void
232 gmnal_api_unlock(nal_t *nal, unsigned long *flags)
233 {
234         gmnal_data_t    *nal_data;
235         nal_cb_t        *nal_cb;
236
237         nal_data = nal->nal_data;
238         nal_cb = nal_data->nal_cb;
239
240         nal_cb->cb_sti(nal_cb, flags);
241
242         return;
243 }
244
245
246 int
247 gmnal_api_startup(nal_t *nal, ptl_pid_t requested_pid,
248                   ptl_ni_limits_t *requested_limits,
249                   ptl_ni_limits_t *actual_limits)
250 {
251
252         nal_cb_t        *nal_cb = NULL;
253         gmnal_data_t    *nal_data = NULL;
254         gmnal_srxd_t    *srxd = NULL;
255         gm_status_t     gm_status;
256         unsigned int    local_nid = 0, global_nid = 0;
257         ptl_process_id_t process_id;
258
259         if (nal->nal_refct != 0) {
260                 if (actual_limits != NULL) {
261                         nal_data = (gmnal_data_t *)nal->nal_data;
262                         nal_cb = nal_data->nal_cb;
263                         *actual_limits = nal->_cb->ni.actual_limits;
264                 return (PTL_OK);
265         }
266
267         /* Called on first PtlNIInit() */
268
269         CDEBUG(D_TRACE, "startup\n");
270
271         LASSERT(global_nal_data == NULL);
272
273         PORTAL_ALLOC(nal_data, sizeof(gmnal_data_t));
274         if (!nal_data) {
275                 CDEBUG(D_ERROR, "can't get memory\n");
276                 return(PTL_NO_SPACE);
277         }       
278         memset(nal_data, 0, sizeof(gmnal_data_t));
279         /*
280          *      set the small message buffer size 
281          */
282
283         CDEBUG(D_INFO, "Allocd and reset nal_data[%p]\n", nal_data);
284         CDEBUG(D_INFO, "small_msg_size is [%d]\n", nal_data->small_msg_size);
285
286         PORTAL_ALLOC(nal_cb, sizeof(nal_cb_t));
287         if (!nal_cb) {
288                 PORTAL_FREE(nal_data, sizeof(gmnal_data_t));
289                 return(PTL_NO_SPACE);
290         }
291         memset(nal_cb, 0, sizeof(nal_cb_t));
292         CDEBUG(D_INFO, "Allocd and reset nal_cb[%p]\n", nal_cb);
293
294         GMNAL_INIT_NAL_CB(nal_cb);
295         /*
296          *      String them all together
297          */
298         nal->nal_data = (void*)nal_data;
299         nal_cb->nal_data = (void*)nal_data;
300         nal_data->nal = nal;
301         nal_data->nal_cb = nal_cb;
302
303         GMNAL_CB_LOCK_INIT(nal_data);
304         GMNAL_GM_LOCK_INIT(nal_data);
305
306
307         /*
308          *      initialise the interface, 
309          */
310         CDEBUG(D_INFO, "Calling gm_init\n");
311         if (gm_init() != GM_SUCCESS) {
312                 CDEBUG(D_ERROR, "call to gm_init failed\n");
313                 PORTAL_FREE(nal_data, sizeof(gmnal_data_t));    
314                 PORTAL_FREE(nal_cb, sizeof(nal_cb_t));
315                 return(PTL_FAIL);
316         }
317
318
319         CDEBUG(D_NET, "Calling gm_open with interface [%d], port [%d], "
320                "name [%s], version [%d]\n", interface, GMNAL_GM_PORT, 
321                "gmnal", GM_API_VERSION);
322
323         GMNAL_GM_LOCK(nal_data);
324         gm_status = gm_open(&nal_data->gm_port, 0, GMNAL_GM_PORT, "gmnal", 
325                             GM_API_VERSION);
326         GMNAL_GM_UNLOCK(nal_data);
327
328         CDEBUG(D_INFO, "gm_open returned [%d]\n", gm_status);
329         if (gm_status == GM_SUCCESS) {
330                 CDEBUG(D_INFO, "gm_open succeeded port[%p]\n", 
331                        nal_data->gm_port);
332         } else {
333                 switch(gm_status) {
334                 case(GM_INVALID_PARAMETER):
335                         CDEBUG(D_ERROR, "gm_open Failure. Invalid Parameter\n");
336                         break;
337                 case(GM_BUSY):
338                         CDEBUG(D_ERROR, "gm_open Failure. GM Busy\n");
339                         break;
340                 case(GM_NO_SUCH_DEVICE):
341                         CDEBUG(D_ERROR, "gm_open Failure. No such device\n");
342                         break;
343                 case(GM_INCOMPATIBLE_LIB_AND_DRIVER):
344                         CDEBUG(D_ERROR, "gm_open Failure. Incompatile lib "
345                                "and driver\n");
346                         break;
347                 case(GM_OUT_OF_MEMORY):
348                         CDEBUG(D_ERROR, "gm_open Failure. Out of Memory\n");
349                         break;
350                 default:
351                         CDEBUG(D_ERROR, "gm_open Failure. Unknow error "
352                                "code [%d]\n", gm_status);
353                         break;
354                 }       
355                 GMNAL_GM_LOCK(nal_data);
356                 gm_finalize();
357                 GMNAL_GM_UNLOCK(nal_data);
358                 PORTAL_FREE(nal_data, sizeof(gmnal_data_t));    
359                 PORTAL_FREE(nal_cb, sizeof(nal_cb_t));
360                 return(PTL_FAIL);
361         }
362
363         
364         nal_data->small_msg_size = gmnal_small_msg_size;
365         nal_data->small_msg_gmsize = 
366                         gm_min_size_for_length(gmnal_small_msg_size);
367
368         if (gmnal_alloc_srxd(nal_data) != GMNAL_STATUS_OK) {
369                 CDEBUG(D_ERROR, "Failed to allocate small rx descriptors\n");
370                 gmnal_free_txd(nal_data);
371                 GMNAL_GM_LOCK(nal_data);
372                 gm_close(nal_data->gm_port);
373                 gm_finalize();
374                 GMNAL_GM_UNLOCK(nal_data);
375                 PORTAL_FREE(nal_data, sizeof(gmnal_data_t));    
376                 PORTAL_FREE(nal_cb, sizeof(nal_cb_t));
377                 return(PTL_FAIL);
378         }
379
380
381         /*
382          *      Hang out a bunch of small receive buffers
383          *      In fact hang them all out
384          */
385         while((srxd = gmnal_get_srxd(nal_data, 0))) {
386                 CDEBUG(D_NET, "giving [%p] to gm_provide_recvive_buffer\n", 
387                        srxd->buffer);
388                 GMNAL_GM_LOCK(nal_data);
389                 gm_provide_receive_buffer_with_tag(nal_data->gm_port, 
390                                                    srxd->buffer, srxd->gmsize, 
391                                                    GM_LOW_PRIORITY, 0);
392                 GMNAL_GM_UNLOCK(nal_data);
393         }
394         
395         /*
396          *      Allocate pools of small tx buffers and descriptors
397          */
398         if (gmnal_alloc_txd(nal_data) != GMNAL_STATUS_OK) {
399                 CDEBUG(D_ERROR, "Failed to allocate small tx descriptors\n");
400                 GMNAL_GM_LOCK(nal_data);
401                 gm_close(nal_data->gm_port);
402                 gm_finalize();
403                 GMNAL_GM_UNLOCK(nal_data);
404                 PORTAL_FREE(nal_data, sizeof(gmnal_data_t));    
405                 PORTAL_FREE(nal_cb, sizeof(nal_cb_t));
406                 return(PTL_FAIL);
407         }
408
409         gmnal_start_kernel_threads(nal_data);
410
411         while (nal_data->rxthread_flag != GMNAL_RXTHREADS_STARTED) {
412                 gmnal_yield(1);
413                 CDEBUG(D_INFO, "Waiting for receive thread signs of life\n");
414         }
415
416         CDEBUG(D_INFO, "receive thread seems to have started\n");
417
418
419         /*
420          *      Initialise the portals library
421          */
422         CDEBUG(D_NET, "Getting node id\n");
423         GMNAL_GM_LOCK(nal_data);
424         gm_status = gm_get_node_id(nal_data->gm_port, &local_nid);
425         GMNAL_GM_UNLOCK(nal_data);
426         if (gm_status != GM_SUCCESS) {
427                 gmnal_stop_rxthread(nal_data);
428                 gmnal_stop_ctthread(nal_data);
429                 CDEBUG(D_ERROR, "can't determine node id\n");
430                 gmnal_free_txd(nal_data);
431                 gmnal_free_srxd(nal_data);
432                 GMNAL_GM_LOCK(nal_data);
433                 gm_close(nal_data->gm_port);
434                 gm_finalize();
435                 GMNAL_GM_UNLOCK(nal_data);
436                 PORTAL_FREE(nal_data, sizeof(gmnal_data_t));    
437                 PORTAL_FREE(nal_cb, sizeof(nal_cb_t));
438                 return(PTL_FAIL);
439         }
440         nal_data->gm_local_nid = local_nid;
441         CDEBUG(D_INFO, "Local node id is [%u]\n", local_nid);
442         GMNAL_GM_LOCK(nal_data);
443         gm_status = gm_node_id_to_global_id(nal_data->gm_port, local_nid, 
444                                             &global_nid);
445         GMNAL_GM_UNLOCK(nal_data);
446         if (gm_status != GM_SUCCESS) {
447                 CDEBUG(D_ERROR, "failed to obtain global id\n");
448                 gmnal_stop_rxthread(nal_data);
449                 gmnal_stop_ctthread(nal_data);
450                 gmnal_free_txd(nal_data);
451                 gmnal_free_srxd(nal_data);
452                 GMNAL_GM_LOCK(nal_data);
453                 gm_close(nal_data->gm_port);
454                 gm_finalize();
455                 GMNAL_GM_UNLOCK(nal_data);
456                 PORTAL_FREE(nal_data, sizeof(gmnal_data_t));    
457                 PORTAL_FREE(nal_cb, sizeof(nal_cb_t));
458                 return(PTL_FAIL);
459         }
460         CDEBUG(D_INFO, "Global node id is [%u]\n", global_nid);
461         nal_data->gm_global_nid = global_nid;
462         snprintf(global_nid_str, GLOBAL_NID_STR_LEN, "%u", global_nid);
463
464 /*
465         pid = gm_getpid();
466 */
467         process_id.pid = 0;
468         process_id.nid = global_nid;
469         
470         CDEBUG(D_INFO, "portals_pid is [%u]\n", process_id.pid);
471         CDEBUG(D_INFO, "portals_nid is ["LPU64"]\n", process_id.nid);
472         
473         CDEBUG(D_PORTALS, "calling lib_init\n");
474         if (lib_init(nal_cb, process_id, 
475                      requested_limits, actual_limits) != PTL_OK) {
476                 CDEBUG(D_ERROR, "lib_init failed\n");
477                 gmnal_stop_rxthread(nal_data);
478                 gmnal_stop_ctthread(nal_data);
479                 gmnal_free_txd(nal_data);
480                 gmnal_free_srxd(nal_data);
481                 GMNAL_GM_LOCK(nal_data);
482                 gm_close(nal_data->gm_port);
483                 gm_finalize();
484                 GMNAL_GM_UNLOCK(nal_data);
485                 PORTAL_FREE(nal_data, sizeof(gmnal_data_t));    
486                 PORTAL_FREE(nal_cb, sizeof(nal_cb_t));
487                 return(PTL_FAIL);
488                 
489         }
490
491         if (libcfs_nal_cmd_register(GMNAL, &gmnal_cmd, nal->nal_data) != 0) {
492                 CDEBUG(D_INFO, "libcfs_nal_cmd_register failed\n");
493
494                 /* XXX these cleanup cases should be restructured to
495                  * minimise duplication... */
496                 lib_fini(nal_cb);
497                 
498                 gmnal_stop_rxthread(nal_data);
499                 gmnal_stop_ctthread(nal_data);
500                 gmnal_free_txd(nal_data);
501                 gmnal_free_srxd(nal_data);
502                 GMNAL_GM_LOCK(nal_data);
503                 gm_close(nal_data->gm_port);
504                 gm_finalize();
505                 GMNAL_GM_UNLOCK(nal_data);
506                 PORTAL_FREE(nal_data, sizeof(gmnal_data_t));    
507                 PORTAL_FREE(nal_cb, sizeof(nal_cb_t));
508                 return(PTL_FAIL);
509         }
510
511         /* might be better to initialise this at module load rather than in
512          * NAL startup */
513         nal_data->sysctl = NULL;
514         nal_data->sysctl = register_sysctl_table (gmnalnal_top_sysctl_table, 0);
515
516         
517         CDEBUG(D_INFO, "gmnal_init finished\n");
518         global_nal_data = nal->nal_data;
519
520         /* no unload now until shutdown */
521         PORTAL_MODULE_USE;
522         
523         return(PTL_OK);
524 }
525
526 nal_t the_gm_nal;
527
528 /* 
529  *        Called when module loaded
530  */
531 int gmnal_init(void)
532 {
533         int    rc;
534
535         memset(&the_gm_nal, 0, sizeof(nal_t));
536         CDEBUG(D_INFO, "reset nal[%p]\n", &the_gm_nal);
537         GMNAL_INIT_NAL(&the_gm_nal);
538
539         rc = ptl_register_nal(GMNAL, &the_gm_nal);
540         if (rc != PTL_OK)
541                 CERROR("Can't register GMNAL: %d\n", rc);
542
543         return (rc);
544 }
545
546                 
547
548 /*
549  *      Called when module removed
550  */
551 void gmnal_fini()
552 {
553         gmnal_data_t    *nal_data = global_nal_data;
554         nal_t           *nal = nal_data->nal;
555         nal_cb_t        *nal_cb = nal_data->nal_cb;
556
557         CDEBUG(D_TRACE, "gmnal_fini\n");
558
559         LASSERT(global_nal_data == NULL);
560
561         ptl_unregister_nal(GMNAL);
562 }