xdf.c revision a576ab5b6e08c47732b3dedca9eaa8a8cbb85720
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER START
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The contents of this file are subject to the terms of the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Common Development and Distribution License (the "License").
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You may not use this file except in compliance with the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
843e19887f64dde75055cf8842fc4db2171eff45johnlev * or http://www.opensolaris.org/os/licensing.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * See the License for the specific language governing permissions
843e19887f64dde75055cf8842fc4db2171eff45johnlev * and limitations under the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * When distributing Covered Code, include this CDDL HEADER in each
843e19887f64dde75055cf8842fc4db2171eff45johnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If applicable, add the following below this CDDL HEADER, with the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * fields enclosed by brackets "[]" replaced with your own identifying
843e19887f64dde75055cf8842fc4db2171eff45johnlev * information: Portions Copyright [yyyy] [name of copyright owner]
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER END
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Use is subject to license terms.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * xdf.c - Xen Virtual Block Device Driver
843e19887f64dde75055cf8842fc4db2171eff45johnlev * TODO:
843e19887f64dde75055cf8842fc4db2171eff45johnlev * - support alternate block size (currently only DEV_BSIZE supported)
843e19887f64dde75055cf8842fc4db2171eff45johnlev * - revalidate geometry for removable devices
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#pragma ident "%Z%%M% %I% %E% SMI"
843e19887f64dde75055cf8842fc4db2171eff45johnlev
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/types.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/conf.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/ddi.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/dditypes.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/sunddi.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/list.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/cmlb.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/dkio.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/vtoc.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/modctl.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/bootconf.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/promif.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/sysmacros.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/kstat.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/mach_mmu.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#ifdef XPV_HVM_DRIVER
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/xpv_support.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#endif
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <public/io/xenbus.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <xen/sys/xenbus_impl.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <xen/sys/xendev.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/gnttab.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <sys/scsi/generic/inquiry.h>
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include <xen/io/blkif_impl.h>
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#include <io/xdf.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define FLUSH_DISKCACHE 0x1
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define WRITE_BARRIER 0x2
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define DEFAULT_FLUSH_BLOCK 156 /* block to write to cause a cache flush */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define USE_WRITE_BARRIER(vdp) \
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((vdp)->xdf_feature_barrier && !(vdp)->xdf_flush_supported)
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define USE_FLUSH_DISKCACHE(vdp) \
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((vdp)->xdf_feature_barrier && (vdp)->xdf_flush_supported)
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define IS_WRITE_BARRIER(vdp, bp) \
843e19887f64dde75055cf8842fc4db2171eff45johnlev (!IS_READ(bp) && USE_WRITE_BARRIER(vdp) && \
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((bp)->b_un.b_addr == (vdp)->xdf_cache_flush_block))
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define IS_FLUSH_DISKCACHE(bp) \
843e19887f64dde75055cf8842fc4db2171eff45johnlev (!IS_READ(bp) && USE_FLUSH_DISKCACHE(vdp) && ((bp)->b_bcount == 0))
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void *vbd_ss;
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic kmem_cache_t *xdf_vreq_cache;
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic kmem_cache_t *xdf_gs_cache;
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_maxphys = XB_MAXPHYS;
843e19887f64dde75055cf8842fc4db2171eff45johnlevint xdfdebug = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlevextern int do_polled_io;
843e19887f64dde75055cf8842fc4db2171eff45johnlevdiskaddr_t xdf_flush_block = DEFAULT_FLUSH_BLOCK;
843e19887f64dde75055cf8842fc4db2171eff45johnlevint xdf_barrier_flush_disable = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * dev_ops and cb_ops entrypoints
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_attach(dev_info_t *, ddi_attach_cmd_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_detach(dev_info_t *, ddi_detach_cmd_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_reset(dev_info_t *, ddi_reset_cmd_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_open(dev_t *, int, int, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_close(dev_t, int, int, struct cred *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_strategy(struct buf *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_read(dev_t, struct uio *, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_aread(dev_t, struct aio_req *, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_write(dev_t, struct uio *, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_awrite(dev_t, struct aio_req *, cred_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_dump(dev_t, caddr_t, daddr_t, int);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic uint_t xdf_intr(caddr_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
843e19887f64dde75055cf8842fc4db2171eff45johnlev caddr_t, int *);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * misc private functions
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_suspend(dev_info_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_resume(dev_info_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_start_connect(xdf_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_start_disconnect(xdf_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_post_connect(xdf_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void xdf_post_disconnect(xdf_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void xdf_oe_change(dev_info_t *, ddi_eventcookie_t, void *, void *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void xdf_iostart(xdf_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void xdf_iofini(xdf_t *, uint64_t, int);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_prepare_rreq(xdf_t *, struct buf *, blkif_request_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_drain_io(xdf_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic boolean_t xdf_isopen(xdf_t *, int);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_check_state_transition(xdf_t *, XenbusState);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_connect(xdf_t *, boolean_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_dmacallback(caddr_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void xdf_timeout_handler(void *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic uint_t xdf_iorestart(caddr_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic v_req_t *vreq_get(xdf_t *, buf_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void vreq_free(xdf_t *, v_req_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int vreq_setup(xdf_t *, v_req_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic ge_slot_t *gs_get(xdf_t *, int);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void gs_free(xdf_t *, ge_slot_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic grant_ref_t gs_grant(ge_slot_t *, mfn_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void unexpectedie(xdf_t *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void xdfmin(struct buf *);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct cb_ops xdf_cbops = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_open,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_close,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_strategy,
843e19887f64dde75055cf8842fc4db2171eff45johnlev nodev,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_dump,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_read,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_write,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_ioctl,
843e19887f64dde75055cf8842fc4db2171eff45johnlev nodev,
843e19887f64dde75055cf8842fc4db2171eff45johnlev nodev,
843e19887f64dde75055cf8842fc4db2171eff45johnlev nodev,
843e19887f64dde75055cf8842fc4db2171eff45johnlev nochpoll,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_prop_op,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL,
843e19887f64dde75055cf8842fc4db2171eff45johnlev D_MP | D_NEW | D_64BIT,
843e19887f64dde75055cf8842fc4db2171eff45johnlev CB_REV,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_aread,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_awrite
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstruct dev_ops xdf_devops = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DEVO_REV, /* devo_rev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev 0, /* devo_refcnt */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_getinfo, /* devo_getinfo */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nulldev, /* devo_identify */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nulldev, /* devo_probe */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_attach, /* devo_attach */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_detach, /* devo_detach */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_reset, /* devo_reset */
843e19887f64dde75055cf8842fc4db2171eff45johnlev &xdf_cbops, /* devo_cb_ops */
843e19887f64dde75055cf8842fc4db2171eff45johnlev (struct bus_ops *)NULL /* devo_bus_ops */
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct modldrv modldrv = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev &mod_driverops, /* Type of module. This one is a driver */
843e19887f64dde75055cf8842fc4db2171eff45johnlev "virtual block driver %I%", /* short description */
843e19887f64dde75055cf8842fc4db2171eff45johnlev &xdf_devops /* driver specific ops */
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct modlinkage xdf_modlinkage = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev MODREV_1, (void *)&modldrv, NULL
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * I/O buffer DMA attributes
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Make sure: one DMA window contains BLKIF_MAX_SEGMENTS_PER_REQUEST at most
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic ddi_dma_attr_t xb_dma_attr = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DMA_ATTR_V0,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (uint64_t)0, /* lowest address */
843e19887f64dde75055cf8842fc4db2171eff45johnlev (uint64_t)0xffffffffffffffff, /* highest usable address */
843e19887f64dde75055cf8842fc4db2171eff45johnlev (uint64_t)0xffffff, /* DMA counter limit max */
843e19887f64dde75055cf8842fc4db2171eff45johnlev (uint64_t)XB_BSIZE, /* alignment in bytes */
843e19887f64dde75055cf8842fc4db2171eff45johnlev XB_BSIZE - 1, /* bitmap of burst sizes */
843e19887f64dde75055cf8842fc4db2171eff45johnlev XB_BSIZE, /* min transfer */
843e19887f64dde75055cf8842fc4db2171eff45johnlev (uint64_t)XB_MAX_XFER, /* maximum transfer */
843e19887f64dde75055cf8842fc4db2171eff45johnlev (uint64_t)PAGEOFFSET, /* 1 page segment length */
843e19887f64dde75055cf8842fc4db2171eff45johnlev BLKIF_MAX_SEGMENTS_PER_REQUEST, /* maximum number of segments */
843e19887f64dde75055cf8842fc4db2171eff45johnlev XB_BSIZE, /* granularity */
843e19887f64dde75055cf8842fc4db2171eff45johnlev 0, /* flags (reserved) */
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic ddi_device_acc_attr_t xc_acc_attr = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DDI_DEVICE_ATTR_V0,
843e19887f64dde75055cf8842fc4db2171eff45johnlev DDI_NEVERSWAP_ACC,
843e19887f64dde75055cf8842fc4db2171eff45johnlev DDI_STRICTORDER_ACC
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* callbacks from commmon label */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_lb_rdwr(dev_info_t *, uchar_t, void *, diskaddr_t, size_t,
843e19887f64dde75055cf8842fc4db2171eff45johnlev void *);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xdf_lb_getinfo(dev_info_t *, int, void *, void *);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic cmlb_tg_ops_t xdf_lb_ops = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev TG_DK_OPS_VERSION_1,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_lb_rdwr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_lb_getinfo
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlev_init(void)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int rc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((rc = ddi_soft_state_init(&vbd_ss, sizeof (xdf_t), 0)) == 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_vreq_cache = kmem_cache_create("xdf_vreq_cache",
843e19887f64dde75055cf8842fc4db2171eff45johnlev sizeof (v_req_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(xdf_vreq_cache != NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_gs_cache = kmem_cache_create("xdf_gs_cache",
843e19887f64dde75055cf8842fc4db2171eff45johnlev sizeof (ge_slot_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(xdf_gs_cache != NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((rc = mod_install(&xdf_modlinkage)) != 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_cache_destroy(xdf_vreq_cache);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_cache_destroy(xdf_gs_cache);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_soft_state_fini(&vbd_ss);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (rc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlev_fini(void)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((err = mod_remove(&xdf_modlinkage)) != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (err);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_cache_destroy(xdf_vreq_cache);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_cache_destroy(xdf_gs_cache);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_soft_state_fini(&vbd_ss);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlev_info(struct modinfo *modinfop)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (mod_info(&xdf_modlinkage, modinfop));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **rp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int instance;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vbdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev instance = XDF_INST(getminor((dev_t)arg));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (cmd) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_INFO_DEVT2DEVINFO:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vbdp = ddi_get_soft_state(vbd_ss, instance)) == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev *rp = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev *rp = vbdp->xdf_dip;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_INFO_DEVT2INSTANCE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev *rp = (void *)(uintptr_t)instance;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *name, caddr_t valuep, int *lengthp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int instance = ddi_get_instance(dip);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev diskaddr_t p_blkcnt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * xdf dynamic properties are device specific and size oriented.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Requests issued under conditions where size is valid are passed
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to ddi_prop_op_nblocks with the size information, otherwise the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * request is passed to ddi_prop_op.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp = ddi_get_soft_state(vbd_ss, instance);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((dev == DDI_DEV_T_ANY) || (vdp == NULL))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ddi_prop_op(dev, dip, prop_op, mod_flags,
843e19887f64dde75055cf8842fc4db2171eff45johnlev name, valuep, lengthp));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* do cv_wait until connected or failed */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_connect(vdp, B_TRUE) != XD_READY) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto out;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cmlb_partinfo(vdp->xdf_vd_lbl, XDF_PART(getminor(dev)), &p_blkcnt,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, NULL, NULL, NULL) == 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
843e19887f64dde75055cf8842fc4db2171eff45johnlev name, valuep, lengthp, (uint64_t)p_blkcnt));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevout:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ddi_prop_op(dev, dip, prop_op, mod_flags, name, valuep,
843e19887f64dde75055cf8842fc4db2171eff45johnlev lengthp));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_iblock_cookie_t ibc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_iblock_cookie_t softibc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int instance;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdfdebug = ddi_prop_get_int(DDI_DEV_T_ANY, devi, DDI_PROP_NOTPROM,
843e19887f64dde75055cf8842fc4db2171eff45johnlev "xdfdebug", 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (cmd) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_ATTACH:
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_RESUME:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (xdf_resume(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev instance = ddi_get_instance(devi);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_soft_state_zalloc(vbd_ss, instance) != DDI_SUCCESS)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DDI_DBG, ("xdf%d: attaching\n", instance));
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp = ddi_get_soft_state(vbd_ss, instance);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_dip = devi;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_get_iblock_cookie(devi, 0, &ibc) != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to get iblock cookie",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_init(&vdp->xdf_dev_lk, NULL, MUTEX_DRIVER, (void *)ibc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_init(&vdp->xdf_cb_lk, NULL, MUTEX_DRIVER, (void *)ibc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev cv_init(&vdp->xdf_dev_cv, NULL, CV_DEFAULT, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_set_driver_private(devi, vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_get_soft_iblock_cookie(devi, DDI_SOFTINT_LOW, &softibc)
843e19887f64dde75055cf8842fc4db2171eff45johnlev != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to get softintr iblock cookie",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout2;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_add_softintr(devi, DDI_SOFTINT_LOW, &vdp->xdf_softintr_id,
843e19887f64dde75055cf8842fc4db2171eff45johnlev &softibc, NULL, xdf_iorestart, (caddr_t)vdp) != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to add softintr",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout2;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * create kstat for iostat(1M)
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vdp->xdf_xdev_iostat = kstat_create("xdf", instance, NULL, "disk",
843e19887f64dde75055cf8842fc4db2171eff45johnlev KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT)) != NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_xdev_iostat->ks_lock = &vdp->xdf_dev_lk;
843e19887f64dde75055cf8842fc4db2171eff45johnlev kstat_install(vdp->xdf_xdev_iostat);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to create kstat",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout3;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * driver handles kernel-issued IOCTLs
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP,
843e19887f64dde75055cf8842fc4db2171eff45johnlev DDI_KERNEL_IOCTL, NULL, 0) != DDI_PROP_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: cannot create DDI_KERNEL_IOCTL prop",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout4;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * create default device minor nodes: non-removable disk
843e19887f64dde75055cf8842fc4db2171eff45johnlev * we will adjust minor nodes after we are connected w/ backend
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmlb_alloc_handle(&vdp->xdf_vd_lbl);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cmlb_attach(devi, &xdf_lb_ops, DTYPE_DIRECT, 0, 1, DDI_NT_BLOCK,
843e19887f64dde75055cf8842fc4db2171eff45johnlev CMLB_FAKE_LABEL_ONE_PARTITION, vdp->xdf_vd_lbl, NULL) != 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: default cmlb attach failed",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout5;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * We ship with cache-enabled disks
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_wce = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Watch backend XenbusState change */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xvdi_add_event_handler(devi, XS_OE_STATE,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_oe_change) != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout6;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_start_connect(vdp) != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: start connection failed",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xdf_start_disconnect(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout7;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_create(&vdp->xdf_vreq_act, sizeof (v_req_t),
843e19887f64dde75055cf8842fc4db2171eff45johnlev offsetof(v_req_t, v_link));
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_create(&vdp->xdf_gs_act, sizeof (ge_slot_t),
843e19887f64dde75055cf8842fc4db2171eff45johnlev offsetof(ge_slot_t, link));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_report_dev(devi);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DDI_DBG, ("xdf%d: attached\n", instance));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout7:
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_remove_event_handler(devi, XS_OE_STATE);
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout6:
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmlb_detach(vdp->xdf_vd_lbl, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout5:
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmlb_free_handle(&vdp->xdf_vd_lbl);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_prop_remove_all(devi);
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout4:
843e19887f64dde75055cf8842fc4db2171eff45johnlev kstat_delete(vdp->xdf_xdev_iostat);
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout3:
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_remove_softintr(vdp->xdf_softintr_id);
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout2:
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_set_driver_private(devi, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev cv_destroy(&vdp->xdf_dev_cv);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_destroy(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_destroy(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout1:
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: attach failed", ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_soft_state_free(vbd_ss, instance);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int instance;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (cmd) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_PM_SUSPEND:
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_SUSPEND:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (xdf_suspend(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DDI_DETACH:
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev instance = ddi_get_instance(devi);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DDI_DBG, ("xdf%d: detaching\n", instance));
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp = ddi_get_soft_state(vbd_ss, instance);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_isopen(vdp, -1)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_status != XD_CLOSED) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(!ISDMACBON(vdp));
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_timeout_id != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) untimeout(vdp->xdf_timeout_id);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_remove_event_handler(devi, XS_OE_STATE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* we'll support backend running in domU later */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifdef DOMU_BACKEND
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xvdi_post_event(devi, XEN_HP_REMOVE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_destroy(&vdp->xdf_vreq_act);
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_destroy(&vdp->xdf_gs_act);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_prop_remove_all(devi);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kstat_delete(vdp->xdf_xdev_iostat);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_remove_softintr(vdp->xdf_softintr_id);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_set_driver_private(devi, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev cv_destroy(&vdp->xdf_dev_cv);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_destroy(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_destroy(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_cache_flush_block != NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(vdp->xdf_flush_mem, 2 * DEV_BSIZE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_soft_state_free(vbd_ss, instance);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_suspend(dev_info_t *devi)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int instance;
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev enum xdf_state st;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev instance = ddi_get_instance(devi);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdfdebug & SUSRES_DBG)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xen_printf("xdf_suspend: xdf#%d\n", instance);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vdp = ddi_get_soft_state(vbd_ss, instance)) == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_suspend(devi);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev st = vdp->xdf_status;
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev /* change status to stop further I/O requests */
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev if (st == XD_READY)
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev vdp->xdf_status = XD_SUSPEND;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* make sure no more I/O responses left in the ring buffer */
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev if ((st == XD_INIT) || (st == XD_READY)) {
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#ifdef XPV_HVM_DRIVER
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj ec_unbind_evtchn(vdp->xdf_evtchn);
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#else
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev (void) ddi_remove_intr(devi, 0, NULL);
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#endif
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev (void) xdf_drain_io(vdp);
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev /*
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev * no need to teardown the ring buffer here
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev * it will be simply re-init'ed during resume when
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev * we call xvdi_alloc_ring
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev */
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdfdebug & SUSRES_DBG)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xen_printf("xdf_suspend: SUCCESS\n");
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_resume(dev_info_t *devi)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int instance;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev instance = ddi_get_instance(devi);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdfdebug & SUSRES_DBG)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xen_printf("xdf_resume: xdf%d\n", instance);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vdp = ddi_get_soft_state(vbd_ss, instance)) == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xvdi_resume(devi) != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
1d03c31e0733adea0edef54f0d5d2ea9639ecd2ajohnlev ASSERT(vdp->xdf_status != XD_READY);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_status = XD_UNKNOWN;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_start_connect(vdp) != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdfdebug & SUSRES_DBG)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xen_printf("xdf_resume: done\n");
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_reset(dev_info_t *devi, ddi_reset_cmd_t cmd)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int instance;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev instance = ddi_get_instance(devi);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DDI_DBG, ("xdf%d: resetting\n", instance));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vdp = ddi_get_soft_state(vbd_ss, instance)) == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * wait for any outstanding I/O to complete
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xdf_drain_io(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DDI_DBG, ("xdf%d: reset complete\n", instance));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_open(dev_t *devp, int flag, int otyp, cred_t *credp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ulong_t parbit;
843e19887f64dde75055cf8842fc4db2171eff45johnlev diskaddr_t p_blkct = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev boolean_t firstopen;
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz boolean_t nodelay;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz nodelay = (flag & (FNDELAY | FNONBLOCK));
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor = getminor(*devp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vdp = ddi_get_soft_state(vbd_ss, XDF_INST(minor))) == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DDI_DBG, ("xdf%d: opening\n", XDF_INST(minor)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* do cv_wait until connected or failed */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz if (!nodelay && (xdf_connect(vdp, B_TRUE) != XD_READY)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((flag & FWRITE) && XD_IS_RO(vdp)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EROFS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev part = XDF_PART(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev parbit = 1 << part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_vd_exclopen & parbit) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EBUSY);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* are we the first one to open this node? */
843e19887f64dde75055cf8842fc4db2171eff45johnlev firstopen = !xdf_isopen(vdp, -1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((flag & FEXCL) && !firstopen) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EBUSY);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (otyp == OTYP_LYR)
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_vd_lyropen[part]++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_vd_open[otyp] |= parbit;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (flag & FEXCL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_vd_exclopen |= parbit;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* force a re-validation */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (firstopen)
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmlb_invalidate(vdp->xdf_vd_lbl, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * check size
843e19887f64dde75055cf8842fc4db2171eff45johnlev * ignore CD/DVD which contains a zero-sized s0
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz if (!nodelay && !XD_IS_CD(vdp) &&
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((cmlb_partinfo(vdp->xdf_vd_lbl, part, &p_blkct,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, NULL, NULL, NULL) != 0) || (p_blkct == 0))) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xdf_close(*devp, flag, otyp, credp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_close(dev_t dev, int flag, int otyp, struct cred *credp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ulong_t parbit;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor = getminor(dev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vdp = ddi_get_soft_state(vbd_ss, XDF_INST(minor))) == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev part = XDF_PART(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!xdf_isopen(vdp, part)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev parbit = 1 << part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (otyp == OTYP_LYR) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_vd_lyropen[part] != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_vd_lyropen[part]--;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_vd_lyropen[part] == 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_vd_open[OTYP_LYR] &= ~parbit;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_vd_open[otyp] &= ~parbit;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_vd_exclopen &= ~parbit;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_strategy(struct buf *bp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor;
843e19887f64dde75055cf8842fc4db2171eff45johnlev diskaddr_t p_blkct, p_blkst;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ulong_t nblks;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor = getminor(bp->b_edev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev part = XDF_PART(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!(vdp = ddi_get_soft_state(vbd_ss, XDF_INST(minor))) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev !xdf_isopen(vdp, part) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmlb_partinfo(vdp->xdf_vd_lbl, part, &p_blkct,
843e19887f64dde75055cf8842fc4db2171eff45johnlev &p_blkst, NULL, NULL, NULL)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev bioerror(bp, ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_resid = bp->b_bcount;
843e19887f64dde75055cf8842fc4db2171eff45johnlev biodone(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!IS_READ(bp) && XD_IS_RO(vdp)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev bioerror(bp, EROFS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_resid = bp->b_bcount;
843e19887f64dde75055cf8842fc4db2171eff45johnlev biodone(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * starting beyond partition
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (bp->b_blkno > p_blkct) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, ("xdf: block %lld exceeds VBD size %"PRIu64,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (longlong_t)bp->b_blkno, (uint64_t)p_blkct));
843e19887f64dde75055cf8842fc4db2171eff45johnlev bioerror(bp, EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_resid = bp->b_bcount;
843e19887f64dde75055cf8842fc4db2171eff45johnlev biodone(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Legacy: don't set error flag at this case */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (bp->b_blkno == p_blkct) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_resid = bp->b_bcount;
843e19887f64dde75055cf8842fc4db2171eff45johnlev biodone(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * adjust for partial transfer
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev nblks = bp->b_bcount >> XB_BSHIFT;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((bp->b_blkno + nblks) > p_blkct) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_resid = ((bp->b_blkno + nblks) - p_blkct) << XB_BSHIFT;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_bcount -= bp->b_resid;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, ("xdf: strategy blk %lld len %lu\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev (longlong_t)bp->b_blkno, (ulong_t)bp->b_bcount));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kstat_waitq_enter(KSTAT_IO_PTR(vdp->xdf_xdev_iostat));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_f_act == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_f_act = vdp->xdf_l_act = bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_l_act->av_forw = bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_l_act = bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->av_forw = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->av_back = NULL; /* not tagged with a v_req */
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_private = (void *)(uintptr_t)p_blkst;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_iostart(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (do_polled_io)
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xdf_drain_io(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_read(dev_t dev, struct uio *uiop, cred_t *credp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor;
843e19887f64dde75055cf8842fc4db2171eff45johnlev diskaddr_t p_blkcnt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor = getminor(dev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!(vdp = ddi_get_soft_state(vbd_ss, XDF_INST(minor))))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, ("xdf: read offset 0x%"PRIx64"\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev (int64_t)uiop->uio_offset));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev part = XDF_PART(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!xdf_isopen(vdp, part))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cmlb_partinfo(vdp->xdf_vd_lbl, part, &p_blkcnt,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, NULL, NULL, NULL))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (U_INVAL(uiop))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (physio(xdf_strategy, NULL, dev, B_READ, xdfmin, uiop));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_write(dev_t dev, struct uio *uiop, cred_t *credp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor;
843e19887f64dde75055cf8842fc4db2171eff45johnlev diskaddr_t p_blkcnt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor = getminor(dev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!(vdp = ddi_get_soft_state(vbd_ss, XDF_INST(minor))))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, ("xdf: write offset 0x%"PRIx64"\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev (int64_t)uiop->uio_offset));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev part = XDF_PART(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!xdf_isopen(vdp, part))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cmlb_partinfo(vdp->xdf_vd_lbl, part, &p_blkcnt,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, NULL, NULL, NULL))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (uiop->uio_loffset >= XB_DTOB(p_blkcnt))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENOSPC);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (U_INVAL(uiop))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (physio(xdf_strategy, NULL, dev, B_WRITE, minphys, uiop));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_aread(dev_t dev, struct aio_req *aiop, cred_t *credp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct uio *uiop = aiop->aio_uio;
843e19887f64dde75055cf8842fc4db2171eff45johnlev diskaddr_t p_blkcnt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor = getminor(dev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!(vdp = ddi_get_soft_state(vbd_ss, XDF_INST(minor))))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev part = XDF_PART(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!xdf_isopen(vdp, part))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cmlb_partinfo(vdp->xdf_vd_lbl, part, &p_blkcnt,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, NULL, NULL, NULL))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (uiop->uio_loffset >= XB_DTOB(p_blkcnt))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENOSPC);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (U_INVAL(uiop))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (aphysio(xdf_strategy, anocancel, dev, B_READ, minphys, aiop));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_awrite(dev_t dev, struct aio_req *aiop, cred_t *credp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct uio *uiop = aiop->aio_uio;
843e19887f64dde75055cf8842fc4db2171eff45johnlev diskaddr_t p_blkcnt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor = getminor(dev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!(vdp = ddi_get_soft_state(vbd_ss, XDF_INST(minor))))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev part = XDF_PART(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!xdf_isopen(vdp, part))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cmlb_partinfo(vdp->xdf_vd_lbl, part, &p_blkcnt,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, NULL, NULL, NULL))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (uiop->uio_loffset >= XB_DTOB(p_blkcnt))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENOSPC);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (U_INVAL(uiop))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (aphysio(xdf_strategy, anocancel, dev, B_WRITE, minphys, aiop));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct buf dumpbuf, *dbp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int err = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev diskaddr_t p_blkcnt, p_blkst;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor = getminor(dev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!(vdp = ddi_get_soft_state(vbd_ss, XDF_INST(minor))))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, ("xdf: dump addr (0x%p) blk (%ld) nblks (%d)\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev addr, blkno, nblk));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev part = XDF_PART(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!xdf_isopen(vdp, part))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cmlb_partinfo(vdp->xdf_vd_lbl, part, &p_blkcnt, &p_blkst,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, NULL, NULL))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((blkno + nblk) > p_blkcnt) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf: block %ld exceeds VBD size %"PRIu64,
843e19887f64dde75055cf8842fc4db2171eff45johnlev blkno + nblk, (uint64_t)vdp->xdf_xdev_nblocks);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp = &dumpbuf;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bioinit(dbp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp->b_flags = B_BUSY;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp->b_un.b_addr = addr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp->b_bcount = nblk << DEV_BSHIFT;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp->b_resid = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp->b_blkno = blkno;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp->b_edev = dev;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp->b_private = (void *)(uintptr_t)p_blkst;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kstat_waitq_enter(KSTAT_IO_PTR(vdp->xdf_xdev_iostat));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_f_act == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_f_act = vdp->xdf_l_act = dbp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_l_act->av_forw = dbp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_l_act = dbp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp->av_forw = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dbp->av_back = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_iostart(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev err = xdf_drain_io(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev biofini(dbp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (err);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
843e19887f64dde75055cf8842fc4db2171eff45johnlev int *rvalp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int instance;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor_t minor;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev minor = getminor(dev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev instance = XDF_INST(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vdp = ddi_get_soft_state(vbd_ss, instance)) == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IOCTL_DBG, ("xdf%d:ioctl: cmd %d (0x%x)\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev instance, cmd, cmd));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev part = XDF_PART(minor);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!xdf_isopen(vdp, part))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (cmd) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCGMEDIAINFO: {
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct dk_minfo media_info;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev media_info.dki_lbsize = DEV_BSIZE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev media_info.dki_capacity = vdp->xdf_xdev_nblocks;
843e19887f64dde75055cf8842fc4db2171eff45johnlev media_info.dki_media_type = DK_FIXED_DISK;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_copyout(&media_info, (void *)arg,
843e19887f64dde75055cf8842fc4db2171eff45johnlev sizeof (struct dk_minfo), mode)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EFAULT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCINFO: {
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct dk_cinfo info;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* controller information */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (XD_IS_CD(vdp))
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_ctype = DKC_CDROM;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_ctype = DKC_VBD;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_cnum = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) strncpy((char *)(&info.dki_cname), "xdf", 8);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* unit information */
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_unit = ddi_get_instance(vdp->xdf_dip);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) strncpy((char *)(&info.dki_dname), "xdf", 8);
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_flags = DKI_FMTVOL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_partition = part;
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_maxtransfer = maxphys / DEV_BSIZE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_addr = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_space = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_prio = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev info.dki_vec = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_copyout(&info, (void *)arg, sizeof (info), mode))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EFAULT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCSTATE: {
843e19887f64dde75055cf8842fc4db2171eff45johnlev enum dkio_state dkstate = DKIO_INSERTED;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_copyout(&dkstate, (void *)arg, sizeof (dkstate),
843e19887f64dde75055cf8842fc4db2171eff45johnlev mode) != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EFAULT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * is media removable?
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCREMOVABLE: {
843e19887f64dde75055cf8842fc4db2171eff45johnlev int i = XD_IS_RM(vdp) ? 1 : 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), mode))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EFAULT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCG_PHYGEOM:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCG_VIRTGEOM:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCGGEOM:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCSGEOM:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCGAPART:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCGVTOC:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCSVTOC:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCPARTINFO:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCGETEFI:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCSETEFI:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCPARTITION: {
843e19887f64dde75055cf8842fc4db2171eff45johnlev int rc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = cmlb_ioctl(vdp->xdf_vd_lbl, dev, cmd, arg, mode, credp,
843e19887f64dde75055cf8842fc4db2171eff45johnlev rvalp, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (rc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCGETWCE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_copyout(&vdp->xdf_wce, (void *)arg,
843e19887f64dde75055cf8842fc4db2171eff45johnlev sizeof (vdp->xdf_wce), mode))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EFAULT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCSETWCE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_copyin((void *)arg, &vdp->xdf_wce,
843e19887f64dde75055cf8842fc4db2171eff45johnlev sizeof (vdp->xdf_wce), mode))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EFAULT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev case DKIOCFLUSHWRITECACHE: {
843e19887f64dde75055cf8842fc4db2171eff45johnlev int rc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct dk_callback *dkc = (struct dk_callback *)arg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_flush_supported) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = xdf_lb_rdwr(vdp->xdf_dip, TG_WRITE,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, 0, 0, (void *)dev);
63c3e6179df15229a074893be77318fc37933d2amrj } else if (vdp->xdf_feature_barrier &&
63c3e6179df15229a074893be77318fc37933d2amrj !xdf_barrier_flush_disable) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = xdf_lb_rdwr(vdp->xdf_dip, TG_WRITE,
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_cache_flush_block, xdf_flush_block,
843e19887f64dde75055cf8842fc4db2171eff45johnlev DEV_BSIZE, (void *)dev);
63c3e6179df15229a074893be77318fc37933d2amrj } else {
63c3e6179df15229a074893be77318fc37933d2amrj return (ENOTTY);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((mode & FKIOCTL) && (dkc != NULL) &&
843e19887f64dde75055cf8842fc4db2171eff45johnlev (dkc->dkc_callback != NULL)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev (*dkc->dkc_callback)(dkc->dkc_cookie, rc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* need to return 0 after calling callback */
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (rc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENOTTY);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * xdf interrupt handler
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic uint_t
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_intr(caddr_t arg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp = (xdf_t *)arg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xendev_ring_t *xbr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev blkif_response_t *resp;
b1a3e7f1642868df84107f6eb9f823e0b02c1ac3mrj int bioerr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint64_t id;
843e19887f64dde75055cf8842fc4db2171eff45johnlev extern int do_polled_io;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint8_t op;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint16_t status;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_acc_handle_t acchdl;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((xbr = vdp->xdf_xb_ring) == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_INTR_UNCLAIMED);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev acchdl = vdp->xdf_xb_ring_hdl;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * complete all requests which have a response
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (resp = xvdi_ring_get_response(xbr)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev id = ddi_get64(acchdl, &resp->id);
843e19887f64dde75055cf8842fc4db2171eff45johnlev op = ddi_get8(acchdl, &resp->operation);
843e19887f64dde75055cf8842fc4db2171eff45johnlev status = ddi_get16(acchdl, (uint16_t *)&resp->status);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(INTR_DBG, ("resp: op %d id %"PRIu64" status %d\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev op, id, status));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * XXPV - close connection to the backend and restart
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (status != BLKIF_RSP_OKAY) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, ("xdf@%s: I/O error while %s",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip),
843e19887f64dde75055cf8842fc4db2171eff45johnlev (op == BLKIF_OP_READ) ? "reading" : "writing"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev bioerr = EIO;
b1a3e7f1642868df84107f6eb9f823e0b02c1ac3mrj } else {
b1a3e7f1642868df84107f6eb9f823e0b02c1ac3mrj bioerr = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_iofini(vdp, id, bioerr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!do_polled_io)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_iostart(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_INTR_CLAIMED);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint xdf_fbrewrites; /* how many times was our flush block rewritten */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Snarf new data if our flush block was re-written
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevcheck_fbwrite(xdf_t *vdp, buf_t *bp, daddr_t blkno)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int nblks;
843e19887f64dde75055cf8842fc4db2171eff45johnlev boolean_t mapin;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (IS_WRITE_BARRIER(vdp, bp))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return; /* write was a flush write */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mapin = B_FALSE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev nblks = bp->b_bcount >> DEV_BSHIFT;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_flush_block >= blkno && xdf_flush_block < (blkno + nblks)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_fbrewrites++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (bp->b_flags & (B_PAGEIO | B_PHYS)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mapin = B_TRUE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp_mapin(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev bcopy(bp->b_un.b_addr +
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((xdf_flush_block - blkno) << DEV_BSHIFT),
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_cache_flush_block, DEV_BSIZE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mapin)
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp_mapout(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_iofini(xdf_t *vdp, uint64_t id, int bioerr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev ge_slot_t *gs = (ge_slot_t *)(uintptr_t)id;
843e19887f64dde75055cf8842fc4db2171eff45johnlev v_req_t *vreq = gs->vreq;
843e19887f64dde75055cf8842fc4db2171eff45johnlev buf_t *bp = vreq->v_buf;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs_free(vdp, gs);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (bioerr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev bioerror(bp, bioerr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_nslots--;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vreq->v_nslots != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev XDF_UPDATE_IO_STAT(vdp, bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kstat_runq_exit(KSTAT_IO_PTR(vdp->xdf_xdev_iostat));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (IS_ERROR(bp))
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_resid = bp->b_bcount;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq_free(vdp, vreq);
843e19887f64dde75055cf8842fc4db2171eff45johnlev biodone(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * return value of xdf_prepare_rreq()
843e19887f64dde75055cf8842fc4db2171eff45johnlev * used in xdf_iostart()
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XF_PARTIAL 0 /* rreq is full, not all I/O in buf transferred */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XF_COMP 1 /* no more I/O left in buf */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_iostart(xdf_t *vdp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xendev_ring_t *xbr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct buf *bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev blkif_request_t *rreq;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int retval;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int rreqready = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbr = vdp->xdf_xb_ring;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * populate the ring request(s)
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * loop until there is no buf to transfer or no free slot
843e19887f64dde75055cf8842fc4db2171eff45johnlev * available in I/O ring
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz for (;;) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_status != XD_READY)
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* active buf queue empty? */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((bp = vdp->xdf_f_act) == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* try to grab a vreq for this bp */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((BP2VREQ(bp) == NULL) && (vreq_get(vdp, bp) == NULL))
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* alloc DMA/GTE resources */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vreq_setup(vdp, BP2VREQ(bp)) != DDI_SUCCESS)
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* get next blkif_request in the ring */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((rreq = xvdi_ring_get_request(xbr)) == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bzero(rreq, sizeof (blkif_request_t));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* populate blkif_request with this buf */
843e19887f64dde75055cf8842fc4db2171eff45johnlev rreqready++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev retval = xdf_prepare_rreq(vdp, bp, rreq);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (retval == XF_COMP) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* finish this bp, switch to next one */
843e19887f64dde75055cf8842fc4db2171eff45johnlev kstat_waitq_to_runq(KSTAT_IO_PTR(vdp->xdf_xdev_iostat));
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_f_act = bp->av_forw;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->av_forw = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Send the request(s) to the backend
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rreqready) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xvdi_ring_push_request(xbr)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, ("xdf_iostart: "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "sent request(s) to backend\n"));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_notify_oe(vdp->xdf_dip);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * populate a single blkif_request_t w/ a buf
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_prepare_rreq(xdf_t *vdp, struct buf *bp, blkif_request_t *rreq)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int rval;
843e19887f64dde75055cf8842fc4db2171eff45johnlev grant_ref_t gr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint8_t fsect, lsect;
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t bcnt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev paddr_t dma_addr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev off_t blk_off;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dev_info_t *dip = vdp->xdf_dip;
843e19887f64dde75055cf8842fc4db2171eff45johnlev blkif_vdev_t vdev = xvdi_get_vdevnum(dip);
843e19887f64dde75055cf8842fc4db2171eff45johnlev v_req_t *vreq = BP2VREQ(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint64_t blkno = vreq->v_blkno;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint_t ndmacs = vreq->v_ndmacs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_acc_handle_t acchdl = vdp->xdf_xb_ring_hdl;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int seg = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int isread = IS_READ(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (isread)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put8(acchdl, &rreq->operation, BLKIF_OP_READ);
843e19887f64dde75055cf8842fc4db2171eff45johnlev else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (vreq->v_flush_diskcache) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case FLUSH_DISKCACHE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put8(acchdl, &rreq->operation,
843e19887f64dde75055cf8842fc4db2171eff45johnlev BLKIF_OP_FLUSH_DISKCACHE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put16(acchdl, &rreq->handle, vdev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put64(acchdl, &rreq->id,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (uint64_t)(uintptr_t)(vreq->v_gs));
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put8(acchdl, &rreq->nr_segments, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (XF_COMP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev case WRITE_BARRIER:
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put8(acchdl, &rreq->operation,
843e19887f64dde75055cf8842fc4db2171eff45johnlev BLKIF_OP_WRITE_BARRIER);
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!vdp->xdf_wce)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put8(acchdl, &rreq->operation,
843e19887f64dde75055cf8842fc4db2171eff45johnlev BLKIF_OP_WRITE_BARRIER);
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put8(acchdl, &rreq->operation,
843e19887f64dde75055cf8842fc4db2171eff45johnlev BLKIF_OP_WRITE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put16(acchdl, &rreq->handle, vdev);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put64(acchdl, &rreq->sector_number, blkno);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put64(acchdl, &rreq->id, (uint64_t)(uintptr_t)(vreq->v_gs));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * loop until all segments are populated or no more dma cookie in buf
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (;;) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Each segment of a blkif request can transfer up to
843e19887f64dde75055cf8842fc4db2171eff45johnlev * one 4K page of data.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev bcnt = vreq->v_dmac.dmac_size;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(bcnt <= PAGESIZE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT((bcnt % XB_BSIZE) == 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev dma_addr = vreq->v_dmac.dmac_laddress;
843e19887f64dde75055cf8842fc4db2171eff45johnlev blk_off = (uint_t)((paddr_t)XB_SEGOFFSET & dma_addr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT((blk_off & XB_BMASK) == 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev fsect = blk_off >> XB_BSHIFT;
843e19887f64dde75055cf8842fc4db2171eff45johnlev lsect = fsect + (bcnt >> XB_BSHIFT) - 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(fsect < XB_MAX_SEGLEN / XB_BSIZE &&
843e19887f64dde75055cf8842fc4db2171eff45johnlev lsect < XB_MAX_SEGLEN / XB_BSIZE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, (" ""seg%d: dmacS %lu blk_off %ld\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev seg, vreq->v_dmac.dmac_size, blk_off));
843e19887f64dde75055cf8842fc4db2171eff45johnlev gr = gs_grant(vreq->v_gs, PATOMA(dma_addr) >> PAGESHIFT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put32(acchdl, &rreq->seg[seg].gref, gr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put8(acchdl, &rreq->seg[seg].first_sect, fsect);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put8(acchdl, &rreq->seg[seg].last_sect, lsect);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, (" ""seg%d: fs %d ls %d gr %d dma 0x%"PRIx64
843e19887f64dde75055cf8842fc4db2171eff45johnlev "\n", seg, fsect, lsect, gr, dma_addr));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev blkno += (bcnt >> XB_BSHIFT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev seg++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(seg <= BLKIF_MAX_SEGMENTS_PER_REQUEST);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (--ndmacs) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_dma_nextcookie(vreq->v_dmahdl, &vreq->v_dmac);
843e19887f64dde75055cf8842fc4db2171eff45johnlev continue;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_status = VREQ_DMAWIN_DONE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_blkno = blkno;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vreq->v_dmaw + 1 == vreq->v_ndmaws)
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* last win */
843e19887f64dde75055cf8842fc4db2171eff45johnlev rval = XF_COMP;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev rval = XF_PARTIAL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_put8(acchdl, &rreq->nr_segments, seg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(IO_DBG, ("xdf_prepare_rreq: request id=%"PRIx64" ready\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev rreq->id));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (rval);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XDF_QSEC 50000 /* .005 second */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XDF_POLLCNT 12 /* loop for 12 times before time out */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_drain_io(xdf_t *vdp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int pollc, rval;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xendev_ring_t *xbr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdfdebug & SUSRES_DBG)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xen_printf("xdf_drain_io: start\n");
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vdp->xdf_status != XD_READY) && (vdp->xdf_status != XD_SUSPEND))
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto out;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev rval = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xbr = vdp->xdf_xb_ring;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(xbr != NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (pollc = 0; pollc < XDF_POLLCNT; pollc++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xvdi_ring_has_unconsumed_responses(xbr)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xdf_intr((caddr_t)vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!xvdi_ring_has_incomp_request(xbr))
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto out;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#ifndef XPV_HVM_DRIVER
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) HYPERVISOR_yield();
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * file-backed devices can be slow
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev drv_usecwait(XDF_QSEC << pollc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf_polled_io: timeout");
843e19887f64dde75055cf8842fc4db2171eff45johnlev rval = EIO;
843e19887f64dde75055cf8842fc4db2171eff45johnlevout:
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdfdebug & SUSRES_DBG)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xen_printf("xdf_drain_io: end, err=%d\n", rval);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (rval);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* ARGSUSED5 */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_lb_rdwr(dev_info_t *devi, uchar_t cmd, void *bufp,
843e19887f64dde75055cf8842fc4db2171eff45johnlev diskaddr_t start, size_t reqlen, void *tg_cookie)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct buf *bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int err = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp = ddi_get_soft_state(vbd_ss, ddi_get_instance(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((start + (reqlen >> DEV_BSHIFT)) > vdp->xdf_xdev_nblocks)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp = getrbuf(KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cmd == TG_READ)
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_flags = B_BUSY | B_READ;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_flags = B_BUSY | B_WRITE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_un.b_addr = bufp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_bcount = reqlen;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_resid = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_blkno = start;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->av_forw = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->av_back = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_edev = DDI_DEV_T_NONE; /* don't have dev_t */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kstat_waitq_enter(KSTAT_IO_PTR(vdp->xdf_xdev_iostat));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_f_act == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_f_act = vdp->xdf_l_act = bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_l_act->av_forw = bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_l_act = bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_iostart(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev err = biowait(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(bp->b_flags & B_DONE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev freerbuf(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (err);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * synthetic geometry
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XDF_NSECTS 256
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XDF_NHEADS 16
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_lb_getcap(dev_info_t *devi, diskaddr_t *capp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp = ddi_get_soft_state(vbd_ss, ddi_get_instance(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev *capp = vdp->xdf_xdev_nblocks;
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(LBL_DBG, ("capacity %llu\n", *capp));
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_lb_getpgeom(dev_info_t *devi, cmlb_geom_t *geomp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint_t ncyl;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint_t spc = XDF_NHEADS * XDF_NSECTS;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp = ddi_get_soft_state(vbd_ss, ddi_get_instance(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ncyl = vdp->xdf_xdev_nblocks / spc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev geomp->g_ncyl = ncyl == 0 ? 1 : ncyl;
843e19887f64dde75055cf8842fc4db2171eff45johnlev geomp->g_acyl = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev geomp->g_nhead = XDF_NHEADS;
843e19887f64dde75055cf8842fc4db2171eff45johnlev geomp->g_secsize = XB_BSIZE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev geomp->g_nsect = XDF_NSECTS;
843e19887f64dde75055cf8842fc4db2171eff45johnlev geomp->g_intrlv = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev geomp->g_rpm = 7200;
843e19887f64dde75055cf8842fc4db2171eff45johnlev geomp->g_capacity = vdp->xdf_xdev_nblocks;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * No real HBA, no geometry available from it
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_lb_getvgeom(dev_info_t *devi, cmlb_geom_t *geomp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_lb_getattribute(dev_info_t *devi, tg_attribute_t *tgattributep)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!(vdp = ddi_get_soft_state(vbd_ss, ddi_get_instance(devi))))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENXIO);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (XD_IS_RO(vdp))
843e19887f64dde75055cf8842fc4db2171eff45johnlev tgattributep->media_is_writable = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev tgattributep->media_is_writable = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* ARGSUSED3 */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_lb_getinfo(dev_info_t *devi, int cmd, void *arg, void *tg_cookie)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (cmd) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case TG_GETPHYGEOM:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (xdf_lb_getpgeom(devi, (cmlb_geom_t *)arg));
843e19887f64dde75055cf8842fc4db2171eff45johnlev case TG_GETVIRTGEOM:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (xdf_lb_getvgeom(devi, (cmlb_geom_t *)arg));
843e19887f64dde75055cf8842fc4db2171eff45johnlev case TG_GETCAPACITY:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (xdf_lb_getcap(devi, (diskaddr_t *)arg));
843e19887f64dde75055cf8842fc4db2171eff45johnlev case TG_GETBLOCKSIZE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev *(uint32_t *)arg = XB_BSIZE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev case TG_GETATTR:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (xdf_lb_getattribute(devi, (tg_attribute_t *)arg));
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENOTTY);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Kick-off connect process
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Status should be XD_UNKNOWN or XD_CLOSED
843e19887f64dde75055cf8842fc4db2171eff45johnlev * On success, status will be changed to XD_INIT
843e19887f64dde75055cf8842fc4db2171eff45johnlev * On error, status won't be changed
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_start_connect(xdf_t *vdp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *xsnode;
843e19887f64dde75055cf8842fc4db2171eff45johnlev grant_ref_t gref;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xenbus_transaction_t xbt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int rv;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dev_info_t *dip = vdp->xdf_dip;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((vdp->xdf_peer = xvdi_get_oeid(dip)) == (domid_t)-1)
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xvdi_alloc_evtchn(dip) != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to alloc event channel",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj vdp->xdf_evtchn = xvdi_get_evtchn(dip);
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#ifdef XPV_HVM_DRIVER
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj ec_bind_evtchn_to_handler(vdp->xdf_evtchn, IPL_VBD, xdf_intr, vdp);
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#else
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ddi_add_intr(dip, 0, NULL, NULL, xdf_intr, (caddr_t)vdp) !=
843e19887f64dde75055cf8842fc4db2171eff45johnlev DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf_start_connect: xdf@%s: "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "failed to add intr handler", ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xvdi_alloc_ring(dip, BLKIF_RING_SIZE,
843e19887f64dde75055cf8842fc4db2171eff45johnlev sizeof (union blkif_sring_entry), &gref, &vdp->xdf_xb_ring) !=
843e19887f64dde75055cf8842fc4db2171eff45johnlev DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to alloc comm ring",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto errout2;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_xb_ring_hdl = vdp->xdf_xb_ring->xr_acc_hdl; /* ugly!! */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Write into xenstore the info needed by backend
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((xsnode = xvdi_get_xsname(dip)) == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "failed to get xenstore node path",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto fail_trans;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlevtrans_retry:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xenbus_transaction_start(&xbt)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to start transaction",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_fatal_error(dip, EIO, "transaction start");
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto fail_trans;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rv = xenbus_printf(xbt, xsnode, "ring-ref", "%u", gref)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to write ring-ref",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_fatal_error(dip, rv, "writing ring-ref");
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto abort_trans;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rv = xenbus_printf(xbt, xsnode, "event-channel", "%u",
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj vdp->xdf_evtchn)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to write event-channel",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_fatal_error(dip, rv, "writing event-channel");
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto abort_trans;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab /*
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * "protocol" is written by the domain builder in the case of PV
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * domains. However, it is not written for HVM domains, so let's
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * write it here.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (rv = xenbus_printf(xbt, xsnode, "protocol", "%s",
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab XEN_IO_PROTO_ABI_NATIVE)) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab cmn_err(CE_WARN, "xdf@%s: failed to write protocol",
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab ddi_get_name_addr(dip));
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab xvdi_fatal_error(dip, rv, "writing protocol");
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab goto abort_trans;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((rv = xvdi_switch_state(dip, xbt, XenbusStateInitialised)) > 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "failed to switch state to XenbusStateInitialised",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_fatal_error(dip, rv, "writing state");
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto abort_trans;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* kick-off connect process */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rv = xenbus_transaction_end(xbt, 0)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rv == EAGAIN)
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto trans_retry;
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: failed to end transaction",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_fatal_error(dip, rv, "completing transaction");
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto fail_trans;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(mutex_owned(&vdp->xdf_cb_lk));
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_status = XD_INIT;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevabort_trans:
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xenbus_transaction_end(xbt, 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlevfail_trans:
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_free_ring(vdp->xdf_xb_ring);
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout2:
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#ifdef XPV_HVM_DRIVER
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj ec_unbind_evtchn(vdp->xdf_evtchn);
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#else
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) ddi_remove_intr(vdp->xdf_dip, 0, NULL);
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#endif
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout1:
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_free_evtchn(dip);
843e19887f64dde75055cf8842fc4db2171eff45johnleverrout:
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: fail to kick-off connecting",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Kick-off disconnect process
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Status won't be changed
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_start_disconnect(xdf_t *vdp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xvdi_switch_state(vdp->xdf_dip, XBT_NULL, XenbusStateClosed) > 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: fail to kick-off disconnecting",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_get_flush_block(xdf_t *vdp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Get a DEV_BSIZE aligned bufer
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_flush_mem = kmem_alloc(DEV_BSIZE * 2, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_cache_flush_block =
843e19887f64dde75055cf8842fc4db2171eff45johnlev (char *)P2ROUNDUP((uintptr_t)(vdp->xdf_flush_mem), DEV_BSIZE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_lb_rdwr(vdp->xdf_dip, TG_READ, vdp->xdf_cache_flush_block,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_flush_block, DEV_BSIZE, NULL) != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Finish other initialization after we've connected to backend
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Status should be XD_INIT before calling this routine
843e19887f64dde75055cf8842fc4db2171eff45johnlev * On success, status should be changed to XD_READY
843e19887f64dde75055cf8842fc4db2171eff45johnlev * On error, status should stay XD_INIT
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_post_connect(xdf_t *vdp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int rv;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint_t len;
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *type;
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *barrier;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dev_info_t *devi = vdp->xdf_dip;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Determine if feature barrier is supported by backend
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xenbus_read(XBT_NULL, xvdi_get_oename(devi),
843e19887f64dde75055cf8842fc4db2171eff45johnlev "feature-barrier", (void **)&barrier, &len) == 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_feature_barrier = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(barrier, len);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_NOTE, "xdf@%s: failed to read feature-barrier",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_feature_barrier = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* probe backend */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rv = xenbus_gather(XBT_NULL, xvdi_get_oename(devi),
843e19887f64dde75055cf8842fc4db2171eff45johnlev "sectors", "%"SCNu64, &vdp->xdf_xdev_nblocks,
843e19887f64dde75055cf8842fc4db2171eff45johnlev "info", "%u", &vdp->xdf_xdev_info, NULL)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf_post_connect: xdf@%s: "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "cannot read backend info", ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_fatal_error(devi, rv, "reading backend info");
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* fix disk type */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xenbus_read(XBT_NULL, xvdi_get_xsname(devi), "device-type",
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void **)&type, &len) != 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf_post_connect: xdf@%s: "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "cannot read device-type", ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_fatal_error(devi, rv, "reading device-type");
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (strcmp(type, "cdrom") == 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_xdev_info |= VDISK_CDROM;
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(type, len);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * We've created all the minor nodes via cmlb_attach() using default
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj * value in xdf_attach() to make it possible to block in xdf_open(),
843e19887f64dde75055cf8842fc4db2171eff45johnlev * in case there's anyone (say, booting thread) ever trying to open
843e19887f64dde75055cf8842fc4db2171eff45johnlev * it before connected to backend. We will refresh all those minor
843e19887f64dde75055cf8842fc4db2171eff45johnlev * nodes w/ latest info we've got now when we are almost connected.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Don't do this when xdf is already opened by someone (could happen
843e19887f64dde75055cf8842fc4db2171eff45johnlev * during resume), for that cmlb_attach() will invalid the label info
843e19887f64dde75055cf8842fc4db2171eff45johnlev * and confuse those who has already opened the node, which is bad.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!xdf_isopen(vdp, -1) && (XD_IS_CD(vdp) || XD_IS_RM(vdp))) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* re-init cmlb w/ latest info we got from backend */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cmlb_attach(devi, &xdf_lb_ops,
843e19887f64dde75055cf8842fc4db2171eff45johnlev XD_IS_CD(vdp) ? DTYPE_RODIRECT : DTYPE_DIRECT,
843e19887f64dde75055cf8842fc4db2171eff45johnlev XD_IS_RM(vdp), 1, DDI_NT_BLOCK,
843e19887f64dde75055cf8842fc4db2171eff45johnlev CMLB_FAKE_LABEL_ONE_PARTITION,
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_vd_lbl, NULL) != 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: cmlb attach failed",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(devi));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* mark vbd is ready for I/O */
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(mutex_owned(&vdp->xdf_cb_lk));
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_status = XD_READY;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If backend has feature-barrier, see if it supports disk
843e19887f64dde75055cf8842fc4db2171eff45johnlev * cache flush op.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_flush_supported = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_feature_barrier) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Pretend we already know flush is supported so probe
843e19887f64dde75055cf8842fc4db2171eff45johnlev * will attempt the correct op.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_flush_supported = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_lb_rdwr(vdp->xdf_dip, TG_WRITE, NULL, 0, 0, 0) == 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_flush_supported = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_flush_supported = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If the other end does not support the cache flush op
843e19887f64dde75055cf8842fc4db2171eff45johnlev * then we must use a barrier-write to force disk
843e19887f64dde75055cf8842fc4db2171eff45johnlev * cache flushing. Barrier writes require that a data
843e19887f64dde75055cf8842fc4db2171eff45johnlev * block actually be written.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Cache a block to barrier-write when we are
843e19887f64dde75055cf8842fc4db2171eff45johnlev * asked to perform a flush.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * XXX - would it be better to just copy 1 block
843e19887f64dde75055cf8842fc4db2171eff45johnlev * (512 bytes) from whatever write we did last
843e19887f64dde75055cf8842fc4db2171eff45johnlev * and rewrite that block?
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_get_flush_block(vdp) != DDI_SUCCESS)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_CONT, "?xdf@%s: %"PRIu64" blocks", ddi_get_name_addr(devi),
843e19887f64dde75055cf8842fc4db2171eff45johnlev (uint64_t)vdp->xdf_xdev_nblocks);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Finish other uninitialization after we've disconnected from backend
843e19887f64dde75055cf8842fc4db2171eff45johnlev * when status is XD_CLOSING or XD_INIT. After returns, status is XD_CLOSED
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_post_disconnect(xdf_t *vdp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#ifdef XPV_HVM_DRIVER
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj ec_unbind_evtchn(vdp->xdf_evtchn);
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#else
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) ddi_remove_intr(vdp->xdf_dip, 0, NULL);
551bc2a66868b5cb5be6b70ab9f55515e77a39a9mrj#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_free_evtchn(vdp->xdf_dip);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xvdi_free_ring(vdp->xdf_xb_ring);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_xb_ring = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_xb_ring_hdl = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_peer = (domid_t)-1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(mutex_owned(&vdp->xdf_cb_lk));
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_status = XD_CLOSED;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_oe_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg, void *impl_data)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev XenbusState new_state = *(XenbusState *)impl_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp = (xdf_t *)ddi_get_driver_private(dip);
843e19887f64dde75055cf8842fc4db2171eff45johnlev boolean_t unexpect_die = B_FALSE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int status;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DDI_DBG, ("xdf@%s: otherend state change to %d!\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip), new_state));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_check_state_transition(vdp, new_state) == DDI_FAILURE) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (new_state) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XenbusStateInitialising:
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(vdp->xdf_status == XD_CLOSED);
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * backend recovered from a previous failure,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * kick-off connect process again
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_start_connect(vdp) != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s:"
843e19887f64dde75055cf8842fc4db2171eff45johnlev " failed to start reconnecting to backend",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XenbusStateConnected:
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(vdp->xdf_status == XD_INIT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateConnected);
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* finish final init after connect */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_post_connect(vdp) != DDI_SUCCESS)
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xdf_start_disconnect(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XenbusStateClosing:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_status == XD_READY) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_isopen(vdp, -1)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_NOTE, "xdf@%s: hot-unplug failed, "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "still in use", ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_status = XD_CLOSING;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xdf_start_disconnect(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XenbusStateClosed:
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* first check if BE closed unexpectedly */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xdf_isopen(vdp, -1)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev unexpect_die = B_TRUE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev unexpectedie(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "xdf@%s: backend closed, "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "reconnecting...", ddi_get_name_addr(dip));
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_status == XD_READY) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_status = XD_CLOSING;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifdef DOMU_BACKEND
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xvdi_post_event(dip, XEN_HP_REMOVE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_post_disconnect(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xvdi_switch_state(dip, XBT_NULL,
843e19887f64dde75055cf8842fc4db2171eff45johnlev XenbusStateClosed);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else if ((vdp->xdf_status == XD_INIT) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (vdp->xdf_status == XD_CLOSING)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_post_disconnect(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_status = XD_CLOSED;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* notify anybody waiting for oe state change */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev cv_broadcast(&vdp->xdf_dev_cv);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev status = vdp->xdf_status;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_cb_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (status == XD_READY) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_iostart(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else if ((status == XD_CLOSED) && !unexpect_die) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* interface is closed successfully, remove all minor nodes */
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmlb_detach(vdp->xdf_vd_lbl, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmlb_free_handle(&vdp->xdf_vd_lbl);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* check if partition is open, -1 - check all partitions on the disk */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic boolean_t
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_isopen(xdf_t *vdp, int partition)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int i;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ulong_t parbit;
843e19887f64dde75055cf8842fc4db2171eff45johnlev boolean_t rval = B_FALSE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (partition == -1)
843e19887f64dde75055cf8842fc4db2171eff45johnlev parbit = (ulong_t)-1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev parbit = 1 << partition;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (i = 0; i < OTYPCNT; i++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_vd_open[i] & parbit)
843e19887f64dde75055cf8842fc4db2171eff45johnlev rval = B_TRUE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (rval);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Xdf_check_state_transition will check the XenbusState change to see
843e19887f64dde75055cf8842fc4db2171eff45johnlev * if the change is a valid transition or not.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The new state is written by backend domain, or by running xenstore-write
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to change it manually in dom0
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_check_state_transition(xdf_t *vdp, XenbusState oestate)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int status;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int stcheck;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define STOK 0 /* need further process */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define STNOP 1 /* no action need taking */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define STBUG 2 /* unexpected state change, could be a bug */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev status = vdp->xdf_status;
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STOK;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (status) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XD_UNKNOWN:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((oestate == XenbusStateUnknown) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateConnected))
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STBUG;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else if ((oestate == XenbusStateInitialising) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitWait) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitialised))
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STNOP;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XD_INIT:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (oestate == XenbusStateUnknown)
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STBUG;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else if ((oestate == XenbusStateInitialising) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitWait) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitialised))
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STNOP;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XD_READY:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((oestate == XenbusStateUnknown) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitialising) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitWait) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitialised))
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STBUG;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else if (oestate == XenbusStateConnected)
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STNOP;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XD_CLOSING:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((oestate == XenbusStateUnknown) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitialising) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitWait) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitialised) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateConnected))
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STBUG;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else if (oestate == XenbusStateClosing)
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STNOP;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XD_CLOSED:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((oestate == XenbusStateUnknown) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateConnected))
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STBUG;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else if ((oestate == XenbusStateInitWait) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateInitialised) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateClosing) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (oestate == XenbusStateClosed))
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STNOP;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case XD_SUSPEND:
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev stcheck = STBUG;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (stcheck == STOK)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (stcheck == STBUG)
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_NOTE, "xdf@%s: unexpected otherend "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "state change to %d!, when status is %d",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip), oestate, status);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_connect(xdf_t *vdp, boolean_t wait)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(mutex_owned(&vdp->xdf_dev_lk));
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (vdp->xdf_status != XD_READY) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!wait || (vdp->xdf_status > XD_READY))
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cv_wait_sig(&vdp->xdf_dev_cv, &vdp->xdf_dev_lk) == 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (vdp->xdf_status);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * callback func when DMA/GTE resources is available
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Note: we only register one callback function to grant table subsystem
843e19887f64dde75055cf8842fc4db2171eff45johnlev * since we only have one 'struct gnttab_free_callback' in xdf_t.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_dmacallback(caddr_t arg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp = (xdf_t *)arg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(vdp != NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DMA_DBG, ("xdf@%s: DMA callback started\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_trigger_softintr(vdp->xdf_softintr_id);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_DMA_CALLBACK_DONE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic uint_t
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_iorestart(caddr_t arg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp = (xdf_t *)arg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(vdp != NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(ISDMACBON(vdp));
843e19887f64dde75055cf8842fc4db2171eff45johnlev SETDMACBOFF(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_iostart(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_INTR_CLAIMED);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdf_timeout_handler(void *arg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_t *vdp = arg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_timeout_id = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* new timeout thread could be re-scheduled */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_iostart(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Alloc a vreq for this bp
843e19887f64dde75055cf8842fc4db2171eff45johnlev * bp->av_back contains the pointer to the vreq upon return
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic v_req_t *
843e19887f64dde75055cf8842fc4db2171eff45johnlevvreq_get(xdf_t *vdp, buf_t *bp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev v_req_t *vreq = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(BP2VREQ(bp) == NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq = kmem_cache_alloc(xdf_vreq_cache, KM_NOSLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vreq == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_timeout_id == 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* restart I/O after one second */
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_timeout_id =
843e19887f64dde75055cf8842fc4db2171eff45johnlev timeout(xdf_timeout_handler, vdp, hz);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev bzero(vreq, sizeof (v_req_t));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_insert_head(&vdp->xdf_vreq_act, (void *)vreq);
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->av_back = (buf_t *)vreq;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_buf = bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_status = VREQ_INIT;
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* init of other fields in vreq is up to the caller */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (vreq);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevvreq_free(xdf_t *vdp, v_req_t *vreq)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev buf_t *bp = vreq->v_buf;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_remove(&vdp->xdf_vreq_act, (void *)vreq);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz if (vreq->v_flush_diskcache == FLUSH_DISKCACHE)
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz goto done;
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (vreq->v_status) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_DMAWIN_DONE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_GS_ALLOCED:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_DMABUF_BOUND:
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) ddi_dma_unbind_handle(vreq->v_dmahdl);
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*FALLTHRU*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_DMAMEM_ALLOCED:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!ALIGNED_XFER(bp)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(vreq->v_abuf != NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!IS_ERROR(bp) && IS_READ(bp))
843e19887f64dde75055cf8842fc4db2171eff45johnlev bcopy(vreq->v_abuf, bp->b_un.b_addr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_bcount);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_dma_mem_free(&vreq->v_align);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*FALLTHRU*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_MEMDMAHDL_ALLOCED:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!ALIGNED_XFER(bp))
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_dma_free_handle(&vreq->v_memdmahdl);
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*FALLTHRU*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_DMAHDL_ALLOCED:
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_dma_free_handle(&vreq->v_dmahdl);
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694czdone:
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_buf->av_back = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_cache_free(xdf_vreq_cache, vreq);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Initalize the DMA and grant table resources for the buf
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevvreq_setup(xdf_t *vdp, v_req_t *vreq)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int rc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_dma_attr_t dmaattr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint_t ndcs, ndws;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_dma_handle_t dh;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_dma_handle_t mdh;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_dma_cookie_t dc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_acc_handle_t abh;
843e19887f64dde75055cf8842fc4db2171eff45johnlev caddr_t aba;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ge_slot_t *gs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t bufsz;
843e19887f64dde75055cf8842fc4db2171eff45johnlev off_t off;
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t sz;
843e19887f64dde75055cf8842fc4db2171eff45johnlev buf_t *bp = vreq->v_buf;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int dma_flags = (IS_READ(bp) ? DDI_DMA_READ : DDI_DMA_WRITE) |
843e19887f64dde75055cf8842fc4db2171eff45johnlev DDI_DMA_STREAMING | DDI_DMA_PARTIAL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (vreq->v_status) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_INIT:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (IS_FLUSH_DISKCACHE(bp)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((gs = gs_get(vdp, IS_READ(bp))) == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DMA_DBG, (
843e19887f64dde75055cf8842fc4db2171eff45johnlev "xdf@%s: get ge_slotfailed\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_blkno = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_nslots = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_gs = gs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_flush_diskcache = FLUSH_DISKCACHE;
a6e5dd18ce1ac2c94bbb09fbb01867dc6effa694cz vreq->v_status = VREQ_GS_ALLOCED;
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs->vreq = vreq;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (IS_WRITE_BARRIER(vdp, bp))
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_flush_diskcache = WRITE_BARRIER;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_blkno = bp->b_blkno +
843e19887f64dde75055cf8842fc4db2171eff45johnlev (diskaddr_t)(uintptr_t)bp->b_private;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_private = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* See if we wrote new data to our flush block */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!IS_READ(bp) && USE_WRITE_BARRIER(vdp))
843e19887f64dde75055cf8842fc4db2171eff45johnlev check_fbwrite(vdp, bp, vreq->v_blkno);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_status = VREQ_INIT_DONE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*FALLTHRU*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_INIT_DONE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * alloc DMA handle
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = ddi_dma_alloc_handle(vdp->xdf_dip, &xb_dma_attr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_dmacallback, (caddr_t)vdp, &dh);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rc != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev SETDMACBON(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DMA_DBG, ("xdf@%s: DMA handle alloc failed\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_dmahdl = dh;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_status = VREQ_DMAHDL_ALLOCED;
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*FALLTHRU*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_DMAHDL_ALLOCED:
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * alloc dma handle for 512-byte aligned buf
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!ALIGNED_XFER(bp)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * XXPV: we need to temporarily enlarge the seg
843e19887f64dde75055cf8842fc4db2171eff45johnlev * boundary and s/g length to work round CR6381968
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev dmaattr = xb_dma_attr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dmaattr.dma_attr_seg = (uint64_t)-1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dmaattr.dma_attr_sgllen = INT_MAX;
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = ddi_dma_alloc_handle(vdp->xdf_dip, &dmaattr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_dmacallback, (caddr_t)vdp, &mdh);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rc != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev SETDMACBON(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DMA_DBG, ("xdf@%s: unaligned buf DMA"
843e19887f64dde75055cf8842fc4db2171eff45johnlev "handle alloc failed\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_memdmahdl = mdh;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_status = VREQ_MEMDMAHDL_ALLOCED;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*FALLTHRU*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_MEMDMAHDL_ALLOCED:
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * alloc 512-byte aligned buf
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!ALIGNED_XFER(bp)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (bp->b_flags & (B_PAGEIO | B_PHYS))
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp_mapin(bp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = ddi_dma_mem_alloc(vreq->v_memdmahdl,
843e19887f64dde75055cf8842fc4db2171eff45johnlev roundup(bp->b_bcount, XB_BSIZE), &xc_acc_attr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev DDI_DMA_STREAMING, xdf_dmacallback, (caddr_t)vdp,
843e19887f64dde75055cf8842fc4db2171eff45johnlev &aba, &bufsz, &abh);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rc != DDI_SUCCESS) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev SETDMACBON(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DMA_DBG, (
843e19887f64dde75055cf8842fc4db2171eff45johnlev "xdf@%s: DMA mem allocation failed\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_abuf = aba;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_align = abh;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_status = VREQ_DMAMEM_ALLOCED;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(bufsz >= bp->b_bcount);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!IS_READ(bp))
843e19887f64dde75055cf8842fc4db2171eff45johnlev bcopy(bp->b_un.b_addr, vreq->v_abuf,
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_bcount);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*FALLTHRU*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_DMAMEM_ALLOCED:
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * dma bind
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ALIGNED_XFER(bp)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = ddi_dma_buf_bind_handle(vreq->v_dmahdl, bp,
843e19887f64dde75055cf8842fc4db2171eff45johnlev dma_flags, xdf_dmacallback, (caddr_t)vdp,
843e19887f64dde75055cf8842fc4db2171eff45johnlev &dc, &ndcs);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = ddi_dma_addr_bind_handle(vreq->v_dmahdl,
843e19887f64dde75055cf8842fc4db2171eff45johnlev NULL, vreq->v_abuf, bp->b_bcount, dma_flags,
843e19887f64dde75055cf8842fc4db2171eff45johnlev xdf_dmacallback, (caddr_t)vdp, &dc, &ndcs);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rc == DDI_DMA_MAPPED || rc == DDI_DMA_PARTIAL_MAP) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* get num of dma windows */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (rc == DDI_DMA_PARTIAL_MAP) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = ddi_dma_numwin(vreq->v_dmahdl, &ndws);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(rc == DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ndws = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev SETDMACBON(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DMA_DBG, ("xdf@%s: DMA bind failed\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_dmac = dc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_dmaw = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_ndmacs = ndcs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_ndmaws = ndws;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_nslots = ndws;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_status = VREQ_DMABUF_BOUND;
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*FALLTHRU*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_DMABUF_BOUND:
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * get ge_slot, callback is set upon failure from gs_get(),
843e19887f64dde75055cf8842fc4db2171eff45johnlev * if not set previously
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((gs = gs_get(vdp, IS_READ(bp))) == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DMA_DBG, ("xdf@%s: get ge_slot failed\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_gs = gs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs->vreq = vreq;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_status = VREQ_GS_ALLOCED;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_GS_ALLOCED:
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* nothing need to be done */
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev case VREQ_DMAWIN_DONE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * move to the next dma window
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT((vreq->v_dmaw + 1) < vreq->v_ndmaws);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* get a ge_slot for this DMA window */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((gs = gs_get(vdp, IS_READ(bp))) == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev DPRINTF(DMA_DBG, ("xdf@%s: get ge_slot failed\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev ddi_get_name_addr(vdp->xdf_dip)));
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_gs = gs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs->vreq = vreq;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_dmaw++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev rc = ddi_dma_getwin(vreq->v_dmahdl, vreq->v_dmaw, &off, &sz,
843e19887f64dde75055cf8842fc4db2171eff45johnlev &vreq->v_dmac, &vreq->v_ndmacs);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(rc == DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq->v_status = VREQ_GS_ALLOCED;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_FAILURE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (DDI_SUCCESS);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic ge_slot_t *
843e19887f64dde75055cf8842fc4db2171eff45johnlevgs_get(xdf_t *vdp, int isread)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev grant_ref_t gh;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ge_slot_t *gs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* try to alloc GTEs needed in this slot, first */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (gnttab_alloc_grant_references(
843e19887f64dde75055cf8842fc4db2171eff45johnlev BLKIF_MAX_SEGMENTS_PER_REQUEST, &gh) == -1) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_gnt_callback.next == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev SETDMACBON(vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev gnttab_request_free_callback(
843e19887f64dde75055cf8842fc4db2171eff45johnlev &vdp->xdf_gnt_callback,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void (*)(void *))xdf_dmacallback,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void *)vdp,
843e19887f64dde75055cf8842fc4db2171eff45johnlev BLKIF_MAX_SEGMENTS_PER_REQUEST);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs = kmem_cache_alloc(xdf_gs_cache, KM_NOSLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (gs == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev gnttab_free_grant_references(gh);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_timeout_id == 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* restart I/O after one second */
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_timeout_id =
843e19887f64dde75055cf8842fc4db2171eff45johnlev timeout(xdf_timeout_handler, vdp, hz);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* init gs_slot */
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_insert_head(&vdp->xdf_gs_act, (void *)gs);
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs->oeid = vdp->xdf_peer;
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs->isread = isread;
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs->ghead = gh;
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs->ngrefs = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (gs);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevgs_free(xdf_t *vdp, ge_slot_t *gs)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int i;
843e19887f64dde75055cf8842fc4db2171eff45johnlev grant_ref_t *gp = gs->ge;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int ngrefs = gs->ngrefs;
843e19887f64dde75055cf8842fc4db2171eff45johnlev boolean_t isread = gs->isread;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev list_remove(&vdp->xdf_gs_act, (void *)gs);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* release all grant table entry resources used in this slot */
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (i = 0; i < ngrefs; i++, gp++)
843e19887f64dde75055cf8842fc4db2171eff45johnlev gnttab_end_foreign_access(*gp, !isread, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev gnttab_free_grant_references(gs->ghead);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_cache_free(xdf_gs_cache, (void *)gs);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic grant_ref_t
843e19887f64dde75055cf8842fc4db2171eff45johnlevgs_grant(ge_slot_t *gs, mfn_t mfn)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev grant_ref_t gr = gnttab_claim_grant_reference(&gs->ghead);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(gr != -1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(gs->ngrefs < BLKIF_MAX_SEGMENTS_PER_REQUEST);
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs->ge[gs->ngrefs++] = gr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev gnttab_grant_foreign_access_ref(gr, gs->oeid, mfn, !gs->isread);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (gr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevunexpectedie(xdf_t *vdp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* clean up I/Os in ring that have responses */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xvdi_ring_has_unconsumed_responses(vdp->xdf_xb_ring)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) xdf_intr((caddr_t)vdp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&vdp->xdf_dev_lk);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* free up all grant table entries */
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (!list_is_empty(&vdp->xdf_gs_act))
843e19887f64dde75055cf8842fc4db2171eff45johnlev gs_free(vdp, list_head(&vdp->xdf_gs_act));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * move bp back to active list orderly
843e19887f64dde75055cf8842fc4db2171eff45johnlev * vreq_busy is updated in vreq_free()
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (!list_is_empty(&vdp->xdf_vreq_act)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev v_req_t *vreq = list_head(&vdp->xdf_vreq_act);
843e19887f64dde75055cf8842fc4db2171eff45johnlev buf_t *bp = vreq->v_buf;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->av_back = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_resid = bp->b_bcount;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vdp->xdf_f_act == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_f_act = vdp->xdf_l_act = bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* move to the head of list */
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->av_forw = vdp->xdf_f_act;
843e19887f64dde75055cf8842fc4db2171eff45johnlev vdp->xdf_f_act = bp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev kstat_runq_back_to_waitq(KSTAT_IO_PTR(vdp->xdf_xdev_iostat));
843e19887f64dde75055cf8842fc4db2171eff45johnlev vreq_free(vdp, vreq);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxdfmin(struct buf *bp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (bp->b_bcount > xdf_maxphys)
843e19887f64dde75055cf8842fc4db2171eff45johnlev bp->b_bcount = xdf_maxphys;
843e19887f64dde75055cf8842fc4db2171eff45johnlev}