[BACK]Return to dk.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / dkwedge

Annotation of src/sys/dev/dkwedge/dk.c, Revision 1.100

1.100   ! riastrad    1: /*     $NetBSD: dk.c,v 1.99 2020/03/01 03:19:46 riastradh Exp $        */
1.1       thorpej     2:
                      3: /*-
1.27      ad          4:  * Copyright (c) 2004, 2005, 2006, 2007 The NetBSD Foundation, Inc.
1.1       thorpej     5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Jason R. Thorpe.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: #include <sys/cdefs.h>
1.100   ! riastrad   33: __KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.99 2020/03/01 03:19:46 riastradh Exp $");
1.1       thorpej    34:
1.50      pooka      35: #ifdef _KERNEL_OPT
1.1       thorpej    36: #include "opt_dkwedge.h"
1.50      pooka      37: #endif
1.1       thorpej    38:
                     39: #include <sys/param.h>
                     40: #include <sys/systm.h>
                     41: #include <sys/proc.h>
                     42: #include <sys/errno.h>
                     43: #include <sys/pool.h>
                     44: #include <sys/ioctl.h>
                     45: #include <sys/disklabel.h>
                     46: #include <sys/disk.h>
                     47: #include <sys/fcntl.h>
1.5       yamt       48: #include <sys/buf.h>
                     49: #include <sys/bufq.h>
1.1       thorpej    50: #include <sys/vnode.h>
1.3       thorpej    51: #include <sys/stat.h>
1.1       thorpej    52: #include <sys/conf.h>
                     53: #include <sys/callout.h>
                     54: #include <sys/kernel.h>
                     55: #include <sys/malloc.h>
1.2       thorpej    56: #include <sys/device.h>
1.15      elad       57: #include <sys/kauth.h>
1.1       thorpej    58:
                     59: #include <miscfs/specfs/specdev.h>
                     60:
                     61: MALLOC_DEFINE(M_DKWEDGE, "dkwedge", "Disk wedge structures");
                     62:
                     63: typedef enum {
                     64:        DKW_STATE_LARVAL        = 0,
                     65:        DKW_STATE_RUNNING       = 1,
                     66:        DKW_STATE_DYING         = 2,
                     67:        DKW_STATE_DEAD          = 666
                     68: } dkwedge_state_t;
                     69:
                     70: struct dkwedge_softc {
1.65      chs        71:        device_t        sc_dev; /* pointer to our pseudo-device */
1.2       thorpej    72:        struct cfdata   sc_cfdata;      /* our cfdata structure */
1.1       thorpej    73:        uint8_t         sc_wname[128];  /* wedge name (Unicode, UTF-8) */
                     74:
                     75:        dkwedge_state_t sc_state;       /* state this wedge is in */
                     76:
                     77:        struct disk     *sc_parent;     /* parent disk */
                     78:        daddr_t         sc_offset;      /* LBA offset of wedge in parent */
                     79:        uint64_t        sc_size;        /* size of wedge in blocks */
                     80:        char            sc_ptype[32];   /* partition type */
                     81:        dev_t           sc_pdev;        /* cached parent's dev_t */
                     82:                                        /* link on parent's wedge list */
                     83:        LIST_ENTRY(dkwedge_softc) sc_plink;
                     84:
                     85:        struct disk     sc_dk;          /* our own disk structure */
1.9       yamt       86:        struct bufq_state *sc_bufq;     /* buffer queue */
1.1       thorpej    87:        struct callout  sc_restart_ch;  /* callout to restart I/O */
                     88:
1.92      mlelstv    89:        kmutex_t        sc_iolock;
                     90:        kcondvar_t      sc_dkdrn;
1.1       thorpej    91:        u_int           sc_iopend;      /* I/Os pending */
1.92      mlelstv    92:        int             sc_flags;       /* flags (sc_iolock) */
1.1       thorpej    93: };
                     94:
                     95: #define        DK_F_WAIT_DRAIN         0x0001  /* waiting for I/O to drain */
                     96:
                     97: static void    dkstart(struct dkwedge_softc *);
                     98: static void    dkiodone(struct buf *);
                     99: static void    dkrestart(void *);
1.52      jakllsch  100: static void    dkminphys(struct buf *);
1.1       thorpej   101:
1.46      dyoung    102: static int     dklastclose(struct dkwedge_softc *);
1.74      mlelstv   103: static int     dkwedge_cleanup_parent(struct dkwedge_softc *, int);
1.47      dyoung    104: static int     dkwedge_detach(device_t, int);
1.74      mlelstv   105: static void    dkwedge_delall1(struct disk *, bool);
                    106: static int     dkwedge_del1(struct dkwedge_info *, int);
1.87      mlelstv   107: static int     dk_open_parent(dev_t, int, struct vnode **);
1.82      mlelstv   108: static int     dk_close_parent(struct vnode *, int);
1.46      dyoung    109:
1.1       thorpej   110: static dev_type_open(dkopen);
                    111: static dev_type_close(dkclose);
                    112: static dev_type_read(dkread);
                    113: static dev_type_write(dkwrite);
                    114: static dev_type_ioctl(dkioctl);
                    115: static dev_type_strategy(dkstrategy);
                    116: static dev_type_dump(dkdump);
                    117: static dev_type_size(dksize);
1.72      dholland  118: static dev_type_discard(dkdiscard);
1.1       thorpej   119:
                    120: const struct bdevsw dk_bdevsw = {
1.68      dholland  121:        .d_open = dkopen,
                    122:        .d_close = dkclose,
                    123:        .d_strategy = dkstrategy,
                    124:        .d_ioctl = dkioctl,
                    125:        .d_dump = dkdump,
                    126:        .d_psize = dksize,
1.72      dholland  127:        .d_discard = dkdiscard,
1.92      mlelstv   128:        .d_flag = D_DISK | D_MPSAFE
1.1       thorpej   129: };
                    130:
                    131: const struct cdevsw dk_cdevsw = {
1.68      dholland  132:        .d_open = dkopen,
                    133:        .d_close = dkclose,
                    134:        .d_read = dkread,
                    135:        .d_write = dkwrite,
                    136:        .d_ioctl = dkioctl,
                    137:        .d_stop = nostop,
                    138:        .d_tty = notty,
                    139:        .d_poll = nopoll,
                    140:        .d_mmap = nommap,
                    141:        .d_kqfilter = nokqfilter,
1.72      dholland  142:        .d_discard = dkdiscard,
1.92      mlelstv   143:        .d_flag = D_DISK | D_MPSAFE
1.1       thorpej   144: };
                    145:
                    146: static struct dkwedge_softc **dkwedges;
                    147: static u_int ndkwedges;
1.27      ad        148: static krwlock_t dkwedges_lock;
1.1       thorpej   149:
                    150: static LIST_HEAD(, dkwedge_discovery_method) dkwedge_discovery_methods;
1.27      ad        151: static krwlock_t dkwedge_discovery_methods_lock;
1.1       thorpej   152:
                    153: /*
1.2       thorpej   154:  * dkwedge_match:
                    155:  *
                    156:  *     Autoconfiguration match function for pseudo-device glue.
                    157:  */
                    158: static int
1.45      cegger    159: dkwedge_match(device_t parent, cfdata_t match,
1.20      christos  160:     void *aux)
1.2       thorpej   161: {
                    162:
                    163:        /* Pseudo-device; always present. */
                    164:        return (1);
                    165: }
                    166:
                    167: /*
                    168:  * dkwedge_attach:
                    169:  *
                    170:  *     Autoconfiguration attach function for pseudo-device glue.
                    171:  */
                    172: static void
1.45      cegger    173: dkwedge_attach(device_t parent, device_t self,
1.20      christos  174:     void *aux)
1.2       thorpej   175: {
                    176:
1.31      jmcneill  177:        if (!pmf_device_register(self, NULL, NULL))
                    178:                aprint_error_dev(self, "couldn't establish power handler\n");
1.2       thorpej   179: }
                    180:
                    181: CFDRIVER_DECL(dk, DV_DISK, NULL);
1.47      dyoung    182: CFATTACH_DECL3_NEW(dk, 0,
                    183:     dkwedge_match, dkwedge_attach, dkwedge_detach, NULL, NULL, NULL,
                    184:     DVF_DETACH_SHUTDOWN);
1.2       thorpej   185:
                    186: /*
1.1       thorpej   187:  * dkwedge_wait_drain:
                    188:  *
                    189:  *     Wait for I/O on the wedge to drain.
                    190:  */
                    191: static void
                    192: dkwedge_wait_drain(struct dkwedge_softc *sc)
                    193: {
                    194:
1.92      mlelstv   195:        mutex_enter(&sc->sc_iolock);
1.1       thorpej   196:        while (sc->sc_iopend != 0) {
                    197:                sc->sc_flags |= DK_F_WAIT_DRAIN;
1.92      mlelstv   198:                cv_wait(&sc->sc_dkdrn, &sc->sc_iolock);
1.1       thorpej   199:        }
1.92      mlelstv   200:        mutex_exit(&sc->sc_iolock);
1.1       thorpej   201: }
                    202:
                    203: /*
                    204:  * dkwedge_compute_pdev:
                    205:  *
                    206:  *     Compute the parent disk's dev_t.
                    207:  */
                    208: static int
