Mon Apr 20 19:20:36 2020 UTC ()
Fix build with DIAGNOSTIC


(bouyer)
diff -r1.83 -r1.84 src/sys/arch/xen/xen/xbdback_xenbus.c

cvs diff -r1.83 -r1.84 src/sys/arch/xen/xen/xbdback_xenbus.c (switch to unified diff)

--- src/sys/arch/xen/xen/xbdback_xenbus.c 2020/04/20 16:12:28 1.83
+++ src/sys/arch/xen/xen/xbdback_xenbus.c 2020/04/20 19:20:35 1.84
@@ -1,1509 +1,1507 @@ @@ -1,1509 +1,1507 @@
1/* $NetBSD: xbdback_xenbus.c,v 1.83 2020/04/20 16:12:28 jdolecek Exp $ */ 1/* $NetBSD: xbdback_xenbus.c,v 1.84 2020/04/20 19:20:35 bouyer Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006 Manuel Bouyer. 4 * Copyright (c) 2006 Manuel Bouyer.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 * 25 *
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: xbdback_xenbus.c,v 1.83 2020/04/20 16:12:28 jdolecek Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: xbdback_xenbus.c,v 1.84 2020/04/20 19:20:35 bouyer Exp $");
30 30
31#include <sys/atomic.h> 31#include <sys/atomic.h>
32#include <sys/buf.h> 32#include <sys/buf.h>
33#include <sys/condvar.h> 33#include <sys/condvar.h>
34#include <sys/conf.h> 34#include <sys/conf.h>
35#include <sys/disk.h> 35#include <sys/disk.h>
36#include <sys/device.h> 36#include <sys/device.h>
37#include <sys/fcntl.h> 37#include <sys/fcntl.h>
38#include <sys/kauth.h> 38#include <sys/kauth.h>
39#include <sys/kernel.h> 39#include <sys/kernel.h>
40#include <sys/kmem.h> 40#include <sys/kmem.h>
41#include <sys/kthread.h> 41#include <sys/kthread.h>
42#include <sys/mutex.h> 42#include <sys/mutex.h>
43#include <sys/param.h> 43#include <sys/param.h>
44#include <sys/queue.h> 44#include <sys/queue.h>
45#include <sys/systm.h> 45#include <sys/systm.h>
46#include <sys/time.h> 46#include <sys/time.h>
47#include <sys/types.h> 47#include <sys/types.h>
48#include <sys/vnode.h> 48#include <sys/vnode.h>
49 49
50#include <xen/xen.h> 50#include <xen/xen.h>
51#include <xen/xen_shm.h> 51#include <xen/xen_shm.h>
52#include <xen/evtchn.h> 52#include <xen/evtchn.h>
53#include <xen/xenbus.h> 53#include <xen/xenbus.h>
54#include <xen/xenring.h> 54#include <xen/xenring.h>
55#include <xen/include/public/io/protocols.h> 55#include <xen/include/public/io/protocols.h>
56 56
57/* #define XENDEBUG_VBD */ 57/* #define XENDEBUG_VBD */
58#ifdef XENDEBUG_VBD 58#ifdef XENDEBUG_VBD
59#define XENPRINTF(x) printf x 59#define XENPRINTF(x) printf x
60#else 60#else
61#define XENPRINTF(x) 61#define XENPRINTF(x)
62#endif 62#endif
63 63
64#define BLKIF_RING_SIZE __CONST_RING_SIZE(blkif, PAGE_SIZE) 64#define BLKIF_RING_SIZE __CONST_RING_SIZE(blkif, PAGE_SIZE)
65 65
66/* 66/*
67 * Backend block device driver for Xen 67 * Backend block device driver for Xen
68 */ 68 */
69 69
70/* Values are expressed in 512-byte sectors */ 70/* Values are expressed in 512-byte sectors */
71#define VBD_BSIZE 512 71#define VBD_BSIZE 512
72#define VBD_MAXSECT ((PAGE_SIZE / VBD_BSIZE) - 1) 72#define VBD_MAXSECT ((PAGE_SIZE / VBD_BSIZE) - 1)
73 73
74/* Need to alloc one extra page to account for possible mapping offset */ 74/* Need to alloc one extra page to account for possible mapping offset */
75#define VBD_VA_SIZE (MAXPHYS + PAGE_SIZE) 75#define VBD_VA_SIZE (MAXPHYS + PAGE_SIZE)
76 76
77struct xbdback_io; 77struct xbdback_io;
78struct xbdback_instance; 78struct xbdback_instance;
79 79
80/* 80/*
81 * status of a xbdback instance: 81 * status of a xbdback instance:
82 * WAITING: xbdback instance is connected, waiting for requests 82 * WAITING: xbdback instance is connected, waiting for requests
83 * RUN: xbdi thread must be woken up, I/Os have to be processed 83 * RUN: xbdi thread must be woken up, I/Os have to be processed
84 * DISCONNECTING: the instance is closing, no more I/Os can be scheduled 84 * DISCONNECTING: the instance is closing, no more I/Os can be scheduled
85 * DISCONNECTED: no I/Os, no ring, the thread should terminate. 85 * DISCONNECTED: no I/Os, no ring, the thread should terminate.
86 */ 86 */
87typedef enum {WAITING, RUN, DISCONNECTING, DISCONNECTED} xbdback_state_t; 87typedef enum {WAITING, RUN, DISCONNECTING, DISCONNECTED} xbdback_state_t;
88 88
89/* 89/*
90 * Each xbdback instance is managed by a single thread that handles all 90 * Each xbdback instance is managed by a single thread that handles all
91 * the I/O processing. As there are a variety of conditions that can block, 91 * the I/O processing. As there are a variety of conditions that can block,
92 * everything will be done in a sort of continuation-passing style. 92 * everything will be done in a sort of continuation-passing style.
93 * 93 *
94 * When the execution has to block to delay processing, for example to 94 * When the execution has to block to delay processing, for example to
95 * allow system to recover because of memory shortage (via shared memory 95 * allow system to recover because of memory shortage (via shared memory
96 * callback), the return value of a continuation can be set to NULL. In that 96 * callback), the return value of a continuation can be set to NULL. In that
97 * case, the thread will go back to sleeping and wait for the proper 97 * case, the thread will go back to sleeping and wait for the proper
98 * condition before it starts processing requests again from where it left. 98 * condition before it starts processing requests again from where it left.
99 * Continuation state is "stored" in the xbdback instance (xbdi_cont), 99 * Continuation state is "stored" in the xbdback instance (xbdi_cont),
100 * and should only be manipulated by the instance thread. 100 * and should only be manipulated by the instance thread.
101 * 101 *
102 * As xbdback(4) has to handle different sort of asynchronous events (Xen 102 * As xbdback(4) has to handle different sort of asynchronous events (Xen
103 * event channels, biointr() soft interrupts, xenbus commands), the xbdi_lock 103 * event channels, biointr() soft interrupts, xenbus commands), the xbdi_lock
104 * mutex is used to protect specific elements of the xbdback instance from 104 * mutex is used to protect specific elements of the xbdback instance from
105 * concurrent access: thread status and ring access (when pushing responses). 105 * concurrent access: thread status and ring access (when pushing responses).
106 *  106 *
107 * Here's how the call graph is supposed to be for a single I/O: 107 * Here's how the call graph is supposed to be for a single I/O:
108 * 108 *
109 * xbdback_co_main() 109 * xbdback_co_main()
110 * | --> xbdback_co_cache_flush() 110 * | --> xbdback_co_cache_flush()
111 * | | | 111 * | | |
112 * | | -> xbdback_co_cache_doflush() or NULL 112 * | | -> xbdback_co_cache_doflush() or NULL
113 * | | | 113 * | | |
114 * | | -> xbdback_co_do_io() 114 * | | -> xbdback_co_do_io()
115 * xbdback_co_main_loop()-| 115 * xbdback_co_main_loop()-|
116 * | |-> xbdback_co_main_done2() or NULL 116 * | |-> xbdback_co_main_done2() or NULL
117 * | | 117 * | |
118 * | --> xbdback_co_main_incr() -> xbdback_co_main_loop() 118 * | --> xbdback_co_main_incr() -> xbdback_co_main_loop()
119 * | 119 * |
120 * xbdback_co_io() -> xbdback_co_main_incr() -> xbdback_co_main_loop() 120 * xbdback_co_io() -> xbdback_co_main_incr() -> xbdback_co_main_loop()
121 * | 121 * |
122 * xbdback_co_io_gotio() -> xbdback_map_shm() 122 * xbdback_co_io_gotio() -> xbdback_map_shm()
123 * | | 123 * | |
124 * | xbdback_co_main_incr() -> xbdback_co_main_loop() 124 * | xbdback_co_main_incr() -> xbdback_co_main_loop()
125 * | 125 * |
126 * xbdback_co_do_io()  126 * xbdback_co_do_io()
127 * | 127 * |
128 * xbdback_co_main_incr() -> xbdback_co_main_loop() 128 * xbdback_co_main_incr() -> xbdback_co_main_loop()
129 */ 129 */
130typedef void *(* xbdback_cont_t)(struct xbdback_instance *, void *); 130typedef void *(* xbdback_cont_t)(struct xbdback_instance *, void *);
131 131
132enum xbdi_proto { 132enum xbdi_proto {
133 XBDIP_NATIVE, 133 XBDIP_NATIVE,
134 XBDIP_32, 134 XBDIP_32,
135 XBDIP_64 135 XBDIP_64
136}; 136};
137 137
138struct xbdback_va { 138struct xbdback_va {
139 SLIST_ENTRY(xbdback_va) xv_next; 139 SLIST_ENTRY(xbdback_va) xv_next;
140 vaddr_t xv_vaddr; 140 vaddr_t xv_vaddr;
141}; 141};
142 142
143/* we keep the xbdback instances in a linked list */ 143/* we keep the xbdback instances in a linked list */
144struct xbdback_instance { 144struct xbdback_instance {
145 SLIST_ENTRY(xbdback_instance) next; 145 SLIST_ENTRY(xbdback_instance) next;
146 struct xenbus_device *xbdi_xbusd; /* our xenstore entry */ 146 struct xenbus_device *xbdi_xbusd; /* our xenstore entry */
147 struct xenbus_watch xbdi_watch; /* to watch our store */ 147 struct xenbus_watch xbdi_watch; /* to watch our store */
148 domid_t xbdi_domid; /* attached to this domain */ 148 domid_t xbdi_domid; /* attached to this domain */
149 uint32_t xbdi_handle; /* domain-specific handle */ 149 uint32_t xbdi_handle; /* domain-specific handle */
150 char xbdi_name[16]; /* name of this instance */ 150 char xbdi_name[16]; /* name of this instance */
151 /* mutex that protects concurrent access to the xbdback instance */ 151 /* mutex that protects concurrent access to the xbdback instance */
152 kmutex_t xbdi_lock; 152 kmutex_t xbdi_lock;
153 kcondvar_t xbdi_cv; /* wait channel for thread work */ 153 kcondvar_t xbdi_cv; /* wait channel for thread work */
154 xbdback_state_t xbdi_status; /* thread's status */ 154 xbdback_state_t xbdi_status; /* thread's status */
155 /* KVA for mapping transfers */ 155 /* KVA for mapping transfers */
156 struct xbdback_va xbdi_va[BLKIF_RING_SIZE]; 156 struct xbdback_va xbdi_va[BLKIF_RING_SIZE];
157 SLIST_HEAD(, xbdback_va) xbdi_va_free; 157 SLIST_HEAD(, xbdback_va) xbdi_va_free;
158 /* backing device parameters */ 158 /* backing device parameters */
159 dev_t xbdi_dev; 159 dev_t xbdi_dev;
160 const struct bdevsw *xbdi_bdevsw; /* pointer to the device's bdevsw */ 160 const struct bdevsw *xbdi_bdevsw; /* pointer to the device's bdevsw */
161 struct vnode *xbdi_vp; 161 struct vnode *xbdi_vp;
162 uint64_t xbdi_size; 162 uint64_t xbdi_size;
163 bool xbdi_ro; /* is device read-only ? */ 163 bool xbdi_ro; /* is device read-only ? */
164 /* parameters for the communication */ 164 /* parameters for the communication */
165 unsigned int xbdi_evtchn; 165 unsigned int xbdi_evtchn;
166 struct intrhand *xbdi_ih; 166 struct intrhand *xbdi_ih;
167 /* private parameters for communication */ 167 /* private parameters for communication */
168 blkif_back_ring_proto_t xbdi_ring; 168 blkif_back_ring_proto_t xbdi_ring;
169 enum xbdi_proto xbdi_proto; 169 enum xbdi_proto xbdi_proto;
170 grant_handle_t xbdi_ring_handle; /* to unmap the ring */ 170 grant_handle_t xbdi_ring_handle; /* to unmap the ring */
171 vaddr_t xbdi_ring_va; /* to unmap the ring */ 171 vaddr_t xbdi_ring_va; /* to unmap the ring */
172 /* disconnection must be postponed until all I/O is done */ 172 /* disconnection must be postponed until all I/O is done */
173 int xbdi_refcnt; 173 int xbdi_refcnt;
174 /*  174 /*
175 * State for I/O processing/coalescing follows; this has to 175 * State for I/O processing/coalescing follows; this has to
176 * live here instead of on the stack because of the 176 * live here instead of on the stack because of the
177 * continuation-ness (see above). 177 * continuation-ness (see above).
178 */ 178 */
179 RING_IDX xbdi_req_prod; /* limit on request indices */ 179 RING_IDX xbdi_req_prod; /* limit on request indices */
180 xbdback_cont_t xbdi_cont; 180 xbdback_cont_t xbdi_cont;
181 /* _request state: track requests fetched from ring */ 181 /* _request state: track requests fetched from ring */
182 struct xbdback_request *xbdi_req; /* if NULL, ignore following */ 182 struct xbdback_request *xbdi_req; /* if NULL, ignore following */
183 blkif_request_t xbdi_xen_req; 183 blkif_request_t xbdi_xen_req;
184 /* _io state: I/O associated to this instance */ 184 /* _io state: I/O associated to this instance */
185 struct xbdback_io *xbdi_io; 185 struct xbdback_io *xbdi_io;
186 /* other state */ 186 /* other state */
187 int xbdi_same_page; /* are we merging two segments on the same page? */ 187 int xbdi_same_page; /* are we merging two segments on the same page? */
188 uint xbdi_pendingreqs; /* number of I/O in fly */ 188 uint xbdi_pendingreqs; /* number of I/O in fly */
189 struct timeval xbdi_lasterr_time; /* error time tracking */ 189 struct timeval xbdi_lasterr_time; /* error time tracking */
190#ifdef DEBUG 190#ifdef DEBUG
191 struct timeval xbdi_lastfragio_time; /* fragmented I/O tracking */ 191 struct timeval xbdi_lastfragio_time; /* fragmented I/O tracking */
192#endif 192#endif
193}; 193};
194/* Manipulation of the above reference count. */ 194/* Manipulation of the above reference count. */
195#define xbdi_get(xbdip) atomic_inc_uint(&(xbdip)->xbdi_refcnt) 195#define xbdi_get(xbdip) atomic_inc_uint(&(xbdip)->xbdi_refcnt)
196#define xbdi_put(xbdip) \ 196#define xbdi_put(xbdip) \
197do { \ 197do { \
198 if (atomic_dec_uint_nv(&(xbdip)->xbdi_refcnt) == 0) \ 198 if (atomic_dec_uint_nv(&(xbdip)->xbdi_refcnt) == 0) \
199 xbdback_finish_disconnect(xbdip); \ 199 xbdback_finish_disconnect(xbdip); \
200} while (/* CONSTCOND */ 0) 200} while (/* CONSTCOND */ 0)
201 201
202static SLIST_HEAD(, xbdback_instance) xbdback_instances; 202static SLIST_HEAD(, xbdback_instance) xbdback_instances;
203static kmutex_t xbdback_lock; 203static kmutex_t xbdback_lock;
204 204
205/* 205/*
206 * For each I/O operation associated with one of those requests, an 206 * For each I/O operation associated with one of those requests, an
207 * xbdback_io is allocated from a pool. It may correspond to multiple 207 * xbdback_io is allocated from a pool. It may correspond to multiple
208 * Xen disk requests, or parts of them, if several arrive at once that 208 * Xen disk requests, or parts of them, if several arrive at once that
209 * can be coalesced. 209 * can be coalesced.
210 */ 210 */
211struct xbdback_io { 211struct xbdback_io {
212 /* The instance pointer is duplicated for convenience. */ 212 /* The instance pointer is duplicated for convenience. */
213 struct xbdback_instance *xio_xbdi; /* our xbd instance */ 213 struct xbdback_instance *xio_xbdi; /* our xbd instance */
214 uint8_t xio_operation; 214 uint8_t xio_operation;
215 uint64_t xio_id; 215 uint64_t xio_id;
216 union { 216 union {
217 struct { 217 struct {
218 struct buf xio_buf; /* our I/O */ 218 struct buf xio_buf; /* our I/O */
219 /* the virtual address to map the request at */ 219 /* the virtual address to map the request at */
220 vaddr_t xio_vaddr; 220 vaddr_t xio_vaddr;
221 struct xbdback_va *xio_xv; 221 struct xbdback_va *xio_xv;
222 vaddr_t xio_start_offset; /* I/O start offset */ 222 vaddr_t xio_start_offset; /* I/O start offset */
223 /* grants to map */ 223 /* grants to map */
224 grant_ref_t xio_gref[XENSHM_MAX_PAGES_PER_REQUEST]; 224 grant_ref_t xio_gref[XENSHM_MAX_PAGES_PER_REQUEST];
225 /* grants release */ 225 /* grants release */
226 grant_handle_t xio_gh[XENSHM_MAX_PAGES_PER_REQUEST]; 226 grant_handle_t xio_gh[XENSHM_MAX_PAGES_PER_REQUEST];
227 uint16_t xio_nrma; /* number of guest pages */ 227 uint16_t xio_nrma; /* number of guest pages */
228 } xio_rw; 228 } xio_rw;
229 } u; 229 } u;
230}; 230};
231#define xio_buf u.xio_rw.xio_buf 231#define xio_buf u.xio_rw.xio_buf
232#define xio_vaddr u.xio_rw.xio_vaddr 232#define xio_vaddr u.xio_rw.xio_vaddr
233#define xio_start_offset u.xio_rw.xio_start_offset 233#define xio_start_offset u.xio_rw.xio_start_offset
234#define xio_xv u.xio_rw.xio_xv 234#define xio_xv u.xio_rw.xio_xv
235#define xio_gref u.xio_rw.xio_gref 235#define xio_gref u.xio_rw.xio_gref
236#define xio_gh u.xio_rw.xio_gh 236#define xio_gh u.xio_rw.xio_gh
237#define xio_nrma u.xio_rw.xio_nrma 237#define xio_nrma u.xio_rw.xio_nrma
238 238
239/* 239/*
240 * Pools to manage the chain of block requests and I/Os fragments 240 * Pools to manage the chain of block requests and I/Os fragments
241 * submitted by frontend. 241 * submitted by frontend.
242 */ 242 */
243static struct pool_cache xbdback_io_pool; 243static struct pool_cache xbdback_io_pool;
244 244
245/* Interval between reports of I/O errors from frontend */ 245/* Interval between reports of I/O errors from frontend */
246static const struct timeval xbdback_err_intvl = { 1, 0 }; 246static const struct timeval xbdback_err_intvl = { 1, 0 };
247 247
248#ifdef DEBUG 248#ifdef DEBUG
249static const struct timeval xbdback_fragio_intvl = { 60, 0 }; 249static const struct timeval xbdback_fragio_intvl = { 60, 0 };
250#endif 250#endif
251 void xbdbackattach(int); 251 void xbdbackattach(int);
252static int xbdback_xenbus_create(struct xenbus_device *); 252static int xbdback_xenbus_create(struct xenbus_device *);
253static int xbdback_xenbus_destroy(void *); 253static int xbdback_xenbus_destroy(void *);
254static void xbdback_frontend_changed(void *, XenbusState); 254static void xbdback_frontend_changed(void *, XenbusState);
255static void xbdback_backend_changed(struct xenbus_watch *, 255static void xbdback_backend_changed(struct xenbus_watch *,
256 const char **, unsigned int); 256 const char **, unsigned int);
257static int xbdback_evthandler(void *); 257static int xbdback_evthandler(void *);
258 258
259static int xbdback_connect(struct xbdback_instance *); 259static int xbdback_connect(struct xbdback_instance *);
260static void xbdback_disconnect(struct xbdback_instance *); 260static void xbdback_disconnect(struct xbdback_instance *);
261static void xbdback_finish_disconnect(struct xbdback_instance *); 261static void xbdback_finish_disconnect(struct xbdback_instance *);
262 262
263static bool xbdif_lookup(domid_t, uint32_t); 263static bool xbdif_lookup(domid_t, uint32_t);
264 264
265static void *xbdback_co_main(struct xbdback_instance *, void *); 265static void *xbdback_co_main(struct xbdback_instance *, void *);
266static void *xbdback_co_main_loop(struct xbdback_instance *, void *); 266static void *xbdback_co_main_loop(struct xbdback_instance *, void *);
267static void *xbdback_co_main_incr(struct xbdback_instance *, void *); 267static void *xbdback_co_main_incr(struct xbdback_instance *, void *);
268static void *xbdback_co_main_done2(struct xbdback_instance *, void *); 268static void *xbdback_co_main_done2(struct xbdback_instance *, void *);
269 269
270static void *xbdback_co_cache_flush(struct xbdback_instance *, void *); 270static void *xbdback_co_cache_flush(struct xbdback_instance *, void *);
271static void *xbdback_co_cache_doflush(struct xbdback_instance *, void *); 271static void *xbdback_co_cache_doflush(struct xbdback_instance *, void *);
272 272
273static void *xbdback_co_io(struct xbdback_instance *, void *); 273static void *xbdback_co_io(struct xbdback_instance *, void *);
274static void *xbdback_co_io_gotio(struct xbdback_instance *, void *); 274static void *xbdback_co_io_gotio(struct xbdback_instance *, void *);
275 275
276static void *xbdback_co_do_io(struct xbdback_instance *, void *); 276static void *xbdback_co_do_io(struct xbdback_instance *, void *);
277 277
278static void xbdback_io_error(struct xbdback_io *, int); 278static void xbdback_io_error(struct xbdback_io *, int);
279static void xbdback_iodone(struct buf *); 279static void xbdback_iodone(struct buf *);
280static void xbdback_send_reply(struct xbdback_instance *, uint64_t , int , int); 280static void xbdback_send_reply(struct xbdback_instance *, uint64_t , int , int);
281 281
282static void *xbdback_map_shm(struct xbdback_io *); 282static void *xbdback_map_shm(struct xbdback_io *);
283static void xbdback_unmap_shm(struct xbdback_io *); 283static void xbdback_unmap_shm(struct xbdback_io *);
284 284
285static void *xbdback_pool_get(struct pool_cache *, 285static void *xbdback_pool_get(struct pool_cache *,
286 struct xbdback_instance *); 286 struct xbdback_instance *);
287static void xbdback_pool_put(struct pool_cache *, void *); 287static void xbdback_pool_put(struct pool_cache *, void *);
288static void xbdback_thread(void *); 288static void xbdback_thread(void *);
289static void xbdback_wakeup_thread(struct xbdback_instance *); 289static void xbdback_wakeup_thread(struct xbdback_instance *);
290static void xbdback_trampoline(struct xbdback_instance *, void *); 290static void xbdback_trampoline(struct xbdback_instance *, void *);
291 291
292static struct xenbus_backend_driver xbd_backend_driver = { 292static struct xenbus_backend_driver xbd_backend_driver = {
293 .xbakd_create = xbdback_xenbus_create, 293 .xbakd_create = xbdback_xenbus_create,
294 .xbakd_type = "vbd" 294 .xbakd_type = "vbd"
295}; 295};
296 296
297void 297void
298xbdbackattach(int n) 298xbdbackattach(int n)
299{ 299{
300 XENPRINTF(("xbdbackattach\n")); 300 XENPRINTF(("xbdbackattach\n"));
301 301
302 /* 302 /*
303 * initialize the backend driver, register the control message handler 303 * initialize the backend driver, register the control message handler
304 * and send driver up message. 304 * and send driver up message.
305 */ 305 */
306 SLIST_INIT(&xbdback_instances); 306 SLIST_INIT(&xbdback_instances);
307 mutex_init(&xbdback_lock, MUTEX_DEFAULT, IPL_NONE); 307 mutex_init(&xbdback_lock, MUTEX_DEFAULT, IPL_NONE);
308 308
309 pool_cache_bootstrap(&xbdback_io_pool, 309 pool_cache_bootstrap(&xbdback_io_pool,
310 sizeof(struct xbdback_io), 0, 0, 0, "xbbip", NULL, 310 sizeof(struct xbdback_io), 0, 0, 0, "xbbip", NULL,
311 IPL_SOFTBIO, NULL, NULL, NULL); 311 IPL_SOFTBIO, NULL, NULL, NULL);
312 312
313 /* we allocate enough to handle a whole ring at once */ 313 /* we allocate enough to handle a whole ring at once */
314 pool_prime(&xbdback_io_pool.pc_pool, BLKIF_RING_SIZE); 314 pool_prime(&xbdback_io_pool.pc_pool, BLKIF_RING_SIZE);
315 315
316 xenbus_backend_register(&xbd_backend_driver); 316 xenbus_backend_register(&xbd_backend_driver);
317} 317}
318 318
319static int 319static int
320xbdback_xenbus_create(struct xenbus_device *xbusd) 320xbdback_xenbus_create(struct xenbus_device *xbusd)
321{ 321{
322 struct xbdback_instance *xbdi; 322 struct xbdback_instance *xbdi;
323 long domid, handle; 323 long domid, handle;
324 int error, i; 324 int error, i;
325 char *ep; 325 char *ep;
326 326
327 if ((error = xenbus_read_ul(NULL, xbusd->xbusd_path, 327 if ((error = xenbus_read_ul(NULL, xbusd->xbusd_path,
328 "frontend-id", &domid, 10)) != 0) { 328 "frontend-id", &domid, 10)) != 0) {
329 aprint_error("xbdback: can't read %s/frontend-id: %d\n", 329 aprint_error("xbdback: can't read %s/frontend-id: %d\n",
330 xbusd->xbusd_path, error); 330 xbusd->xbusd_path, error);
331 return error; 331 return error;
332 } 332 }
333 333
334 /* 334 /*
335 * get handle: this is the last component of the path; which is 335 * get handle: this is the last component of the path; which is
336 * a decimal number. $path/dev contains the device name, which is not 336 * a decimal number. $path/dev contains the device name, which is not
337 * appropriate. 337 * appropriate.
338 */ 338 */
339 for (i = strlen(xbusd->xbusd_path); i > 0; i--) { 339 for (i = strlen(xbusd->xbusd_path); i > 0; i--) {
340 if (xbusd->xbusd_path[i] == '/') 340 if (xbusd->xbusd_path[i] == '/')
341 break; 341 break;
342 } 342 }
343 if (i == 0) { 343 if (i == 0) {
344 aprint_error("xbdback: can't parse %s\n", 344 aprint_error("xbdback: can't parse %s\n",
345 xbusd->xbusd_path); 345 xbusd->xbusd_path);
346 return EFTYPE; 346 return EFTYPE;
347 } 347 }
348 handle = strtoul(&xbusd->xbusd_path[i+1], &ep, 10); 348 handle = strtoul(&xbusd->xbusd_path[i+1], &ep, 10);
349 if (*ep != '\0') { 349 if (*ep != '\0') {
350 aprint_error("xbdback: can't parse %s\n", 350 aprint_error("xbdback: can't parse %s\n",
351 xbusd->xbusd_path); 351 xbusd->xbusd_path);
352 return EFTYPE; 352 return EFTYPE;
353 } 353 }
354  354
355 if (xbdif_lookup(domid, handle)) { 355 if (xbdif_lookup(domid, handle)) {
356 return EEXIST; 356 return EEXIST;
357 } 357 }
358 xbdi = kmem_zalloc(sizeof(*xbdi), KM_SLEEP); 358 xbdi = kmem_zalloc(sizeof(*xbdi), KM_SLEEP);
359 359
360 xbdi->xbdi_domid = domid; 360 xbdi->xbdi_domid = domid;
361 xbdi->xbdi_handle = handle; 361 xbdi->xbdi_handle = handle;
362 snprintf(xbdi->xbdi_name, sizeof(xbdi->xbdi_name), "xbdb%di%d", 362 snprintf(xbdi->xbdi_name, sizeof(xbdi->xbdi_name), "xbdb%di%d",
363 xbdi->xbdi_domid, xbdi->xbdi_handle); 363 xbdi->xbdi_domid, xbdi->xbdi_handle);
364 364
365 /* initialize status and reference counter */ 365 /* initialize status and reference counter */
366 xbdi->xbdi_status = DISCONNECTED; 366 xbdi->xbdi_status = DISCONNECTED;
367 xbdi_get(xbdi); 367 xbdi_get(xbdi);
368 368
369 mutex_init(&xbdi->xbdi_lock, MUTEX_DEFAULT, IPL_BIO); 369 mutex_init(&xbdi->xbdi_lock, MUTEX_DEFAULT, IPL_BIO);
370 cv_init(&xbdi->xbdi_cv, xbdi->xbdi_name); 370 cv_init(&xbdi->xbdi_cv, xbdi->xbdi_name);
371 mutex_enter(&xbdback_lock); 371 mutex_enter(&xbdback_lock);
372 SLIST_INSERT_HEAD(&xbdback_instances, xbdi, next); 372 SLIST_INSERT_HEAD(&xbdback_instances, xbdi, next);
373 mutex_exit(&xbdback_lock); 373 mutex_exit(&xbdback_lock);
374 374
375 xbusd->xbusd_u.b.b_cookie = xbdi;  375 xbusd->xbusd_u.b.b_cookie = xbdi;
376 xbusd->xbusd_u.b.b_detach = xbdback_xenbus_destroy; 376 xbusd->xbusd_u.b.b_detach = xbdback_xenbus_destroy;
377 xbusd->xbusd_otherend_changed = xbdback_frontend_changed; 377 xbusd->xbusd_otherend_changed = xbdback_frontend_changed;
378 xbdi->xbdi_xbusd = xbusd; 378 xbdi->xbdi_xbusd = xbusd;
379 379
380 SLIST_INIT(&xbdi->xbdi_va_free); 380 SLIST_INIT(&xbdi->xbdi_va_free);
381 for (i = 0; i < BLKIF_RING_SIZE; i++) { 381 for (i = 0; i < BLKIF_RING_SIZE; i++) {
382 xbdi->xbdi_va[i].xv_vaddr = uvm_km_alloc(kernel_map, 382 xbdi->xbdi_va[i].xv_vaddr = uvm_km_alloc(kernel_map,
383 VBD_VA_SIZE, 0, UVM_KMF_VAONLY|UVM_KMF_WAITVA); 383 VBD_VA_SIZE, 0, UVM_KMF_VAONLY|UVM_KMF_WAITVA);
384 SLIST_INSERT_HEAD(&xbdi->xbdi_va_free, &xbdi->xbdi_va[i], 384 SLIST_INSERT_HEAD(&xbdi->xbdi_va_free, &xbdi->xbdi_va[i],
385 xv_next); 385 xv_next);
386 } 386 }
387 387
388 error = xenbus_watch_path2(xbusd, xbusd->xbusd_path, "physical-device", 388 error = xenbus_watch_path2(xbusd, xbusd->xbusd_path, "physical-device",
389 &xbdi->xbdi_watch, xbdback_backend_changed); 389 &xbdi->xbdi_watch, xbdback_backend_changed);
390 if (error) { 390 if (error) {
391 printf("failed to watch on %s/physical-device: %d\n", 391 printf("failed to watch on %s/physical-device: %d\n",
392 xbusd->xbusd_path, error); 392 xbusd->xbusd_path, error);
393 goto fail; 393 goto fail;
394 } 394 }
395 xbdi->xbdi_watch.xbw_dev = xbusd; 395 xbdi->xbdi_watch.xbw_dev = xbusd;
396 error = xenbus_switch_state(xbusd, NULL, XenbusStateInitWait); 396 error = xenbus_switch_state(xbusd, NULL, XenbusStateInitWait);
397 if (error) { 397 if (error) {
398 printf("failed to switch state on %s: %d\n", 398 printf("failed to switch state on %s: %d\n",
399 xbusd->xbusd_path, error); 399 xbusd->xbusd_path, error);
400 goto fail2; 400 goto fail2;
401 } 401 }
402 return 0; 402 return 0;
403fail2: 403fail2:
404 unregister_xenbus_watch(&xbdi->xbdi_watch); 404 unregister_xenbus_watch(&xbdi->xbdi_watch);
405fail: 405fail:
406 kmem_free(xbdi, sizeof(*xbdi)); 406 kmem_free(xbdi, sizeof(*xbdi));
407 return error; 407 return error;
408} 408}
409 409
410static int 410static int
411xbdback_xenbus_destroy(void *arg) 411xbdback_xenbus_destroy(void *arg)
412{ 412{
413 struct xbdback_instance *xbdi = arg; 413 struct xbdback_instance *xbdi = arg;
414 struct xenbus_device *xbusd = xbdi->xbdi_xbusd; 414 struct xenbus_device *xbusd = xbdi->xbdi_xbusd;
415 struct gnttab_unmap_grant_ref ungrop; 415 struct gnttab_unmap_grant_ref ungrop;
416 int err; 416 int err;
417 417
418 XENPRINTF(("xbdback_xenbus_destroy state %d\n", xbdi->xbdi_status)); 418 XENPRINTF(("xbdback_xenbus_destroy state %d\n", xbdi->xbdi_status));
419 419
420 xbdback_disconnect(xbdi); 420 xbdback_disconnect(xbdi);
421 421
422 /* unregister watch */ 422 /* unregister watch */
423 if (xbdi->xbdi_watch.node) 423 if (xbdi->xbdi_watch.node)
424 xenbus_unwatch_path(&xbdi->xbdi_watch); 424 xenbus_unwatch_path(&xbdi->xbdi_watch);
425 425
426 /* unmap ring */ 426 /* unmap ring */
427 if (xbdi->xbdi_ring_va != 0) { 427 if (xbdi->xbdi_ring_va != 0) {
428 ungrop.host_addr = xbdi->xbdi_ring_va; 428 ungrop.host_addr = xbdi->xbdi_ring_va;
429 ungrop.handle = xbdi->xbdi_ring_handle; 429 ungrop.handle = xbdi->xbdi_ring_handle;
430 ungrop.dev_bus_addr = 0; 430 ungrop.dev_bus_addr = 0;
431 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 431 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
432 &ungrop, 1); 432 &ungrop, 1);
433 if (err) 433 if (err)
434 printf("xbdback %s: unmap_grant_ref failed: %d\n", 434 printf("xbdback %s: unmap_grant_ref failed: %d\n",
435 xbusd->xbusd_otherend, err); 435 xbusd->xbusd_otherend, err);
436 uvm_km_free(kernel_map, xbdi->xbdi_ring_va, 436 uvm_km_free(kernel_map, xbdi->xbdi_ring_va,
437 PAGE_SIZE, UVM_KMF_VAONLY); 437 PAGE_SIZE, UVM_KMF_VAONLY);
438 } 438 }
439 /* close device */ 439 /* close device */
440 if (xbdi->xbdi_size) { 440 if (xbdi->xbdi_size) {
441 const char *name; 441 const char *name;
442 struct dkwedge_info wi; 442 struct dkwedge_info wi;
443 if (getdiskinfo(xbdi->xbdi_vp, &wi) == 0) 443 if (getdiskinfo(xbdi->xbdi_vp, &wi) == 0)
444 name = wi.dkw_devname; 444 name = wi.dkw_devname;
445 else 445 else
446 name = "*unknown*"; 446 name = "*unknown*";
447 printf("xbd backend: detach device %s for domain %d\n", 447 printf("xbd backend: detach device %s for domain %d\n",
448 name, xbdi->xbdi_domid); 448 name, xbdi->xbdi_domid);
449 vn_close(xbdi->xbdi_vp, FREAD, NOCRED); 449 vn_close(xbdi->xbdi_vp, FREAD, NOCRED);
450 } 450 }
451 mutex_enter(&xbdback_lock); 451 mutex_enter(&xbdback_lock);
452 SLIST_REMOVE(&xbdback_instances, xbdi, xbdback_instance, next); 452 SLIST_REMOVE(&xbdback_instances, xbdi, xbdback_instance, next);
453 mutex_exit(&xbdback_lock); 453 mutex_exit(&xbdback_lock);
454 454
455 for (int i = 0; i < BLKIF_RING_SIZE; i++) { 455 for (int i = 0; i < BLKIF_RING_SIZE; i++) {
456 if (xbdi->xbdi_va[i].xv_vaddr != 0) { 456 if (xbdi->xbdi_va[i].xv_vaddr != 0) {
457 uvm_km_free(kernel_map, xbdi->xbdi_va[i].xv_vaddr, 457 uvm_km_free(kernel_map, xbdi->xbdi_va[i].xv_vaddr,
458 VBD_VA_SIZE, UVM_KMF_VAONLY); 458 VBD_VA_SIZE, UVM_KMF_VAONLY);
459 xbdi->xbdi_va[i].xv_vaddr = 0; 459 xbdi->xbdi_va[i].xv_vaddr = 0;
460 } 460 }
461 } 461 }
462 462
463 mutex_destroy(&xbdi->xbdi_lock); 463 mutex_destroy(&xbdi->xbdi_lock);
464 cv_destroy(&xbdi->xbdi_cv); 464 cv_destroy(&xbdi->xbdi_cv);
465 kmem_free(xbdi, sizeof(*xbdi)); 465 kmem_free(xbdi, sizeof(*xbdi));
466 return 0; 466 return 0;
467} 467}
468 468
469static int 469static int
470xbdback_connect(struct xbdback_instance *xbdi) 470xbdback_connect(struct xbdback_instance *xbdi)
471{ 471{
472 int err; 472 int err;
473 struct gnttab_map_grant_ref grop; 473 struct gnttab_map_grant_ref grop;
474 struct gnttab_unmap_grant_ref ungrop; 474 struct gnttab_unmap_grant_ref ungrop;
475 evtchn_op_t evop; 475 evtchn_op_t evop;
476 u_long ring_ref, revtchn; 476 u_long ring_ref, revtchn;
477 char xsproto[32]; 477 char xsproto[32];
478 const char *proto; 478 const char *proto;
479 struct xenbus_device *xbusd = xbdi->xbdi_xbusd; 479 struct xenbus_device *xbusd = xbdi->xbdi_xbusd;
480 480
481 XENPRINTF(("xbdback %s: connect\n", xbusd->xbusd_path)); 481 XENPRINTF(("xbdback %s: connect\n", xbusd->xbusd_path));
482 /* read comunication informations */ 482 /* read comunication informations */
483 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, 483 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend,
484 "ring-ref", &ring_ref, 10); 484 "ring-ref", &ring_ref, 10);
485 if (err) { 485 if (err) {
486 xenbus_dev_fatal(xbusd, err, "reading %s/ring-ref", 486 xenbus_dev_fatal(xbusd, err, "reading %s/ring-ref",
487 xbusd->xbusd_otherend); 487 xbusd->xbusd_otherend);
488 return -1; 488 return -1;
489 } 489 }
490 XENPRINTF(("xbdback %s: connect ring-ref %lu\n", xbusd->xbusd_path, ring_ref)); 490 XENPRINTF(("xbdback %s: connect ring-ref %lu\n", xbusd->xbusd_path, ring_ref));
491 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, 491 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend,
492 "event-channel", &revtchn, 10); 492 "event-channel", &revtchn, 10);
493 if (err) { 493 if (err) {
494 xenbus_dev_fatal(xbusd, err, "reading %s/event-channel", 494 xenbus_dev_fatal(xbusd, err, "reading %s/event-channel",
495 xbusd->xbusd_otherend); 495 xbusd->xbusd_otherend);
496 return -1; 496 return -1;
497 } 497 }
498 XENPRINTF(("xbdback %s: connect revtchn %lu\n", xbusd->xbusd_path, revtchn)); 498 XENPRINTF(("xbdback %s: connect revtchn %lu\n", xbusd->xbusd_path, revtchn));
499 err = xenbus_read(NULL, xbusd->xbusd_otherend, "protocol", 499 err = xenbus_read(NULL, xbusd->xbusd_otherend, "protocol",
500 xsproto, sizeof(xsproto)); 500 xsproto, sizeof(xsproto));
501 if (err) { 501 if (err) {
502 xbdi->xbdi_proto = XBDIP_NATIVE; 502 xbdi->xbdi_proto = XBDIP_NATIVE;
503 proto = "unspecified"; 503 proto = "unspecified";
504 XENPRINTF(("xbdback %s: connect no xsproto\n", xbusd->xbusd_path)); 504 XENPRINTF(("xbdback %s: connect no xsproto\n", xbusd->xbusd_path));
505 } else { 505 } else {
506 XENPRINTF(("xbdback %s: connect xsproto %s\n", xbusd->xbusd_path, xsproto)); 506 XENPRINTF(("xbdback %s: connect xsproto %s\n", xbusd->xbusd_path, xsproto));
507 if (strcmp(xsproto, XEN_IO_PROTO_ABI_NATIVE) == 0) { 507 if (strcmp(xsproto, XEN_IO_PROTO_ABI_NATIVE) == 0) {
508 xbdi->xbdi_proto = XBDIP_NATIVE; 508 xbdi->xbdi_proto = XBDIP_NATIVE;
509 proto = XEN_IO_PROTO_ABI_NATIVE; 509 proto = XEN_IO_PROTO_ABI_NATIVE;
510 } else if (strcmp(xsproto, XEN_IO_PROTO_ABI_X86_32) == 0) { 510 } else if (strcmp(xsproto, XEN_IO_PROTO_ABI_X86_32) == 0) {
511 xbdi->xbdi_proto = XBDIP_32; 511 xbdi->xbdi_proto = XBDIP_32;
512 proto = XEN_IO_PROTO_ABI_X86_32; 512 proto = XEN_IO_PROTO_ABI_X86_32;
513 } else if (strcmp(xsproto, XEN_IO_PROTO_ABI_X86_64) == 0) { 513 } else if (strcmp(xsproto, XEN_IO_PROTO_ABI_X86_64) == 0) {
514 xbdi->xbdi_proto = XBDIP_64; 514 xbdi->xbdi_proto = XBDIP_64;
515 proto = XEN_IO_PROTO_ABI_X86_64; 515 proto = XEN_IO_PROTO_ABI_X86_64;
516 } else { 516 } else {
517 aprint_error("xbd domain %d: unknown proto %s\n", 517 aprint_error("xbd domain %d: unknown proto %s\n",
518 xbdi->xbdi_domid, xsproto); 518 xbdi->xbdi_domid, xsproto);
519 return -1; 519 return -1;
520 } 520 }
521 } 521 }
522 522
523 /* allocate VA space and map rings */ 523 /* allocate VA space and map rings */
524 xbdi->xbdi_ring_va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, 524 xbdi->xbdi_ring_va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
525 UVM_KMF_VAONLY); 525 UVM_KMF_VAONLY);
526 if (xbdi->xbdi_ring_va == 0) { 526 if (xbdi->xbdi_ring_va == 0) {
527 xenbus_dev_fatal(xbusd, ENOMEM, 527 xenbus_dev_fatal(xbusd, ENOMEM,
528 "can't get VA for ring", xbusd->xbusd_otherend); 528 "can't get VA for ring", xbusd->xbusd_otherend);
529 return -1; 529 return -1;
530 } 530 }
531 XENPRINTF(("xbdback %s: connect va 0x%" PRIxVADDR "\n", xbusd->xbusd_path, xbdi->xbdi_ring_va)); 531 XENPRINTF(("xbdback %s: connect va 0x%" PRIxVADDR "\n", xbusd->xbusd_path, xbdi->xbdi_ring_va));
532 532
533 grop.host_addr = xbdi->xbdi_ring_va; 533 grop.host_addr = xbdi->xbdi_ring_va;
534 grop.flags = GNTMAP_host_map; 534 grop.flags = GNTMAP_host_map;
535 grop.ref = ring_ref; 535 grop.ref = ring_ref;
536 grop.dom = xbdi->xbdi_domid; 536 grop.dom = xbdi->xbdi_domid;
537 err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, 537 err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
538 &grop, 1); 538 &grop, 1);
539 if (err || grop.status) { 539 if (err || grop.status) {
540 aprint_error("xbdback %s: can't map grant ref: %d/%d\n", 540 aprint_error("xbdback %s: can't map grant ref: %d/%d\n",
541 xbusd->xbusd_path, err, grop.status); 541 xbusd->xbusd_path, err, grop.status);
542 xenbus_dev_fatal(xbusd, EINVAL, 542 xenbus_dev_fatal(xbusd, EINVAL,
543 "can't map ring", xbusd->xbusd_otherend); 543 "can't map ring", xbusd->xbusd_otherend);
544 goto err; 544 goto err;
545 } 545 }
546 xbdi->xbdi_ring_handle = grop.handle; 546 xbdi->xbdi_ring_handle = grop.handle;
547 XENPRINTF(("xbdback %s: connect grhandle %d\n", xbusd->xbusd_path, grop.handle)); 547 XENPRINTF(("xbdback %s: connect grhandle %d\n", xbusd->xbusd_path, grop.handle));
548 548
549 switch(xbdi->xbdi_proto) { 549 switch(xbdi->xbdi_proto) {
550 case XBDIP_NATIVE: 550 case XBDIP_NATIVE:
551 { 551 {
552 blkif_sring_t *sring = (void *)xbdi->xbdi_ring_va; 552 blkif_sring_t *sring = (void *)xbdi->xbdi_ring_va;
553 BACK_RING_INIT(&xbdi->xbdi_ring.ring_n, sring, PAGE_SIZE); 553 BACK_RING_INIT(&xbdi->xbdi_ring.ring_n, sring, PAGE_SIZE);
554 break; 554 break;
555 } 555 }
556 case XBDIP_32: 556 case XBDIP_32:
557 { 557 {
558 blkif_x86_32_sring_t *sring = (void *)xbdi->xbdi_ring_va; 558 blkif_x86_32_sring_t *sring = (void *)xbdi->xbdi_ring_va;
559 BACK_RING_INIT(&xbdi->xbdi_ring.ring_32, sring, PAGE_SIZE); 559 BACK_RING_INIT(&xbdi->xbdi_ring.ring_32, sring, PAGE_SIZE);
560 break; 560 break;
561 } 561 }
562 case XBDIP_64: 562 case XBDIP_64:
563 { 563 {
564 blkif_x86_64_sring_t *sring = (void *)xbdi->xbdi_ring_va; 564 blkif_x86_64_sring_t *sring = (void *)xbdi->xbdi_ring_va;
565 BACK_RING_INIT(&xbdi->xbdi_ring.ring_64, sring, PAGE_SIZE); 565 BACK_RING_INIT(&xbdi->xbdi_ring.ring_64, sring, PAGE_SIZE);
566 break; 566 break;
567 } 567 }
568 } 568 }
569 569
570 evop.cmd = EVTCHNOP_bind_interdomain; 570 evop.cmd = EVTCHNOP_bind_interdomain;
571 evop.u.bind_interdomain.remote_dom = xbdi->xbdi_domid; 571 evop.u.bind_interdomain.remote_dom = xbdi->xbdi_domid;
572 evop.u.bind_interdomain.remote_port = revtchn; 572 evop.u.bind_interdomain.remote_port = revtchn;
573 err = HYPERVISOR_event_channel_op(&evop); 573 err = HYPERVISOR_event_channel_op(&evop);
574 if (err) { 574 if (err) {
575 aprint_error("blkback %s: " 575 aprint_error("blkback %s: "
576 "can't get event channel: %d\n", 576 "can't get event channel: %d\n",
577 xbusd->xbusd_otherend, err); 577 xbusd->xbusd_otherend, err);
578 xenbus_dev_fatal(xbusd, err, 578 xenbus_dev_fatal(xbusd, err,
579 "can't bind event channel", xbusd->xbusd_otherend); 579 "can't bind event channel", xbusd->xbusd_otherend);
580 goto err2; 580 goto err2;
581 } 581 }
582 XENPRINTF(("xbdback %s: connect evchannel %d\n", xbusd->xbusd_path, xbdi->xbdi_evtchn)); 582 XENPRINTF(("xbdback %s: connect evchannel %d\n", xbusd->xbusd_path, xbdi->xbdi_evtchn));
583 xbdi->xbdi_evtchn = evop.u.bind_interdomain.local_port; 583 xbdi->xbdi_evtchn = evop.u.bind_interdomain.local_port;
584 584
585 xbdi->xbdi_ih = xen_intr_establish_xname(-1, &xen_pic, xbdi->xbdi_evtchn, 585 xbdi->xbdi_ih = xen_intr_establish_xname(-1, &xen_pic, xbdi->xbdi_evtchn,
586 IST_LEVEL, IPL_BIO, xbdback_evthandler, xbdi, false, 586 IST_LEVEL, IPL_BIO, xbdback_evthandler, xbdi, false,
587 xbdi->xbdi_name); 587 xbdi->xbdi_name);
588 KASSERT(xbdi->xbdi_ih != NULL); 588 KASSERT(xbdi->xbdi_ih != NULL);
589 aprint_verbose("xbd backend domain %d handle %#x (%d) " 589 aprint_verbose("xbd backend domain %d handle %#x (%d) "
590 "using event channel %d, protocol %s\n", xbdi->xbdi_domid, 590 "using event channel %d, protocol %s\n", xbdi->xbdi_domid,
591 xbdi->xbdi_handle, xbdi->xbdi_handle, xbdi->xbdi_evtchn, proto); 591 xbdi->xbdi_handle, xbdi->xbdi_handle, xbdi->xbdi_evtchn, proto);
592 592
593 /* enable the xbdback event handler machinery */ 593 /* enable the xbdback event handler machinery */
594 xbdi->xbdi_status = WAITING; 594 xbdi->xbdi_status = WAITING;
595 hypervisor_unmask_event(xbdi->xbdi_evtchn); 595 hypervisor_unmask_event(xbdi->xbdi_evtchn);
596 hypervisor_notify_via_evtchn(xbdi->xbdi_evtchn); 596 hypervisor_notify_via_evtchn(xbdi->xbdi_evtchn);
597 597
598 if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, 598 if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
599 xbdback_thread, xbdi, NULL, "%s", xbdi->xbdi_name) == 0) 599 xbdback_thread, xbdi, NULL, "%s", xbdi->xbdi_name) == 0)
600 return 0; 600 return 0;
601 601
602err2: 602err2:
603 /* unmap ring */ 603 /* unmap ring */
604 ungrop.host_addr = xbdi->xbdi_ring_va; 604 ungrop.host_addr = xbdi->xbdi_ring_va;
605 ungrop.handle = xbdi->xbdi_ring_handle; 605 ungrop.handle = xbdi->xbdi_ring_handle;
606 ungrop.dev_bus_addr = 0; 606 ungrop.dev_bus_addr = 0;
607 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 607 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
608 &ungrop, 1); 608 &ungrop, 1);
609 if (err) 609 if (err)
610 aprint_error("xbdback %s: unmap_grant_ref failed: %d\n", 610 aprint_error("xbdback %s: unmap_grant_ref failed: %d\n",
611 xbusd->xbusd_path, err); 611 xbusd->xbusd_path, err);
612 612
613err: 613err:
614 /* free ring VA space */ 614 /* free ring VA space */
615 uvm_km_free(kernel_map, xbdi->xbdi_ring_va, PAGE_SIZE, UVM_KMF_VAONLY); 615 uvm_km_free(kernel_map, xbdi->xbdi_ring_va, PAGE_SIZE, UVM_KMF_VAONLY);
616 return -1; 616 return -1;
617} 617}
618 618
619/* 619/*
620 * Signal a xbdback thread to disconnect. Done in 'xenwatch' thread context. 620 * Signal a xbdback thread to disconnect. Done in 'xenwatch' thread context.
621 */ 621 */
622static void 622static void
623xbdback_disconnect(struct xbdback_instance *xbdi) 623xbdback_disconnect(struct xbdback_instance *xbdi)
624{ 624{
625  625
626 mutex_enter(&xbdi->xbdi_lock); 626 mutex_enter(&xbdi->xbdi_lock);
627 if (xbdi->xbdi_status == DISCONNECTED) { 627 if (xbdi->xbdi_status == DISCONNECTED) {
628 mutex_exit(&xbdi->xbdi_lock); 628 mutex_exit(&xbdi->xbdi_lock);
629 return; 629 return;
630 } 630 }
631 hypervisor_mask_event(xbdi->xbdi_evtchn); 631 hypervisor_mask_event(xbdi->xbdi_evtchn);
632 xen_intr_disestablish(xbdi->xbdi_ih); 632 xen_intr_disestablish(xbdi->xbdi_ih);
633 633
634 /* signal thread that we want to disconnect, then wait for it */ 634 /* signal thread that we want to disconnect, then wait for it */
635 xbdi->xbdi_status = DISCONNECTING; 635 xbdi->xbdi_status = DISCONNECTING;
636 cv_signal(&xbdi->xbdi_cv); 636 cv_signal(&xbdi->xbdi_cv);
637 637
638 while (xbdi->xbdi_status != DISCONNECTED) 638 while (xbdi->xbdi_status != DISCONNECTED)
639 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock); 639 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock);
640 640
641 mutex_exit(&xbdi->xbdi_lock); 641 mutex_exit(&xbdi->xbdi_lock);
642 642
643 xenbus_switch_state(xbdi->xbdi_xbusd, NULL, XenbusStateClosing); 643 xenbus_switch_state(xbdi->xbdi_xbusd, NULL, XenbusStateClosing);
644} 644}
645 645
646static void 646static void
647xbdback_frontend_changed(void *arg, XenbusState new_state) 647xbdback_frontend_changed(void *arg, XenbusState new_state)
648{ 648{
649 struct xbdback_instance *xbdi = arg; 649 struct xbdback_instance *xbdi = arg;
650 struct xenbus_device *xbusd = xbdi->xbdi_xbusd; 650 struct xenbus_device *xbusd = xbdi->xbdi_xbusd;
651 651
652 XENPRINTF(("xbdback %s: new state %d\n", xbusd->xbusd_path, new_state)); 652 XENPRINTF(("xbdback %s: new state %d\n", xbusd->xbusd_path, new_state));
653 switch(new_state) { 653 switch(new_state) {
654 case XenbusStateInitialising: 654 case XenbusStateInitialising:
655 break; 655 break;
656 case XenbusStateInitialised: 656 case XenbusStateInitialised:
657 case XenbusStateConnected: 657 case XenbusStateConnected:
658 if (xbdi->xbdi_status == WAITING || xbdi->xbdi_status == RUN) 658 if (xbdi->xbdi_status == WAITING || xbdi->xbdi_status == RUN)
659 break; 659 break;
660 xbdback_connect(xbdi); 660 xbdback_connect(xbdi);
661 break; 661 break;
662 case XenbusStateClosing: 662 case XenbusStateClosing:
663 xbdback_disconnect(xbdi); 663 xbdback_disconnect(xbdi);
664 break; 664 break;
665 case XenbusStateClosed: 665 case XenbusStateClosed:
666 /* otherend_changed() should handle it for us */ 666 /* otherend_changed() should handle it for us */
667 panic("xbdback_frontend_changed: closed\n"); 667 panic("xbdback_frontend_changed: closed\n");
668 case XenbusStateUnknown: 668 case XenbusStateUnknown:
669 case XenbusStateInitWait: 669 case XenbusStateInitWait:
670 default: 670 default:
671 aprint_error("xbdback %s: invalid frontend state %d\n", 671 aprint_error("xbdback %s: invalid frontend state %d\n",
672 xbusd->xbusd_path, new_state); 672 xbusd->xbusd_path, new_state);
673 } 673 }
674 return; 674 return;
675} 675}
676 676
677static void 677static void
678xbdback_backend_changed(struct xenbus_watch *watch, 678xbdback_backend_changed(struct xenbus_watch *watch,
679 const char **vec, unsigned int len) 679 const char **vec, unsigned int len)
680{ 680{
681 struct xenbus_device *xbusd = watch->xbw_dev; 681 struct xenbus_device *xbusd = watch->xbw_dev;
682 struct xbdback_instance *xbdi = xbusd->xbusd_u.b.b_cookie; 682 struct xbdback_instance *xbdi = xbusd->xbusd_u.b.b_cookie;
683 int err; 683 int err;
684 long dev; 684 long dev;
685 char mode[32]; 685 char mode[32];
686 struct xenbus_transaction *xbt; 686 struct xenbus_transaction *xbt;
687 const char *devname; 687 const char *devname;
688 int major; 688 int major;
689 689
690 err = xenbus_read_ul(NULL, xbusd->xbusd_path, "physical-device", 690 err = xenbus_read_ul(NULL, xbusd->xbusd_path, "physical-device",
691 &dev, 10); 691 &dev, 10);
692 /* 692 /*
693 * An error can occur as the watch can fire up just after being 693 * An error can occur as the watch can fire up just after being
694 * registered. So we have to ignore error :( 694 * registered. So we have to ignore error :(
695 */ 695 */
696 if (err) 696 if (err)
697 return; 697 return;
698 /* 698 /*
699 * we can also fire up after having opened the device, don't try 699 * we can also fire up after having opened the device, don't try
700 * to do it twice. 700 * to do it twice.
701 */ 701 */
702 if (xbdi->xbdi_vp != NULL) { 702 if (xbdi->xbdi_vp != NULL) {
703 if (xbdi->xbdi_status == WAITING || xbdi->xbdi_status == RUN) { 703 if (xbdi->xbdi_status == WAITING || xbdi->xbdi_status == RUN) {
704 if (xbdi->xbdi_dev != dev) { 704 if (xbdi->xbdi_dev != dev) {
705 printf("xbdback %s: changing physical device " 705 printf("xbdback %s: changing physical device "
706 "from %#"PRIx64" to %#lx not supported\n", 706 "from %#"PRIx64" to %#lx not supported\n",
707 xbusd->xbusd_path, xbdi->xbdi_dev, dev); 707 xbusd->xbusd_path, xbdi->xbdi_dev, dev);
708 } 708 }
709 } 709 }
710 return; 710 return;
711 } 711 }
712 xbdi->xbdi_dev = dev; 712 xbdi->xbdi_dev = dev;
713 err = xenbus_read(NULL, xbusd->xbusd_path, "mode", mode, sizeof(mode)); 713 err = xenbus_read(NULL, xbusd->xbusd_path, "mode", mode, sizeof(mode));
714 if (err) { 714 if (err) {
715 printf("xbdback: failed to read %s/mode: %d\n", 715 printf("xbdback: failed to read %s/mode: %d\n",
716 xbusd->xbusd_path, err); 716 xbusd->xbusd_path, err);
717 return; 717 return;
718 } 718 }
719 if (mode[0] == 'w') 719 if (mode[0] == 'w')
720 xbdi->xbdi_ro = false; 720 xbdi->xbdi_ro = false;
721 else 721 else
722 xbdi->xbdi_ro = true; 722 xbdi->xbdi_ro = true;
723 major = major(xbdi->xbdi_dev); 723 major = major(xbdi->xbdi_dev);
724 devname = devsw_blk2name(major); 724 devname = devsw_blk2name(major);
725 if (devname == NULL) { 725 if (devname == NULL) {
726 printf("xbdback %s: unknown device 0x%"PRIx64"\n", 726 printf("xbdback %s: unknown device 0x%"PRIx64"\n",
727 xbusd->xbusd_path, xbdi->xbdi_dev); 727 xbusd->xbusd_path, xbdi->xbdi_dev);
728 return; 728 return;
729 } 729 }
730 xbdi->xbdi_bdevsw = bdevsw_lookup(xbdi->xbdi_dev); 730 xbdi->xbdi_bdevsw = bdevsw_lookup(xbdi->xbdi_dev);
731 if (xbdi->xbdi_bdevsw == NULL) { 731 if (xbdi->xbdi_bdevsw == NULL) {
732 printf("xbdback %s: no bdevsw for device 0x%"PRIx64"\n", 732 printf("xbdback %s: no bdevsw for device 0x%"PRIx64"\n",
733 xbusd->xbusd_path, xbdi->xbdi_dev); 733 xbusd->xbusd_path, xbdi->xbdi_dev);
734 return; 734 return;
735 } 735 }
736 err = bdevvp(xbdi->xbdi_dev, &xbdi->xbdi_vp); 736 err = bdevvp(xbdi->xbdi_dev, &xbdi->xbdi_vp);
737 if (err) { 737 if (err) {
738 printf("xbdback %s: can't open device 0x%"PRIx64": %d\n", 738 printf("xbdback %s: can't open device 0x%"PRIx64": %d\n",
739 xbusd->xbusd_path, xbdi->xbdi_dev, err); 739 xbusd->xbusd_path, xbdi->xbdi_dev, err);
740 return; 740 return;
741 } 741 }
742 err = vn_lock(xbdi->xbdi_vp, LK_EXCLUSIVE | LK_RETRY); 742 err = vn_lock(xbdi->xbdi_vp, LK_EXCLUSIVE | LK_RETRY);
743 if (err) { 743 if (err) {
744 printf("xbdback %s: can't vn_lock device 0x%"PRIx64": %d\n", 744 printf("xbdback %s: can't vn_lock device 0x%"PRIx64": %d\n",
745 xbusd->xbusd_path, xbdi->xbdi_dev, err); 745 xbusd->xbusd_path, xbdi->xbdi_dev, err);
746 vrele(xbdi->xbdi_vp); 746 vrele(xbdi->xbdi_vp);
747 return; 747 return;
748 } 748 }
749 err = VOP_OPEN(xbdi->xbdi_vp, FREAD, NOCRED); 749 err = VOP_OPEN(xbdi->xbdi_vp, FREAD, NOCRED);
750 if (err) { 750 if (err) {
751 printf("xbdback %s: can't VOP_OPEN device 0x%"PRIx64": %d\n", 751 printf("xbdback %s: can't VOP_OPEN device 0x%"PRIx64": %d\n",
752 xbusd->xbusd_path, xbdi->xbdi_dev, err); 752 xbusd->xbusd_path, xbdi->xbdi_dev, err);
753 vput(xbdi->xbdi_vp); 753 vput(xbdi->xbdi_vp);
754 return; 754 return;
755 } 755 }
756 VOP_UNLOCK(xbdi->xbdi_vp); 756 VOP_UNLOCK(xbdi->xbdi_vp);
757 757
758 /* dk device; get wedge data */ 758 /* dk device; get wedge data */
759 struct dkwedge_info wi; 759 struct dkwedge_info wi;
760 if ((err = getdiskinfo(xbdi->xbdi_vp, &wi)) == 0) { 760 if ((err = getdiskinfo(xbdi->xbdi_vp, &wi)) == 0) {
761 xbdi->xbdi_size = wi.dkw_size; 761 xbdi->xbdi_size = wi.dkw_size;
762 printf("xbd backend: attach device %s (size %" PRIu64 ") " 762 printf("xbd backend: attach device %s (size %" PRIu64 ") "
763 "for domain %d\n", wi.dkw_devname, xbdi->xbdi_size, 763 "for domain %d\n", wi.dkw_devname, xbdi->xbdi_size,
764 xbdi->xbdi_domid); 764 xbdi->xbdi_domid);
765 } else { 765 } else {
766 /* If both Ioctls failed set device size to 0 and return */ 766 /* If both Ioctls failed set device size to 0 and return */
767 printf("xbdback %s: can't DIOCGWEDGEINFO device " 767 printf("xbdback %s: can't DIOCGWEDGEINFO device "
768 "0x%"PRIx64": %d\n", xbusd->xbusd_path, 768 "0x%"PRIx64": %d\n", xbusd->xbusd_path,
769 xbdi->xbdi_dev, err);  769 xbdi->xbdi_dev, err);
770 xbdi->xbdi_size = xbdi->xbdi_dev = 0; 770 xbdi->xbdi_size = xbdi->xbdi_dev = 0;
771 vn_close(xbdi->xbdi_vp, FREAD, NOCRED); 771 vn_close(xbdi->xbdi_vp, FREAD, NOCRED);
772 xbdi->xbdi_vp = NULL; 772 xbdi->xbdi_vp = NULL;
773 return; 773 return;
774 } 774 }
775again: 775again:
776 xbt = xenbus_transaction_start(); 776 xbt = xenbus_transaction_start();
777 if (xbt == NULL) { 777 if (xbt == NULL) {
778 printf("xbdback %s: can't start transaction\n", 778 printf("xbdback %s: can't start transaction\n",
779 xbusd->xbusd_path); 779 xbusd->xbusd_path);
780 return; 780 return;
781 } 781 }
782 err = xenbus_printf(xbt, xbusd->xbusd_path, "sectors", "%" PRIu64 , 782 err = xenbus_printf(xbt, xbusd->xbusd_path, "sectors", "%" PRIu64 ,
783 xbdi->xbdi_size); 783 xbdi->xbdi_size);
784 if (err) { 784 if (err) {
785 printf("xbdback: failed to write %s/sectors: %d\n", 785 printf("xbdback: failed to write %s/sectors: %d\n",
786 xbusd->xbusd_path, err); 786 xbusd->xbusd_path, err);
787 goto abort; 787 goto abort;
788 } 788 }
789 err = xenbus_printf(xbt, xbusd->xbusd_path, "info", "%u", 789 err = xenbus_printf(xbt, xbusd->xbusd_path, "info", "%u",
790 xbdi->xbdi_ro ? VDISK_READONLY : 0); 790 xbdi->xbdi_ro ? VDISK_READONLY : 0);
791 if (err) { 791 if (err) {
792 printf("xbdback: failed to write %s/info: %d\n", 792 printf("xbdback: failed to write %s/info: %d\n",
793 xbusd->xbusd_path, err); 793 xbusd->xbusd_path, err);
794 goto abort; 794 goto abort;
795 } 795 }
796 err = xenbus_printf(xbt, xbusd->xbusd_path, "sector-size", "%lu", 796 err = xenbus_printf(xbt, xbusd->xbusd_path, "sector-size", "%lu",
797 (u_long)DEV_BSIZE); 797 (u_long)DEV_BSIZE);
798 if (err) { 798 if (err) {
799 printf("xbdback: failed to write %s/sector-size: %d\n", 799 printf("xbdback: failed to write %s/sector-size: %d\n",
800 xbusd->xbusd_path, err); 800 xbusd->xbusd_path, err);
801 goto abort; 801 goto abort;
802 } 802 }
803 err = xenbus_printf(xbt, xbusd->xbusd_path, "feature-flush-cache", 803 err = xenbus_printf(xbt, xbusd->xbusd_path, "feature-flush-cache",
804 "%u", 1); 804 "%u", 1);
805 if (err) { 805 if (err) {
806 printf("xbdback: failed to write %s/feature-flush-cache: %d\n", 806 printf("xbdback: failed to write %s/feature-flush-cache: %d\n",
807 xbusd->xbusd_path, err); 807 xbusd->xbusd_path, err);
808 goto abort; 808 goto abort;
809 } 809 }
810 err = xenbus_transaction_end(xbt, 0); 810 err = xenbus_transaction_end(xbt, 0);
811 if (err == EAGAIN) 811 if (err == EAGAIN)
812 goto again; 812 goto again;
813 if (err) { 813 if (err) {
814 printf("xbdback %s: can't end transaction: %d\n", 814 printf("xbdback %s: can't end transaction: %d\n",
815 xbusd->xbusd_path, err); 815 xbusd->xbusd_path, err);
816 } 816 }
817 err = xenbus_switch_state(xbusd, NULL, XenbusStateConnected); 817 err = xenbus_switch_state(xbusd, NULL, XenbusStateConnected);
818 if (err) { 818 if (err) {
819 printf("xbdback %s: can't switch state: %d\n", 819 printf("xbdback %s: can't switch state: %d\n",
820 xbusd->xbusd_path, err); 820 xbusd->xbusd_path, err);
821 } 821 }
822 return; 822 return;
823abort: 823abort:
824 xenbus_transaction_end(xbt, 1); 824 xenbus_transaction_end(xbt, 1);
825} 825}
826 826
827/* 827/*
828 * Used by a xbdi thread to signal that it is now disconnected. 828 * Used by a xbdi thread to signal that it is now disconnected.
829 */ 829 */
830static void 830static void
831xbdback_finish_disconnect(struct xbdback_instance *xbdi) 831xbdback_finish_disconnect(struct xbdback_instance *xbdi)
832{ 832{
833 KASSERT(mutex_owned(&xbdi->xbdi_lock)); 833 KASSERT(mutex_owned(&xbdi->xbdi_lock));
834 KASSERT(xbdi->xbdi_status == DISCONNECTING); 834 KASSERT(xbdi->xbdi_status == DISCONNECTING);
835 835
836 xbdi->xbdi_status = DISCONNECTED; 836 xbdi->xbdi_status = DISCONNECTED;
837 837
838 cv_signal(&xbdi->xbdi_cv); 838 cv_signal(&xbdi->xbdi_cv);
839} 839}
840 840
841static bool 841static bool
842xbdif_lookup(domid_t dom , uint32_t handle) 842xbdif_lookup(domid_t dom , uint32_t handle)
843{ 843{
844 struct xbdback_instance *xbdi; 844 struct xbdback_instance *xbdi;
845 bool found = false; 845 bool found = false;
846 846
847 mutex_enter(&xbdback_lock); 847 mutex_enter(&xbdback_lock);
848 SLIST_FOREACH(xbdi, &xbdback_instances, next) { 848 SLIST_FOREACH(xbdi, &xbdback_instances, next) {
849 if (xbdi->xbdi_domid == dom && xbdi->xbdi_handle == handle) { 849 if (xbdi->xbdi_domid == dom && xbdi->xbdi_handle == handle) {
850 found = true; 850 found = true;
851 break; 851 break;
852 } 852 }
853 } 853 }
854 mutex_exit(&xbdback_lock); 854 mutex_exit(&xbdback_lock);
855 855
856 return found; 856 return found;
857} 857}
858 858
859static int 859static int
860xbdback_evthandler(void *arg) 860xbdback_evthandler(void *arg)
861{ 861{
862 struct xbdback_instance *xbdi = arg; 862 struct xbdback_instance *xbdi = arg;
863 863
864 XENPRINTF(("xbdback_evthandler domain %d: cont %p\n", 864 XENPRINTF(("xbdback_evthandler domain %d: cont %p\n",
865 xbdi->xbdi_domid, xbdi->xbdi_cont)); 865 xbdi->xbdi_domid, xbdi->xbdi_cont));
866 866
867 xbdback_wakeup_thread(xbdi); 867 xbdback_wakeup_thread(xbdi);
868 868
869 return 1; 869 return 1;
870} 870}
871 871
872/* 872/*
873 * Main thread routine for one xbdback instance. Woken up by 873 * Main thread routine for one xbdback instance. Woken up by
874 * xbdback_evthandler when a domain has I/O work scheduled in a I/O ring. 874 * xbdback_evthandler when a domain has I/O work scheduled in a I/O ring.
875 */ 875 */
876static void 876static void
877xbdback_thread(void *arg) 877xbdback_thread(void *arg)
878{ 878{
879 struct xbdback_instance *xbdi = arg; 879 struct xbdback_instance *xbdi = arg;
880 880
881 for (;;) { 881 for (;;) {
882 mutex_enter(&xbdi->xbdi_lock); 882 mutex_enter(&xbdi->xbdi_lock);
883 switch (xbdi->xbdi_status) { 883 switch (xbdi->xbdi_status) {
884 case WAITING: 884 case WAITING:
885 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock); 885 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock);
886 mutex_exit(&xbdi->xbdi_lock); 886 mutex_exit(&xbdi->xbdi_lock);
887 break; 887 break;
888 case RUN: 888 case RUN:
889 xbdi->xbdi_status = WAITING; /* reset state */ 889 xbdi->xbdi_status = WAITING; /* reset state */
890 mutex_exit(&xbdi->xbdi_lock); 890 mutex_exit(&xbdi->xbdi_lock);
891 891
892 if (xbdi->xbdi_cont == NULL) { 892 if (xbdi->xbdi_cont == NULL) {
893 xbdi->xbdi_cont = xbdback_co_main; 893 xbdi->xbdi_cont = xbdback_co_main;
894 } 894 }
895 895
896 xbdback_trampoline(xbdi, xbdi); 896 xbdback_trampoline(xbdi, xbdi);
897 break; 897 break;
898 case DISCONNECTING: 898 case DISCONNECTING:
899 if (xbdi->xbdi_pendingreqs > 0) { 899 if (xbdi->xbdi_pendingreqs > 0) {
900 /* there are pending I/Os. Wait for them. */ 900 /* there are pending I/Os. Wait for them. */
901 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock); 901 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock);
902 mutex_exit(&xbdi->xbdi_lock); 902 mutex_exit(&xbdi->xbdi_lock);
903 break; 903 break;
904 } 904 }
905  905
906 /* All I/Os should have been processed by now, 906 /* All I/Os should have been processed by now,
907 * xbdi_refcnt should drop to 0 */ 907 * xbdi_refcnt should drop to 0 */
908 xbdi_put(xbdi); 908 xbdi_put(xbdi);
909 KASSERT(xbdi->xbdi_refcnt == 0); 909 KASSERT(xbdi->xbdi_refcnt == 0);
910 mutex_exit(&xbdi->xbdi_lock); 910 mutex_exit(&xbdi->xbdi_lock);
911 kthread_exit(0); 911 kthread_exit(0);
912 break; 912 break;
913 default: 913 default:
914 panic("%s: invalid state %d", 914 panic("%s: invalid state %d",
915 xbdi->xbdi_name, xbdi->xbdi_status); 915 xbdi->xbdi_name, xbdi->xbdi_status);
916 } 916 }
917 } 917 }
918} 918}
919 919
920static void * 920static void *
921xbdback_co_main(struct xbdback_instance *xbdi, void *obj) 921xbdback_co_main(struct xbdback_instance *xbdi, void *obj)
922{ 922{
923 (void)obj; 923 (void)obj;
924 924
925 xbdi->xbdi_req_prod = xbdi->xbdi_ring.ring_n.sring->req_prod; 925 xbdi->xbdi_req_prod = xbdi->xbdi_ring.ring_n.sring->req_prod;
926 xen_rmb(); /* ensure we see all requests up to req_prod */ 926 xen_rmb(); /* ensure we see all requests up to req_prod */
927 /* 927 /*
928 * note that we'll eventually get a full ring of request. 928 * note that we'll eventually get a full ring of request.
929 * in this case, MASK_BLKIF_IDX(req_cons) == MASK_BLKIF_IDX(req_prod) 929 * in this case, MASK_BLKIF_IDX(req_cons) == MASK_BLKIF_IDX(req_prod)
930 */ 930 */
931 xbdi->xbdi_cont = xbdback_co_main_loop; 931 xbdi->xbdi_cont = xbdback_co_main_loop;
932 return xbdi; 932 return xbdi;
933} 933}
934 934
935/* 935/*
936 * Fetch a blkif request from the ring, and pass control to the appropriate 936 * Fetch a blkif request from the ring, and pass control to the appropriate
937 * continuation. 937 * continuation.
938 * If someone asked for disconnection, do not fetch any more request from 938 * If someone asked for disconnection, do not fetch any more request from
939 * the ring. 939 * the ring.
940 */ 940 */
941static void * 941static void *
942xbdback_co_main_loop(struct xbdback_instance *xbdi, void *obj)  942xbdback_co_main_loop(struct xbdback_instance *xbdi, void *obj)
943{ 943{
944 blkif_request_t *req; 944 blkif_request_t *req;
945 blkif_x86_32_request_t *req32; 945 blkif_x86_32_request_t *req32;
946 blkif_x86_64_request_t *req64; 946 blkif_x86_64_request_t *req64;
947 947
948 (void)obj; 948 (void)obj;
949 req = &xbdi->xbdi_xen_req; 949 req = &xbdi->xbdi_xen_req;
950 if (xbdi->xbdi_ring.ring_n.req_cons != xbdi->xbdi_req_prod) { 950 if (xbdi->xbdi_ring.ring_n.req_cons != xbdi->xbdi_req_prod) {
951 switch(xbdi->xbdi_proto) { 951 switch(xbdi->xbdi_proto) {
952 case XBDIP_NATIVE: 952 case XBDIP_NATIVE:
953 memcpy(req, RING_GET_REQUEST(&xbdi->xbdi_ring.ring_n, 953 memcpy(req, RING_GET_REQUEST(&xbdi->xbdi_ring.ring_n,
954 xbdi->xbdi_ring.ring_n.req_cons), 954 xbdi->xbdi_ring.ring_n.req_cons),
955 sizeof(blkif_request_t)); 955 sizeof(blkif_request_t));
956 break; 956 break;
957 case XBDIP_32: 957 case XBDIP_32:
958 req32 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_32, 958 req32 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_32,
959 xbdi->xbdi_ring.ring_n.req_cons); 959 xbdi->xbdi_ring.ring_n.req_cons);
960 req->operation = req32->operation; 960 req->operation = req32->operation;
961 req->nr_segments = req32->nr_segments; 961 req->nr_segments = req32->nr_segments;
962 req->handle = req32->handle; 962 req->handle = req32->handle;
963 req->id = req32->id; 963 req->id = req32->id;
964 req->sector_number = req32->sector_number; 964 req->sector_number = req32->sector_number;
965 break; 965 break;
966  966
967 case XBDIP_64: 967 case XBDIP_64:
968 req64 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_64, 968 req64 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_64,
969 xbdi->xbdi_ring.ring_n.req_cons); 969 xbdi->xbdi_ring.ring_n.req_cons);
970 req->operation = req64->operation; 970 req->operation = req64->operation;
971 req->nr_segments = req64->nr_segments; 971 req->nr_segments = req64->nr_segments;
972 req->handle = req64->handle; 972 req->handle = req64->handle;
973 req->id = req64->id; 973 req->id = req64->id;
974 req->sector_number = req64->sector_number; 974 req->sector_number = req64->sector_number;
975 break; 975 break;
976 } 976 }
977 __insn_barrier(); 977 __insn_barrier();
978 XENPRINTF(("xbdback op %d req_cons 0x%x req_prod 0x%x " 978 XENPRINTF(("xbdback op %d req_cons 0x%x req_prod 0x%x "
979 "resp_prod 0x%x id %" PRIu64 "\n", req->operation, 979 "resp_prod 0x%x id %" PRIu64 "\n", req->operation,
980 xbdi->xbdi_ring.ring_n.req_cons, 980 xbdi->xbdi_ring.ring_n.req_cons,
981 xbdi->xbdi_req_prod, 981 xbdi->xbdi_req_prod,
982 xbdi->xbdi_ring.ring_n.rsp_prod_pvt, 982 xbdi->xbdi_ring.ring_n.rsp_prod_pvt,
983 req->id)); 983 req->id));
984 switch(req->operation) { 984 switch(req->operation) {
985 case BLKIF_OP_READ: 985 case BLKIF_OP_READ:
986 case BLKIF_OP_WRITE: 986 case BLKIF_OP_WRITE:
987 xbdi->xbdi_cont = xbdback_co_io; 987 xbdi->xbdi_cont = xbdback_co_io;
988 break; 988 break;
989 case BLKIF_OP_FLUSH_DISKCACHE: 989 case BLKIF_OP_FLUSH_DISKCACHE:
990 xbdi_get(xbdi); 990 xbdi_get(xbdi);
991 xbdi->xbdi_cont = xbdback_co_cache_flush; 991 xbdi->xbdi_cont = xbdback_co_cache_flush;
992 break; 992 break;
993 default: 993 default:
994 if (ratecheck(&xbdi->xbdi_lasterr_time, 994 if (ratecheck(&xbdi->xbdi_lasterr_time,
995 &xbdback_err_intvl)) { 995 &xbdback_err_intvl)) {
996 printf("%s: unknown operation %d\n", 996 printf("%s: unknown operation %d\n",
997 xbdi->xbdi_name, req->operation); 997 xbdi->xbdi_name, req->operation);
998 } 998 }
999 xbdback_send_reply(xbdi, req->id, req->operation, 999 xbdback_send_reply(xbdi, req->id, req->operation,
1000 BLKIF_RSP_ERROR); 1000 BLKIF_RSP_ERROR);
1001 xbdi->xbdi_cont = xbdback_co_main_incr; 1001 xbdi->xbdi_cont = xbdback_co_main_incr;
1002 break; 1002 break;
1003 } 1003 }
1004 } else { 1004 } else {
1005 KASSERT(xbdi->xbdi_io == NULL); 1005 KASSERT(xbdi->xbdi_io == NULL);
1006 xbdi->xbdi_cont = xbdback_co_main_done2; 1006 xbdi->xbdi_cont = xbdback_co_main_done2;
1007 } 1007 }
1008 return xbdi; 1008 return xbdi;
1009} 1009}
1010 1010
1011/* 1011/*
1012 * Increment consumer index and move on to the next request. In case 1012 * Increment consumer index and move on to the next request. In case
1013 * we want to disconnect, leave continuation now. 1013 * we want to disconnect, leave continuation now.
1014 */ 1014 */
1015static void * 1015static void *
1016xbdback_co_main_incr(struct xbdback_instance *xbdi, void *obj) 1016xbdback_co_main_incr(struct xbdback_instance *xbdi, void *obj)
1017{ 1017{
1018 (void)obj; 1018 (void)obj;
1019 blkif_back_ring_t *ring = &xbdi->xbdi_ring.ring_n; 1019 blkif_back_ring_t *ring = &xbdi->xbdi_ring.ring_n;
1020 1020
1021 ring->req_cons++; 1021 ring->req_cons++;
1022 1022
1023 /* 1023 /*
1024 * Do not bother with locking here when checking for xbdi_status: if 1024 * Do not bother with locking here when checking for xbdi_status: if
1025 * we get a transient state, we will get the right value at 1025 * we get a transient state, we will get the right value at
1026 * the next increment. 1026 * the next increment.
1027 */ 1027 */
1028 if (xbdi->xbdi_status == DISCONNECTING) 1028 if (xbdi->xbdi_status == DISCONNECTING)
1029 xbdi->xbdi_cont = NULL; 1029 xbdi->xbdi_cont = NULL;
1030 else 1030 else
1031 xbdi->xbdi_cont = xbdback_co_main_loop; 1031 xbdi->xbdi_cont = xbdback_co_main_loop;
1032 1032
1033 /* 1033 /*
1034 * Each time the thread processes a full ring of requests, give 1034 * Each time the thread processes a full ring of requests, give
1035 * a chance to other threads to process I/Os too 1035 * a chance to other threads to process I/Os too
1036 */ 1036 */
1037 if ((ring->req_cons % BLKIF_RING_SIZE) == 0) 1037 if ((ring->req_cons % BLKIF_RING_SIZE) == 0)
1038 yield(); 1038 yield();
1039 1039
1040 return xbdi; 1040 return xbdi;
1041} 1041}
1042 1042
1043/* 1043/*
1044 * Check for requests in the instance's ring. In case there are, start again 1044 * Check for requests in the instance's ring. In case there are, start again
1045 * from the beginning. If not, stall. 1045 * from the beginning. If not, stall.
1046 */ 1046 */
1047static void * 1047static void *
1048xbdback_co_main_done2(struct xbdback_instance *xbdi, void *obj) 1048xbdback_co_main_done2(struct xbdback_instance *xbdi, void *obj)
1049{ 1049{
1050 int work_to_do; 1050 int work_to_do;
1051 1051
1052 KASSERT(xbdi->xbdio_io == NULL); 
1053 RING_FINAL_CHECK_FOR_REQUESTS(&xbdi->xbdi_ring.ring_n, work_to_do); 1052 RING_FINAL_CHECK_FOR_REQUESTS(&xbdi->xbdi_ring.ring_n, work_to_do);
1054 if (work_to_do) 1053 if (work_to_do)
1055 xbdi->xbdi_cont = xbdback_co_main; 1054 xbdi->xbdi_cont = xbdback_co_main;
1056 else 1055 else
1057 xbdi->xbdi_cont = NULL; 1056 xbdi->xbdi_cont = NULL;
1058 1057
1059 return xbdi; 1058 return xbdi;
1060} 1059}
1061 1060
1062/* 1061/*
1063 * Frontend requested a cache flush operation. 1062 * Frontend requested a cache flush operation.
1064 */ 1063 */
1065static void * 1064static void *
1066xbdback_co_cache_flush(struct xbdback_instance *xbdi, void *obj __unused) 1065xbdback_co_cache_flush(struct xbdback_instance *xbdi, void *obj __unused)
1067{ 1066{
1068 if (xbdi->xbdi_pendingreqs > 0) { 1067 if (xbdi->xbdi_pendingreqs > 0) {
1069 /* 1068 /*
1070 * There are pending requests. 1069 * There are pending requests.
1071 * Event or iodone() will restart processing 1070 * Event or iodone() will restart processing
1072 */ 1071 */
1073 xbdi->xbdi_cont = NULL; 1072 xbdi->xbdi_cont = NULL;
1074 xbdi_put(xbdi); 1073 xbdi_put(xbdi);
1075 return NULL; 1074 return NULL;
1076 } 1075 }
1077 xbdi->xbdi_cont = xbdback_co_cache_doflush; 1076 xbdi->xbdi_cont = xbdback_co_cache_doflush;
1078 return xbdback_pool_get(&xbdback_io_pool, xbdi); 1077 return xbdback_pool_get(&xbdback_io_pool, xbdi);
1079} 1078}
1080 1079
1081/* Start the flush work */ 1080/* Start the flush work */
1082static void * 1081static void *
1083xbdback_co_cache_doflush(struct xbdback_instance *xbdi, void *obj) 1082xbdback_co_cache_doflush(struct xbdback_instance *xbdi, void *obj)
1084{ 1083{
1085 struct xbdback_io *xbd_io; 1084 struct xbdback_io *xbd_io;
1086 1085
1087 XENPRINTF(("xbdback_co_cache_doflush %p %p\n", xbdi, obj)); 1086 XENPRINTF(("xbdback_co_cache_doflush %p %p\n", xbdi, obj));
1088 xbd_io = xbdi->xbdi_io = obj; 1087 xbd_io = xbdi->xbdi_io = obj;
1089 xbd_io->xio_xbdi = xbdi; 1088 xbd_io->xio_xbdi = xbdi;
1090 xbd_io->xio_operation = xbdi->xbdi_xen_req.operation; 1089 xbd_io->xio_operation = xbdi->xbdi_xen_req.operation;
1091 xbd_io->xio_id = xbdi->xbdi_xen_req.id; 1090 xbd_io->xio_id = xbdi->xbdi_xen_req.id;
1092 xbdi->xbdi_cont = xbdback_co_do_io; 1091 xbdi->xbdi_cont = xbdback_co_do_io;
1093 return xbdi; 1092 return xbdi;
1094} 1093}
1095 1094
1096/* 1095/*
1097 * A read or write I/O request must be processed. Do some checks first, 1096 * A read or write I/O request must be processed. Do some checks first,
1098 * then get the segment information directly from the ring request. 1097 * then get the segment information directly from the ring request.
1099 */ 1098 */
1100static void * 1099static void *
1101xbdback_co_io(struct xbdback_instance *xbdi, void *obj) 1100xbdback_co_io(struct xbdback_instance *xbdi, void *obj)
1102{  1101{
1103 int i, error; 1102 int i, error;
1104 blkif_request_t *req; 1103 blkif_request_t *req;
1105 blkif_x86_32_request_t *req32; 1104 blkif_x86_32_request_t *req32;
1106 blkif_x86_64_request_t *req64; 1105 blkif_x86_64_request_t *req64;
1107 1106
1108 (void)obj; 1107 (void)obj;
1109 1108
1110 /* some sanity checks */ 1109 /* some sanity checks */
1111 req = &xbdi->xbdi_xen_req; 1110 req = &xbdi->xbdi_xen_req;
1112 if (req->nr_segments < 1 || 1111 if (req->nr_segments < 1 ||
1113 req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { 1112 req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST) {
1114 if (ratecheck(&xbdi->xbdi_lasterr_time, 1113 if (ratecheck(&xbdi->xbdi_lasterr_time,
1115 &xbdback_err_intvl)) { 1114 &xbdback_err_intvl)) {
1116 printf("%s: invalid number of segments: %d\n", 1115 printf("%s: invalid number of segments: %d\n",
1117 xbdi->xbdi_name, 1116 xbdi->xbdi_name,
1118 xbdi->xbdi_xen_req.nr_segments); 1117 xbdi->xbdi_xen_req.nr_segments);
1119 } 1118 }
1120 error = EINVAL; 1119 error = EINVAL;
1121 goto end; 1120 goto end;
1122 } 1121 }
1123 1122
1124 KASSERT(req->operation == BLKIF_OP_READ || 1123 KASSERT(req->operation == BLKIF_OP_READ ||
1125 req->operation == BLKIF_OP_WRITE); 1124 req->operation == BLKIF_OP_WRITE);
1126 if (req->operation == BLKIF_OP_WRITE) { 1125 if (req->operation == BLKIF_OP_WRITE) {
1127 if (xbdi->xbdi_ro) { 1126 if (xbdi->xbdi_ro) {
1128 error = EROFS; 1127 error = EROFS;
1129 goto end; 1128 goto end;
1130 } 1129 }
1131 } 1130 }
1132 1131
1133 /* copy request segments */ 1132 /* copy request segments */
1134 switch(xbdi->xbdi_proto) { 1133 switch(xbdi->xbdi_proto) {
1135 case XBDIP_NATIVE: 1134 case XBDIP_NATIVE:
1136 /* already copied in xbdback_co_main_loop */ 1135 /* already copied in xbdback_co_main_loop */
1137 break; 1136 break;
1138 case XBDIP_32: 1137 case XBDIP_32:
1139 req32 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_32, 1138 req32 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_32,
1140 xbdi->xbdi_ring.ring_n.req_cons); 1139 xbdi->xbdi_ring.ring_n.req_cons);
1141 for (i = 0; i < req->nr_segments; i++) 1140 for (i = 0; i < req->nr_segments; i++)
1142 req->seg[i] = req32->seg[i]; 1141 req->seg[i] = req32->seg[i];
1143 break; 1142 break;
1144 case XBDIP_64: 1143 case XBDIP_64:
1145 req64 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_64, 1144 req64 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_64,
1146 xbdi->xbdi_ring.ring_n.req_cons); 1145 xbdi->xbdi_ring.ring_n.req_cons);
1147 for (i = 0; i < req->nr_segments; i++) 1146 for (i = 0; i < req->nr_segments; i++)
1148 req->seg[i] = req64->seg[i]; 1147 req->seg[i] = req64->seg[i];
1149 break; 1148 break;
1150 } 1149 }
1151 1150
1152 KASSERT(xbdi->xbdi_io == NULL); 1151 KASSERT(xbdi->xbdi_io == NULL);
1153 xbdi->xbdi_cont = xbdback_co_io_gotio; 1152 xbdi->xbdi_cont = xbdback_co_io_gotio;
1154 return xbdback_pool_get(&xbdback_io_pool, xbdi); 1153 return xbdback_pool_get(&xbdback_io_pool, xbdi);
1155 1154
1156 end: 1155 end:
1157 xbdback_send_reply(xbdi, xbdi->xbdi_xen_req.id, 1156 xbdback_send_reply(xbdi, xbdi->xbdi_xen_req.id,
1158 xbdi->xbdi_xen_req.operation, 1157 xbdi->xbdi_xen_req.operation,
1159 (error == EROFS) ? BLKIF_RSP_EOPNOTSUPP : BLKIF_RSP_ERROR); 1158 (error == EROFS) ? BLKIF_RSP_EOPNOTSUPP : BLKIF_RSP_ERROR);
1160 xbdi->xbdi_cont = xbdback_co_main_incr; 1159 xbdi->xbdi_cont = xbdback_co_main_incr;
1161 return xbdi; 1160 return xbdi;
1162} 1161}
1163 1162
1164/* Prepare an I/O buffer for a xbdback instance */ 1163/* Prepare an I/O buffer for a xbdback instance */
1165static void * 1164static void *
1166xbdback_co_io_gotio(struct xbdback_instance *xbdi, void *obj) 1165xbdback_co_io_gotio(struct xbdback_instance *xbdi, void *obj)
1167{ 1166{
1168 struct xbdback_io *xbd_io; 1167 struct xbdback_io *xbd_io;
1169 int buf_flags; 1168 int buf_flags;
1170 size_t bcount; 1169 size_t bcount;
1171 blkif_request_t *req; 1170 blkif_request_t *req;
1172 1171
1173 xbdi_get(xbdi); 1172 xbdi_get(xbdi);
1174 atomic_inc_uint(&xbdi->xbdi_pendingreqs); 1173 atomic_inc_uint(&xbdi->xbdi_pendingreqs);
1175  1174
1176 req = &xbdi->xbdi_xen_req; 1175 req = &xbdi->xbdi_xen_req;
1177 xbd_io = xbdi->xbdi_io = obj; 1176 xbd_io = xbdi->xbdi_io = obj;
1178 memset(xbd_io, 0, sizeof(*xbd_io)); 1177 memset(xbd_io, 0, sizeof(*xbd_io));
1179 buf_init(&xbd_io->xio_buf); 1178 buf_init(&xbd_io->xio_buf);
1180 xbd_io->xio_xbdi = xbdi; 1179 xbd_io->xio_xbdi = xbdi;
1181 xbd_io->xio_operation = req->operation; 1180 xbd_io->xio_operation = req->operation;
1182 xbd_io->xio_id = req->id; 1181 xbd_io->xio_id = req->id;
1183 1182
1184 /* Process segments */ 1183 /* Process segments */
1185 bcount = 0; 1184 bcount = 0;
1186 for (int i = 0; i < req->nr_segments; i++) { 1185 for (int i = 0; i < req->nr_segments; i++) {
1187 xbd_io->xio_gref[i] = req->seg[i].gref; 1186 xbd_io->xio_gref[i] = req->seg[i].gref;
1188 bcount += (req->seg[i].last_sect - req->seg[i].first_sect + 1) 1187 bcount += (req->seg[i].last_sect - req->seg[i].first_sect + 1)
1189 * VBD_BSIZE; 1188 * VBD_BSIZE;
1190 } 1189 }
1191 KASSERT(bcount <= MAXPHYS); 1190 KASSERT(bcount <= MAXPHYS);
1192 xbd_io->xio_nrma = req->nr_segments; 1191 xbd_io->xio_nrma = req->nr_segments;
1193 1192
1194 xbd_io->xio_start_offset = req->seg[0].first_sect * VBD_BSIZE; 1193 xbd_io->xio_start_offset = req->seg[0].first_sect * VBD_BSIZE;
1195 KASSERT(xbd_io->xio_start_offset < PAGE_SIZE); 1194 KASSERT(xbd_io->xio_start_offset < PAGE_SIZE);
1196 KASSERT(bcount + xbd_io->xio_start_offset < VBD_VA_SIZE); 1195 KASSERT(bcount + xbd_io->xio_start_offset < VBD_VA_SIZE);
1197 1196
1198 if (xbdi->xbdi_xen_req.operation == BLKIF_OP_WRITE) { 1197 if (xbdi->xbdi_xen_req.operation == BLKIF_OP_WRITE) {
1199 buf_flags = B_WRITE; 1198 buf_flags = B_WRITE;
1200 } else { 1199 } else {
1201 buf_flags = B_READ; 1200 buf_flags = B_READ;
1202 } 1201 }
1203 1202
1204 xbd_io->xio_buf.b_flags = buf_flags; 1203 xbd_io->xio_buf.b_flags = buf_flags;
1205 xbd_io->xio_buf.b_cflags = 0; 1204 xbd_io->xio_buf.b_cflags = 0;
1206 xbd_io->xio_buf.b_oflags = 0; 1205 xbd_io->xio_buf.b_oflags = 0;
1207 xbd_io->xio_buf.b_iodone = xbdback_iodone; 1206 xbd_io->xio_buf.b_iodone = xbdback_iodone;
1208 xbd_io->xio_buf.b_proc = NULL; 1207 xbd_io->xio_buf.b_proc = NULL;
1209 xbd_io->xio_buf.b_vp = xbdi->xbdi_vp; 1208 xbd_io->xio_buf.b_vp = xbdi->xbdi_vp;
1210 xbd_io->xio_buf.b_objlock = xbdi->xbdi_vp->v_interlock; 1209 xbd_io->xio_buf.b_objlock = xbdi->xbdi_vp->v_interlock;
1211 xbd_io->xio_buf.b_dev = xbdi->xbdi_dev; 1210 xbd_io->xio_buf.b_dev = xbdi->xbdi_dev;
1212 xbd_io->xio_buf.b_blkno = req->sector_number; 1211 xbd_io->xio_buf.b_blkno = req->sector_number;
1213 xbd_io->xio_buf.b_bcount = bcount; 1212 xbd_io->xio_buf.b_bcount = bcount;
1214 xbd_io->xio_buf.b_data = NULL; 1213 xbd_io->xio_buf.b_data = NULL;
1215 xbd_io->xio_buf.b_private = xbd_io; 1214 xbd_io->xio_buf.b_private = xbd_io;
1216 1215
1217 xbdi->xbdi_cont = xbdback_co_do_io; 1216 xbdi->xbdi_cont = xbdback_co_do_io;
1218 return xbdback_map_shm(xbdi->xbdi_io); 1217 return xbdback_map_shm(xbdi->xbdi_io);
1219} 1218}
1220 1219
1221static void 1220static void
1222xbdback_io_error(struct xbdback_io *xbd_io, int error) 1221xbdback_io_error(struct xbdback_io *xbd_io, int error)
1223{ 1222{
1224 xbd_io->xio_buf.b_error = error; 1223 xbd_io->xio_buf.b_error = error;
1225 xbdback_iodone(&xbd_io->xio_buf); 1224 xbdback_iodone(&xbd_io->xio_buf);
1226} 1225}
1227 1226
1228/* 1227/*
1229 * Main xbdback I/O routine. It can either perform a flush operation or 1228 * Main xbdback I/O routine. It can either perform a flush operation or
1230 * schedule a read/write operation. 1229 * schedule a read/write operation.
1231 */ 1230 */
1232static void * 1231static void *
1233xbdback_co_do_io(struct xbdback_instance *xbdi, void *obj) 1232xbdback_co_do_io(struct xbdback_instance *xbdi, void *obj)
1234{ 1233{
1235 struct xbdback_io *xbd_io = xbdi->xbdi_io; 1234 struct xbdback_io *xbd_io = xbdi->xbdi_io;
1236 int nsegs __diagused; 
1237 1235
1238 switch (xbd_io->xio_operation) { 1236 switch (xbd_io->xio_operation) {
1239 case BLKIF_OP_FLUSH_DISKCACHE: 1237 case BLKIF_OP_FLUSH_DISKCACHE:
1240 { 1238 {
1241 int error; 1239 int error;
1242 int force = 1; 1240 int force = 1;
1243 1241
1244 error = VOP_IOCTL(xbdi->xbdi_vp, DIOCCACHESYNC, &force, FWRITE, 1242 error = VOP_IOCTL(xbdi->xbdi_vp, DIOCCACHESYNC, &force, FWRITE,
1245 kauth_cred_get()); 1243 kauth_cred_get());
1246 if (error) { 1244 if (error) {
1247 aprint_error("xbdback %s: DIOCCACHESYNC returned %d\n", 1245 aprint_error("xbdback %s: DIOCCACHESYNC returned %d\n",
1248 xbdi->xbdi_xbusd->xbusd_path, error); 1246 xbdi->xbdi_xbusd->xbusd_path, error);
1249 if (error == EOPNOTSUPP || error == ENOTTY) 1247 if (error == EOPNOTSUPP || error == ENOTTY)
1250 error = BLKIF_RSP_EOPNOTSUPP; 1248 error = BLKIF_RSP_EOPNOTSUPP;
1251 else 1249 else
1252 error = BLKIF_RSP_ERROR; 1250 error = BLKIF_RSP_ERROR;
1253 } else 1251 } else
1254 error = BLKIF_RSP_OKAY; 1252 error = BLKIF_RSP_OKAY;
1255 xbdback_send_reply(xbdi, xbd_io->xio_id, 1253 xbdback_send_reply(xbdi, xbd_io->xio_id,
1256 xbd_io->xio_operation, error); 1254 xbd_io->xio_operation, error);
1257 xbdback_pool_put(&xbdback_io_pool, xbd_io); 1255 xbdback_pool_put(&xbdback_io_pool, xbd_io);
1258 xbdi_put(xbdi); 1256 xbdi_put(xbdi);
1259 xbdi->xbdi_io = NULL; 1257 xbdi->xbdi_io = NULL;
1260 xbdi->xbdi_cont = xbdback_co_main_incr; 1258 xbdi->xbdi_cont = xbdback_co_main_incr;
1261 return xbdi; 1259 return xbdi;
1262 } 1260 }
1263 case BLKIF_OP_READ: 1261 case BLKIF_OP_READ:
1264 case BLKIF_OP_WRITE: 1262 case BLKIF_OP_WRITE:
1265 xbd_io->xio_buf.b_data = (void *) 1263 xbd_io->xio_buf.b_data = (void *)
1266 (xbd_io->xio_vaddr + xbd_io->xio_start_offset); 1264 (xbd_io->xio_vaddr + xbd_io->xio_start_offset);
1267 1265
1268 if ((xbd_io->xio_buf.b_flags & B_READ) == 0) { 1266 if ((xbd_io->xio_buf.b_flags & B_READ) == 0) {
1269 mutex_enter(xbd_io->xio_buf.b_vp->v_interlock); 1267 mutex_enter(xbd_io->xio_buf.b_vp->v_interlock);
1270 xbd_io->xio_buf.b_vp->v_numoutput++; 1268 xbd_io->xio_buf.b_vp->v_numoutput++;
1271 mutex_exit(xbd_io->xio_buf.b_vp->v_interlock); 1269 mutex_exit(xbd_io->xio_buf.b_vp->v_interlock);
1272 } 1270 }
1273 /* will call xbdback_iodone() asynchronously when done */ 1271 /* will call xbdback_iodone() asynchronously when done */
1274 bdev_strategy(&xbd_io->xio_buf); 1272 bdev_strategy(&xbd_io->xio_buf);
1275 xbdi->xbdi_io = NULL; 1273 xbdi->xbdi_io = NULL;
1276 xbdi->xbdi_cont = xbdback_co_main_incr; 1274 xbdi->xbdi_cont = xbdback_co_main_incr;
1277 return xbdi; 1275 return xbdi;
1278 default: 1276 default:
1279 /* Should never happen */ 1277 /* Should never happen */
1280 panic("xbdback_co_do_io: unsupported operation %d", 1278 panic("xbdback_co_do_io: unsupported operation %d",
1281 xbd_io->xio_operation); 1279 xbd_io->xio_operation);
1282 } 1280 }
1283} 1281}
1284 1282
1285/* 1283/*
1286 * Called from softint(9) context when an I/O is done: for each request, send 1284 * Called from softint(9) context when an I/O is done: for each request, send
1287 * back the associated reply to the domain. 1285 * back the associated reply to the domain.
1288 * 1286 *
1289 * This gets reused by xbdback_io_error to report errors from other sources. 1287 * This gets reused by xbdback_io_error to report errors from other sources.
1290 */ 1288 */
1291static void 1289static void
1292xbdback_iodone(struct buf *bp) 1290xbdback_iodone(struct buf *bp)
1293{ 1291{
1294 struct xbdback_io *xbd_io; 1292 struct xbdback_io *xbd_io;
1295 struct xbdback_instance *xbdi; 1293 struct xbdback_instance *xbdi;
1296 int status; 1294 int status;
1297 1295
1298 KERNEL_LOCK(1, NULL); /* XXXSMP */ 1296 KERNEL_LOCK(1, NULL); /* XXXSMP */
1299 1297
1300 xbd_io = bp->b_private; 1298 xbd_io = bp->b_private;
1301 xbdi = xbd_io->xio_xbdi; 1299 xbdi = xbd_io->xio_xbdi;
1302 1300
1303 XENPRINTF(("xbdback_io domain %d: iodone ptr 0x%lx\n", 1301 XENPRINTF(("xbdback_io domain %d: iodone ptr 0x%lx\n",
1304 xbdi->xbdi_domid, (long)xbd_io)); 1302 xbdi->xbdi_domid, (long)xbd_io));
1305 1303
1306 KASSERT(bp->b_error != 0 || xbd_io->xio_xv != NULL); 1304 KASSERT(bp->b_error != 0 || xbd_io->xio_xv != NULL);
1307 if (xbd_io->xio_xv != NULL) 1305 if (xbd_io->xio_xv != NULL)
1308 xbdback_unmap_shm(xbd_io); 1306 xbdback_unmap_shm(xbd_io);
1309 1307
1310 if (bp->b_error != 0) { 1308 if (bp->b_error != 0) {
1311 printf("xbd IO domain %d: error %d\n", 1309 printf("xbd IO domain %d: error %d\n",
1312 xbdi->xbdi_domid, bp->b_error); 1310 xbdi->xbdi_domid, bp->b_error);
1313 status = BLKIF_RSP_ERROR; 1311 status = BLKIF_RSP_ERROR;
1314 } else 1312 } else
1315 status = BLKIF_RSP_OKAY; 1313 status = BLKIF_RSP_OKAY;
1316  1314
1317 xbdback_send_reply(xbdi, xbd_io->xio_id, xbd_io->xio_operation, status); 1315 xbdback_send_reply(xbdi, xbd_io->xio_id, xbd_io->xio_operation, status);
1318 1316
1319 xbdi_put(xbdi); 1317 xbdi_put(xbdi);
1320 atomic_dec_uint(&xbdi->xbdi_pendingreqs); 1318 atomic_dec_uint(&xbdi->xbdi_pendingreqs);
1321 buf_destroy(&xbd_io->xio_buf); 1319 buf_destroy(&xbd_io->xio_buf);
1322 xbdback_pool_put(&xbdback_io_pool, xbd_io); 1320 xbdback_pool_put(&xbdback_io_pool, xbd_io);
1323 1321
1324 xbdback_wakeup_thread(xbdi); 1322 xbdback_wakeup_thread(xbdi);
1325 KERNEL_UNLOCK_ONE(NULL); /* XXXSMP */ 1323 KERNEL_UNLOCK_ONE(NULL); /* XXXSMP */
1326} 1324}
1327 1325
1328/* 1326/*
1329 * Wake up the per xbdback instance thread. 1327 * Wake up the per xbdback instance thread.
1330 */ 1328 */
1331static void 1329static void
1332xbdback_wakeup_thread(struct xbdback_instance *xbdi) 1330xbdback_wakeup_thread(struct xbdback_instance *xbdi)
1333{ 1331{
1334 1332
1335 mutex_enter(&xbdi->xbdi_lock); 1333 mutex_enter(&xbdi->xbdi_lock);
1336 /* only set RUN state when we are WAITING for work */ 1334 /* only set RUN state when we are WAITING for work */
1337 if (xbdi->xbdi_status == WAITING) 1335 if (xbdi->xbdi_status == WAITING)
1338 xbdi->xbdi_status = RUN; 1336 xbdi->xbdi_status = RUN;
1339 cv_broadcast(&xbdi->xbdi_cv); 1337 cv_broadcast(&xbdi->xbdi_cv);
1340 mutex_exit(&xbdi->xbdi_lock); 1338 mutex_exit(&xbdi->xbdi_lock);
1341} 1339}
1342 1340
1343/* 1341/*
1344 * called once a request has completed. Place the reply in the ring and 1342 * called once a request has completed. Place the reply in the ring and
1345 * notify the guest OS. 1343 * notify the guest OS.
1346 */ 1344 */
1347static void 1345static void
1348xbdback_send_reply(struct xbdback_instance *xbdi, uint64_t id, 1346xbdback_send_reply(struct xbdback_instance *xbdi, uint64_t id,
1349 int op, int status) 1347 int op, int status)
1350{ 1348{
1351 blkif_response_t *resp_n; 1349 blkif_response_t *resp_n;
1352 blkif_x86_32_response_t *resp32; 1350 blkif_x86_32_response_t *resp32;
1353 blkif_x86_64_response_t *resp64; 1351 blkif_x86_64_response_t *resp64;
1354 int notify; 1352 int notify;
1355 1353
1356 /* 1354 /*
1357 * The ring can be accessed by the xbdback thread, xbdback_iodone() 1355 * The ring can be accessed by the xbdback thread, xbdback_iodone()
1358 * handler, or any handler that triggered the shm callback. So 1356 * handler, or any handler that triggered the shm callback. So
1359 * protect ring access via the xbdi_lock mutex. 1357 * protect ring access via the xbdi_lock mutex.
1360 */ 1358 */
1361 mutex_enter(&xbdi->xbdi_lock); 1359 mutex_enter(&xbdi->xbdi_lock);
1362 switch (xbdi->xbdi_proto) { 1360 switch (xbdi->xbdi_proto) {
1363 case XBDIP_NATIVE: 1361 case XBDIP_NATIVE:
1364 resp_n = RING_GET_RESPONSE(&xbdi->xbdi_ring.ring_n, 1362 resp_n = RING_GET_RESPONSE(&xbdi->xbdi_ring.ring_n,
1365 xbdi->xbdi_ring.ring_n.rsp_prod_pvt); 1363 xbdi->xbdi_ring.ring_n.rsp_prod_pvt);
1366 resp_n->id = id; 1364 resp_n->id = id;
1367 resp_n->operation = op; 1365 resp_n->operation = op;
1368 resp_n->status = status; 1366 resp_n->status = status;
1369 break; 1367 break;
1370 case XBDIP_32: 1368 case XBDIP_32:
1371 resp32 = RING_GET_RESPONSE(&xbdi->xbdi_ring.ring_32, 1369 resp32 = RING_GET_RESPONSE(&xbdi->xbdi_ring.ring_32,
1372 xbdi->xbdi_ring.ring_n.rsp_prod_pvt); 1370 xbdi->xbdi_ring.ring_n.rsp_prod_pvt);
1373 resp32->id = id; 1371 resp32->id = id;
1374 resp32->operation = op; 1372 resp32->operation = op;
1375 resp32->status = status; 1373 resp32->status = status;
1376 break; 1374 break;
1377 case XBDIP_64: 1375 case XBDIP_64:
1378 resp64 = RING_GET_RESPONSE(&xbdi->xbdi_ring.ring_64, 1376 resp64 = RING_GET_RESPONSE(&xbdi->xbdi_ring.ring_64,
1379 xbdi->xbdi_ring.ring_n.rsp_prod_pvt); 1377 xbdi->xbdi_ring.ring_n.rsp_prod_pvt);
1380 resp64->id = id; 1378 resp64->id = id;
1381 resp64->operation = op; 1379 resp64->operation = op;
1382 resp64->status = status; 1380 resp64->status = status;
1383 break; 1381 break;
1384 } 1382 }
1385 xbdi->xbdi_ring.ring_n.rsp_prod_pvt++; 1383 xbdi->xbdi_ring.ring_n.rsp_prod_pvt++;
1386 RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&xbdi->xbdi_ring.ring_n, notify); 1384 RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&xbdi->xbdi_ring.ring_n, notify);
1387 mutex_exit(&xbdi->xbdi_lock); 1385 mutex_exit(&xbdi->xbdi_lock);
1388 1386
1389 if (notify) { 1387 if (notify) {
1390 XENPRINTF(("xbdback_send_reply notify %d\n", xbdi->xbdi_domid)); 1388 XENPRINTF(("xbdback_send_reply notify %d\n", xbdi->xbdi_domid));
1391 hypervisor_notify_via_evtchn(xbdi->xbdi_evtchn); 1389 hypervisor_notify_via_evtchn(xbdi->xbdi_evtchn);
1392 } 1390 }
1393} 1391}
1394 1392
1395/* 1393/*
1396 * Map multiple entries of an I/O request into backend's VA space. 1394 * Map multiple entries of an I/O request into backend's VA space.
1397 * The xbd_io->xio_gref array has to be filled out by the caller. 1395 * The xbd_io->xio_gref array has to be filled out by the caller.
1398 */ 1396 */
1399static void * 1397static void *
1400xbdback_map_shm(struct xbdback_io *xbd_io) 1398xbdback_map_shm(struct xbdback_io *xbd_io)
1401{ 1399{
1402 struct xbdback_instance *xbdi = xbd_io->xio_xbdi; 1400 struct xbdback_instance *xbdi = xbd_io->xio_xbdi;
1403 int error, s; 1401 int error, s;
1404 1402
1405#ifdef XENDEBUG_VBD 1403#ifdef XENDEBUG_VBD
1406 int i; 1404 int i;
1407 printf("xbdback_map_shm map grant "); 1405 printf("xbdback_map_shm map grant ");
1408 for (i = 0; i < xbd_io->xio_nrma; i++) { 1406 for (i = 0; i < xbd_io->xio_nrma; i++) {
1409 printf("%u ", (u_int)xbd_io->xio_gref[i]); 1407 printf("%u ", (u_int)xbd_io->xio_gref[i]);
1410 } 1408 }
1411#endif 1409#endif
1412 1410
1413 s = splvm(); /* XXXSMP */ 1411 s = splvm(); /* XXXSMP */
1414 xbd_io->xio_xv = SLIST_FIRST(&xbdi->xbdi_va_free); 1412 xbd_io->xio_xv = SLIST_FIRST(&xbdi->xbdi_va_free);
1415 KASSERT(xbd_io->xio_xv != NULL); 1413 KASSERT(xbd_io->xio_xv != NULL);
1416 SLIST_REMOVE_HEAD(&xbdi->xbdi_va_free, xv_next); 1414 SLIST_REMOVE_HEAD(&xbdi->xbdi_va_free, xv_next);
1417 xbd_io->xio_vaddr = xbd_io->xio_xv->xv_vaddr; 1415 xbd_io->xio_vaddr = xbd_io->xio_xv->xv_vaddr;
1418 splx(s); 1416 splx(s);
1419 1417
1420 error = xen_shm_map(xbd_io->xio_nrma, xbdi->xbdi_domid, 1418 error = xen_shm_map(xbd_io->xio_nrma, xbdi->xbdi_domid,
1421 xbd_io->xio_gref, xbd_io->xio_vaddr, xbd_io->xio_gh,  1419 xbd_io->xio_gref, xbd_io->xio_vaddr, xbd_io->xio_gh,
1422 (xbd_io->xio_operation == BLKIF_OP_WRITE) ? XSHM_RO : 0); 1420 (xbd_io->xio_operation == BLKIF_OP_WRITE) ? XSHM_RO : 0);
1423 1421
1424 switch(error) { 1422 switch(error) {
1425 case 0: 1423 case 0:
1426#ifdef XENDEBUG_VBD 1424#ifdef XENDEBUG_VBD
1427 printf("handle "); 1425 printf("handle ");
1428 for (i = 0; i < xbd_io->xio_nrma; i++) { 1426 for (i = 0; i < xbd_io->xio_nrma; i++) {
1429 printf("%u ", (u_int)xbd_io->xio_gh[i]); 1427 printf("%u ", (u_int)xbd_io->xio_gh[i]);
1430 } 1428 }
1431 printf("\n"); 1429 printf("\n");
1432#endif 1430#endif
1433 return xbdi; 1431 return xbdi;
1434 default: 1432 default:
1435 if (ratecheck(&xbdi->xbdi_lasterr_time, &xbdback_err_intvl)) { 1433 if (ratecheck(&xbdi->xbdi_lasterr_time, &xbdback_err_intvl)) {
1436 printf("xbdback_map_shm: xen_shm error %d ", error); 1434 printf("xbdback_map_shm: xen_shm error %d ", error);
1437 } 1435 }
1438 xbdback_io_error(xbdi->xbdi_io, error); 1436 xbdback_io_error(xbdi->xbdi_io, error);
1439 SLIST_INSERT_HEAD(&xbdi->xbdi_va_free, xbd_io->xio_xv, xv_next); 1437 SLIST_INSERT_HEAD(&xbdi->xbdi_va_free, xbd_io->xio_xv, xv_next);
1440 xbd_io->xio_xv = NULL; 1438 xbd_io->xio_xv = NULL;
1441 xbdi->xbdi_io = NULL; 1439 xbdi->xbdi_io = NULL;
1442 // do not retry 1440 // do not retry
1443 xbdi->xbdi_cont = xbdback_co_main_incr; 1441 xbdi->xbdi_cont = xbdback_co_main_incr;
1444 return xbdi; 1442 return xbdi;
1445 } 1443 }
1446} 1444}
1447 1445
1448/* unmap a request from our virtual address space (request is done) */ 1446/* unmap a request from our virtual address space (request is done) */
1449static void 1447static void
1450xbdback_unmap_shm(struct xbdback_io *xbd_io) 1448xbdback_unmap_shm(struct xbdback_io *xbd_io)
1451{ 1449{
1452 struct xbdback_instance *xbdi = xbd_io->xio_xbdi; 1450 struct xbdback_instance *xbdi = xbd_io->xio_xbdi;
1453 1451
1454#ifdef XENDEBUG_VBD 1452#ifdef XENDEBUG_VBD
1455 int i; 1453 int i;
1456 printf("xbdback_unmap_shm handle "); 1454 printf("xbdback_unmap_shm handle ");
1457 for (i = 0; i < xbd_io->xio_nrma; i++) { 1455 for (i = 0; i < xbd_io->xio_nrma; i++) {
1458 printf("%u ", (u_int)xbd_io->xio_gh[i]); 1456 printf("%u ", (u_int)xbd_io->xio_gh[i]);
1459 } 1457 }
1460 printf("\n"); 1458 printf("\n");
1461#endif 1459#endif
1462 1460
1463 KASSERT(xbd_io->xio_xv != NULL); 1461 KASSERT(xbd_io->xio_xv != NULL);
1464 xen_shm_unmap(xbd_io->xio_vaddr, xbd_io->xio_nrma, 1462 xen_shm_unmap(xbd_io->xio_vaddr, xbd_io->xio_nrma,
1465 xbd_io->xio_gh); 1463 xbd_io->xio_gh);
1466 SLIST_INSERT_HEAD(&xbdi->xbdi_va_free, xbd_io->xio_xv, xv_next); 1464 SLIST_INSERT_HEAD(&xbdi->xbdi_va_free, xbd_io->xio_xv, xv_next);
1467 xbd_io->xio_xv = NULL; 1465 xbd_io->xio_xv = NULL;
1468 xbd_io->xio_vaddr = -1; 1466 xbd_io->xio_vaddr = -1;
1469} 1467}
1470 1468
1471/* Obtain memory from a pool */ 1469/* Obtain memory from a pool */
1472static void * 1470static void *
1473xbdback_pool_get(struct pool_cache *pc, 1471xbdback_pool_get(struct pool_cache *pc,
1474 struct xbdback_instance *xbdi) 1472 struct xbdback_instance *xbdi)
1475{ 1473{
1476 return pool_cache_get(pc, PR_WAITOK); 1474 return pool_cache_get(pc, PR_WAITOK);
1477} 1475}
1478 1476
1479/* Restore memory to a pool */ 1477/* Restore memory to a pool */
1480static void 1478static void
1481xbdback_pool_put(struct pool_cache *pc, void *item) 1479xbdback_pool_put(struct pool_cache *pc, void *item)
1482{ 1480{
1483 pool_cache_put(pc, item); 1481 pool_cache_put(pc, item);
1484} 1482}
1485 1483
1486/* 1484/*
1487 * Trampoline routine. Calls continuations in a loop and only exits when 1485 * Trampoline routine. Calls continuations in a loop and only exits when
1488 * either the returned object or the next callback is NULL. 1486 * either the returned object or the next callback is NULL.
1489 */ 1487 */
1490static void 1488static void
1491xbdback_trampoline(struct xbdback_instance *xbdi, void *obj) 1489xbdback_trampoline(struct xbdback_instance *xbdi, void *obj)
1492{ 1490{
1493 xbdback_cont_t cont; 1491 xbdback_cont_t cont;
1494 1492
1495 while(obj != NULL && xbdi->xbdi_cont != NULL) { 1493 while(obj != NULL && xbdi->xbdi_cont != NULL) {
1496 cont = xbdi->xbdi_cont; 1494 cont = xbdi->xbdi_cont;
1497#ifdef DIAGNOSTIC 1495#ifdef DIAGNOSTIC
1498 xbdi->xbdi_cont = (xbdback_cont_t)0xDEADBEEF; 1496 xbdi->xbdi_cont = (xbdback_cont_t)0xDEADBEEF;
1499#endif 1497#endif
1500 obj = (*cont)(xbdi, obj); 1498 obj = (*cont)(xbdi, obj);
1501#ifdef DIAGNOSTIC 1499#ifdef DIAGNOSTIC
1502 if (xbdi->xbdi_cont == (xbdback_cont_t)0xDEADBEEF) { 1500 if (xbdi->xbdi_cont == (xbdback_cont_t)0xDEADBEEF) {
1503 printf("xbdback_trampoline: 0x%lx didn't set " 1501 printf("xbdback_trampoline: 0x%lx didn't set "
1504 "xbdi->xbdi_cont!\n", (long)cont); 1502 "xbdi->xbdi_cont!\n", (long)cont);
1505 panic("xbdback_trampoline: bad continuation"); 1503 panic("xbdback_trampoline: bad continuation");
1506 } 1504 }
1507#endif 1505#endif
1508 } 1506 }
1509} 1507}