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