1.74      mlelstv   209: dkwedge_compute_pdev(const char *pname, dev_t *pdevp, enum vtype type)
1.1       thorpej   210: {
                    211:        const char *name, *cp;
1.63      drochner  212:        devmajor_t pmaj;
                    213:        int punit;
1.1       thorpej   214:        char devname[16];
                    215:
                    216:        name = pname;
1.74      mlelstv   217:        switch (type) {
                    218:        case VBLK:
                    219:                pmaj = devsw_name2blk(name, devname, sizeof(devname));
                    220:                break;
                    221:        case VCHR:
                    222:                pmaj = devsw_name2chr(name, devname, sizeof(devname));
                    223:                break;
                    224:        default:
1.75      mlelstv   225:                pmaj = NODEVMAJOR;
1.74      mlelstv   226:                break;
                    227:        }
1.75      mlelstv   228:        if (pmaj == NODEVMAJOR)
1.1       thorpej   229:                return (ENODEV);
1.6       perry     230:
1.1       thorpej   231:        name += strlen(devname);
                    232:        for (cp = name, punit = 0; *cp >= '0' && *cp <= '9'; cp++)
                    233:                punit = (punit * 10) + (*cp - '0');
                    234:        if (cp == name) {
                    235:                /* Invalid parent disk name. */
                    236:                return (ENODEV);
                    237:        }
                    238:
                    239:        *pdevp = MAKEDISKDEV(pmaj, punit, RAW_PART);
                    240:
                    241:        return (0);
                    242: }
                    243:
                    244: /*
                    245:  * dkwedge_array_expand:
                    246:  *
                    247:  *     Expand the dkwedges array.
                    248:  */
                    249: static void
                    250: dkwedge_array_expand(void)
                    251: {
                    252:        int newcnt = ndkwedges + 16;
                    253:        struct dkwedge_softc **newarray, **oldarray;
                    254:
                    255:        newarray = malloc(newcnt * sizeof(*newarray), M_DKWEDGE,
                    256:            M_WAITOK|M_ZERO);
                    257:        if ((oldarray = dkwedges) != NULL)
                    258:                memcpy(newarray, dkwedges, ndkwedges * sizeof(*newarray));
                    259:        dkwedges = newarray;
                    260:        ndkwedges = newcnt;
                    261:        if (oldarray != NULL)
                    262:                free(oldarray, M_DKWEDGE);
                    263: }
                    264:
1.48      haad      265: static void
1.77      mlelstv   266: dk_set_geometry(struct dkwedge_softc *sc, struct disk *pdk)
1.48      haad      267: {
1.77      mlelstv   268:        struct disk *dk = &sc->sc_dk;
                    269:        struct disk_geom *dg = &dk->dk_geom;
1.48      haad      270:
1.66      christos  271:        memset(dg, 0, sizeof(*dg));
1.48      haad      272:
1.86      mlelstv   273:        dg->dg_secperunit = sc->sc_size;
1.77      mlelstv   274:        dg->dg_secsize = DEV_BSIZE << pdk->dk_blkshift;
1.76      mlelstv   275:
                    276:        /* fake numbers, 1 cylinder is 1 MB with default sector size */
1.66      christos  277:        dg->dg_nsectors = 32;
                    278:        dg->dg_ntracks = 64;
1.76      mlelstv   279:        dg->dg_ncylinders = dg->dg_secperunit / (dg->dg_nsectors * dg->dg_ntracks);
1.48      haad      280:
1.77      mlelstv   281:        disk_set_info(sc->sc_dev, dk, NULL);
1.48      haad      282: }
                    283:
1.1       thorpej   284: /*
                    285:  * dkwedge_add:                [exported function]
                    286:  *
                    287:  *     Add a disk wedge based on the provided information.
                    288:  *
                    289:  *     The incoming dkw_devname[] is ignored, instead being
                    290:  *     filled in and returned to the caller.
                    291:  */
                    292: int
                    293: dkwedge_add(struct dkwedge_info *dkw)
                    294: {
                    295:        struct dkwedge_softc *sc, *lsc;
                    296:        struct disk *pdk;
                    297:        u_int unit;
                    298:        int error;
                    299:        dev_t pdev;
                    300:
                    301:        dkw->dkw_parent[sizeof(dkw->dkw_parent) - 1] = '\0';
                    302:        pdk = disk_find(dkw->dkw_parent);
                    303:        if (pdk == NULL)
                    304:                return (ENODEV);
                    305:
1.74      mlelstv   306:        error = dkwedge_compute_pdev(pdk->dk_name, &pdev, VBLK);
1.1       thorpej   307:        if (error)
                    308:                return (error);
                    309:
                    310:        if (dkw->dkw_offset < 0)
                    311:                return (EINVAL);
                    312:
                    313:        sc = malloc(sizeof(*sc), M_DKWEDGE, M_WAITOK|M_ZERO);
                    314:        sc->sc_state = DKW_STATE_LARVAL;
                    315:        sc->sc_parent = pdk;
                    316:        sc->sc_pdev = pdev;
                    317:        sc->sc_offset = dkw->dkw_offset;
                    318:        sc->sc_size = dkw->dkw_size;
                    319:
                    320:        memcpy(sc->sc_wname, dkw->dkw_wname, sizeof(sc->sc_wname));
                    321:        sc->sc_wname[sizeof(sc->sc_wname) - 1] = '\0';
                    322:
                    323:        memcpy(sc->sc_ptype, dkw->dkw_ptype, sizeof(sc->sc_ptype));
                    324:        sc->sc_ptype[sizeof(sc->sc_ptype) - 1] = '\0';
                    325:
1.9       yamt      326:        bufq_alloc(&sc->sc_bufq, "fcfs", 0);
1.1       thorpej   327:
1.26      ad        328:        callout_init(&sc->sc_restart_ch, 0);
1.1       thorpej   329:        callout_setfunc(&sc->sc_restart_ch, dkrestart, sc);
                    330:
1.92      mlelstv   331:        mutex_init(&sc->sc_iolock, MUTEX_DEFAULT, IPL_BIO);
                    332:        cv_init(&sc->sc_dkdrn, "dkdrn");
                    333:
1.1       thorpej   334:        /*
                    335:         * Wedge will be added; increment the wedge count for the parent.
                    336:         * Only allow this to happend if RAW_PART is the only thing open.
                    337:         */
1.27      ad        338:        mutex_enter(&pdk->dk_openlock);
1.1       thorpej   339:        if (pdk->dk_openmask & ~(1 << RAW_PART))
                    340:                error = EBUSY;
                    341:        else {
                    342:                /* Check for wedge overlap. */
                    343:                LIST_FOREACH(lsc, &pdk->dk_wedges, sc_plink) {
                    344:                        daddr_t lastblk = sc->sc_offset + sc->sc_size - 1;
                    345:                        daddr_t llastblk = lsc->sc_offset + lsc->sc_size - 1;
                    346:
                    347:                        if (sc->sc_offset >= lsc->sc_offset &&
                    348:                            sc->sc_offset <= llastblk) {
1.63      drochner  349:                                /* Overlaps the tail of the existing wedge. */
1.1       thorpej   350:                                break;
                    351:                        }
                    352:                        if (lastblk >= lsc->sc_offset &&
                    353:                            lastblk <= llastblk) {
                    354:                                /* Overlaps the head of the existing wedge. */
                    355:                                break;
                    356:                        }
                    357:                }
1.74      mlelstv   358:                if (lsc != NULL) {
                    359:                        if (sc->sc_offset == lsc->sc_offset &&
                    360:                            sc->sc_size == lsc->sc_size &&
                    361:                            strcmp(sc->sc_wname, lsc->sc_wname) == 0)
                    362:                                error = EEXIST;
                    363:                        else
                    364:                                error = EINVAL;
                    365:                } else {
1.1       thorpej   366:                        pdk->dk_nwedges++;
                    367:                        LIST_INSERT_HEAD(&pdk->dk_wedges, sc, sc_plink);
                    368:                }
                    369:        }
1.27      ad        370:        mutex_exit(&pdk->dk_openlock);
1.1       thorpej   371:        if (error) {
1.93      mlelstv   372:                cv_destroy(&sc->sc_dkdrn);
                    373:                mutex_destroy(&sc->sc_iolock);
1.9       yamt      374:                bufq_free(sc->sc_bufq);
1.1       thorpej   375:                free(sc, M_DKWEDGE);
                    376:                return (error);
                    377:        }
                    378:
1.2       thorpej   379:        /* Fill in our cfdata for the pseudo-device glue. */
                    380:        sc->sc_cfdata.cf_name = dk_cd.cd_name;
                    381:        sc->sc_cfdata.cf_atname = dk_ca.ca_name;
                    382:        /* sc->sc_cfdata.cf_unit set below */
1.8       nathanw   383:        sc->sc_cfdata.cf_fstate = FSTATE_STAR;
1.2       thorpej   384:
1.1       thorpej   385:        /* Insert the larval wedge into the array. */
1.27      ad        386:        rw_enter(&dkwedges_lock, RW_WRITER);
1.1       thorpej   387:        for (error = 0;;) {
                    388:                struct dkwedge_softc **scpp;
                    389:
                    390:                /*
                    391:                 * Check for a duplicate wname while searching for
                    392:                 * a slot.
                    393:                 */
                    394:                for (scpp = NULL, unit = 0; unit < ndkwedges; unit++) {
                    395:                        if (dkwedges[unit] == NULL) {
                    396:                                if (scpp == NULL) {
                    397:                                        scpp = &dkwedges[unit];
1.2       thorpej   398:                                        sc->sc_cfdata.cf_unit = unit;
1.1       thorpej   399:                                }
                    400:                        } else {
                    401:                                /* XXX Unicode. */
                    402:                                if (strcmp(dkwedges[unit]->sc_wname,
                    403:                                           sc->sc_wname) == 0) {
                    404:                                        error = EEXIST;
                    405:                                        break;
                    406:                                }
                    407:                        }
                    408:                }
                    409:                if (error)
                    410:                        break;
                    411:                KASSERT(unit == ndkwedges);
                    412:                if (scpp == NULL)
                    413:                        dkwedge_array_expand();
                    414:                else {
1.2       thorpej   415:                        KASSERT(scpp == &dkwedges[sc->sc_cfdata.cf_unit]);
1.1       thorpej   416:                        *scpp = sc;
                    417:                        break;
                    418:                }
                    419:        }
1.27      ad        420:        rw_exit(&dkwedges_lock);
1.1       thorpej   421:        if (error) {
1.27      ad        422:                mutex_enter(&pdk->dk_openlock);
1.1       thorpej   423:                pdk->dk_nwedges--;
                    424:                LIST_REMOVE(sc, sc_plink);
1.27      ad        425:                mutex_exit(&pdk->dk_openlock);
1.1       thorpej   426:
1.93      mlelstv   427:                cv_destroy(&sc->sc_dkdrn);
                    428:                mutex_destroy(&sc->sc_iolock);
1.9       yamt      429:                bufq_free(sc->sc_bufq);
1.1       thorpej   430:                free(sc, M_DKWEDGE);
                    431:                return (error);
                    432:        }
                    433:
1.2       thorpej   434:        /*
                    435:         * Now that we know the unit #, attach a pseudo-device for
                    436:         * this wedge instance.  This will provide us with the
1.65      chs       437:         * device_t necessary for glue to other parts of the system.
1.2       thorpej   438:         *
                    439:         * This should never fail, unless we're almost totally out of
                    440:         * memory.
                    441:         */
                    442:        if ((sc->sc_dev = config_attach_pseudo(&sc->sc_cfdata)) == NULL) {
                    443:                aprint_error("%s%u: unable to attach pseudo-device\n",
                    444:                    sc->sc_cfdata.cf_name, sc->sc_cfdata.cf_unit);
                    445:
1.27      ad        446:                rw_enter(&dkwedges_lock, RW_WRITER);
1.2       thorpej   447:                dkwedges[sc->sc_cfdata.cf_unit] = NULL;
1.27      ad        448:                rw_exit(&dkwedges_lock);
1.2       thorpej   449:
1.27      ad        450:                mutex_enter(&pdk->dk_openlock);
1.2       thorpej   451:                pdk->dk_nwedges--;
                    452:                LIST_REMOVE(sc, sc_plink);
1.27      ad        453:                mutex_exit(&pdk->dk_openlock);
1.2       thorpej   454:
1.93      mlelstv   455:                cv_destroy(&sc->sc_dkdrn);
                    456:                mutex_destroy(&sc->sc_iolock);
1.9       yamt      457:                bufq_free(sc->sc_bufq);
1.2       thorpej   458:                free(sc, M_DKWEDGE);
                    459:                return (ENOMEM);
                    460:        }
1.1       thorpej   461:
                    462:        /* Return the devname to the caller. */
1.36      cegger    463:        strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev),
                    464:                sizeof(dkw->dkw_devname));
