]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/dev/pdq/pdq_ifsubr.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / dev / pdq / pdq_ifsubr.c
1 /*      $NetBSD: pdq_ifsubr.c,v 1.38 2001/12/21 23:21:47 matt Exp $     */
2
3 /*-
4  * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $NetBSD: pdq_ifsubr.c,v 1.12 1997/06/05 01:56:35 thomas Exp$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 /*
33  * DEC PDQ FDDI Controller; code for BSD derived operating systems
34  *
35  *      This module provide bus independent BSD specific O/S functions.
36  *      (ie. it provides an ifnet interface to the rest of the system)
37  */
38
39
40 #define PDQ_OSSUPPORT
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/lock.h>
46 #include <sys/mutex.h>
47 #include <sys/malloc.h>
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
50
51 #include <sys/module.h>
52 #include <sys/bus.h>
53
54 #include <machine/bus.h>
55 #include <machine/resource.h>
56 #include <sys/rman.h> 
57
58 #include <net/if.h>
59 #include <net/if_arp.h>
60 #include <net/if_dl.h>
61 #include <net/if_media.h> 
62 #include <net/if_types.h> 
63 #include <net/fddi.h>
64
65 #include <net/bpf.h>
66
67 #include <dev/pdq/pdq_freebsd.h>
68 #include <dev/pdq/pdqreg.h>
69
70 devclass_t pdq_devclass;
71
72 static void
73 pdq_ifinit(
74     pdq_softc_t *sc)
75 {
76     if (PDQ_IFNET(sc)->if_flags & IFF_UP) {
77         PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_RUNNING;
78         if (PDQ_IFNET(sc)->if_flags & IFF_PROMISC) {
79             sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
80         } else {
81             sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
82         }
83         if (PDQ_IFNET(sc)->if_flags & IFF_LINK1) {
84             sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
85         } else {
86             sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
87         }
88         sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
89         pdq_run(sc->sc_pdq);
90     } else {
91         PDQ_IFNET(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
92         sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
93         pdq_stop(sc->sc_pdq);
94     }
95 }
96 \f
97 static void
98 pdq_ifwatchdog(
99     struct ifnet *ifp)
100 {
101     /*
102      * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
103      * seconds.  Remove all queued packets.
104      */
105
106     ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
107     ifp->if_timer = 0;
108     for (;;) {
109         struct mbuf *m;
110         IFQ_DEQUEUE(&ifp->if_snd, m);
111         if (m == NULL)
112             return;
113         PDQ_OS_DATABUF_FREE(PDQ_OS_IFP_TO_SOFTC(ifp)->sc_pdq, m);
114     }
115 }
116
117 static void
118 pdq_ifstart(
119     struct ifnet *ifp)
120 {
121     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
122     struct mbuf *m;
123     int tx = 0;
124
125     if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
126         return;
127
128     if (PDQ_IFNET(sc)->if_timer == 0)
129         PDQ_IFNET(sc)->if_timer = PDQ_OS_TX_TIMEOUT;
130
131     if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
132         PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_OACTIVE;
133         return;
134     }
135     sc->sc_flags |= PDQIF_DOWNCALL;
136     for (;; tx = 1) {
137         IF_DEQUEUE(&ifp->if_snd, m);
138         if (m == NULL)
139             break;
140 #if defined(PDQ_BUS_DMA) && !defined(PDQ_BUS_DMA_NOTX)
141         if ((m->m_flags & M_HASTXDMAMAP) == 0) {
142             bus_dmamap_t map;
143             if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
144                 m->m_data[0] = PDQ_FDDI_PH0;
145                 m->m_data[1] = PDQ_FDDI_PH1;
146                 m->m_data[2] = PDQ_FDDI_PH2;
147             }
148             if (!bus_dmamap_create(sc->sc_dmatag, m->m_pkthdr.len, 255,
149                                    m->m_pkthdr.len, 0, BUS_DMA_NOWAIT, &map)) {
150                 if (!bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
151                                           BUS_DMA_WRITE|BUS_DMA_NOWAIT)) {
152                     bus_dmamap_sync(sc->sc_dmatag, map, 0, m->m_pkthdr.len,
153                                     BUS_DMASYNC_PREWRITE);
154                     M_SETCTX(m, map);
155                     m->m_flags |= M_HASTXDMAMAP;
156                 }
157             }
158             if ((m->m_flags & M_HASTXDMAMAP) == 0)
159                 break;
160         }
161 #else
162         if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
163             m->m_data[0] = PDQ_FDDI_PH0;
164             m->m_data[1] = PDQ_FDDI_PH1;
165             m->m_data[2] = PDQ_FDDI_PH2;
166         }
167 #endif
168
169         if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE)
170             break;
171     }
172     if (m != NULL) {
173         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
174         IF_PREPEND(&ifp->if_snd, m);
175     }
176     if (tx)
177         PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
178     sc->sc_flags &= ~PDQIF_DOWNCALL;
179 }
180 \f
181 void
182 pdq_os_receive_pdu(
183     pdq_t *pdq,
184     struct mbuf *m,
185     size_t pktlen,
186     int drop)
187 {
188     pdq_softc_t *sc = pdq->pdq_os_ctx;
189     struct ifnet *ifp = PDQ_IFNET(sc);
190     struct fddi_header *fh;
191
192     ifp->if_ipackets++;
193 #if defined(PDQ_BUS_DMA)
194     {
195         /*
196          * Even though the first mbuf start at the first fddi header octet,
197          * the dmamap starts PDQ_OS_HDR_OFFSET octets earlier.  Any additional
198          * mbufs will start normally.
199          */
200         int offset = PDQ_OS_HDR_OFFSET;
201         struct mbuf *m0;
202         for (m0 = m; m0 != NULL; m0 = m0->m_next, offset = 0) {
203             pdq_os_databuf_sync(sc, m0, offset, m0->m_len, BUS_DMASYNC_POSTREAD);
204             bus_dmamap_unload(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
205             bus_dmamap_destroy(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
206             m0->m_flags &= ~M_HASRXDMAMAP;
207             M_SETCTX(m0, NULL);
208         }
209     }
210 #endif
211     m->m_pkthdr.len = pktlen;
212     fh = mtod(m, struct fddi_header *);
213     if (drop || (fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
214         ifp->if_iqdrops++;
215         ifp->if_ierrors++;
216         PDQ_OS_DATABUF_FREE(pdq, m);
217         return;
218     }
219
220     m->m_pkthdr.rcvif = ifp;
221     (*ifp->if_input)(ifp, m);
222 }
223
224 void
225 pdq_os_restart_transmitter(
226     pdq_t *pdq)
227 {
228     pdq_softc_t *sc = pdq->pdq_os_ctx;
229     PDQ_IFNET(sc)->if_drv_flags &= ~IFF_DRV_OACTIVE;
230     if (IFQ_IS_EMPTY(&PDQ_IFNET(sc)->if_snd) == 0) {
231         PDQ_IFNET(sc)->if_timer = PDQ_OS_TX_TIMEOUT;
232         if ((sc->sc_flags & PDQIF_DOWNCALL) == 0)
233             pdq_ifstart(PDQ_IFNET(sc));
234     } else {
235         PDQ_IFNET(sc)->if_timer = 0;
236     }
237 }
238
239 void
240 pdq_os_transmit_done(
241     pdq_t *pdq,
242     struct mbuf *m)
243 {
244     pdq_softc_t *sc = pdq->pdq_os_ctx;
245 #if defined(NBPFILTER) && NBPFILTER > 0
246     if (PQD_IFNET(sc)->if_bpf != NULL)
247         PDQ_BPF_MTAP(sc, m);
248 #endif
249     PDQ_OS_DATABUF_FREE(pdq, m);
250     PDQ_IFNET(sc)->if_opackets++;
251 }
252 \f
253 void
254 pdq_os_addr_fill(
255     pdq_t *pdq,
256     pdq_lanaddr_t *addr,
257     size_t num_addrs)
258 {
259     pdq_softc_t *sc = pdq->pdq_os_ctx;
260     struct ifnet *ifp;
261     struct ifmultiaddr *ifma;
262
263     ifp = sc->ifp;
264
265     /*
266      * ADDR_FILTER_SET is always issued before FILTER_SET so
267      * we can play with PDQ_ALLMULTI and not worry about 
268      * queueing a FILTER_SET ourselves.
269      */
270
271     pdq->pdq_flags &= ~PDQ_ALLMULTI;
272 #if defined(IFF_ALLMULTI)
273     PDQ_IFNET(sc)->if_flags &= ~IFF_ALLMULTI;
274 #endif
275
276     if_maddr_rlock(PDQ_IFNET(sc));
277     for (ifma = TAILQ_FIRST(&PDQ_IFNET(sc)->if_multiaddrs); ifma && num_addrs > 0;
278          ifma = TAILQ_NEXT(ifma, ifma_link)) {
279             char *mcaddr;
280             if (ifma->ifma_addr->sa_family != AF_LINK)
281                     continue;
282             mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
283             ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) mcaddr)[0];
284             ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) mcaddr)[1];
285             ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) mcaddr)[2];
286             addr++;
287             num_addrs--;
288     }
289     if_maddr_runlock(PDQ_IFNET(sc));
290     /*
291      * If not all the address fit into the CAM, turn on all-multicast mode.
292      */
293     if (ifma != NULL) {
294         pdq->pdq_flags |= PDQ_ALLMULTI;
295 #if defined(IFF_ALLMULTI)
296         PDQ_IFNET(sc)->if_flags |= IFF_ALLMULTI;
297 #endif
298     }
299 }
300 \f
301 #if defined(IFM_FDDI)
302 static int
303 pdq_ifmedia_change(
304     struct ifnet *ifp)
305 {
306     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
307
308     if (sc->sc_ifmedia.ifm_media & IFM_FDX) {
309         if ((sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) == 0) {
310             sc->sc_pdq->pdq_flags |= PDQ_WANT_FDX;
311             if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
312                 pdq_run(sc->sc_pdq);
313         }
314     } else if (sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) {
315         sc->sc_pdq->pdq_flags &= ~PDQ_WANT_FDX;
316         if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
317             pdq_run(sc->sc_pdq);
318     }
319
320     return 0;
321 }
322
323 static void
324 pdq_ifmedia_status(
325     struct ifnet *ifp,
326     struct ifmediareq *ifmr)
327 {
328     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
329
330     ifmr->ifm_status = IFM_AVALID;
331     if (sc->sc_pdq->pdq_flags & PDQ_IS_ONRING)
332         ifmr->ifm_status |= IFM_ACTIVE;
333
334     ifmr->ifm_active = (ifmr->ifm_current & ~IFM_FDX);
335     if (sc->sc_pdq->pdq_flags & PDQ_IS_FDX)
336         ifmr->ifm_active |= IFM_FDX;
337 }
338
339 void
340 pdq_os_update_status(
341     pdq_t *pdq,
342     const void *arg)
343 {
344     pdq_softc_t * const sc = pdq->pdq_os_ctx;
345     const pdq_response_status_chars_get_t *rsp = arg;
346     int media = 0;
347
348     switch (rsp->status_chars_get.pmd_type[0]) {
349         case PDQ_PMD_TYPE_ANSI_MUTLI_MODE:         media = IFM_FDDI_MMF; break;
350         case PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1: media = IFM_FDDI_SMF; break;
351         case PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2: media = IFM_FDDI_SMF; break;
352         case PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR: media = IFM_FDDI_UTP; break;
353         default: media |= IFM_MANUAL;
354     }
355
356     if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
357         media |= IFM_FDDI_DA;
358
359     sc->sc_ifmedia.ifm_media = media | IFM_FDDI;
360 }
361 #endif /* defined(IFM_FDDI) */
362 \f
363 static int
364 pdq_ifioctl(
365     struct ifnet *ifp,
366     u_long cmd,
367     caddr_t data)
368 {
369     pdq_softc_t *sc = PDQ_OS_IFP_TO_SOFTC(ifp);
370     int error = 0;
371
372     PDQ_LOCK(sc);
373
374     switch (cmd) {
375         case SIOCSIFFLAGS: {
376             pdq_ifinit(sc);
377             break;
378         }
379
380         case SIOCADDMULTI:
381         case SIOCDELMULTI: {
382             if (PDQ_IFNET(sc)->if_drv_flags & IFF_DRV_RUNNING) {
383                     pdq_run(sc->sc_pdq);
384                 error = 0;
385             }
386             break;
387         }
388
389 #if defined(IFM_FDDI) && defined(SIOCSIFMEDIA)
390         case SIOCSIFMEDIA:
391         case SIOCGIFMEDIA: {
392             struct ifreq *ifr = (struct ifreq *)data;
393             error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
394             break;
395         }
396 #endif
397
398         default: {
399             error = fddi_ioctl(ifp, cmd, data);
400             break;
401         }
402     }
403
404     PDQ_UNLOCK(sc);
405     return error;
406 }
407 \f
408 #ifndef IFF_NOTRAILERS
409 #define IFF_NOTRAILERS  0
410 #endif
411
412 void
413 pdq_ifattach(pdq_softc_t *sc, const pdq_uint8_t *llc)
414 {
415     struct ifnet *ifp;
416
417     ifp = PDQ_IFNET(sc) = if_alloc(IFT_FDDI);
418     if (ifp == NULL)
419         panic("%s: can not if_alloc()", device_get_nameunit(sc->dev));
420
421     mtx_init(&sc->mtx, device_get_nameunit(sc->dev), MTX_NETWORK_LOCK,
422         MTX_DEF | MTX_RECURSE);
423
424     ifp->if_softc = sc;
425     ifp->if_init = (if_init_f_t *)pdq_ifinit;
426     ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
427     ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
428
429     ifp->if_watchdog = pdq_ifwatchdog;
430
431     ifp->if_ioctl = pdq_ifioctl;
432     ifp->if_start = pdq_ifstart;
433
434 #if defined(IFM_FDDI)
435     {
436         const int media = sc->sc_ifmedia.ifm_media;
437         ifmedia_init(&sc->sc_ifmedia, IFM_FDX,
438                      pdq_ifmedia_change, pdq_ifmedia_status);
439         ifmedia_add(&sc->sc_ifmedia, media, 0, 0);
440         ifmedia_set(&sc->sc_ifmedia, media);
441     }
442 #endif
443   
444     fddi_ifattach(ifp, llc, FDDI_BPF_SUPPORTED);
445 }
446
447 void
448 pdq_ifdetach (pdq_softc_t *sc)
449 {
450     struct ifnet *ifp;
451
452     ifp = sc->ifp;
453
454     fddi_ifdetach(ifp, FDDI_BPF_SUPPORTED);
455     if_free(ifp);
456     pdq_stop(sc->sc_pdq);
457     pdq_free(sc->dev);
458
459     return;
460 }
461
462 void
463 pdq_free (device_t dev)
464 {
465         pdq_softc_t *sc;
466
467         sc = device_get_softc(dev);
468
469         if (sc->io)
470                 bus_release_resource(dev, sc->io_type, sc->io_rid, sc->io);
471         if (sc->mem)
472                 bus_release_resource(dev, sc->mem_type, sc->mem_rid, sc->mem);
473         if (sc->irq_ih)
474                 bus_teardown_intr(dev, sc->irq, sc->irq_ih);
475         if (sc->irq)
476                 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
477
478         /*
479          * Destroy the mutex.
480          */
481         if (mtx_initialized(&sc->mtx) != 0) {
482                 mtx_destroy(&sc->mtx);
483         }
484
485         return;
486 }
487
488 #if defined(PDQ_BUS_DMA) 
489 int
490 pdq_os_memalloc_contig(
491     pdq_t *pdq)
492 {
493     pdq_softc_t * const sc = pdq->pdq_os_ctx;
494     bus_dma_segment_t db_segs[1], ui_segs[1], cb_segs[1];
495     int db_nsegs = 0, ui_nsegs = 0;
496     int steps = 0;
497     int not_ok;
498
499     not_ok = bus_dmamem_alloc(sc->sc_dmatag,
500                          sizeof(*pdq->pdq_dbp), sizeof(*pdq->pdq_dbp),
501                          sizeof(*pdq->pdq_dbp), db_segs, 1, &db_nsegs,
502                          BUS_DMA_NOWAIT);
503     if (!not_ok) {
504         steps = 1;
505         not_ok = bus_dmamem_map(sc->sc_dmatag, db_segs, db_nsegs,
506                                 sizeof(*pdq->pdq_dbp), (caddr_t *) &pdq->pdq_dbp,
507                                 BUS_DMA_NOWAIT);
508     }
509     if (!not_ok) {
510         steps = 2;
511         not_ok = bus_dmamap_create(sc->sc_dmatag, db_segs[0].ds_len, 1,
512                                    0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_dbmap);
513     }
514     if (!not_ok) {
515         steps = 3;
516         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_dbmap,
517                                  pdq->pdq_dbp, sizeof(*pdq->pdq_dbp),
518                                  NULL, BUS_DMA_NOWAIT);
519     }
520     if (!not_ok) {
521         steps = 4;
522         pdq->pdq_pa_descriptor_block = sc->sc_dbmap->dm_segs[0].ds_addr;
523         not_ok = bus_dmamem_alloc(sc->sc_dmatag,
524                          PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE,
525                          ui_segs, 1, &ui_nsegs, BUS_DMA_NOWAIT);
526     }
527     if (!not_ok) {
528         steps = 5;
529         not_ok = bus_dmamem_map(sc->sc_dmatag, ui_segs, ui_nsegs,
530                             PDQ_OS_PAGESIZE,
531                             (caddr_t *) &pdq->pdq_unsolicited_info.ui_events,
532                             BUS_DMA_NOWAIT);
533     }
534     if (!not_ok) {
535         steps = 6;
536         not_ok = bus_dmamap_create(sc->sc_dmatag, ui_segs[0].ds_len, 1,
537                                    PDQ_OS_PAGESIZE, 0, BUS_DMA_NOWAIT,
538                                    &sc->sc_uimap);
539     }
540     if (!not_ok) {
541         steps = 7;
542         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_uimap,
543                                  pdq->pdq_unsolicited_info.ui_events,
544                                  PDQ_OS_PAGESIZE, NULL, BUS_DMA_NOWAIT);
545     }
546     if (!not_ok) {
547         steps = 8;
548         pdq->pdq_unsolicited_info.ui_pa_bufstart = sc->sc_uimap->dm_segs[0].ds_addr;
549         cb_segs[0] = db_segs[0];
550         cb_segs[0].ds_addr += offsetof(pdq_descriptor_block_t, pdqdb_consumer);
551         cb_segs[0].ds_len = sizeof(pdq_consumer_block_t);
552         not_ok = bus_dmamem_map(sc->sc_dmatag, cb_segs, 1,
553                                 sizeof(*pdq->pdq_cbp), (caddr_t *) &pdq->pdq_cbp,
554                                 BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
555     }
556     if (!not_ok) {
557         steps = 9;
558         not_ok = bus_dmamap_create(sc->sc_dmatag, cb_segs[0].ds_len, 1,
559                                    0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_cbmap);
560     }
561     if (!not_ok) {
562         steps = 10;
563         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_cbmap,
564                                  (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp),
565                                  NULL, BUS_DMA_NOWAIT);
566     }
567     if (!not_ok) {
568         pdq->pdq_pa_consumer_block = sc->sc_cbmap->dm_segs[0].ds_addr;
569         return not_ok;
570     }
571
572     switch (steps) {
573         case 11: {
574             bus_dmamap_unload(sc->sc_dmatag, sc->sc_cbmap);
575             /* FALL THROUGH */
576         }
577         case 10: {
578             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cbmap);
579             /* FALL THROUGH */
580         }
581         case 9: {
582             bus_dmamem_unmap(sc->sc_dmatag,
583                              (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp));
584             /* FALL THROUGH */
585         }
586         case 8: {
587             bus_dmamap_unload(sc->sc_dmatag, sc->sc_uimap);
588             /* FALL THROUGH */
589         }
590         case 7: {
591             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_uimap);
592             /* FALL THROUGH */
593         }
594         case 6: {
595             bus_dmamem_unmap(sc->sc_dmatag,
596                              (caddr_t) pdq->pdq_unsolicited_info.ui_events,
597                              PDQ_OS_PAGESIZE);
598             /* FALL THROUGH */
599         }
600         case 5: {
601             bus_dmamem_free(sc->sc_dmatag, ui_segs, ui_nsegs);
602             /* FALL THROUGH */
603         }
604         case 4: {
605             bus_dmamap_unload(sc->sc_dmatag, sc->sc_dbmap);
606             /* FALL THROUGH */
607         }
608         case 3: {
609             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dbmap);
610             /* FALL THROUGH */
611         }
612         case 2: {
613             bus_dmamem_unmap(sc->sc_dmatag,
614                              (caddr_t) pdq->pdq_dbp,
615                              sizeof(*pdq->pdq_dbp));
616             /* FALL THROUGH */
617         }
618         case 1: {
619             bus_dmamem_free(sc->sc_dmatag, db_segs, db_nsegs);
620             /* FALL THROUGH */
621         }
622     }
623
624     return not_ok;
625 }
626
627 extern void
628 pdq_os_descriptor_block_sync(
629     pdq_os_ctx_t *sc,
630     size_t offset,
631     size_t length,
632     int ops)
633 {
634     bus_dmamap_sync(sc->sc_dmatag, sc->sc_dbmap, offset, length, ops);
635 }
636
637 extern void
638 pdq_os_consumer_block_sync(
639     pdq_os_ctx_t *sc,
640     int ops)
641 {
642     bus_dmamap_sync(sc->sc_dmatag, sc->sc_cbmap, 0, sizeof(pdq_consumer_block_t), ops);
643 }
644
645 extern void
646 pdq_os_unsolicited_event_sync(
647     pdq_os_ctx_t *sc,
648     size_t offset,
649     size_t length,
650     int ops)
651 {
652     bus_dmamap_sync(sc->sc_dmatag, sc->sc_uimap, offset, length, ops);
653 }
654
655 extern void
656 pdq_os_databuf_sync(
657     pdq_os_ctx_t *sc,
658     struct mbuf *m,
659     size_t offset,
660     size_t length,
661     int ops)
662 {
663     bus_dmamap_sync(sc->sc_dmatag, M_GETCTX(m, bus_dmamap_t), offset, length, ops);
664 }
665
666 extern void
667 pdq_os_databuf_free(
668     pdq_os_ctx_t *sc,
669     struct mbuf *m)
670 {
671     if (m->m_flags & (M_HASRXDMAMAP|M_HASTXDMAMAP)) {
672         bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t);
673         bus_dmamap_unload(sc->sc_dmatag, map);
674         bus_dmamap_destroy(sc->sc_dmatag, map);
675         m->m_flags &= ~(M_HASRXDMAMAP|M_HASTXDMAMAP);
676     }
677     m_freem(m);
678 }
679
680 extern struct mbuf *
681 pdq_os_databuf_alloc(
682     pdq_os_ctx_t *sc)
683 {
684     struct mbuf *m;
685     bus_dmamap_t map;
686
687     MGETHDR(m, M_DONTWAIT, MT_DATA);
688     if (m == NULL) {
689         printf("%s: can't alloc small buf\n", sc->sc_dev.dv_xname);
690         return NULL;
691     }
692     MCLGET(m, M_DONTWAIT);
693     if ((m->m_flags & M_EXT) == 0) {
694         printf("%s: can't alloc cluster\n", sc->sc_dev.dv_xname);
695         m_free(m);
696         return NULL;
697     }
698     m->m_pkthdr.len = m->m_len = PDQ_OS_DATABUF_SIZE;
699
700     if (bus_dmamap_create(sc->sc_dmatag, PDQ_OS_DATABUF_SIZE,
701                            1, PDQ_OS_DATABUF_SIZE, 0, BUS_DMA_NOWAIT, &map)) {
702         printf("%s: can't create dmamap\n", sc->sc_dev.dv_xname);
703         m_free(m);
704         return NULL;
705     }
706     if (bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
707                              BUS_DMA_READ|BUS_DMA_NOWAIT)) {
708         printf("%s: can't load dmamap\n", sc->sc_dev.dv_xname);
709         bus_dmamap_destroy(sc->sc_dmatag, map);
710         m_free(m);
711         return NULL;
712     }
713     m->m_flags |= M_HASRXDMAMAP;
714     M_SETCTX(m, map);
715     return m;
716 }
717 #endif