Whamcloud - gitweb
- merge 0.7rc1 from b_devel to HEAD (20030612 merge point)
[fs/lustre-release.git] / lnet / klnds / scimaclnd / scimacnal_cb.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:cindent:
3  *
4  * Copyright (C) 2003 High Performance Computing Center North (HPC2N)
5  *   Author: Niklas Edmundsson <nikke@hpc2n.umu.se>
6
7  *
8  * This file is part of Portals, http://www.sf.net/projects/lustre/
9  *
10  * Portals is free software; you can redistribute it and/or
11  * modify it under the terms of version 2 of the GNU General Public
12  * License as published by the Free Software Foundation.
13  *
14  * Portals is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Portals; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  */
24
25 #include "scimacnal.h"
26
27 static int 
28 kscimacnal_read (nal_cb_t *nal, void *private,
29                 void *dst_addr, user_ptr src_addr, size_t len)
30 {
31         CDEBUG(D_NET, "0x%Lx: reading %ld bytes from %p -> %p\n",
32                nal->ni.nid, (long)len, src_addr, dst_addr );
33         memcpy( dst_addr, src_addr, len );
34         return 0;
35 }
36
37
38 static int 
39 kscimacnal_write(nal_cb_t *nal, void *private,
40                 user_ptr dst_addr, void *src_addr, size_t len)
41 {
42         CDEBUG(D_NET, "0x%Lx: writing %ld bytes from %p -> %p\n",
43                nal->ni.nid, (long)len, src_addr, dst_addr );
44         memcpy( dst_addr, src_addr, len );
45         return 0;
46 }
47
48
49 static void *
50 kscimacnal_malloc(nal_cb_t *nal, size_t len)
51 {
52         void *buf;
53
54         PORTAL_ALLOC(buf, len);
55         return buf;
56 }
57
58
59 static void 
60 kscimacnal_free(nal_cb_t *nal, void *buf, size_t len)
61 {
62         PORTAL_FREE(buf, len);
63 }
64
65
66 static void 
67 kscimacnal_printf(nal_cb_t *nal, const char *fmt, ...)
68 {
69         va_list         ap;
70         char msg[256]; 
71
72         if (portal_debug & D_NET) {
73                 va_start( ap, fmt );
74                 vsnprintf( msg, sizeof(msg), fmt, ap );
75                 va_end( ap );
76
77                 printk("CPUId: %d %s",smp_processor_id(), msg);
78         }
79 }
80
81
82 static void 
83 kscimacnal_cli(nal_cb_t *nal, unsigned long *flags)
84 {
85         kscimacnal_data_t *data= nal->nal_data;
86
87         spin_lock_irqsave(&data->ksci_dispatch_lock,*flags);
88 }
89
90
91 static void 
92 kscimacnal_sti(nal_cb_t *nal, unsigned long *flags)
93 {
94         kscimacnal_data_t *data= nal->nal_data; 
95
96         spin_unlock_irqrestore(&data->ksci_dispatch_lock,*flags);
97 }
98
99
100 static int 
101 kscimacnal_dist(nal_cb_t *nal, ptl_nid_t nid, unsigned long *dist)
102 {
103         /* FIXME: Network distance has a meaning, but is there no easy
104          * way to figure it out (depends on routing) */
105
106         if ( nal->ni.nid == nid ) {
107                 *dist = 0;
108         } else {
109                 *dist = 1;
110         }
111
112         return 0;
113 }
114
115
116 static
117 char * get_mac_error(mac_status_t status) 
118 {
119         switch(status) {
120                 case MAC_MSG_STAT_OK:
121                         return "MAC_MSG_STAT_OK";
122                 case MAC_MSG_STAT_FREED:
123                         return "MAC_MSG_STAT_FREED";
124                 case MAC_MSG_STAT_ABORTED:
125                         return "MAC_MSG_STAT_ABORTED";
126                 case MAC_MSG_STAT_TIMEDOUT:
127                         return "MAC_MSG_STAT_TIMEDOUT";
128                 case MAC_MSG_STAT_NODEUNREACH:
129                         return "MAC_MSG_STAT_NODEUNREACH";
130                 case MAC_MSG_STAT_NETDOWN:
131                         return "MAC_MSG_STAT_NETDOWN";
132                 case MAC_MSG_STAT_RESET:
133                         return "MAC_MSG_STAT_RESET";
134                 case MAC_MSG_STAT_INITFAILED:
135                         return "MAC_MSG_STAT_INITFAILED";
136                 case MAC_MSG_STAT_SYNCFAILED:
137                         return "MAC_MSG_STAT_SYNCFAILED";
138                 case MAC_MSG_STAT_BADPROTO:
139                         return "MAC_MSG_STAT_BADPROTO";
140                 case MAC_MSG_STAT_NOBUFSPACE:
141                         return "MAC_MSG_STAT_NOBUFSPACE";
142                 case MAC_MSG_STAT_CONGESTION:
143                         return "MAC_MSG_STAT_CONGESTION";
144                 case MAC_MSG_STAT_OTHER:
145                         return "MAC_MSG_STAT_OTHER";
146                 default:
147                         return "Unknown error";
148         }
149 }
150
151
152 /* FIXME add routing code here ? */
153
154 /* Called by ScaMac when transmission is complete  (ie. message is released) */
155 static void 
156 kscimacnal_txrelease(mac_mblk_t *msg, mac_msg_status_t status, void *context)
157 {
158         kscimacnal_tx_t *ktx = (kscimacnal_tx_t *)context;
159         int err=0;
160         
161         LASSERT (ktx != NULL);
162
163         /* Euh, there is no feedback when transmission fails?! */
164         switch(status) {
165                 case MAC_MSG_STAT_OK:        /* normal */
166                         break;
167                 default:
168                         CERROR("%s (%d):\n", get_mac_error(status), status);
169                         err = -EIO;
170                         break;
171         }
172
173         lib_finalize(ktx->ktx_nal, ktx->ktx_private, ktx->ktx_cookie);
174
175         PORTAL_FREE(ktx, (sizeof(kscimacnal_tx_t)));
176 }
177
178
179 /* Called by portals when it wants to send a message.
180  * Since ScaMAC has it's own TX thread we don't bother setting up our own. */
181 static int 
182 kscimacnal_send(nal_cb_t        *nal,
183            void            *private,
184            lib_msg_t       *cookie,
185            ptl_hdr_t       *hdr,
186            int              type, 
187            ptl_nid_t        nid,
188            ptl_pid_t        pid,
189            unsigned int     payload_niov,
190            struct iovec    *payload_iov,
191            size_t           payload_len)
192 {
193         kscimacnal_tx_t    *ktx=NULL;
194         kscimacnal_data_t  *ksci = nal->nal_data;
195         int              rc=0;
196         int              buf_len = sizeof(ptl_hdr_t) + payload_len;
197         mac_mblk_t      *msg=NULL, *lastblk, *newblk;
198         unsigned long   physaddr;
199         
200
201         CDEBUG(D_NET, "sending %d bytes from %p to nid 0x%Lx niov: %d\n",
202                payload_len, payload_iov, nid, payload_niov);
203
204         LASSERT(ksci != NULL);
205
206         LASSERT(hdr != NULL);
207
208         /* Do real check if we can send this */
209         if (buf_len > mac_get_mtusize(ksci->ksci_machandle)) {
210                 CERROR("kscimacnal:request exceeds TX MTU size (%ld).\n",
211                                 mac_get_mtusize(ksci->ksci_machandle));
212                 return -EINVAL;
213         }
214
215
216         /* save transaction info for later finalize and cleanup */
217         PORTAL_ALLOC(ktx, (sizeof(kscimacnal_tx_t)));
218         if (!ktx) {
219                 return -ENOMEM;
220         }
221
222         /* *SIGH* hdr is a stack variable in the calling function, so we
223          * need to copy it to a buffer. Zerocopy magic (or is it just
224          * deferred memcpy?) is annoying sometimes.  */
225         memcpy(&ktx->ktx_hdr, hdr, sizeof(ptl_hdr_t));
226
227         /* First, put the header in the main message mblk */
228         msg = mac_alloc_mblk(&ktx->ktx_hdr, sizeof(ptl_hdr_t),
229                         kscimacnal_txrelease, ktx);
230         if (!msg) {
231                 PORTAL_FREE(ktx, (sizeof(kscimacnal_tx_t)));
232                 return -ENOMEM;
233         }
234         mac_put_mblk(msg, sizeof(ptl_hdr_t));
235         lastblk=msg;
236
237         /* Allocate additional mblks for each iov as needed.
238          * Essentially lib_copy_iov2buf with a twist or two */
239         while (payload_len > 0)
240         {
241                 ptl_size_t nob;
242
243                 LASSERT (payload_niov > 0);
244
245                 nob = MIN (payload_iov->iov_len, payload_len);
246
247                 /* We don't need a callback on the additional mblks, since
248                  * all release callbacks seems to be called when the entire
249                  * message has been sent */
250                 newblk=mac_alloc_mblk(payload_iov->iov_base, nob, NULL, NULL);
251                 if(!newblk) {
252                         mac_free_msg(msg);
253                         PORTAL_FREE(ktx, (sizeof(kscimacnal_tx_t)));
254                         return -ENOMEM;
255                 }
256                 mac_put_mblk(newblk, nob);
257                 mac_link_mblk(lastblk, newblk);
258                 lastblk=newblk;
259
260                 payload_len -= nob;
261                 payload_niov--;
262                 payload_iov++;
263         }
264
265         ktx->ktx_nal = nal;
266         ktx->ktx_private = private;
267         ktx->ktx_cookie = cookie;
268
269         CDEBUG(D_NET, "mac_send %d bytes to nid: 0x%Lx\n", buf_len, nid);
270
271         physaddr = htonl(nid);
272
273         if((rc=mac_send(ksci->ksci_machandle, msg,
274                                         (mac_physaddr_t *) &physaddr))) {
275                 CERROR("kscimacnal: mac_send() failed, rc=%d\n", rc);
276                 mac_free_msg(msg);
277                 PORTAL_FREE(ktx, (sizeof(kscimacnal_tx_t)));
278                 return rc;
279         }
280
281         return 0;
282 }
283
284
285 void
286 kscimacnal_fwd_packet (void *arg, kpr_fwd_desc_t *fwd)
287 {
288         CERROR ("forwarding not implemented\n");
289 }
290
291
292 /* Process a received portals packet */
293 /* Called by the ScaMac RX thread when a packet is received */
294 void
295 kscimacnal_rx(mac_handle_t *handle, mac_mblk_t *msg, mac_msg_type_t type,
296                 void *userdata)
297 {
298         ptl_hdr_t       *hdr = NULL;
299         kscimacnal_rx_t     krx; 
300         mac_size_t       size;
301         kscimacnal_data_t  *ksci = userdata;
302
303         LASSERT(ksci != NULL);
304
305         if ( !ksci->ksci_init || ksci->ksci_shuttingdown || 
306                     type == MAC_MSG_TYPE_CTRL || type == MAC_MSG_TYPE_OTHER ) {
307                 /* We're not interested in messages not for us, ignore */
308                 mac_free_msg(msg);
309                 return;
310         }
311
312         size = mac_msg_size(msg);
313
314         CDEBUG(D_NET,"msg %p type %d, size %ld bytes (%ld mblks)\n", 
315                         msg, type, size, mac_msg_mblks(msg));
316
317         if( size < sizeof( ptl_hdr_t ) ) {
318                 /* XXX what's this for? */
319                 if (ksci->ksci_shuttingdown)
320                         return;
321                 CERROR("kscimacnal: did not receive complete portal header,"
322                                 "size= %ld\n", size);
323                 /* Free the message before exiting */
324                 mac_free_msg(msg);
325                 return;
326         }
327
328         /* Provide everything we know */
329         krx.handle = handle;
330         krx.msg = msg;
331         krx.type = type;
332         krx.userdata = userdata;
333
334         /* mac_msg_next returns the next mblk with unread data */
335         hdr = mac_get_mblk(mac_msg_next(msg), sizeof(ptl_hdr_t) );
336
337         if(!hdr) {
338                 CERROR("kscimacnal: no data block in message %p\n", msg);
339                 mac_free_msg(msg);
340                 return;
341         }
342
343         if ( hdr->dest_nid == kscimacnal_lib.ni.nid ) {
344                 PROF_START(lib_parse);
345                 /* sets wanted_len, iovs etc and calls our callback */
346                 lib_parse(&kscimacnal_lib, hdr, &krx);
347                 PROF_FINISH(lib_parse);
348 #if 0 /* FIXME: Is it possible to detect this? */
349         } else if (kgmnal_ispeer(hdr->dest_nid)) {
350                 /* should have gone direct to peer */
351                 CERROR("dropping packet from 0x%llx to 0x%llx:"
352                                 "target is a  peer\n",
353                                 hdr->src_nid, hdr->dest_nid);
354                 kgmnal_requeue_rx(&krx);
355 #endif /* if 0 FIXME */
356         } else {
357                 /* forward to gateway */
358                 CERROR("forwarding not implemented, mynid=0x%llx dest=0x%llx\n",
359                                 kscimacnal_lib.ni.nid, hdr->dest_nid);
360         }
361
362         mac_free_msg(msg);
363
364         CDEBUG(D_NET, "msg %p: Done\n", msg);
365 }
366
367
368 /* Called by portals to process a recieved packet */
369 static int kscimacnal_recv(nal_cb_t     *nal, 
370                       void         *private, 
371                       lib_msg_t    *cookie, 
372                       unsigned int  niov, 
373                       struct iovec *iov, 
374                       size_t        mlen, 
375                       size_t        rlen)
376 {
377         kscimacnal_rx_t    *krx = private;
378         mac_mblk_t      *mblk;
379         void            *src;
380         mac_size_t       pkt_len;
381         ptl_size_t       iovused=0;
382
383         LASSERT (krx != NULL);
384         LASSERT (krx->msg != NULL);
385
386         CDEBUG(D_NET,"msg %p: mlen=%d, rlen=%d, niov=%d\n",
387                         krx->msg, mlen, rlen, niov);
388
389         /* What was actually received must be >= what sender claims to have
390          * sent.  This is an LASSERT, since lib-move doesn't check cb return
391          * code yet. Also, rlen seems to be negative when mlen==0 so don't
392          * assert on that.
393          */
394         LASSERT (mlen==0 || mac_msg_size(krx->msg) >= sizeof(ptl_hdr_t)+rlen);
395         LASSERT (mlen==0 || mlen <= rlen);
396
397         PROF_START(memcpy);
398
399         /* mac_msg_next returns next mblk with unread data (ie. can
400          * be same mblk */
401         while (mlen != 0 && (mblk = mac_msg_next(krx->msg))) {
402                 pkt_len = mac_mblk_len(mblk);
403                 src = mac_get_mblk(mblk, pkt_len); /* Next unread block */
404
405                 CDEBUG(D_NET,"msg %p: mblk: %p pkt_len: %ld  src: %p\n",
406                                 krx->msg, mblk, pkt_len, src);
407
408                 LASSERT(src != NULL);
409
410                 /* Essentially lib_copy_buf2iov but with continuation support,
411                  * we "gracefully" thrash the argument vars ;) */
412                 while (pkt_len > 0) {
413                         ptl_size_t nob;
414
415                         LASSERT (niov > 0);
416
417                         LASSERT(iovused < iov->iov_len);
418
419                         nob = MIN (iov->iov_len-iovused, pkt_len);
420                         CDEBUG(D_NET, "iovbase: %p iovlen: %d src: %p  nob: %d "
421                                         "iovused: %d\n",
422                                         iov->iov_base, iov->iov_len,
423                                         src, nob, iovused);
424
425                         memcpy (iov->iov_base+iovused, src, nob);
426                         pkt_len -= nob;
427                         src += nob;
428
429                         if(nob+iovused < iov->iov_len) {
430                                 /* We didn't use all of the iov */
431                                 iovused+=nob;
432                         }
433                         else {
434                                 niov--;
435                                 iov++;
436                                 iovused=0;
437                         }
438                 }
439         }
440         PROF_FINISH(memcpy);
441
442         CDEBUG(D_NET, "Calling lib_finalize.\n");
443
444         PROF_START(lib_finalize);
445         lib_finalize(nal, private, cookie);
446         PROF_FINISH(lib_finalize);
447
448         CDEBUG(D_NET, "Done.\n");
449
450         return rlen;
451 }
452
453
454 nal_cb_t kscimacnal_lib = {
455         nal_data:       &kscimacnal_data,               /* NAL private data */
456         cb_send:         kscimacnal_send,
457         cb_send_pages:   NULL,                  /* Ignore for now */
458         cb_recv:         kscimacnal_recv,
459         cb_recv_pages:   NULL,
460         cb_read:         kscimacnal_read,
461         cb_write:        kscimacnal_write,
462         cb_malloc:       kscimacnal_malloc,
463         cb_free:         kscimacnal_free,
464         cb_printf:       kscimacnal_printf,
465         cb_cli:          kscimacnal_cli,
466         cb_sti:          kscimacnal_sti,
467         cb_dist:         kscimacnal_dist
468 };