1.1       thorpej   465:
                    466:        /*
                    467:         * XXX Really ought to make the disk_attach() and the changing
                    468:         * of state to RUNNING atomic.
                    469:         */
                    470:
1.36      cegger    471:        disk_init(&sc->sc_dk, device_xname(sc->sc_dev), NULL);
1.77      mlelstv   472:        dk_set_geometry(sc, pdk);
1.1       thorpej   473:        disk_attach(&sc->sc_dk);
                    474:
                    475:        /* Disk wedge is ready for use! */
                    476:        sc->sc_state = DKW_STATE_RUNNING;
                    477:
                    478:        /* Announce our arrival. */
1.84      jmcneill  479:        aprint_normal(
                    480:            "%s at %s: \"%s\", %"PRIu64" blocks at %"PRId64", type: %s\n",
                    481:            device_xname(sc->sc_dev), pdk->dk_name,
                    482:            sc->sc_wname,       /* XXX Unicode */
                    483:            sc->sc_size, sc->sc_offset,
                    484:            sc->sc_ptype[0] == '\0' ? "<unknown>" : sc->sc_ptype);
1.1       thorpej   485:
                    486:        return (0);
                    487: }
                    488:
                    489: /*
1.47      dyoung    490:  * dkwedge_find:
1.1       thorpej   491:  *
1.47      dyoung    492:  *     Lookup a disk wedge based on the provided information.
1.1       thorpej   493:  *     NOTE: We look up the wedge based on the wedge devname,
                    494:  *     not wname.
1.47      dyoung    495:  *
                    496:  *     Return NULL if the wedge is not found, otherwise return
                    497:  *     the wedge's softc.  Assign the wedge's unit number to unitp
                    498:  *     if unitp is not NULL.
1.1       thorpej   499:  */
1.47      dyoung    500: static struct dkwedge_softc *
                    501: dkwedge_find(struct dkwedge_info *dkw, u_int *unitp)
1.1       thorpej   502: {
                    503:        struct dkwedge_softc *sc = NULL;
                    504:        u_int unit;
                    505:
                    506:        /* Find our softc. */
                    507:        dkw->dkw_devname[sizeof(dkw->dkw_devname) - 1] = '\0';
1.47      dyoung    508:        rw_enter(&dkwedges_lock, RW_READER);
1.1       thorpej   509:        for (unit = 0; unit < ndkwedges; unit++) {
                    510:                if ((sc = dkwedges[unit]) != NULL &&
1.36      cegger    511:                    strcmp(device_xname(sc->sc_dev), dkw->dkw_devname) == 0 &&
1.1       thorpej   512:                    strcmp(sc->sc_parent->dk_name, dkw->dkw_parent) == 0) {
                    513:                        break;
                    514:                }
                    515:        }
1.27      ad        516:        rw_exit(&dkwedges_lock);
1.1       thorpej   517:        if (unit == ndkwedges)
1.47      dyoung    518:                return NULL;
                    519:
                    520:        if (unitp != NULL)
                    521:                *unitp = unit;
                    522:
                    523:        return sc;
                    524: }
                    525:
                    526: /*
                    527:  * dkwedge_del:                [exported function]
                    528:  *
                    529:  *     Delete a disk wedge based on the provided information.
                    530:  *     NOTE: We look up the wedge based on the wedge devname,
                    531:  *     not wname.
                    532:  */
                    533: int
                    534: dkwedge_del(struct dkwedge_info *dkw)
                    535: {
1.74      mlelstv   536:        return dkwedge_del1(dkw, 0);
                    537: }
                    538:
                    539: int
                    540: dkwedge_del1(struct dkwedge_info *dkw, int flags)
                    541: {
1.47      dyoung    542:        struct dkwedge_softc *sc = NULL;
                    543:
                    544:        /* Find our softc. */
                    545:        if ((sc = dkwedge_find(dkw, NULL)) == NULL)
1.1       thorpej   546:                return (ESRCH);
                    547:
1.74      mlelstv   548:        return config_detach(sc->sc_dev, flags);
1.47      dyoung    549: }
                    550:
                    551: static int
1.74      mlelstv   552: dkwedge_cleanup_parent(struct dkwedge_softc *sc, int flags)
1.47      dyoung    553: {
                    554:        struct disk *dk = &sc->sc_dk;
                    555:        int rc;
                    556:
                    557:        rc = 0;
                    558:        mutex_enter(&dk->dk_openlock);
                    559:        if (dk->dk_openmask == 0)
1.91      mlelstv   560:                /* nothing to do */
                    561:                mutex_exit(&dk->dk_openlock);
1.90      mlelstv   562:        else if ((flags & DETACH_FORCE) == 0) {
1.47      dyoung    563:                rc = EBUSY;
1.90      mlelstv   564:                mutex_exit(&dk->dk_openlock);
                    565:        }  else {
1.57      bouyer    566:                mutex_enter(&sc->sc_parent->dk_rawlock);
1.90      mlelstv   567:                rc = dklastclose(sc); /* releases locks */
1.57      bouyer    568:        }
1.47      dyoung    569:
                    570:        return rc;
                    571: }
                    572:
                    573: /*
                    574:  * dkwedge_detach:
                    575:  *
                    576:  *     Autoconfiguration detach function for pseudo-device glue.
                    577:  */
                    578: static int
                    579: dkwedge_detach(device_t self, int flags)
                    580: {
                    581:        struct dkwedge_softc *sc = NULL;
                    582:        u_int unit;
1.92      mlelstv   583:        int bmaj, cmaj, rc;
1.47      dyoung    584:
                    585:        rw_enter(&dkwedges_lock, RW_WRITER);
                    586:        for (unit = 0; unit < ndkwedges; unit++) {
                    587:                if ((sc = dkwedges[unit]) != NULL && sc->sc_dev == self)
                    588:                        break;
                    589:        }
                    590:        if (unit == ndkwedges)
                    591:                rc = ENXIO;
1.74      mlelstv   592:        else if ((rc = dkwedge_cleanup_parent(sc, flags)) == 0) {
1.47      dyoung    593:                /* Mark the wedge as dying. */
                    594:                sc->sc_state = DKW_STATE_DYING;
                    595:        }
                    596:        rw_exit(&dkwedges_lock);
                    597:
                    598:        if (rc != 0)
                    599:                return rc;
                    600:
                    601:        pmf_device_deregister(self);
1.1       thorpej   602:
                    603:        /* Locate the wedge major numbers. */
                    604:        bmaj = bdevsw_lookup_major(&dk_bdevsw);
                    605:        cmaj = cdevsw_lookup_major(&dk_cdevsw);
                    606:
                    607:        /* Kill any pending restart. */
                    608:        callout_stop(&sc->sc_restart_ch);
                    609:
                    610:        /*
                    611:         * dkstart() will kill any queued buffers now that the
                    612:         * state of the wedge is not RUNNING.  Once we've done
                    613:         * that, wait for any other pending I/O to complete.
                    614:         */
                    615:        dkstart(sc);
                    616:        dkwedge_wait_drain(sc);
                    617:
                    618:        /* Nuke the vnodes for any open instances. */
1.14      thorpej   619:        vdevgone(bmaj, unit, unit, VBLK);
                    620:        vdevgone(cmaj, unit, unit, VCHR);
1.1       thorpej   621:
                    622:        /* Clean up the parent. */
1.74      mlelstv   623:        dkwedge_cleanup_parent(sc, flags | DETACH_FORCE);
1.1       thorpej   624:
                    625:        /* Announce our departure. */
1.36      cegger    626:        aprint_normal("%s at %s (%s) deleted\n", device_xname(sc->sc_dev),
1.1       thorpej   627:            sc->sc_parent->dk_name,
                    628:            sc->sc_wname);      /* XXX Unicode */
                    629:
1.27      ad        630:        mutex_enter(&sc->sc_parent->dk_openlock);
1.1       thorpej   631:        sc->sc_parent->dk_nwedges--;
                    632:        LIST_REMOVE(sc, sc_plink);
1.27      ad        633:        mutex_exit(&sc->sc_parent->dk_openlock);
1.1       thorpej   634:
                    635:        /* Delete our buffer queue. */
1.9       yamt      636:        bufq_free(sc->sc_bufq);
1.1       thorpej   637:
                    638:        /* Detach from the disk list. */
                    639:        disk_detach(&sc->sc_dk);
1.39      plunky    640:        disk_destroy(&sc->sc_dk);
1.1       thorpej   641:
                    642:        /* Poof. */
1.27      ad        643:        rw_enter(&dkwedges_lock, RW_WRITER);
1.1       thorpej   644:        dkwedges[unit] = NULL;
                    645:        sc->sc_state = DKW_STATE_DEAD;
1.27      ad        646:        rw_exit(&dkwedges_lock);
1.1       thorpej   647:
1.92      mlelstv   648:        mutex_destroy(&sc->sc_iolock);
                    649:        cv_destroy(&sc->sc_dkdrn);
                    650:
1.1       thorpej   651:        free(sc, M_DKWEDGE);
                    652:
1.47      dyoung    653:        return 0;
1.1       thorpej   654: }
                    655:
                    656: /*
                    657:  * dkwedge_delall:     [exported function]
                    658:  *
                    659:  *     Delete all of the wedges on the specified disk.  Used when
                    660:  *     a disk is being detached.
                    661:  */
                    662: void
                    663: dkwedge_delall(struct disk *pdk)
                    664: {
1.74      mlelstv   665:        dkwedge_delall1(pdk, false);
                    666: }
                    667:
                    668: static void
                    669: dkwedge_delall1(struct disk *pdk, bool idleonly)
                    670: {
1.1       thorpej   671:        struct dkwedge_info dkw;
                    672:        struct dkwedge_softc *sc;
1.74      mlelstv   673:        int flags;
                    674:
                    675:        flags = DETACH_QUIET;
                    676:        if (!idleonly) flags |= DETACH_FORCE;
1.1       thorpej   677:
                    678:        for (;;) {
1.27      ad        679:                mutex_enter(&pdk->dk_openlock);
1.74      mlelstv   680:                LIST_FOREACH(sc, &pdk->dk_wedges, sc_plink) {
                    681:                        if (!idleonly || sc->sc_dk.dk_openmask == 0)
                    682:                                break;
                    683:                }
                    684:                if (sc == NULL) {
                    685:                        KASSERT(idleonly || pdk->dk_nwedges == 0);
1.27      ad        686:                        mutex_exit(&pdk->dk_openlock);
1.1       thorpej   687:                        return;
                    688:                }
1.94      maya      689:                strlcpy(dkw.dkw_parent, pdk->dk_name, sizeof(dkw.dkw_parent));
1.36      cegger    690:                strlcpy(dkw.dkw_devname, device_xname(sc->sc_dev),
                    691:                        sizeof(dkw.dkw_devname));
1.27      ad        692:                mutex_exit(&pdk->dk_openlock);
1.74      mlelstv   693:                (void) dkwedge_del1(&dkw, flags);
1.1       thorpej   694:        }
                    695: }
                    696:
                    697: /*
                    698:  * dkwedge_list:       [exported function]
                    699:  *
                    700:  *     List all of the wedges on a particular disk.
                    701:  */
                    702: int
