Merge from vendor branch ZLIB:
[dragonfly.git] / sys / netproto / atm / atm_device.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/atm_device.c,v 1.5 1999/08/28 00:48:35 peter Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/atm_device.c,v 1.7 2005/06/02 22:37:45 dillon Exp $
28  */
29
30 /*
31  * Core ATM Services
32  * -----------------
33  *
34  * ATM device support functions
35  *
36  */
37
38 #include "kern_include.h"
39
40 /*
41  * Private structures for managing allocated kernel memory resources
42  *
43  * For each allocation of kernel memory, one Mem_ent will be used.  
44  * The Mem_ent structures will be allocated in blocks inside of a 
45  * Mem_blk structure.
46  */
47 #define MEM_NMEMENT     10              /* How many Mem_ent's in a Mem_blk */
48
49 struct mem_ent {
50         void            *me_kaddr;      /* Allocated memory address */
51         u_int           me_ksize;       /* Allocated memory length */
52         void            *me_uaddr;      /* Memory address returned to caller */
53         u_int           me_flags;       /* Flags (see below) */
54 };
55 typedef struct mem_ent  Mem_ent;
56
57 /*
58  * Memory entry flags
59  */
60 #define MEF_NONCACHE    1               /* Memory is noncacheable */
61
62
63 struct mem_blk {
64         struct mem_blk  *mb_next;       /* Next block in chain */
65         Mem_ent         mb_mement[MEM_NMEMENT]; /* Allocated memory entries */
66 };
67 typedef struct mem_blk  Mem_blk;
68
69 static Mem_blk          *atm_mem_head = NULL;
70
71 static struct t_atm_cause       atm_dev_cause = {
72         T_ATM_ITU_CODING,
73         T_ATM_LOC_USER,
74         T_ATM_CAUSE_VPCI_VCI_ASSIGNMENT_FAILURE,
75         {0, 0, 0, 0}
76 };
77
78
79 /*
80  * ATM Device Stack Instantiation
81  *
82  * Called from a critical section.
83  *
84  * Arguments
85  *      ssp             pointer to array of stack definition pointers
86  *                      for connection
87  *                      ssp[0] points to upper layer's stack definition
88  *                      ssp[1] points to this layer's stack definition
89  *                      ssp[2] points to lower layer's stack definition
90  *      cvcp            pointer to connection vcc for this stack
91  *
92  * Returns
93  *      0               instantiation successful
94  *      err             instantiation failed - reason indicated
95  *
96  */
97 int
98 atm_dev_inst(ssp, cvcp)
99         struct stack_defn       **ssp;
100         Atm_connvc              *cvcp;
101 {
102         Cmn_unit        *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
103         Cmn_vcc         *cvp;
104         int             err;
105
106         /*
107          * Check to see if device has been initialized
108          */
109         if ((cup->cu_flags & CUF_INITED) == 0)
110                 return ( EIO );
111
112         /*
113          * Validate lower SAP
114          */
115         /*
116          * Device driver is the lowest layer - no need to validate
117          */
118
119         /*
120          * Validate PVC vpi.vci
121          */
122         if (cvcp->cvc_attr.called.addr.address_format == T_ATM_PVC_ADDR) {
123                 /*
124                  * Look through existing circuits - return error if found
125                  */
126                 Atm_addr_pvc    *pp;
127
128                 pp = (Atm_addr_pvc *)cvcp->cvc_attr.called.addr.address;
129                 if (atm_dev_vcc_find(cup, ATM_PVC_GET_VPI(pp),
130                                 ATM_PVC_GET_VCI(pp), 0))
131                         return ( EADDRINUSE );
132         }
133
134         /*
135          * Validate our SAP type
136          */
137         switch ((*(ssp+1))->sd_sap) {
138         case SAP_CPCS_AAL3_4:
139         case SAP_CPCS_AAL5:
140         case SAP_ATM:
141                 break;
142         default:
143                 return (EINVAL);
144         }
145
146         /*
147          * Allocate a VCC control block
148          */
149         if ( ( cvp = (Cmn_vcc *)atm_allocate(cup->cu_vcc_pool) ) == NULL )
150                 return ( ENOMEM );
151         
152         cvp->cv_state = CVS_INST;
153         cvp->cv_toku = (*ssp)->sd_toku;
154         cvp->cv_upper = (*ssp)->sd_upper;
155         cvp->cv_connvc = cvcp;
156
157         /*
158          * Let device have a look at the connection request
159          */
160         err = (*cup->cu_instvcc)(cup, cvp);
161         if (err) {
162                 atm_free((caddr_t)cvp);
163                 return (err);
164         }
165
166         /*
167          * Looks good so far, so link in device VCC
168          */
169         LINK2TAIL ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
170
171         /*
172          * Save my token
173          */
174         (*++ssp)->sd_toku = cvp;
175
176         /*
177          * Pass instantiation down the stack
178          */
179         /*
180          * No need - we're the lowest point.
181          */
182         /* err = (*(ssp + 1))->sd_inst(ssp, cvcp); */
183
184         /*
185          * Save the lower layer's interface info
186          */
187         /*
188          * No need - we're the lowest point
189          */
190         /* cvp->cv_lower = (*++ssp)->sd_lower; */
191         /* cvp->cv_tok1 = (*ssp)->sd_toku; */
192
193         return (0);
194 }
195
196
197 /*
198  * ATM Device Stack Command Handler
199  *
200  * Arguments
201  *      cmd             stack command code
202  *      tok             session token (Cmn_vcc)
203  *      arg1            command specific argument
204  *      arg2            command specific argument
205  *
206  * Returns
207  *      none
208  *
209  */
210 /*ARGSUSED*/
211 void
212 atm_dev_lower(cmd, tok, arg1, arg2)
213         int     cmd;
214         void    *tok;
215         int     arg1;
216         int     arg2;
217 {
218         Cmn_vcc         *cvp = (Cmn_vcc *)tok;
219         Atm_connvc      *cvcp = cvp->cv_connvc;
220         Cmn_unit        *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
221         struct vccb     *vcp;
222         u_int           state;
223
224         switch ( cmd ) {
225
226         case CPCS_INIT:
227                 /*
228                  * Sanity check
229                  */
230                 if ( cvp->cv_state != CVS_INST ) {
231                         log ( LOG_ERR,
232                                 "atm_dev_lower: INIT: tok=%p, state=%d\n",
233                                 tok, cvp->cv_state );
234                         break;
235                 }
236
237                 vcp = cvp->cv_connvc->cvc_vcc;
238
239                 /*
240                  * Validate SVC vpi.vci
241                  */
242                 if ( vcp->vc_type & VCC_SVC ) {
243
244                         if (atm_dev_vcc_find(cup, vcp->vc_vpi, vcp->vc_vci,
245                                         vcp->vc_type & (VCC_IN | VCC_OUT))
246                                                 != cvp){
247                                 log ( LOG_ERR,
248                                   "atm_dev_lower: dup SVC (%d,%d) tok=%p\n",
249                                         vcp->vc_vpi, vcp->vc_vci, tok );
250                                 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
251                                 break;
252                         }
253                 }
254
255                 /*
256                  * Tell the device to open the VCC
257                  */
258                 cvp->cv_state = CVS_INITED;
259                 crit_enter();
260                 if ((*cup->cu_openvcc)(cup, cvp)) {
261                         atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
262                         crit_exit();
263                         break;
264                 }
265                 crit_exit();
266                 break;
267
268         case CPCS_TERM: {
269                 KBuffer         *m, *prev, *next;
270                 int             *ip;
271
272                 crit_enter();
273
274                 /*
275                  * Disconnect the VCC - ignore return code
276                  */
277                 if ((cvp->cv_state == CVS_INITED) || 
278                     (cvp->cv_state == CVS_ACTIVE)) {
279                         (void) (*cup->cu_closevcc)(cup, cvp);
280                 }
281                 cvp->cv_state = CVS_TERM;
282
283                 /*
284                  * Remove from interface list
285                  */
286                 UNLINK ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
287
288                 /*
289                  * Free any buffers from this VCC on the ATM interrupt queue
290                  */
291                 prev = NULL;
292                 for (m = atm_intrq.ifq_head; m; m = next) {
293                         next = KB_QNEXT(m);
294
295                         /*
296                          * See if this entry is for the terminating VCC
297                          */
298                         KB_DATASTART(m, ip, int *);
299                         ip++;
300                         if (*ip == (int)cvp) {
301                                 /*
302                                  * Yep, so dequeue the entry
303                                  */
304                                 if (prev == NULL)
305                                         atm_intrq.ifq_head = next;
306                                 else
307                                         KB_QNEXT(prev) = next;
308
309                                 if (next == NULL)
310                                         atm_intrq.ifq_tail = prev;
311
312                                 atm_intrq.ifq_len--;
313
314                                 /*
315                                  * Free the unwanted buffers
316                                  */
317                                 KB_FREEALL(m);
318                         } else {
319                                 prev = m;
320                         }
321                 }
322                 crit_exit();
323
324                 /*
325                  * Free VCC resources
326                  */
327                 (void) atm_free((caddr_t)cvp);
328                 break;
329                 }
330
331         case CPCS_UNITDATA_INV:
332
333                 /*
334                  * Sanity check
335                  *
336                  * Use temp state variable since we dont want to lock out
337                  * interrupts, but initial VC activation interrupt may
338                  * happen here, changing state somewhere in the middle.
339                  */
340                 state = cvp->cv_state;
341                 if ((state != CVS_ACTIVE) && 
342                     (state != CVS_INITED)) {
343                         log ( LOG_ERR,
344                             "atm_dev_lower: UNITDATA: tok=%p, state=%d\n",
345                                 tok, state );
346                         KB_FREEALL((KBuffer *)arg1);
347                         break;
348                 }
349
350                 /*
351                  * Hand the data off to the device
352                  */
353                 (*cup->cu_output)(cup, cvp, (KBuffer *)arg1);
354
355                 break;
356
357         case CPCS_UABORT_INV:
358                 log ( LOG_ERR,
359                     "atm_dev_lower: unimplemented stack cmd 0x%x, tok=%p\n",
360                         cmd, tok );
361                 break;
362
363         default:
364                 log ( LOG_ERR,
365                         "atm_dev_lower: unknown stack cmd 0x%x, tok=%p\n",
366                         cmd, tok );
367
368         }
369
370         return;
371 }
372
373
374
375 /*
376  * Allocate kernel memory block
377  * 
378  * This function will allocate a kernel memory block of the type specified
379  * in the flags parameter.  The returned address will point to a memory
380  * block of the requested size and alignment.  The memory block will also 
381  * be zeroed.  The alloc/free functions will manage/mask both the OS-specific 
382  * kernel memory management requirements and the bookkeeping required to
383  * deal with data alignment issues. 
384  *
385  * This function should not be called from interrupt level.
386  *
387  * Arguments:
388  *      size    size of memory block to allocate
389  *      align   data alignment requirement 
390  *      flags   allocation flags (ATM_DEV_*)
391  *
392  * Returns:
393  *      uaddr   pointer to aligned memory block
394  *      NULL    unable to allocate memory
395  *
396  */
397 void *         
398 atm_dev_alloc(size, align, flags)
399         u_int           size;
400         u_int           align;
401         u_int           flags;
402 {
403         Mem_blk         *mbp;
404         Mem_ent         *mep;
405         u_int           kalign, ksize;
406         int             i;
407
408         crit_enter();
409
410         /*
411          * Find a free Mem_ent
412          */
413         mep = NULL;
414         for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
415                 for (i = 0; i < MEM_NMEMENT; i++) {
416                         if (mbp->mb_mement[i].me_uaddr == NULL) {
417                                 mep = &mbp->mb_mement[i];
418                                 break;
419                         }
420                 }
421         }
422
423         /*
424          * If there are no free Mem_ent's, then allocate a new Mem_blk
425          * and link it into the chain
426          */
427         if (mep == NULL) {
428                 mbp = KM_ALLOC(sizeof(Mem_blk), M_DEVBUF, 
429                                 M_INTWAIT | M_NULLOK);
430                 if (mbp == NULL) {
431                         log(LOG_ERR, "atm_dev_alloc: Mem_blk failure\n");
432                         crit_exit();
433                         return (NULL);
434                 }
435                 KM_ZERO(mbp, sizeof(Mem_blk));
436
437                 mbp->mb_next = atm_mem_head;
438                 atm_mem_head = mbp;
439                 mep = mbp->mb_mement;
440         }
441
442         /*
443          * Now we need to get the kernel's allocation alignment minimum
444          *
445          * This is obviously very OS-specific stuff
446          */
447         kalign = MINALLOCSIZE;
448
449         /*
450          * Figure out how much memory we must allocate to satify the
451          * user's size and alignment needs
452          */
453         if (align <= kalign)
454                 ksize = size;
455         else
456                 ksize = size + align - kalign;
457
458         /*
459          * Finally, go get the memory
460          */
461         if (flags & ATM_DEV_NONCACHE) {
462                 mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_INTWAIT | M_NULLOK);
463         } else {
464                 mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_INTWAIT | M_NULLOK);
465         }
466
467         if (mep->me_kaddr == NULL) {
468                 log(LOG_ERR, "atm_dev_alloc: %skernel memory unavailable\n",
469                         (flags & ATM_DEV_NONCACHE) ? "non-cacheable " : "");
470                 crit_exit();
471                 return (NULL);
472         }
473
474         /*
475          * Calculate correct alignment address to pass back to user
476          */
477         mep->me_uaddr = (void *) roundup((u_int)mep->me_kaddr, align);
478         mep->me_ksize = ksize;
479         mep->me_flags = flags;
480
481         /*
482          * Clear memory for user
483          */
484         KM_ZERO(mep->me_uaddr, size);
485
486         ATM_DEBUG4("atm_dev_alloc: size=%d, align=%d, flags=%d, uaddr=%p\n", 
487                 size, align, flags, mep->me_uaddr);
488
489         crit_exit();
490
491         return (mep->me_uaddr);
492 }
493
494
495 /*
496  * Free kernel memory block
497  * 
498  * This function will free a kernel memory block previously allocated by
499  * the atm_dev_alloc function.  
500  *
501  * This function should not be called from interrupt level.
502  *
503  * Arguments:
504  *      uaddr   pointer to allocated aligned memory block
505  *
506  * Returns:
507  *      none
508  *
509  */
510 void
511 atm_dev_free(volatile void *uaddr)
512 {
513         Mem_blk         *mbp;
514         Mem_ent         *mep;
515         int             i;
516
517         ATM_DEBUG1("atm_dev_free: uaddr=%p\n", uaddr);
518
519         crit_enter();
520
521         /*
522          * Protect ourselves...
523          */
524         if (uaddr == NULL)
525                 panic("atm_dev_free: trying to free null address");
526
527         /*
528          * Find our associated entry
529          */
530         mep = NULL;
531         for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
532                 for (i = 0; i < MEM_NMEMENT; i++) {
533                         if (mbp->mb_mement[i].me_uaddr == uaddr) {
534                                 mep = &mbp->mb_mement[i];
535                                 break;
536                         }
537                 }
538         }
539
540         /*
541          * If we didn't find our entry, then unceremoniously let the caller
542          * know they screwed up (it certainly couldn't be a bug here...)
543          */
544         if (mep == NULL)
545                 panic("atm_dev_free: trying to free unknown address");
546         
547         /*
548          * Give the memory space back to the kernel
549          */
550         if (mep->me_flags & ATM_DEV_NONCACHE) {
551                 KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF);
552         } else {
553                 KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF);
554         }
555
556         /*
557          * Free our entry
558          */
559         mep->me_uaddr = NULL;
560
561         crit_exit();
562
563         return;
564 }
565
566 /*
567  * Compress buffer chain
568  * 
569  * This function will compress a supplied buffer chain into a minimum number
570  * of kernel buffers.  Typically, this function will be used because the
571  * number of buffers in an output buffer chain is too large for a device's
572  * DMA capabilities.  This should only be called as a last resort, since
573  * all the data copying will surely kill any hopes of decent performance.
574  *
575  * Arguments:
576  *      m       pointer to source buffer chain
577  *
578  * Returns:
579  *      n       pointer to compressed buffer chain
580  *
581  */
582 KBuffer *         
583 atm_dev_compress(m)
584         KBuffer         *m;
585 {
586         KBuffer         *n, *n0, **np;
587         int             len, space;
588         caddr_t         src, dst;
589
590         n = n0 = NULL;
591         np = &n0;
592         dst = NULL;
593         space = 0;
594
595         /*
596          * Copy each source buffer into compressed chain
597          */
598         while (m) {
599
600                 if (space == 0) {
601
602                         /*
603                          * Allocate another buffer for compressed chain
604                          */
605                         KB_ALLOCEXT(n, ATM_DEV_CMPR_LG, KB_F_NOWAIT, KB_T_DATA);
606                         if (n) {
607                                 space = ATM_DEV_CMPR_LG;
608                         } else {
609                                 KB_ALLOC(n, ATM_DEV_CMPR_SM, KB_F_NOWAIT, 
610                                         KB_T_DATA);
611                                 if (n) {
612                                         space = ATM_DEV_CMPR_SM;
613                                 } else {
614                                         /*
615                                          * Unable to get any new buffers, so
616                                          * just return the partially compressed
617                                          * chain and hope...
618                                          */
619                                         *np = m;
620                                         break;
621                                 }
622                         }
623
624                         KB_HEADSET(n, 0);
625                         KB_LEN(n) = 0;
626                         KB_BFRSTART(n, dst, caddr_t);
627
628                         *np = n;
629                         np = &KB_NEXT(n);
630                 }
631
632                 /*
633                  * Copy what we can from source buffer
634                  */
635                 len = MIN(space, KB_LEN(m));
636                 KB_DATASTART(m, src, caddr_t);
637                 KM_COPY(src, dst, len);
638
639                 /*
640                  * Adjust for copied data
641                  */
642                 dst += len;
643                 space -= len;
644
645                 KB_HEADADJ(m, -len);
646                 KB_TAILADJ(n, len);
647
648                 /*
649                  * If we've exhausted our current source buffer, free it
650                  * and move to the next one
651                  */
652                 if (KB_LEN(m) == 0) {
653                         KB_FREEONE(m, m);
654                 }
655         }
656
657         return (n0);
658 }
659
660
661 /*
662  * Locate VCC entry
663  * 
664  * This function will return the VCC entry for a specified interface and
665  * VPI/VCI value.
666  *
667  * Arguments:
668  *      cup     pointer to interface unit structure
669  *      vpi     VPI value
670  *      vci     VCI value
671  *      type    VCC type
672  *
673  * Returns:
674  *      vcp     pointer to located VCC entry matching
675  *      NULL    no VCC found
676  *
677  */
678 Cmn_vcc *
679 atm_dev_vcc_find(cup, vpi, vci, type)
680         Cmn_unit        *cup;
681         u_int           vpi;
682         u_int           vci;
683         u_int           type;
684 {
685         Cmn_vcc         *cvp;
686
687         crit_enter();
688         /*
689          * Go find VCC
690          *
691          * (Probably should stick in a hash table some time)
692          */
693         for (cvp = cup->cu_vcc; cvp; cvp = cvp->cv_next) {
694                 struct vccb     *vcp;
695
696                 vcp = cvp->cv_connvc->cvc_vcc;
697                 if ((vcp->vc_vci == vci) && (vcp->vc_vpi == vpi) && 
698                     ((vcp->vc_type & type) == type))
699                         break;
700         }
701         crit_exit();
702         return (cvp);
703 }
704
705
706 #ifdef notdef
707 /*
708  * Module unloading notification
709  * 
710  * This function must be called just prior to unloading the module from 
711  * memory.  All allocated memory will be freed here and anything else that
712  * needs cleaning up.
713  *
714  * Arguments:
715  *      none
716  *
717  * Returns:
718  *      none
719  *
720  */
721 void
722 atm_unload()
723 {
724         Mem_blk         *mbp;
725         Mem_ent         *mep;
726         int             i;
727
728         crit_enter();
729
730         /*
731          * Free up all of our memory management storage
732          */
733         while (mbp = atm_mem_head) {
734
735                 /*
736                  * Make sure users have freed up all of their memory
737                  */
738                 for (i = 0; i < MEM_NMEMENT; i++) {
739                         if (mbp->mb_mement[i].me_uaddr != NULL) {
740                                 panic("atm_unload: unfreed memory");
741                         }
742                 }
743
744                 atm_mem_head = mbp->mb_next;
745
746                 /*
747                  * Hand this block back to the kernel
748                  */
749                 KM_FREE((caddr_t) mbp, sizeof(Mem_blk), M_DEVBUF);
750         }
751
752         crit_exit();
753
754         return;
755 }
756 #endif  /* notdef */
757
758
759 /*
760  * Print a PDU
761  * 
762  * Arguments:
763  *      cup     pointer to device unit
764  *      cvp     pointer to VCC control block
765  *      m       pointer to pdu buffer chain
766  *      msg     pointer to message string
767  *
768  * Returns:
769  *      none
770  *
771  */
772 void
773 atm_dev_pdu_print(cup, cvp, m, msg)
774         Cmn_unit        *cup;
775         Cmn_vcc         *cvp;
776         KBuffer         *m;
777         char            *msg;
778 {
779         char            buf[128];
780
781         snprintf(buf, sizeof(buf), "%s vcc=(%d,%d)", msg, 
782                 cvp->cv_connvc->cvc_vcc->vc_vpi, 
783                 cvp->cv_connvc->cvc_vcc->vc_vci);
784
785         atm_pdu_print(m, buf);
786 }
787