189e0f4d2SKip Macy /* 28698b76cSKip Macy * XenBSD block device driver 38698b76cSKip Macy * 433eebb6aSJustin T. Gibbs * Copyright (c) 2010-2013 Spectra Logic Corporation 5e4808c4bSKip Macy * Copyright (c) 2009 Scott Long, Yahoo! 68698b76cSKip Macy * Copyright (c) 2009 Frank Suchomel, Citrix 79999d2cbSKip Macy * Copyright (c) 2009 Doug F. Rabson, Citrix 89999d2cbSKip Macy * Copyright (c) 2005 Kip Macy 99999d2cbSKip Macy * Copyright (c) 2003-2004, Keir Fraser & Steve Hand 109999d2cbSKip Macy * Modifications by Mark A. Williamson are (c) Intel Research Cambridge 119999d2cbSKip Macy * 129999d2cbSKip Macy * 139999d2cbSKip Macy * Permission is hereby granted, free of charge, to any person obtaining a copy 149999d2cbSKip Macy * of this software and associated documentation files (the "Software"), to 159999d2cbSKip Macy * deal in the Software without restriction, including without limitation the 169999d2cbSKip Macy * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 179999d2cbSKip Macy * sell copies of the Software, and to permit persons to whom the Software is 189999d2cbSKip Macy * furnished to do so, subject to the following conditions: 199999d2cbSKip Macy * 209999d2cbSKip Macy * The above copyright notice and this permission notice shall be included in 219999d2cbSKip Macy * all copies or substantial portions of the Software. 229999d2cbSKip Macy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 239999d2cbSKip Macy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 249999d2cbSKip Macy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 259999d2cbSKip Macy * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 269999d2cbSKip Macy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 279999d2cbSKip Macy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 289999d2cbSKip Macy * DEALINGS IN THE SOFTWARE. 2989e0f4d2SKip Macy */ 3089e0f4d2SKip Macy 3189e0f4d2SKip Macy #include <sys/cdefs.h> 3289e0f4d2SKip Macy __FBSDID("$FreeBSD$"); 3389e0f4d2SKip Macy 3489e0f4d2SKip Macy #include <sys/param.h> 3589e0f4d2SKip Macy #include <sys/systm.h> 3689e0f4d2SKip Macy #include <sys/malloc.h> 3789e0f4d2SKip Macy #include <sys/kernel.h> 3889e0f4d2SKip Macy #include <vm/vm.h> 3989e0f4d2SKip Macy #include <vm/pmap.h> 4089e0f4d2SKip Macy 4189e0f4d2SKip Macy #include <sys/bio.h> 4289e0f4d2SKip Macy #include <sys/bus.h> 4389e0f4d2SKip Macy #include <sys/conf.h> 4489e0f4d2SKip Macy #include <sys/module.h> 458b8bfa35SJustin T. Gibbs #include <sys/sysctl.h> 4689e0f4d2SKip Macy 4789e0f4d2SKip Macy #include <machine/bus.h> 4889e0f4d2SKip Macy #include <sys/rman.h> 4989e0f4d2SKip Macy #include <machine/resource.h> 5089e0f4d2SKip Macy #include <machine/intr_machdep.h> 5189e0f4d2SKip Macy #include <machine/vmparam.h> 52e4808c4bSKip Macy #include <sys/bus_dma.h> 5389e0f4d2SKip Macy 5476acc41fSJustin T. Gibbs #include <xen/xen-os.h> 5512678024SDoug Rabson #include <xen/hypervisor.h> 563a6d1fcfSKip Macy #include <xen/xen_intr.h> 5712678024SDoug Rabson #include <xen/gnttab.h> 5889e0f4d2SKip Macy #include <xen/interface/grant_table.h> 5923dc5621SKip Macy #include <xen/interface/io/protocols.h> 6023dc5621SKip Macy #include <xen/xenbus/xenbusvar.h> 6189e0f4d2SKip Macy 6276acc41fSJustin T. Gibbs #include <machine/_inttypes.h> 6376acc41fSJustin T. Gibbs #include <machine/xen/xenvar.h> 6476acc41fSJustin T. Gibbs 6589e0f4d2SKip Macy #include <geom/geom_disk.h> 6689e0f4d2SKip Macy 6789e0f4d2SKip Macy #include <dev/xen/blkfront/block.h> 6889e0f4d2SKip Macy 6923dc5621SKip Macy #include "xenbus_if.h" 7023dc5621SKip Macy 71fac3fd80SJustin T. Gibbs /*--------------------------- Forward Declarations ---------------------------*/ 7233eebb6aSJustin T. Gibbs static void xbd_closing(device_t); 73fac3fd80SJustin T. Gibbs static void xbd_startio(struct xbd_softc *sc); 7489e0f4d2SKip Macy 75fac3fd80SJustin T. Gibbs /*---------------------------------- Macros ----------------------------------*/ 76fac3fd80SJustin T. Gibbs #if 0 77fac3fd80SJustin T. Gibbs #define DPRINTK(fmt, args...) printf("[XEN] %s:%d: " fmt ".\n", __func__, __LINE__, ##args) 78fac3fd80SJustin T. Gibbs #else 79fac3fd80SJustin T. Gibbs #define DPRINTK(fmt, args...) 80fac3fd80SJustin T. Gibbs #endif 81fac3fd80SJustin T. Gibbs 82fac3fd80SJustin T. Gibbs #define XBD_SECTOR_SHFT 9 83ff662b5cSJustin T. Gibbs 84fac3fd80SJustin T. Gibbs /*---------------------------- Global Static Data ----------------------------*/ 85fac3fd80SJustin T. Gibbs static MALLOC_DEFINE(M_XENBLOCKFRONT, "xbd", "Xen Block Front driver data"); 8689e0f4d2SKip Macy 87fac3fd80SJustin T. Gibbs /*---------------------------- Command Processing ----------------------------*/ 88127a9483SJustin T. Gibbs static void 89127a9483SJustin T. Gibbs xbd_freeze(struct xbd_softc *sc, xbd_flag_t xbd_flag) 90127a9483SJustin T. Gibbs { 91127a9483SJustin T. Gibbs if (xbd_flag != XBDF_NONE && (sc->xbd_flags & xbd_flag) != 0) 92127a9483SJustin T. Gibbs return; 93127a9483SJustin T. Gibbs 94127a9483SJustin T. Gibbs sc->xbd_flags |= xbd_flag; 95127a9483SJustin T. Gibbs sc->xbd_qfrozen_cnt++; 96127a9483SJustin T. Gibbs } 97127a9483SJustin T. Gibbs 98127a9483SJustin T. Gibbs static void 99127a9483SJustin T. Gibbs xbd_thaw(struct xbd_softc *sc, xbd_flag_t xbd_flag) 100127a9483SJustin T. Gibbs { 101127a9483SJustin T. Gibbs if (xbd_flag != XBDF_NONE && (sc->xbd_flags & xbd_flag) == 0) 102127a9483SJustin T. Gibbs return; 103127a9483SJustin T. Gibbs 104b834eea6SJustin T. Gibbs if (sc->xbd_qfrozen_cnt == 0) 105127a9483SJustin T. Gibbs panic("%s: Thaw with flag 0x%x while not frozen.", 106127a9483SJustin T. Gibbs __func__, xbd_flag); 107127a9483SJustin T. Gibbs 108127a9483SJustin T. Gibbs sc->xbd_flags &= ~xbd_flag; 109127a9483SJustin T. Gibbs sc->xbd_qfrozen_cnt--; 110127a9483SJustin T. Gibbs } 111127a9483SJustin T. Gibbs 1129985113bSJustin T. Gibbs static void 1139985113bSJustin T. Gibbs xbd_cm_freeze(struct xbd_softc *sc, struct xbd_command *cm, xbdc_flag_t cm_flag) 1149985113bSJustin T. Gibbs { 1159985113bSJustin T. Gibbs if ((cm->cm_flags & XBDCF_FROZEN) != 0) 1169985113bSJustin T. Gibbs return; 1179985113bSJustin T. Gibbs 1189985113bSJustin T. Gibbs cm->cm_flags |= XBDCF_FROZEN|cm_flag; 1199985113bSJustin T. Gibbs xbd_freeze(sc, XBDF_NONE); 1209985113bSJustin T. Gibbs } 1219985113bSJustin T. Gibbs 1229985113bSJustin T. Gibbs static void 1239985113bSJustin T. Gibbs xbd_cm_thaw(struct xbd_softc *sc, struct xbd_command *cm) 1249985113bSJustin T. Gibbs { 1259985113bSJustin T. Gibbs if ((cm->cm_flags & XBDCF_FROZEN) == 0) 1269985113bSJustin T. Gibbs return; 1279985113bSJustin T. Gibbs 1289985113bSJustin T. Gibbs cm->cm_flags &= ~XBDCF_FROZEN; 1299985113bSJustin T. Gibbs xbd_thaw(sc, XBDF_NONE); 1309985113bSJustin T. Gibbs } 1319985113bSJustin T. Gibbs 132fac3fd80SJustin T. Gibbs static inline void 133cdf5d66fSJustin T. Gibbs xbd_flush_requests(struct xbd_softc *sc) 134fac3fd80SJustin T. Gibbs { 135fac3fd80SJustin T. Gibbs int notify; 136e4808c4bSKip Macy 137fac3fd80SJustin T. Gibbs RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->xbd_ring, notify); 13889e0f4d2SKip Macy 139fac3fd80SJustin T. Gibbs if (notify) 14076acc41fSJustin T. Gibbs xen_intr_signal(sc->xen_intr_handle); 141fac3fd80SJustin T. Gibbs } 14289e0f4d2SKip Macy 14323dc5621SKip Macy static void 144fac3fd80SJustin T. Gibbs xbd_free_command(struct xbd_command *cm) 14523dc5621SKip Macy { 14623dc5621SKip Macy 147e2c1fe90SJustin T. Gibbs KASSERT((cm->cm_flags & XBDCF_Q_MASK) == XBD_Q_NONE, 148e2c1fe90SJustin T. Gibbs ("Freeing command that is still on queue %d.", 149e2c1fe90SJustin T. Gibbs cm->cm_flags & XBDCF_Q_MASK)); 15023dc5621SKip Macy 151e2c1fe90SJustin T. Gibbs cm->cm_flags = XBDCF_INITIALIZER; 152fac3fd80SJustin T. Gibbs cm->cm_bp = NULL; 153fac3fd80SJustin T. Gibbs cm->cm_complete = NULL; 154e2c1fe90SJustin T. Gibbs xbd_enqueue_cm(cm, XBD_Q_FREE); 155127a9483SJustin T. Gibbs xbd_thaw(cm->cm_sc, XBDF_CM_SHORTAGE); 15623dc5621SKip Macy } 15723dc5621SKip Macy 15889e0f4d2SKip Macy static void 159fac3fd80SJustin T. Gibbs xbd_queue_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 16089e0f4d2SKip Macy { 161fac3fd80SJustin T. Gibbs struct xbd_softc *sc; 162fac3fd80SJustin T. Gibbs struct xbd_command *cm; 163fac3fd80SJustin T. Gibbs blkif_request_t *ring_req; 164fac3fd80SJustin T. Gibbs struct blkif_request_segment *sg; 165fac3fd80SJustin T. Gibbs struct blkif_request_segment *last_block_sg; 166fac3fd80SJustin T. Gibbs grant_ref_t *sg_ref; 167fac3fd80SJustin T. Gibbs vm_paddr_t buffer_ma; 168fac3fd80SJustin T. Gibbs uint64_t fsect, lsect; 169fac3fd80SJustin T. Gibbs int ref; 170fac3fd80SJustin T. Gibbs int op; 171fac3fd80SJustin T. Gibbs int block_segs; 17289e0f4d2SKip Macy 173fac3fd80SJustin T. Gibbs cm = arg; 174fac3fd80SJustin T. Gibbs sc = cm->cm_sc; 175fac3fd80SJustin T. Gibbs 176fac3fd80SJustin T. Gibbs if (error) { 177fac3fd80SJustin T. Gibbs cm->cm_bp->bio_error = EIO; 178fac3fd80SJustin T. Gibbs biodone(cm->cm_bp); 179fac3fd80SJustin T. Gibbs xbd_free_command(cm); 18089e0f4d2SKip Macy return; 18189e0f4d2SKip Macy } 18289e0f4d2SKip Macy 183fac3fd80SJustin T. Gibbs /* Fill out a communications ring structure. */ 184fac3fd80SJustin T. Gibbs ring_req = RING_GET_REQUEST(&sc->xbd_ring, sc->xbd_ring.req_prod_pvt); 185fac3fd80SJustin T. Gibbs sc->xbd_ring.req_prod_pvt++; 186fac3fd80SJustin T. Gibbs ring_req->id = cm->cm_id; 187fac3fd80SJustin T. Gibbs ring_req->operation = cm->cm_operation; 188fac3fd80SJustin T. Gibbs ring_req->sector_number = cm->cm_sector_number; 189fac3fd80SJustin T. Gibbs ring_req->handle = (blkif_vdev_t)(uintptr_t)sc->xbd_disk; 190fac3fd80SJustin T. Gibbs ring_req->nr_segments = nsegs; 191fac3fd80SJustin T. Gibbs cm->cm_nseg = nsegs; 192fac3fd80SJustin T. Gibbs 193*112cacaeSRoger Pau Monné block_segs = MIN(nsegs, BLKIF_MAX_SEGMENTS_PER_REQUEST); 194fac3fd80SJustin T. Gibbs sg = ring_req->seg; 195fac3fd80SJustin T. Gibbs last_block_sg = sg + block_segs; 196fac3fd80SJustin T. Gibbs sg_ref = cm->cm_sg_refs; 197fac3fd80SJustin T. Gibbs 198fac3fd80SJustin T. Gibbs while (sg < last_block_sg) { 199fac3fd80SJustin T. Gibbs buffer_ma = segs->ds_addr; 200fac3fd80SJustin T. Gibbs fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT; 201fac3fd80SJustin T. Gibbs lsect = fsect + (segs->ds_len >> XBD_SECTOR_SHFT) - 1; 202fac3fd80SJustin T. Gibbs 203fac3fd80SJustin T. Gibbs KASSERT(lsect <= 7, ("XEN disk driver data cannot " 204fac3fd80SJustin T. Gibbs "cross a page boundary")); 205fac3fd80SJustin T. Gibbs 206fac3fd80SJustin T. Gibbs /* install a grant reference. */ 207fac3fd80SJustin T. Gibbs ref = gnttab_claim_grant_reference(&cm->cm_gref_head); 208fac3fd80SJustin T. Gibbs 209e4808c4bSKip Macy /* 210fac3fd80SJustin T. Gibbs * GNTTAB_LIST_END == 0xffffffff, but it is private 211fac3fd80SJustin T. Gibbs * to gnttab.c. 212e4808c4bSKip Macy */ 213fac3fd80SJustin T. Gibbs KASSERT(ref != ~0, ("grant_reference failed")); 214fac3fd80SJustin T. Gibbs 215fac3fd80SJustin T. Gibbs gnttab_grant_foreign_access_ref( 216fac3fd80SJustin T. Gibbs ref, 217fac3fd80SJustin T. Gibbs xenbus_get_otherend_id(sc->xbd_dev), 218fac3fd80SJustin T. Gibbs buffer_ma >> PAGE_SHIFT, 219fac3fd80SJustin T. Gibbs ring_req->operation == BLKIF_OP_WRITE); 220fac3fd80SJustin T. Gibbs 221fac3fd80SJustin T. Gibbs *sg_ref = ref; 222fac3fd80SJustin T. Gibbs *sg = (struct blkif_request_segment) { 223fac3fd80SJustin T. Gibbs .gref = ref, 224fac3fd80SJustin T. Gibbs .first_sect = fsect, 225fac3fd80SJustin T. Gibbs .last_sect = lsect 226fac3fd80SJustin T. Gibbs }; 227fac3fd80SJustin T. Gibbs sg++; 228fac3fd80SJustin T. Gibbs sg_ref++; 229fac3fd80SJustin T. Gibbs segs++; 230fac3fd80SJustin T. Gibbs nsegs--; 231fac3fd80SJustin T. Gibbs } 232fac3fd80SJustin T. Gibbs 233fac3fd80SJustin T. Gibbs if (cm->cm_operation == BLKIF_OP_READ) 234fac3fd80SJustin T. Gibbs op = BUS_DMASYNC_PREREAD; 235fac3fd80SJustin T. Gibbs else if (cm->cm_operation == BLKIF_OP_WRITE) 236fac3fd80SJustin T. Gibbs op = BUS_DMASYNC_PREWRITE; 237fac3fd80SJustin T. Gibbs else 238fac3fd80SJustin T. Gibbs op = 0; 239fac3fd80SJustin T. Gibbs bus_dmamap_sync(sc->xbd_io_dmat, cm->cm_map, op); 240fac3fd80SJustin T. Gibbs 241fac3fd80SJustin T. Gibbs gnttab_free_grant_references(cm->cm_gref_head); 242fac3fd80SJustin T. Gibbs 243e2c1fe90SJustin T. Gibbs xbd_enqueue_cm(cm, XBD_Q_BUSY); 244fac3fd80SJustin T. Gibbs 245fac3fd80SJustin T. Gibbs /* 246127a9483SJustin T. Gibbs * If bus dma had to asynchronously call us back to dispatch 247127a9483SJustin T. Gibbs * this command, we are no longer executing in the context of 248127a9483SJustin T. Gibbs * xbd_startio(). Thus we cannot rely on xbd_startio()'s call to 249127a9483SJustin T. Gibbs * xbd_flush_requests() to publish this command to the backend 250127a9483SJustin T. Gibbs * along with any other commands that it could batch. 251fac3fd80SJustin T. Gibbs */ 252127a9483SJustin T. Gibbs if ((cm->cm_flags & XBDCF_ASYNC_MAPPING) != 0) 253cdf5d66fSJustin T. Gibbs xbd_flush_requests(sc); 254fac3fd80SJustin T. Gibbs 255fac3fd80SJustin T. Gibbs return; 256fac3fd80SJustin T. Gibbs } 257fac3fd80SJustin T. Gibbs 258fac3fd80SJustin T. Gibbs static int 259fac3fd80SJustin T. Gibbs xbd_queue_request(struct xbd_softc *sc, struct xbd_command *cm) 260fac3fd80SJustin T. Gibbs { 261fac3fd80SJustin T. Gibbs int error; 262fac3fd80SJustin T. Gibbs 26377b6916dSRoger Pau Monné error = bus_dmamap_load(sc->xbd_io_dmat, cm->cm_map, cm->cm_data, 26477b6916dSRoger Pau Monné cm->cm_datalen, xbd_queue_cb, cm, 0); 265fac3fd80SJustin T. Gibbs if (error == EINPROGRESS) { 266127a9483SJustin T. Gibbs /* 267127a9483SJustin T. Gibbs * Maintain queuing order by freezing the queue. The next 268127a9483SJustin T. Gibbs * command may not require as many resources as the command 269127a9483SJustin T. Gibbs * we just attempted to map, so we can't rely on bus dma 270127a9483SJustin T. Gibbs * blocking for it too. 271127a9483SJustin T. Gibbs */ 2729985113bSJustin T. Gibbs xbd_cm_freeze(sc, cm, XBDCF_ASYNC_MAPPING); 273fac3fd80SJustin T. Gibbs return (0); 274fac3fd80SJustin T. Gibbs } 275fac3fd80SJustin T. Gibbs 276fac3fd80SJustin T. Gibbs return (error); 277fac3fd80SJustin T. Gibbs } 278fac3fd80SJustin T. Gibbs 279fac3fd80SJustin T. Gibbs static void 280fac3fd80SJustin T. Gibbs xbd_restart_queue_callback(void *arg) 281fac3fd80SJustin T. Gibbs { 282fac3fd80SJustin T. Gibbs struct xbd_softc *sc = arg; 283fac3fd80SJustin T. Gibbs 28433eebb6aSJustin T. Gibbs mtx_lock(&sc->xbd_io_lock); 285e4808c4bSKip Macy 286127a9483SJustin T. Gibbs xbd_thaw(sc, XBDF_GNT_SHORTAGE); 287127a9483SJustin T. Gibbs 28833eebb6aSJustin T. Gibbs xbd_startio(sc); 289e4808c4bSKip Macy 29033eebb6aSJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 291fac3fd80SJustin T. Gibbs } 292fac3fd80SJustin T. Gibbs 293fac3fd80SJustin T. Gibbs static struct xbd_command * 294fac3fd80SJustin T. Gibbs xbd_bio_command(struct xbd_softc *sc) 295fac3fd80SJustin T. Gibbs { 296fac3fd80SJustin T. Gibbs struct xbd_command *cm; 297fac3fd80SJustin T. Gibbs struct bio *bp; 298fac3fd80SJustin T. Gibbs 29976acc41fSJustin T. Gibbs if (__predict_false(sc->xbd_state != XBD_STATE_CONNECTED)) 300fac3fd80SJustin T. Gibbs return (NULL); 301fac3fd80SJustin T. Gibbs 302fac3fd80SJustin T. Gibbs bp = xbd_dequeue_bio(sc); 303fac3fd80SJustin T. Gibbs if (bp == NULL) 304fac3fd80SJustin T. Gibbs return (NULL); 305fac3fd80SJustin T. Gibbs 306e2c1fe90SJustin T. Gibbs if ((cm = xbd_dequeue_cm(sc, XBD_Q_FREE)) == NULL) { 307127a9483SJustin T. Gibbs xbd_freeze(sc, XBDF_CM_SHORTAGE); 308fac3fd80SJustin T. Gibbs xbd_requeue_bio(sc, bp); 309fac3fd80SJustin T. Gibbs return (NULL); 310fac3fd80SJustin T. Gibbs } 311fac3fd80SJustin T. Gibbs 312fac3fd80SJustin T. Gibbs if (gnttab_alloc_grant_references(sc->xbd_max_request_segments, 313fac3fd80SJustin T. Gibbs &cm->cm_gref_head) != 0) { 314fac3fd80SJustin T. Gibbs gnttab_request_free_callback(&sc->xbd_callback, 315fac3fd80SJustin T. Gibbs xbd_restart_queue_callback, sc, 316fac3fd80SJustin T. Gibbs sc->xbd_max_request_segments); 317127a9483SJustin T. Gibbs xbd_freeze(sc, XBDF_GNT_SHORTAGE); 318fac3fd80SJustin T. Gibbs xbd_requeue_bio(sc, bp); 319e2c1fe90SJustin T. Gibbs xbd_enqueue_cm(cm, XBD_Q_FREE); 320fac3fd80SJustin T. Gibbs return (NULL); 321fac3fd80SJustin T. Gibbs } 322fac3fd80SJustin T. Gibbs 323fac3fd80SJustin T. Gibbs cm->cm_bp = bp; 32477b6916dSRoger Pau Monné cm->cm_data = bp->bio_data; 32577b6916dSRoger Pau Monné cm->cm_datalen = bp->bio_bcount; 326fac3fd80SJustin T. Gibbs cm->cm_sector_number = (blkif_sector_t)bp->bio_pblkno; 327fac3fd80SJustin T. Gibbs 3289985113bSJustin T. Gibbs switch (bp->bio_cmd) { 3299985113bSJustin T. Gibbs case BIO_READ: 3309985113bSJustin T. Gibbs cm->cm_operation = BLKIF_OP_READ; 3319985113bSJustin T. Gibbs break; 3329985113bSJustin T. Gibbs case BIO_WRITE: 3339985113bSJustin T. Gibbs cm->cm_operation = BLKIF_OP_WRITE; 3349985113bSJustin T. Gibbs if ((bp->bio_flags & BIO_ORDERED) != 0) { 3359985113bSJustin T. Gibbs if ((sc->xbd_flags & XBDF_BARRIER) != 0) { 3369985113bSJustin T. Gibbs cm->cm_operation = BLKIF_OP_WRITE_BARRIER; 3379985113bSJustin T. Gibbs } else { 3389985113bSJustin T. Gibbs /* 3399985113bSJustin T. Gibbs * Single step this command. 3409985113bSJustin T. Gibbs */ 3419985113bSJustin T. Gibbs cm->cm_flags |= XBDCF_Q_FREEZE; 3429985113bSJustin T. Gibbs if (xbd_queue_length(sc, XBD_Q_BUSY) != 0) { 3439985113bSJustin T. Gibbs /* 3449985113bSJustin T. Gibbs * Wait for in-flight requests to 3459985113bSJustin T. Gibbs * finish. 3469985113bSJustin T. Gibbs */ 3479985113bSJustin T. Gibbs xbd_freeze(sc, XBDF_WAIT_IDLE); 3489985113bSJustin T. Gibbs xbd_requeue_cm(cm, XBD_Q_READY); 3499985113bSJustin T. Gibbs return (NULL); 3509985113bSJustin T. Gibbs } 3519985113bSJustin T. Gibbs } 3529985113bSJustin T. Gibbs } 3539985113bSJustin T. Gibbs break; 3549985113bSJustin T. Gibbs case BIO_FLUSH: 3559985113bSJustin T. Gibbs if ((sc->xbd_flags & XBDF_FLUSH) != 0) 3569985113bSJustin T. Gibbs cm->cm_operation = BLKIF_OP_FLUSH_DISKCACHE; 3579985113bSJustin T. Gibbs else if ((sc->xbd_flags & XBDF_BARRIER) != 0) 3589985113bSJustin T. Gibbs cm->cm_operation = BLKIF_OP_WRITE_BARRIER; 3599985113bSJustin T. Gibbs else 3609985113bSJustin T. Gibbs panic("flush request, but no flush support available"); 3619985113bSJustin T. Gibbs break; 3629985113bSJustin T. Gibbs default: 3639985113bSJustin T. Gibbs panic("unknown bio command %d", bp->bio_cmd); 3649985113bSJustin T. Gibbs } 3659985113bSJustin T. Gibbs 366fac3fd80SJustin T. Gibbs return (cm); 367fac3fd80SJustin T. Gibbs } 368fac3fd80SJustin T. Gibbs 369fac3fd80SJustin T. Gibbs /* 370fac3fd80SJustin T. Gibbs * Dequeue buffers and place them in the shared communication ring. 371fac3fd80SJustin T. Gibbs * Return when no more requests can be accepted or all buffers have 372fac3fd80SJustin T. Gibbs * been queued. 373fac3fd80SJustin T. Gibbs * 374fac3fd80SJustin T. Gibbs * Signal XEN once the ring has been filled out. 375fac3fd80SJustin T. Gibbs */ 376fac3fd80SJustin T. Gibbs static void 377fac3fd80SJustin T. Gibbs xbd_startio(struct xbd_softc *sc) 378fac3fd80SJustin T. Gibbs { 379fac3fd80SJustin T. Gibbs struct xbd_command *cm; 380fac3fd80SJustin T. Gibbs int error, queued = 0; 381fac3fd80SJustin T. Gibbs 382fac3fd80SJustin T. Gibbs mtx_assert(&sc->xbd_io_lock, MA_OWNED); 383fac3fd80SJustin T. Gibbs 384e2c1fe90SJustin T. Gibbs if (sc->xbd_state != XBD_STATE_CONNECTED) 385e4808c4bSKip Macy return; 386fac3fd80SJustin T. Gibbs 387*112cacaeSRoger Pau Monné while (!RING_FULL(&sc->xbd_ring)) { 388*112cacaeSRoger Pau Monné 389127a9483SJustin T. Gibbs if (sc->xbd_qfrozen_cnt != 0) 390fac3fd80SJustin T. Gibbs break; 391fac3fd80SJustin T. Gibbs 392e2c1fe90SJustin T. Gibbs cm = xbd_dequeue_cm(sc, XBD_Q_READY); 393fac3fd80SJustin T. Gibbs 394fac3fd80SJustin T. Gibbs if (cm == NULL) 395fac3fd80SJustin T. Gibbs cm = xbd_bio_command(sc); 396fac3fd80SJustin T. Gibbs 397fac3fd80SJustin T. Gibbs if (cm == NULL) 398fac3fd80SJustin T. Gibbs break; 399fac3fd80SJustin T. Gibbs 4009985113bSJustin T. Gibbs if ((cm->cm_flags & XBDCF_Q_FREEZE) != 0) { 4019985113bSJustin T. Gibbs /* 4029985113bSJustin T. Gibbs * Single step command. Future work is 4039985113bSJustin T. Gibbs * held off until this command completes. 4049985113bSJustin T. Gibbs */ 4059985113bSJustin T. Gibbs xbd_cm_freeze(sc, cm, XBDCF_Q_FREEZE); 4069985113bSJustin T. Gibbs } 4079985113bSJustin T. Gibbs 408fac3fd80SJustin T. Gibbs if ((error = xbd_queue_request(sc, cm)) != 0) { 409fac3fd80SJustin T. Gibbs printf("xbd_queue_request returned %d\n", error); 410fac3fd80SJustin T. Gibbs break; 411fac3fd80SJustin T. Gibbs } 412fac3fd80SJustin T. Gibbs queued++; 413fac3fd80SJustin T. Gibbs } 414fac3fd80SJustin T. Gibbs 415fac3fd80SJustin T. Gibbs if (queued != 0) 416cdf5d66fSJustin T. Gibbs xbd_flush_requests(sc); 417e4808c4bSKip Macy } 418e4808c4bSKip Macy 419e4808c4bSKip Macy static void 42033eebb6aSJustin T. Gibbs xbd_bio_complete(struct xbd_softc *sc, struct xbd_command *cm) 421e4808c4bSKip Macy { 422e4808c4bSKip Macy struct bio *bp; 423e4808c4bSKip Macy 42433eebb6aSJustin T. Gibbs bp = cm->cm_bp; 425e4808c4bSKip Macy 42676acc41fSJustin T. Gibbs if (__predict_false(cm->cm_status != BLKIF_RSP_OKAY)) { 427e4808c4bSKip Macy disk_err(bp, "disk error" , -1, 0); 42833eebb6aSJustin T. Gibbs printf(" status: %x\n", cm->cm_status); 429e4808c4bSKip Macy bp->bio_flags |= BIO_ERROR; 430e4808c4bSKip Macy } 431e4808c4bSKip Macy 432e4808c4bSKip Macy if (bp->bio_flags & BIO_ERROR) 433e4808c4bSKip Macy bp->bio_error = EIO; 434e4808c4bSKip Macy else 435e4808c4bSKip Macy bp->bio_resid = 0; 436e4808c4bSKip Macy 43733eebb6aSJustin T. Gibbs xbd_free_command(cm); 438e4808c4bSKip Macy biodone(bp); 439e4808c4bSKip Macy } 440e4808c4bSKip Macy 441fac3fd80SJustin T. Gibbs static void 442fac3fd80SJustin T. Gibbs xbd_int(void *xsc) 443fac3fd80SJustin T. Gibbs { 444fac3fd80SJustin T. Gibbs struct xbd_softc *sc = xsc; 445fac3fd80SJustin T. Gibbs struct xbd_command *cm; 446fac3fd80SJustin T. Gibbs blkif_response_t *bret; 447fac3fd80SJustin T. Gibbs RING_IDX i, rp; 448fac3fd80SJustin T. Gibbs int op; 449fac3fd80SJustin T. Gibbs 450fac3fd80SJustin T. Gibbs mtx_lock(&sc->xbd_io_lock); 451fac3fd80SJustin T. Gibbs 45276acc41fSJustin T. Gibbs if (__predict_false(sc->xbd_state == XBD_STATE_DISCONNECTED)) { 453fac3fd80SJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 454fac3fd80SJustin T. Gibbs return; 455fac3fd80SJustin T. Gibbs } 456fac3fd80SJustin T. Gibbs 457fac3fd80SJustin T. Gibbs again: 458fac3fd80SJustin T. Gibbs rp = sc->xbd_ring.sring->rsp_prod; 459fac3fd80SJustin T. Gibbs rmb(); /* Ensure we see queued responses up to 'rp'. */ 460fac3fd80SJustin T. Gibbs 461fac3fd80SJustin T. Gibbs for (i = sc->xbd_ring.rsp_cons; i != rp;) { 462fac3fd80SJustin T. Gibbs bret = RING_GET_RESPONSE(&sc->xbd_ring, i); 463fac3fd80SJustin T. Gibbs cm = &sc->xbd_shadow[bret->id]; 464fac3fd80SJustin T. Gibbs 465e2c1fe90SJustin T. Gibbs xbd_remove_cm(cm, XBD_Q_BUSY); 466*112cacaeSRoger Pau Monné gnttab_end_foreign_access_references(cm->cm_nseg, 467*112cacaeSRoger Pau Monné cm->cm_sg_refs); 468*112cacaeSRoger Pau Monné i++; 469fac3fd80SJustin T. Gibbs 470fac3fd80SJustin T. Gibbs if (cm->cm_operation == BLKIF_OP_READ) 471fac3fd80SJustin T. Gibbs op = BUS_DMASYNC_POSTREAD; 4729985113bSJustin T. Gibbs else if (cm->cm_operation == BLKIF_OP_WRITE || 4739985113bSJustin T. Gibbs cm->cm_operation == BLKIF_OP_WRITE_BARRIER) 474fac3fd80SJustin T. Gibbs op = BUS_DMASYNC_POSTWRITE; 475fac3fd80SJustin T. Gibbs else 476fac3fd80SJustin T. Gibbs op = 0; 477fac3fd80SJustin T. Gibbs bus_dmamap_sync(sc->xbd_io_dmat, cm->cm_map, op); 478fac3fd80SJustin T. Gibbs bus_dmamap_unload(sc->xbd_io_dmat, cm->cm_map); 479fac3fd80SJustin T. Gibbs 480fac3fd80SJustin T. Gibbs /* 481127a9483SJustin T. Gibbs * Release any hold this command has on future command 482127a9483SJustin T. Gibbs * dispatch. 483fac3fd80SJustin T. Gibbs */ 4849985113bSJustin T. Gibbs xbd_cm_thaw(sc, cm); 485fac3fd80SJustin T. Gibbs 486fac3fd80SJustin T. Gibbs /* 487fac3fd80SJustin T. Gibbs * Directly call the i/o complete routine to save an 488fac3fd80SJustin T. Gibbs * an indirection in the common case. 489fac3fd80SJustin T. Gibbs */ 490fac3fd80SJustin T. Gibbs cm->cm_status = bret->status; 491fac3fd80SJustin T. Gibbs if (cm->cm_bp) 492fac3fd80SJustin T. Gibbs xbd_bio_complete(sc, cm); 493fac3fd80SJustin T. Gibbs else if (cm->cm_complete != NULL) 494fac3fd80SJustin T. Gibbs cm->cm_complete(cm); 495fac3fd80SJustin T. Gibbs else 496fac3fd80SJustin T. Gibbs xbd_free_command(cm); 497fac3fd80SJustin T. Gibbs } 498fac3fd80SJustin T. Gibbs 499fac3fd80SJustin T. Gibbs sc->xbd_ring.rsp_cons = i; 500fac3fd80SJustin T. Gibbs 501fac3fd80SJustin T. Gibbs if (i != sc->xbd_ring.req_prod_pvt) { 502fac3fd80SJustin T. Gibbs int more_to_do; 503fac3fd80SJustin T. Gibbs RING_FINAL_CHECK_FOR_RESPONSES(&sc->xbd_ring, more_to_do); 504fac3fd80SJustin T. Gibbs if (more_to_do) 505fac3fd80SJustin T. Gibbs goto again; 506fac3fd80SJustin T. Gibbs } else { 507fac3fd80SJustin T. Gibbs sc->xbd_ring.sring->rsp_event = i + 1; 508fac3fd80SJustin T. Gibbs } 509fac3fd80SJustin T. Gibbs 5109985113bSJustin T. Gibbs if (xbd_queue_length(sc, XBD_Q_BUSY) == 0) 5119985113bSJustin T. Gibbs xbd_thaw(sc, XBDF_WAIT_IDLE); 5129985113bSJustin T. Gibbs 513fac3fd80SJustin T. Gibbs xbd_startio(sc); 514fac3fd80SJustin T. Gibbs 51576acc41fSJustin T. Gibbs if (__predict_false(sc->xbd_state == XBD_STATE_SUSPENDED)) 516e2c1fe90SJustin T. Gibbs wakeup(&sc->xbd_cm_q[XBD_Q_BUSY]); 517fac3fd80SJustin T. Gibbs 518fac3fd80SJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 519fac3fd80SJustin T. Gibbs } 520fac3fd80SJustin T. Gibbs 521fac3fd80SJustin T. Gibbs /*------------------------------- Dump Support -------------------------------*/ 522fac3fd80SJustin T. Gibbs /** 523fac3fd80SJustin T. Gibbs * Quiesce the disk writes for a dump file before allowing the next buffer. 524fac3fd80SJustin T. Gibbs */ 5258698b76cSKip Macy static void 52633eebb6aSJustin T. Gibbs xbd_quiesce(struct xbd_softc *sc) 5278698b76cSKip Macy { 5288698b76cSKip Macy int mtd; 5298698b76cSKip Macy 5308698b76cSKip Macy // While there are outstanding requests 5319985113bSJustin T. Gibbs while (xbd_queue_length(sc, XBD_Q_BUSY) != 0) { 53233eebb6aSJustin T. Gibbs RING_FINAL_CHECK_FOR_RESPONSES(&sc->xbd_ring, mtd); 5338698b76cSKip Macy if (mtd) { 534e4808c4bSKip Macy /* Recieved request completions, update queue. */ 53533eebb6aSJustin T. Gibbs xbd_int(sc); 5368698b76cSKip Macy } 5379985113bSJustin T. Gibbs if (xbd_queue_length(sc, XBD_Q_BUSY) != 0) { 538e4808c4bSKip Macy /* 539e4808c4bSKip Macy * Still pending requests, wait for the disk i/o 540e4808c4bSKip Macy * to complete. 541e4808c4bSKip Macy */ 542be7747b4SKip Macy HYPERVISOR_yield(); 5438698b76cSKip Macy } 5448698b76cSKip Macy } 5458698b76cSKip Macy } 5468698b76cSKip Macy 547e4808c4bSKip Macy /* Kernel dump function for a paravirtualized disk device */ 548e4808c4bSKip Macy static void 54933eebb6aSJustin T. Gibbs xbd_dump_complete(struct xbd_command *cm) 550e4808c4bSKip Macy { 5518698b76cSKip Macy 552e2c1fe90SJustin T. Gibbs xbd_enqueue_cm(cm, XBD_Q_COMPLETE); 553e4808c4bSKip Macy } 554e4808c4bSKip Macy 5558698b76cSKip Macy static int 55633eebb6aSJustin T. Gibbs xbd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, 5578698b76cSKip Macy size_t length) 5588698b76cSKip Macy { 5598698b76cSKip Macy struct disk *dp = arg; 56033eebb6aSJustin T. Gibbs struct xbd_softc *sc = dp->d_drv1; 56133eebb6aSJustin T. Gibbs struct xbd_command *cm; 562e4808c4bSKip Macy size_t chunk; 563e4808c4bSKip Macy int sbp; 5648698b76cSKip Macy int rc = 0; 5658698b76cSKip Macy 566e4808c4bSKip Macy if (length <= 0) 567e4808c4bSKip Macy return (rc); 5688698b76cSKip Macy 56933eebb6aSJustin T. Gibbs xbd_quiesce(sc); /* All quiet on the western front. */ 570e4808c4bSKip Macy 571e4808c4bSKip Macy /* 572e4808c4bSKip Macy * If this lock is held, then this module is failing, and a 573e4808c4bSKip Macy * successful kernel dump is highly unlikely anyway. 574e4808c4bSKip Macy */ 57533eebb6aSJustin T. Gibbs mtx_lock(&sc->xbd_io_lock); 576e4808c4bSKip Macy 577e4808c4bSKip Macy /* Split the 64KB block as needed */ 578e4808c4bSKip Macy for (sbp=0; length > 0; sbp++) { 579e2c1fe90SJustin T. Gibbs cm = xbd_dequeue_cm(sc, XBD_Q_FREE); 580e4808c4bSKip Macy if (cm == NULL) { 58133eebb6aSJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 58233eebb6aSJustin T. Gibbs device_printf(sc->xbd_dev, "dump: no more commands?\n"); 583e4808c4bSKip Macy return (EBUSY); 584e4808c4bSKip Macy } 585e4808c4bSKip Macy 58633eebb6aSJustin T. Gibbs if (gnttab_alloc_grant_references(sc->xbd_max_request_segments, 58733eebb6aSJustin T. Gibbs &cm->cm_gref_head) != 0) { 58833eebb6aSJustin T. Gibbs xbd_free_command(cm); 58933eebb6aSJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 59033eebb6aSJustin T. Gibbs device_printf(sc->xbd_dev, "no more grant allocs?\n"); 591e4808c4bSKip Macy return (EBUSY); 592e4808c4bSKip Macy } 593e4808c4bSKip Macy 59433eebb6aSJustin T. Gibbs chunk = length > sc->xbd_max_request_size ? 59533eebb6aSJustin T. Gibbs sc->xbd_max_request_size : length; 59633eebb6aSJustin T. Gibbs cm->cm_data = virtual; 59733eebb6aSJustin T. Gibbs cm->cm_datalen = chunk; 59833eebb6aSJustin T. Gibbs cm->cm_operation = BLKIF_OP_WRITE; 59933eebb6aSJustin T. Gibbs cm->cm_sector_number = offset / dp->d_sectorsize; 60033eebb6aSJustin T. Gibbs cm->cm_complete = xbd_dump_complete; 601e4808c4bSKip Macy 602e2c1fe90SJustin T. Gibbs xbd_enqueue_cm(cm, XBD_Q_READY); 6038698b76cSKip Macy 6048698b76cSKip Macy length -= chunk; 6058698b76cSKip Macy offset += chunk; 6068698b76cSKip Macy virtual = (char *) virtual + chunk; 6078698b76cSKip Macy } 6088698b76cSKip Macy 609e4808c4bSKip Macy /* Tell DOM0 to do the I/O */ 61033eebb6aSJustin T. Gibbs xbd_startio(sc); 61133eebb6aSJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 612e4808c4bSKip Macy 613e4808c4bSKip Macy /* Poll for the completion. */ 61433eebb6aSJustin T. Gibbs xbd_quiesce(sc); /* All quite on the eastern front */ 615e4808c4bSKip Macy 616e4808c4bSKip Macy /* If there were any errors, bail out... */ 617e2c1fe90SJustin T. Gibbs while ((cm = xbd_dequeue_cm(sc, XBD_Q_COMPLETE)) != NULL) { 61833eebb6aSJustin T. Gibbs if (cm->cm_status != BLKIF_RSP_OKAY) { 61933eebb6aSJustin T. Gibbs device_printf(sc->xbd_dev, 620e4808c4bSKip Macy "Dump I/O failed at sector %jd\n", 62133eebb6aSJustin T. Gibbs cm->cm_sector_number); 622e4808c4bSKip Macy rc = EIO; 6238698b76cSKip Macy } 62433eebb6aSJustin T. Gibbs xbd_free_command(cm); 6258698b76cSKip Macy } 626e4808c4bSKip Macy 6278698b76cSKip Macy return (rc); 6288698b76cSKip Macy } 6298698b76cSKip Macy 630fac3fd80SJustin T. Gibbs /*----------------------------- Disk Entrypoints -----------------------------*/ 63123dc5621SKip Macy static int 632fac3fd80SJustin T. Gibbs xbd_open(struct disk *dp) 63389e0f4d2SKip Macy { 634fac3fd80SJustin T. Gibbs struct xbd_softc *sc = dp->d_drv1; 63523dc5621SKip Macy 636fac3fd80SJustin T. Gibbs if (sc == NULL) { 637fac3fd80SJustin T. Gibbs printf("xb%d: not found", sc->xbd_unit); 63823dc5621SKip Macy return (ENXIO); 63923dc5621SKip Macy } 64023dc5621SKip Macy 641e2c1fe90SJustin T. Gibbs sc->xbd_flags |= XBDF_OPEN; 642fac3fd80SJustin T. Gibbs sc->xbd_users++; 643fac3fd80SJustin T. Gibbs return (0); 644fac3fd80SJustin T. Gibbs } 645fac3fd80SJustin T. Gibbs 646fac3fd80SJustin T. Gibbs static int 647fac3fd80SJustin T. Gibbs xbd_close(struct disk *dp) 648fac3fd80SJustin T. Gibbs { 649fac3fd80SJustin T. Gibbs struct xbd_softc *sc = dp->d_drv1; 650fac3fd80SJustin T. Gibbs 651fac3fd80SJustin T. Gibbs if (sc == NULL) 652fac3fd80SJustin T. Gibbs return (ENXIO); 653e2c1fe90SJustin T. Gibbs sc->xbd_flags &= ~XBDF_OPEN; 654fac3fd80SJustin T. Gibbs if (--(sc->xbd_users) == 0) { 655fac3fd80SJustin T. Gibbs /* 656fac3fd80SJustin T. Gibbs * Check whether we have been instructed to close. We will 657fac3fd80SJustin T. Gibbs * have ignored this request initially, as the device was 658fac3fd80SJustin T. Gibbs * still mounted. 659fac3fd80SJustin T. Gibbs */ 660fac3fd80SJustin T. Gibbs if (xenbus_get_otherend_state(sc->xbd_dev) == 661fac3fd80SJustin T. Gibbs XenbusStateClosing) 662fac3fd80SJustin T. Gibbs xbd_closing(sc->xbd_dev); 663fac3fd80SJustin T. Gibbs } 664fac3fd80SJustin T. Gibbs return (0); 665fac3fd80SJustin T. Gibbs } 666fac3fd80SJustin T. Gibbs 667fac3fd80SJustin T. Gibbs static int 668fac3fd80SJustin T. Gibbs xbd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 669fac3fd80SJustin T. Gibbs { 670fac3fd80SJustin T. Gibbs struct xbd_softc *sc = dp->d_drv1; 671fac3fd80SJustin T. Gibbs 672fac3fd80SJustin T. Gibbs if (sc == NULL) 673fac3fd80SJustin T. Gibbs return (ENXIO); 674fac3fd80SJustin T. Gibbs 675fac3fd80SJustin T. Gibbs return (ENOTTY); 676fac3fd80SJustin T. Gibbs } 677fac3fd80SJustin T. Gibbs 678fac3fd80SJustin T. Gibbs /* 679fac3fd80SJustin T. Gibbs * Read/write routine for a buffer. Finds the proper unit, place it on 680fac3fd80SJustin T. Gibbs * the sortq and kick the controller. 681fac3fd80SJustin T. Gibbs */ 682fac3fd80SJustin T. Gibbs static void 683fac3fd80SJustin T. Gibbs xbd_strategy(struct bio *bp) 684fac3fd80SJustin T. Gibbs { 685fac3fd80SJustin T. Gibbs struct xbd_softc *sc = bp->bio_disk->d_drv1; 686fac3fd80SJustin T. Gibbs 687fac3fd80SJustin T. Gibbs /* bogus disk? */ 688fac3fd80SJustin T. Gibbs if (sc == NULL) { 689fac3fd80SJustin T. Gibbs bp->bio_error = EINVAL; 690fac3fd80SJustin T. Gibbs bp->bio_flags |= BIO_ERROR; 691fac3fd80SJustin T. Gibbs bp->bio_resid = bp->bio_bcount; 692fac3fd80SJustin T. Gibbs biodone(bp); 693fac3fd80SJustin T. Gibbs return; 694fac3fd80SJustin T. Gibbs } 695fac3fd80SJustin T. Gibbs 696fac3fd80SJustin T. Gibbs /* 697fac3fd80SJustin T. Gibbs * Place it in the queue of disk activities for this disk 698fac3fd80SJustin T. Gibbs */ 699fac3fd80SJustin T. Gibbs mtx_lock(&sc->xbd_io_lock); 700fac3fd80SJustin T. Gibbs 701fac3fd80SJustin T. Gibbs xbd_enqueue_bio(sc, bp); 702fac3fd80SJustin T. Gibbs xbd_startio(sc); 703fac3fd80SJustin T. Gibbs 704fac3fd80SJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 705fac3fd80SJustin T. Gibbs return; 706fac3fd80SJustin T. Gibbs } 707fac3fd80SJustin T. Gibbs 708fac3fd80SJustin T. Gibbs /*------------------------------ Ring Management -----------------------------*/ 709fac3fd80SJustin T. Gibbs static int 710cdf5d66fSJustin T. Gibbs xbd_alloc_ring(struct xbd_softc *sc) 711fac3fd80SJustin T. Gibbs { 712fac3fd80SJustin T. Gibbs blkif_sring_t *sring; 713fac3fd80SJustin T. Gibbs uintptr_t sring_page_addr; 714fac3fd80SJustin T. Gibbs int error; 715fac3fd80SJustin T. Gibbs int i; 716fac3fd80SJustin T. Gibbs 717fac3fd80SJustin T. Gibbs sring = malloc(sc->xbd_ring_pages * PAGE_SIZE, M_XENBLOCKFRONT, 718fac3fd80SJustin T. Gibbs M_NOWAIT|M_ZERO); 719fac3fd80SJustin T. Gibbs if (sring == NULL) { 720fac3fd80SJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, ENOMEM, "allocating shared ring"); 721fac3fd80SJustin T. Gibbs return (ENOMEM); 722fac3fd80SJustin T. Gibbs } 723fac3fd80SJustin T. Gibbs SHARED_RING_INIT(sring); 724fac3fd80SJustin T. Gibbs FRONT_RING_INIT(&sc->xbd_ring, sring, sc->xbd_ring_pages * PAGE_SIZE); 725fac3fd80SJustin T. Gibbs 726fac3fd80SJustin T. Gibbs for (i = 0, sring_page_addr = (uintptr_t)sring; 727fac3fd80SJustin T. Gibbs i < sc->xbd_ring_pages; 728fac3fd80SJustin T. Gibbs i++, sring_page_addr += PAGE_SIZE) { 729fac3fd80SJustin T. Gibbs 730fac3fd80SJustin T. Gibbs error = xenbus_grant_ring(sc->xbd_dev, 731fac3fd80SJustin T. Gibbs (vtomach(sring_page_addr) >> PAGE_SHIFT), 732fac3fd80SJustin T. Gibbs &sc->xbd_ring_ref[i]); 733fac3fd80SJustin T. Gibbs if (error) { 734fac3fd80SJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 735fac3fd80SJustin T. Gibbs "granting ring_ref(%d)", i); 736fac3fd80SJustin T. Gibbs return (error); 737fac3fd80SJustin T. Gibbs } 738fac3fd80SJustin T. Gibbs } 739fac3fd80SJustin T. Gibbs if (sc->xbd_ring_pages == 1) { 740fac3fd80SJustin T. Gibbs error = xs_printf(XST_NIL, xenbus_get_node(sc->xbd_dev), 741fac3fd80SJustin T. Gibbs "ring-ref", "%u", sc->xbd_ring_ref[0]); 742fac3fd80SJustin T. Gibbs if (error) { 743fac3fd80SJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 744fac3fd80SJustin T. Gibbs "writing %s/ring-ref", 745fac3fd80SJustin T. Gibbs xenbus_get_node(sc->xbd_dev)); 746fac3fd80SJustin T. Gibbs return (error); 747fac3fd80SJustin T. Gibbs } 748fac3fd80SJustin T. Gibbs } else { 749fac3fd80SJustin T. Gibbs for (i = 0; i < sc->xbd_ring_pages; i++) { 750fac3fd80SJustin T. Gibbs char ring_ref_name[]= "ring_refXX"; 751fac3fd80SJustin T. Gibbs 752fac3fd80SJustin T. Gibbs snprintf(ring_ref_name, sizeof(ring_ref_name), 753fac3fd80SJustin T. Gibbs "ring-ref%u", i); 754fac3fd80SJustin T. Gibbs error = xs_printf(XST_NIL, xenbus_get_node(sc->xbd_dev), 755fac3fd80SJustin T. Gibbs ring_ref_name, "%u", sc->xbd_ring_ref[i]); 756fac3fd80SJustin T. Gibbs if (error) { 757fac3fd80SJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 758fac3fd80SJustin T. Gibbs "writing %s/%s", 759fac3fd80SJustin T. Gibbs xenbus_get_node(sc->xbd_dev), 760fac3fd80SJustin T. Gibbs ring_ref_name); 761fac3fd80SJustin T. Gibbs return (error); 762fac3fd80SJustin T. Gibbs } 763fac3fd80SJustin T. Gibbs } 764fac3fd80SJustin T. Gibbs } 765fac3fd80SJustin T. Gibbs 76676acc41fSJustin T. Gibbs error = xen_intr_alloc_and_bind_local_port(sc->xbd_dev, 76776acc41fSJustin T. Gibbs xenbus_get_otherend_id(sc->xbd_dev), NULL, xbd_int, sc, 76876acc41fSJustin T. Gibbs INTR_TYPE_BIO | INTR_MPSAFE, &sc->xen_intr_handle); 769fac3fd80SJustin T. Gibbs if (error) { 770fac3fd80SJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 77176acc41fSJustin T. Gibbs "xen_intr_alloc_and_bind_local_port failed"); 772fac3fd80SJustin T. Gibbs return (error); 773fac3fd80SJustin T. Gibbs } 774fac3fd80SJustin T. Gibbs 775fac3fd80SJustin T. Gibbs return (0); 776fac3fd80SJustin T. Gibbs } 777fac3fd80SJustin T. Gibbs 778d9fab01dSJustin T. Gibbs static void 779d9fab01dSJustin T. Gibbs xbd_free_ring(struct xbd_softc *sc) 780d9fab01dSJustin T. Gibbs { 781d9fab01dSJustin T. Gibbs int i; 782d9fab01dSJustin T. Gibbs 783d9fab01dSJustin T. Gibbs if (sc->xbd_ring.sring == NULL) 784d9fab01dSJustin T. Gibbs return; 785d9fab01dSJustin T. Gibbs 786d9fab01dSJustin T. Gibbs for (i = 0; i < sc->xbd_ring_pages; i++) { 787d9fab01dSJustin T. Gibbs if (sc->xbd_ring_ref[i] != GRANT_REF_INVALID) { 788d9fab01dSJustin T. Gibbs gnttab_end_foreign_access_ref(sc->xbd_ring_ref[i]); 789d9fab01dSJustin T. Gibbs sc->xbd_ring_ref[i] = GRANT_REF_INVALID; 790d9fab01dSJustin T. Gibbs } 791d9fab01dSJustin T. Gibbs } 792d9fab01dSJustin T. Gibbs free(sc->xbd_ring.sring, M_XENBLOCKFRONT); 793d9fab01dSJustin T. Gibbs sc->xbd_ring.sring = NULL; 794d9fab01dSJustin T. Gibbs } 795d9fab01dSJustin T. Gibbs 796fac3fd80SJustin T. Gibbs /*-------------------------- Initialization/Teardown -------------------------*/ 7979985113bSJustin T. Gibbs static int 7989985113bSJustin T. Gibbs xbd_feature_string(struct xbd_softc *sc, char *features, size_t len) 7999985113bSJustin T. Gibbs { 8009985113bSJustin T. Gibbs struct sbuf sb; 8019985113bSJustin T. Gibbs int feature_cnt; 8029985113bSJustin T. Gibbs 8039985113bSJustin T. Gibbs sbuf_new(&sb, features, len, SBUF_FIXEDLEN); 8049985113bSJustin T. Gibbs 8059985113bSJustin T. Gibbs feature_cnt = 0; 8069985113bSJustin T. Gibbs if ((sc->xbd_flags & XBDF_FLUSH) != 0) { 8079985113bSJustin T. Gibbs sbuf_printf(&sb, "flush"); 8089985113bSJustin T. Gibbs feature_cnt++; 8099985113bSJustin T. Gibbs } 8109985113bSJustin T. Gibbs 8119985113bSJustin T. Gibbs if ((sc->xbd_flags & XBDF_BARRIER) != 0) { 8129985113bSJustin T. Gibbs if (feature_cnt != 0) 8139985113bSJustin T. Gibbs sbuf_printf(&sb, ", "); 8149985113bSJustin T. Gibbs sbuf_printf(&sb, "write_barrier"); 8159985113bSJustin T. Gibbs feature_cnt++; 8169985113bSJustin T. Gibbs } 8179985113bSJustin T. Gibbs 8189985113bSJustin T. Gibbs (void) sbuf_finish(&sb); 8199985113bSJustin T. Gibbs return (sbuf_len(&sb)); 8209985113bSJustin T. Gibbs } 8219985113bSJustin T. Gibbs 8229985113bSJustin T. Gibbs static int 8239985113bSJustin T. Gibbs xbd_sysctl_features(SYSCTL_HANDLER_ARGS) 8249985113bSJustin T. Gibbs { 8259985113bSJustin T. Gibbs char features[80]; 8269985113bSJustin T. Gibbs struct xbd_softc *sc = arg1; 8279985113bSJustin T. Gibbs int error; 8289985113bSJustin T. Gibbs int len; 8299985113bSJustin T. Gibbs 8309985113bSJustin T. Gibbs error = sysctl_wire_old_buffer(req, 0); 8319985113bSJustin T. Gibbs if (error != 0) 8329985113bSJustin T. Gibbs return (error); 8339985113bSJustin T. Gibbs 8349985113bSJustin T. Gibbs len = xbd_feature_string(sc, features, sizeof(features)); 8359985113bSJustin T. Gibbs 8369985113bSJustin T. Gibbs /* len is -1 on error, which will make the SYSCTL_OUT a no-op. */ 8379985113bSJustin T. Gibbs return (SYSCTL_OUT(req, features, len + 1/*NUL*/)); 8389985113bSJustin T. Gibbs } 8399985113bSJustin T. Gibbs 8408b8bfa35SJustin T. Gibbs static void 84133eebb6aSJustin T. Gibbs xbd_setup_sysctl(struct xbd_softc *xbd) 8428b8bfa35SJustin T. Gibbs { 8438b8bfa35SJustin T. Gibbs struct sysctl_ctx_list *sysctl_ctx = NULL; 8448b8bfa35SJustin T. Gibbs struct sysctl_oid *sysctl_tree = NULL; 8459985113bSJustin T. Gibbs struct sysctl_oid_list *children; 8468b8bfa35SJustin T. Gibbs 84733eebb6aSJustin T. Gibbs sysctl_ctx = device_get_sysctl_ctx(xbd->xbd_dev); 8488b8bfa35SJustin T. Gibbs if (sysctl_ctx == NULL) 8498b8bfa35SJustin T. Gibbs return; 8508b8bfa35SJustin T. Gibbs 85133eebb6aSJustin T. Gibbs sysctl_tree = device_get_sysctl_tree(xbd->xbd_dev); 8528b8bfa35SJustin T. Gibbs if (sysctl_tree == NULL) 8538b8bfa35SJustin T. Gibbs return; 8548b8bfa35SJustin T. Gibbs 8559985113bSJustin T. Gibbs children = SYSCTL_CHILDREN(sysctl_tree); 8569985113bSJustin T. Gibbs SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO, 85733eebb6aSJustin T. Gibbs "max_requests", CTLFLAG_RD, &xbd->xbd_max_requests, -1, 8588b8bfa35SJustin T. Gibbs "maximum outstanding requests (negotiated)"); 8598b8bfa35SJustin T. Gibbs 8609985113bSJustin T. Gibbs SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO, 8618b8bfa35SJustin T. Gibbs "max_request_segments", CTLFLAG_RD, 86233eebb6aSJustin T. Gibbs &xbd->xbd_max_request_segments, 0, 8638b8bfa35SJustin T. Gibbs "maximum number of pages per requests (negotiated)"); 8648b8bfa35SJustin T. Gibbs 8659985113bSJustin T. Gibbs SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO, 86633eebb6aSJustin T. Gibbs "max_request_size", CTLFLAG_RD, &xbd->xbd_max_request_size, 0, 8678b8bfa35SJustin T. Gibbs "maximum size in bytes of a request (negotiated)"); 8688b8bfa35SJustin T. Gibbs 8699985113bSJustin T. Gibbs SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO, 87033eebb6aSJustin T. Gibbs "ring_pages", CTLFLAG_RD, &xbd->xbd_ring_pages, 0, 8718b8bfa35SJustin T. Gibbs "communication channel pages (negotiated)"); 8729985113bSJustin T. Gibbs 8739985113bSJustin T. Gibbs SYSCTL_ADD_PROC(sysctl_ctx, children, OID_AUTO, 8749985113bSJustin T. Gibbs "features", CTLTYPE_STRING|CTLFLAG_RD, xbd, 0, 8759985113bSJustin T. Gibbs xbd_sysctl_features, "A", "protocol features (negotiated)"); 8768b8bfa35SJustin T. Gibbs } 8778b8bfa35SJustin T. Gibbs 87823dc5621SKip Macy /* 879fac3fd80SJustin T. Gibbs * Translate Linux major/minor to an appropriate name and unit 880fac3fd80SJustin T. Gibbs * number. For HVM guests, this allows us to use the same drive names 881fac3fd80SJustin T. Gibbs * with blkfront as the emulated drives, easing transition slightly. 88223dc5621SKip Macy */ 883fac3fd80SJustin T. Gibbs static void 884fac3fd80SJustin T. Gibbs xbd_vdevice_to_unit(uint32_t vdevice, int *unit, const char **name) 88523dc5621SKip Macy { 886fac3fd80SJustin T. Gibbs static struct vdev_info { 887fac3fd80SJustin T. Gibbs int major; 888fac3fd80SJustin T. Gibbs int shift; 889fac3fd80SJustin T. Gibbs int base; 89023dc5621SKip Macy const char *name; 891fac3fd80SJustin T. Gibbs } info[] = { 892fac3fd80SJustin T. Gibbs {3, 6, 0, "ada"}, /* ide0 */ 893fac3fd80SJustin T. Gibbs {22, 6, 2, "ada"}, /* ide1 */ 894fac3fd80SJustin T. Gibbs {33, 6, 4, "ada"}, /* ide2 */ 895fac3fd80SJustin T. Gibbs {34, 6, 6, "ada"}, /* ide3 */ 896fac3fd80SJustin T. Gibbs {56, 6, 8, "ada"}, /* ide4 */ 897fac3fd80SJustin T. Gibbs {57, 6, 10, "ada"}, /* ide5 */ 898fac3fd80SJustin T. Gibbs {88, 6, 12, "ada"}, /* ide6 */ 899fac3fd80SJustin T. Gibbs {89, 6, 14, "ada"}, /* ide7 */ 900fac3fd80SJustin T. Gibbs {90, 6, 16, "ada"}, /* ide8 */ 901fac3fd80SJustin T. Gibbs {91, 6, 18, "ada"}, /* ide9 */ 90289e0f4d2SKip Macy 903fac3fd80SJustin T. Gibbs {8, 4, 0, "da"}, /* scsi disk0 */ 904fac3fd80SJustin T. Gibbs {65, 4, 16, "da"}, /* scsi disk1 */ 905fac3fd80SJustin T. Gibbs {66, 4, 32, "da"}, /* scsi disk2 */ 906fac3fd80SJustin T. Gibbs {67, 4, 48, "da"}, /* scsi disk3 */ 907fac3fd80SJustin T. Gibbs {68, 4, 64, "da"}, /* scsi disk4 */ 908fac3fd80SJustin T. Gibbs {69, 4, 80, "da"}, /* scsi disk5 */ 909fac3fd80SJustin T. Gibbs {70, 4, 96, "da"}, /* scsi disk6 */ 910fac3fd80SJustin T. Gibbs {71, 4, 112, "da"}, /* scsi disk7 */ 911fac3fd80SJustin T. Gibbs {128, 4, 128, "da"}, /* scsi disk8 */ 912fac3fd80SJustin T. Gibbs {129, 4, 144, "da"}, /* scsi disk9 */ 913fac3fd80SJustin T. Gibbs {130, 4, 160, "da"}, /* scsi disk10 */ 914fac3fd80SJustin T. Gibbs {131, 4, 176, "da"}, /* scsi disk11 */ 915fac3fd80SJustin T. Gibbs {132, 4, 192, "da"}, /* scsi disk12 */ 916fac3fd80SJustin T. Gibbs {133, 4, 208, "da"}, /* scsi disk13 */ 917fac3fd80SJustin T. Gibbs {134, 4, 224, "da"}, /* scsi disk14 */ 918fac3fd80SJustin T. Gibbs {135, 4, 240, "da"}, /* scsi disk15 */ 919fac3fd80SJustin T. Gibbs 920fac3fd80SJustin T. Gibbs {202, 4, 0, "xbd"}, /* xbd */ 921fac3fd80SJustin T. Gibbs 922fac3fd80SJustin T. Gibbs {0, 0, 0, NULL}, 923fac3fd80SJustin T. Gibbs }; 924fac3fd80SJustin T. Gibbs int major = vdevice >> 8; 925fac3fd80SJustin T. Gibbs int minor = vdevice & 0xff; 926fac3fd80SJustin T. Gibbs int i; 927fac3fd80SJustin T. Gibbs 928fac3fd80SJustin T. Gibbs if (vdevice & (1 << 28)) { 929fac3fd80SJustin T. Gibbs *unit = (vdevice & ((1 << 28) - 1)) >> 8; 930fac3fd80SJustin T. Gibbs *name = "xbd"; 931fac3fd80SJustin T. Gibbs return; 93289e0f4d2SKip Macy } 93389e0f4d2SKip Macy 934fac3fd80SJustin T. Gibbs for (i = 0; info[i].major; i++) { 935fac3fd80SJustin T. Gibbs if (info[i].major == major) { 936fac3fd80SJustin T. Gibbs *unit = info[i].base + (minor >> info[i].shift); 937fac3fd80SJustin T. Gibbs *name = info[i].name; 938fac3fd80SJustin T. Gibbs return; 939fac3fd80SJustin T. Gibbs } 940fac3fd80SJustin T. Gibbs } 941fac3fd80SJustin T. Gibbs 942fac3fd80SJustin T. Gibbs *unit = minor >> 4; 943fac3fd80SJustin T. Gibbs *name = "xbd"; 944fac3fd80SJustin T. Gibbs } 945fac3fd80SJustin T. Gibbs 946fac3fd80SJustin T. Gibbs int 947fac3fd80SJustin T. Gibbs xbd_instance_create(struct xbd_softc *sc, blkif_sector_t sectors, 948fac3fd80SJustin T. Gibbs int vdevice, uint16_t vdisk_info, unsigned long sector_size) 949fac3fd80SJustin T. Gibbs { 9509985113bSJustin T. Gibbs char features[80]; 951fac3fd80SJustin T. Gibbs int unit, error = 0; 952fac3fd80SJustin T. Gibbs const char *name; 953fac3fd80SJustin T. Gibbs 95433eebb6aSJustin T. Gibbs xbd_vdevice_to_unit(vdevice, &unit, &name); 95523dc5621SKip Macy 956fac3fd80SJustin T. Gibbs sc->xbd_unit = unit; 95789e0f4d2SKip Macy 9589985113bSJustin T. Gibbs if (strcmp(name, "xbd") != 0) 959fac3fd80SJustin T. Gibbs device_printf(sc->xbd_dev, "attaching as %s%d\n", name, unit); 96089e0f4d2SKip Macy 9619985113bSJustin T. Gibbs if (xbd_feature_string(sc, features, sizeof(features)) > 0) { 9629985113bSJustin T. Gibbs device_printf(sc->xbd_dev, "features: %s\n", 9639985113bSJustin T. Gibbs features); 9649985113bSJustin T. Gibbs } 9659985113bSJustin T. Gibbs 966fac3fd80SJustin T. Gibbs sc->xbd_disk = disk_alloc(); 967fac3fd80SJustin T. Gibbs sc->xbd_disk->d_unit = sc->xbd_unit; 968fac3fd80SJustin T. Gibbs sc->xbd_disk->d_open = xbd_open; 969fac3fd80SJustin T. Gibbs sc->xbd_disk->d_close = xbd_close; 970fac3fd80SJustin T. Gibbs sc->xbd_disk->d_ioctl = xbd_ioctl; 971fac3fd80SJustin T. Gibbs sc->xbd_disk->d_strategy = xbd_strategy; 972fac3fd80SJustin T. Gibbs sc->xbd_disk->d_dump = xbd_dump; 973fac3fd80SJustin T. Gibbs sc->xbd_disk->d_name = name; 974fac3fd80SJustin T. Gibbs sc->xbd_disk->d_drv1 = sc; 975fac3fd80SJustin T. Gibbs sc->xbd_disk->d_sectorsize = sector_size; 9768b8bfa35SJustin T. Gibbs 977fac3fd80SJustin T. Gibbs sc->xbd_disk->d_mediasize = sectors * sector_size; 978fac3fd80SJustin T. Gibbs sc->xbd_disk->d_maxsize = sc->xbd_max_request_size; 97977b6916dSRoger Pau Monné sc->xbd_disk->d_flags = 0; 9809985113bSJustin T. Gibbs if ((sc->xbd_flags & (XBDF_FLUSH|XBDF_BARRIER)) != 0) { 9819985113bSJustin T. Gibbs sc->xbd_disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 9829985113bSJustin T. Gibbs device_printf(sc->xbd_dev, 9839985113bSJustin T. Gibbs "synchronize cache commands enabled.\n"); 9849985113bSJustin T. Gibbs } 985fac3fd80SJustin T. Gibbs disk_create(sc->xbd_disk, DISK_VERSION); 98612678024SDoug Rabson 987fac3fd80SJustin T. Gibbs return error; 98812678024SDoug Rabson } 98912678024SDoug Rabson 990fac3fd80SJustin T. Gibbs static void 991fac3fd80SJustin T. Gibbs xbd_free(struct xbd_softc *sc) 99212678024SDoug Rabson { 993fac3fd80SJustin T. Gibbs int i; 99412678024SDoug Rabson 99512678024SDoug Rabson /* Prevent new requests being issued until we fix things up. */ 99633eebb6aSJustin T. Gibbs mtx_lock(&sc->xbd_io_lock); 997e2c1fe90SJustin T. Gibbs sc->xbd_state = XBD_STATE_DISCONNECTED; 99833eebb6aSJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 99989e0f4d2SKip Macy 1000fac3fd80SJustin T. Gibbs /* Free resources associated with old device channel. */ 1001d9fab01dSJustin T. Gibbs xbd_free_ring(sc); 1002fac3fd80SJustin T. Gibbs if (sc->xbd_shadow) { 100389e0f4d2SKip Macy 1004fac3fd80SJustin T. Gibbs for (i = 0; i < sc->xbd_max_requests; i++) { 1005fac3fd80SJustin T. Gibbs struct xbd_command *cm; 100689e0f4d2SKip Macy 1007fac3fd80SJustin T. Gibbs cm = &sc->xbd_shadow[i]; 1008fac3fd80SJustin T. Gibbs if (cm->cm_sg_refs != NULL) { 1009fac3fd80SJustin T. Gibbs free(cm->cm_sg_refs, M_XENBLOCKFRONT); 1010fac3fd80SJustin T. Gibbs cm->cm_sg_refs = NULL; 101189e0f4d2SKip Macy } 101289e0f4d2SKip Macy 1013fac3fd80SJustin T. Gibbs bus_dmamap_destroy(sc->xbd_io_dmat, cm->cm_map); 1014fac3fd80SJustin T. Gibbs } 1015fac3fd80SJustin T. Gibbs free(sc->xbd_shadow, M_XENBLOCKFRONT); 1016fac3fd80SJustin T. Gibbs sc->xbd_shadow = NULL; 1017fac3fd80SJustin T. Gibbs 1018fac3fd80SJustin T. Gibbs bus_dma_tag_destroy(sc->xbd_io_dmat); 1019fac3fd80SJustin T. Gibbs 1020e2c1fe90SJustin T. Gibbs xbd_initq_cm(sc, XBD_Q_FREE); 1021e2c1fe90SJustin T. Gibbs xbd_initq_cm(sc, XBD_Q_READY); 1022e2c1fe90SJustin T. Gibbs xbd_initq_cm(sc, XBD_Q_COMPLETE); 1023fac3fd80SJustin T. Gibbs } 1024fac3fd80SJustin T. Gibbs 102576acc41fSJustin T. Gibbs xen_intr_unbind(&sc->xen_intr_handle); 102676acc41fSJustin T. Gibbs 1027fac3fd80SJustin T. Gibbs } 1028fac3fd80SJustin T. Gibbs 1029fac3fd80SJustin T. Gibbs /*--------------------------- State Change Handlers --------------------------*/ 1030ff662b5cSJustin T. Gibbs static void 103133eebb6aSJustin T. Gibbs xbd_initialize(struct xbd_softc *sc) 103289e0f4d2SKip Macy { 1033ff662b5cSJustin T. Gibbs const char *otherend_path; 1034ff662b5cSJustin T. Gibbs const char *node_path; 10358b8bfa35SJustin T. Gibbs uint32_t max_ring_page_order; 1036ff662b5cSJustin T. Gibbs int error; 1037ff662b5cSJustin T. Gibbs int i; 103889e0f4d2SKip Macy 103933eebb6aSJustin T. Gibbs if (xenbus_get_state(sc->xbd_dev) != XenbusStateInitialising) { 104006a630f6SJustin T. Gibbs /* Initialization has already been performed. */ 1041ff662b5cSJustin T. Gibbs return; 104206a630f6SJustin T. Gibbs } 104389e0f4d2SKip Macy 1044ff662b5cSJustin T. Gibbs /* 1045ff662b5cSJustin T. Gibbs * Protocol defaults valid even if negotiation for a 1046ff662b5cSJustin T. Gibbs * setting fails. 1047ff662b5cSJustin T. Gibbs */ 10488b8bfa35SJustin T. Gibbs max_ring_page_order = 0; 104933eebb6aSJustin T. Gibbs sc->xbd_ring_pages = 1; 1050*112cacaeSRoger Pau Monné sc->xbd_max_request_segments = BLKIF_MAX_SEGMENTS_PER_REQUEST; 105133eebb6aSJustin T. Gibbs sc->xbd_max_request_size = 105233eebb6aSJustin T. Gibbs XBD_SEGS_TO_SIZE(sc->xbd_max_request_segments); 1053ff662b5cSJustin T. Gibbs 1054ff662b5cSJustin T. Gibbs /* 1055ff662b5cSJustin T. Gibbs * Protocol negotiation. 1056ff662b5cSJustin T. Gibbs * 1057ff662b5cSJustin T. Gibbs * \note xs_gather() returns on the first encountered error, so 1058ff662b5cSJustin T. Gibbs * we must use independant calls in order to guarantee 1059ff662b5cSJustin T. Gibbs * we don't miss information in a sparsly populated back-end 1060ff662b5cSJustin T. Gibbs * tree. 10618b8bfa35SJustin T. Gibbs * 10628b8bfa35SJustin T. Gibbs * \note xs_scanf() does not update variables for unmatched 10638b8bfa35SJustin T. Gibbs * fields. 1064ff662b5cSJustin T. Gibbs */ 106533eebb6aSJustin T. Gibbs otherend_path = xenbus_get_otherend_path(sc->xbd_dev); 106633eebb6aSJustin T. Gibbs node_path = xenbus_get_node(sc->xbd_dev); 10678b8bfa35SJustin T. Gibbs 10688b8bfa35SJustin T. Gibbs /* Support both backend schemes for relaying ring page limits. */ 10698b8bfa35SJustin T. Gibbs (void)xs_scanf(XST_NIL, otherend_path, 10708b8bfa35SJustin T. Gibbs "max-ring-page-order", NULL, "%" PRIu32, 10718b8bfa35SJustin T. Gibbs &max_ring_page_order); 107233eebb6aSJustin T. Gibbs sc->xbd_ring_pages = 1 << max_ring_page_order; 1073ff662b5cSJustin T. Gibbs (void)xs_scanf(XST_NIL, otherend_path, 1074ff662b5cSJustin T. Gibbs "max-ring-pages", NULL, "%" PRIu32, 107533eebb6aSJustin T. Gibbs &sc->xbd_ring_pages); 107633eebb6aSJustin T. Gibbs if (sc->xbd_ring_pages < 1) 107733eebb6aSJustin T. Gibbs sc->xbd_ring_pages = 1; 1078ff662b5cSJustin T. Gibbs 107933eebb6aSJustin T. Gibbs if (sc->xbd_ring_pages > XBD_MAX_RING_PAGES) { 108033eebb6aSJustin T. Gibbs device_printf(sc->xbd_dev, 108133eebb6aSJustin T. Gibbs "Back-end specified ring-pages of %u " 1082*112cacaeSRoger Pau Monné "limited to front-end limit of %u.\n", 108333eebb6aSJustin T. Gibbs sc->xbd_ring_pages, XBD_MAX_RING_PAGES); 108433eebb6aSJustin T. Gibbs sc->xbd_ring_pages = XBD_MAX_RING_PAGES; 108589e0f4d2SKip Macy } 108689e0f4d2SKip Macy 108733eebb6aSJustin T. Gibbs if (powerof2(sc->xbd_ring_pages) == 0) { 10888b8bfa35SJustin T. Gibbs uint32_t new_page_limit; 10898b8bfa35SJustin T. Gibbs 109033eebb6aSJustin T. Gibbs new_page_limit = 0x01 << (fls(sc->xbd_ring_pages) - 1); 109133eebb6aSJustin T. Gibbs device_printf(sc->xbd_dev, 109233eebb6aSJustin T. Gibbs "Back-end specified ring-pages of %u " 109333eebb6aSJustin T. Gibbs "is not a power of 2. Limited to %u.\n", 109433eebb6aSJustin T. Gibbs sc->xbd_ring_pages, new_page_limit); 109533eebb6aSJustin T. Gibbs sc->xbd_ring_pages = new_page_limit; 10968b8bfa35SJustin T. Gibbs } 10978b8bfa35SJustin T. Gibbs 1098*112cacaeSRoger Pau Monné sc->xbd_max_requests = 1099*112cacaeSRoger Pau Monné BLKIF_MAX_RING_REQUESTS(sc->xbd_ring_pages * PAGE_SIZE); 110033eebb6aSJustin T. Gibbs if (sc->xbd_max_requests > XBD_MAX_REQUESTS) { 110133eebb6aSJustin T. Gibbs device_printf(sc->xbd_dev, 110233eebb6aSJustin T. Gibbs "Back-end specified max_requests of %u " 1103*112cacaeSRoger Pau Monné "limited to front-end limit of %zu.\n", 110433eebb6aSJustin T. Gibbs sc->xbd_max_requests, XBD_MAX_REQUESTS); 110533eebb6aSJustin T. Gibbs sc->xbd_max_requests = XBD_MAX_REQUESTS; 110689e0f4d2SKip Macy } 1107ff662b5cSJustin T. Gibbs 1108ff662b5cSJustin T. Gibbs /* Allocate datastructures based on negotiated values. */ 110933eebb6aSJustin T. Gibbs error = bus_dma_tag_create( 111033eebb6aSJustin T. Gibbs bus_get_dma_tag(sc->xbd_dev), /* parent */ 1111ff662b5cSJustin T. Gibbs 512, PAGE_SIZE, /* algnmnt, boundary */ 1112ff662b5cSJustin T. Gibbs BUS_SPACE_MAXADDR, /* lowaddr */ 1113ff662b5cSJustin T. Gibbs BUS_SPACE_MAXADDR, /* highaddr */ 1114ff662b5cSJustin T. Gibbs NULL, NULL, /* filter, filterarg */ 111533eebb6aSJustin T. Gibbs sc->xbd_max_request_size, 111633eebb6aSJustin T. Gibbs sc->xbd_max_request_segments, 1117ff662b5cSJustin T. Gibbs PAGE_SIZE, /* maxsegsize */ 1118ff662b5cSJustin T. Gibbs BUS_DMA_ALLOCNOW, /* flags */ 1119ff662b5cSJustin T. Gibbs busdma_lock_mutex, /* lockfunc */ 112033eebb6aSJustin T. Gibbs &sc->xbd_io_lock, /* lockarg */ 112133eebb6aSJustin T. Gibbs &sc->xbd_io_dmat); 1122ff662b5cSJustin T. Gibbs if (error != 0) { 112333eebb6aSJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 1124ff662b5cSJustin T. Gibbs "Cannot allocate parent DMA tag\n"); 1125ff662b5cSJustin T. Gibbs return; 1126ff662b5cSJustin T. Gibbs } 1127ff662b5cSJustin T. Gibbs 1128ff662b5cSJustin T. Gibbs /* Per-transaction data allocation. */ 112933eebb6aSJustin T. Gibbs sc->xbd_shadow = malloc(sizeof(*sc->xbd_shadow) * sc->xbd_max_requests, 1130ff662b5cSJustin T. Gibbs M_XENBLOCKFRONT, M_NOWAIT|M_ZERO); 113133eebb6aSJustin T. Gibbs if (sc->xbd_shadow == NULL) { 113233eebb6aSJustin T. Gibbs bus_dma_tag_destroy(sc->xbd_io_dmat); 113333eebb6aSJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 1134ff662b5cSJustin T. Gibbs "Cannot allocate request structures\n"); 113506a630f6SJustin T. Gibbs return; 1136ff662b5cSJustin T. Gibbs } 1137ff662b5cSJustin T. Gibbs 113833eebb6aSJustin T. Gibbs for (i = 0; i < sc->xbd_max_requests; i++) { 113933eebb6aSJustin T. Gibbs struct xbd_command *cm; 1140ff662b5cSJustin T. Gibbs 114133eebb6aSJustin T. Gibbs cm = &sc->xbd_shadow[i]; 114233eebb6aSJustin T. Gibbs cm->cm_sg_refs = malloc( 114333eebb6aSJustin T. Gibbs sizeof(grant_ref_t) * sc->xbd_max_request_segments, 1144ff662b5cSJustin T. Gibbs M_XENBLOCKFRONT, M_NOWAIT); 114533eebb6aSJustin T. Gibbs if (cm->cm_sg_refs == NULL) 1146ff662b5cSJustin T. Gibbs break; 114733eebb6aSJustin T. Gibbs cm->cm_id = i; 1148e2c1fe90SJustin T. Gibbs cm->cm_flags = XBDCF_INITIALIZER; 1149ff662b5cSJustin T. Gibbs cm->cm_sc = sc; 115033eebb6aSJustin T. Gibbs if (bus_dmamap_create(sc->xbd_io_dmat, 0, &cm->cm_map) != 0) 1151ff662b5cSJustin T. Gibbs break; 115233eebb6aSJustin T. Gibbs xbd_free_command(cm); 1153ff662b5cSJustin T. Gibbs } 1154ff662b5cSJustin T. Gibbs 1155cdf5d66fSJustin T. Gibbs if (xbd_alloc_ring(sc) != 0) 1156ff662b5cSJustin T. Gibbs return; 1157ff662b5cSJustin T. Gibbs 11588b8bfa35SJustin T. Gibbs /* Support both backend schemes for relaying ring page limits. */ 115933eebb6aSJustin T. Gibbs if (sc->xbd_ring_pages > 1) { 1160ff662b5cSJustin T. Gibbs error = xs_printf(XST_NIL, node_path, 116133eebb6aSJustin T. Gibbs "num-ring-pages","%u", 116233eebb6aSJustin T. Gibbs sc->xbd_ring_pages); 1163ff662b5cSJustin T. Gibbs if (error) { 116433eebb6aSJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 11658b8bfa35SJustin T. Gibbs "writing %s/num-ring-pages", 11668b8bfa35SJustin T. Gibbs node_path); 11678b8bfa35SJustin T. Gibbs return; 11688b8bfa35SJustin T. Gibbs } 11690d172324SJustin T. Gibbs 11708b8bfa35SJustin T. Gibbs error = xs_printf(XST_NIL, node_path, 11710d172324SJustin T. Gibbs "ring-page-order", "%u", 117233eebb6aSJustin T. Gibbs fls(sc->xbd_ring_pages) - 1); 11738b8bfa35SJustin T. Gibbs if (error) { 117433eebb6aSJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 11758b8bfa35SJustin T. Gibbs "writing %s/ring-page-order", 1176ff662b5cSJustin T. Gibbs node_path); 1177ff662b5cSJustin T. Gibbs return; 1178ff662b5cSJustin T. Gibbs } 11790d172324SJustin T. Gibbs } 1180ff662b5cSJustin T. Gibbs 1181ff662b5cSJustin T. Gibbs error = xs_printf(XST_NIL, node_path, "event-channel", 118276acc41fSJustin T. Gibbs "%u", xen_intr_port(sc->xen_intr_handle)); 1183ff662b5cSJustin T. Gibbs if (error) { 118433eebb6aSJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 1185ff662b5cSJustin T. Gibbs "writing %s/event-channel", 1186ff662b5cSJustin T. Gibbs node_path); 1187ff662b5cSJustin T. Gibbs return; 1188ff662b5cSJustin T. Gibbs } 1189ff662b5cSJustin T. Gibbs 119033eebb6aSJustin T. Gibbs error = xs_printf(XST_NIL, node_path, "protocol", 119133eebb6aSJustin T. Gibbs "%s", XEN_IO_PROTO_ABI_NATIVE); 1192ff662b5cSJustin T. Gibbs if (error) { 119333eebb6aSJustin T. Gibbs xenbus_dev_fatal(sc->xbd_dev, error, 1194ff662b5cSJustin T. Gibbs "writing %s/protocol", 1195ff662b5cSJustin T. Gibbs node_path); 1196ff662b5cSJustin T. Gibbs return; 119723dc5621SKip Macy } 119812678024SDoug Rabson 119933eebb6aSJustin T. Gibbs xenbus_set_state(sc->xbd_dev, XenbusStateInitialised); 120089e0f4d2SKip Macy } 120189e0f4d2SKip Macy 120289e0f4d2SKip Macy /* 120333eebb6aSJustin T. Gibbs * Invoked when the backend is finally 'ready' (and has published 120433eebb6aSJustin T. Gibbs * the details about the physical device - #sectors, size, etc). 120589e0f4d2SKip Macy */ 120689e0f4d2SKip Macy static void 120733eebb6aSJustin T. Gibbs xbd_connect(struct xbd_softc *sc) 120889e0f4d2SKip Macy { 120933eebb6aSJustin T. Gibbs device_t dev = sc->xbd_dev; 121089e0f4d2SKip Macy unsigned long sectors, sector_size; 121189e0f4d2SKip Macy unsigned int binfo; 12129985113bSJustin T. Gibbs int err, feature_barrier, feature_flush; 121389e0f4d2SKip Macy 1214e2c1fe90SJustin T. Gibbs if (sc->xbd_state == XBD_STATE_CONNECTED || 1215e2c1fe90SJustin T. Gibbs sc->xbd_state == XBD_STATE_SUSPENDED) 121689e0f4d2SKip Macy return; 121789e0f4d2SKip Macy 121823dc5621SKip Macy DPRINTK("blkfront.c:connect:%s.\n", xenbus_get_otherend_path(dev)); 121989e0f4d2SKip Macy 1220ff662b5cSJustin T. Gibbs err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev), 122189e0f4d2SKip Macy "sectors", "%lu", §ors, 122289e0f4d2SKip Macy "info", "%u", &binfo, 122389e0f4d2SKip Macy "sector-size", "%lu", §or_size, 122489e0f4d2SKip Macy NULL); 122589e0f4d2SKip Macy if (err) { 122623dc5621SKip Macy xenbus_dev_fatal(dev, err, 122789e0f4d2SKip Macy "reading backend fields at %s", 122823dc5621SKip Macy xenbus_get_otherend_path(dev)); 122989e0f4d2SKip Macy return; 123089e0f4d2SKip Macy } 1231ff662b5cSJustin T. Gibbs err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev), 1232e4808c4bSKip Macy "feature-barrier", "%lu", &feature_barrier, 123389e0f4d2SKip Macy NULL); 12349985113bSJustin T. Gibbs if (err == 0 && feature_barrier != 0) 1235e2c1fe90SJustin T. Gibbs sc->xbd_flags |= XBDF_BARRIER; 123689e0f4d2SKip Macy 12379985113bSJustin T. Gibbs err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev), 12389985113bSJustin T. Gibbs "feature-flush-cache", "%lu", &feature_flush, 12399985113bSJustin T. Gibbs NULL); 12409985113bSJustin T. Gibbs if (err == 0 && feature_flush != 0) 12419985113bSJustin T. Gibbs sc->xbd_flags |= XBDF_FLUSH; 12429985113bSJustin T. Gibbs 124333eebb6aSJustin T. Gibbs if (sc->xbd_disk == NULL) { 124423dc5621SKip Macy device_printf(dev, "%juMB <%s> at %s", 124523dc5621SKip Macy (uintmax_t) sectors / (1048576 / sector_size), 124623dc5621SKip Macy device_get_desc(dev), 124723dc5621SKip Macy xenbus_get_node(dev)); 124823dc5621SKip Macy bus_print_child_footer(device_get_parent(dev), dev); 124989e0f4d2SKip Macy 125033eebb6aSJustin T. Gibbs xbd_instance_create(sc, sectors, sc->xbd_vdevice, binfo, 125133eebb6aSJustin T. Gibbs sector_size); 125206a630f6SJustin T. Gibbs } 125323dc5621SKip Macy 125423dc5621SKip Macy (void)xenbus_set_state(dev, XenbusStateConnected); 125589e0f4d2SKip Macy 125689e0f4d2SKip Macy /* Kick pending requests. */ 125733eebb6aSJustin T. Gibbs mtx_lock(&sc->xbd_io_lock); 1258e2c1fe90SJustin T. Gibbs sc->xbd_state = XBD_STATE_CONNECTED; 125933eebb6aSJustin T. Gibbs xbd_startio(sc); 1260e2c1fe90SJustin T. Gibbs sc->xbd_flags |= XBDF_READY; 126133eebb6aSJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 126289e0f4d2SKip Macy } 126389e0f4d2SKip Macy 126489e0f4d2SKip Macy /** 126589e0f4d2SKip Macy * Handle the change of state of the backend to Closing. We must delete our 126689e0f4d2SKip Macy * device-layer structures now, to ensure that writes are flushed through to 1267a4660d59SJustin T. Gibbs * the backend. Once this is done, we can switch to Closed in 126889e0f4d2SKip Macy * acknowledgement. 126989e0f4d2SKip Macy */ 127023dc5621SKip Macy static void 127133eebb6aSJustin T. Gibbs xbd_closing(device_t dev) 127289e0f4d2SKip Macy { 127333eebb6aSJustin T. Gibbs struct xbd_softc *sc = device_get_softc(dev); 127489e0f4d2SKip Macy 1275ff662b5cSJustin T. Gibbs xenbus_set_state(dev, XenbusStateClosing); 1276ff662b5cSJustin T. Gibbs 127733eebb6aSJustin T. Gibbs DPRINTK("xbd_closing: %s removed\n", xenbus_get_node(dev)); 127889e0f4d2SKip Macy 127933eebb6aSJustin T. Gibbs if (sc->xbd_disk != NULL) { 128033eebb6aSJustin T. Gibbs disk_destroy(sc->xbd_disk); 128133eebb6aSJustin T. Gibbs sc->xbd_disk = NULL; 128289e0f4d2SKip Macy } 128389e0f4d2SKip Macy 128423dc5621SKip Macy xenbus_set_state(dev, XenbusStateClosed); 128589e0f4d2SKip Macy } 128689e0f4d2SKip Macy 1287fac3fd80SJustin T. Gibbs /*---------------------------- NewBus Entrypoints ----------------------------*/ 1288fac3fd80SJustin T. Gibbs static int 1289fac3fd80SJustin T. Gibbs xbd_probe(device_t dev) 1290fac3fd80SJustin T. Gibbs { 1291a371f519SJustin T. Gibbs if (strcmp(xenbus_get_type(dev), "vbd") != 0) 1292a371f519SJustin T. Gibbs return (ENXIO); 1293fac3fd80SJustin T. Gibbs 1294a371f519SJustin T. Gibbs if (xen_hvm_domain()) { 1295a371f519SJustin T. Gibbs int error; 1296a371f519SJustin T. Gibbs char *type; 1297a371f519SJustin T. Gibbs 1298a371f519SJustin T. Gibbs /* 1299a371f519SJustin T. Gibbs * When running in an HVM domain, IDE disk emulation is 1300a371f519SJustin T. Gibbs * disabled early in boot so that native drivers will 1301a371f519SJustin T. Gibbs * not see emulated hardware. However, CDROM device 1302a371f519SJustin T. Gibbs * emulation cannot be disabled. 1303a371f519SJustin T. Gibbs * 1304a371f519SJustin T. Gibbs * Through use of FreeBSD's vm_guest and xen_hvm_domain() 1305a371f519SJustin T. Gibbs * APIs, we could modify the native CDROM driver to fail its 1306a371f519SJustin T. Gibbs * probe when running under Xen. Unfortunatlely, the PV 1307a371f519SJustin T. Gibbs * CDROM support in XenServer (up through at least version 1308a371f519SJustin T. Gibbs * 6.2) isn't functional, so we instead rely on the emulated 1309a371f519SJustin T. Gibbs * CDROM instance, and fail to attach the PV one here in 1310a371f519SJustin T. Gibbs * the blkfront driver. 1311a371f519SJustin T. Gibbs */ 1312a371f519SJustin T. Gibbs error = xs_read(XST_NIL, xenbus_get_node(dev), 1313a371f519SJustin T. Gibbs "device-type", NULL, (void **) &type); 1314a371f519SJustin T. Gibbs if (error) 1315a371f519SJustin T. Gibbs return (ENXIO); 1316a371f519SJustin T. Gibbs 1317a371f519SJustin T. Gibbs if (strncmp(type, "cdrom", 5) == 0) { 1318a371f519SJustin T. Gibbs free(type, M_XENSTORE); 1319a371f519SJustin T. Gibbs return (ENXIO); 1320a371f519SJustin T. Gibbs } 1321a371f519SJustin T. Gibbs free(type, M_XENSTORE); 1322a371f519SJustin T. Gibbs } 1323a371f519SJustin T. Gibbs 1324fac3fd80SJustin T. Gibbs device_set_desc(dev, "Virtual Block Device"); 1325fac3fd80SJustin T. Gibbs device_quiet(dev); 1326fac3fd80SJustin T. Gibbs return (0); 1327fac3fd80SJustin T. Gibbs } 1328fac3fd80SJustin T. Gibbs 1329fac3fd80SJustin T. Gibbs /* 1330fac3fd80SJustin T. Gibbs * Setup supplies the backend dir, virtual device. We place an event 1331fac3fd80SJustin T. Gibbs * channel and shared frame entries. We watch backend to wait if it's 1332fac3fd80SJustin T. Gibbs * ok. 1333fac3fd80SJustin T. Gibbs */ 1334fac3fd80SJustin T. Gibbs static int 1335fac3fd80SJustin T. Gibbs xbd_attach(device_t dev) 1336fac3fd80SJustin T. Gibbs { 1337fac3fd80SJustin T. Gibbs struct xbd_softc *sc; 1338fac3fd80SJustin T. Gibbs const char *name; 1339fac3fd80SJustin T. Gibbs uint32_t vdevice; 1340fac3fd80SJustin T. Gibbs int error; 1341fac3fd80SJustin T. Gibbs int i; 1342fac3fd80SJustin T. Gibbs int unit; 1343fac3fd80SJustin T. Gibbs 1344fac3fd80SJustin T. Gibbs /* FIXME: Use dynamic device id if this is not set. */ 1345fac3fd80SJustin T. Gibbs error = xs_scanf(XST_NIL, xenbus_get_node(dev), 1346fac3fd80SJustin T. Gibbs "virtual-device", NULL, "%" PRIu32, &vdevice); 134748a1ceedSColin Percival if (error) 134848a1ceedSColin Percival error = xs_scanf(XST_NIL, xenbus_get_node(dev), 134948a1ceedSColin Percival "virtual-device-ext", NULL, "%" PRIu32, &vdevice); 1350fac3fd80SJustin T. Gibbs if (error) { 1351fac3fd80SJustin T. Gibbs xenbus_dev_fatal(dev, error, "reading virtual-device"); 1352fac3fd80SJustin T. Gibbs device_printf(dev, "Couldn't determine virtual device.\n"); 1353fac3fd80SJustin T. Gibbs return (error); 1354fac3fd80SJustin T. Gibbs } 1355fac3fd80SJustin T. Gibbs 1356fac3fd80SJustin T. Gibbs xbd_vdevice_to_unit(vdevice, &unit, &name); 1357fac3fd80SJustin T. Gibbs if (!strcmp(name, "xbd")) 1358fac3fd80SJustin T. Gibbs device_set_unit(dev, unit); 1359fac3fd80SJustin T. Gibbs 1360fac3fd80SJustin T. Gibbs sc = device_get_softc(dev); 1361fac3fd80SJustin T. Gibbs mtx_init(&sc->xbd_io_lock, "blkfront i/o lock", NULL, MTX_DEF); 1362e2c1fe90SJustin T. Gibbs xbd_initqs(sc); 1363fac3fd80SJustin T. Gibbs for (i = 0; i < XBD_MAX_RING_PAGES; i++) 1364d9fab01dSJustin T. Gibbs sc->xbd_ring_ref[i] = GRANT_REF_INVALID; 1365fac3fd80SJustin T. Gibbs 1366fac3fd80SJustin T. Gibbs sc->xbd_dev = dev; 1367fac3fd80SJustin T. Gibbs sc->xbd_vdevice = vdevice; 1368e2c1fe90SJustin T. Gibbs sc->xbd_state = XBD_STATE_DISCONNECTED; 1369fac3fd80SJustin T. Gibbs 1370fac3fd80SJustin T. Gibbs xbd_setup_sysctl(sc); 1371fac3fd80SJustin T. Gibbs 1372fac3fd80SJustin T. Gibbs /* Wait for backend device to publish its protocol capabilities. */ 1373fac3fd80SJustin T. Gibbs xenbus_set_state(dev, XenbusStateInitialising); 1374fac3fd80SJustin T. Gibbs 1375fac3fd80SJustin T. Gibbs return (0); 1376fac3fd80SJustin T. Gibbs } 137789e0f4d2SKip Macy 137823dc5621SKip Macy static int 137933eebb6aSJustin T. Gibbs xbd_detach(device_t dev) 138089e0f4d2SKip Macy { 138133eebb6aSJustin T. Gibbs struct xbd_softc *sc = device_get_softc(dev); 138289e0f4d2SKip Macy 1383e2c1fe90SJustin T. Gibbs DPRINTK("%s: %s removed\n", __func__, xenbus_get_node(dev)); 138489e0f4d2SKip Macy 138533eebb6aSJustin T. Gibbs xbd_free(sc); 138633eebb6aSJustin T. Gibbs mtx_destroy(&sc->xbd_io_lock); 138789e0f4d2SKip Macy 138889e0f4d2SKip Macy return 0; 138989e0f4d2SKip Macy } 139089e0f4d2SKip Macy 139189e0f4d2SKip Macy static int 1392fac3fd80SJustin T. Gibbs xbd_suspend(device_t dev) 139389e0f4d2SKip Macy { 1394fac3fd80SJustin T. Gibbs struct xbd_softc *sc = device_get_softc(dev); 1395fac3fd80SJustin T. Gibbs int retval; 1396fac3fd80SJustin T. Gibbs int saved_state; 139789e0f4d2SKip Macy 139889e0f4d2SKip Macy /* Prevent new requests being issued until we fix things up. */ 139933eebb6aSJustin T. Gibbs mtx_lock(&sc->xbd_io_lock); 1400e2c1fe90SJustin T. Gibbs saved_state = sc->xbd_state; 1401e2c1fe90SJustin T. Gibbs sc->xbd_state = XBD_STATE_SUSPENDED; 1402fac3fd80SJustin T. Gibbs 1403fac3fd80SJustin T. Gibbs /* Wait for outstanding I/O to drain. */ 1404fac3fd80SJustin T. Gibbs retval = 0; 14059985113bSJustin T. Gibbs while (xbd_queue_length(sc, XBD_Q_BUSY) != 0) { 1406e2c1fe90SJustin T. Gibbs if (msleep(&sc->xbd_cm_q[XBD_Q_BUSY], &sc->xbd_io_lock, 1407fac3fd80SJustin T. Gibbs PRIBIO, "blkf_susp", 30 * hz) == EWOULDBLOCK) { 1408fac3fd80SJustin T. Gibbs retval = EBUSY; 1409fac3fd80SJustin T. Gibbs break; 1410fac3fd80SJustin T. Gibbs } 1411fac3fd80SJustin T. Gibbs } 141233eebb6aSJustin T. Gibbs mtx_unlock(&sc->xbd_io_lock); 141389e0f4d2SKip Macy 1414fac3fd80SJustin T. Gibbs if (retval != 0) 1415e2c1fe90SJustin T. Gibbs sc->xbd_state = saved_state; 141633eebb6aSJustin T. Gibbs 1417fac3fd80SJustin T. Gibbs return (retval); 141889e0f4d2SKip Macy } 141989e0f4d2SKip Macy 1420ff662b5cSJustin T. Gibbs static int 1421fac3fd80SJustin T. Gibbs xbd_resume(device_t dev) 142289e0f4d2SKip Macy { 1423fac3fd80SJustin T. Gibbs struct xbd_softc *sc = device_get_softc(dev); 1424fac3fd80SJustin T. Gibbs 1425fac3fd80SJustin T. Gibbs DPRINTK("xbd_resume: %s\n", xenbus_get_node(dev)); 1426fac3fd80SJustin T. Gibbs 1427fac3fd80SJustin T. Gibbs xbd_free(sc); 1428fac3fd80SJustin T. Gibbs xbd_initialize(sc); 1429fac3fd80SJustin T. Gibbs return (0); 143089e0f4d2SKip Macy } 143189e0f4d2SKip Macy 1432fac3fd80SJustin T. Gibbs /** 1433fac3fd80SJustin T. Gibbs * Callback received when the backend's state changes. 1434fac3fd80SJustin T. Gibbs */ 1435fac3fd80SJustin T. Gibbs static void 1436fac3fd80SJustin T. Gibbs xbd_backend_changed(device_t dev, XenbusState backend_state) 1437fac3fd80SJustin T. Gibbs { 1438fac3fd80SJustin T. Gibbs struct xbd_softc *sc = device_get_softc(dev); 1439fac3fd80SJustin T. Gibbs 1440fac3fd80SJustin T. Gibbs DPRINTK("backend_state=%d\n", backend_state); 1441fac3fd80SJustin T. Gibbs 1442fac3fd80SJustin T. Gibbs switch (backend_state) { 1443fac3fd80SJustin T. Gibbs case XenbusStateUnknown: 1444fac3fd80SJustin T. Gibbs case XenbusStateInitialising: 1445fac3fd80SJustin T. Gibbs case XenbusStateReconfigured: 1446fac3fd80SJustin T. Gibbs case XenbusStateReconfiguring: 1447fac3fd80SJustin T. Gibbs case XenbusStateClosed: 1448fac3fd80SJustin T. Gibbs break; 1449fac3fd80SJustin T. Gibbs 1450fac3fd80SJustin T. Gibbs case XenbusStateInitWait: 1451fac3fd80SJustin T. Gibbs case XenbusStateInitialised: 1452fac3fd80SJustin T. Gibbs xbd_initialize(sc); 1453fac3fd80SJustin T. Gibbs break; 1454fac3fd80SJustin T. Gibbs 1455fac3fd80SJustin T. Gibbs case XenbusStateConnected: 1456fac3fd80SJustin T. Gibbs xbd_initialize(sc); 1457fac3fd80SJustin T. Gibbs xbd_connect(sc); 1458fac3fd80SJustin T. Gibbs break; 1459fac3fd80SJustin T. Gibbs 1460fac3fd80SJustin T. Gibbs case XenbusStateClosing: 1461fac3fd80SJustin T. Gibbs if (sc->xbd_users > 0) 1462fac3fd80SJustin T. Gibbs xenbus_dev_error(dev, -EBUSY, 1463fac3fd80SJustin T. Gibbs "Device in use; refusing to close"); 1464fac3fd80SJustin T. Gibbs else 1465fac3fd80SJustin T. Gibbs xbd_closing(dev); 1466fac3fd80SJustin T. Gibbs break; 1467fac3fd80SJustin T. Gibbs } 1468fac3fd80SJustin T. Gibbs } 1469fac3fd80SJustin T. Gibbs 1470fac3fd80SJustin T. Gibbs /*---------------------------- NewBus Registration ---------------------------*/ 147133eebb6aSJustin T. Gibbs static device_method_t xbd_methods[] = { 147223dc5621SKip Macy /* Device interface */ 147333eebb6aSJustin T. Gibbs DEVMETHOD(device_probe, xbd_probe), 147433eebb6aSJustin T. Gibbs DEVMETHOD(device_attach, xbd_attach), 147533eebb6aSJustin T. Gibbs DEVMETHOD(device_detach, xbd_detach), 147623dc5621SKip Macy DEVMETHOD(device_shutdown, bus_generic_shutdown), 147733eebb6aSJustin T. Gibbs DEVMETHOD(device_suspend, xbd_suspend), 147833eebb6aSJustin T. Gibbs DEVMETHOD(device_resume, xbd_resume), 147989e0f4d2SKip Macy 148023dc5621SKip Macy /* Xenbus interface */ 148133eebb6aSJustin T. Gibbs DEVMETHOD(xenbus_otherend_changed, xbd_backend_changed), 148289e0f4d2SKip Macy 148323dc5621SKip Macy { 0, 0 } 148489e0f4d2SKip Macy }; 148589e0f4d2SKip Macy 148633eebb6aSJustin T. Gibbs static driver_t xbd_driver = { 148723dc5621SKip Macy "xbd", 148833eebb6aSJustin T. Gibbs xbd_methods, 148933eebb6aSJustin T. Gibbs sizeof(struct xbd_softc), 149089e0f4d2SKip Macy }; 149133eebb6aSJustin T. Gibbs devclass_t xbd_devclass; 149289e0f4d2SKip Macy 149333eebb6aSJustin T. Gibbs DRIVER_MODULE(xbd, xenbusb_front, xbd_driver, xbd_devclass, 0, 0); 1494