1.10      christos  703: dkwedge_list(struct disk *pdk, struct dkwedge_list *dkwl, struct lwp *l)
1.1       thorpej   704: {
                    705:        struct uio uio;
                    706:        struct iovec iov;
                    707:        struct dkwedge_softc *sc;
                    708:        struct dkwedge_info dkw;
                    709:        int error = 0;
                    710:
                    711:        iov.iov_base = dkwl->dkwl_buf;
                    712:        iov.iov_len = dkwl->dkwl_bufsize;
                    713:
                    714:        uio.uio_iov = &iov;
                    715:        uio.uio_iovcnt = 1;
                    716:        uio.uio_offset = 0;
                    717:        uio.uio_resid = dkwl->dkwl_bufsize;
                    718:        uio.uio_rw = UIO_READ;
1.51      pooka     719:        KASSERT(l == curlwp);
                    720:        uio.uio_vmspace = l->l_proc->p_vmspace;
1.1       thorpej   721:
                    722:        dkwl->dkwl_ncopied = 0;
                    723:
1.27      ad        724:        mutex_enter(&pdk->dk_openlock);
1.1       thorpej   725:        LIST_FOREACH(sc, &pdk->dk_wedges, sc_plink) {
                    726:                if (uio.uio_resid < sizeof(dkw))
                    727:                        break;
                    728:
                    729:                if (sc->sc_state != DKW_STATE_RUNNING)
                    730:                        continue;
                    731:
1.36      cegger    732:                strlcpy(dkw.dkw_devname, device_xname(sc->sc_dev),
                    733:                        sizeof(dkw.dkw_devname));
1.1       thorpej   734:                memcpy(dkw.dkw_wname, sc->sc_wname, sizeof(dkw.dkw_wname));
                    735:                dkw.dkw_wname[sizeof(dkw.dkw_wname) - 1] = '\0';
1.94      maya      736:                strlcpy(dkw.dkw_parent, sc->sc_parent->dk_name,
                    737:                    sizeof(dkw.dkw_parent));
1.1       thorpej   738:                dkw.dkw_offset = sc->sc_offset;
                    739:                dkw.dkw_size = sc->sc_size;
1.94      maya      740:                strlcpy(dkw.dkw_ptype, sc->sc_ptype, sizeof(dkw.dkw_ptype));
1.1       thorpej   741:
                    742:                error = uiomove(&dkw, sizeof(dkw), &uio);
                    743:                if (error)
                    744:                        break;
                    745:                dkwl->dkwl_ncopied++;
                    746:        }
                    747:        dkwl->dkwl_nwedges = pdk->dk_nwedges;
1.27      ad        748:        mutex_exit(&pdk->dk_openlock);
1.1       thorpej   749:
                    750:        return (error);
                    751: }
                    752:
1.25      dyoung    753: device_t
                    754: dkwedge_find_by_wname(const char *wname)
                    755: {
                    756:        device_t dv = NULL;
                    757:        struct dkwedge_softc *sc;
                    758:        int i;
                    759:
1.27      ad        760:        rw_enter(&dkwedges_lock, RW_WRITER);
1.25      dyoung    761:        for (i = 0; i < ndkwedges; i++) {
                    762:                if ((sc = dkwedges[i]) == NULL)
                    763:                        continue;
                    764:                if (strcmp(sc->sc_wname, wname) == 0) {
                    765:                        if (dv != NULL) {
                    766:                                printf(
                    767:                                    "WARNING: double match for wedge name %s "
                    768:                                    "(%s, %s)\n", wname, device_xname(dv),
                    769:                                    device_xname(sc->sc_dev));
                    770:                                continue;
                    771:                        }
                    772:                        dv = sc->sc_dev;
                    773:                }
                    774:        }
1.27      ad        775:        rw_exit(&dkwedges_lock);
1.25      dyoung    776:        return dv;
                    777: }
                    778:
1.89      christos  779: device_t
                    780: dkwedge_find_by_parent(const char *name, size_t *i)
                    781: {
                    782:        rw_enter(&dkwedges_lock, RW_WRITER);
                    783:        for (; *i < (size_t)ndkwedges; (*i)++) {
                    784:                struct dkwedge_softc *sc;
                    785:                if ((sc = dkwedges[*i]) == NULL)
                    786:                        continue;
                    787:                if (strcmp(sc->sc_parent->dk_name, name) != 0)
                    788:                        continue;
                    789:                rw_exit(&dkwedges_lock);
                    790:                return sc->sc_dev;
                    791:        }
                    792:        rw_exit(&dkwedges_lock);
                    793:        return NULL;
                    794: }
                    795:
1.25      dyoung    796: void
                    797: dkwedge_print_wnames(void)
                    798: {
                    799:        struct dkwedge_softc *sc;
                    800:        int i;
                    801:
1.27      ad        802:        rw_enter(&dkwedges_lock, RW_WRITER);
1.25      dyoung    803:        for (i = 0; i < ndkwedges; i++) {
                    804:                if ((sc = dkwedges[i]) == NULL)
                    805:                        continue;
                    806:                printf(" wedge:%s", sc->sc_wname);
                    807:        }
1.27      ad        808:        rw_exit(&dkwedges_lock);
1.25      dyoung    809: }
                    810:
1.1       thorpej   811: /*
1.18      uebayasi  812:  * We need a dummy object to stuff into the dkwedge discovery method link
1.1       thorpej   813:  * set to ensure that there is always at least one object in the set.
                    814:  */
                    815: static struct dkwedge_discovery_method dummy_discovery_method;
                    816: __link_set_add_bss(dkwedge_methods, dummy_discovery_method);
                    817:
                    818: /*
1.27      ad        819:  * dkwedge_init:
1.1       thorpej   820:  *
1.27      ad        821:  *     Initialize the disk wedge subsystem.
1.1       thorpej   822:  */
1.27      ad        823: void
                    824: dkwedge_init(void)
