1843e1988Sjohnlev /* 2843e1988Sjohnlev * CDDL HEADER START 3843e1988Sjohnlev * 4843e1988Sjohnlev * The contents of this file are subject to the terms of the 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * You may not use this file except in compliance with the License. 7843e1988Sjohnlev * 8843e1988Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9843e1988Sjohnlev * or http://www.opensolaris.org/os/licensing. 10843e1988Sjohnlev * See the License for the specific language governing permissions 11843e1988Sjohnlev * and limitations under the License. 12843e1988Sjohnlev * 13843e1988Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 14843e1988Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15843e1988Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 16843e1988Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 17843e1988Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18843e1988Sjohnlev * 19843e1988Sjohnlev * CDDL HEADER END 20843e1988Sjohnlev */ 21843e1988Sjohnlev 22843e1988Sjohnlev /* 237f0b8309SEdward Pilatowicz * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24843e1988Sjohnlev * Use is subject to license terms. 25843e1988Sjohnlev */ 26843e1988Sjohnlev 27843e1988Sjohnlev /* 28843e1988Sjohnlev * Note: This is the backend part of the split PV disk driver. This driver 29843e1988Sjohnlev * is not a nexus driver, nor is it a leaf driver(block/char/stream driver). 30843e1988Sjohnlev * Currently, it does not create any minor node. So, although, it runs in 31843e1988Sjohnlev * backend domain, it will not be used directly from within dom0. 32843e1988Sjohnlev * It simply gets block I/O requests issued by frontend from a shared page 33843e1988Sjohnlev * (blkif ring buffer - defined by Xen) between backend and frontend domain, 34843e1988Sjohnlev * generates a buf, and push it down to underlying disk target driver via 35843e1988Sjohnlev * ldi interface. When buf is done, this driver will generate a response 36843e1988Sjohnlev * and put it into ring buffer to inform frontend of the status of the I/O 37843e1988Sjohnlev * request issued by it. When a new virtual device entry is added in xenstore, 38843e1988Sjohnlev * there will be an watch event sent from Xen to xvdi framework, who will, 39843e1988Sjohnlev * in turn, create the devinfo node and try to attach this driver 40843e1988Sjohnlev * (see xvdi_create_dev). When frontend peer changes its state to 41843e1988Sjohnlev * XenbusStateClose, an event will also be sent from Xen to xvdi framework, 42843e1988Sjohnlev * who will detach and remove this devinfo node (see i_xvdi_oestate_handler). 43843e1988Sjohnlev * I/O requests get from ring buffer and event coming from xenstore cannot be 44843e1988Sjohnlev * trusted. We verify them in xdb_get_buf() and xdb_check_state_transition(). 45843e1988Sjohnlev * 46843e1988Sjohnlev * Virtual device configuration is read/written from/to the database via 47843e1988Sjohnlev * xenbus_* interfaces. Driver also use xvdi_* to interact with hypervisor. 48843e1988Sjohnlev * There is an on-going effort to make xvdi_* cover all xenbus_*. 49843e1988Sjohnlev */ 50843e1988Sjohnlev 51551bc2a6Smrj #include <sys/types.h> 52551bc2a6Smrj #include <sys/conf.h> 53551bc2a6Smrj #include <sys/ddi.h> 54551bc2a6Smrj #include <sys/dditypes.h> 55551bc2a6Smrj #include <sys/sunddi.h> 56551bc2a6Smrj #include <sys/list.h> 57551bc2a6Smrj #include <sys/dkio.h> 58551bc2a6Smrj #include <sys/cmlb.h> 59551bc2a6Smrj #include <sys/vtoc.h> 60551bc2a6Smrj #include <sys/modctl.h> 61551bc2a6Smrj #include <sys/bootconf.h> 62551bc2a6Smrj #include <sys/promif.h> 63551bc2a6Smrj #include <sys/sysmacros.h> 64551bc2a6Smrj #include <public/io/xenbus.h> 657f0b8309SEdward Pilatowicz #include <public/io/xs_wire.h> 66551bc2a6Smrj #include <xen/sys/xenbus_impl.h> 67551bc2a6Smrj #include <xen/sys/xendev.h> 68551bc2a6Smrj #include <sys/gnttab.h> 69551bc2a6Smrj #include <sys/scsi/generic/inquiry.h> 70551bc2a6Smrj #include <vm/seg_kmem.h> 71843e1988Sjohnlev #include <vm/hat_i86.h> 72551bc2a6Smrj #include <sys/gnttab.h> 73551bc2a6Smrj #include <sys/lofi.h> 74551bc2a6Smrj #include <io/xdf.h> 75a576ab5bSrab #include <xen/io/blkif_impl.h> 76551bc2a6Smrj #include <io/xdb.h> 77843e1988Sjohnlev 78843e1988Sjohnlev static xdb_t *xdb_statep; 79843e1988Sjohnlev static int xdb_debug = 0; 80843e1988Sjohnlev 817f0b8309SEdward Pilatowicz static void xdb_close(dev_info_t *); 82a576ab5bSrab static int xdb_push_response(xdb_t *, uint64_t, uint8_t, uint16_t); 83a576ab5bSrab static int xdb_get_request(xdb_t *, blkif_request_t *); 84a576ab5bSrab static void blkif_get_x86_32_req(blkif_request_t *, blkif_x86_32_request_t *); 85a576ab5bSrab static void blkif_get_x86_64_req(blkif_request_t *, blkif_x86_64_request_t *); 867f0b8309SEdward Pilatowicz static int xdb_biodone(buf_t *); 877f0b8309SEdward Pilatowicz 88a576ab5bSrab 89843e1988Sjohnlev #ifdef DEBUG 90843e1988Sjohnlev /* 91843e1988Sjohnlev * debug aid functions 92843e1988Sjohnlev */ 93843e1988Sjohnlev 94843e1988Sjohnlev static void 95843e1988Sjohnlev logva(xdb_t *vdp, uint64_t va) 96843e1988Sjohnlev { 97843e1988Sjohnlev uint64_t *page_addrs; 98843e1988Sjohnlev int i; 99843e1988Sjohnlev 100843e1988Sjohnlev page_addrs = vdp->page_addrs; 101a576ab5bSrab for (i = 0; i < XDB_MAX_IO_PAGES(vdp); i++) { 102843e1988Sjohnlev if (page_addrs[i] == va) 103843e1988Sjohnlev debug_enter("VA remapping found!"); 104843e1988Sjohnlev } 105843e1988Sjohnlev 106a576ab5bSrab for (i = 0; i < XDB_MAX_IO_PAGES(vdp); i++) { 107843e1988Sjohnlev if (page_addrs[i] == 0) { 108843e1988Sjohnlev page_addrs[i] = va; 109843e1988Sjohnlev break; 110843e1988Sjohnlev } 111843e1988Sjohnlev } 112a576ab5bSrab ASSERT(i < XDB_MAX_IO_PAGES(vdp)); 113843e1988Sjohnlev } 114843e1988Sjohnlev 115843e1988Sjohnlev static void 116843e1988Sjohnlev unlogva(xdb_t *vdp, uint64_t va) 117843e1988Sjohnlev { 118843e1988Sjohnlev uint64_t *page_addrs; 119843e1988Sjohnlev int i; 120843e1988Sjohnlev 121843e1988Sjohnlev page_addrs = vdp->page_addrs; 122a576ab5bSrab for (i = 0; i < XDB_MAX_IO_PAGES(vdp); i++) { 123843e1988Sjohnlev if (page_addrs[i] == va) { 124843e1988Sjohnlev page_addrs[i] = 0; 125843e1988Sjohnlev break; 126843e1988Sjohnlev } 127843e1988Sjohnlev } 128a576ab5bSrab ASSERT(i < XDB_MAX_IO_PAGES(vdp)); 129843e1988Sjohnlev } 130843e1988Sjohnlev 131843e1988Sjohnlev static void 132843e1988Sjohnlev xdb_dump_request_oe(blkif_request_t *req) 133843e1988Sjohnlev { 134843e1988Sjohnlev int i; 135843e1988Sjohnlev 136843e1988Sjohnlev /* 137843e1988Sjohnlev * Exploit the public interface definitions for BLKIF_OP_READ 138843e1988Sjohnlev * etc.. 139843e1988Sjohnlev */ 140843e1988Sjohnlev char *op_name[] = { "read", "write", "barrier", "flush" }; 141843e1988Sjohnlev 142843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "op=%s", op_name[req->operation])); 143843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "num of segments=%d", 144843e1988Sjohnlev req->nr_segments)); 145843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "handle=%d", req->handle)); 146843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "id=%llu", 147843e1988Sjohnlev (unsigned long long)req->id)); 148843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "start sector=%llu", 149843e1988Sjohnlev (unsigned long long)req->sector_number)); 150843e1988Sjohnlev for (i = 0; i < req->nr_segments; i++) { 151843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "gref=%d, first sec=%d," 152843e1988Sjohnlev "last sec=%d", req->seg[i].gref, req->seg[i].first_sect, 153843e1988Sjohnlev req->seg[i].last_sect)); 154843e1988Sjohnlev } 155843e1988Sjohnlev } 156843e1988Sjohnlev #endif /* DEBUG */ 157843e1988Sjohnlev 158843e1988Sjohnlev /* 159843e1988Sjohnlev * Statistics. 160843e1988Sjohnlev */ 161843e1988Sjohnlev static char *xdb_stats[] = { 162843e1988Sjohnlev "rd_reqs", 163843e1988Sjohnlev "wr_reqs", 164843e1988Sjohnlev "br_reqs", 165843e1988Sjohnlev "fl_reqs", 166843e1988Sjohnlev "oo_reqs" 167843e1988Sjohnlev }; 168843e1988Sjohnlev 169843e1988Sjohnlev static int 170843e1988Sjohnlev xdb_kstat_update(kstat_t *ksp, int flag) 171843e1988Sjohnlev { 172843e1988Sjohnlev xdb_t *vdp; 173843e1988Sjohnlev kstat_named_t *knp; 174843e1988Sjohnlev 175843e1988Sjohnlev if (flag != KSTAT_READ) 176843e1988Sjohnlev return (EACCES); 177843e1988Sjohnlev 178843e1988Sjohnlev vdp = ksp->ks_private; 179843e1988Sjohnlev knp = ksp->ks_data; 180843e1988Sjohnlev 181843e1988Sjohnlev /* 182843e1988Sjohnlev * Assignment order should match that of the names in 183843e1988Sjohnlev * xdb_stats. 184843e1988Sjohnlev */ 185843e1988Sjohnlev (knp++)->value.ui64 = vdp->xs_stat_req_reads; 186843e1988Sjohnlev (knp++)->value.ui64 = vdp->xs_stat_req_writes; 187843e1988Sjohnlev (knp++)->value.ui64 = vdp->xs_stat_req_barriers; 188843e1988Sjohnlev (knp++)->value.ui64 = vdp->xs_stat_req_flushes; 189843e1988Sjohnlev (knp++)->value.ui64 = 0; /* oo_req */ 190843e1988Sjohnlev 191843e1988Sjohnlev return (0); 192843e1988Sjohnlev } 193843e1988Sjohnlev 194843e1988Sjohnlev static boolean_t 195843e1988Sjohnlev xdb_kstat_init(xdb_t *vdp) 196843e1988Sjohnlev { 197843e1988Sjohnlev int nstat = sizeof (xdb_stats) / sizeof (xdb_stats[0]); 198843e1988Sjohnlev char **cp = xdb_stats; 199843e1988Sjohnlev kstat_named_t *knp; 200843e1988Sjohnlev 201843e1988Sjohnlev if ((vdp->xs_kstats = kstat_create("xdb", 202843e1988Sjohnlev ddi_get_instance(vdp->xs_dip), 203843e1988Sjohnlev "req_statistics", "block", KSTAT_TYPE_NAMED, 204843e1988Sjohnlev nstat, 0)) == NULL) 205843e1988Sjohnlev return (B_FALSE); 206843e1988Sjohnlev 207843e1988Sjohnlev vdp->xs_kstats->ks_private = vdp; 208843e1988Sjohnlev vdp->xs_kstats->ks_update = xdb_kstat_update; 209843e1988Sjohnlev 210843e1988Sjohnlev knp = vdp->xs_kstats->ks_data; 211843e1988Sjohnlev while (nstat > 0) { 212843e1988Sjohnlev kstat_named_init(knp, *cp, KSTAT_DATA_UINT64); 213843e1988Sjohnlev knp++; 214843e1988Sjohnlev cp++; 215843e1988Sjohnlev nstat--; 216843e1988Sjohnlev } 217843e1988Sjohnlev 218843e1988Sjohnlev kstat_install(vdp->xs_kstats); 219843e1988Sjohnlev 220843e1988Sjohnlev return (B_TRUE); 221843e1988Sjohnlev } 222843e1988Sjohnlev 2237f0b8309SEdward Pilatowicz static char * 2247f0b8309SEdward Pilatowicz i_pathname(dev_info_t *dip) 2257f0b8309SEdward Pilatowicz { 2267f0b8309SEdward Pilatowicz char *path, *rv; 2277f0b8309SEdward Pilatowicz 2287f0b8309SEdward Pilatowicz path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2297f0b8309SEdward Pilatowicz (void) ddi_pathname(dip, path); 2307f0b8309SEdward Pilatowicz rv = strdup(path); 2317f0b8309SEdward Pilatowicz kmem_free(path, MAXPATHLEN); 2327f0b8309SEdward Pilatowicz 2337f0b8309SEdward Pilatowicz return (rv); 2347f0b8309SEdward Pilatowicz } 235843e1988Sjohnlev 236843e1988Sjohnlev static buf_t * 237843e1988Sjohnlev xdb_get_buf(xdb_t *vdp, blkif_request_t *req, xdb_request_t *xreq) 238843e1988Sjohnlev { 239843e1988Sjohnlev buf_t *bp; 240843e1988Sjohnlev uint8_t segs, curseg; 241843e1988Sjohnlev int sectors; 242843e1988Sjohnlev int i, err; 243843e1988Sjohnlev gnttab_map_grant_ref_t mapops[BLKIF_MAX_SEGMENTS_PER_REQUEST]; 244843e1988Sjohnlev ddi_acc_handle_t acchdl; 245843e1988Sjohnlev 246843e1988Sjohnlev acchdl = vdp->xs_ring_hdl; 247843e1988Sjohnlev bp = XDB_XREQ2BP(xreq); 248843e1988Sjohnlev curseg = xreq->xr_curseg; 249843e1988Sjohnlev /* init a new xdb request */ 250843e1988Sjohnlev if (req != NULL) { 251843e1988Sjohnlev ASSERT(MUTEX_HELD(&vdp->xs_iomutex)); 252843e1988Sjohnlev boolean_t pagemapok = B_TRUE; 253843e1988Sjohnlev uint8_t op = ddi_get8(acchdl, &req->operation); 254843e1988Sjohnlev 255843e1988Sjohnlev xreq->xr_vdp = vdp; 256843e1988Sjohnlev xreq->xr_op = op; 257843e1988Sjohnlev xreq->xr_id = ddi_get64(acchdl, &req->id); 258843e1988Sjohnlev segs = xreq->xr_buf_pages = ddi_get8(acchdl, &req->nr_segments); 259843e1988Sjohnlev if (segs == 0) { 260843e1988Sjohnlev if (op != BLKIF_OP_FLUSH_DISKCACHE) 261843e1988Sjohnlev cmn_err(CE_WARN, "!non-BLKIF_OP_FLUSH_DISKCACHE" 262843e1988Sjohnlev " is seen from domain %d with zero " 263843e1988Sjohnlev "length data buffer!", vdp->xs_peer); 264843e1988Sjohnlev bioinit(bp); 265843e1988Sjohnlev bp->b_bcount = 0; 266843e1988Sjohnlev bp->b_lblkno = 0; 267843e1988Sjohnlev bp->b_un.b_addr = NULL; 268843e1988Sjohnlev return (bp); 269843e1988Sjohnlev } else if (op == BLKIF_OP_FLUSH_DISKCACHE) { 270843e1988Sjohnlev cmn_err(CE_WARN, "!BLKIF_OP_FLUSH_DISKCACHE" 271843e1988Sjohnlev " is seen from domain %d with non-zero " 272843e1988Sjohnlev "length data buffer!", vdp->xs_peer); 273843e1988Sjohnlev } 274843e1988Sjohnlev 275843e1988Sjohnlev /* 276843e1988Sjohnlev * segs should be no bigger than BLKIF_MAX_SEGMENTS_PER_REQUEST 277843e1988Sjohnlev * according to the definition of blk interface by Xen 278843e1988Sjohnlev * we do sanity check here 279843e1988Sjohnlev */ 280843e1988Sjohnlev if (segs > BLKIF_MAX_SEGMENTS_PER_REQUEST) 281843e1988Sjohnlev segs = xreq->xr_buf_pages = 282843e1988Sjohnlev BLKIF_MAX_SEGMENTS_PER_REQUEST; 283843e1988Sjohnlev 284843e1988Sjohnlev for (i = 0; i < segs; i++) { 285843e1988Sjohnlev uint8_t fs, ls; 286843e1988Sjohnlev 287843e1988Sjohnlev mapops[i].host_addr = 288843e1988Sjohnlev (uint64_t)(uintptr_t)XDB_IOPAGE_VA( 289843e1988Sjohnlev vdp->xs_iopage_va, xreq->xr_idx, i); 290843e1988Sjohnlev mapops[i].dom = vdp->xs_peer; 291843e1988Sjohnlev mapops[i].ref = ddi_get32(acchdl, &req->seg[i].gref); 292843e1988Sjohnlev mapops[i].flags = GNTMAP_host_map; 293843e1988Sjohnlev if (op != BLKIF_OP_READ) 294843e1988Sjohnlev mapops[i].flags |= GNTMAP_readonly; 295843e1988Sjohnlev 296843e1988Sjohnlev fs = ddi_get8(acchdl, &req->seg[i].first_sect); 297843e1988Sjohnlev ls = ddi_get8(acchdl, &req->seg[i].last_sect); 298843e1988Sjohnlev 299843e1988Sjohnlev /* 300843e1988Sjohnlev * first_sect should be no bigger than last_sect and 301843e1988Sjohnlev * both of them should be no bigger than 302ee56d0c8SMark Johnson * XB_LAST_SECTOR_IN_SEG according to definition 303843e1988Sjohnlev * of blk interface by Xen, so sanity check again 304843e1988Sjohnlev */ 305ee56d0c8SMark Johnson if (fs > XB_LAST_SECTOR_IN_SEG) 306ee56d0c8SMark Johnson fs = XB_LAST_SECTOR_IN_SEG; 307ee56d0c8SMark Johnson if (ls > XB_LAST_SECTOR_IN_SEG) 308ee56d0c8SMark Johnson ls = XB_LAST_SECTOR_IN_SEG; 309843e1988Sjohnlev if (fs > ls) 310843e1988Sjohnlev fs = ls; 311843e1988Sjohnlev 312843e1988Sjohnlev xreq->xr_segs[i].fs = fs; 313843e1988Sjohnlev xreq->xr_segs[i].ls = ls; 314843e1988Sjohnlev } 315843e1988Sjohnlev 316843e1988Sjohnlev /* map in io pages */ 3177eea693dSMark Johnson err = xen_map_gref(GNTTABOP_map_grant_ref, mapops, i, B_FALSE); 318843e1988Sjohnlev if (err != 0) 319843e1988Sjohnlev return (NULL); 320843e1988Sjohnlev for (i = 0; i < segs; i++) { 321843e1988Sjohnlev /* 322843e1988Sjohnlev * Although HYPERVISOR_grant_table_op() returned no 323843e1988Sjohnlev * error, mapping of each single page can fail. So, 324843e1988Sjohnlev * we have to do the check here and handle the error 325843e1988Sjohnlev * if needed 326843e1988Sjohnlev */ 327843e1988Sjohnlev if (mapops[i].status != GNTST_okay) { 328843e1988Sjohnlev int j; 329843e1988Sjohnlev for (j = 0; j < i; j++) { 330843e1988Sjohnlev #ifdef DEBUG 331843e1988Sjohnlev unlogva(vdp, mapops[j].host_addr); 332843e1988Sjohnlev #endif 333843e1988Sjohnlev xen_release_pfn( 334843e1988Sjohnlev xreq->xr_plist[j].p_pagenum); 335843e1988Sjohnlev } 336843e1988Sjohnlev pagemapok = B_FALSE; 337843e1988Sjohnlev break; 338843e1988Sjohnlev } 339843e1988Sjohnlev /* record page mapping handle for unmapping later */ 340843e1988Sjohnlev xreq->xr_page_hdls[i] = mapops[i].handle; 341843e1988Sjohnlev #ifdef DEBUG 342843e1988Sjohnlev logva(vdp, mapops[i].host_addr); 343843e1988Sjohnlev #endif 344843e1988Sjohnlev /* 345843e1988Sjohnlev * Pass the MFNs down using the shadow list (xr_pplist) 346843e1988Sjohnlev * 347843e1988Sjohnlev * This is pretty ugly since we have implict knowledge 348843e1988Sjohnlev * of how the rootnex binds buffers. 349843e1988Sjohnlev * The GNTTABOP_map_grant_ref op makes us do some ugly 350843e1988Sjohnlev * stuff since we're not allowed to touch these PTEs 351843e1988Sjohnlev * from the VM. 352843e1988Sjohnlev * 353843e1988Sjohnlev * Obviously, these aren't real page_t's. The rootnex 354843e1988Sjohnlev * only needs p_pagenum. 355843e1988Sjohnlev * Also, don't use btop() here or 32 bit PAE breaks. 356843e1988Sjohnlev */ 357843e1988Sjohnlev xreq->xr_pplist[i] = &xreq->xr_plist[i]; 358843e1988Sjohnlev xreq->xr_plist[i].p_pagenum = 359843e1988Sjohnlev xen_assign_pfn(mapops[i].dev_bus_addr >> PAGESHIFT); 360843e1988Sjohnlev } 361843e1988Sjohnlev 362843e1988Sjohnlev /* 363843e1988Sjohnlev * not all pages mapped in successfully, unmap those mapped-in 364843e1988Sjohnlev * page and return failure 365843e1988Sjohnlev */ 366843e1988Sjohnlev if (!pagemapok) { 367843e1988Sjohnlev gnttab_unmap_grant_ref_t unmapop; 368843e1988Sjohnlev 369843e1988Sjohnlev for (i = 0; i < segs; i++) { 370843e1988Sjohnlev if (mapops[i].status != GNTST_okay) 371843e1988Sjohnlev continue; 372843e1988Sjohnlev unmapop.host_addr = 373843e1988Sjohnlev (uint64_t)(uintptr_t)XDB_IOPAGE_VA( 374843e1988Sjohnlev vdp->xs_iopage_va, xreq->xr_idx, i); 375843e1988Sjohnlev unmapop.dev_bus_addr = NULL; 376843e1988Sjohnlev unmapop.handle = mapops[i].handle; 377843e1988Sjohnlev (void) HYPERVISOR_grant_table_op( 378843e1988Sjohnlev GNTTABOP_unmap_grant_ref, &unmapop, 1); 379843e1988Sjohnlev } 380843e1988Sjohnlev 381843e1988Sjohnlev return (NULL); 382843e1988Sjohnlev } 383843e1988Sjohnlev bioinit(bp); 384843e1988Sjohnlev bp->b_lblkno = ddi_get64(acchdl, &req->sector_number); 385843e1988Sjohnlev bp->b_flags = B_BUSY | B_SHADOW | B_PHYS; 386843e1988Sjohnlev bp->b_flags |= (ddi_get8(acchdl, &req->operation) == 387843e1988Sjohnlev BLKIF_OP_READ) ? B_READ : (B_WRITE | B_ASYNC); 388843e1988Sjohnlev } else { 389843e1988Sjohnlev uint64_t blkst; 390843e1988Sjohnlev int isread; 391843e1988Sjohnlev 392843e1988Sjohnlev /* reuse this buf */ 393843e1988Sjohnlev blkst = bp->b_lblkno + bp->b_bcount / DEV_BSIZE; 394843e1988Sjohnlev isread = bp->b_flags & B_READ; 395843e1988Sjohnlev bioreset(bp); 396843e1988Sjohnlev bp->b_lblkno = blkst; 397843e1988Sjohnlev bp->b_flags = B_BUSY | B_SHADOW | B_PHYS; 398843e1988Sjohnlev bp->b_flags |= isread ? B_READ : (B_WRITE | B_ASYNC); 399843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "reuse buf, xreq is %d!!", 400843e1988Sjohnlev xreq->xr_idx)); 401843e1988Sjohnlev } 402843e1988Sjohnlev 403843e1988Sjohnlev /* form a buf */ 404843e1988Sjohnlev bp->b_un.b_addr = XDB_IOPAGE_VA(vdp->xs_iopage_va, xreq->xr_idx, 405843e1988Sjohnlev curseg) + xreq->xr_segs[curseg].fs * DEV_BSIZE; 406843e1988Sjohnlev bp->b_shadow = &xreq->xr_pplist[curseg]; 407843e1988Sjohnlev bp->b_iodone = xdb_biodone; 408843e1988Sjohnlev sectors = 0; 409ee56d0c8SMark Johnson 410843e1988Sjohnlev /* 411ee56d0c8SMark Johnson * Run through the segments. There are XB_NUM_SECTORS_PER_SEG sectors 412ee56d0c8SMark Johnson * per segment. On some OSes (e.g. Linux), there may be empty gaps 413ee56d0c8SMark Johnson * between segments. (i.e. the first segment may end on sector 6 and 414ee56d0c8SMark Johnson * the second segment start on sector 4). 415ee56d0c8SMark Johnson * 416ee56d0c8SMark Johnson * if a segments first sector is not set to 0, and this is not the 417ee56d0c8SMark Johnson * first segment in our buf, end this buf now. 418ee56d0c8SMark Johnson * 419ee56d0c8SMark Johnson * if a segments last sector is not set to XB_LAST_SECTOR_IN_SEG, and 420ee56d0c8SMark Johnson * this is not the last segment in the request, add this segment into 421ee56d0c8SMark Johnson * the buf, then end this buf (updating the pointer to point to the 422ee56d0c8SMark Johnson * next segment next time around). 423843e1988Sjohnlev */ 424ee56d0c8SMark Johnson for (i = curseg; i < xreq->xr_buf_pages; i++) { 425ee56d0c8SMark Johnson if ((xreq->xr_segs[i].fs != 0) && (i != curseg)) { 426843e1988Sjohnlev break; 427843e1988Sjohnlev } 428843e1988Sjohnlev sectors += (xreq->xr_segs[i].ls - xreq->xr_segs[i].fs + 1); 429ee56d0c8SMark Johnson if ((xreq->xr_segs[i].ls != XB_LAST_SECTOR_IN_SEG) && 430ee56d0c8SMark Johnson (i != (xreq->xr_buf_pages - 1))) { 431ee56d0c8SMark Johnson i++; 432ee56d0c8SMark Johnson break; 433ee56d0c8SMark Johnson } 434843e1988Sjohnlev } 435843e1988Sjohnlev xreq->xr_curseg = i; 436843e1988Sjohnlev bp->b_bcount = sectors * DEV_BSIZE; 437843e1988Sjohnlev bp->b_bufsize = bp->b_bcount; 438843e1988Sjohnlev 439843e1988Sjohnlev return (bp); 440843e1988Sjohnlev } 441843e1988Sjohnlev 442843e1988Sjohnlev static xdb_request_t * 443843e1988Sjohnlev xdb_get_req(xdb_t *vdp) 444843e1988Sjohnlev { 445843e1988Sjohnlev xdb_request_t *req; 446843e1988Sjohnlev int idx; 447843e1988Sjohnlev 448843e1988Sjohnlev ASSERT(MUTEX_HELD(&vdp->xs_iomutex)); 449843e1988Sjohnlev ASSERT(vdp->xs_free_req != -1); 450843e1988Sjohnlev req = &vdp->xs_req[vdp->xs_free_req]; 451843e1988Sjohnlev vdp->xs_free_req = req->xr_next; 452843e1988Sjohnlev idx = req->xr_idx; 453843e1988Sjohnlev bzero(req, sizeof (xdb_request_t)); 454843e1988Sjohnlev req->xr_idx = idx; 455843e1988Sjohnlev return (req); 456843e1988Sjohnlev } 457843e1988Sjohnlev 458843e1988Sjohnlev static void 459843e1988Sjohnlev xdb_free_req(xdb_request_t *req) 460843e1988Sjohnlev { 461843e1988Sjohnlev xdb_t *vdp = req->xr_vdp; 462843e1988Sjohnlev 463843e1988Sjohnlev ASSERT(MUTEX_HELD(&vdp->xs_iomutex)); 464843e1988Sjohnlev req->xr_next = vdp->xs_free_req; 465843e1988Sjohnlev vdp->xs_free_req = req->xr_idx; 466843e1988Sjohnlev } 467843e1988Sjohnlev 468843e1988Sjohnlev static void 469843e1988Sjohnlev xdb_response(xdb_t *vdp, blkif_request_t *req, boolean_t ok) 470843e1988Sjohnlev { 471843e1988Sjohnlev ddi_acc_handle_t acchdl = vdp->xs_ring_hdl; 472843e1988Sjohnlev 473a576ab5bSrab if (xdb_push_response(vdp, ddi_get64(acchdl, &req->id), 474a576ab5bSrab ddi_get8(acchdl, &req->operation), ok)) 475843e1988Sjohnlev xvdi_notify_oe(vdp->xs_dip); 476843e1988Sjohnlev } 477843e1988Sjohnlev 478843e1988Sjohnlev static void 479843e1988Sjohnlev xdb_init_ioreqs(xdb_t *vdp) 480843e1988Sjohnlev { 481843e1988Sjohnlev int i; 482843e1988Sjohnlev 483a576ab5bSrab ASSERT(vdp->xs_nentry); 484a576ab5bSrab 485a576ab5bSrab if (vdp->xs_req == NULL) 486a576ab5bSrab vdp->xs_req = kmem_alloc(vdp->xs_nentry * 487a576ab5bSrab sizeof (xdb_request_t), KM_SLEEP); 488a576ab5bSrab #ifdef DEBUG 489a576ab5bSrab if (vdp->page_addrs == NULL) 490a576ab5bSrab vdp->page_addrs = kmem_zalloc(XDB_MAX_IO_PAGES(vdp) * 491a576ab5bSrab sizeof (uint64_t), KM_SLEEP); 492a576ab5bSrab #endif 493a576ab5bSrab for (i = 0; i < vdp->xs_nentry; i++) { 494843e1988Sjohnlev vdp->xs_req[i].xr_idx = i; 495843e1988Sjohnlev vdp->xs_req[i].xr_next = i + 1; 496843e1988Sjohnlev } 497a576ab5bSrab vdp->xs_req[vdp->xs_nentry - 1].xr_next = -1; 498843e1988Sjohnlev vdp->xs_free_req = 0; 499843e1988Sjohnlev 500843e1988Sjohnlev /* alloc va in host dom for io page mapping */ 501843e1988Sjohnlev vdp->xs_iopage_va = vmem_xalloc(heap_arena, 502a576ab5bSrab XDB_MAX_IO_PAGES(vdp) * PAGESIZE, PAGESIZE, 0, 0, 0, 0, 503843e1988Sjohnlev VM_SLEEP); 504a576ab5bSrab for (i = 0; i < XDB_MAX_IO_PAGES(vdp); i++) 505843e1988Sjohnlev hat_prepare_mapping(kas.a_hat, 5067eea693dSMark Johnson vdp->xs_iopage_va + i * PAGESIZE, NULL); 507843e1988Sjohnlev } 508843e1988Sjohnlev 509843e1988Sjohnlev static void 510843e1988Sjohnlev xdb_uninit_ioreqs(xdb_t *vdp) 511843e1988Sjohnlev { 512843e1988Sjohnlev int i; 513843e1988Sjohnlev 514a576ab5bSrab for (i = 0; i < XDB_MAX_IO_PAGES(vdp); i++) 515843e1988Sjohnlev hat_release_mapping(kas.a_hat, 516843e1988Sjohnlev vdp->xs_iopage_va + i * PAGESIZE); 517843e1988Sjohnlev vmem_xfree(heap_arena, vdp->xs_iopage_va, 518a576ab5bSrab XDB_MAX_IO_PAGES(vdp) * PAGESIZE); 519a576ab5bSrab if (vdp->xs_req != NULL) { 520a576ab5bSrab kmem_free(vdp->xs_req, vdp->xs_nentry * sizeof (xdb_request_t)); 521a576ab5bSrab vdp->xs_req = NULL; 522a576ab5bSrab } 523a576ab5bSrab #ifdef DEBUG 524a576ab5bSrab if (vdp->page_addrs != NULL) { 525a576ab5bSrab kmem_free(vdp->page_addrs, XDB_MAX_IO_PAGES(vdp) * 526a576ab5bSrab sizeof (uint64_t)); 527a576ab5bSrab vdp->page_addrs = NULL; 528a576ab5bSrab } 529a576ab5bSrab #endif 530843e1988Sjohnlev } 531843e1988Sjohnlev 532843e1988Sjohnlev static uint_t 533843e1988Sjohnlev xdb_intr(caddr_t arg) 534843e1988Sjohnlev { 5357f0b8309SEdward Pilatowicz xdb_t *vdp = (xdb_t *)arg; 5367f0b8309SEdward Pilatowicz dev_info_t *dip = vdp->xs_dip; 5377f0b8309SEdward Pilatowicz blkif_request_t req, *reqp = &req; 538843e1988Sjohnlev xdb_request_t *xreq; 539843e1988Sjohnlev buf_t *bp; 540843e1988Sjohnlev uint8_t op; 541843e1988Sjohnlev int ret = DDI_INTR_UNCLAIMED; 542843e1988Sjohnlev 543843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, 544843e1988Sjohnlev "xdb@%s: I/O request received from dom %d", 545843e1988Sjohnlev ddi_get_name_addr(dip), vdp->xs_peer)); 546843e1988Sjohnlev 547843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 548843e1988Sjohnlev 549843e1988Sjohnlev /* shouldn't touch ring buffer if not in connected state */ 5507f0b8309SEdward Pilatowicz if (!vdp->xs_if_connected) { 551843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 552843e1988Sjohnlev return (DDI_INTR_UNCLAIMED); 553843e1988Sjohnlev } 5547f0b8309SEdward Pilatowicz ASSERT(vdp->xs_hp_connected && vdp->xs_fe_initialised); 555843e1988Sjohnlev 556843e1988Sjohnlev /* 557843e1988Sjohnlev * We'll loop till there is no more request in the ring 558843e1988Sjohnlev * We won't stuck in this loop for ever since the size of ring buffer 559843e1988Sjohnlev * is limited, and frontend will stop pushing requests into it when 560843e1988Sjohnlev * the ring buffer is full 561843e1988Sjohnlev */ 562843e1988Sjohnlev 563843e1988Sjohnlev /* req_event will be increased in xvdi_ring_get_request() */ 564a576ab5bSrab while (xdb_get_request(vdp, reqp)) { 565843e1988Sjohnlev ret = DDI_INTR_CLAIMED; 566843e1988Sjohnlev 567a576ab5bSrab op = ddi_get8(vdp->xs_ring_hdl, &reqp->operation); 568843e1988Sjohnlev if (op == BLKIF_OP_READ || 569843e1988Sjohnlev op == BLKIF_OP_WRITE || 570843e1988Sjohnlev op == BLKIF_OP_WRITE_BARRIER || 571843e1988Sjohnlev op == BLKIF_OP_FLUSH_DISKCACHE) { 572843e1988Sjohnlev #ifdef DEBUG 573a576ab5bSrab xdb_dump_request_oe(reqp); 574843e1988Sjohnlev #endif 575843e1988Sjohnlev xreq = xdb_get_req(vdp); 576843e1988Sjohnlev ASSERT(xreq); 577843e1988Sjohnlev switch (op) { 578843e1988Sjohnlev case BLKIF_OP_READ: 579843e1988Sjohnlev vdp->xs_stat_req_reads++; 580843e1988Sjohnlev break; 581843e1988Sjohnlev case BLKIF_OP_WRITE_BARRIER: 582843e1988Sjohnlev vdp->xs_stat_req_barriers++; 583843e1988Sjohnlev /* FALLTHRU */ 584843e1988Sjohnlev case BLKIF_OP_WRITE: 585843e1988Sjohnlev vdp->xs_stat_req_writes++; 586843e1988Sjohnlev break; 587843e1988Sjohnlev case BLKIF_OP_FLUSH_DISKCACHE: 588843e1988Sjohnlev vdp->xs_stat_req_flushes++; 589843e1988Sjohnlev break; 590843e1988Sjohnlev } 591843e1988Sjohnlev 592843e1988Sjohnlev xreq->xr_curseg = 0; /* start from first segment */ 593a576ab5bSrab bp = xdb_get_buf(vdp, reqp, xreq); 594843e1988Sjohnlev if (bp == NULL) { 595843e1988Sjohnlev /* failed to form a buf */ 596843e1988Sjohnlev xdb_free_req(xreq); 597a576ab5bSrab xdb_response(vdp, reqp, B_FALSE); 598843e1988Sjohnlev continue; 599843e1988Sjohnlev } 600843e1988Sjohnlev bp->av_forw = NULL; 601843e1988Sjohnlev 602843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, 603843e1988Sjohnlev " buf %p, blkno %lld, size %lu, addr %p", 604843e1988Sjohnlev (void *)bp, (longlong_t)bp->b_blkno, 605843e1988Sjohnlev (ulong_t)bp->b_bcount, (void *)bp->b_un.b_addr)); 606843e1988Sjohnlev 607843e1988Sjohnlev /* send bp to underlying blk driver */ 608843e1988Sjohnlev if (vdp->xs_f_iobuf == NULL) { 609843e1988Sjohnlev vdp->xs_f_iobuf = vdp->xs_l_iobuf = bp; 610843e1988Sjohnlev } else { 611843e1988Sjohnlev vdp->xs_l_iobuf->av_forw = bp; 612843e1988Sjohnlev vdp->xs_l_iobuf = bp; 613843e1988Sjohnlev } 614843e1988Sjohnlev } else { 615a576ab5bSrab xdb_response(vdp, reqp, B_FALSE); 616843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_WARN, "xdb@%s: " 617843e1988Sjohnlev "Unsupported cmd received from dom %d", 618843e1988Sjohnlev ddi_get_name_addr(dip), vdp->xs_peer)); 619843e1988Sjohnlev } 620843e1988Sjohnlev } 621843e1988Sjohnlev /* notify our taskq to push buf to underlying blk driver */ 622843e1988Sjohnlev if (ret == DDI_INTR_CLAIMED) 623843e1988Sjohnlev cv_broadcast(&vdp->xs_iocv); 624843e1988Sjohnlev 625843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 626843e1988Sjohnlev 627843e1988Sjohnlev return (ret); 628843e1988Sjohnlev } 629843e1988Sjohnlev 630843e1988Sjohnlev static int 631843e1988Sjohnlev xdb_biodone(buf_t *bp) 632843e1988Sjohnlev { 633843e1988Sjohnlev int i, err, bioerr; 634843e1988Sjohnlev uint8_t segs; 635843e1988Sjohnlev gnttab_unmap_grant_ref_t unmapops[BLKIF_MAX_SEGMENTS_PER_REQUEST]; 636843e1988Sjohnlev xdb_request_t *xreq = XDB_BP2XREQ(bp); 637843e1988Sjohnlev xdb_t *vdp = xreq->xr_vdp; 638843e1988Sjohnlev buf_t *nbp; 639843e1988Sjohnlev 640843e1988Sjohnlev bioerr = geterror(bp); 641843e1988Sjohnlev if (bioerr) 642843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_WARN, "xdb@%s: I/O error %d", 643843e1988Sjohnlev ddi_get_name_addr(vdp->xs_dip), bioerr)); 644843e1988Sjohnlev 645843e1988Sjohnlev /* check if we are done w/ this I/O request */ 646843e1988Sjohnlev if ((bioerr == 0) && (xreq->xr_curseg < xreq->xr_buf_pages)) { 647843e1988Sjohnlev nbp = xdb_get_buf(vdp, NULL, xreq); 648843e1988Sjohnlev if (nbp) { 649843e1988Sjohnlev err = ldi_strategy(vdp->xs_ldi_hdl, nbp); 650843e1988Sjohnlev if (err == 0) { 651843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, 652843e1988Sjohnlev "sent buf to backend ok")); 653843e1988Sjohnlev return (DDI_SUCCESS); 654843e1988Sjohnlev } 655843e1988Sjohnlev bioerr = EIO; 656843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_WARN, "xdb@%s: " 657843e1988Sjohnlev "sent buf to backend dev failed, err=%d", 658843e1988Sjohnlev ddi_get_name_addr(vdp->xs_dip), err)); 659843e1988Sjohnlev } else { 660843e1988Sjohnlev bioerr = EIO; 661843e1988Sjohnlev } 662843e1988Sjohnlev } 663843e1988Sjohnlev 664843e1988Sjohnlev /* unmap io pages */ 665843e1988Sjohnlev segs = xreq->xr_buf_pages; 666843e1988Sjohnlev /* 667843e1988Sjohnlev * segs should be no bigger than BLKIF_MAX_SEGMENTS_PER_REQUEST 668843e1988Sjohnlev * according to the definition of blk interface by Xen 669843e1988Sjohnlev */ 670843e1988Sjohnlev ASSERT(segs <= BLKIF_MAX_SEGMENTS_PER_REQUEST); 671843e1988Sjohnlev for (i = 0; i < segs; i++) { 672843e1988Sjohnlev unmapops[i].host_addr = (uint64_t)(uintptr_t)XDB_IOPAGE_VA( 673843e1988Sjohnlev vdp->xs_iopage_va, xreq->xr_idx, i); 674843e1988Sjohnlev #ifdef DEBUG 675843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 676843e1988Sjohnlev unlogva(vdp, unmapops[i].host_addr); 677843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 678843e1988Sjohnlev #endif 679843e1988Sjohnlev unmapops[i].dev_bus_addr = NULL; 680843e1988Sjohnlev unmapops[i].handle = xreq->xr_page_hdls[i]; 681843e1988Sjohnlev } 682843e1988Sjohnlev err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 683843e1988Sjohnlev unmapops, segs); 684843e1988Sjohnlev ASSERT(!err); 685843e1988Sjohnlev 686843e1988Sjohnlev /* 687843e1988Sjohnlev * If we have reached a barrier write or a cache flush , then we must 688843e1988Sjohnlev * flush all our I/Os. 689843e1988Sjohnlev */ 690843e1988Sjohnlev if (xreq->xr_op == BLKIF_OP_WRITE_BARRIER || 691843e1988Sjohnlev xreq->xr_op == BLKIF_OP_FLUSH_DISKCACHE) { 692843e1988Sjohnlev /* 693843e1988Sjohnlev * XXX At this point the write did succeed, so I don't 694843e1988Sjohnlev * believe we should report an error because the flush 695843e1988Sjohnlev * failed. However, this is a debatable point, so 696843e1988Sjohnlev * maybe we need to think more carefully about this. 697843e1988Sjohnlev * For now, just cast to void. 698843e1988Sjohnlev */ 699843e1988Sjohnlev (void) ldi_ioctl(vdp->xs_ldi_hdl, 700843e1988Sjohnlev DKIOCFLUSHWRITECACHE, NULL, FKIOCTL, kcred, NULL); 701843e1988Sjohnlev } 702843e1988Sjohnlev 703843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 704843e1988Sjohnlev 705843e1988Sjohnlev /* send response back to frontend */ 7067f0b8309SEdward Pilatowicz if (vdp->xs_if_connected) { 7077f0b8309SEdward Pilatowicz ASSERT(vdp->xs_hp_connected && vdp->xs_fe_initialised); 708a576ab5bSrab if (xdb_push_response(vdp, xreq->xr_id, xreq->xr_op, bioerr)) 709843e1988Sjohnlev xvdi_notify_oe(vdp->xs_dip); 710843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, 711843e1988Sjohnlev "sent resp back to frontend, id=%llu", 712843e1988Sjohnlev (unsigned long long)xreq->xr_id)); 713843e1988Sjohnlev } 714843e1988Sjohnlev /* free io resources */ 715843e1988Sjohnlev biofini(bp); 716843e1988Sjohnlev xdb_free_req(xreq); 717843e1988Sjohnlev 718843e1988Sjohnlev vdp->xs_ionum--; 7197f0b8309SEdward Pilatowicz if (!vdp->xs_if_connected && (vdp->xs_ionum == 0)) { 720843e1988Sjohnlev /* we're closing, someone is waiting for I/O clean-up */ 721843e1988Sjohnlev cv_signal(&vdp->xs_ionumcv); 722a576ab5bSrab } 723843e1988Sjohnlev 724843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 725843e1988Sjohnlev 726843e1988Sjohnlev return (DDI_SUCCESS); 727843e1988Sjohnlev } 728843e1988Sjohnlev 729843e1988Sjohnlev static int 730843e1988Sjohnlev xdb_bindto_frontend(xdb_t *vdp) 731843e1988Sjohnlev { 732843e1988Sjohnlev int err; 733843e1988Sjohnlev char *oename; 734843e1988Sjohnlev grant_ref_t gref; 735843e1988Sjohnlev evtchn_port_t evtchn; 736843e1988Sjohnlev dev_info_t *dip = vdp->xs_dip; 737a576ab5bSrab char protocol[64] = ""; 738843e1988Sjohnlev 7397f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 7407f0b8309SEdward Pilatowicz 7417f0b8309SEdward Pilatowicz /* 7427f0b8309SEdward Pilatowicz * Switch to the XenbusStateInitialised state. This let's the 7437f0b8309SEdward Pilatowicz * frontend know that we're about to negotiate a connection. 7447f0b8309SEdward Pilatowicz */ 7457f0b8309SEdward Pilatowicz (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateInitialised); 7467f0b8309SEdward Pilatowicz 747843e1988Sjohnlev /* 748843e1988Sjohnlev * Gather info from frontend 749843e1988Sjohnlev */ 750843e1988Sjohnlev oename = xvdi_get_oename(dip); 751843e1988Sjohnlev if (oename == NULL) 752843e1988Sjohnlev return (DDI_FAILURE); 753843e1988Sjohnlev 754843e1988Sjohnlev err = xenbus_gather(XBT_NULL, oename, 7557f0b8309SEdward Pilatowicz XBP_RING_REF, "%lu", &gref, 7567f0b8309SEdward Pilatowicz XBP_EVENT_CHAN, "%u", &evtchn, 7577f0b8309SEdward Pilatowicz NULL); 758843e1988Sjohnlev if (err != 0) { 7597f0b8309SEdward Pilatowicz xvdi_dev_error(dip, err, 760843e1988Sjohnlev "Getting ring-ref and evtchn from frontend"); 761843e1988Sjohnlev return (DDI_FAILURE); 762843e1988Sjohnlev } 763843e1988Sjohnlev 764a576ab5bSrab vdp->xs_blk_protocol = BLKIF_PROTOCOL_NATIVE; 765a576ab5bSrab vdp->xs_nentry = BLKIF_RING_SIZE; 766a576ab5bSrab vdp->xs_entrysize = sizeof (union blkif_sring_entry); 767a576ab5bSrab 768a576ab5bSrab err = xenbus_gather(XBT_NULL, oename, 7697f0b8309SEdward Pilatowicz XBP_PROTOCOL, "%63s", protocol, NULL); 770a576ab5bSrab if (err) 771a576ab5bSrab (void) strcpy(protocol, "unspecified, assuming native"); 772a576ab5bSrab else { 773a576ab5bSrab /* 774a576ab5bSrab * We must check for NATIVE first, so that the fast path 775a576ab5bSrab * is taken for copying data from the guest to the host. 776a576ab5bSrab */ 777a576ab5bSrab if (strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE) != 0) { 778a576ab5bSrab if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) { 779a576ab5bSrab vdp->xs_blk_protocol = BLKIF_PROTOCOL_X86_32; 780a576ab5bSrab vdp->xs_nentry = BLKIF_X86_32_RING_SIZE; 781a576ab5bSrab vdp->xs_entrysize = 782a576ab5bSrab sizeof (union blkif_x86_32_sring_entry); 783a576ab5bSrab } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 784a576ab5bSrab 0) { 785a576ab5bSrab vdp->xs_blk_protocol = BLKIF_PROTOCOL_X86_64; 786a576ab5bSrab vdp->xs_nentry = BLKIF_X86_64_RING_SIZE; 787a576ab5bSrab vdp->xs_entrysize = 788a576ab5bSrab sizeof (union blkif_x86_64_sring_entry); 789a576ab5bSrab } else { 790a576ab5bSrab xvdi_fatal_error(dip, err, "unknown protocol"); 791a576ab5bSrab return (DDI_FAILURE); 792a576ab5bSrab } 793a576ab5bSrab } 794a576ab5bSrab } 795a576ab5bSrab #ifdef DEBUG 7961ca30e39Sjohnlev cmn_err(CE_NOTE, "!xdb@%s: blkif protocol '%s' ", 797a576ab5bSrab ddi_get_name_addr(dip), protocol); 798a576ab5bSrab #endif 799a576ab5bSrab 800843e1988Sjohnlev /* 8017f0b8309SEdward Pilatowicz * Map and init ring. The ring parameters must match those which 8027f0b8309SEdward Pilatowicz * have been allocated in the front end. 803843e1988Sjohnlev */ 8047f0b8309SEdward Pilatowicz if (xvdi_map_ring(dip, vdp->xs_nentry, vdp->xs_entrysize, 8057f0b8309SEdward Pilatowicz gref, &vdp->xs_ring) != DDI_SUCCESS) 806843e1988Sjohnlev return (DDI_FAILURE); 8077f0b8309SEdward Pilatowicz 808843e1988Sjohnlev /* 809843e1988Sjohnlev * This will be removed after we use shadow I/O ring request since 810843e1988Sjohnlev * we don't need to access the ring itself directly, thus the access 811843e1988Sjohnlev * handle is not needed 812843e1988Sjohnlev */ 813843e1988Sjohnlev vdp->xs_ring_hdl = vdp->xs_ring->xr_acc_hdl; 814843e1988Sjohnlev 8157f0b8309SEdward Pilatowicz /* bind event channel */ 816843e1988Sjohnlev err = xvdi_bind_evtchn(dip, evtchn); 817843e1988Sjohnlev if (err != DDI_SUCCESS) { 818843e1988Sjohnlev xvdi_unmap_ring(vdp->xs_ring); 819843e1988Sjohnlev return (DDI_FAILURE); 820843e1988Sjohnlev } 821843e1988Sjohnlev 822843e1988Sjohnlev return (DDI_SUCCESS); 823843e1988Sjohnlev } 824843e1988Sjohnlev 825843e1988Sjohnlev static void 826843e1988Sjohnlev xdb_unbindfrom_frontend(xdb_t *vdp) 827843e1988Sjohnlev { 8287f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 8297f0b8309SEdward Pilatowicz 830843e1988Sjohnlev xvdi_free_evtchn(vdp->xs_dip); 831843e1988Sjohnlev xvdi_unmap_ring(vdp->xs_ring); 832843e1988Sjohnlev } 833843e1988Sjohnlev 8347f0b8309SEdward Pilatowicz /* 8357f0b8309SEdward Pilatowicz * xdb_params_change() initiates a allows change to the underlying device/file 8367f0b8309SEdward Pilatowicz * that the backend is accessing. It does this by disconnecting from the 8377f0b8309SEdward Pilatowicz * frontend, closing the old device, clearing a bunch of xenbus parameters, 8387f0b8309SEdward Pilatowicz * and switching back to the XenbusStateInitialising state. The frontend 8397f0b8309SEdward Pilatowicz * should notice this transition to the XenbusStateInitialising state and 8407f0b8309SEdward Pilatowicz * should attempt to reconnect to us (the backend). 8417f0b8309SEdward Pilatowicz */ 8427f0b8309SEdward Pilatowicz static void 8437f0b8309SEdward Pilatowicz xdb_params_change(xdb_t *vdp, char *params, boolean_t update_xs) 8447f0b8309SEdward Pilatowicz { 8457f0b8309SEdward Pilatowicz xenbus_transaction_t xbt; 8467f0b8309SEdward Pilatowicz dev_info_t *dip = vdp->xs_dip; 8477f0b8309SEdward Pilatowicz char *xsname; 8487f0b8309SEdward Pilatowicz int err; 8497f0b8309SEdward Pilatowicz 8507f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 8517f0b8309SEdward Pilatowicz ASSERT(vdp->xs_params_path != NULL); 8527f0b8309SEdward Pilatowicz 8537f0b8309SEdward Pilatowicz if ((xsname = xvdi_get_xsname(dip)) == NULL) 8547f0b8309SEdward Pilatowicz return; 8557f0b8309SEdward Pilatowicz if (strcmp(vdp->xs_params_path, params) == 0) 8567f0b8309SEdward Pilatowicz return; 8577f0b8309SEdward Pilatowicz 8587f0b8309SEdward Pilatowicz /* 8597f0b8309SEdward Pilatowicz * Close the device we're currently accessing and update the 8607f0b8309SEdward Pilatowicz * path which points to our backend device/file. 8617f0b8309SEdward Pilatowicz */ 8627f0b8309SEdward Pilatowicz xdb_close(dip); 8637f0b8309SEdward Pilatowicz vdp->xs_fe_initialised = B_FALSE; 8647f0b8309SEdward Pilatowicz 8657f0b8309SEdward Pilatowicz trans_retry: 8667f0b8309SEdward Pilatowicz if ((err = xenbus_transaction_start(&xbt)) != 0) { 8677f0b8309SEdward Pilatowicz xvdi_dev_error(dip, err, "params change transaction init"); 8687f0b8309SEdward Pilatowicz goto errout; 8697f0b8309SEdward Pilatowicz } 8707f0b8309SEdward Pilatowicz 8717f0b8309SEdward Pilatowicz /* 8727f0b8309SEdward Pilatowicz * Delete all the xenbus properties that are connection dependant 8737f0b8309SEdward Pilatowicz * and go back to the initializing state so that the frontend 8747f0b8309SEdward Pilatowicz * driver can re-negotiate a connection. 8757f0b8309SEdward Pilatowicz */ 8767f0b8309SEdward Pilatowicz if (((err = xenbus_rm(xbt, xsname, XBP_FB)) != 0) || 8777f0b8309SEdward Pilatowicz ((err = xenbus_rm(xbt, xsname, XBP_INFO)) != 0) || 8787f0b8309SEdward Pilatowicz ((err = xenbus_rm(xbt, xsname, "sector-size")) != 0) || 8797f0b8309SEdward Pilatowicz ((err = xenbus_rm(xbt, xsname, XBP_SECTORS)) != 0) || 8807f0b8309SEdward Pilatowicz ((err = xenbus_rm(xbt, xsname, "instance")) != 0) || 8817f0b8309SEdward Pilatowicz ((err = xenbus_rm(xbt, xsname, "node")) != 0) || 8827f0b8309SEdward Pilatowicz (update_xs && ((err = xenbus_printf(xbt, xsname, 8837f0b8309SEdward Pilatowicz "params", "%s", params)) != 0)) || 8847f0b8309SEdward Pilatowicz ((err = xvdi_switch_state(dip, 8857f0b8309SEdward Pilatowicz xbt, XenbusStateInitialising) > 0))) { 8867f0b8309SEdward Pilatowicz (void) xenbus_transaction_end(xbt, 1); 8877f0b8309SEdward Pilatowicz xvdi_dev_error(dip, err, "params change transaction setup"); 8887f0b8309SEdward Pilatowicz goto errout; 8897f0b8309SEdward Pilatowicz } 8907f0b8309SEdward Pilatowicz 8917f0b8309SEdward Pilatowicz if ((err = xenbus_transaction_end(xbt, 0)) != 0) { 8927f0b8309SEdward Pilatowicz if (err == EAGAIN) { 8937f0b8309SEdward Pilatowicz /* transaction is ended, don't need to abort it */ 8947f0b8309SEdward Pilatowicz goto trans_retry; 8957f0b8309SEdward Pilatowicz } 8967f0b8309SEdward Pilatowicz xvdi_dev_error(dip, err, "params change transaction commit"); 8977f0b8309SEdward Pilatowicz goto errout; 8987f0b8309SEdward Pilatowicz } 8997f0b8309SEdward Pilatowicz 9007f0b8309SEdward Pilatowicz /* Change the device that we plan to access */ 9017f0b8309SEdward Pilatowicz strfree(vdp->xs_params_path); 9027f0b8309SEdward Pilatowicz vdp->xs_params_path = strdup(params); 9037f0b8309SEdward Pilatowicz return; 9047f0b8309SEdward Pilatowicz 9057f0b8309SEdward Pilatowicz errout: 9067f0b8309SEdward Pilatowicz (void) xvdi_switch_state(dip, xbt, XenbusStateInitialising); 9077f0b8309SEdward Pilatowicz } 9087f0b8309SEdward Pilatowicz 9097f0b8309SEdward Pilatowicz /* 9107f0b8309SEdward Pilatowicz * xdb_watch_params_cb() - This callback is invoked whenever there 9117f0b8309SEdward Pilatowicz * is an update to the following xenbus parameter: 9127f0b8309SEdward Pilatowicz * /local/domain/0/backend/vbd/<domU_id>/<domU_dev>/params 9137f0b8309SEdward Pilatowicz * 9147f0b8309SEdward Pilatowicz * This normally happens during xm block-configure operations, which 9157f0b8309SEdward Pilatowicz * are used to change CD device images for HVM domUs. 9167f0b8309SEdward Pilatowicz */ 9177f0b8309SEdward Pilatowicz /*ARGSUSED*/ 9187f0b8309SEdward Pilatowicz static void 9197f0b8309SEdward Pilatowicz xdb_watch_params_cb(dev_info_t *dip, const char *path, void *arg) 9207f0b8309SEdward Pilatowicz { 9217f0b8309SEdward Pilatowicz xdb_t *vdp = (xdb_t *)ddi_get_driver_private(dip); 9227f0b8309SEdward Pilatowicz char *xsname, *oename, *str, *str2; 9237f0b8309SEdward Pilatowicz 9247f0b8309SEdward Pilatowicz if (((xsname = xvdi_get_xsname(dip)) == NULL) || 9257f0b8309SEdward Pilatowicz ((oename = xvdi_get_oename(dip)) == NULL)) { 9267f0b8309SEdward Pilatowicz return; 9277f0b8309SEdward Pilatowicz } 9287f0b8309SEdward Pilatowicz 9297f0b8309SEdward Pilatowicz mutex_enter(&vdp->xs_cbmutex); 9307f0b8309SEdward Pilatowicz 9317f0b8309SEdward Pilatowicz if (xenbus_read_str(xsname, "params", &str) != 0) { 9327f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 9337f0b8309SEdward Pilatowicz return; 9347f0b8309SEdward Pilatowicz } 9357f0b8309SEdward Pilatowicz 9367f0b8309SEdward Pilatowicz if (strcmp(vdp->xs_params_path, str) == 0) { 9377f0b8309SEdward Pilatowicz /* Nothing todo */ 9387f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 9397f0b8309SEdward Pilatowicz strfree(str); 9407f0b8309SEdward Pilatowicz return; 9417f0b8309SEdward Pilatowicz } 9427f0b8309SEdward Pilatowicz 9437f0b8309SEdward Pilatowicz /* 9447f0b8309SEdward Pilatowicz * If the frontend isn't a cd device, doesn't support media 9457f0b8309SEdward Pilatowicz * requests, or has locked the media, then we can't change 9467f0b8309SEdward Pilatowicz * the params value. restore the current value. 9477f0b8309SEdward Pilatowicz */ 9487f0b8309SEdward Pilatowicz str2 = NULL; 9497f0b8309SEdward Pilatowicz if (!XDB_IS_FE_CD(vdp) || 9507f0b8309SEdward Pilatowicz (xenbus_read_str(oename, XBP_MEDIA_REQ, &str2) != 0) || 9517f0b8309SEdward Pilatowicz (strcmp(str2, XBV_MEDIA_REQ_LOCK) == 0)) { 9527f0b8309SEdward Pilatowicz if (str2 != NULL) 9537f0b8309SEdward Pilatowicz strfree(str2); 9547f0b8309SEdward Pilatowicz strfree(str); 9557f0b8309SEdward Pilatowicz 9567f0b8309SEdward Pilatowicz str = i_pathname(dip); 9577f0b8309SEdward Pilatowicz cmn_err(CE_NOTE, 9587f0b8309SEdward Pilatowicz "!%s: media locked, ignoring params update", str); 9597f0b8309SEdward Pilatowicz strfree(str); 9607f0b8309SEdward Pilatowicz 9617f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 9627f0b8309SEdward Pilatowicz return; 9637f0b8309SEdward Pilatowicz } 9647f0b8309SEdward Pilatowicz 9657f0b8309SEdward Pilatowicz XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, 9667f0b8309SEdward Pilatowicz "block-configure params request: \"%s\"", str)); 9677f0b8309SEdward Pilatowicz 9687f0b8309SEdward Pilatowicz xdb_params_change(vdp, str, B_FALSE); 9697f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 9707f0b8309SEdward Pilatowicz strfree(str); 9717f0b8309SEdward Pilatowicz } 9727f0b8309SEdward Pilatowicz 9737f0b8309SEdward Pilatowicz /* 9747f0b8309SEdward Pilatowicz * xdb_watch_media_req_cb() - This callback is invoked whenever there 9757f0b8309SEdward Pilatowicz * is an update to the following xenbus parameter: 9767f0b8309SEdward Pilatowicz * /local/domain/<domU_id>/device/vbd/<domU_dev>/media-req 9777f0b8309SEdward Pilatowicz * 9787f0b8309SEdward Pilatowicz * Media requests are only supported on CD devices and are issued by 9797f0b8309SEdward Pilatowicz * the frontend. Currently the only supported media request operaions 9807f0b8309SEdward Pilatowicz * are "lock" and "eject". A "lock" prevents the backend from changing 9817f0b8309SEdward Pilatowicz * the backing device/file (via xm block-configure). An "eject" requests 9827f0b8309SEdward Pilatowicz * tells the backend device that it should disconnect from the frontend 9837f0b8309SEdward Pilatowicz * and closing the backing device/file that is currently in use. 9847f0b8309SEdward Pilatowicz */ 9857f0b8309SEdward Pilatowicz /*ARGSUSED*/ 9867f0b8309SEdward Pilatowicz static void 9877f0b8309SEdward Pilatowicz xdb_watch_media_req_cb(dev_info_t *dip, const char *path, void *arg) 9887f0b8309SEdward Pilatowicz { 9897f0b8309SEdward Pilatowicz xdb_t *vdp = (xdb_t *)ddi_get_driver_private(dip); 9907f0b8309SEdward Pilatowicz char *oename, *str; 9917f0b8309SEdward Pilatowicz 9927f0b8309SEdward Pilatowicz mutex_enter(&vdp->xs_cbmutex); 9937f0b8309SEdward Pilatowicz 9947f0b8309SEdward Pilatowicz if ((oename = xvdi_get_oename(dip)) == NULL) { 9957f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 9967f0b8309SEdward Pilatowicz return; 9977f0b8309SEdward Pilatowicz } 9987f0b8309SEdward Pilatowicz 9997f0b8309SEdward Pilatowicz if (xenbus_read_str(oename, XBP_MEDIA_REQ, &str) != 0) { 10007f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 10017f0b8309SEdward Pilatowicz return; 10027f0b8309SEdward Pilatowicz } 10037f0b8309SEdward Pilatowicz 10047f0b8309SEdward Pilatowicz if (!XDB_IS_FE_CD(vdp)) { 10057f0b8309SEdward Pilatowicz xvdi_dev_error(dip, EINVAL, 10067f0b8309SEdward Pilatowicz "media-req only supported for cdrom devices"); 10077f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 10087f0b8309SEdward Pilatowicz return; 10097f0b8309SEdward Pilatowicz } 10107f0b8309SEdward Pilatowicz 10117f0b8309SEdward Pilatowicz if (strcmp(str, XBV_MEDIA_REQ_EJECT) != 0) { 10127f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 10137f0b8309SEdward Pilatowicz strfree(str); 10147f0b8309SEdward Pilatowicz return; 10157f0b8309SEdward Pilatowicz } 10167f0b8309SEdward Pilatowicz strfree(str); 10177f0b8309SEdward Pilatowicz 10187f0b8309SEdward Pilatowicz XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "media eject request")); 10197f0b8309SEdward Pilatowicz 10207f0b8309SEdward Pilatowicz xdb_params_change(vdp, "", B_TRUE); 10217f0b8309SEdward Pilatowicz (void) xenbus_printf(XBT_NULL, oename, 10227f0b8309SEdward Pilatowicz XBP_MEDIA_REQ, "%s", XBV_MEDIA_REQ_NONE); 10237f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 10247f0b8309SEdward Pilatowicz } 10257f0b8309SEdward Pilatowicz 10267f0b8309SEdward Pilatowicz /* 10277f0b8309SEdward Pilatowicz * If we're dealing with a cdrom device, let the frontend know that 10287f0b8309SEdward Pilatowicz * we support media requests via XBP_MEDIA_REQ_SUP, and setup a watch 10297f0b8309SEdward Pilatowicz * to handle those frontend media request changes, which modify the 10307f0b8309SEdward Pilatowicz * following xenstore parameter: 10317f0b8309SEdward Pilatowicz * /local/domain/<domU_id>/device/vbd/<domU_dev>/media-req 10327f0b8309SEdward Pilatowicz */ 10337f0b8309SEdward Pilatowicz static boolean_t 10347f0b8309SEdward Pilatowicz xdb_media_req_init(xdb_t *vdp) 10357f0b8309SEdward Pilatowicz { 10367f0b8309SEdward Pilatowicz dev_info_t *dip = vdp->xs_dip; 10377f0b8309SEdward Pilatowicz char *xsname, *oename; 10387f0b8309SEdward Pilatowicz 10397f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 10407f0b8309SEdward Pilatowicz 10417f0b8309SEdward Pilatowicz if (((xsname = xvdi_get_xsname(dip)) == NULL) || 10427f0b8309SEdward Pilatowicz ((oename = xvdi_get_oename(dip)) == NULL)) 10437f0b8309SEdward Pilatowicz return (B_FALSE); 10447f0b8309SEdward Pilatowicz 10457f0b8309SEdward Pilatowicz if (!XDB_IS_FE_CD(vdp)) 10467f0b8309SEdward Pilatowicz return (B_TRUE); 10477f0b8309SEdward Pilatowicz 10487f0b8309SEdward Pilatowicz if (xenbus_printf(XBT_NULL, xsname, XBP_MEDIA_REQ_SUP, "%d", 1) != 0) 10497f0b8309SEdward Pilatowicz return (B_FALSE); 10507f0b8309SEdward Pilatowicz 10517f0b8309SEdward Pilatowicz if (xvdi_add_xb_watch_handler(dip, oename, 10527f0b8309SEdward Pilatowicz XBP_MEDIA_REQ, xdb_watch_media_req_cb, NULL) != DDI_SUCCESS) { 10537f0b8309SEdward Pilatowicz xvdi_dev_error(dip, EAGAIN, 10547f0b8309SEdward Pilatowicz "Failed to register watch for cdrom media requests"); 10557f0b8309SEdward Pilatowicz return (B_FALSE); 10567f0b8309SEdward Pilatowicz } 10577f0b8309SEdward Pilatowicz 10587f0b8309SEdward Pilatowicz return (B_TRUE); 10597f0b8309SEdward Pilatowicz } 10607f0b8309SEdward Pilatowicz 10617f0b8309SEdward Pilatowicz /* 10627f0b8309SEdward Pilatowicz * Get our params value. Also, if we're using "params" then setup a 10637f0b8309SEdward Pilatowicz * watch to handle xm block-configure operations which modify the 10647f0b8309SEdward Pilatowicz * following xenstore parameter: 10657f0b8309SEdward Pilatowicz * /local/domain/0/backend/vbd/<domU_id>/<domU_dev>/params 10667f0b8309SEdward Pilatowicz */ 10677f0b8309SEdward Pilatowicz static boolean_t 10687f0b8309SEdward Pilatowicz xdb_params_init(xdb_t *vdp) 10697f0b8309SEdward Pilatowicz { 10707f0b8309SEdward Pilatowicz dev_info_t *dip = vdp->xs_dip; 10717f0b8309SEdward Pilatowicz char *str, *xsname; 1072*349b53ddSStuart Maybee int err; 10737f0b8309SEdward Pilatowicz 10747f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 10757f0b8309SEdward Pilatowicz ASSERT(vdp->xs_params_path == NULL); 10767f0b8309SEdward Pilatowicz 10777f0b8309SEdward Pilatowicz if ((xsname = xvdi_get_xsname(dip)) == NULL) 10787f0b8309SEdward Pilatowicz return (B_FALSE); 10797f0b8309SEdward Pilatowicz 10807f0b8309SEdward Pilatowicz err = xenbus_read_str(xsname, "params", &str); 1081*349b53ddSStuart Maybee if (err != 0) { 10827f0b8309SEdward Pilatowicz return (B_FALSE); 1083*349b53ddSStuart Maybee } 10847f0b8309SEdward Pilatowicz vdp->xs_params_path = str; 10857f0b8309SEdward Pilatowicz 10867f0b8309SEdward Pilatowicz if (xvdi_add_xb_watch_handler(dip, xsname, "params", 10877f0b8309SEdward Pilatowicz xdb_watch_params_cb, NULL) != DDI_SUCCESS) { 10887f0b8309SEdward Pilatowicz strfree(vdp->xs_params_path); 10897f0b8309SEdward Pilatowicz vdp->xs_params_path = NULL; 10907f0b8309SEdward Pilatowicz return (B_FALSE); 10917f0b8309SEdward Pilatowicz } 10927f0b8309SEdward Pilatowicz 10937f0b8309SEdward Pilatowicz return (B_TRUE); 10947f0b8309SEdward Pilatowicz } 10957f0b8309SEdward Pilatowicz 1096843e1988Sjohnlev #define LOFI_CTRL_NODE "/dev/lofictl" 1097843e1988Sjohnlev #define LOFI_DEV_NODE "/devices/pseudo/lofi@0:" 10987f0b8309SEdward Pilatowicz #define LOFI_MODE (FREAD | FWRITE | FEXCL) 1099843e1988Sjohnlev 1100843e1988Sjohnlev static int 1101843e1988Sjohnlev xdb_setup_node(xdb_t *vdp, char *path) 1102843e1988Sjohnlev { 11037f0b8309SEdward Pilatowicz dev_info_t *dip = vdp->xs_dip; 11047f0b8309SEdward Pilatowicz char *xsname, *str; 1105843e1988Sjohnlev ldi_handle_t ldi_hdl; 1106843e1988Sjohnlev struct lofi_ioctl *li; 11077f0b8309SEdward Pilatowicz int minor, err; 1108843e1988Sjohnlev 11097f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 11107f0b8309SEdward Pilatowicz 11117f0b8309SEdward Pilatowicz if ((xsname = xvdi_get_xsname(dip)) == NULL) 1112843e1988Sjohnlev return (DDI_FAILURE); 1113843e1988Sjohnlev 11147f0b8309SEdward Pilatowicz if ((err = xenbus_read_str(xsname, "type", &str)) != 0) { 11157f0b8309SEdward Pilatowicz xvdi_dev_error(dip, err, "Getting type from backend device"); 1116843e1988Sjohnlev return (DDI_FAILURE); 1117843e1988Sjohnlev } 11187f0b8309SEdward Pilatowicz if (strcmp(str, "file") == 0) 11197f0b8309SEdward Pilatowicz vdp->xs_type |= XDB_DEV_BE_LOFI; 11207f0b8309SEdward Pilatowicz strfree(str); 1121843e1988Sjohnlev 11227f0b8309SEdward Pilatowicz if (!XDB_IS_BE_LOFI(vdp)) { 11237f0b8309SEdward Pilatowicz (void) strlcpy(path, vdp->xs_params_path, MAXPATHLEN); 11247f0b8309SEdward Pilatowicz ASSERT(vdp->xs_lofi_path == NULL); 1125843e1988Sjohnlev return (DDI_SUCCESS); 1126843e1988Sjohnlev } 1127843e1988Sjohnlev 1128843e1988Sjohnlev do { 1129843e1988Sjohnlev err = ldi_open_by_name(LOFI_CTRL_NODE, LOFI_MODE, kcred, 1130843e1988Sjohnlev &ldi_hdl, vdp->xs_ldi_li); 1131843e1988Sjohnlev } while (err == EBUSY); 1132843e1988Sjohnlev if (err != 0) { 1133843e1988Sjohnlev return (DDI_FAILURE); 1134843e1988Sjohnlev } 1135843e1988Sjohnlev 1136843e1988Sjohnlev li = kmem_zalloc(sizeof (*li), KM_SLEEP); 11377f0b8309SEdward Pilatowicz (void) strlcpy(li->li_filename, vdp->xs_params_path, 11387f0b8309SEdward Pilatowicz sizeof (li->li_filename)); 11397f0b8309SEdward Pilatowicz err = ldi_ioctl(ldi_hdl, LOFI_MAP_FILE, (intptr_t)li, 11407f0b8309SEdward Pilatowicz LOFI_MODE | FKIOCTL, kcred, &minor); 1141843e1988Sjohnlev (void) ldi_close(ldi_hdl, LOFI_MODE, kcred); 1142843e1988Sjohnlev kmem_free(li, sizeof (*li)); 11437f0b8309SEdward Pilatowicz 11447f0b8309SEdward Pilatowicz if (err != 0) { 11457f0b8309SEdward Pilatowicz cmn_err(CE_WARN, "xdb@%s: Failed to create lofi dev for %s", 11467f0b8309SEdward Pilatowicz ddi_get_name_addr(dip), vdp->xs_params_path); 1147843e1988Sjohnlev return (DDI_FAILURE); 1148843e1988Sjohnlev } 11497f0b8309SEdward Pilatowicz 1150843e1988Sjohnlev /* 1151843e1988Sjohnlev * return '/devices/...' instead of '/dev/lofi/...' since the 1152843e1988Sjohnlev * former is available immediately after calling ldi_ioctl 1153843e1988Sjohnlev */ 11546f02aa44SDina K Nimeh (void) snprintf(path, MAXPATHLEN, LOFI_DEV_NODE "%d", minor); 11557f0b8309SEdward Pilatowicz (void) xenbus_printf(XBT_NULL, xsname, "node", "%s", path); 11567f0b8309SEdward Pilatowicz 11577f0b8309SEdward Pilatowicz ASSERT(vdp->xs_lofi_path == NULL); 11587f0b8309SEdward Pilatowicz vdp->xs_lofi_path = strdup(path); 11597f0b8309SEdward Pilatowicz 1160843e1988Sjohnlev return (DDI_SUCCESS); 1161843e1988Sjohnlev } 1162843e1988Sjohnlev 1163843e1988Sjohnlev static void 1164843e1988Sjohnlev xdb_teardown_node(xdb_t *vdp) 1165843e1988Sjohnlev { 11667f0b8309SEdward Pilatowicz dev_info_t *dip = vdp->xs_dip; 1167843e1988Sjohnlev ldi_handle_t ldi_hdl; 1168843e1988Sjohnlev struct lofi_ioctl *li; 1169843e1988Sjohnlev int err; 1170843e1988Sjohnlev 11717f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 11727f0b8309SEdward Pilatowicz 11737f0b8309SEdward Pilatowicz if (!XDB_IS_BE_LOFI(vdp)) 1174843e1988Sjohnlev return; 1175843e1988Sjohnlev 11767f0b8309SEdward Pilatowicz vdp->xs_type &= ~XDB_DEV_BE_LOFI; 11777f0b8309SEdward Pilatowicz ASSERT(vdp->xs_lofi_path != NULL); 1178843e1988Sjohnlev 1179843e1988Sjohnlev li = kmem_zalloc(sizeof (*li), KM_SLEEP); 11807f0b8309SEdward Pilatowicz (void) strlcpy(li->li_filename, vdp->xs_params_path, 11817f0b8309SEdward Pilatowicz sizeof (li->li_filename)); 1182843e1988Sjohnlev 1183843e1988Sjohnlev do { 1184843e1988Sjohnlev err = ldi_open_by_name(LOFI_CTRL_NODE, LOFI_MODE, kcred, 1185843e1988Sjohnlev &ldi_hdl, vdp->xs_ldi_li); 1186843e1988Sjohnlev } while (err == EBUSY); 1187843e1988Sjohnlev 1188843e1988Sjohnlev if (err != 0) { 1189843e1988Sjohnlev kmem_free(li, sizeof (*li)); 1190843e1988Sjohnlev return; 1191843e1988Sjohnlev } 1192843e1988Sjohnlev 1193843e1988Sjohnlev if (ldi_ioctl(ldi_hdl, LOFI_UNMAP_FILE, (intptr_t)li, 1194843e1988Sjohnlev LOFI_MODE | FKIOCTL, kcred, NULL) != 0) { 1195843e1988Sjohnlev cmn_err(CE_WARN, "xdb@%s: Failed to delete lofi dev for %s", 1196843e1988Sjohnlev ddi_get_name_addr(dip), li->li_filename); 1197843e1988Sjohnlev } 1198843e1988Sjohnlev 1199843e1988Sjohnlev (void) ldi_close(ldi_hdl, LOFI_MODE, kcred); 1200843e1988Sjohnlev kmem_free(li, sizeof (*li)); 12017f0b8309SEdward Pilatowicz 12027f0b8309SEdward Pilatowicz strfree(vdp->xs_lofi_path); 12037f0b8309SEdward Pilatowicz vdp->xs_lofi_path = NULL; 1204843e1988Sjohnlev } 1205843e1988Sjohnlev 1206843e1988Sjohnlev static int 1207843e1988Sjohnlev xdb_open_device(xdb_t *vdp) 1208843e1988Sjohnlev { 12097f0b8309SEdward Pilatowicz dev_info_t *dip = vdp->xs_dip; 1210843e1988Sjohnlev uint64_t devsize; 121165908c77Syu, larry liu - Sun Microsystems - Beijing China int blksize; 1212843e1988Sjohnlev char *nodepath; 1213*349b53ddSStuart Maybee char *xsname; 1214*349b53ddSStuart Maybee char *str; 1215*349b53ddSStuart Maybee int err; 1216843e1988Sjohnlev 12177f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 1218843e1988Sjohnlev 12197f0b8309SEdward Pilatowicz if (strlen(vdp->xs_params_path) == 0) { 1220843e1988Sjohnlev /* 12217f0b8309SEdward Pilatowicz * it's possible to have no backing device when dealing 12227f0b8309SEdward Pilatowicz * with a pv cdrom drive that has no virtual cd associated 12237f0b8309SEdward Pilatowicz * with it. 1224843e1988Sjohnlev */ 12257f0b8309SEdward Pilatowicz ASSERT(XDB_IS_FE_CD(vdp)); 12267f0b8309SEdward Pilatowicz ASSERT(vdp->xs_sectors == 0); 12277f0b8309SEdward Pilatowicz ASSERT(vdp->xs_ldi_li == NULL); 12287f0b8309SEdward Pilatowicz ASSERT(vdp->xs_ldi_hdl == NULL); 12297f0b8309SEdward Pilatowicz return (DDI_SUCCESS); 12307f0b8309SEdward Pilatowicz } 12317f0b8309SEdward Pilatowicz 1232*349b53ddSStuart Maybee /* 1233*349b53ddSStuart Maybee * after the hotplug scripts have "connected" the device, check to see 1234*349b53ddSStuart Maybee * if we're using a dynamic device. If so, replace the params path 1235*349b53ddSStuart Maybee * with the dynamic one. 1236*349b53ddSStuart Maybee */ 1237*349b53ddSStuart Maybee xsname = xvdi_get_xsname(dip); 1238*349b53ddSStuart Maybee err = xenbus_read_str(xsname, "dynamic-device-path", &str); 1239*349b53ddSStuart Maybee if (err == 0) { 1240*349b53ddSStuart Maybee strfree(vdp->xs_params_path); 1241*349b53ddSStuart Maybee vdp->xs_params_path = str; 1242*349b53ddSStuart Maybee } 1243*349b53ddSStuart Maybee 1244843e1988Sjohnlev if (ldi_ident_from_dip(dip, &vdp->xs_ldi_li) != 0) 1245843e1988Sjohnlev return (DDI_FAILURE); 1246843e1988Sjohnlev 12476f02aa44SDina K Nimeh nodepath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 12487f0b8309SEdward Pilatowicz 12497f0b8309SEdward Pilatowicz /* try to open backend device */ 12507f0b8309SEdward Pilatowicz if (xdb_setup_node(vdp, nodepath) != DDI_SUCCESS) { 12517f0b8309SEdward Pilatowicz xvdi_dev_error(dip, ENXIO, 1252843e1988Sjohnlev "Getting device path of backend device"); 1253843e1988Sjohnlev ldi_ident_release(vdp->xs_ldi_li); 12546f02aa44SDina K Nimeh kmem_free(nodepath, MAXPATHLEN); 1255843e1988Sjohnlev return (DDI_FAILURE); 1256843e1988Sjohnlev } 1257843e1988Sjohnlev 1258843e1988Sjohnlev if (ldi_open_by_name(nodepath, 1259843e1988Sjohnlev FREAD | (XDB_IS_RO(vdp) ? 0 : FWRITE), 1260843e1988Sjohnlev kcred, &vdp->xs_ldi_hdl, vdp->xs_ldi_li) != 0) { 1261843e1988Sjohnlev xdb_teardown_node(vdp); 1262843e1988Sjohnlev ldi_ident_release(vdp->xs_ldi_li); 1263843e1988Sjohnlev cmn_err(CE_WARN, "xdb@%s: Failed to open: %s", 1264843e1988Sjohnlev ddi_get_name_addr(dip), nodepath); 12656f02aa44SDina K Nimeh kmem_free(nodepath, MAXPATHLEN); 1266843e1988Sjohnlev return (DDI_FAILURE); 1267843e1988Sjohnlev } 1268843e1988Sjohnlev 1269843e1988Sjohnlev if (ldi_get_size(vdp->xs_ldi_hdl, &devsize) != DDI_SUCCESS) { 1270843e1988Sjohnlev (void) ldi_close(vdp->xs_ldi_hdl, 1271843e1988Sjohnlev FREAD | (XDB_IS_RO(vdp) ? 0 : FWRITE), kcred); 1272843e1988Sjohnlev xdb_teardown_node(vdp); 1273843e1988Sjohnlev ldi_ident_release(vdp->xs_ldi_li); 12746f02aa44SDina K Nimeh kmem_free(nodepath, MAXPATHLEN); 1275843e1988Sjohnlev return (DDI_FAILURE); 1276843e1988Sjohnlev } 127765908c77Syu, larry liu - Sun Microsystems - Beijing China 127865908c77Syu, larry liu - Sun Microsystems - Beijing China blksize = ldi_prop_get_int64(vdp->xs_ldi_hdl, 127965908c77Syu, larry liu - Sun Microsystems - Beijing China DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 128065908c77Syu, larry liu - Sun Microsystems - Beijing China "blksize", DEV_BSIZE); 128165908c77Syu, larry liu - Sun Microsystems - Beijing China if (blksize == DEV_BSIZE) 128265908c77Syu, larry liu - Sun Microsystems - Beijing China blksize = ldi_prop_get_int(vdp->xs_ldi_hdl, 128365908c77Syu, larry liu - Sun Microsystems - Beijing China LDI_DEV_T_ANY | DDI_PROP_DONTPASS | 128465908c77Syu, larry liu - Sun Microsystems - Beijing China DDI_PROP_NOTPROM, "device-blksize", DEV_BSIZE); 128565908c77Syu, larry liu - Sun Microsystems - Beijing China 128665908c77Syu, larry liu - Sun Microsystems - Beijing China vdp->xs_sec_size = blksize; 128765908c77Syu, larry liu - Sun Microsystems - Beijing China vdp->xs_sectors = devsize / blksize; 1288843e1988Sjohnlev 12897f0b8309SEdward Pilatowicz /* check if the underlying device is a CD/DVD disc */ 12907f0b8309SEdward Pilatowicz if (ldi_prop_get_int(vdp->xs_ldi_hdl, LDI_DEV_T_ANY | DDI_PROP_DONTPASS, 12917f0b8309SEdward Pilatowicz INQUIRY_DEVICE_TYPE, DTYPE_DIRECT) == DTYPE_RODIRECT) 12927f0b8309SEdward Pilatowicz vdp->xs_type |= XDB_DEV_BE_CD; 12937f0b8309SEdward Pilatowicz 12947f0b8309SEdward Pilatowicz /* check if the underlying device is a removable disk */ 12957f0b8309SEdward Pilatowicz if (ldi_prop_exists(vdp->xs_ldi_hdl, 12967f0b8309SEdward Pilatowicz LDI_DEV_T_ANY | DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 12977f0b8309SEdward Pilatowicz "removable-media")) 12987f0b8309SEdward Pilatowicz vdp->xs_type |= XDB_DEV_BE_RMB; 12997f0b8309SEdward Pilatowicz 13006f02aa44SDina K Nimeh kmem_free(nodepath, MAXPATHLEN); 1301843e1988Sjohnlev return (DDI_SUCCESS); 1302843e1988Sjohnlev } 1303843e1988Sjohnlev 1304843e1988Sjohnlev static void 1305843e1988Sjohnlev xdb_close_device(xdb_t *vdp) 1306843e1988Sjohnlev { 13077f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 13087f0b8309SEdward Pilatowicz 13097f0b8309SEdward Pilatowicz if (strlen(vdp->xs_params_path) == 0) { 13107f0b8309SEdward Pilatowicz ASSERT(XDB_IS_FE_CD(vdp)); 13117f0b8309SEdward Pilatowicz ASSERT(vdp->xs_sectors == 0); 13127f0b8309SEdward Pilatowicz ASSERT(vdp->xs_ldi_li == NULL); 13137f0b8309SEdward Pilatowicz ASSERT(vdp->xs_ldi_hdl == NULL); 13147f0b8309SEdward Pilatowicz return; 13157f0b8309SEdward Pilatowicz } 13167f0b8309SEdward Pilatowicz 1317843e1988Sjohnlev (void) ldi_close(vdp->xs_ldi_hdl, 1318843e1988Sjohnlev FREAD | (XDB_IS_RO(vdp) ? 0 : FWRITE), kcred); 1319843e1988Sjohnlev xdb_teardown_node(vdp); 1320843e1988Sjohnlev ldi_ident_release(vdp->xs_ldi_li); 13217f0b8309SEdward Pilatowicz vdp->xs_type &= ~(XDB_DEV_BE_CD | XDB_DEV_BE_RMB); 13227f0b8309SEdward Pilatowicz vdp->xs_sectors = 0; 1323843e1988Sjohnlev vdp->xs_ldi_li = NULL; 1324843e1988Sjohnlev vdp->xs_ldi_hdl = NULL; 1325843e1988Sjohnlev } 1326843e1988Sjohnlev 1327843e1988Sjohnlev /* 1328843e1988Sjohnlev * Kick-off connect process 13297f0b8309SEdward Pilatowicz * If xs_fe_initialised == B_TRUE and xs_hp_connected == B_TRUE 13307f0b8309SEdward Pilatowicz * the xs_if_connected will be changed to B_TRUE on success, 1331843e1988Sjohnlev */ 13327f0b8309SEdward Pilatowicz static void 1333843e1988Sjohnlev xdb_start_connect(xdb_t *vdp) 1334843e1988Sjohnlev { 1335843e1988Sjohnlev xenbus_transaction_t xbt; 1336843e1988Sjohnlev dev_info_t *dip = vdp->xs_dip; 13377f0b8309SEdward Pilatowicz boolean_t fb_exists; 13387f0b8309SEdward Pilatowicz int err, instance = ddi_get_instance(dip); 13397f0b8309SEdward Pilatowicz uint64_t sectors; 13407f0b8309SEdward Pilatowicz uint_t dinfo, ssize; 13417f0b8309SEdward Pilatowicz char *xsname; 13427f0b8309SEdward Pilatowicz 13437f0b8309SEdward Pilatowicz ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 13447f0b8309SEdward Pilatowicz 13457f0b8309SEdward Pilatowicz if (((xsname = xvdi_get_xsname(dip)) == NULL) || 13467f0b8309SEdward Pilatowicz ((vdp->xs_peer = xvdi_get_oeid(dip)) == (domid_t)-1)) 13477f0b8309SEdward Pilatowicz return; 13487f0b8309SEdward Pilatowicz 13497f0b8309SEdward Pilatowicz mutex_enter(&vdp->xs_iomutex); 13507f0b8309SEdward Pilatowicz /* 13517f0b8309SEdward Pilatowicz * if the hotplug scripts haven't run or if the frontend is not 13527f0b8309SEdward Pilatowicz * initialized, then we can't try to connect. 13537f0b8309SEdward Pilatowicz */ 13547f0b8309SEdward Pilatowicz if (!vdp->xs_hp_connected || !vdp->xs_fe_initialised) { 13557f0b8309SEdward Pilatowicz ASSERT(!vdp->xs_if_connected); 13567f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_iomutex); 13577f0b8309SEdward Pilatowicz return; 13587f0b8309SEdward Pilatowicz } 13597f0b8309SEdward Pilatowicz 13607f0b8309SEdward Pilatowicz /* If we're already connected then there's nothing todo */ 13617f0b8309SEdward Pilatowicz if (vdp->xs_if_connected) { 13627f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_iomutex); 13637f0b8309SEdward Pilatowicz return; 13647f0b8309SEdward Pilatowicz } 13657f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_iomutex); 1366843e1988Sjohnlev 1367843e1988Sjohnlev /* 1368843e1988Sjohnlev * Start connect to frontend only when backend device are ready 1369843e1988Sjohnlev * and frontend has moved to XenbusStateInitialised, which means 13707f0b8309SEdward Pilatowicz * ready to connect. 1371843e1988Sjohnlev */ 13727f0b8309SEdward Pilatowicz XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, 13737f0b8309SEdward Pilatowicz "xdb@%s: starting connection process", ddi_get_name_addr(dip))); 1374843e1988Sjohnlev 13757f0b8309SEdward Pilatowicz if (xdb_open_device(vdp) != DDI_SUCCESS) 13767f0b8309SEdward Pilatowicz return; 1377843e1988Sjohnlev 13787f0b8309SEdward Pilatowicz if (xdb_bindto_frontend(vdp) != DDI_SUCCESS) { 13797f0b8309SEdward Pilatowicz xdb_close_device(vdp); 13807f0b8309SEdward Pilatowicz return; 13817f0b8309SEdward Pilatowicz } 1382843e1988Sjohnlev 1383843e1988Sjohnlev /* init i/o requests */ 1384843e1988Sjohnlev xdb_init_ioreqs(vdp); 1385843e1988Sjohnlev 1386843e1988Sjohnlev if (ddi_add_intr(dip, 0, NULL, NULL, xdb_intr, (caddr_t)vdp) 13877f0b8309SEdward Pilatowicz != DDI_SUCCESS) { 13887f0b8309SEdward Pilatowicz xdb_uninit_ioreqs(vdp); 13897f0b8309SEdward Pilatowicz xdb_unbindfrom_frontend(vdp); 13907f0b8309SEdward Pilatowicz xdb_close_device(vdp); 13917f0b8309SEdward Pilatowicz return; 13927f0b8309SEdward Pilatowicz } 13937f0b8309SEdward Pilatowicz 13947f0b8309SEdward Pilatowicz dinfo = 0; 13957f0b8309SEdward Pilatowicz if (XDB_IS_RO(vdp)) 13967f0b8309SEdward Pilatowicz dinfo |= VDISK_READONLY; 13977f0b8309SEdward Pilatowicz if (XDB_IS_BE_RMB(vdp)) 13987f0b8309SEdward Pilatowicz dinfo |= VDISK_REMOVABLE; 13997f0b8309SEdward Pilatowicz if (XDB_IS_BE_CD(vdp)) 14007f0b8309SEdward Pilatowicz dinfo |= VDISK_CDROM; 14017f0b8309SEdward Pilatowicz if (XDB_IS_FE_CD(vdp)) 14027f0b8309SEdward Pilatowicz dinfo |= VDISK_REMOVABLE | VDISK_CDROM; 1403843e1988Sjohnlev 1404843e1988Sjohnlev /* 1405843e1988Sjohnlev * we can recieve intr any time from now on 1406843e1988Sjohnlev * mark that we're ready to take intr 1407843e1988Sjohnlev */ 1408843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 14097f0b8309SEdward Pilatowicz ASSERT(vdp->xs_fe_initialised); 14107f0b8309SEdward Pilatowicz vdp->xs_if_connected = B_TRUE; 1411843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 1412843e1988Sjohnlev 1413843e1988Sjohnlev trans_retry: 14147f0b8309SEdward Pilatowicz /* write into xenstore the info needed by frontend */ 14157f0b8309SEdward Pilatowicz if ((err = xenbus_transaction_start(&xbt)) != 0) { 14167f0b8309SEdward Pilatowicz xvdi_dev_error(dip, err, "connect transaction init"); 14177f0b8309SEdward Pilatowicz goto errout; 1418843e1988Sjohnlev } 1419843e1988Sjohnlev 14207f0b8309SEdward Pilatowicz /* If feature-barrier isn't present in xenstore, add it. */ 14217f0b8309SEdward Pilatowicz fb_exists = xenbus_exists(xsname, XBP_FB); 1422843e1988Sjohnlev 142365908c77Syu, larry liu - Sun Microsystems - Beijing China ssize = (vdp->xs_sec_size == 0) ? DEV_BSIZE : vdp->xs_sec_size; 14247f0b8309SEdward Pilatowicz sectors = vdp->xs_sectors; 14257f0b8309SEdward Pilatowicz if (((!fb_exists && 14267f0b8309SEdward Pilatowicz (err = xenbus_printf(xbt, xsname, XBP_FB, "%d", 1)))) || 14277f0b8309SEdward Pilatowicz (err = xenbus_printf(xbt, xsname, XBP_INFO, "%u", dinfo)) || 142865908c77Syu, larry liu - Sun Microsystems - Beijing China (err = xenbus_printf(xbt, xsname, XBP_SECTOR_SIZE, "%u", ssize)) || 14297f0b8309SEdward Pilatowicz (err = xenbus_printf(xbt, xsname, 14307f0b8309SEdward Pilatowicz XBP_SECTORS, "%"PRIu64, sectors)) || 14317f0b8309SEdward Pilatowicz (err = xenbus_printf(xbt, xsname, "instance", "%d", instance)) || 14327f0b8309SEdward Pilatowicz ((err = xvdi_switch_state(dip, xbt, XenbusStateConnected)) > 0)) { 14337f0b8309SEdward Pilatowicz (void) xenbus_transaction_end(xbt, 1); 14347f0b8309SEdward Pilatowicz xvdi_dev_error(dip, err, "connect transaction setup"); 14357f0b8309SEdward Pilatowicz goto errout; 1436843e1988Sjohnlev } 1437843e1988Sjohnlev 14387f0b8309SEdward Pilatowicz if ((err = xenbus_transaction_end(xbt, 0)) != 0) { 14397f0b8309SEdward Pilatowicz if (err == EAGAIN) { 1440843e1988Sjohnlev /* transaction is ended, don't need to abort it */ 1441843e1988Sjohnlev goto trans_retry; 14427f0b8309SEdward Pilatowicz } 14437f0b8309SEdward Pilatowicz xvdi_dev_error(dip, err, "connect transaction commit"); 14447f0b8309SEdward Pilatowicz goto errout; 1445843e1988Sjohnlev } 1446843e1988Sjohnlev 14477f0b8309SEdward Pilatowicz return; 1448843e1988Sjohnlev 14497f0b8309SEdward Pilatowicz errout: 14507f0b8309SEdward Pilatowicz xdb_close(dip); 1451843e1988Sjohnlev } 1452843e1988Sjohnlev 1453843e1988Sjohnlev /* 1454843e1988Sjohnlev * Disconnect from frontend and close backend device 1455843e1988Sjohnlev */ 1456843e1988Sjohnlev static void 1457843e1988Sjohnlev xdb_close(dev_info_t *dip) 1458843e1988Sjohnlev { 1459843e1988Sjohnlev xdb_t *vdp = (xdb_t *)ddi_get_driver_private(dip); 1460843e1988Sjohnlev 1461843e1988Sjohnlev ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); 1462843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 1463843e1988Sjohnlev 14647f0b8309SEdward Pilatowicz /* 14657f0b8309SEdward Pilatowicz * if the hotplug scripts haven't run or if the frontend is not 14667f0b8309SEdward Pilatowicz * initialized, then we can't be connected, so there's no 14677f0b8309SEdward Pilatowicz * connection to close. 14687f0b8309SEdward Pilatowicz */ 14697f0b8309SEdward Pilatowicz if (!vdp->xs_hp_connected || !vdp->xs_fe_initialised) { 14707f0b8309SEdward Pilatowicz ASSERT(!vdp->xs_if_connected); 1471843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 1472843e1988Sjohnlev return; 1473843e1988Sjohnlev } 14747f0b8309SEdward Pilatowicz 14757f0b8309SEdward Pilatowicz /* if we're not connected, there's nothing to do */ 14767f0b8309SEdward Pilatowicz if (!vdp->xs_if_connected) { 14777f0b8309SEdward Pilatowicz cv_broadcast(&vdp->xs_iocv); 14787f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_iomutex); 14797f0b8309SEdward Pilatowicz return; 14807f0b8309SEdward Pilatowicz } 14817f0b8309SEdward Pilatowicz 14827f0b8309SEdward Pilatowicz XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "closing while connected")); 14837f0b8309SEdward Pilatowicz 14847f0b8309SEdward Pilatowicz vdp->xs_if_connected = B_FALSE; 1485843e1988Sjohnlev cv_broadcast(&vdp->xs_iocv); 1486843e1988Sjohnlev 1487843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 1488843e1988Sjohnlev 1489843e1988Sjohnlev /* stop accepting I/O request from frontend */ 1490843e1988Sjohnlev ddi_remove_intr(dip, 0, NULL); 14917f0b8309SEdward Pilatowicz 1492843e1988Sjohnlev /* clear all on-going I/Os, if any */ 1493843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 1494843e1988Sjohnlev while (vdp->xs_ionum > 0) 1495843e1988Sjohnlev cv_wait(&vdp->xs_ionumcv, &vdp->xs_iomutex); 1496843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 1497843e1988Sjohnlev 1498843e1988Sjohnlev /* clean up resources and close this interface */ 1499843e1988Sjohnlev xdb_uninit_ioreqs(vdp); 1500843e1988Sjohnlev xdb_unbindfrom_frontend(vdp); 1501843e1988Sjohnlev xdb_close_device(vdp); 1502843e1988Sjohnlev vdp->xs_peer = (domid_t)-1; 1503843e1988Sjohnlev } 1504843e1988Sjohnlev 1505843e1988Sjohnlev static void 1506843e1988Sjohnlev xdb_send_buf(void *arg) 1507843e1988Sjohnlev { 1508843e1988Sjohnlev xdb_t *vdp = (xdb_t *)arg; 15097f0b8309SEdward Pilatowicz buf_t *bp; 15107f0b8309SEdward Pilatowicz int err; 1511843e1988Sjohnlev 1512843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 15137f0b8309SEdward Pilatowicz while (vdp->xs_send_buf) { 15147f0b8309SEdward Pilatowicz if ((bp = vdp->xs_f_iobuf) == NULL) { 15157f0b8309SEdward Pilatowicz /* wait for some io to send */ 15167f0b8309SEdward Pilatowicz XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, 15177f0b8309SEdward Pilatowicz "send buf waiting for io")); 15187f0b8309SEdward Pilatowicz cv_wait(&vdp->xs_iocv, &vdp->xs_iomutex); 15197f0b8309SEdward Pilatowicz continue; 15207f0b8309SEdward Pilatowicz } 1521843e1988Sjohnlev 1522843e1988Sjohnlev vdp->xs_f_iobuf = bp->av_forw; 1523843e1988Sjohnlev bp->av_forw = NULL; 1524a576ab5bSrab vdp->xs_ionum++; 15257f0b8309SEdward Pilatowicz 1526843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 15277f0b8309SEdward Pilatowicz if (bp->b_bcount == 0) { 15287f0b8309SEdward Pilatowicz /* no I/O needs to be done */ 15297f0b8309SEdward Pilatowicz (void) xdb_biodone(bp); 15307f0b8309SEdward Pilatowicz mutex_enter(&vdp->xs_iomutex); 15317f0b8309SEdward Pilatowicz continue; 15327f0b8309SEdward Pilatowicz } 15337f0b8309SEdward Pilatowicz 15347f0b8309SEdward Pilatowicz err = EIO; 15357f0b8309SEdward Pilatowicz if (vdp->xs_ldi_hdl != NULL) 15367f0b8309SEdward Pilatowicz err = ldi_strategy(vdp->xs_ldi_hdl, bp); 1537843e1988Sjohnlev if (err != 0) { 1538843e1988Sjohnlev bp->b_flags |= B_ERROR; 1539843e1988Sjohnlev (void) xdb_biodone(bp); 1540843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_WARN, 15417f0b8309SEdward Pilatowicz "xdb@%s: sent buf to backend devfailed, err=%d", 15427f0b8309SEdward Pilatowicz ddi_get_name_addr(vdp->xs_dip), err)); 1543843e1988Sjohnlev } else { 1544843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, 1545843e1988Sjohnlev "sent buf to backend ok")); 1546843e1988Sjohnlev } 1547843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 1548843e1988Sjohnlev } 15497f0b8309SEdward Pilatowicz XDB_DBPRINT(XDB_DBG_IO, (CE_NOTE, "send buf finishing")); 1550843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 1551843e1988Sjohnlev } 1552843e1988Sjohnlev 1553843e1988Sjohnlev /*ARGSUSED*/ 1554843e1988Sjohnlev static void 1555843e1988Sjohnlev xdb_hp_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg, 1556843e1988Sjohnlev void *impl_data) 1557843e1988Sjohnlev { 1558843e1988Sjohnlev xendev_hotplug_state_t state = *(xendev_hotplug_state_t *)impl_data; 1559843e1988Sjohnlev xdb_t *vdp = (xdb_t *)ddi_get_driver_private(dip); 1560843e1988Sjohnlev 1561843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "xdb@%s: " 1562843e1988Sjohnlev "hotplug status change to %d!", ddi_get_name_addr(dip), state)); 1563843e1988Sjohnlev 15647f0b8309SEdward Pilatowicz if (state != Connected) 15657f0b8309SEdward Pilatowicz return; 15667f0b8309SEdward Pilatowicz 1567843e1988Sjohnlev mutex_enter(&vdp->xs_cbmutex); 15687f0b8309SEdward Pilatowicz 15697f0b8309SEdward Pilatowicz /* If hotplug script have already run, there's nothing todo */ 15707f0b8309SEdward Pilatowicz if (vdp->xs_hp_connected) { 15717f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 15727f0b8309SEdward Pilatowicz return; 1573843e1988Sjohnlev } 15747f0b8309SEdward Pilatowicz 15757f0b8309SEdward Pilatowicz vdp->xs_hp_connected = B_TRUE; 15767f0b8309SEdward Pilatowicz xdb_start_connect(vdp); 1577843e1988Sjohnlev mutex_exit(&vdp->xs_cbmutex); 1578843e1988Sjohnlev } 1579843e1988Sjohnlev 1580843e1988Sjohnlev /*ARGSUSED*/ 1581843e1988Sjohnlev static void 1582843e1988Sjohnlev xdb_oe_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg, 1583843e1988Sjohnlev void *impl_data) 1584843e1988Sjohnlev { 1585843e1988Sjohnlev XenbusState new_state = *(XenbusState *)impl_data; 1586843e1988Sjohnlev xdb_t *vdp = (xdb_t *)ddi_get_driver_private(dip); 1587843e1988Sjohnlev 1588843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "xdb@%s: " 1589843e1988Sjohnlev "otherend state change to %d!", ddi_get_name_addr(dip), new_state)); 1590843e1988Sjohnlev 1591843e1988Sjohnlev mutex_enter(&vdp->xs_cbmutex); 1592843e1988Sjohnlev 15937f0b8309SEdward Pilatowicz /* 15947f0b8309SEdward Pilatowicz * Now it'd really be nice if there was a well defined state 15957f0b8309SEdward Pilatowicz * transition model for xen frontend drivers, but unfortunatly 15967f0b8309SEdward Pilatowicz * there isn't. So we're stuck with assuming that all state 15977f0b8309SEdward Pilatowicz * transitions are possible, and we'll just have to deal with 15987f0b8309SEdward Pilatowicz * them regardless of what state we're in. 15997f0b8309SEdward Pilatowicz */ 1600843e1988Sjohnlev switch (new_state) { 16017f0b8309SEdward Pilatowicz case XenbusStateUnknown: 16027f0b8309SEdward Pilatowicz case XenbusStateInitialising: 16037f0b8309SEdward Pilatowicz case XenbusStateInitWait: 16047f0b8309SEdward Pilatowicz /* tear down our connection to the frontend */ 16057f0b8309SEdward Pilatowicz xdb_close(dip); 16067f0b8309SEdward Pilatowicz vdp->xs_fe_initialised = B_FALSE; 1607843e1988Sjohnlev break; 16087f0b8309SEdward Pilatowicz 16097f0b8309SEdward Pilatowicz case XenbusStateInitialised: 16107f0b8309SEdward Pilatowicz /* 16117f0b8309SEdward Pilatowicz * If we were conected, then we need to drop the connection 16127f0b8309SEdward Pilatowicz * and re-negotiate it. 16137f0b8309SEdward Pilatowicz */ 16147f0b8309SEdward Pilatowicz xdb_close(dip); 16157f0b8309SEdward Pilatowicz vdp->xs_fe_initialised = B_TRUE; 16167f0b8309SEdward Pilatowicz xdb_start_connect(vdp); 16177f0b8309SEdward Pilatowicz break; 16187f0b8309SEdward Pilatowicz 16197f0b8309SEdward Pilatowicz case XenbusStateConnected: 16207f0b8309SEdward Pilatowicz /* nothing todo here other than congratulate the frontend */ 16217f0b8309SEdward Pilatowicz break; 16227f0b8309SEdward Pilatowicz 1623843e1988Sjohnlev case XenbusStateClosing: 16247f0b8309SEdward Pilatowicz /* monkey see monkey do */ 1625843e1988Sjohnlev (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosing); 1626843e1988Sjohnlev break; 16277eea693dSMark Johnson 16287f0b8309SEdward Pilatowicz case XenbusStateClosed: 16297f0b8309SEdward Pilatowicz /* tear down our connection to the frontend */ 16307f0b8309SEdward Pilatowicz xdb_close(dip); 16317f0b8309SEdward Pilatowicz vdp->xs_fe_initialised = B_FALSE; 16327f0b8309SEdward Pilatowicz (void) xvdi_switch_state(dip, XBT_NULL, new_state); 16337f0b8309SEdward Pilatowicz break; 1634843e1988Sjohnlev } 1635843e1988Sjohnlev 1636843e1988Sjohnlev mutex_exit(&vdp->xs_cbmutex); 1637843e1988Sjohnlev } 1638843e1988Sjohnlev 1639843e1988Sjohnlev static int 1640843e1988Sjohnlev xdb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1641843e1988Sjohnlev { 1642843e1988Sjohnlev ddi_iblock_cookie_t ibc; 16437f0b8309SEdward Pilatowicz xdb_t *vdp; 16447f0b8309SEdward Pilatowicz int instance = ddi_get_instance(dip); 16457f0b8309SEdward Pilatowicz char *xsname, *oename; 16467f0b8309SEdward Pilatowicz char *str; 1647843e1988Sjohnlev 1648843e1988Sjohnlev switch (cmd) { 1649843e1988Sjohnlev case DDI_RESUME: 1650843e1988Sjohnlev return (DDI_FAILURE); 1651843e1988Sjohnlev case DDI_ATTACH: 1652843e1988Sjohnlev break; 1653843e1988Sjohnlev default: 1654843e1988Sjohnlev return (DDI_FAILURE); 1655843e1988Sjohnlev } 1656843e1988Sjohnlev /* DDI_ATTACH */ 16577f0b8309SEdward Pilatowicz 16587f0b8309SEdward Pilatowicz if (((xsname = xvdi_get_xsname(dip)) == NULL) || 16597f0b8309SEdward Pilatowicz ((oename = xvdi_get_oename(dip)) == NULL)) 16607f0b8309SEdward Pilatowicz return (DDI_FAILURE); 16617f0b8309SEdward Pilatowicz 16627f0b8309SEdward Pilatowicz /* 16637f0b8309SEdward Pilatowicz * Disable auto-detach. This is necessary so that we don't get 16647f0b8309SEdward Pilatowicz * detached while we're disconnected from the front end. 16657f0b8309SEdward Pilatowicz */ 16667f0b8309SEdward Pilatowicz (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, DDI_NO_AUTODETACH, 1); 16677f0b8309SEdward Pilatowicz 16687f0b8309SEdward Pilatowicz if (ddi_get_iblock_cookie(dip, 0, &ibc) != DDI_SUCCESS) 16697f0b8309SEdward Pilatowicz return (DDI_FAILURE); 16707f0b8309SEdward Pilatowicz 1671843e1988Sjohnlev if (ddi_soft_state_zalloc(xdb_statep, instance) != DDI_SUCCESS) 1672843e1988Sjohnlev return (DDI_FAILURE); 1673843e1988Sjohnlev 1674843e1988Sjohnlev vdp = ddi_get_soft_state(xdb_statep, instance); 1675843e1988Sjohnlev vdp->xs_dip = dip; 1676843e1988Sjohnlev mutex_init(&vdp->xs_iomutex, NULL, MUTEX_DRIVER, (void *)ibc); 1677843e1988Sjohnlev mutex_init(&vdp->xs_cbmutex, NULL, MUTEX_DRIVER, (void *)ibc); 1678843e1988Sjohnlev cv_init(&vdp->xs_iocv, NULL, CV_DRIVER, NULL); 1679843e1988Sjohnlev cv_init(&vdp->xs_ionumcv, NULL, CV_DRIVER, NULL); 1680843e1988Sjohnlev ddi_set_driver_private(dip, vdp); 1681843e1988Sjohnlev 16827f0b8309SEdward Pilatowicz if (!xdb_kstat_init(vdp)) 16837f0b8309SEdward Pilatowicz goto errout1; 16847f0b8309SEdward Pilatowicz 16857f0b8309SEdward Pilatowicz /* Check if the frontend device is supposed to be a cdrom */ 16867f0b8309SEdward Pilatowicz if (xenbus_read_str(oename, XBP_DEV_TYPE, &str) != 0) 16877f0b8309SEdward Pilatowicz return (DDI_FAILURE); 16887f0b8309SEdward Pilatowicz if (strcmp(str, XBV_DEV_TYPE_CD) == 0) 16897f0b8309SEdward Pilatowicz vdp->xs_type |= XDB_DEV_FE_CD; 16907f0b8309SEdward Pilatowicz strfree(str); 16917f0b8309SEdward Pilatowicz 16927f0b8309SEdward Pilatowicz /* Check if the frontend device is supposed to be read only */ 16937f0b8309SEdward Pilatowicz if (xenbus_read_str(xsname, "mode", &str) != 0) 16947f0b8309SEdward Pilatowicz return (DDI_FAILURE); 16957f0b8309SEdward Pilatowicz if ((strcmp(str, "r") == NULL) || (strcmp(str, "ro") == NULL)) 16967f0b8309SEdward Pilatowicz vdp->xs_type |= XDB_DEV_RO; 16977f0b8309SEdward Pilatowicz strfree(str); 16987f0b8309SEdward Pilatowicz 16997f0b8309SEdward Pilatowicz mutex_enter(&vdp->xs_cbmutex); 17007f0b8309SEdward Pilatowicz if (!xdb_media_req_init(vdp) || !xdb_params_init(vdp)) { 17017f0b8309SEdward Pilatowicz xvdi_remove_xb_watch_handlers(dip); 17027f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 17037f0b8309SEdward Pilatowicz goto errout2; 17047f0b8309SEdward Pilatowicz } 17057f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 17067f0b8309SEdward Pilatowicz 17077f0b8309SEdward Pilatowicz vdp->xs_send_buf = B_TRUE; 1708843e1988Sjohnlev vdp->xs_iotaskq = ddi_taskq_create(dip, "xdb_iotask", 1, 1709843e1988Sjohnlev TASKQ_DEFAULTPRI, 0); 1710843e1988Sjohnlev (void) ddi_taskq_dispatch(vdp->xs_iotaskq, xdb_send_buf, vdp, 1711843e1988Sjohnlev DDI_SLEEP); 1712843e1988Sjohnlev 1713843e1988Sjohnlev /* Watch frontend and hotplug state change */ 17147f0b8309SEdward Pilatowicz if ((xvdi_add_event_handler(dip, XS_OE_STATE, xdb_oe_state_change, 17157f0b8309SEdward Pilatowicz NULL) != DDI_SUCCESS) || 17167f0b8309SEdward Pilatowicz (xvdi_add_event_handler(dip, XS_HP_STATE, xdb_hp_state_change, 17177f0b8309SEdward Pilatowicz NULL) != DDI_SUCCESS)) 1718843e1988Sjohnlev goto errout3; 1719843e1988Sjohnlev 1720843e1988Sjohnlev /* 1721843e1988Sjohnlev * Kick-off hotplug script 1722843e1988Sjohnlev */ 1723843e1988Sjohnlev if (xvdi_post_event(dip, XEN_HP_ADD) != DDI_SUCCESS) { 1724843e1988Sjohnlev cmn_err(CE_WARN, "xdb@%s: failed to start hotplug script", 1725843e1988Sjohnlev ddi_get_name_addr(dip)); 17267f0b8309SEdward Pilatowicz goto errout3; 1727843e1988Sjohnlev } 1728843e1988Sjohnlev 1729843e1988Sjohnlev /* 1730843e1988Sjohnlev * start waiting for hotplug event and otherend state event 1731843e1988Sjohnlev * mainly for debugging, frontend will not take any op seeing this 1732843e1988Sjohnlev */ 1733843e1988Sjohnlev (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateInitWait); 1734843e1988Sjohnlev 1735843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "xdb@%s: attached!", 1736843e1988Sjohnlev ddi_get_name_addr(dip))); 1737843e1988Sjohnlev return (DDI_SUCCESS); 1738843e1988Sjohnlev 1739843e1988Sjohnlev errout3: 17407f0b8309SEdward Pilatowicz ASSERT(vdp->xs_hp_connected && vdp->xs_if_connected); 17417f0b8309SEdward Pilatowicz 17427f0b8309SEdward Pilatowicz xvdi_remove_event_handler(dip, NULL); 17437f0b8309SEdward Pilatowicz 17447f0b8309SEdward Pilatowicz /* Disconnect from the backend */ 1745843e1988Sjohnlev mutex_enter(&vdp->xs_cbmutex); 1746843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 17477f0b8309SEdward Pilatowicz vdp->xs_send_buf = B_FALSE; 1748843e1988Sjohnlev cv_broadcast(&vdp->xs_iocv); 1749843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 1750843e1988Sjohnlev mutex_exit(&vdp->xs_cbmutex); 17517f0b8309SEdward Pilatowicz 17527f0b8309SEdward Pilatowicz /* wait for all io to dtrain and destroy io taskq */ 1753843e1988Sjohnlev ddi_taskq_destroy(vdp->xs_iotaskq); 17547f0b8309SEdward Pilatowicz 17557f0b8309SEdward Pilatowicz /* tear down block-configure watch */ 17567f0b8309SEdward Pilatowicz mutex_enter(&vdp->xs_cbmutex); 17577f0b8309SEdward Pilatowicz xvdi_remove_xb_watch_handlers(dip); 17587f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 17597f0b8309SEdward Pilatowicz 1760843e1988Sjohnlev errout2: 17617f0b8309SEdward Pilatowicz /* remove kstats */ 17627f0b8309SEdward Pilatowicz kstat_delete(vdp->xs_kstats); 17637f0b8309SEdward Pilatowicz 17647f0b8309SEdward Pilatowicz errout1: 17657f0b8309SEdward Pilatowicz /* free up driver state */ 1766843e1988Sjohnlev ddi_set_driver_private(dip, NULL); 1767843e1988Sjohnlev cv_destroy(&vdp->xs_iocv); 1768843e1988Sjohnlev cv_destroy(&vdp->xs_ionumcv); 1769843e1988Sjohnlev mutex_destroy(&vdp->xs_cbmutex); 1770843e1988Sjohnlev mutex_destroy(&vdp->xs_iomutex); 1771843e1988Sjohnlev ddi_soft_state_free(xdb_statep, instance); 17727f0b8309SEdward Pilatowicz 1773843e1988Sjohnlev return (DDI_FAILURE); 1774843e1988Sjohnlev } 1775843e1988Sjohnlev 1776843e1988Sjohnlev /*ARGSUSED*/ 1777843e1988Sjohnlev static int 1778843e1988Sjohnlev xdb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1779843e1988Sjohnlev { 1780843e1988Sjohnlev int instance = ddi_get_instance(dip); 1781843e1988Sjohnlev xdb_t *vdp = XDB_INST2SOFTS(instance); 1782843e1988Sjohnlev 1783843e1988Sjohnlev switch (cmd) { 1784843e1988Sjohnlev case DDI_SUSPEND: 1785843e1988Sjohnlev return (DDI_FAILURE); 1786843e1988Sjohnlev case DDI_DETACH: 1787843e1988Sjohnlev break; 1788843e1988Sjohnlev default: 1789843e1988Sjohnlev return (DDI_FAILURE); 1790843e1988Sjohnlev } 1791843e1988Sjohnlev 1792843e1988Sjohnlev /* DDI_DETACH handling */ 1793843e1988Sjohnlev 17947f0b8309SEdward Pilatowicz /* refuse to detach if we're still in use by the frontend */ 1795843e1988Sjohnlev mutex_enter(&vdp->xs_iomutex); 17967f0b8309SEdward Pilatowicz if (vdp->xs_if_connected) { 1797843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 1798843e1988Sjohnlev return (DDI_FAILURE); 1799843e1988Sjohnlev } 18007f0b8309SEdward Pilatowicz vdp->xs_send_buf = B_FALSE; 18017f0b8309SEdward Pilatowicz cv_broadcast(&vdp->xs_iocv); 1802843e1988Sjohnlev mutex_exit(&vdp->xs_iomutex); 1803843e1988Sjohnlev 1804843e1988Sjohnlev xvdi_remove_event_handler(dip, NULL); 1805843e1988Sjohnlev (void) xvdi_post_event(dip, XEN_HP_REMOVE); 1806843e1988Sjohnlev 1807843e1988Sjohnlev ddi_taskq_destroy(vdp->xs_iotaskq); 18087f0b8309SEdward Pilatowicz 18097f0b8309SEdward Pilatowicz mutex_enter(&vdp->xs_cbmutex); 18107f0b8309SEdward Pilatowicz xvdi_remove_xb_watch_handlers(dip); 18117f0b8309SEdward Pilatowicz mutex_exit(&vdp->xs_cbmutex); 18127f0b8309SEdward Pilatowicz 1813843e1988Sjohnlev cv_destroy(&vdp->xs_iocv); 1814843e1988Sjohnlev cv_destroy(&vdp->xs_ionumcv); 1815843e1988Sjohnlev mutex_destroy(&vdp->xs_cbmutex); 1816843e1988Sjohnlev mutex_destroy(&vdp->xs_iomutex); 1817843e1988Sjohnlev kstat_delete(vdp->xs_kstats); 1818843e1988Sjohnlev ddi_set_driver_private(dip, NULL); 1819843e1988Sjohnlev ddi_soft_state_free(xdb_statep, instance); 1820843e1988Sjohnlev 1821843e1988Sjohnlev XDB_DBPRINT(XDB_DBG_INFO, (CE_NOTE, "xdb@%s: detached!", 1822843e1988Sjohnlev ddi_get_name_addr(dip))); 1823843e1988Sjohnlev return (DDI_SUCCESS); 1824843e1988Sjohnlev } 1825843e1988Sjohnlev 1826843e1988Sjohnlev static struct dev_ops xdb_dev_ops = { 1827843e1988Sjohnlev DEVO_REV, /* devo_rev */ 1828843e1988Sjohnlev 0, /* devo_refcnt */ 1829843e1988Sjohnlev ddi_getinfo_1to1, /* devo_getinfo */ 1830843e1988Sjohnlev nulldev, /* devo_identify */ 1831843e1988Sjohnlev nulldev, /* devo_probe */ 1832843e1988Sjohnlev xdb_attach, /* devo_attach */ 1833843e1988Sjohnlev xdb_detach, /* devo_detach */ 1834843e1988Sjohnlev nodev, /* devo_reset */ 1835843e1988Sjohnlev NULL, /* devo_cb_ops */ 1836843e1988Sjohnlev NULL, /* devo_bus_ops */ 183719397407SSherry Moore NULL, /* power */ 183819397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 1839843e1988Sjohnlev }; 1840843e1988Sjohnlev 1841843e1988Sjohnlev /* 1842843e1988Sjohnlev * Module linkage information for the kernel. 1843843e1988Sjohnlev */ 1844843e1988Sjohnlev static struct modldrv modldrv = { 1845843e1988Sjohnlev &mod_driverops, /* Type of module. */ 184619397407SSherry Moore "vbd backend driver", /* Name of the module */ 1847843e1988Sjohnlev &xdb_dev_ops /* driver ops */ 1848843e1988Sjohnlev }; 1849843e1988Sjohnlev 1850843e1988Sjohnlev static struct modlinkage xdb_modlinkage = { 1851843e1988Sjohnlev MODREV_1, 1852843e1988Sjohnlev &modldrv, 1853843e1988Sjohnlev NULL 1854843e1988Sjohnlev }; 1855843e1988Sjohnlev 1856843e1988Sjohnlev int 1857843e1988Sjohnlev _init(void) 1858843e1988Sjohnlev { 1859843e1988Sjohnlev int rv; 1860843e1988Sjohnlev 1861843e1988Sjohnlev if ((rv = ddi_soft_state_init((void **)&xdb_statep, 1862843e1988Sjohnlev sizeof (xdb_t), 0)) == 0) 1863843e1988Sjohnlev if ((rv = mod_install(&xdb_modlinkage)) != 0) 1864843e1988Sjohnlev ddi_soft_state_fini((void **)&xdb_statep); 1865843e1988Sjohnlev return (rv); 1866843e1988Sjohnlev } 1867843e1988Sjohnlev 1868843e1988Sjohnlev int 1869843e1988Sjohnlev _fini(void) 1870843e1988Sjohnlev { 1871843e1988Sjohnlev int rv; 1872843e1988Sjohnlev 1873843e1988Sjohnlev if ((rv = mod_remove(&xdb_modlinkage)) != 0) 1874843e1988Sjohnlev return (rv); 1875843e1988Sjohnlev ddi_soft_state_fini((void **)&xdb_statep); 1876843e1988Sjohnlev return (rv); 1877843e1988Sjohnlev } 1878843e1988Sjohnlev 1879843e1988Sjohnlev int 1880843e1988Sjohnlev _info(struct modinfo *modinfop) 1881843e1988Sjohnlev { 1882843e1988Sjohnlev return (mod_info(&xdb_modlinkage, modinfop)); 1883843e1988Sjohnlev } 1884a576ab5bSrab 1885a576ab5bSrab static int 1886a576ab5bSrab xdb_get_request(xdb_t *vdp, blkif_request_t *req) 1887a576ab5bSrab { 1888a576ab5bSrab void *src = xvdi_ring_get_request(vdp->xs_ring); 1889a576ab5bSrab 1890a576ab5bSrab if (src == NULL) 1891a576ab5bSrab return (0); 1892a576ab5bSrab 1893a576ab5bSrab switch (vdp->xs_blk_protocol) { 1894a576ab5bSrab case BLKIF_PROTOCOL_NATIVE: 1895a576ab5bSrab (void) memcpy(req, src, sizeof (*req)); 1896a576ab5bSrab break; 1897a576ab5bSrab case BLKIF_PROTOCOL_X86_32: 1898a576ab5bSrab blkif_get_x86_32_req(req, src); 1899a576ab5bSrab break; 1900a576ab5bSrab case BLKIF_PROTOCOL_X86_64: 1901a576ab5bSrab blkif_get_x86_64_req(req, src); 1902a576ab5bSrab break; 1903a576ab5bSrab default: 1904a576ab5bSrab cmn_err(CE_PANIC, "xdb@%s: unrecognised protocol: %d", 1905a576ab5bSrab ddi_get_name_addr(vdp->xs_dip), 1906a576ab5bSrab vdp->xs_blk_protocol); 1907a576ab5bSrab } 1908a576ab5bSrab return (1); 1909a576ab5bSrab } 1910a576ab5bSrab 1911a576ab5bSrab static int 1912a576ab5bSrab xdb_push_response(xdb_t *vdp, uint64_t id, uint8_t op, uint16_t status) 1913a576ab5bSrab { 1914a576ab5bSrab ddi_acc_handle_t acchdl = vdp->xs_ring_hdl; 1915a576ab5bSrab blkif_response_t *rsp = xvdi_ring_get_response(vdp->xs_ring); 1916a576ab5bSrab blkif_x86_32_response_t *rsp_32 = (blkif_x86_32_response_t *)rsp; 1917a576ab5bSrab blkif_x86_64_response_t *rsp_64 = (blkif_x86_64_response_t *)rsp; 1918a576ab5bSrab 1919a576ab5bSrab ASSERT(rsp); 1920a576ab5bSrab 1921a576ab5bSrab switch (vdp->xs_blk_protocol) { 1922a576ab5bSrab case BLKIF_PROTOCOL_NATIVE: 1923a576ab5bSrab ddi_put64(acchdl, &rsp->id, id); 1924a576ab5bSrab ddi_put8(acchdl, &rsp->operation, op); 1925a576ab5bSrab ddi_put16(acchdl, (uint16_t *)&rsp->status, 1926a576ab5bSrab status == 0 ? BLKIF_RSP_OKAY : BLKIF_RSP_ERROR); 1927a576ab5bSrab break; 1928a576ab5bSrab case BLKIF_PROTOCOL_X86_32: 1929a576ab5bSrab ddi_put64(acchdl, &rsp_32->id, id); 1930a576ab5bSrab ddi_put8(acchdl, &rsp_32->operation, op); 1931a576ab5bSrab ddi_put16(acchdl, (uint16_t *)&rsp_32->status, 1932a576ab5bSrab status == 0 ? BLKIF_RSP_OKAY : BLKIF_RSP_ERROR); 1933a576ab5bSrab break; 1934a576ab5bSrab case BLKIF_PROTOCOL_X86_64: 1935a576ab5bSrab ddi_put64(acchdl, &rsp_64->id, id); 1936a576ab5bSrab ddi_put8(acchdl, &rsp_64->operation, op); 1937a576ab5bSrab ddi_put16(acchdl, (uint16_t *)&rsp_64->status, 1938a576ab5bSrab status == 0 ? BLKIF_RSP_OKAY : BLKIF_RSP_ERROR); 1939a576ab5bSrab break; 1940a576ab5bSrab default: 1941a576ab5bSrab cmn_err(CE_PANIC, "xdb@%s: unrecognised protocol: %d", 1942a576ab5bSrab ddi_get_name_addr(vdp->xs_dip), 1943a576ab5bSrab vdp->xs_blk_protocol); 1944a576ab5bSrab } 1945a576ab5bSrab 1946a576ab5bSrab return (xvdi_ring_push_response(vdp->xs_ring)); 1947a576ab5bSrab } 1948a576ab5bSrab 1949a576ab5bSrab static void 1950a576ab5bSrab blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src) 1951a576ab5bSrab { 1952a576ab5bSrab int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; 1953a576ab5bSrab dst->operation = src->operation; 1954a576ab5bSrab dst->nr_segments = src->nr_segments; 1955a576ab5bSrab dst->handle = src->handle; 1956a576ab5bSrab dst->id = src->id; 1957a576ab5bSrab dst->sector_number = src->sector_number; 1958a576ab5bSrab if (n > src->nr_segments) 1959a576ab5bSrab n = src->nr_segments; 1960a576ab5bSrab for (i = 0; i < n; i++) 1961a576ab5bSrab dst->seg[i] = src->seg[i]; 1962a576ab5bSrab } 1963a576ab5bSrab 1964a576ab5bSrab static void 1965a576ab5bSrab blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src) 1966a576ab5bSrab { 1967a576ab5bSrab int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; 1968a576ab5bSrab dst->operation = src->operation; 1969a576ab5bSrab dst->nr_segments = src->nr_segments; 1970a576ab5bSrab dst->handle = src->handle; 1971a576ab5bSrab dst->id = src->id; 1972a576ab5bSrab dst->sector_number = src->sector_number; 1973a576ab5bSrab if (n > src->nr_segments) 1974a576ab5bSrab n = src->nr_segments; 1975a576ab5bSrab for (i = 0; i < n; i++) 1976a576ab5bSrab dst->seg[i] = src->seg[i]; 1977a576ab5bSrab } 1978