1275048Sbr/*- 2275048Sbr * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3275048Sbr * All rights reserved. 4275048Sbr * 5275048Sbr * This software was developed by SRI International and the University of 6275048Sbr * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7275048Sbr * ("CTSRD"), as part of the DARPA CRASH research programme. 8275048Sbr * 9275048Sbr * Redistribution and use in source and binary forms, with or without 10275048Sbr * modification, are permitted provided that the following conditions 11275048Sbr * are met: 12275048Sbr * 1. Redistributions of source code must retain the above copyright 13275048Sbr * notice, this list of conditions and the following disclaimer. 14275048Sbr * 2. Redistributions in binary form must reproduce the above copyright 15275048Sbr * notice, this list of conditions and the following disclaimer in the 16275048Sbr * documentation and/or other materials provided with the distribution. 17275048Sbr * 18275048Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19275048Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20275048Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21275048Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22275048Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23275048Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24275048Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25275048Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26275048Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27275048Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28275048Sbr * SUCH DAMAGE. 29275048Sbr */ 30275048Sbr 31275048Sbr/* 32275048Sbr * BERI virtio block backend driver 33275048Sbr */ 34275048Sbr 35275048Sbr#include <sys/cdefs.h> 36275048Sbr__FBSDID("$FreeBSD: stable/11/sys/dev/beri/virtio/virtio_block.c 315221 2017-03-14 02:06:03Z pfg $"); 37275048Sbr 38275048Sbr#include <sys/param.h> 39275048Sbr#include <sys/systm.h> 40275048Sbr#include <sys/bus.h> 41275048Sbr#include <sys/kernel.h> 42275048Sbr#include <sys/module.h> 43275048Sbr#include <sys/rman.h> 44275048Sbr#include <sys/conf.h> 45275048Sbr#include <sys/stat.h> 46275048Sbr#include <sys/endian.h> 47275048Sbr#include <sys/disk.h> 48275048Sbr#include <sys/vnode.h> 49275048Sbr#include <sys/fcntl.h> 50275048Sbr#include <sys/kthread.h> 51275048Sbr#include <sys/buf.h> 52275048Sbr#include <sys/mdioctl.h> 53275048Sbr#include <sys/namei.h> 54275048Sbr 55275048Sbr#include <machine/bus.h> 56275048Sbr#include <machine/fdt.h> 57275048Sbr#include <machine/cpu.h> 58275048Sbr#include <machine/intr.h> 59275048Sbr 60275048Sbr#include <dev/fdt/fdt_common.h> 61275048Sbr#include <dev/ofw/openfirm.h> 62275048Sbr#include <dev/ofw/ofw_bus.h> 63275048Sbr#include <dev/ofw/ofw_bus_subr.h> 64275048Sbr 65275048Sbr#include <dev/beri/virtio/virtio.h> 66275048Sbr#include <dev/beri/virtio/virtio_mmio_platform.h> 67275048Sbr#include <dev/altera/pio/pio.h> 68275048Sbr#include <dev/virtio/mmio/virtio_mmio.h> 69275048Sbr#include <dev/virtio/block/virtio_blk.h> 70276354Sbryanv#include <dev/virtio/virtio_ids.h> 71276354Sbryanv#include <dev/virtio/virtio_config.h> 72275048Sbr#include <dev/virtio/virtio_ring.h> 73275048Sbr 74275048Sbr#include "pio_if.h" 75275048Sbr 76275048Sbr#define DPRINTF(fmt, ...) 77275048Sbr 78275647Sbr/* We use indirect descriptors */ 79275647Sbr#define NUM_DESCS 1 80275647Sbr#define NUM_QUEUES 1 81275647Sbr 82275647Sbr#define VTBLK_BLK_ID_BYTES 20 83275647Sbr#define VTBLK_MAXSEGS 256 84275647Sbr 85275048Sbrstruct beri_vtblk_softc { 86275048Sbr struct resource *res[1]; 87275048Sbr bus_space_tag_t bst; 88275048Sbr bus_space_handle_t bsh; 89275048Sbr struct cdev *cdev; 90275048Sbr device_t dev; 91275048Sbr int opened; 92275048Sbr device_t pio_recv; 93275048Sbr device_t pio_send; 94275048Sbr struct vqueue_info vs_queues[NUM_QUEUES]; 95275048Sbr char ident[VTBLK_BLK_ID_BYTES]; 96275048Sbr struct ucred *cred; 97275048Sbr struct vnode *vnode; 98275048Sbr struct thread *vtblk_ktd; 99275048Sbr struct sx sc_mtx; 100275048Sbr int beri_mem_offset; 101275048Sbr struct md_ioctl *mdio; 102275048Sbr struct virtio_blk_config *cfg; 103275048Sbr}; 104275048Sbr 105275048Sbrstatic struct resource_spec beri_spec[] = { 106275048Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 107275048Sbr { -1, 0 } 108275048Sbr}; 109275048Sbr 110275048Sbrstatic int 111275048Sbrvtblk_rdwr(struct beri_vtblk_softc *sc, struct iovec *iov, 112275048Sbr int cnt, int offset, int operation, int iolen) 113275048Sbr{ 114275048Sbr struct vnode *vp; 115275048Sbr struct mount *mp; 116275048Sbr struct uio auio; 117275048Sbr int error; 118275048Sbr 119275048Sbr bzero(&auio, sizeof(auio)); 120275048Sbr 121275048Sbr vp = sc->vnode; 122275048Sbr 123275048Sbr KASSERT(vp != NULL, ("file not opened")); 124275048Sbr 125275048Sbr auio.uio_iov = iov; 126275048Sbr auio.uio_iovcnt = cnt; 127275048Sbr auio.uio_offset = offset; 128275048Sbr auio.uio_segflg = UIO_SYSSPACE; 129275048Sbr auio.uio_rw = operation; 130275048Sbr auio.uio_resid = iolen; 131275048Sbr auio.uio_td = curthread; 132275048Sbr 133275048Sbr if (operation == 0) { 134275048Sbr vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 135275048Sbr error = VOP_READ(vp, &auio, IO_DIRECT, sc->cred); 136275048Sbr VOP_UNLOCK(vp, 0); 137275048Sbr } else { 138275048Sbr (void) vn_start_write(vp, &mp, V_WAIT); 139275048Sbr vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 140275048Sbr error = VOP_WRITE(vp, &auio, IO_SYNC, sc->cred); 141275048Sbr VOP_UNLOCK(vp, 0); 142275048Sbr vn_finished_write(mp); 143275048Sbr } 144275048Sbr 145275048Sbr return (error); 146275048Sbr} 147275048Sbr 148275048Sbrstatic void 149275048Sbrvtblk_proc(struct beri_vtblk_softc *sc, struct vqueue_info *vq) 150275048Sbr{ 151275048Sbr struct iovec iov[VTBLK_MAXSEGS + 2]; 152275048Sbr uint16_t flags[VTBLK_MAXSEGS + 2]; 153275048Sbr struct virtio_blk_outhdr *vbh; 154276710Sbr struct iovec *tiov; 155275048Sbr uint8_t *status; 156275048Sbr off_t offset; 157275048Sbr int iolen; 158275048Sbr int type; 159275048Sbr int i, n; 160275048Sbr int err; 161275048Sbr 162275048Sbr n = vq_getchain(sc->beri_mem_offset, vq, iov, 163275048Sbr VTBLK_MAXSEGS + 2, flags); 164275048Sbr KASSERT(n >= 2 && n <= VTBLK_MAXSEGS + 2, 165275048Sbr ("wrong n value %d", n)); 166275048Sbr 167276710Sbr tiov = getcopy(iov, n); 168275048Sbr vbh = iov[0].iov_base; 169275048Sbr 170275048Sbr status = iov[n-1].iov_base; 171275048Sbr KASSERT(iov[n-1].iov_len == 1, 172275048Sbr ("iov_len == %d", iov[n-1].iov_len)); 173275048Sbr 174275048Sbr type = be32toh(vbh->type) & ~VIRTIO_BLK_T_BARRIER; 175275048Sbr offset = be64toh(vbh->sector) * DEV_BSIZE; 176275048Sbr 177275048Sbr iolen = 0; 178275048Sbr for (i = 1; i < (n-1); i++) { 179275048Sbr iolen += iov[i].iov_len; 180275048Sbr } 181275048Sbr 182275048Sbr switch (type) { 183275048Sbr case VIRTIO_BLK_T_OUT: 184275048Sbr case VIRTIO_BLK_T_IN: 185276710Sbr err = vtblk_rdwr(sc, tiov + 1, i - 1, 186275048Sbr offset, type, iolen); 187275048Sbr break; 188275048Sbr case VIRTIO_BLK_T_GET_ID: 189275048Sbr /* Assume a single buffer */ 190275048Sbr strlcpy(iov[1].iov_base, sc->ident, 191275048Sbr MIN(iov[1].iov_len, sizeof(sc->ident))); 192275048Sbr err = 0; 193275048Sbr break; 194275048Sbr case VIRTIO_BLK_T_FLUSH: 195275048Sbr /* Possible? */ 196275048Sbr default: 197275048Sbr err = -ENOSYS; 198275048Sbr break; 199275048Sbr } 200275048Sbr 201275048Sbr if (err < 0) { 202275048Sbr if (err == -ENOSYS) { 203275048Sbr *status = VIRTIO_BLK_S_UNSUPP; 204275048Sbr } else 205275048Sbr *status = VIRTIO_BLK_S_IOERR; 206275048Sbr } else 207275048Sbr *status = VIRTIO_BLK_S_OK; 208275048Sbr 209276710Sbr free(tiov, M_DEVBUF); 210275048Sbr vq_relchain(vq, iov, n, 1); 211275048Sbr} 212275048Sbr 213275048Sbrstatic int 214275048Sbrclose_file(struct beri_vtblk_softc *sc, struct thread *td) 215275048Sbr{ 216275048Sbr int error; 217275048Sbr 218275048Sbr if (sc->vnode != NULL) { 219275048Sbr vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY); 220275048Sbr sc->vnode->v_vflag &= ~VV_MD; 221275048Sbr VOP_UNLOCK(sc->vnode, 0); 222275048Sbr error = vn_close(sc->vnode, (FREAD|FWRITE), 223275048Sbr sc->cred, td); 224275048Sbr if (error != 0) 225275048Sbr return (error); 226275048Sbr sc->vnode = NULL; 227275048Sbr } 228275048Sbr 229275048Sbr if (sc->cred != NULL) 230275048Sbr crfree(sc->cred); 231275048Sbr 232275048Sbr return (0); 233275048Sbr} 234275048Sbr 235275048Sbrstatic int 236275048Sbropen_file(struct beri_vtblk_softc *sc, struct thread *td) 237275048Sbr{ 238275048Sbr struct nameidata nd; 239275048Sbr struct vattr vattr; 240275048Sbr int error; 241275048Sbr int flags; 242275048Sbr 243275048Sbr flags = (FREAD | FWRITE); 244275048Sbr NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, 245275048Sbr sc->mdio->md_file, td); 246275048Sbr error = vn_open(&nd, &flags, 0, NULL); 247275048Sbr if (error != 0) 248275048Sbr return (error); 249275048Sbr NDFREE(&nd, NDF_ONLY_PNBUF); 250275048Sbr 251275048Sbr if (nd.ni_vp->v_type != VREG) { 252275048Sbr return (EINVAL); 253275048Sbr } 254275048Sbr 255275048Sbr error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred); 256275048Sbr if (error != 0) 257275048Sbr return (error); 258275048Sbr 259275048Sbr if (VOP_ISLOCKED(nd.ni_vp) != LK_EXCLUSIVE) { 260275048Sbr vn_lock(nd.ni_vp, LK_UPGRADE | LK_RETRY); 261275048Sbr if (nd.ni_vp->v_iflag & VI_DOOMED) { 262275048Sbr return (1); 263275048Sbr } 264275048Sbr } 265275048Sbr nd.ni_vp->v_vflag |= VV_MD; 266275048Sbr VOP_UNLOCK(nd.ni_vp, 0); 267275048Sbr 268275048Sbr sc->vnode = nd.ni_vp; 269275048Sbr sc->cred = crhold(td->td_ucred); 270275048Sbr 271275048Sbr return (0); 272275048Sbr} 273275048Sbr 274275048Sbrstatic int 275275048Sbrvtblk_notify(struct beri_vtblk_softc *sc) 276275048Sbr{ 277275048Sbr struct vqueue_info *vq; 278275048Sbr int queue; 279275048Sbr int reg; 280275048Sbr 281275048Sbr vq = &sc->vs_queues[0]; 282275048Sbr if (!vq_ring_ready(vq)) 283275048Sbr return (0); 284275048Sbr 285275048Sbr if (!sc->opened) 286275048Sbr return (0); 287275048Sbr 288275048Sbr reg = READ2(sc, VIRTIO_MMIO_QUEUE_NOTIFY); 289275048Sbr queue = be16toh(reg); 290275048Sbr 291275048Sbr KASSERT(queue == 0, ("we support single queue only")); 292275048Sbr 293275048Sbr /* Process new descriptors */ 294275048Sbr vq = &sc->vs_queues[queue]; 295275048Sbr vq->vq_save_used = be16toh(vq->vq_used->idx); 296275048Sbr while (vq_has_descs(vq)) 297275048Sbr vtblk_proc(sc, vq); 298275048Sbr 299275647Sbr /* Interrupt the other side */ 300275647Sbr if ((be16toh(vq->vq_avail->flags) & VRING_AVAIL_F_NO_INTERRUPT) == 0) { 301275647Sbr reg = htobe32(VIRTIO_MMIO_INT_VRING); 302275647Sbr WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg); 303275647Sbr PIO_SET(sc->pio_send, Q_INTR, 1); 304275647Sbr } 305275048Sbr 306275048Sbr return (0); 307275048Sbr} 308275048Sbr 309275048Sbrstatic int 310275048Sbrvq_init(struct beri_vtblk_softc *sc) 311275048Sbr{ 312275048Sbr struct vqueue_info *vq; 313275048Sbr uint8_t *base; 314275048Sbr int size; 315275048Sbr int reg; 316275048Sbr int pfn; 317275048Sbr 318275048Sbr vq = &sc->vs_queues[0]; 319275647Sbr vq->vq_qsize = NUM_DESCS; 320275048Sbr 321275048Sbr reg = READ4(sc, VIRTIO_MMIO_QUEUE_PFN); 322275048Sbr pfn = be32toh(reg); 323275048Sbr vq->vq_pfn = pfn; 324275048Sbr 325275048Sbr size = vring_size(vq->vq_qsize, VRING_ALIGN); 326275048Sbr base = paddr_map(sc->beri_mem_offset, 327275048Sbr (pfn << PAGE_SHIFT), size); 328275048Sbr 329275048Sbr /* First pages are descriptors */ 330275048Sbr vq->vq_desc = (struct vring_desc *)base; 331275048Sbr base += vq->vq_qsize * sizeof(struct vring_desc); 332275048Sbr 333275048Sbr /* Then avail ring */ 334275048Sbr vq->vq_avail = (struct vring_avail *)base; 335275048Sbr base += (2 + vq->vq_qsize + 1) * sizeof(uint16_t); 336275048Sbr 337275048Sbr /* Then it's rounded up to the next page */ 338275048Sbr base = (uint8_t *)roundup2((uintptr_t)base, VRING_ALIGN); 339275048Sbr 340275048Sbr /* And the last pages are the used ring */ 341275048Sbr vq->vq_used = (struct vring_used *)base; 342275048Sbr 343275048Sbr /* Mark queue as allocated, and start at 0 when we use it. */ 344275048Sbr vq->vq_flags = VQ_ALLOC; 345275048Sbr vq->vq_last_avail = 0; 346275048Sbr 347275048Sbr return (0); 348275048Sbr} 349275048Sbr 350275048Sbr 351275048Sbrstatic void 352275048Sbrvtblk_thread(void *arg) 353275048Sbr{ 354275048Sbr struct beri_vtblk_softc *sc; 355275048Sbr int err; 356275048Sbr 357275048Sbr sc = arg; 358275048Sbr 359275048Sbr sx_xlock(&sc->sc_mtx); 360275048Sbr for (;;) { 361275048Sbr err = msleep(sc, &sc->sc_mtx, PCATCH | PZERO, "prd", hz); 362275048Sbr vtblk_notify(sc); 363275048Sbr } 364275048Sbr sx_xunlock(&sc->sc_mtx); 365275048Sbr 366275048Sbr kthread_exit(); 367275048Sbr} 368275048Sbr 369275048Sbrstatic int 370275048Sbrbackend_info(struct beri_vtblk_softc *sc) 371275048Sbr{ 372275048Sbr struct virtio_blk_config *cfg; 373275048Sbr uint32_t *s; 374275048Sbr int reg; 375275048Sbr int i; 376275048Sbr 377275048Sbr /* Specify that we provide block device */ 378275048Sbr reg = htobe32(VIRTIO_ID_BLOCK); 379275048Sbr WRITE4(sc, VIRTIO_MMIO_DEVICE_ID, reg); 380275048Sbr 381275647Sbr /* Queue size */ 382275647Sbr reg = htobe32(NUM_DESCS); 383275647Sbr WRITE4(sc, VIRTIO_MMIO_QUEUE_NUM_MAX, reg); 384275048Sbr 385275048Sbr /* Our features */ 386275048Sbr reg = htobe32(VIRTIO_RING_F_INDIRECT_DESC 387275048Sbr | VIRTIO_BLK_F_BLK_SIZE 388275048Sbr | VIRTIO_BLK_F_SEG_MAX); 389275048Sbr WRITE4(sc, VIRTIO_MMIO_HOST_FEATURES, reg); 390275048Sbr 391275048Sbr cfg = sc->cfg; 392275048Sbr cfg->capacity = htobe64(sc->mdio->md_mediasize / DEV_BSIZE); 393275048Sbr cfg->size_max = 0; /* not negotiated */ 394275048Sbr cfg->seg_max = htobe32(VTBLK_MAXSEGS); 395275048Sbr cfg->blk_size = htobe32(DEV_BSIZE); 396275048Sbr 397275048Sbr s = (uint32_t *)cfg; 398275048Sbr 399275048Sbr for (i = 0; i < sizeof(struct virtio_blk_config); i+=4) { 400275048Sbr WRITE4(sc, VIRTIO_MMIO_CONFIG + i, *s); 401275048Sbr s+=1; 402275048Sbr } 403275048Sbr 404275048Sbr sprintf(sc->ident, "Virtio block backend"); 405275048Sbr 406275048Sbr return (0); 407275048Sbr} 408275048Sbr 409275048Sbrstatic void 410275048Sbrvtblk_intr(void *arg) 411275048Sbr{ 412275048Sbr struct beri_vtblk_softc *sc; 413275048Sbr int pending; 414275048Sbr int reg; 415275048Sbr 416275048Sbr sc = arg; 417275048Sbr 418275048Sbr reg = PIO_READ(sc->pio_recv); 419275048Sbr 420275048Sbr /* Ack */ 421275048Sbr PIO_SET(sc->pio_recv, reg, 0); 422275048Sbr 423275048Sbr pending = htobe32(reg); 424275048Sbr 425275048Sbr if (pending & Q_PFN) { 426275048Sbr vq_init(sc); 427275048Sbr } 428275048Sbr 429275048Sbr if (pending & Q_NOTIFY) { 430275048Sbr wakeup(sc); 431275048Sbr } 432275048Sbr} 433275048Sbr 434275048Sbrstatic int 435275048Sbrberi_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 436275048Sbr int flags, struct thread *td) 437275048Sbr{ 438275048Sbr struct beri_vtblk_softc *sc; 439275048Sbr int err; 440275048Sbr 441275048Sbr sc = dev->si_drv1; 442275048Sbr 443275048Sbr switch (cmd) { 444275048Sbr case MDIOCATTACH: 445275048Sbr /* take file as argument */ 446275048Sbr if (sc->vnode != NULL) { 447275048Sbr /* Already opened */ 448275048Sbr return (1); 449275048Sbr } 450275048Sbr sc->mdio = (struct md_ioctl *)addr; 451275048Sbr backend_info(sc); 452275048Sbr DPRINTF("opening file, td 0x%08x\n", (int)td); 453275048Sbr err = open_file(sc, td); 454275048Sbr if (err) 455275048Sbr return (err); 456275048Sbr PIO_SETUP_IRQ(sc->pio_recv, vtblk_intr, sc); 457275048Sbr sc->opened = 1; 458275048Sbr break; 459275048Sbr case MDIOCDETACH: 460315221Spfg if (sc->vnode == NULL) { 461275048Sbr /* File not opened */ 462275048Sbr return (1); 463275048Sbr } 464275048Sbr sc->opened = 0; 465275048Sbr DPRINTF("closing file, td 0x%08x\n", (int)td); 466275048Sbr err = close_file(sc, td); 467275048Sbr if (err) 468275048Sbr return (err); 469275048Sbr PIO_TEARDOWN_IRQ(sc->pio_recv); 470275048Sbr break; 471275048Sbr default: 472275048Sbr break; 473275048Sbr } 474275048Sbr 475275048Sbr return (0); 476275048Sbr} 477275048Sbr 478275048Sbrstatic struct cdevsw beri_cdevsw = { 479275048Sbr .d_version = D_VERSION, 480275048Sbr .d_ioctl = beri_ioctl, 481275048Sbr .d_name = "virtio block backend", 482275048Sbr}; 483275048Sbr 484275048Sbrstatic int 485275048Sbrberi_vtblk_probe(device_t dev) 486275048Sbr{ 487275048Sbr 488275048Sbr if (!ofw_bus_status_okay(dev)) 489275048Sbr return (ENXIO); 490275048Sbr 491275048Sbr if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-vtblk")) 492275048Sbr return (ENXIO); 493275048Sbr 494275048Sbr device_set_desc(dev, "SRI-Cambridge BERI block"); 495275048Sbr return (BUS_PROBE_DEFAULT); 496275048Sbr} 497275048Sbr 498275048Sbrstatic int 499275048Sbrberi_vtblk_attach(device_t dev) 500275048Sbr{ 501275048Sbr struct beri_vtblk_softc *sc; 502275048Sbr int error; 503275048Sbr 504275048Sbr sc = device_get_softc(dev); 505275048Sbr sc->dev = dev; 506275048Sbr 507275048Sbr if (bus_alloc_resources(dev, beri_spec, sc->res)) { 508275048Sbr device_printf(dev, "could not allocate resources\n"); 509275048Sbr return (ENXIO); 510275048Sbr } 511275048Sbr 512275048Sbr /* Memory interface */ 513275048Sbr sc->bst = rman_get_bustag(sc->res[0]); 514275048Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 515275048Sbr 516275048Sbr sc->cfg = malloc(sizeof(struct virtio_blk_config), 517275048Sbr M_DEVBUF, M_NOWAIT|M_ZERO); 518275048Sbr 519275048Sbr sx_init(&sc->sc_mtx, device_get_nameunit(sc->dev)); 520275048Sbr 521275048Sbr error = kthread_add(vtblk_thread, sc, NULL, &sc->vtblk_ktd, 522275048Sbr 0, 0, "beri_virtio_block"); 523275048Sbr if (error) { 524275048Sbr device_printf(dev, "cannot create kthread\n"); 525275048Sbr return (ENXIO); 526275048Sbr } 527275048Sbr 528275647Sbr if (setup_offset(dev, &sc->beri_mem_offset) != 0) 529275048Sbr return (ENXIO); 530275647Sbr if (setup_pio(dev, "pio-send", &sc->pio_send) != 0) 531275048Sbr return (ENXIO); 532275647Sbr if (setup_pio(dev, "pio-recv", &sc->pio_recv) != 0) 533275048Sbr return (ENXIO); 534275048Sbr 535275048Sbr sc->cdev = make_dev(&beri_cdevsw, 0, UID_ROOT, GID_WHEEL, 536275048Sbr S_IRWXU, "beri_vtblk"); 537275048Sbr if (sc->cdev == NULL) { 538275048Sbr device_printf(dev, "Failed to create character device.\n"); 539275048Sbr return (ENXIO); 540275048Sbr } 541275048Sbr 542275048Sbr sc->cdev->si_drv1 = sc; 543275048Sbr return (0); 544275048Sbr} 545275048Sbr 546275048Sbrstatic device_method_t beri_vtblk_methods[] = { 547275048Sbr DEVMETHOD(device_probe, beri_vtblk_probe), 548275048Sbr DEVMETHOD(device_attach, beri_vtblk_attach), 549275048Sbr { 0, 0 } 550275048Sbr}; 551275048Sbr 552275048Sbrstatic driver_t beri_vtblk_driver = { 553275048Sbr "beri_vtblk", 554275048Sbr beri_vtblk_methods, 555275048Sbr sizeof(struct beri_vtblk_softc), 556275048Sbr}; 557275048Sbr 558275048Sbrstatic devclass_t beri_vtblk_devclass; 559275048Sbr 560275048SbrDRIVER_MODULE(beri_vtblk, simplebus, beri_vtblk_driver, 561275048Sbr beri_vtblk_devclass, 0, 0); 562