1.1       thorpej   825: {
                    826:        __link_set_decl(dkwedge_methods, struct dkwedge_discovery_method);
                    827:        struct dkwedge_discovery_method * const *ddmp;
                    828:        struct dkwedge_discovery_method *lddm, *ddm;
                    829:
1.27      ad        830:        rw_init(&dkwedges_lock);
                    831:        rw_init(&dkwedge_discovery_methods_lock);
                    832:
                    833:        if (config_cfdriver_attach(&dk_cd) != 0)
                    834:                panic("dkwedge: unable to attach cfdriver");
                    835:        if (config_cfattach_attach(dk_cd.cd_name, &dk_ca) != 0)
                    836:                panic("dkwedge: unable to attach cfattach");
1.1       thorpej   837:
1.27      ad        838:        rw_enter(&dkwedge_discovery_methods_lock, RW_WRITER);
1.1       thorpej   839:
                    840:        LIST_INIT(&dkwedge_discovery_methods);
                    841:
                    842:        __link_set_foreach(ddmp, dkwedge_methods) {
                    843:                ddm = *ddmp;
                    844:                if (ddm == &dummy_discovery_method)
                    845:                        continue;
                    846:                if (LIST_EMPTY(&dkwedge_discovery_methods)) {
                    847:                        LIST_INSERT_HEAD(&dkwedge_discovery_methods,
                    848:                                         ddm, ddm_list);
                    849:                        continue;
                    850:                }
                    851:                LIST_FOREACH(lddm, &dkwedge_discovery_methods, ddm_list) {
                    852:                        if (ddm->ddm_priority == lddm->ddm_priority) {
                    853:                                aprint_error("dk-method-%s: method \"%s\" "
                    854:                                    "already exists at priority %d\n",
                    855:                                    ddm->ddm_name, lddm->ddm_name,
                    856:                                    lddm->ddm_priority);
                    857:                                /* Not inserted. */
                    858:                                break;
                    859:                        }
                    860:                        if (ddm->ddm_priority < lddm->ddm_priority) {
                    861:                                /* Higher priority; insert before. */
                    862:                                LIST_INSERT_BEFORE(lddm, ddm, ddm_list);
                    863:                                break;
                    864:                        }
                    865:                        if (LIST_NEXT(lddm, ddm_list) == NULL) {
                    866:                                /* Last one; insert after. */
                    867:                                KASSERT(lddm->ddm_priority < ddm->ddm_priority);
                    868:                                LIST_INSERT_AFTER(lddm, ddm, ddm_list);
                    869:                                break;
                    870:                        }
                    871:                }
                    872:        }
                    873:
1.27      ad        874:        rw_exit(&dkwedge_discovery_methods_lock);
1.1       thorpej   875: }
                    876:
                    877: #ifdef DKWEDGE_AUTODISCOVER
                    878: int    dkwedge_autodiscover = 1;
                    879: #else
                    880: int    dkwedge_autodiscover = 0;
                    881: #endif
                    882:
                    883: /*
                    884:  * dkwedge_discover:   [exported function]
                    885:  *
                    886:  *     Discover the wedges on a newly attached disk.
1.74      mlelstv   887:  *     Remove all unused wedges on the disk first.
1.1       thorpej   888:  */
                    889: void
                    890: dkwedge_discover(struct disk *pdk)
                    891: {
                    892:        struct dkwedge_discovery_method *ddm;
                    893:        struct vnode *vp;
                    894:        int error;
                    895:        dev_t pdev;
                    896:
                    897:        /*
                    898:         * Require people playing with wedges to enable this explicitly.
                    899:         */
                    900:        if (dkwedge_autodiscover == 0)
                    901:                return;
                    902:
1.27      ad        903:        rw_enter(&dkwedge_discovery_methods_lock, RW_READER);
1.1       thorpej   904:
1.74      mlelstv   905:        /*
                    906:         * Use the character device for scanning, the block device
                    907:         * is busy if there are already wedges attached.
                    908:         */
                    909:        error = dkwedge_compute_pdev(pdk->dk_name, &pdev, VCHR);
1.1       thorpej   910:        if (error) {
                    911:                aprint_error("%s: unable to compute pdev, error = %d\n",
                    912:                    pdk->dk_name, error);
                    913:                goto out;
                    914:        }
                    915:
1.74      mlelstv   916:        error = cdevvp(pdev, &vp);
1.1       thorpej   917:        if (error) {
                    918:                aprint_error("%s: unable to find vnode for pdev, error = %d\n",
                    919:                    pdk->dk_name, error);
                    920:                goto out;
                    921:        }
                    922:
                    923:        error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    924:        if (error) {
                    925:                aprint_error("%s: unable to lock vnode for pdev, error = %d\n",
                    926:                    pdk->dk_name, error);
                    927:                vrele(vp);
                    928:                goto out;
                    929:        }
                    930:
1.62      jmcneill  931:        error = VOP_OPEN(vp, FREAD | FSILENT, NOCRED);
1.1       thorpej   932:        if (error) {
1.67      soren     933:                if (error != ENODEV)
                    934:                        aprint_error("%s: unable to open device, error = %d\n",
                    935:                            pdk->dk_name, error);
1.1       thorpej   936:                vput(vp);
                    937:                goto out;
                    938:        }
1.56      hannken   939:        VOP_UNLOCK(vp);
1.1       thorpej   940:
                    941:        /*
1.74      mlelstv   942:         * Remove unused wedges
                    943:         */
                    944:        dkwedge_delall1(pdk, true);
                    945:
                    946:        /*
1.1       thorpej   947:         * For each supported partition map type, look to see if
                    948:         * this map type exists.  If so, parse it and add the
                    949:         * corresponding wedges.
                    950:         */
                    951:        LIST_FOREACH(ddm, &dkwedge_discovery_methods, ddm_list) {
                    952:                error = (*ddm->ddm_discover)(pdk, vp);
                    953:                if (error == 0) {
                    954:                        /* Successfully created wedges; we're done. */
                    955:                        break;
                    956:                }
                    957:        }
                    958:
1.35      ad        959:        error = vn_close(vp, FREAD, NOCRED);
1.1       thorpej   960:        if (error) {
                    961:                aprint_error("%s: unable to close device, error = %d\n",
                    962:                    pdk->dk_name, error);
                    963:                /* We'll just assume the vnode has been cleaned up. */
                    964:        }
1.75      mlelstv   965:
1.1       thorpej   966:  out:
1.27      ad        967:        rw_exit(&dkwedge_discovery_methods_lock);
1.1       thorpej   968: }
                    969:
                    970: /*
                    971:  * dkwedge_read:
                    972:  *
1.37      agc       973:  *     Read some data from the specified disk, used for
1.1       thorpej   974:  *     partition discovery.
                    975:  */
                    976: int
1.20      christos  977: dkwedge_read(struct disk *pdk, struct vnode *vp, daddr_t blkno,
1.19      christos  978:     void *tbuf, size_t len)
1.1       thorpej   979: {
1.74      mlelstv   980:        buf_t *bp;
1.81      mlelstv   981:        int error;
1.82      mlelstv   982:        bool isopen;
                    983:        dev_t bdev;
1.83      pooka     984:        struct vnode *bdvp;
1.74      mlelstv   985:
                    986:        /*
                    987:         * The kernel cannot read from a character device vnode
                    988:         * as physio() only handles user memory.
                    989:         *
1.82      mlelstv   990:         * If the block device has already been opened by a wedge
                    991:         * use that vnode and temporarily bump the open counter.
                    992:         *
                    993:         * Otherwise try to open the block device.
1.74      mlelstv   994:         */
1.1       thorpej   995:
1.82      mlelstv   996:        bdev = devsw_chr2blk(vp->v_rdev);
                    997:
                    998:        mutex_enter(&pdk->dk_rawlock);
                    999:        if (pdk->dk_rawopens != 0) {
                   1000:                KASSERT(pdk->dk_rawvp != NULL);
                   1001:                isopen = true;
                   1002:                ++pdk->dk_rawopens;
1.83      pooka    1003:                bdvp = pdk->dk_rawvp;
1.87      mlelstv  1004:                error = 0;
1.82      mlelstv  1005:        } else {
                   1006:                isopen = false;
1.87      mlelstv  1007:                error = dk_open_parent(bdev, FREAD, &bdvp);
1.82      mlelstv  1008:        }
                   1009:        mutex_exit(&pdk->dk_rawlock);
                   1010:
1.87      mlelstv  1011:        if (error)
                   1012:                return error;
1.82      mlelstv  1013:
1.83      pooka    1014:        bp = getiobuf(bdvp, true);
1.41      ad       1015:        bp->b_flags = B_READ;
1.74      mlelstv  1016:        bp->b_cflags = BC_BUSY;
1.82      mlelstv  1017:        bp->b_dev = bdev;
1.41      ad       1018:        bp->b_data = tbuf;
1.75      mlelstv  1019:        bp->b_bufsize = bp->b_bcount = len;
1.74      mlelstv  1020:        bp->b_blkno = blkno;
1.75      mlelstv  1021:        bp->b_cylinder = 0;
                   1022:        bp->b_error = 0;
1.74      mlelstv  1023:
1.83      pooka    1024:        VOP_STRATEGY(bdvp, bp);
1.74      mlelstv  1025:        error = biowait(bp);
1.41      ad       1026:        putiobuf(bp);
1.1       thorpej  1027:
1.82      mlelstv  1028:        mutex_enter(&pdk->dk_rawlock);
                   1029:        if (isopen) {
                   1030:                --pdk->dk_rawopens;
                   1031:        } else {
1.83      pooka    1032:                dk_close_parent(bdvp, FREAD);
1.82      mlelstv  1033:        }
                   1034:        mutex_exit(&pdk->dk_rawlock);
1.74      mlelstv  1035:
                   1036:        return error;
1.1       thorpej  1037: }
                   1038:
                   1039: /*
                   1040:  * dkwedge_lookup:
                   1041:  *
                   1042:  *     Look up a dkwedge_softc based on the provided dev_t.
                   1043:  */
                   1044: static struct dkwedge_softc *
                   1045: dkwedge_lookup(dev_t dev)
                   1046: {
1.3       thorpej  1047:        int unit = minor(dev);
1.1       thorpej  1048:
                   1049:        if (unit >= ndkwedges)
                   1050:                return (NULL);
                   1051:
                   1052:        KASSERT(dkwedges != NULL);
                   1053:
                   1054:        return (dkwedges[unit]);
                   1055: }
                   1056:
1.87      mlelstv  1057: static int
                   1058: dk_open_parent(dev_t dev, int mode, struct vnode **vpp)
