1181643Skmacy/* 2196661Skmacy * XenBSD block device driver 3196661Skmacy * 4251195Sgibbs * Copyright (c) 2010-2013 Spectra Logic Corporation 5199960Skmacy * Copyright (c) 2009 Scott Long, Yahoo! 6196661Skmacy * Copyright (c) 2009 Frank Suchomel, Citrix 7199959Skmacy * Copyright (c) 2009 Doug F. Rabson, Citrix 8199959Skmacy * Copyright (c) 2005 Kip Macy 9199959Skmacy * Copyright (c) 2003-2004, Keir Fraser & Steve Hand 10199959Skmacy * Modifications by Mark A. Williamson are (c) Intel Research Cambridge 11199959Skmacy * 12199959Skmacy * 13199959Skmacy * Permission is hereby granted, free of charge, to any person obtaining a copy 14199959Skmacy * of this software and associated documentation files (the "Software"), to 15199959Skmacy * deal in the Software without restriction, including without limitation the 16199959Skmacy * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 17199959Skmacy * sell copies of the Software, and to permit persons to whom the Software is 18199959Skmacy * furnished to do so, subject to the following conditions: 19199959Skmacy * 20199959Skmacy * The above copyright notice and this permission notice shall be included in 21199959Skmacy * all copies or substantial portions of the Software. 22199959Skmacy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23199959Skmacy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24199959Skmacy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25199959Skmacy * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26199959Skmacy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27199959Skmacy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28199959Skmacy * DEALINGS IN THE SOFTWARE. 29181643Skmacy */ 30181643Skmacy 31181643Skmacy#include <sys/cdefs.h> 32181643Skmacy__FBSDID("$FreeBSD: releng/10.2/sys/dev/xen/blkfront/blkfront.c 285738 2015-07-21 07:22:18Z royger $"); 33181643Skmacy 34181643Skmacy#include <sys/param.h> 35181643Skmacy#include <sys/systm.h> 36181643Skmacy#include <sys/malloc.h> 37181643Skmacy#include <sys/kernel.h> 38181643Skmacy#include <vm/vm.h> 39181643Skmacy#include <vm/pmap.h> 40181643Skmacy 41181643Skmacy#include <sys/bio.h> 42181643Skmacy#include <sys/bus.h> 43181643Skmacy#include <sys/conf.h> 44181643Skmacy#include <sys/module.h> 45231743Sgibbs#include <sys/sysctl.h> 46181643Skmacy 47181643Skmacy#include <machine/bus.h> 48181643Skmacy#include <sys/rman.h> 49181643Skmacy#include <machine/resource.h> 50181643Skmacy#include <machine/intr_machdep.h> 51181643Skmacy#include <machine/vmparam.h> 52199960Skmacy#include <sys/bus_dma.h> 53181643Skmacy 54255040Sgibbs#include <xen/xen-os.h> 55186557Skmacy#include <xen/hypervisor.h> 56186557Skmacy#include <xen/xen_intr.h> 57189699Sdfr#include <xen/gnttab.h> 58181643Skmacy#include <xen/interface/grant_table.h> 59185605Skmacy#include <xen/interface/io/protocols.h> 60185605Skmacy#include <xen/xenbus/xenbusvar.h> 61181643Skmacy 62255040Sgibbs#include <machine/_inttypes.h> 63255040Sgibbs#include <machine/xen/xenvar.h> 64255040Sgibbs 65181643Skmacy#include <geom/geom_disk.h> 66181643Skmacy 67181643Skmacy#include <dev/xen/blkfront/block.h> 68181643Skmacy 69185605Skmacy#include "xenbus_if.h" 70185605Skmacy 71251204Sgibbs/*--------------------------- Forward Declarations ---------------------------*/ 72251204Sgibbsstatic void xbd_closing(device_t); 73251195Sgibbsstatic void xbd_startio(struct xbd_softc *sc); 74181643Skmacy 75251204Sgibbs/*---------------------------------- Macros ----------------------------------*/ 76251204Sgibbs#if 0 77251204Sgibbs#define DPRINTK(fmt, args...) printf("[XEN] %s:%d: " fmt ".\n", __func__, __LINE__, ##args) 78251204Sgibbs#else 79251204Sgibbs#define DPRINTK(fmt, args...) 80251204Sgibbs#endif 81214077Sgibbs 82251204Sgibbs#define XBD_SECTOR_SHFT 9 83251204Sgibbs 84251204Sgibbs/*---------------------------- Global Static Data ----------------------------*/ 85251204Sgibbsstatic MALLOC_DEFINE(M_XENBLOCKFRONT, "xbd", "Xen Block Front driver data"); 86181643Skmacy 87251204Sgibbs/*---------------------------- Command Processing ----------------------------*/ 88251772Sgibbsstatic void 89251772Sgibbsxbd_freeze(struct xbd_softc *sc, xbd_flag_t xbd_flag) 90251772Sgibbs{ 91251772Sgibbs if (xbd_flag != XBDF_NONE && (sc->xbd_flags & xbd_flag) != 0) 92251772Sgibbs return; 93251772Sgibbs 94251772Sgibbs sc->xbd_flags |= xbd_flag; 95251772Sgibbs sc->xbd_qfrozen_cnt++; 96251772Sgibbs} 97251772Sgibbs 98251772Sgibbsstatic void 99251772Sgibbsxbd_thaw(struct xbd_softc *sc, xbd_flag_t xbd_flag) 100251772Sgibbs{ 101251772Sgibbs if (xbd_flag != XBDF_NONE && (sc->xbd_flags & xbd_flag) == 0) 102251772Sgibbs return; 103251772Sgibbs 104251807Sgibbs if (sc->xbd_qfrozen_cnt == 0) 105251772Sgibbs panic("%s: Thaw with flag 0x%x while not frozen.", 106251772Sgibbs __func__, xbd_flag); 107251772Sgibbs 108251772Sgibbs sc->xbd_flags &= ~xbd_flag; 109251772Sgibbs sc->xbd_qfrozen_cnt--; 110251772Sgibbs} 111251772Sgibbs 112252260Sgibbsstatic void 113252260Sgibbsxbd_cm_freeze(struct xbd_softc *sc, struct xbd_command *cm, xbdc_flag_t cm_flag) 114252260Sgibbs{ 115252260Sgibbs if ((cm->cm_flags & XBDCF_FROZEN) != 0) 116252260Sgibbs return; 117252260Sgibbs 118252260Sgibbs cm->cm_flags |= XBDCF_FROZEN|cm_flag; 119252260Sgibbs xbd_freeze(sc, XBDF_NONE); 120252260Sgibbs} 121252260Sgibbs 122252260Sgibbsstatic void 123252260Sgibbsxbd_cm_thaw(struct xbd_softc *sc, struct xbd_command *cm) 124252260Sgibbs{ 125252260Sgibbs if ((cm->cm_flags & XBDCF_FROZEN) == 0) 126252260Sgibbs return; 127252260Sgibbs 128252260Sgibbs cm->cm_flags &= ~XBDCF_FROZEN; 129252260Sgibbs xbd_thaw(sc, XBDF_NONE); 130252260Sgibbs} 131252260Sgibbs 132251204Sgibbsstatic inline void 133251206Sgibbsxbd_flush_requests(struct xbd_softc *sc) 134251204Sgibbs{ 135251204Sgibbs int notify; 136199960Skmacy 137251204Sgibbs RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->xbd_ring, notify); 138181643Skmacy 139251204Sgibbs if (notify) 140255040Sgibbs xen_intr_signal(sc->xen_intr_handle); 141251204Sgibbs} 142181643Skmacy 143251204Sgibbsstatic void 144251204Sgibbsxbd_free_command(struct xbd_command *cm) 145251204Sgibbs{ 146181643Skmacy 147251751Sgibbs KASSERT((cm->cm_flags & XBDCF_Q_MASK) == XBD_Q_NONE, 148251751Sgibbs ("Freeing command that is still on queue %d.", 149251751Sgibbs cm->cm_flags & XBDCF_Q_MASK)); 150181643Skmacy 151251751Sgibbs cm->cm_flags = XBDCF_INITIALIZER; 152251204Sgibbs cm->cm_bp = NULL; 153251204Sgibbs cm->cm_complete = NULL; 154251751Sgibbs xbd_enqueue_cm(cm, XBD_Q_FREE); 155251772Sgibbs xbd_thaw(cm->cm_sc, XBDF_CM_SHORTAGE); 156251204Sgibbs} 157181643Skmacy 158185605Skmacystatic void 159251204Sgibbsxbd_queue_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 160185605Skmacy{ 161251204Sgibbs struct xbd_softc *sc; 162251204Sgibbs struct xbd_command *cm; 163251204Sgibbs blkif_request_t *ring_req; 164251204Sgibbs struct blkif_request_segment *sg; 165251204Sgibbs struct blkif_request_segment *last_block_sg; 166251204Sgibbs grant_ref_t *sg_ref; 167251204Sgibbs vm_paddr_t buffer_ma; 168251204Sgibbs uint64_t fsect, lsect; 169251204Sgibbs int ref; 170251204Sgibbs int op; 171251204Sgibbs int block_segs; 172185605Skmacy 173251204Sgibbs cm = arg; 174251204Sgibbs sc = cm->cm_sc; 175185605Skmacy 176251204Sgibbs if (error) { 177251204Sgibbs cm->cm_bp->bio_error = EIO; 178251204Sgibbs biodone(cm->cm_bp); 179251204Sgibbs xbd_free_command(cm); 180231743Sgibbs return; 181185605Skmacy } 182185605Skmacy 183251204Sgibbs /* Fill out a communications ring structure. */ 184251204Sgibbs ring_req = RING_GET_REQUEST(&sc->xbd_ring, sc->xbd_ring.req_prod_pvt); 185251204Sgibbs sc->xbd_ring.req_prod_pvt++; 186251204Sgibbs ring_req->id = cm->cm_id; 187251204Sgibbs ring_req->operation = cm->cm_operation; 188251204Sgibbs ring_req->sector_number = cm->cm_sector_number; 189251204Sgibbs ring_req->handle = (blkif_vdev_t)(uintptr_t)sc->xbd_disk; 190251204Sgibbs ring_req->nr_segments = nsegs; 191251204Sgibbs cm->cm_nseg = nsegs; 192251204Sgibbs 193285738Sroyger block_segs = MIN(nsegs, BLKIF_MAX_SEGMENTS_PER_REQUEST); 194251204Sgibbs sg = ring_req->seg; 195251204Sgibbs last_block_sg = sg + block_segs; 196251204Sgibbs sg_ref = cm->cm_sg_refs; 197251204Sgibbs 198285738Sroyger while (sg < last_block_sg) { 199285738Sroyger buffer_ma = segs->ds_addr; 200285738Sroyger fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT; 201285738Sroyger lsect = fsect + (segs->ds_len >> XBD_SECTOR_SHFT) - 1; 202251204Sgibbs 203285738Sroyger KASSERT(lsect <= 7, ("XEN disk driver data cannot " 204285738Sroyger "cross a page boundary")); 205251204Sgibbs 206285738Sroyger /* install a grant reference. */ 207285738Sroyger ref = gnttab_claim_grant_reference(&cm->cm_gref_head); 208251204Sgibbs 209285738Sroyger /* 210285738Sroyger * GNTTAB_LIST_END == 0xffffffff, but it is private 211285738Sroyger * to gnttab.c. 212285738Sroyger */ 213285738Sroyger KASSERT(ref != ~0, ("grant_reference failed")); 214251204Sgibbs 215285738Sroyger gnttab_grant_foreign_access_ref( 216285738Sroyger ref, 217285738Sroyger xenbus_get_otherend_id(sc->xbd_dev), 218285738Sroyger buffer_ma >> PAGE_SHIFT, 219285738Sroyger ring_req->operation == BLKIF_OP_WRITE); 220251204Sgibbs 221285738Sroyger *sg_ref = ref; 222285738Sroyger *sg = (struct blkif_request_segment) { 223285738Sroyger .gref = ref, 224285738Sroyger .first_sect = fsect, 225285738Sroyger .last_sect = lsect 226285738Sroyger }; 227285738Sroyger sg++; 228285738Sroyger sg_ref++; 229285738Sroyger segs++; 230285738Sroyger nsegs--; 231185605Skmacy } 232185605Skmacy 233251204Sgibbs if (cm->cm_operation == BLKIF_OP_READ) 234251204Sgibbs op = BUS_DMASYNC_PREREAD; 235251204Sgibbs else if (cm->cm_operation == BLKIF_OP_WRITE) 236251204Sgibbs op = BUS_DMASYNC_PREWRITE; 237251204Sgibbs else 238251204Sgibbs op = 0; 239251204Sgibbs bus_dmamap_sync(sc->xbd_io_dmat, cm->cm_map, op); 240251204Sgibbs 241251204Sgibbs gnttab_free_grant_references(cm->cm_gref_head); 242251204Sgibbs 243251751Sgibbs xbd_enqueue_cm(cm, XBD_Q_BUSY); 244251204Sgibbs 245251204Sgibbs /* 246251772Sgibbs * If bus dma had to asynchronously call us back to dispatch 247251772Sgibbs * this command, we are no longer executing in the context of 248251772Sgibbs * xbd_startio(). Thus we cannot rely on xbd_startio()'s call to 249251772Sgibbs * xbd_flush_requests() to publish this command to the backend 250251772Sgibbs * along with any other commands that it could batch. 251251204Sgibbs */ 252251772Sgibbs if ((cm->cm_flags & XBDCF_ASYNC_MAPPING) != 0) 253251206Sgibbs xbd_flush_requests(sc); 254251204Sgibbs 255251204Sgibbs return; 256185605Skmacy} 257185605Skmacy 258251204Sgibbsstatic int 259251204Sgibbsxbd_queue_request(struct xbd_softc *sc, struct xbd_command *cm) 260181643Skmacy{ 261251204Sgibbs int error; 262186557Skmacy 263271611Sroyger error = bus_dmamap_load(sc->xbd_io_dmat, cm->cm_map, cm->cm_data, 264271611Sroyger cm->cm_datalen, xbd_queue_cb, cm, 0); 265251204Sgibbs if (error == EINPROGRESS) { 266251772Sgibbs /* 267251772Sgibbs * Maintain queuing order by freezing the queue. The next 268251772Sgibbs * command may not require as many resources as the command 269251772Sgibbs * we just attempted to map, so we can't rely on bus dma 270251772Sgibbs * blocking for it too. 271251772Sgibbs */ 272252260Sgibbs xbd_cm_freeze(sc, cm, XBDCF_ASYNC_MAPPING); 273251204Sgibbs return (0); 274251204Sgibbs } 275182082Skmacy 276251204Sgibbs return (error); 277251204Sgibbs} 278181643Skmacy 279251204Sgibbsstatic void 280251204Sgibbsxbd_restart_queue_callback(void *arg) 281251204Sgibbs{ 282251204Sgibbs struct xbd_softc *sc = arg; 283185605Skmacy 284251204Sgibbs mtx_lock(&sc->xbd_io_lock); 285181643Skmacy 286251772Sgibbs xbd_thaw(sc, XBDF_GNT_SHORTAGE); 287251772Sgibbs 288251204Sgibbs xbd_startio(sc); 289181643Skmacy 290251204Sgibbs mtx_unlock(&sc->xbd_io_lock); 291181643Skmacy} 292181643Skmacy 293251204Sgibbsstatic struct xbd_command * 294251204Sgibbsxbd_bio_command(struct xbd_softc *sc) 295251204Sgibbs{ 296251204Sgibbs struct xbd_command *cm; 297251204Sgibbs struct bio *bp; 298181643Skmacy 299255040Sgibbs if (__predict_false(sc->xbd_state != XBD_STATE_CONNECTED)) 300251204Sgibbs return (NULL); 301251204Sgibbs 302251204Sgibbs bp = xbd_dequeue_bio(sc); 303251204Sgibbs if (bp == NULL) 304251204Sgibbs return (NULL); 305251204Sgibbs 306251751Sgibbs if ((cm = xbd_dequeue_cm(sc, XBD_Q_FREE)) == NULL) { 307251772Sgibbs xbd_freeze(sc, XBDF_CM_SHORTAGE); 308251204Sgibbs xbd_requeue_bio(sc, bp); 309251204Sgibbs return (NULL); 310251204Sgibbs } 311251204Sgibbs 312251204Sgibbs if (gnttab_alloc_grant_references(sc->xbd_max_request_segments, 313251204Sgibbs &cm->cm_gref_head) != 0) { 314251204Sgibbs gnttab_request_free_callback(&sc->xbd_callback, 315251204Sgibbs xbd_restart_queue_callback, sc, 316251204Sgibbs sc->xbd_max_request_segments); 317251772Sgibbs xbd_freeze(sc, XBDF_GNT_SHORTAGE); 318251204Sgibbs xbd_requeue_bio(sc, bp); 319251751Sgibbs xbd_enqueue_cm(cm, XBD_Q_FREE); 320251204Sgibbs return (NULL); 321251204Sgibbs } 322251204Sgibbs 323251204Sgibbs cm->cm_bp = bp; 324271611Sroyger cm->cm_data = bp->bio_data; 325271611Sroyger cm->cm_datalen = bp->bio_bcount; 326251204Sgibbs cm->cm_sector_number = (blkif_sector_t)bp->bio_pblkno; 327251204Sgibbs 328252260Sgibbs switch (bp->bio_cmd) { 329252260Sgibbs case BIO_READ: 330252260Sgibbs cm->cm_operation = BLKIF_OP_READ; 331252260Sgibbs break; 332252260Sgibbs case BIO_WRITE: 333252260Sgibbs cm->cm_operation = BLKIF_OP_WRITE; 334252260Sgibbs if ((bp->bio_flags & BIO_ORDERED) != 0) { 335252260Sgibbs if ((sc->xbd_flags & XBDF_BARRIER) != 0) { 336252260Sgibbs cm->cm_operation = BLKIF_OP_WRITE_BARRIER; 337252260Sgibbs } else { 338252260Sgibbs /* 339252260Sgibbs * Single step this command. 340252260Sgibbs */ 341252260Sgibbs cm->cm_flags |= XBDCF_Q_FREEZE; 342252260Sgibbs if (xbd_queue_length(sc, XBD_Q_BUSY) != 0) { 343252260Sgibbs /* 344252260Sgibbs * Wait for in-flight requests to 345252260Sgibbs * finish. 346252260Sgibbs */ 347252260Sgibbs xbd_freeze(sc, XBDF_WAIT_IDLE); 348252260Sgibbs xbd_requeue_cm(cm, XBD_Q_READY); 349252260Sgibbs return (NULL); 350252260Sgibbs } 351252260Sgibbs } 352252260Sgibbs } 353252260Sgibbs break; 354252260Sgibbs case BIO_FLUSH: 355252260Sgibbs if ((sc->xbd_flags & XBDF_FLUSH) != 0) 356252260Sgibbs cm->cm_operation = BLKIF_OP_FLUSH_DISKCACHE; 357252260Sgibbs else if ((sc->xbd_flags & XBDF_BARRIER) != 0) 358252260Sgibbs cm->cm_operation = BLKIF_OP_WRITE_BARRIER; 359252260Sgibbs else 360252260Sgibbs panic("flush request, but no flush support available"); 361252260Sgibbs break; 362252260Sgibbs default: 363252260Sgibbs panic("unknown bio command %d", bp->bio_cmd); 364252260Sgibbs } 365252260Sgibbs 366251204Sgibbs return (cm); 367251204Sgibbs} 368251204Sgibbs 369181643Skmacy/* 370251204Sgibbs * Dequeue buffers and place them in the shared communication ring. 371251204Sgibbs * Return when no more requests can be accepted or all buffers have 372251204Sgibbs * been queued. 373251204Sgibbs * 374251204Sgibbs * Signal XEN once the ring has been filled out. 375181643Skmacy */ 376181643Skmacystatic void 377251204Sgibbsxbd_startio(struct xbd_softc *sc) 378181643Skmacy{ 379251204Sgibbs struct xbd_command *cm; 380251204Sgibbs int error, queued = 0; 381181643Skmacy 382251204Sgibbs mtx_assert(&sc->xbd_io_lock, MA_OWNED); 383251204Sgibbs 384251751Sgibbs if (sc->xbd_state != XBD_STATE_CONNECTED) 385199960Skmacy return; 386181643Skmacy 387285738Sroyger while (!RING_FULL(&sc->xbd_ring)) { 388285738Sroyger 389251772Sgibbs if (sc->xbd_qfrozen_cnt != 0) 390251204Sgibbs break; 391196661Skmacy 392251751Sgibbs cm = xbd_dequeue_cm(sc, XBD_Q_READY); 393181643Skmacy 394251204Sgibbs if (cm == NULL) 395251204Sgibbs cm = xbd_bio_command(sc); 396251204Sgibbs 397251204Sgibbs if (cm == NULL) 398251204Sgibbs break; 399251204Sgibbs 400252260Sgibbs if ((cm->cm_flags & XBDCF_Q_FREEZE) != 0) { 401252260Sgibbs /* 402252260Sgibbs * Single step command. Future work is 403252260Sgibbs * held off until this command completes. 404252260Sgibbs */ 405252260Sgibbs xbd_cm_freeze(sc, cm, XBDCF_Q_FREEZE); 406252260Sgibbs } 407252260Sgibbs 408251204Sgibbs if ((error = xbd_queue_request(sc, cm)) != 0) { 409251204Sgibbs printf("xbd_queue_request returned %d\n", error); 410251204Sgibbs break; 411251204Sgibbs } 412251204Sgibbs queued++; 413251204Sgibbs } 414251204Sgibbs 415251204Sgibbs if (queued != 0) 416251206Sgibbs xbd_flush_requests(sc); 417199960Skmacy} 418181643Skmacy 419199960Skmacystatic void 420251195Sgibbsxbd_bio_complete(struct xbd_softc *sc, struct xbd_command *cm) 421199960Skmacy{ 422199960Skmacy struct bio *bp; 423199960Skmacy 424251195Sgibbs bp = cm->cm_bp; 425199960Skmacy 426255040Sgibbs if (__predict_false(cm->cm_status != BLKIF_RSP_OKAY)) { 427199960Skmacy disk_err(bp, "disk error" , -1, 0); 428251195Sgibbs printf(" status: %x\n", cm->cm_status); 429199960Skmacy bp->bio_flags |= BIO_ERROR; 430199960Skmacy } 431199960Skmacy 432199960Skmacy if (bp->bio_flags & BIO_ERROR) 433199960Skmacy bp->bio_error = EIO; 434199960Skmacy else 435199960Skmacy bp->bio_resid = 0; 436199960Skmacy 437251195Sgibbs xbd_free_command(cm); 438181643Skmacy biodone(bp); 439181643Skmacy} 440181643Skmacy 441196661Skmacystatic void 442251204Sgibbsxbd_int(void *xsc) 443251204Sgibbs{ 444251204Sgibbs struct xbd_softc *sc = xsc; 445251204Sgibbs struct xbd_command *cm; 446251204Sgibbs blkif_response_t *bret; 447251204Sgibbs RING_IDX i, rp; 448251204Sgibbs int op; 449251204Sgibbs 450251204Sgibbs mtx_lock(&sc->xbd_io_lock); 451251204Sgibbs 452255040Sgibbs if (__predict_false(sc->xbd_state == XBD_STATE_DISCONNECTED)) { 453251204Sgibbs mtx_unlock(&sc->xbd_io_lock); 454251204Sgibbs return; 455251204Sgibbs } 456251204Sgibbs 457251204Sgibbs again: 458251204Sgibbs rp = sc->xbd_ring.sring->rsp_prod; 459251204Sgibbs rmb(); /* Ensure we see queued responses up to 'rp'. */ 460251204Sgibbs 461251204Sgibbs for (i = sc->xbd_ring.rsp_cons; i != rp;) { 462251204Sgibbs bret = RING_GET_RESPONSE(&sc->xbd_ring, i); 463251204Sgibbs cm = &sc->xbd_shadow[bret->id]; 464251204Sgibbs 465251751Sgibbs xbd_remove_cm(cm, XBD_Q_BUSY); 466285738Sroyger gnttab_end_foreign_access_references(cm->cm_nseg, 467285738Sroyger cm->cm_sg_refs); 468285738Sroyger i++; 469251204Sgibbs 470251204Sgibbs if (cm->cm_operation == BLKIF_OP_READ) 471251204Sgibbs op = BUS_DMASYNC_POSTREAD; 472252260Sgibbs else if (cm->cm_operation == BLKIF_OP_WRITE || 473252260Sgibbs cm->cm_operation == BLKIF_OP_WRITE_BARRIER) 474251204Sgibbs op = BUS_DMASYNC_POSTWRITE; 475251204Sgibbs else 476251204Sgibbs op = 0; 477251204Sgibbs bus_dmamap_sync(sc->xbd_io_dmat, cm->cm_map, op); 478251204Sgibbs bus_dmamap_unload(sc->xbd_io_dmat, cm->cm_map); 479251204Sgibbs 480251204Sgibbs /* 481251772Sgibbs * Release any hold this command has on future command 482251772Sgibbs * dispatch. 483251204Sgibbs */ 484252260Sgibbs xbd_cm_thaw(sc, cm); 485251204Sgibbs 486251204Sgibbs /* 487251204Sgibbs * Directly call the i/o complete routine to save an 488251204Sgibbs * an indirection in the common case. 489251204Sgibbs */ 490251204Sgibbs cm->cm_status = bret->status; 491251204Sgibbs if (cm->cm_bp) 492251204Sgibbs xbd_bio_complete(sc, cm); 493251204Sgibbs else if (cm->cm_complete != NULL) 494251204Sgibbs cm->cm_complete(cm); 495251204Sgibbs else 496251204Sgibbs xbd_free_command(cm); 497251204Sgibbs } 498251204Sgibbs 499251204Sgibbs sc->xbd_ring.rsp_cons = i; 500251204Sgibbs 501251204Sgibbs if (i != sc->xbd_ring.req_prod_pvt) { 502251204Sgibbs int more_to_do; 503251204Sgibbs RING_FINAL_CHECK_FOR_RESPONSES(&sc->xbd_ring, more_to_do); 504251204Sgibbs if (more_to_do) 505251204Sgibbs goto again; 506251204Sgibbs } else { 507251204Sgibbs sc->xbd_ring.sring->rsp_event = i + 1; 508251204Sgibbs } 509251204Sgibbs 510252260Sgibbs if (xbd_queue_length(sc, XBD_Q_BUSY) == 0) 511252260Sgibbs xbd_thaw(sc, XBDF_WAIT_IDLE); 512252260Sgibbs 513251204Sgibbs xbd_startio(sc); 514251204Sgibbs 515255040Sgibbs if (__predict_false(sc->xbd_state == XBD_STATE_SUSPENDED)) 516251751Sgibbs wakeup(&sc->xbd_cm_q[XBD_Q_BUSY]); 517251204Sgibbs 518251204Sgibbs mtx_unlock(&sc->xbd_io_lock); 519251204Sgibbs} 520251204Sgibbs 521251204Sgibbs/*------------------------------- Dump Support -------------------------------*/ 522251204Sgibbs/** 523251204Sgibbs * Quiesce the disk writes for a dump file before allowing the next buffer. 524251204Sgibbs */ 525251204Sgibbsstatic void 526251195Sgibbsxbd_quiesce(struct xbd_softc *sc) 527196661Skmacy{ 528251195Sgibbs int mtd; 529196661Skmacy 530196661Skmacy // While there are outstanding requests 531252260Sgibbs while (xbd_queue_length(sc, XBD_Q_BUSY) != 0) { 532251195Sgibbs RING_FINAL_CHECK_FOR_RESPONSES(&sc->xbd_ring, mtd); 533196661Skmacy if (mtd) { 534199960Skmacy /* Recieved request completions, update queue. */ 535251195Sgibbs xbd_int(sc); 536196661Skmacy } 537252260Sgibbs if (xbd_queue_length(sc, XBD_Q_BUSY) != 0) { 538199960Skmacy /* 539199960Skmacy * Still pending requests, wait for the disk i/o 540199960Skmacy * to complete. 541199960Skmacy */ 542199734Skmacy HYPERVISOR_yield(); 543196661Skmacy } 544196661Skmacy } 545196661Skmacy} 546196661Skmacy 547199960Skmacy/* Kernel dump function for a paravirtualized disk device */ 548199960Skmacystatic void 549251195Sgibbsxbd_dump_complete(struct xbd_command *cm) 550199960Skmacy{ 551196661Skmacy 552251751Sgibbs xbd_enqueue_cm(cm, XBD_Q_COMPLETE); 553199960Skmacy} 554199960Skmacy 555185605Skmacystatic int 556251195Sgibbsxbd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, 557251195Sgibbs size_t length) 558196661Skmacy{ 559251195Sgibbs struct disk *dp = arg; 560251195Sgibbs struct xbd_softc *sc = dp->d_drv1; 561251195Sgibbs struct xbd_command *cm; 562251195Sgibbs size_t chunk; 563251195Sgibbs int sbp; 564251195Sgibbs int rc = 0; 565196661Skmacy 566199960Skmacy if (length <= 0) 567199960Skmacy return (rc); 568196661Skmacy 569251195Sgibbs xbd_quiesce(sc); /* All quiet on the western front. */ 570196661Skmacy 571199960Skmacy /* 572199960Skmacy * If this lock is held, then this module is failing, and a 573199960Skmacy * successful kernel dump is highly unlikely anyway. 574199960Skmacy */ 575251195Sgibbs mtx_lock(&sc->xbd_io_lock); 576199960Skmacy 577199960Skmacy /* Split the 64KB block as needed */ 578199960Skmacy for (sbp=0; length > 0; sbp++) { 579251751Sgibbs cm = xbd_dequeue_cm(sc, XBD_Q_FREE); 580199960Skmacy if (cm == NULL) { 581251195Sgibbs mtx_unlock(&sc->xbd_io_lock); 582251195Sgibbs device_printf(sc->xbd_dev, "dump: no more commands?\n"); 583199960Skmacy return (EBUSY); 584196661Skmacy } 585196661Skmacy 586251195Sgibbs if (gnttab_alloc_grant_references(sc->xbd_max_request_segments, 587251195Sgibbs &cm->cm_gref_head) != 0) { 588251195Sgibbs xbd_free_command(cm); 589251195Sgibbs mtx_unlock(&sc->xbd_io_lock); 590251195Sgibbs device_printf(sc->xbd_dev, "no more grant allocs?\n"); 591199960Skmacy return (EBUSY); 592196661Skmacy } 593199960Skmacy 594251195Sgibbs chunk = length > sc->xbd_max_request_size ? 595251195Sgibbs sc->xbd_max_request_size : length; 596251195Sgibbs cm->cm_data = virtual; 597251195Sgibbs cm->cm_datalen = chunk; 598251195Sgibbs cm->cm_operation = BLKIF_OP_WRITE; 599251195Sgibbs cm->cm_sector_number = offset / dp->d_sectorsize; 600251195Sgibbs cm->cm_complete = xbd_dump_complete; 601199960Skmacy 602251751Sgibbs xbd_enqueue_cm(cm, XBD_Q_READY); 603199960Skmacy 604199960Skmacy length -= chunk; 605199960Skmacy offset += chunk; 606199960Skmacy virtual = (char *) virtual + chunk; 607196661Skmacy } 608199960Skmacy 609199960Skmacy /* Tell DOM0 to do the I/O */ 610251195Sgibbs xbd_startio(sc); 611251195Sgibbs mtx_unlock(&sc->xbd_io_lock); 612199960Skmacy 613199960Skmacy /* Poll for the completion. */ 614251195Sgibbs xbd_quiesce(sc); /* All quite on the eastern front */ 615199960Skmacy 616199960Skmacy /* If there were any errors, bail out... */ 617251751Sgibbs while ((cm = xbd_dequeue_cm(sc, XBD_Q_COMPLETE)) != NULL) { 618251195Sgibbs if (cm->cm_status != BLKIF_RSP_OKAY) { 619251195Sgibbs device_printf(sc->xbd_dev, 620199960Skmacy "Dump I/O failed at sector %jd\n", 621251195Sgibbs cm->cm_sector_number); 622199960Skmacy rc = EIO; 623199960Skmacy } 624251195Sgibbs xbd_free_command(cm); 625199960Skmacy } 626199960Skmacy 627196661Skmacy return (rc); 628196661Skmacy} 629196661Skmacy 630251204Sgibbs/*----------------------------- Disk Entrypoints -----------------------------*/ 631251204Sgibbsstatic int 632251204Sgibbsxbd_open(struct disk *dp) 633251204Sgibbs{ 634251204Sgibbs struct xbd_softc *sc = dp->d_drv1; 635196661Skmacy 636251204Sgibbs if (sc == NULL) { 637251204Sgibbs printf("xb%d: not found", sc->xbd_unit); 638251204Sgibbs return (ENXIO); 639251204Sgibbs } 640251204Sgibbs 641251751Sgibbs sc->xbd_flags |= XBDF_OPEN; 642251204Sgibbs sc->xbd_users++; 643251204Sgibbs return (0); 644251204Sgibbs} 645251204Sgibbs 646196661Skmacystatic int 647251204Sgibbsxbd_close(struct disk *dp) 648185605Skmacy{ 649251204Sgibbs struct xbd_softc *sc = dp->d_drv1; 650181643Skmacy 651251204Sgibbs if (sc == NULL) 652251204Sgibbs return (ENXIO); 653251751Sgibbs sc->xbd_flags &= ~XBDF_OPEN; 654251204Sgibbs if (--(sc->xbd_users) == 0) { 655251204Sgibbs /* 656251204Sgibbs * Check whether we have been instructed to close. We will 657251204Sgibbs * have ignored this request initially, as the device was 658251204Sgibbs * still mounted. 659251204Sgibbs */ 660251204Sgibbs if (xenbus_get_otherend_state(sc->xbd_dev) == 661251204Sgibbs XenbusStateClosing) 662251204Sgibbs xbd_closing(sc->xbd_dev); 663185605Skmacy } 664251204Sgibbs return (0); 665251204Sgibbs} 666181643Skmacy 667251204Sgibbsstatic int 668251204Sgibbsxbd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) 669251204Sgibbs{ 670251204Sgibbs struct xbd_softc *sc = dp->d_drv1; 671251204Sgibbs 672251204Sgibbs if (sc == NULL) 673251204Sgibbs return (ENXIO); 674251204Sgibbs 675251204Sgibbs return (ENOTTY); 676185605Skmacy} 677185605Skmacy 678251204Sgibbs/* 679251204Sgibbs * Read/write routine for a buffer. Finds the proper unit, place it on 680251204Sgibbs * the sortq and kick the controller. 681251204Sgibbs */ 682231743Sgibbsstatic void 683251204Sgibbsxbd_strategy(struct bio *bp) 684251204Sgibbs{ 685251204Sgibbs struct xbd_softc *sc = bp->bio_disk->d_drv1; 686251204Sgibbs 687251204Sgibbs /* bogus disk? */ 688251204Sgibbs if (sc == NULL) { 689251204Sgibbs bp->bio_error = EINVAL; 690251204Sgibbs bp->bio_flags |= BIO_ERROR; 691251204Sgibbs bp->bio_resid = bp->bio_bcount; 692251204Sgibbs biodone(bp); 693251204Sgibbs return; 694251204Sgibbs } 695251204Sgibbs 696251204Sgibbs /* 697251204Sgibbs * Place it in the queue of disk activities for this disk 698251204Sgibbs */ 699251204Sgibbs mtx_lock(&sc->xbd_io_lock); 700251204Sgibbs 701251204Sgibbs xbd_enqueue_bio(sc, bp); 702251204Sgibbs xbd_startio(sc); 703251204Sgibbs 704251204Sgibbs mtx_unlock(&sc->xbd_io_lock); 705251204Sgibbs return; 706251204Sgibbs} 707251204Sgibbs 708251204Sgibbs/*------------------------------ Ring Management -----------------------------*/ 709251204Sgibbsstatic int 710251206Sgibbsxbd_alloc_ring(struct xbd_softc *sc) 711251204Sgibbs{ 712251204Sgibbs blkif_sring_t *sring; 713251204Sgibbs uintptr_t sring_page_addr; 714251204Sgibbs int error; 715251204Sgibbs int i; 716251204Sgibbs 717251204Sgibbs sring = malloc(sc->xbd_ring_pages * PAGE_SIZE, M_XENBLOCKFRONT, 718251204Sgibbs M_NOWAIT|M_ZERO); 719251204Sgibbs if (sring == NULL) { 720251204Sgibbs xenbus_dev_fatal(sc->xbd_dev, ENOMEM, "allocating shared ring"); 721251204Sgibbs return (ENOMEM); 722251204Sgibbs } 723251204Sgibbs SHARED_RING_INIT(sring); 724251204Sgibbs FRONT_RING_INIT(&sc->xbd_ring, sring, sc->xbd_ring_pages * PAGE_SIZE); 725251204Sgibbs 726251204Sgibbs for (i = 0, sring_page_addr = (uintptr_t)sring; 727251204Sgibbs i < sc->xbd_ring_pages; 728251204Sgibbs i++, sring_page_addr += PAGE_SIZE) { 729251204Sgibbs 730251204Sgibbs error = xenbus_grant_ring(sc->xbd_dev, 731251204Sgibbs (vtomach(sring_page_addr) >> PAGE_SHIFT), 732251204Sgibbs &sc->xbd_ring_ref[i]); 733251204Sgibbs if (error) { 734251204Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 735251204Sgibbs "granting ring_ref(%d)", i); 736251204Sgibbs return (error); 737251204Sgibbs } 738251204Sgibbs } 739251204Sgibbs if (sc->xbd_ring_pages == 1) { 740251204Sgibbs error = xs_printf(XST_NIL, xenbus_get_node(sc->xbd_dev), 741251204Sgibbs "ring-ref", "%u", sc->xbd_ring_ref[0]); 742251204Sgibbs if (error) { 743251204Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 744251204Sgibbs "writing %s/ring-ref", 745251204Sgibbs xenbus_get_node(sc->xbd_dev)); 746251204Sgibbs return (error); 747251204Sgibbs } 748251204Sgibbs } else { 749251204Sgibbs for (i = 0; i < sc->xbd_ring_pages; i++) { 750251204Sgibbs char ring_ref_name[]= "ring_refXX"; 751251204Sgibbs 752251204Sgibbs snprintf(ring_ref_name, sizeof(ring_ref_name), 753251204Sgibbs "ring-ref%u", i); 754251204Sgibbs error = xs_printf(XST_NIL, xenbus_get_node(sc->xbd_dev), 755251204Sgibbs ring_ref_name, "%u", sc->xbd_ring_ref[i]); 756251204Sgibbs if (error) { 757251204Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 758251204Sgibbs "writing %s/%s", 759251204Sgibbs xenbus_get_node(sc->xbd_dev), 760251204Sgibbs ring_ref_name); 761251204Sgibbs return (error); 762251204Sgibbs } 763251204Sgibbs } 764251204Sgibbs } 765251204Sgibbs 766255040Sgibbs error = xen_intr_alloc_and_bind_local_port(sc->xbd_dev, 767255040Sgibbs xenbus_get_otherend_id(sc->xbd_dev), NULL, xbd_int, sc, 768255040Sgibbs INTR_TYPE_BIO | INTR_MPSAFE, &sc->xen_intr_handle); 769251204Sgibbs if (error) { 770251204Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 771255040Sgibbs "xen_intr_alloc_and_bind_local_port failed"); 772251204Sgibbs return (error); 773251204Sgibbs } 774251204Sgibbs 775251204Sgibbs return (0); 776251204Sgibbs} 777251204Sgibbs 778251214Sgibbsstatic void 779251214Sgibbsxbd_free_ring(struct xbd_softc *sc) 780251214Sgibbs{ 781251214Sgibbs int i; 782251214Sgibbs 783251214Sgibbs if (sc->xbd_ring.sring == NULL) 784251214Sgibbs return; 785251214Sgibbs 786251214Sgibbs for (i = 0; i < sc->xbd_ring_pages; i++) { 787251214Sgibbs if (sc->xbd_ring_ref[i] != GRANT_REF_INVALID) { 788251214Sgibbs gnttab_end_foreign_access_ref(sc->xbd_ring_ref[i]); 789251214Sgibbs sc->xbd_ring_ref[i] = GRANT_REF_INVALID; 790251214Sgibbs } 791251214Sgibbs } 792251214Sgibbs free(sc->xbd_ring.sring, M_XENBLOCKFRONT); 793251214Sgibbs sc->xbd_ring.sring = NULL; 794251214Sgibbs} 795251214Sgibbs 796251204Sgibbs/*-------------------------- Initialization/Teardown -------------------------*/ 797252260Sgibbsstatic int 798252260Sgibbsxbd_feature_string(struct xbd_softc *sc, char *features, size_t len) 799252260Sgibbs{ 800252260Sgibbs struct sbuf sb; 801252260Sgibbs int feature_cnt; 802252260Sgibbs 803252260Sgibbs sbuf_new(&sb, features, len, SBUF_FIXEDLEN); 804252260Sgibbs 805252260Sgibbs feature_cnt = 0; 806252260Sgibbs if ((sc->xbd_flags & XBDF_FLUSH) != 0) { 807252260Sgibbs sbuf_printf(&sb, "flush"); 808252260Sgibbs feature_cnt++; 809252260Sgibbs } 810252260Sgibbs 811252260Sgibbs if ((sc->xbd_flags & XBDF_BARRIER) != 0) { 812252260Sgibbs if (feature_cnt != 0) 813252260Sgibbs sbuf_printf(&sb, ", "); 814252260Sgibbs sbuf_printf(&sb, "write_barrier"); 815252260Sgibbs feature_cnt++; 816252260Sgibbs } 817252260Sgibbs 818252260Sgibbs (void) sbuf_finish(&sb); 819252260Sgibbs return (sbuf_len(&sb)); 820252260Sgibbs} 821252260Sgibbs 822252260Sgibbsstatic int 823252260Sgibbsxbd_sysctl_features(SYSCTL_HANDLER_ARGS) 824252260Sgibbs{ 825252260Sgibbs char features[80]; 826252260Sgibbs struct xbd_softc *sc = arg1; 827252260Sgibbs int error; 828252260Sgibbs int len; 829252260Sgibbs 830252260Sgibbs error = sysctl_wire_old_buffer(req, 0); 831252260Sgibbs if (error != 0) 832252260Sgibbs return (error); 833252260Sgibbs 834252260Sgibbs len = xbd_feature_string(sc, features, sizeof(features)); 835252260Sgibbs 836252260Sgibbs /* len is -1 on error, which will make the SYSCTL_OUT a no-op. */ 837252260Sgibbs return (SYSCTL_OUT(req, features, len + 1/*NUL*/)); 838252260Sgibbs} 839252260Sgibbs 840251204Sgibbsstatic void 841251195Sgibbsxbd_setup_sysctl(struct xbd_softc *xbd) 842231743Sgibbs{ 843231743Sgibbs struct sysctl_ctx_list *sysctl_ctx = NULL; 844251195Sgibbs struct sysctl_oid *sysctl_tree = NULL; 845252260Sgibbs struct sysctl_oid_list *children; 846231743Sgibbs 847251195Sgibbs sysctl_ctx = device_get_sysctl_ctx(xbd->xbd_dev); 848231743Sgibbs if (sysctl_ctx == NULL) 849231743Sgibbs return; 850231743Sgibbs 851251195Sgibbs sysctl_tree = device_get_sysctl_tree(xbd->xbd_dev); 852231743Sgibbs if (sysctl_tree == NULL) 853231743Sgibbs return; 854231743Sgibbs 855252260Sgibbs children = SYSCTL_CHILDREN(sysctl_tree); 856252260Sgibbs SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO, 857251195Sgibbs "max_requests", CTLFLAG_RD, &xbd->xbd_max_requests, -1, 858251195Sgibbs "maximum outstanding requests (negotiated)"); 859231743Sgibbs 860252260Sgibbs SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO, 861251195Sgibbs "max_request_segments", CTLFLAG_RD, 862251195Sgibbs &xbd->xbd_max_request_segments, 0, 863251195Sgibbs "maximum number of pages per requests (negotiated)"); 864231743Sgibbs 865252260Sgibbs SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO, 866251195Sgibbs "max_request_size", CTLFLAG_RD, &xbd->xbd_max_request_size, 0, 867251195Sgibbs "maximum size in bytes of a request (negotiated)"); 868231743Sgibbs 869252260Sgibbs SYSCTL_ADD_UINT(sysctl_ctx, children, OID_AUTO, 870251195Sgibbs "ring_pages", CTLFLAG_RD, &xbd->xbd_ring_pages, 0, 871251195Sgibbs "communication channel pages (negotiated)"); 872252260Sgibbs 873252260Sgibbs SYSCTL_ADD_PROC(sysctl_ctx, children, OID_AUTO, 874252260Sgibbs "features", CTLTYPE_STRING|CTLFLAG_RD, xbd, 0, 875252260Sgibbs xbd_sysctl_features, "A", "protocol features (negotiated)"); 876231743Sgibbs} 877231743Sgibbs 878185605Skmacy/* 879251204Sgibbs * Translate Linux major/minor to an appropriate name and unit 880251204Sgibbs * number. For HVM guests, this allows us to use the same drive names 881251204Sgibbs * with blkfront as the emulated drives, easing transition slightly. 882185605Skmacy */ 883251204Sgibbsstatic void 884251204Sgibbsxbd_vdevice_to_unit(uint32_t vdevice, int *unit, const char **name) 885181643Skmacy{ 886251204Sgibbs static struct vdev_info { 887251204Sgibbs int major; 888251204Sgibbs int shift; 889251204Sgibbs int base; 890251204Sgibbs const char *name; 891251204Sgibbs } info[] = { 892251204Sgibbs {3, 6, 0, "ada"}, /* ide0 */ 893251204Sgibbs {22, 6, 2, "ada"}, /* ide1 */ 894251204Sgibbs {33, 6, 4, "ada"}, /* ide2 */ 895251204Sgibbs {34, 6, 6, "ada"}, /* ide3 */ 896251204Sgibbs {56, 6, 8, "ada"}, /* ide4 */ 897251204Sgibbs {57, 6, 10, "ada"}, /* ide5 */ 898251204Sgibbs {88, 6, 12, "ada"}, /* ide6 */ 899251204Sgibbs {89, 6, 14, "ada"}, /* ide7 */ 900251204Sgibbs {90, 6, 16, "ada"}, /* ide8 */ 901251204Sgibbs {91, 6, 18, "ada"}, /* ide9 */ 902251204Sgibbs 903251204Sgibbs {8, 4, 0, "da"}, /* scsi disk0 */ 904251204Sgibbs {65, 4, 16, "da"}, /* scsi disk1 */ 905251204Sgibbs {66, 4, 32, "da"}, /* scsi disk2 */ 906251204Sgibbs {67, 4, 48, "da"}, /* scsi disk3 */ 907251204Sgibbs {68, 4, 64, "da"}, /* scsi disk4 */ 908251204Sgibbs {69, 4, 80, "da"}, /* scsi disk5 */ 909251204Sgibbs {70, 4, 96, "da"}, /* scsi disk6 */ 910251204Sgibbs {71, 4, 112, "da"}, /* scsi disk7 */ 911251204Sgibbs {128, 4, 128, "da"}, /* scsi disk8 */ 912251204Sgibbs {129, 4, 144, "da"}, /* scsi disk9 */ 913251204Sgibbs {130, 4, 160, "da"}, /* scsi disk10 */ 914251204Sgibbs {131, 4, 176, "da"}, /* scsi disk11 */ 915251204Sgibbs {132, 4, 192, "da"}, /* scsi disk12 */ 916251204Sgibbs {133, 4, 208, "da"}, /* scsi disk13 */ 917251204Sgibbs {134, 4, 224, "da"}, /* scsi disk14 */ 918251204Sgibbs {135, 4, 240, "da"}, /* scsi disk15 */ 919251204Sgibbs 920251204Sgibbs {202, 4, 0, "xbd"}, /* xbd */ 921251204Sgibbs 922251204Sgibbs {0, 0, 0, NULL}, 923251204Sgibbs }; 924251204Sgibbs int major = vdevice >> 8; 925251204Sgibbs int minor = vdevice & 0xff; 926214077Sgibbs int i; 927181643Skmacy 928251204Sgibbs if (vdevice & (1 << 28)) { 929251204Sgibbs *unit = (vdevice & ((1 << 28) - 1)) >> 8; 930251204Sgibbs *name = "xbd"; 931251204Sgibbs return; 932181643Skmacy } 933181643Skmacy 934251204Sgibbs for (i = 0; info[i].major; i++) { 935251204Sgibbs if (info[i].major == major) { 936251204Sgibbs *unit = info[i].base + (minor >> info[i].shift); 937251204Sgibbs *name = info[i].name; 938251204Sgibbs return; 939251204Sgibbs } 940251204Sgibbs } 941251204Sgibbs 942251204Sgibbs *unit = minor >> 4; 943251204Sgibbs *name = "xbd"; 944251204Sgibbs} 945251204Sgibbs 946251204Sgibbsint 947251204Sgibbsxbd_instance_create(struct xbd_softc *sc, blkif_sector_t sectors, 948251204Sgibbs int vdevice, uint16_t vdisk_info, unsigned long sector_size) 949251204Sgibbs{ 950252260Sgibbs char features[80]; 951251204Sgibbs int unit, error = 0; 952251204Sgibbs const char *name; 953251204Sgibbs 954251195Sgibbs xbd_vdevice_to_unit(vdevice, &unit, &name); 955185605Skmacy 956251204Sgibbs sc->xbd_unit = unit; 957181643Skmacy 958252260Sgibbs if (strcmp(name, "xbd") != 0) 959251204Sgibbs device_printf(sc->xbd_dev, "attaching as %s%d\n", name, unit); 960199960Skmacy 961252260Sgibbs if (xbd_feature_string(sc, features, sizeof(features)) > 0) { 962252260Sgibbs device_printf(sc->xbd_dev, "features: %s\n", 963252260Sgibbs features); 964252260Sgibbs } 965252260Sgibbs 966251204Sgibbs sc->xbd_disk = disk_alloc(); 967251204Sgibbs sc->xbd_disk->d_unit = sc->xbd_unit; 968251204Sgibbs sc->xbd_disk->d_open = xbd_open; 969251204Sgibbs sc->xbd_disk->d_close = xbd_close; 970251204Sgibbs sc->xbd_disk->d_ioctl = xbd_ioctl; 971251204Sgibbs sc->xbd_disk->d_strategy = xbd_strategy; 972251204Sgibbs sc->xbd_disk->d_dump = xbd_dump; 973251204Sgibbs sc->xbd_disk->d_name = name; 974251204Sgibbs sc->xbd_disk->d_drv1 = sc; 975251204Sgibbs sc->xbd_disk->d_sectorsize = sector_size; 976231743Sgibbs 977251204Sgibbs sc->xbd_disk->d_mediasize = sectors * sector_size; 978251204Sgibbs sc->xbd_disk->d_maxsize = sc->xbd_max_request_size; 979271611Sroyger sc->xbd_disk->d_flags = 0; 980252260Sgibbs if ((sc->xbd_flags & (XBDF_FLUSH|XBDF_BARRIER)) != 0) { 981252260Sgibbs sc->xbd_disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 982252260Sgibbs device_printf(sc->xbd_dev, 983252260Sgibbs "synchronize cache commands enabled.\n"); 984252260Sgibbs } 985251204Sgibbs disk_create(sc->xbd_disk, DISK_VERSION); 986181643Skmacy 987251204Sgibbs return error; 988181643Skmacy} 989181643Skmacy 990251204Sgibbsstatic void 991251204Sgibbsxbd_free(struct xbd_softc *sc) 992189699Sdfr{ 993251204Sgibbs int i; 994251204Sgibbs 995189699Sdfr /* Prevent new requests being issued until we fix things up. */ 996251195Sgibbs mtx_lock(&sc->xbd_io_lock); 997251751Sgibbs sc->xbd_state = XBD_STATE_DISCONNECTED; 998251204Sgibbs mtx_unlock(&sc->xbd_io_lock); 999225705Sgibbs 1000251204Sgibbs /* Free resources associated with old device channel. */ 1001251214Sgibbs xbd_free_ring(sc); 1002251204Sgibbs if (sc->xbd_shadow) { 1003225705Sgibbs 1004251204Sgibbs for (i = 0; i < sc->xbd_max_requests; i++) { 1005251204Sgibbs struct xbd_command *cm; 1006189699Sdfr 1007251204Sgibbs cm = &sc->xbd_shadow[i]; 1008251204Sgibbs if (cm->cm_sg_refs != NULL) { 1009251204Sgibbs free(cm->cm_sg_refs, M_XENBLOCKFRONT); 1010251204Sgibbs cm->cm_sg_refs = NULL; 1011251204Sgibbs } 1012181643Skmacy 1013251204Sgibbs bus_dmamap_destroy(sc->xbd_io_dmat, cm->cm_map); 1014251204Sgibbs } 1015251204Sgibbs free(sc->xbd_shadow, M_XENBLOCKFRONT); 1016251204Sgibbs sc->xbd_shadow = NULL; 1017181643Skmacy 1018251204Sgibbs bus_dma_tag_destroy(sc->xbd_io_dmat); 1019251204Sgibbs 1020251751Sgibbs xbd_initq_cm(sc, XBD_Q_FREE); 1021251751Sgibbs xbd_initq_cm(sc, XBD_Q_READY); 1022251751Sgibbs xbd_initq_cm(sc, XBD_Q_COMPLETE); 1023251204Sgibbs } 1024251204Sgibbs 1025255040Sgibbs xen_intr_unbind(&sc->xen_intr_handle); 1026255040Sgibbs 1027181643Skmacy} 1028181643Skmacy 1029251204Sgibbs/*--------------------------- State Change Handlers --------------------------*/ 1030214077Sgibbsstatic void 1031251195Sgibbsxbd_initialize(struct xbd_softc *sc) 1032181643Skmacy{ 1033214077Sgibbs const char *otherend_path; 1034214077Sgibbs const char *node_path; 1035231743Sgibbs uint32_t max_ring_page_order; 1036214077Sgibbs int error; 1037214077Sgibbs int i; 1038181643Skmacy 1039251195Sgibbs if (xenbus_get_state(sc->xbd_dev) != XenbusStateInitialising) { 1040225705Sgibbs /* Initialization has already been performed. */ 1041225705Sgibbs return; 1042225705Sgibbs } 1043181643Skmacy 1044214077Sgibbs /* 1045214077Sgibbs * Protocol defaults valid even if negotiation for a 1046214077Sgibbs * setting fails. 1047214077Sgibbs */ 1048231743Sgibbs max_ring_page_order = 0; 1049251195Sgibbs sc->xbd_ring_pages = 1; 1050285738Sroyger sc->xbd_max_request_segments = BLKIF_MAX_SEGMENTS_PER_REQUEST; 1051251195Sgibbs sc->xbd_max_request_size = 1052251195Sgibbs XBD_SEGS_TO_SIZE(sc->xbd_max_request_segments); 1053214077Sgibbs 1054214077Sgibbs /* 1055214077Sgibbs * Protocol negotiation. 1056214077Sgibbs * 1057214077Sgibbs * \note xs_gather() returns on the first encountered error, so 1058214077Sgibbs * we must use independant calls in order to guarantee 1059214077Sgibbs * we don't miss information in a sparsly populated back-end 1060214077Sgibbs * tree. 1061231743Sgibbs * 1062231743Sgibbs * \note xs_scanf() does not update variables for unmatched 1063231743Sgibbs * fields. 1064214077Sgibbs */ 1065251195Sgibbs otherend_path = xenbus_get_otherend_path(sc->xbd_dev); 1066251195Sgibbs node_path = xenbus_get_node(sc->xbd_dev); 1067231743Sgibbs 1068231743Sgibbs /* Support both backend schemes for relaying ring page limits. */ 1069214077Sgibbs (void)xs_scanf(XST_NIL, otherend_path, 1070251195Sgibbs "max-ring-page-order", NULL, "%" PRIu32, 1071251195Sgibbs &max_ring_page_order); 1072251195Sgibbs sc->xbd_ring_pages = 1 << max_ring_page_order; 1073231743Sgibbs (void)xs_scanf(XST_NIL, otherend_path, 1074251195Sgibbs "max-ring-pages", NULL, "%" PRIu32, 1075251195Sgibbs &sc->xbd_ring_pages); 1076251195Sgibbs if (sc->xbd_ring_pages < 1) 1077251195Sgibbs sc->xbd_ring_pages = 1; 1078214077Sgibbs 1079251195Sgibbs if (sc->xbd_ring_pages > XBD_MAX_RING_PAGES) { 1080251195Sgibbs device_printf(sc->xbd_dev, 1081251195Sgibbs "Back-end specified ring-pages of %u " 1082285738Sroyger "limited to front-end limit of %u.\n", 1083251195Sgibbs sc->xbd_ring_pages, XBD_MAX_RING_PAGES); 1084251195Sgibbs sc->xbd_ring_pages = XBD_MAX_RING_PAGES; 1085181643Skmacy } 1086181643Skmacy 1087251195Sgibbs if (powerof2(sc->xbd_ring_pages) == 0) { 1088231743Sgibbs uint32_t new_page_limit; 1089231743Sgibbs 1090251195Sgibbs new_page_limit = 0x01 << (fls(sc->xbd_ring_pages) - 1); 1091251195Sgibbs device_printf(sc->xbd_dev, 1092251195Sgibbs "Back-end specified ring-pages of %u " 1093251195Sgibbs "is not a power of 2. Limited to %u.\n", 1094251195Sgibbs sc->xbd_ring_pages, new_page_limit); 1095251195Sgibbs sc->xbd_ring_pages = new_page_limit; 1096231743Sgibbs } 1097231743Sgibbs 1098285738Sroyger sc->xbd_max_requests = 1099285738Sroyger BLKIF_MAX_RING_REQUESTS(sc->xbd_ring_pages * PAGE_SIZE); 1100251195Sgibbs if (sc->xbd_max_requests > XBD_MAX_REQUESTS) { 1101251195Sgibbs device_printf(sc->xbd_dev, 1102251195Sgibbs "Back-end specified max_requests of %u " 1103285738Sroyger "limited to front-end limit of %zu.\n", 1104251195Sgibbs sc->xbd_max_requests, XBD_MAX_REQUESTS); 1105251195Sgibbs sc->xbd_max_requests = XBD_MAX_REQUESTS; 1106181643Skmacy } 1107214077Sgibbs 1108214077Sgibbs /* Allocate datastructures based on negotiated values. */ 1109251195Sgibbs error = bus_dma_tag_create( 1110251195Sgibbs bus_get_dma_tag(sc->xbd_dev), /* parent */ 1111251195Sgibbs 512, PAGE_SIZE, /* algnmnt, boundary */ 1112251195Sgibbs BUS_SPACE_MAXADDR, /* lowaddr */ 1113251195Sgibbs BUS_SPACE_MAXADDR, /* highaddr */ 1114251195Sgibbs NULL, NULL, /* filter, filterarg */ 1115251195Sgibbs sc->xbd_max_request_size, 1116251195Sgibbs sc->xbd_max_request_segments, 1117251195Sgibbs PAGE_SIZE, /* maxsegsize */ 1118251195Sgibbs BUS_DMA_ALLOCNOW, /* flags */ 1119251195Sgibbs busdma_lock_mutex, /* lockfunc */ 1120251195Sgibbs &sc->xbd_io_lock, /* lockarg */ 1121251195Sgibbs &sc->xbd_io_dmat); 1122214077Sgibbs if (error != 0) { 1123251195Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 1124251195Sgibbs "Cannot allocate parent DMA tag\n"); 1125214077Sgibbs return; 1126181643Skmacy } 1127181643Skmacy 1128214077Sgibbs /* Per-transaction data allocation. */ 1129251195Sgibbs sc->xbd_shadow = malloc(sizeof(*sc->xbd_shadow) * sc->xbd_max_requests, 1130251195Sgibbs M_XENBLOCKFRONT, M_NOWAIT|M_ZERO); 1131251195Sgibbs if (sc->xbd_shadow == NULL) { 1132251195Sgibbs bus_dma_tag_destroy(sc->xbd_io_dmat); 1133251195Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 1134251195Sgibbs "Cannot allocate request structures\n"); 1135225705Sgibbs return; 1136214077Sgibbs } 1137214077Sgibbs 1138251195Sgibbs for (i = 0; i < sc->xbd_max_requests; i++) { 1139251195Sgibbs struct xbd_command *cm; 1140214077Sgibbs 1141251195Sgibbs cm = &sc->xbd_shadow[i]; 1142251195Sgibbs cm->cm_sg_refs = malloc( 1143251195Sgibbs sizeof(grant_ref_t) * sc->xbd_max_request_segments, 1144251195Sgibbs M_XENBLOCKFRONT, M_NOWAIT); 1145251195Sgibbs if (cm->cm_sg_refs == NULL) 1146214077Sgibbs break; 1147251195Sgibbs cm->cm_id = i; 1148251751Sgibbs cm->cm_flags = XBDCF_INITIALIZER; 1149214077Sgibbs cm->cm_sc = sc; 1150251195Sgibbs if (bus_dmamap_create(sc->xbd_io_dmat, 0, &cm->cm_map) != 0) 1151214077Sgibbs break; 1152251195Sgibbs xbd_free_command(cm); 1153214077Sgibbs } 1154214077Sgibbs 1155251206Sgibbs if (xbd_alloc_ring(sc) != 0) 1156214077Sgibbs return; 1157214077Sgibbs 1158231743Sgibbs /* Support both backend schemes for relaying ring page limits. */ 1159251195Sgibbs if (sc->xbd_ring_pages > 1) { 1160233465Sgibbs error = xs_printf(XST_NIL, node_path, 1161251195Sgibbs "num-ring-pages","%u", 1162251195Sgibbs sc->xbd_ring_pages); 1163233465Sgibbs if (error) { 1164251195Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 1165251195Sgibbs "writing %s/num-ring-pages", 1166251195Sgibbs node_path); 1167233465Sgibbs return; 1168233465Sgibbs } 1169233465Sgibbs 1170233465Sgibbs error = xs_printf(XST_NIL, node_path, 1171251195Sgibbs "ring-page-order", "%u", 1172251195Sgibbs fls(sc->xbd_ring_pages) - 1); 1173233465Sgibbs if (error) { 1174251195Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 1175251195Sgibbs "writing %s/ring-page-order", 1176251195Sgibbs node_path); 1177233465Sgibbs return; 1178233465Sgibbs } 1179214077Sgibbs } 1180214077Sgibbs 1181214077Sgibbs error = xs_printf(XST_NIL, node_path, "event-channel", 1182255040Sgibbs "%u", xen_intr_port(sc->xen_intr_handle)); 1183214077Sgibbs if (error) { 1184251195Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 1185251195Sgibbs "writing %s/event-channel", 1186251195Sgibbs node_path); 1187214077Sgibbs return; 1188214077Sgibbs } 1189214077Sgibbs 1190251195Sgibbs error = xs_printf(XST_NIL, node_path, "protocol", 1191251195Sgibbs "%s", XEN_IO_PROTO_ABI_NATIVE); 1192214077Sgibbs if (error) { 1193251195Sgibbs xenbus_dev_fatal(sc->xbd_dev, error, 1194251195Sgibbs "writing %s/protocol", 1195251195Sgibbs node_path); 1196214077Sgibbs return; 1197214077Sgibbs } 1198214077Sgibbs 1199251195Sgibbs xenbus_set_state(sc->xbd_dev, XenbusStateInitialised); 1200181643Skmacy} 1201181643Skmacy 1202181643Skmacy/* 1203251195Sgibbs * Invoked when the backend is finally 'ready' (and has published 1204251195Sgibbs * the details about the physical device - #sectors, size, etc). 1205251195Sgibbs */ 1206181643Skmacystatic void 1207251195Sgibbsxbd_connect(struct xbd_softc *sc) 1208181643Skmacy{ 1209251195Sgibbs device_t dev = sc->xbd_dev; 1210181643Skmacy unsigned long sectors, sector_size; 1211181643Skmacy unsigned int binfo; 1212252260Sgibbs int err, feature_barrier, feature_flush; 1213181643Skmacy 1214251751Sgibbs if (sc->xbd_state == XBD_STATE_CONNECTED || 1215251751Sgibbs sc->xbd_state == XBD_STATE_SUSPENDED) 1216181643Skmacy return; 1217181643Skmacy 1218185605Skmacy DPRINTK("blkfront.c:connect:%s.\n", xenbus_get_otherend_path(dev)); 1219181643Skmacy 1220214077Sgibbs err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev), 1221251195Sgibbs "sectors", "%lu", §ors, 1222251195Sgibbs "info", "%u", &binfo, 1223251195Sgibbs "sector-size", "%lu", §or_size, 1224251195Sgibbs NULL); 1225181643Skmacy if (err) { 1226185605Skmacy xenbus_dev_fatal(dev, err, 1227185605Skmacy "reading backend fields at %s", 1228185605Skmacy xenbus_get_otherend_path(dev)); 1229181643Skmacy return; 1230181643Skmacy } 1231214077Sgibbs err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev), 1232251195Sgibbs "feature-barrier", "%lu", &feature_barrier, 1233251195Sgibbs NULL); 1234252260Sgibbs if (err == 0 && feature_barrier != 0) 1235251751Sgibbs sc->xbd_flags |= XBDF_BARRIER; 1236181643Skmacy 1237252260Sgibbs err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev), 1238252260Sgibbs "feature-flush-cache", "%lu", &feature_flush, 1239252260Sgibbs NULL); 1240252260Sgibbs if (err == 0 && feature_flush != 0) 1241252260Sgibbs sc->xbd_flags |= XBDF_FLUSH; 1242252260Sgibbs 1243251195Sgibbs if (sc->xbd_disk == NULL) { 1244225705Sgibbs device_printf(dev, "%juMB <%s> at %s", 1245225705Sgibbs (uintmax_t) sectors / (1048576 / sector_size), 1246225705Sgibbs device_get_desc(dev), 1247225705Sgibbs xenbus_get_node(dev)); 1248225705Sgibbs bus_print_child_footer(device_get_parent(dev), dev); 1249181643Skmacy 1250251195Sgibbs xbd_instance_create(sc, sectors, sc->xbd_vdevice, binfo, 1251251195Sgibbs sector_size); 1252225705Sgibbs } 1253181643Skmacy 1254185605Skmacy (void)xenbus_set_state(dev, XenbusStateConnected); 1255185605Skmacy 1256181643Skmacy /* Kick pending requests. */ 1257251195Sgibbs mtx_lock(&sc->xbd_io_lock); 1258251751Sgibbs sc->xbd_state = XBD_STATE_CONNECTED; 1259251195Sgibbs xbd_startio(sc); 1260251751Sgibbs sc->xbd_flags |= XBDF_READY; 1261251195Sgibbs mtx_unlock(&sc->xbd_io_lock); 1262181643Skmacy} 1263181643Skmacy 1264181643Skmacy/** 1265181643Skmacy * Handle the change of state of the backend to Closing. We must delete our 1266181643Skmacy * device-layer structures now, to ensure that writes are flushed through to 1267201138Sgibbs * the backend. Once this is done, we can switch to Closed in 1268181643Skmacy * acknowledgement. 1269181643Skmacy */ 1270185605Skmacystatic void 1271251195Sgibbsxbd_closing(device_t dev) 1272181643Skmacy{ 1273251195Sgibbs struct xbd_softc *sc = device_get_softc(dev); 1274181643Skmacy 1275214077Sgibbs xenbus_set_state(dev, XenbusStateClosing); 1276214077Sgibbs 1277251195Sgibbs DPRINTK("xbd_closing: %s removed\n", xenbus_get_node(dev)); 1278181643Skmacy 1279251195Sgibbs if (sc->xbd_disk != NULL) { 1280251195Sgibbs disk_destroy(sc->xbd_disk); 1281251195Sgibbs sc->xbd_disk = NULL; 1282181643Skmacy } 1283181643Skmacy 1284214077Sgibbs xenbus_set_state(dev, XenbusStateClosed); 1285181643Skmacy} 1286181643Skmacy 1287251204Sgibbs/*---------------------------- NewBus Entrypoints ----------------------------*/ 1288185605Skmacystatic int 1289251204Sgibbsxbd_probe(device_t dev) 1290181643Skmacy{ 1291256757Sgibbs if (strcmp(xenbus_get_type(dev), "vbd") != 0) 1292256757Sgibbs return (ENXIO); 1293181643Skmacy 1294256757Sgibbs if (xen_hvm_domain()) { 1295256757Sgibbs int error; 1296256757Sgibbs char *type; 1297256757Sgibbs 1298256757Sgibbs /* 1299256757Sgibbs * When running in an HVM domain, IDE disk emulation is 1300256757Sgibbs * disabled early in boot so that native drivers will 1301256757Sgibbs * not see emulated hardware. However, CDROM device 1302256757Sgibbs * emulation cannot be disabled. 1303256757Sgibbs * 1304256757Sgibbs * Through use of FreeBSD's vm_guest and xen_hvm_domain() 1305256757Sgibbs * APIs, we could modify the native CDROM driver to fail its 1306256757Sgibbs * probe when running under Xen. Unfortunatlely, the PV 1307256757Sgibbs * CDROM support in XenServer (up through at least version 1308256757Sgibbs * 6.2) isn't functional, so we instead rely on the emulated 1309256757Sgibbs * CDROM instance, and fail to attach the PV one here in 1310256757Sgibbs * the blkfront driver. 1311256757Sgibbs */ 1312256757Sgibbs error = xs_read(XST_NIL, xenbus_get_node(dev), 1313256757Sgibbs "device-type", NULL, (void **) &type); 1314256757Sgibbs if (error) 1315256757Sgibbs return (ENXIO); 1316256757Sgibbs 1317256757Sgibbs if (strncmp(type, "cdrom", 5) == 0) { 1318256757Sgibbs free(type, M_XENSTORE); 1319256757Sgibbs return (ENXIO); 1320256757Sgibbs } 1321256757Sgibbs free(type, M_XENSTORE); 1322181643Skmacy } 1323181643Skmacy 1324256757Sgibbs device_set_desc(dev, "Virtual Block Device"); 1325256757Sgibbs device_quiet(dev); 1326256757Sgibbs return (0); 1327181643Skmacy} 1328181643Skmacy 1329251204Sgibbs/* 1330251204Sgibbs * Setup supplies the backend dir, virtual device. We place an event 1331251204Sgibbs * channel and shared frame entries. We watch backend to wait if it's 1332251204Sgibbs * ok. 1333251204Sgibbs */ 1334181643Skmacystatic int 1335251204Sgibbsxbd_attach(device_t dev) 1336181643Skmacy{ 1337251204Sgibbs struct xbd_softc *sc; 1338251204Sgibbs const char *name; 1339251204Sgibbs uint32_t vdevice; 1340251204Sgibbs int error; 1341251204Sgibbs int i; 1342251204Sgibbs int unit; 1343181643Skmacy 1344251204Sgibbs /* FIXME: Use dynamic device id if this is not set. */ 1345251204Sgibbs error = xs_scanf(XST_NIL, xenbus_get_node(dev), 1346251204Sgibbs "virtual-device", NULL, "%" PRIu32, &vdevice); 1347255051Scperciva if (error) 1348255051Scperciva error = xs_scanf(XST_NIL, xenbus_get_node(dev), 1349255051Scperciva "virtual-device-ext", NULL, "%" PRIu32, &vdevice); 1350251204Sgibbs if (error) { 1351251204Sgibbs xenbus_dev_fatal(dev, error, "reading virtual-device"); 1352251204Sgibbs device_printf(dev, "Couldn't determine virtual device.\n"); 1353251204Sgibbs return (error); 1354181643Skmacy } 1355181643Skmacy 1356251204Sgibbs xbd_vdevice_to_unit(vdevice, &unit, &name); 1357251204Sgibbs if (!strcmp(name, "xbd")) 1358251204Sgibbs device_set_unit(dev, unit); 1359181643Skmacy 1360251204Sgibbs sc = device_get_softc(dev); 1361251204Sgibbs mtx_init(&sc->xbd_io_lock, "blkfront i/o lock", NULL, MTX_DEF); 1362251751Sgibbs xbd_initqs(sc); 1363251204Sgibbs for (i = 0; i < XBD_MAX_RING_PAGES; i++) 1364251214Sgibbs sc->xbd_ring_ref[i] = GRANT_REF_INVALID; 1365181643Skmacy 1366251204Sgibbs sc->xbd_dev = dev; 1367251204Sgibbs sc->xbd_vdevice = vdevice; 1368251751Sgibbs sc->xbd_state = XBD_STATE_DISCONNECTED; 1369181643Skmacy 1370251204Sgibbs xbd_setup_sysctl(sc); 1371181643Skmacy 1372251204Sgibbs /* Wait for backend device to publish its protocol capabilities. */ 1373251204Sgibbs xenbus_set_state(dev, XenbusStateInitialising); 1374199960Skmacy 1375251204Sgibbs return (0); 1376199960Skmacy} 1377199960Skmacy 1378251204Sgibbsstatic int 1379251204Sgibbsxbd_detach(device_t dev) 1380181643Skmacy{ 1381251204Sgibbs struct xbd_softc *sc = device_get_softc(dev); 1382181643Skmacy 1383251751Sgibbs DPRINTK("%s: %s removed\n", __func__, xenbus_get_node(dev)); 1384181643Skmacy 1385251204Sgibbs xbd_free(sc); 1386251204Sgibbs mtx_destroy(&sc->xbd_io_lock); 1387199960Skmacy 1388251204Sgibbs return 0; 1389199960Skmacy} 1390181643Skmacy 1391199960Skmacystatic int 1392251204Sgibbsxbd_suspend(device_t dev) 1393199960Skmacy{ 1394251204Sgibbs struct xbd_softc *sc = device_get_softc(dev); 1395251204Sgibbs int retval; 1396251204Sgibbs int saved_state; 1397181643Skmacy 1398251204Sgibbs /* Prevent new requests being issued until we fix things up. */ 1399251204Sgibbs mtx_lock(&sc->xbd_io_lock); 1400251751Sgibbs saved_state = sc->xbd_state; 1401251751Sgibbs sc->xbd_state = XBD_STATE_SUSPENDED; 1402199960Skmacy 1403251204Sgibbs /* Wait for outstanding I/O to drain. */ 1404251204Sgibbs retval = 0; 1405252260Sgibbs while (xbd_queue_length(sc, XBD_Q_BUSY) != 0) { 1406251751Sgibbs if (msleep(&sc->xbd_cm_q[XBD_Q_BUSY], &sc->xbd_io_lock, 1407251204Sgibbs PRIBIO, "blkf_susp", 30 * hz) == EWOULDBLOCK) { 1408251204Sgibbs retval = EBUSY; 1409251204Sgibbs break; 1410214077Sgibbs } 1411199960Skmacy } 1412251204Sgibbs mtx_unlock(&sc->xbd_io_lock); 1413181643Skmacy 1414251204Sgibbs if (retval != 0) 1415251751Sgibbs sc->xbd_state = saved_state; 1416199960Skmacy 1417251204Sgibbs return (retval); 1418199960Skmacy} 1419181643Skmacy 1420251204Sgibbsstatic int 1421251204Sgibbsxbd_resume(device_t dev) 1422181643Skmacy{ 1423251204Sgibbs struct xbd_softc *sc = device_get_softc(dev); 1424181643Skmacy 1425251204Sgibbs DPRINTK("xbd_resume: %s\n", xenbus_get_node(dev)); 1426181643Skmacy 1427251204Sgibbs xbd_free(sc); 1428251204Sgibbs xbd_initialize(sc); 1429251204Sgibbs return (0); 1430181643Skmacy} 1431181643Skmacy 1432251204Sgibbs/** 1433251204Sgibbs * Callback received when the backend's state changes. 1434251204Sgibbs */ 1435181643Skmacystatic void 1436251204Sgibbsxbd_backend_changed(device_t dev, XenbusState backend_state) 1437181643Skmacy{ 1438251204Sgibbs struct xbd_softc *sc = device_get_softc(dev); 1439181643Skmacy 1440251204Sgibbs DPRINTK("backend_state=%d\n", backend_state); 1441181643Skmacy 1442251204Sgibbs switch (backend_state) { 1443251204Sgibbs case XenbusStateUnknown: 1444251204Sgibbs case XenbusStateInitialising: 1445251204Sgibbs case XenbusStateReconfigured: 1446251204Sgibbs case XenbusStateReconfiguring: 1447251204Sgibbs case XenbusStateClosed: 1448251204Sgibbs break; 1449181643Skmacy 1450251204Sgibbs case XenbusStateInitWait: 1451251204Sgibbs case XenbusStateInitialised: 1452251204Sgibbs xbd_initialize(sc); 1453251204Sgibbs break; 1454181643Skmacy 1455251204Sgibbs case XenbusStateConnected: 1456251204Sgibbs xbd_initialize(sc); 1457251204Sgibbs xbd_connect(sc); 1458251204Sgibbs break; 1459181643Skmacy 1460251204Sgibbs case XenbusStateClosing: 1461251204Sgibbs if (sc->xbd_users > 0) 1462251204Sgibbs xenbus_dev_error(dev, -EBUSY, 1463251204Sgibbs "Device in use; refusing to close"); 1464199960Skmacy else 1465251204Sgibbs xbd_closing(dev); 1466251204Sgibbs break; 1467181643Skmacy } 1468181643Skmacy} 1469181643Skmacy 1470251204Sgibbs/*---------------------------- NewBus Registration ---------------------------*/ 1471251195Sgibbsstatic device_method_t xbd_methods[] = { 1472185605Skmacy /* Device interface */ 1473251195Sgibbs DEVMETHOD(device_probe, xbd_probe), 1474251195Sgibbs DEVMETHOD(device_attach, xbd_attach), 1475251195Sgibbs DEVMETHOD(device_detach, xbd_detach), 1476185605Skmacy DEVMETHOD(device_shutdown, bus_generic_shutdown), 1477251195Sgibbs DEVMETHOD(device_suspend, xbd_suspend), 1478251195Sgibbs DEVMETHOD(device_resume, xbd_resume), 1479185605Skmacy 1480185605Skmacy /* Xenbus interface */ 1481251195Sgibbs DEVMETHOD(xenbus_otherend_changed, xbd_backend_changed), 1482181643Skmacy 1483185605Skmacy { 0, 0 } 1484185605Skmacy}; 1485181643Skmacy 1486251195Sgibbsstatic driver_t xbd_driver = { 1487185605Skmacy "xbd", 1488251195Sgibbs xbd_methods, 1489251195Sgibbs sizeof(struct xbd_softc), 1490185605Skmacy}; 1491251195Sgibbsdevclass_t xbd_devclass; 1492185605Skmacy 1493251195SgibbsDRIVER_MODULE(xbd, xenbusb_front, xbd_driver, xbd_devclass, 0, 0); 1494