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