1.82      mlelstv  1059: {
                   1060:        struct vnode *vp;
                   1061:        int error;
                   1062:
                   1063:        error = bdevvp(dev, &vp);
                   1064:        if (error)
1.87      mlelstv  1065:                return error;
1.82      mlelstv  1066:
                   1067:        error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                   1068:        if (error) {
                   1069:                vrele(vp);
1.87      mlelstv  1070:                return error;
1.82      mlelstv  1071:        }
                   1072:        error = VOP_OPEN(vp, mode, NOCRED);
                   1073:        if (error) {
                   1074:                vput(vp);
1.87      mlelstv  1075:                return error;
1.82      mlelstv  1076:        }
                   1077:
                   1078:        /* VOP_OPEN() doesn't do this for us. */
                   1079:        if (mode & FWRITE) {
                   1080:                mutex_enter(vp->v_interlock);
                   1081:                vp->v_writecount++;
                   1082:                mutex_exit(vp->v_interlock);
                   1083:        }
                   1084:
                   1085:        VOP_UNLOCK(vp);
                   1086:
1.87      mlelstv  1087:        *vpp = vp;
                   1088:
                   1089:        return 0;
1.82      mlelstv  1090: }
                   1091:
                   1092: static int
                   1093: dk_close_parent(struct vnode *vp, int mode)
                   1094: {
                   1095:        int error;
                   1096:
                   1097:        error = vn_close(vp, mode, NOCRED);
                   1098:        return error;
                   1099: }
                   1100:
1.1       thorpej  1101: /*
                   1102:  * dkopen:             [devsw entry point]
                   1103:  *
                   1104:  *     Open a wedge.
                   1105:  */
                   1106: static int
1.20      christos 1107: dkopen(dev_t dev, int flags, int fmt, struct lwp *l)
1.1       thorpej  1108: {
                   1109:        struct dkwedge_softc *sc = dkwedge_lookup(dev);
                   1110:        struct vnode *vp;
1.14      thorpej  1111:        int error = 0;
1.1       thorpej  1112:
                   1113:        if (sc == NULL)
                   1114:                return (ENODEV);
                   1115:        if (sc->sc_state != DKW_STATE_RUNNING)
                   1116:                return (ENXIO);
                   1117:
                   1118:        /*
                   1119:         * We go through a complicated little dance to only open the parent
                   1120:         * vnode once per wedge, no matter how many times the wedge is
                   1121:         * opened.  The reason?  We see one dkopen() per open call, but
                   1122:         * only dkclose() on the last close.
                   1123:         */
1.27      ad       1124:        mutex_enter(&sc->sc_dk.dk_openlock);
                   1125:        mutex_enter(&sc->sc_parent->dk_rawlock);
1.3       thorpej  1126:        if (sc->sc_dk.dk_openmask == 0) {
1.23      dyoung   1127:                if (sc->sc_parent->dk_rawopens == 0) {
1.1       thorpej  1128:                        KASSERT(sc->sc_parent->dk_rawvp == NULL);
1.87      mlelstv  1129:                        error = dk_open_parent(sc->sc_pdev, FREAD | FWRITE, &vp);
                   1130:                        if (error)
1.1       thorpej  1131:                                goto popen_fail;
                   1132:                        sc->sc_parent->dk_rawvp = vp;
                   1133:                }
1.24      christos 1134:                sc->sc_parent->dk_rawopens++;
1.1       thorpej  1135:        }
1.17      dbj      1136:        if (fmt == S_IFCHR)
                   1137:                sc->sc_dk.dk_copenmask |= 1;
                   1138:        else
                   1139:                sc->sc_dk.dk_bopenmask |= 1;
                   1140:        sc->sc_dk.dk_openmask =
                   1141:            sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
1.1       thorpej  1142:
                   1143:  popen_fail:
1.27      ad       1144:        mutex_exit(&sc->sc_parent->dk_rawlock);
                   1145:        mutex_exit(&sc->sc_dk.dk_openlock);
1.1       thorpej  1146:        return (error);
                   1147: }
                   1148:
                   1149: /*
1.46      dyoung   1150:  * Caller must hold sc->sc_dk.dk_openlock and sc->sc_parent->dk_rawlock.
                   1151:  */
                   1152: static int
                   1153: dklastclose(struct dkwedge_softc *sc)
                   1154: {
1.98      yamaguch 1155:        struct vnode *vp;
                   1156:        int error = 0;
1.74      mlelstv  1157:
1.98      yamaguch 1158:        vp = NULL;
1.74      mlelstv  1159:        if (sc->sc_parent->dk_rawopens > 0) {
1.98      yamaguch 1160:                if (--sc->sc_parent->dk_rawopens == 0) {
                   1161:                        KASSERT(sc->sc_parent->dk_rawvp != NULL);
                   1162:                        vp = sc->sc_parent->dk_rawvp;
                   1163:                        sc->sc_parent->dk_rawvp = NULL;
                   1164:                }
1.74      mlelstv  1165:        }
                   1166:
                   1167:        mutex_exit(&sc->sc_parent->dk_rawlock);
1.90      mlelstv  1168:        mutex_exit(&sc->sc_dk.dk_openlock);
1.46      dyoung   1169:
1.98      yamaguch 1170:        if (vp) {
                   1171:                dk_close_parent(vp, FREAD | FWRITE);
1.74      mlelstv  1172:        }
                   1173:
1.46      dyoung   1174:        return error;
                   1175: }
                   1176:
                   1177: /*
1.1       thorpej  1178:  * dkclose:            [devsw entry point]
                   1179:  *
                   1180:  *     Close a wedge.
                   1181:  */
                   1182: static int
1.20      christos 1183: dkclose(dev_t dev, int flags, int fmt, struct lwp *l)
1.1       thorpej  1184: {
                   1185:        struct dkwedge_softc *sc = dkwedge_lookup(dev);
                   1186:        int error = 0;
                   1187:
1.59      christos 1188:        if (sc == NULL)
                   1189:                return (ENODEV);
                   1190:        if (sc->sc_state != DKW_STATE_RUNNING)
                   1191:                return (ENXIO);
                   1192:
1.3       thorpej  1193:        KASSERT(sc->sc_dk.dk_openmask != 0);
1.1       thorpej  1194:
1.27      ad       1195:        mutex_enter(&sc->sc_dk.dk_openlock);
                   1196:        mutex_enter(&sc->sc_parent->dk_rawlock);
1.1       thorpej  1197:
1.3       thorpej  1198:        if (fmt == S_IFCHR)
                   1199:                sc->sc_dk.dk_copenmask &= ~1;
                   1200:        else
                   1201:                sc->sc_dk.dk_bopenmask &= ~1;
                   1202:        sc->sc_dk.dk_openmask =
                   1203:            sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
                   1204:
1.46      dyoung   1205:        if (sc->sc_dk.dk_openmask == 0)
1.90      mlelstv  1206:                error = dklastclose(sc); /* releases locks */
                   1207:        else {
1.57      bouyer   1208:                mutex_exit(&sc->sc_parent->dk_rawlock);
1.90      mlelstv  1209:                mutex_exit(&sc->sc_dk.dk_openlock);
                   1210:        }
1.1       thorpej  1211:
                   1212:        return (error);
                   1213: }
                   1214:
                   1215: /*
                   1216:  * dkstragegy:         [devsw entry point]
                   1217:  *
                   1218:  *     Perform I/O based on the wedge I/O strategy.
                   1219:  */
                   1220: static void
                   1221: dkstrategy(struct buf *bp)
                   1222: {
                   1223:        struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev);
1.54      mlelstv  1224:        uint64_t p_size, p_offset;
1.1       thorpej  1225:
1.59      christos 1226:        if (sc == NULL) {
                   1227:                bp->b_error = ENODEV;
                   1228:                goto done;
                   1229:        }
1.60      christos 1230:
                   1231:        if (sc->sc_state != DKW_STATE_RUNNING ||
                   1232:            sc->sc_parent->dk_rawvp == NULL) {
1.1       thorpej  1233:                bp->b_error = ENXIO;
                   1234:                goto done;
                   1235:        }
                   1236:
                   1237:        /* If it's an empty transfer, wake up the top half now. */
                   1238:        if (bp->b_bcount == 0)
                   1239:                goto done;
                   1240:
1.54      mlelstv  1241:        p_offset = sc->sc_offset << sc->sc_parent->dk_blkshift;
                   1242:        p_size   = sc->sc_size << sc->sc_parent->dk_blkshift;
                   1243:
1.1       thorpej  1244:        /* Make sure it's in-range. */
1.54      mlelstv  1245:        if (bounds_check_with_mediasize(bp, DEV_BSIZE, p_size) <= 0)
1.1       thorpej  1246:                goto done;
                   1247:
                   1248:        /* Translate it to the parent's raw LBA. */
1.54      mlelstv  1249:        bp->b_rawblkno = bp->b_blkno + p_offset;
1.1       thorpej  1250:
                   1251:        /* Place it in the queue and start I/O on the unit. */
1.92      mlelstv  1252:        mutex_enter(&sc->sc_iolock);
1.1       thorpej  1253:        sc->sc_iopend++;
1.96      mlelstv  1254:        disk_wait(&sc->sc_dk);
1.43      yamt     1255:        bufq_put(sc->sc_bufq, bp);
1.92      mlelstv  1256:        mutex_exit(&sc->sc_iolock);
                   1257:
1.1       thorpej  1258:        dkstart(sc);
                   1259:        return;
                   1260:
                   1261:  done:
                   1262:        bp->b_resid = bp->b_bcount;
                   1263:        biodone(bp);
                   1264: }
                   1265:
                   1266: /*
                   1267:  * dkstart:
                   1268:  *
                   1269:  *     Start I/O that has been enqueued on the wedge.
                   1270:  */
                   1271: static void
                   1272: dkstart(struct dkwedge_softc *sc)
                   1273: {
1.32      ad       1274:        struct vnode *vp;
1.1       thorpej  1275:        struct buf *bp, *nbp;
                   1276:
1.92      mlelstv  1277:        mutex_enter(&sc->sc_iolock);
                   1278:
1.1       thorpej  1279:        /* Do as much work as has been enqueued. */
1.43      yamt     1280:        while ((bp = bufq_peek(sc->sc_bufq)) != NULL) {
1.92      mlelstv  1281:
1.1       thorpej  1282:                if (sc->sc_state != DKW_STATE_RUNNING) {
1.43      yamt     1283:                        (void) bufq_get(sc->sc_bufq);
1.1       thorpej  1284:                        if (sc->sc_iopend-- == 1 &&
                   1285:                            (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) {
                   1286:                                sc->sc_flags &= ~DK_F_WAIT_DRAIN;
1.92      mlelstv  1287:                                cv_broadcast(&sc->sc_dkdrn);
1.1       thorpej  1288:                        }
1.92      mlelstv  1289:                        mutex_exit(&sc->sc_iolock);
1.1       thorpej  1290:                        bp->b_error = ENXIO;
                   1291:                        bp->b_resid = bp->b_bcount;
                   1292:                        biodone(bp);
1.92      mlelstv  1293:                        mutex_enter(&sc->sc_iolock);
                   1294:                        continue;
1.1       thorpej  1295:                }
                   1296:
1.92      mlelstv  1297:                /* fetch an I/O buf with sc_iolock dropped */
                   1298:                mutex_exit(&sc->sc_iolock);
1.32      ad       1299:                nbp = getiobuf(sc->sc_parent->dk_rawvp, false);
1.92      mlelstv  1300:                mutex_enter(&sc->sc_iolock);
1.1       thorpej  1301:                if (nbp == NULL) {
                   1302:                        /*
                   1303:                         * No resources to run this request; leave the
                   1304:                         * buffer queued up, and schedule a timer to
                   1305:                         * restart the queue in 1/2 a second.
                   1306:                         */
                   1307:                        callout_schedule(&sc->sc_restart_ch, hz / 2);
1.92      mlelstv  1308:                        break;
                   1309:                }
                   1310:
                   1311:                /*
                   1312:                 * fetch buf, this can fail if another thread
                   1313:                 * has already processed the queue, it can also
                   1314:                 * return a completely different buf.
                   1315:                 */
                   1316:                bp = bufq_get(sc->sc_bufq);
                   1317:                if (bp == NULL) {
                   1318:                        mutex_exit(&sc->sc_iolock);
                   1319:                        putiobuf(nbp);
                   1320:                        mutex_enter(&sc->sc_iolock);
                   1321:                        continue;
1.1       thorpej  1322:                }
                   1323:
1.92      mlelstv  1324:                /* Instrumentation. */
                   1325:                disk_busy(&sc->sc_dk);
                   1326:
                   1327:                /* release lock for VOP_STRATEGY */
                   1328:                mutex_exit(&sc->sc_iolock);
1.1       thorpej  1329:
                   1330:                nbp->b_data = bp->b_data;
1.32      ad       1331:                nbp->b_flags = bp->b_flags;
                   1332:                nbp->b_oflags = bp->b_oflags;
                   1333:                nbp->b_cflags = bp->b_cflags;
1.1       thorpej  1334:                nbp->b_iodone = dkiodone;
                   1335:                nbp->b_proc = bp->b_proc;
                   1336:                nbp->b_blkno = bp->b_rawblkno;
                   1337:                nbp->b_dev = sc->sc_parent->dk_rawvp->v_rdev;
                   1338:                nbp->b_bcount = bp->b_bcount;
                   1339:                nbp->b_private = bp;
                   1340:                BIO_COPYPRIO(nbp, bp);
                   1341:
1.32      ad       1342:                vp = nbp->b_vp;
                   1343:                if ((nbp->b_flags & B_READ) == 0) {
1.61      rmind    1344:                        mutex_enter(vp->v_interlock);
1.32      ad       1345:                        vp->v_numoutput++;
1.61      rmind    1346:                        mutex_exit(vp->v_interlock);
1.32      ad       1347:                }
                   1348:                VOP_STRATEGY(vp, nbp);
1.92      mlelstv  1349:
                   1350:                mutex_enter(&sc->sc_iolock);
1.1       thorpej  1351:        }
1.92      mlelstv  1352:
                   1353:        mutex_exit(&sc->sc_iolock);
1.1       thorpej  1354: }
                   1355:
                   1356: /*
                   1357:  * dkiodone:
                   1358:  *
                   1359:  *     I/O to a wedge has completed; alert the top half.
                   1360:  */
                   1361: static void
                   1362: dkiodone(struct buf *bp)
                   1363: {
                   1364:        struct buf *obp = bp->b_private;
                   1365:        struct dkwedge_softc *sc = dkwedge_lookup(obp->b_dev);
                   1366:
1.28      ad       1367:        if (bp->b_error != 0)
1.1       thorpej  1368:                obp->b_error = bp->b_error;
                   1369:        obp->b_resid = bp->b_resid;
1.11      yamt     1370:        putiobuf(bp);
1.1       thorpej  1371:
1.92      mlelstv  1372:        mutex_enter(&sc->sc_iolock);
1.1       thorpej  1373:        if (sc->sc_iopend-- == 1 && (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) {
                   1374:                sc->sc_flags &= ~DK_F_WAIT_DRAIN;
1.92      mlelstv  1375:                cv_broadcast(&sc->sc_dkdrn);
1.1       thorpej  1376:        }
                   1377:
                   1378:        disk_unbusy(&sc->sc_dk, obp->b_bcount - obp->b_resid,
                   1379:            obp->b_flags & B_READ);
1.92      mlelstv  1380:        mutex_exit(&sc->sc_iolock);
1.1       thorpej  1381:
                   1382:        biodone(obp);
                   1383:
                   1384:        /* Kick the queue in case there is more work we can do. */
                   1385:        dkstart(sc);
                   1386: }
                   1387:
                   1388: /*
                   1389:  * dkrestart:
                   1390:  *
                   1391:  *     Restart the work queue after it was stalled due to
                   1392:  *     a resource shortage.  Invoked via a callout.
                   1393:  */
                   1394: static void
                   1395: dkrestart(void *v)
                   1396: {
                   1397:        struct dkwedge_softc *sc = v;
                   1398:
                   1399:        dkstart(sc);
                   1400: }
                   1401:
                   1402: /*
1.52      jakllsch 1403:  * dkminphys:
                   1404:  *
                   1405:  *     Call parent's minphys function.
                   1406:  */
                   1407: static void
                   1408: dkminphys(struct buf *bp)
                   1409: {
                   1410:        struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev);
                   1411:        dev_t dev;
                   1412:
                   1413:        dev = bp->b_dev;
                   1414:        bp->b_dev = sc->sc_pdev;
                   1415:        (*sc->sc_parent->dk_driver->d_minphys)(bp);
                   1416:        bp->b_dev = dev;
                   1417: }
                   1418:
                   1419: /*
1.1       thorpej  1420:  * dkread:             [devsw entry point]
                   1421:  *
                   1422:  *     Read from a wedge.
                   1423:  */
                   1424: static int
1.20      christos 1425: dkread(dev_t dev, struct uio *uio, int flags)
1.1       thorpej  1426: {
                   1427:        struct dkwedge_softc *sc = dkwedge_lookup(dev);
                   1428:
1.59      christos 1429:        if (sc == NULL)
                   1430:                return (ENODEV);
1.1       thorpej  1431:        if (sc->sc_state != DKW_STATE_RUNNING)
                   1432:                return (ENXIO);
1.6       perry    1433:
1.52      jakllsch 1434:        return (physio(dkstrategy, NULL, dev, B_READ, dkminphys, uio));
1.1       thorpej  1435: }
                   1436:
                   1437: /*
                   1438:  * dkwrite:            [devsw entry point]
                   1439:  *
                   1440:  *     Write to a wedge.
                   1441:  */
                   1442: static int
1.20      christos 1443: dkwrite(dev_t dev, struct uio *uio, int flags)
1.1       thorpej  1444: {
                   1445:        struct dkwedge_softc *sc = dkwedge_lookup(dev);
                   1446:
1.59      christos 1447:        if (sc == NULL)
                   1448:                return (ENODEV);
1.1       thorpej  1449:        if (sc->sc_state != DKW_STATE_RUNNING)
                   1450:                return (ENXIO);
1.6       perry    1451:
1.52      jakllsch 1452:        return (physio(dkstrategy, NULL, dev, B_WRITE, dkminphys, uio));
1.1       thorpej  1453: }
                   1454:
                   1455: /*
                   1456:  * dkioctl:            [devsw entry point]
                   1457:  *
                   1458:  *     Perform an ioctl request on a wedge.
                   1459:  */
                   1460: static int
1.22      christos 1461: dkioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1.1       thorpej  1462: {
                   1463:        struct dkwedge_softc *sc = dkwedge_lookup(dev);
                   1464:        int error = 0;
                   1465:
1.59      christos 1466:        if (sc == NULL)
                   1467:                return (ENODEV);
1.1       thorpej  1468:        if (sc->sc_state != DKW_STATE_RUNNING)
                   1469:                return (ENXIO);
1.60      christos 1470:        if (sc->sc_parent->dk_rawvp == NULL)
                   1471:                return (ENXIO);
1.1       thorpej  1472:
1.78      christos 1473:        /*
1.79      christos 1474:         * We pass NODEV instead of our device to indicate we don't
1.78      christos 1475:         * want to handle disklabel ioctls
                   1476:         */
1.79      christos 1477:        error = disk_ioctl(&sc->sc_dk, NODEV, cmd, data, flag, l);
1.48      haad     1478:        if (error != EPASSTHROUGH)
                   1479:                return (error);
                   1480:
                   1481:        error = 0;
                   1482:
1.1       thorpej  1483:        switch (cmd) {
1.95      jdolecek 1484:        case DIOCGSTRATEGY:
                   1485:        case DIOCGCACHE:
1.4       thorpej  1486:        case DIOCCACHESYNC:
1.95      jdolecek 1487:                error = VOP_IOCTL(sc->sc_parent->dk_rawvp, cmd, data, flag,
1.30      pooka    1488:                                          l != NULL ? l->l_cred : NOCRED);
1.4       thorpej  1489:                break;
1.1       thorpej  1490:        case DIOCGWEDGEINFO:
                   1491:            {
1.48      haad     1492:                struct dkwedge_info *dkw = (void *) data;
1.1       thorpej  1493:
1.36      cegger   1494:                strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev),
                   1495:                        sizeof(dkw->dkw_devname));
1.1       thorpej  1496:                memcpy(dkw->dkw_wname, sc->sc_wname, sizeof(dkw->dkw_wname));
                   1497:                dkw->dkw_wname[sizeof(dkw->dkw_wname) - 1] = '\0';
1.94      maya     1498:                strlcpy(dkw->dkw_parent, sc->sc_parent->dk_name,
                   1499:                    sizeof(dkw->dkw_parent));
1.1       thorpej  1500:                dkw->dkw_offset = sc->sc_offset;
                   1501:                dkw->dkw_size = sc->sc_size;
1.94      maya     1502:                strlcpy(dkw->dkw_ptype, sc->sc_ptype, sizeof(dkw->dkw_ptype));
1.1       thorpej  1503:
                   1504:                break;
                   1505:            }
1.100   ! riastrad 1506:        case DIOCGSECTORALIGN:
        !          1507:            {
        !          1508:                struct disk_sectoralign *dsa = data;
        !          1509:                uint32_t r;
        !          1510:
        !          1511:                error = VOP_IOCTL(sc->sc_parent->dk_rawvp, cmd, dsa, flag,
        !          1512:                    l != NULL ? l->l_cred : NOCRED);
        !          1513:                if (error)
        !          1514:                        break;
1.1       thorpej  1515:
1.100   ! riastrad 1516:                r = sc->sc_offset % dsa->dsa_alignment;
        !          1517:                if (r < dsa->dsa_firstaligned)
        !          1518:                        dsa->dsa_firstaligned = dsa->dsa_firstaligned - r;
        !          1519:                else
        !          1520:                        dsa->dsa_firstaligned = (dsa->dsa_firstaligned +
        !          1521:                            dsa->dsa_alignment) - r;
        !          1522:                break;
        !          1523:            }
1.1       thorpej  1524:        default:
                   1525:                error = ENOTTY;
                   1526:        }
                   1527:
                   1528:        return (error);
                   1529: }
                   1530:
                   1531: /*
1.72      dholland 1532:  * dkdiscard:          [devsw entry point]
                   1533:  *
                   1534:  *     Perform a discard-range request on a wedge.
                   1535:  */
                   1536: static int
                   1537: dkdiscard(dev_t dev, off_t pos, off_t len)
                   1538: {
                   1539:        struct dkwedge_softc *sc = dkwedge_lookup(dev);
1.73      riastrad 1540:        unsigned shift;
                   1541:        off_t offset, maxlen;
1.72      dholland 1542:
                   1543:        if (sc == NULL)
                   1544:                return (ENODEV);
                   1545:        if (sc->sc_state != DKW_STATE_RUNNING)
                   1546:                return (ENXIO);
                   1547:        if (sc->sc_parent->dk_rawvp == NULL)
                   1548:                return (ENXIO);
                   1549:
1.73      riastrad 1550:        shift = (sc->sc_parent->dk_blkshift + DEV_BSHIFT);
                   1551:        KASSERT(__type_fit(off_t, sc->sc_size));
                   1552:        KASSERT(__type_fit(off_t, sc->sc_offset));
                   1553:        KASSERT(0 <= sc->sc_offset);
                   1554:        KASSERT(sc->sc_size <= (__type_max(off_t) >> shift));
                   1555:        KASSERT(sc->sc_offset <= ((__type_max(off_t) >> shift) - sc->sc_size));
                   1556:        offset = ((off_t)sc->sc_offset << shift);
                   1557:        maxlen = ((off_t)sc->sc_size << shift);
                   1558:
                   1559:        if (len > maxlen)
                   1560:                return (EINVAL);
                   1561:        if (pos > (maxlen - len))
                   1562:                return (EINVAL);
                   1563:
                   1564:        pos += offset;
1.72      dholland 1565:        return VOP_FDISCARD(sc->sc_parent->dk_rawvp, pos, len);
                   1566: }
                   1567:
                   1568: /*
1.1       thorpej  1569:  * dksize:             [devsw entry point]
                   1570:  *
                   1571:  *     Query the size of a wedge for the purpose of performing a dump
                   1572:  *     or for swapping to.
                   1573:  */
                   1574: static int
                   1575: dksize(dev_t dev)
                   1576: {
1.13      thorpej  1577:        struct dkwedge_softc *sc = dkwedge_lookup(dev);
                   1578:        int rv = -1;
                   1579:
                   1580:        if (sc == NULL)
                   1581:                return (-1);
                   1582:        if (sc->sc_state != DKW_STATE_RUNNING)
1.55      mlelstv  1583:                return (-1);
1.13      thorpej  1584:
1.27      ad       1585:        mutex_enter(&sc->sc_dk.dk_openlock);
                   1586:        mutex_enter(&sc->sc_parent->dk_rawlock);
1.1       thorpej  1587:
1.13      thorpej  1588:        /* Our content type is static, no need to open the device. */
                   1589:
                   1590:        if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) == 0) {
                   1591:                /* Saturate if we are larger than INT_MAX. */
                   1592:                if (sc->sc_size > INT_MAX)
                   1593:                        rv = INT_MAX;
                   1594:                else
                   1595:                        rv = (int) sc->sc_size;
                   1596:        }
                   1597:
1.27      ad       1598:        mutex_exit(&sc->sc_parent->dk_rawlock);
                   1599:        mutex_exit(&sc->sc_dk.dk_openlock);
1.13      thorpej  1600:
                   1601:        return (rv);
1.1       thorpej  1602: }
                   1603:
                   1604: /*
                   1605:  * dkdump:             [devsw entry point]
                   1606:  *
                   1607:  *     Perform a crash dump to a wedge.
                   1608:  */
                   1609: static int
1.23      dyoung   1610: dkdump(dev_t dev, daddr_t blkno, void *va, size_t size)
1.1       thorpej  1611: {
1.23      dyoung   1612:        struct dkwedge_softc *sc = dkwedge_lookup(dev);
                   1613:        const struct bdevsw *bdev;
                   1614:        int rv = 0;
                   1615:
                   1616:        if (sc == NULL)
1.59      christos 1617:                return (ENODEV);
1.23      dyoung   1618:        if (sc->sc_state != DKW_STATE_RUNNING)
                   1619:                return (ENXIO);
                   1620:
1.27      ad       1621:        mutex_enter(&sc->sc_dk.dk_openlock);
                   1622:        mutex_enter(&sc->sc_parent->dk_rawlock);
1.23      dyoung   1623:
                   1624:        /* Our content type is static, no need to open the device. */
                   1625:
1.88      mlelstv  1626:        if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) != 0 &&
1.99      riastrad 1627:            strcmp(sc->sc_ptype, DKW_PTYPE_RAID) != 0 &&
                   1628:            strcmp(sc->sc_ptype, DKW_PTYPE_CGD) != 0) {
1.23      dyoung   1629:                rv = ENXIO;
                   1630:                goto out;
                   1631:        }
                   1632:        if (size % DEV_BSIZE != 0) {
                   1633:                rv = EINVAL;
                   1634:                goto out;
                   1635:        }
1.97      mlelstv  1636:        if (blkno < 0 || blkno + size / DEV_BSIZE > sc->sc_size) {
1.23      dyoung   1637:                printf("%s: blkno (%" PRIu64 ") + size / DEV_BSIZE (%zu) > "
                   1638:                    "sc->sc_size (%" PRIu64 ")\n", __func__, blkno,
                   1639:                    size / DEV_BSIZE, sc->sc_size);
                   1640:                rv = EINVAL;
                   1641:                goto out;
                   1642:        }
                   1643:
                   1644:        bdev = bdevsw_lookup(sc->sc_pdev);
                   1645:        rv = (*bdev->d_dump)(sc->sc_pdev, blkno + sc->sc_offset, va, size);
                   1646:
                   1647: out:
1.27      ad       1648:        mutex_exit(&sc->sc_parent->dk_rawlock);
                   1649:        mutex_exit(&sc->sc_dk.dk_openlock);
1.1       thorpej  1650:
1.23      dyoung   1651:        return rv;
1.1       thorpej  1652: }
1.49      pooka    1653:
                   1654: /*
                   1655:  * config glue
                   1656:  */
                   1657:
1.64      mlelstv  1658: /*
                   1659:  * dkwedge_find_partition
                   1660:  *
                   1661:  *     Find wedge corresponding to the specified parent name
                   1662:  *     and offset/length.
                   1663:  */
                   1664: device_t
                   1665: dkwedge_find_partition(device_t parent, daddr_t startblk, uint64_t nblks)
1.49      pooka    1666: {
1.64      mlelstv  1667:        struct dkwedge_softc *sc;
                   1668:        int i;
                   1669:        device_t wedge = NULL;
1.49      pooka    1670:
1.64      mlelstv  1671:        rw_enter(&dkwedges_lock, RW_READER);
                   1672:        for (i = 0; i < ndkwedges; i++) {
                   1673:                if ((sc = dkwedges[i]) == NULL)
                   1674:                        continue;
                   1675:                if (strcmp(sc->sc_parent->dk_name, device_xname(parent)) == 0 &&
                   1676:                    sc->sc_offset == startblk &&
                   1677:                    sc->sc_size == nblks) {
                   1678:                        if (wedge) {
                   1679:                                printf("WARNING: double match for boot wedge "
                   1680:                                    "(%s, %s)\n",
                   1681:                                    device_xname(wedge),
                   1682:                                    device_xname(sc->sc_dev));
                   1683:                                continue;
                   1684:                        }
                   1685:                        wedge = sc->sc_dev;
                   1686:                }
1.49      pooka    1687:        }
1.64      mlelstv  1688:        rw_exit(&dkwedges_lock);
1.49      pooka    1689:
1.64      mlelstv  1690:        return wedge;
                   1691: }
1.49      pooka    1692:
1.69      christos 1693: const char *
                   1694: dkwedge_get_parent_name(dev_t dev)
                   1695: {
                   1696:        /* XXX: perhaps do this in lookup? */
                   1697:        int bmaj = bdevsw_lookup_major(&dk_bdevsw);
                   1698:        int cmaj = cdevsw_lookup_major(&dk_cdevsw);
                   1699:        if (major(dev) != bmaj && major(dev) != cmaj)
                   1700:                return NULL;
                   1701:        struct dkwedge_softc *sc = dkwedge_lookup(dev);
                   1702:        if (sc == NULL)
                   1703:                return NULL;
                   1704:        return sc->sc_parent->dk_name;
                   1705: }
1.75      mlelstv  1706:

CVSweb <webmaster@jp.NetBSD.org>