Mon Apr 20 19:29:09 2020 UTC ()
xbdback_fragio_intvl is also no longer used


(jdolecek)
diff -r1.84 -r1.85 src/sys/arch/xen/xen/xbdback_xenbus.c

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

--- src/sys/arch/xen/xen/xbdback_xenbus.c 2020/04/20 19:20:35 1.84
+++ src/sys/arch/xen/xen/xbdback_xenbus.c 2020/04/20 19:29:09 1.85
@@ -1,1249 +1,1246 @@ @@ -1,1249 +1,1246 @@
1/* $NetBSD: xbdback_xenbus.c,v 1.84 2020/04/20 19:20:35 bouyer Exp $ */ 1/* $NetBSD: xbdback_xenbus.c,v 1.85 2020/04/20 19:29:09 jdolecek 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.84 2020/04/20 19:20:35 bouyer Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: xbdback_xenbus.c,v 1.85 2020/04/20 19:29:09 jdolecek 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 
249static const struct timeval xbdback_fragio_intvl = { 60, 0 }; 
250#endif 
251 void xbdbackattach(int); 248 void xbdbackattach(int);
252static int xbdback_xenbus_create(struct xenbus_device *); 249static int xbdback_xenbus_create(struct xenbus_device *);
253static int xbdback_xenbus_destroy(void *); 250static int xbdback_xenbus_destroy(void *);
254static void xbdback_frontend_changed(void *, XenbusState); 251static void xbdback_frontend_changed(void *, XenbusState);
255static void xbdback_backend_changed(struct xenbus_watch *, 252static void xbdback_backend_changed(struct xenbus_watch *,
256 const char **, unsigned int); 253 const char **, unsigned int);
257static int xbdback_evthandler(void *); 254static int xbdback_evthandler(void *);
258 255
259static int xbdback_connect(struct xbdback_instance *); 256static int xbdback_connect(struct xbdback_instance *);
260static void xbdback_disconnect(struct xbdback_instance *); 257static void xbdback_disconnect(struct xbdback_instance *);
261static void xbdback_finish_disconnect(struct xbdback_instance *); 258static void xbdback_finish_disconnect(struct xbdback_instance *);
262 259
263static bool xbdif_lookup(domid_t, uint32_t); 260static bool xbdif_lookup(domid_t, uint32_t);
264 261
265static void *xbdback_co_main(struct xbdback_instance *, void *); 262static void *xbdback_co_main(struct xbdback_instance *, void *);
266static void *xbdback_co_main_loop(struct xbdback_instance *, void *); 263static void *xbdback_co_main_loop(struct xbdback_instance *, void *);
267static void *xbdback_co_main_incr(struct xbdback_instance *, void *); 264static void *xbdback_co_main_incr(struct xbdback_instance *, void *);
268static void *xbdback_co_main_done2(struct xbdback_instance *, void *); 265static void *xbdback_co_main_done2(struct xbdback_instance *, void *);
269 266
270static void *xbdback_co_cache_flush(struct xbdback_instance *, void *); 267static void *xbdback_co_cache_flush(struct xbdback_instance *, void *);
271static void *xbdback_co_cache_doflush(struct xbdback_instance *, void *); 268static void *xbdback_co_cache_doflush(struct xbdback_instance *, void *);
272 269
273static void *xbdback_co_io(struct xbdback_instance *, void *); 270static void *xbdback_co_io(struct xbdback_instance *, void *);
274static void *xbdback_co_io_gotio(struct xbdback_instance *, void *); 271static void *xbdback_co_io_gotio(struct xbdback_instance *, void *);
275 272
276static void *xbdback_co_do_io(struct xbdback_instance *, void *); 273static void *xbdback_co_do_io(struct xbdback_instance *, void *);
277 274
278static void xbdback_io_error(struct xbdback_io *, int); 275static void xbdback_io_error(struct xbdback_io *, int);
279static void xbdback_iodone(struct buf *); 276static void xbdback_iodone(struct buf *);
280static void xbdback_send_reply(struct xbdback_instance *, uint64_t , int , int); 277static void xbdback_send_reply(struct xbdback_instance *, uint64_t , int , int);
281 278
282static void *xbdback_map_shm(struct xbdback_io *); 279static void *xbdback_map_shm(struct xbdback_io *);
283static void xbdback_unmap_shm(struct xbdback_io *); 280static void xbdback_unmap_shm(struct xbdback_io *);
284 281
285static void *xbdback_pool_get(struct pool_cache *, 282static void *xbdback_pool_get(struct pool_cache *,
286 struct xbdback_instance *); 283 struct xbdback_instance *);
287static void xbdback_pool_put(struct pool_cache *, void *); 284static void xbdback_pool_put(struct pool_cache *, void *);
288static void xbdback_thread(void *); 285static void xbdback_thread(void *);
289static void xbdback_wakeup_thread(struct xbdback_instance *); 286static void xbdback_wakeup_thread(struct xbdback_instance *);
290static void xbdback_trampoline(struct xbdback_instance *, void *); 287static void xbdback_trampoline(struct xbdback_instance *, void *);
291 288
292static struct xenbus_backend_driver xbd_backend_driver = { 289static struct xenbus_backend_driver xbd_backend_driver = {
293 .xbakd_create = xbdback_xenbus_create, 290 .xbakd_create = xbdback_xenbus_create,
294 .xbakd_type = "vbd" 291 .xbakd_type = "vbd"
295}; 292};
296 293
297void 294void
298xbdbackattach(int n) 295xbdbackattach(int n)
299{ 296{
300 XENPRINTF(("xbdbackattach\n")); 297 XENPRINTF(("xbdbackattach\n"));
301 298
302 /* 299 /*
303 * initialize the backend driver, register the control message handler 300 * initialize the backend driver, register the control message handler
304 * and send driver up message. 301 * and send driver up message.
305 */ 302 */
306 SLIST_INIT(&xbdback_instances); 303 SLIST_INIT(&xbdback_instances);
307 mutex_init(&xbdback_lock, MUTEX_DEFAULT, IPL_NONE); 304 mutex_init(&xbdback_lock, MUTEX_DEFAULT, IPL_NONE);
308 305
309 pool_cache_bootstrap(&xbdback_io_pool, 306 pool_cache_bootstrap(&xbdback_io_pool,
310 sizeof(struct xbdback_io), 0, 0, 0, "xbbip", NULL, 307 sizeof(struct xbdback_io), 0, 0, 0, "xbbip", NULL,
311 IPL_SOFTBIO, NULL, NULL, NULL); 308 IPL_SOFTBIO, NULL, NULL, NULL);
312 309
313 /* we allocate enough to handle a whole ring at once */ 310 /* we allocate enough to handle a whole ring at once */
314 pool_prime(&xbdback_io_pool.pc_pool, BLKIF_RING_SIZE); 311 pool_prime(&xbdback_io_pool.pc_pool, BLKIF_RING_SIZE);
315 312
316 xenbus_backend_register(&xbd_backend_driver); 313 xenbus_backend_register(&xbd_backend_driver);
317} 314}
318 315
319static int 316static int
320xbdback_xenbus_create(struct xenbus_device *xbusd) 317xbdback_xenbus_create(struct xenbus_device *xbusd)
321{ 318{
322 struct xbdback_instance *xbdi; 319 struct xbdback_instance *xbdi;
323 long domid, handle; 320 long domid, handle;
324 int error, i; 321 int error, i;
325 char *ep; 322 char *ep;
326 323
327 if ((error = xenbus_read_ul(NULL, xbusd->xbusd_path, 324 if ((error = xenbus_read_ul(NULL, xbusd->xbusd_path,
328 "frontend-id", &domid, 10)) != 0) { 325 "frontend-id", &domid, 10)) != 0) {
329 aprint_error("xbdback: can't read %s/frontend-id: %d\n", 326 aprint_error("xbdback: can't read %s/frontend-id: %d\n",
330 xbusd->xbusd_path, error); 327 xbusd->xbusd_path, error);
331 return error; 328 return error;
332 } 329 }
333 330
334 /* 331 /*
335 * get handle: this is the last component of the path; which is 332 * 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 333 * a decimal number. $path/dev contains the device name, which is not
337 * appropriate. 334 * appropriate.
338 */ 335 */
339 for (i = strlen(xbusd->xbusd_path); i > 0; i--) { 336 for (i = strlen(xbusd->xbusd_path); i > 0; i--) {
340 if (xbusd->xbusd_path[i] == '/') 337 if (xbusd->xbusd_path[i] == '/')
341 break; 338 break;
342 } 339 }
343 if (i == 0) { 340 if (i == 0) {
344 aprint_error("xbdback: can't parse %s\n", 341 aprint_error("xbdback: can't parse %s\n",
345 xbusd->xbusd_path); 342 xbusd->xbusd_path);
346 return EFTYPE; 343 return EFTYPE;
347 } 344 }
348 handle = strtoul(&xbusd->xbusd_path[i+1], &ep, 10); 345 handle = strtoul(&xbusd->xbusd_path[i+1], &ep, 10);
349 if (*ep != '\0') { 346 if (*ep != '\0') {
350 aprint_error("xbdback: can't parse %s\n", 347 aprint_error("xbdback: can't parse %s\n",
351 xbusd->xbusd_path); 348 xbusd->xbusd_path);
352 return EFTYPE; 349 return EFTYPE;
353 } 350 }
354  351
355 if (xbdif_lookup(domid, handle)) { 352 if (xbdif_lookup(domid, handle)) {
356 return EEXIST; 353 return EEXIST;
357 } 354 }
358 xbdi = kmem_zalloc(sizeof(*xbdi), KM_SLEEP); 355 xbdi = kmem_zalloc(sizeof(*xbdi), KM_SLEEP);
359 356
360 xbdi->xbdi_domid = domid; 357 xbdi->xbdi_domid = domid;
361 xbdi->xbdi_handle = handle; 358 xbdi->xbdi_handle = handle;
362 snprintf(xbdi->xbdi_name, sizeof(xbdi->xbdi_name), "xbdb%di%d", 359 snprintf(xbdi->xbdi_name, sizeof(xbdi->xbdi_name), "xbdb%di%d",
363 xbdi->xbdi_domid, xbdi->xbdi_handle); 360 xbdi->xbdi_domid, xbdi->xbdi_handle);
364 361
365 /* initialize status and reference counter */ 362 /* initialize status and reference counter */
366 xbdi->xbdi_status = DISCONNECTED; 363 xbdi->xbdi_status = DISCONNECTED;
367 xbdi_get(xbdi); 364 xbdi_get(xbdi);
368 365
369 mutex_init(&xbdi->xbdi_lock, MUTEX_DEFAULT, IPL_BIO); 366 mutex_init(&xbdi->xbdi_lock, MUTEX_DEFAULT, IPL_BIO);
370 cv_init(&xbdi->xbdi_cv, xbdi->xbdi_name); 367 cv_init(&xbdi->xbdi_cv, xbdi->xbdi_name);
371 mutex_enter(&xbdback_lock); 368 mutex_enter(&xbdback_lock);
372 SLIST_INSERT_HEAD(&xbdback_instances, xbdi, next); 369 SLIST_INSERT_HEAD(&xbdback_instances, xbdi, next);
373 mutex_exit(&xbdback_lock); 370 mutex_exit(&xbdback_lock);
374 371
375 xbusd->xbusd_u.b.b_cookie = xbdi;  372 xbusd->xbusd_u.b.b_cookie = xbdi;
376 xbusd->xbusd_u.b.b_detach = xbdback_xenbus_destroy; 373 xbusd->xbusd_u.b.b_detach = xbdback_xenbus_destroy;
377 xbusd->xbusd_otherend_changed = xbdback_frontend_changed; 374 xbusd->xbusd_otherend_changed = xbdback_frontend_changed;
378 xbdi->xbdi_xbusd = xbusd; 375 xbdi->xbdi_xbusd = xbusd;
379 376
380 SLIST_INIT(&xbdi->xbdi_va_free); 377 SLIST_INIT(&xbdi->xbdi_va_free);
381 for (i = 0; i < BLKIF_RING_SIZE; i++) { 378 for (i = 0; i < BLKIF_RING_SIZE; i++) {
382 xbdi->xbdi_va[i].xv_vaddr = uvm_km_alloc(kernel_map, 379 xbdi->xbdi_va[i].xv_vaddr = uvm_km_alloc(kernel_map,
383 VBD_VA_SIZE, 0, UVM_KMF_VAONLY|UVM_KMF_WAITVA); 380 VBD_VA_SIZE, 0, UVM_KMF_VAONLY|UVM_KMF_WAITVA);
384 SLIST_INSERT_HEAD(&xbdi->xbdi_va_free, &xbdi->xbdi_va[i], 381 SLIST_INSERT_HEAD(&xbdi->xbdi_va_free, &xbdi->xbdi_va[i],
385 xv_next); 382 xv_next);
386 } 383 }
387 384
388 error = xenbus_watch_path2(xbusd, xbusd->xbusd_path, "physical-device", 385 error = xenbus_watch_path2(xbusd, xbusd->xbusd_path, "physical-device",
389 &xbdi->xbdi_watch, xbdback_backend_changed); 386 &xbdi->xbdi_watch, xbdback_backend_changed);
390 if (error) { 387 if (error) {
391 printf("failed to watch on %s/physical-device: %d\n", 388 printf("failed to watch on %s/physical-device: %d\n",
392 xbusd->xbusd_path, error); 389 xbusd->xbusd_path, error);
393 goto fail; 390 goto fail;
394 } 391 }
395 xbdi->xbdi_watch.xbw_dev = xbusd; 392 xbdi->xbdi_watch.xbw_dev = xbusd;
396 error = xenbus_switch_state(xbusd, NULL, XenbusStateInitWait); 393 error = xenbus_switch_state(xbusd, NULL, XenbusStateInitWait);
397 if (error) { 394 if (error) {
398 printf("failed to switch state on %s: %d\n", 395 printf("failed to switch state on %s: %d\n",
399 xbusd->xbusd_path, error); 396 xbusd->xbusd_path, error);
400 goto fail2; 397 goto fail2;
401 } 398 }
402 return 0; 399 return 0;
403fail2: 400fail2:
404 unregister_xenbus_watch(&xbdi->xbdi_watch); 401 unregister_xenbus_watch(&xbdi->xbdi_watch);
405fail: 402fail:
406 kmem_free(xbdi, sizeof(*xbdi)); 403 kmem_free(xbdi, sizeof(*xbdi));
407 return error; 404 return error;
408} 405}
409 406
410static int 407static int
411xbdback_xenbus_destroy(void *arg) 408xbdback_xenbus_destroy(void *arg)
412{ 409{
413 struct xbdback_instance *xbdi = arg; 410 struct xbdback_instance *xbdi = arg;
414 struct xenbus_device *xbusd = xbdi->xbdi_xbusd; 411 struct xenbus_device *xbusd = xbdi->xbdi_xbusd;
415 struct gnttab_unmap_grant_ref ungrop; 412 struct gnttab_unmap_grant_ref ungrop;
416 int err; 413 int err;
417 414
418 XENPRINTF(("xbdback_xenbus_destroy state %d\n", xbdi->xbdi_status)); 415 XENPRINTF(("xbdback_xenbus_destroy state %d\n", xbdi->xbdi_status));
419 416
420 xbdback_disconnect(xbdi); 417 xbdback_disconnect(xbdi);
421 418
422 /* unregister watch */ 419 /* unregister watch */
423 if (xbdi->xbdi_watch.node) 420 if (xbdi->xbdi_watch.node)
424 xenbus_unwatch_path(&xbdi->xbdi_watch); 421 xenbus_unwatch_path(&xbdi->xbdi_watch);
425 422
426 /* unmap ring */ 423 /* unmap ring */
427 if (xbdi->xbdi_ring_va != 0) { 424 if (xbdi->xbdi_ring_va != 0) {
428 ungrop.host_addr = xbdi->xbdi_ring_va; 425 ungrop.host_addr = xbdi->xbdi_ring_va;
429 ungrop.handle = xbdi->xbdi_ring_handle; 426 ungrop.handle = xbdi->xbdi_ring_handle;
430 ungrop.dev_bus_addr = 0; 427 ungrop.dev_bus_addr = 0;
431 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 428 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
432 &ungrop, 1); 429 &ungrop, 1);
433 if (err) 430 if (err)
434 printf("xbdback %s: unmap_grant_ref failed: %d\n", 431 printf("xbdback %s: unmap_grant_ref failed: %d\n",
435 xbusd->xbusd_otherend, err); 432 xbusd->xbusd_otherend, err);
436 uvm_km_free(kernel_map, xbdi->xbdi_ring_va, 433 uvm_km_free(kernel_map, xbdi->xbdi_ring_va,
437 PAGE_SIZE, UVM_KMF_VAONLY); 434 PAGE_SIZE, UVM_KMF_VAONLY);
438 } 435 }
439 /* close device */ 436 /* close device */
440 if (xbdi->xbdi_size) { 437 if (xbdi->xbdi_size) {
441 const char *name; 438 const char *name;
442 struct dkwedge_info wi; 439 struct dkwedge_info wi;
443 if (getdiskinfo(xbdi->xbdi_vp, &wi) == 0) 440 if (getdiskinfo(xbdi->xbdi_vp, &wi) == 0)
444 name = wi.dkw_devname; 441 name = wi.dkw_devname;
445 else 442 else
446 name = "*unknown*"; 443 name = "*unknown*";
447 printf("xbd backend: detach device %s for domain %d\n", 444 printf("xbd backend: detach device %s for domain %d\n",
448 name, xbdi->xbdi_domid); 445 name, xbdi->xbdi_domid);
449 vn_close(xbdi->xbdi_vp, FREAD, NOCRED); 446 vn_close(xbdi->xbdi_vp, FREAD, NOCRED);
450 } 447 }
451 mutex_enter(&xbdback_lock); 448 mutex_enter(&xbdback_lock);
452 SLIST_REMOVE(&xbdback_instances, xbdi, xbdback_instance, next); 449 SLIST_REMOVE(&xbdback_instances, xbdi, xbdback_instance, next);
453 mutex_exit(&xbdback_lock); 450 mutex_exit(&xbdback_lock);
454 451
455 for (int i = 0; i < BLKIF_RING_SIZE; i++) { 452 for (int i = 0; i < BLKIF_RING_SIZE; i++) {
456 if (xbdi->xbdi_va[i].xv_vaddr != 0) { 453 if (xbdi->xbdi_va[i].xv_vaddr != 0) {
457 uvm_km_free(kernel_map, xbdi->xbdi_va[i].xv_vaddr, 454 uvm_km_free(kernel_map, xbdi->xbdi_va[i].xv_vaddr,
458 VBD_VA_SIZE, UVM_KMF_VAONLY); 455 VBD_VA_SIZE, UVM_KMF_VAONLY);
459 xbdi->xbdi_va[i].xv_vaddr = 0; 456 xbdi->xbdi_va[i].xv_vaddr = 0;
460 } 457 }
461 } 458 }
462 459
463 mutex_destroy(&xbdi->xbdi_lock); 460 mutex_destroy(&xbdi->xbdi_lock);
464 cv_destroy(&xbdi->xbdi_cv); 461 cv_destroy(&xbdi->xbdi_cv);
465 kmem_free(xbdi, sizeof(*xbdi)); 462 kmem_free(xbdi, sizeof(*xbdi));
466 return 0; 463 return 0;
467} 464}
468 465
469static int 466static int
470xbdback_connect(struct xbdback_instance *xbdi) 467xbdback_connect(struct xbdback_instance *xbdi)
471{ 468{
472 int err; 469 int err;
473 struct gnttab_map_grant_ref grop; 470 struct gnttab_map_grant_ref grop;
474 struct gnttab_unmap_grant_ref ungrop; 471 struct gnttab_unmap_grant_ref ungrop;
475 evtchn_op_t evop; 472 evtchn_op_t evop;
476 u_long ring_ref, revtchn; 473 u_long ring_ref, revtchn;
477 char xsproto[32]; 474 char xsproto[32];
478 const char *proto; 475 const char *proto;
479 struct xenbus_device *xbusd = xbdi->xbdi_xbusd; 476 struct xenbus_device *xbusd = xbdi->xbdi_xbusd;
480 477
481 XENPRINTF(("xbdback %s: connect\n", xbusd->xbusd_path)); 478 XENPRINTF(("xbdback %s: connect\n", xbusd->xbusd_path));
482 /* read comunication informations */ 479 /* read comunication informations */
483 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, 480 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend,
484 "ring-ref", &ring_ref, 10); 481 "ring-ref", &ring_ref, 10);
485 if (err) { 482 if (err) {
486 xenbus_dev_fatal(xbusd, err, "reading %s/ring-ref", 483 xenbus_dev_fatal(xbusd, err, "reading %s/ring-ref",
487 xbusd->xbusd_otherend); 484 xbusd->xbusd_otherend);
488 return -1; 485 return -1;
489 } 486 }
490 XENPRINTF(("xbdback %s: connect ring-ref %lu\n", xbusd->xbusd_path, ring_ref)); 487 XENPRINTF(("xbdback %s: connect ring-ref %lu\n", xbusd->xbusd_path, ring_ref));
491 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, 488 err = xenbus_read_ul(NULL, xbusd->xbusd_otherend,
492 "event-channel", &revtchn, 10); 489 "event-channel", &revtchn, 10);
493 if (err) { 490 if (err) {
494 xenbus_dev_fatal(xbusd, err, "reading %s/event-channel", 491 xenbus_dev_fatal(xbusd, err, "reading %s/event-channel",
495 xbusd->xbusd_otherend); 492 xbusd->xbusd_otherend);
496 return -1; 493 return -1;
497 } 494 }
498 XENPRINTF(("xbdback %s: connect revtchn %lu\n", xbusd->xbusd_path, revtchn)); 495 XENPRINTF(("xbdback %s: connect revtchn %lu\n", xbusd->xbusd_path, revtchn));
499 err = xenbus_read(NULL, xbusd->xbusd_otherend, "protocol", 496 err = xenbus_read(NULL, xbusd->xbusd_otherend, "protocol",
500 xsproto, sizeof(xsproto)); 497 xsproto, sizeof(xsproto));
501 if (err) { 498 if (err) {
502 xbdi->xbdi_proto = XBDIP_NATIVE; 499 xbdi->xbdi_proto = XBDIP_NATIVE;
503 proto = "unspecified"; 500 proto = "unspecified";
504 XENPRINTF(("xbdback %s: connect no xsproto\n", xbusd->xbusd_path)); 501 XENPRINTF(("xbdback %s: connect no xsproto\n", xbusd->xbusd_path));
505 } else { 502 } else {
506 XENPRINTF(("xbdback %s: connect xsproto %s\n", xbusd->xbusd_path, xsproto)); 503 XENPRINTF(("xbdback %s: connect xsproto %s\n", xbusd->xbusd_path, xsproto));
507 if (strcmp(xsproto, XEN_IO_PROTO_ABI_NATIVE) == 0) { 504 if (strcmp(xsproto, XEN_IO_PROTO_ABI_NATIVE) == 0) {
508 xbdi->xbdi_proto = XBDIP_NATIVE; 505 xbdi->xbdi_proto = XBDIP_NATIVE;
509 proto = XEN_IO_PROTO_ABI_NATIVE; 506 proto = XEN_IO_PROTO_ABI_NATIVE;
510 } else if (strcmp(xsproto, XEN_IO_PROTO_ABI_X86_32) == 0) { 507 } else if (strcmp(xsproto, XEN_IO_PROTO_ABI_X86_32) == 0) {
511 xbdi->xbdi_proto = XBDIP_32; 508 xbdi->xbdi_proto = XBDIP_32;
512 proto = XEN_IO_PROTO_ABI_X86_32; 509 proto = XEN_IO_PROTO_ABI_X86_32;
513 } else if (strcmp(xsproto, XEN_IO_PROTO_ABI_X86_64) == 0) { 510 } else if (strcmp(xsproto, XEN_IO_PROTO_ABI_X86_64) == 0) {
514 xbdi->xbdi_proto = XBDIP_64; 511 xbdi->xbdi_proto = XBDIP_64;
515 proto = XEN_IO_PROTO_ABI_X86_64; 512 proto = XEN_IO_PROTO_ABI_X86_64;
516 } else { 513 } else {
517 aprint_error("xbd domain %d: unknown proto %s\n", 514 aprint_error("xbd domain %d: unknown proto %s\n",
518 xbdi->xbdi_domid, xsproto); 515 xbdi->xbdi_domid, xsproto);
519 return -1; 516 return -1;
520 } 517 }
521 } 518 }
522 519
523 /* allocate VA space and map rings */ 520 /* allocate VA space and map rings */
524 xbdi->xbdi_ring_va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, 521 xbdi->xbdi_ring_va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
525 UVM_KMF_VAONLY); 522 UVM_KMF_VAONLY);
526 if (xbdi->xbdi_ring_va == 0) { 523 if (xbdi->xbdi_ring_va == 0) {
527 xenbus_dev_fatal(xbusd, ENOMEM, 524 xenbus_dev_fatal(xbusd, ENOMEM,
528 "can't get VA for ring", xbusd->xbusd_otherend); 525 "can't get VA for ring", xbusd->xbusd_otherend);
529 return -1; 526 return -1;
530 } 527 }
531 XENPRINTF(("xbdback %s: connect va 0x%" PRIxVADDR "\n", xbusd->xbusd_path, xbdi->xbdi_ring_va)); 528 XENPRINTF(("xbdback %s: connect va 0x%" PRIxVADDR "\n", xbusd->xbusd_path, xbdi->xbdi_ring_va));
532 529
533 grop.host_addr = xbdi->xbdi_ring_va; 530 grop.host_addr = xbdi->xbdi_ring_va;
534 grop.flags = GNTMAP_host_map; 531 grop.flags = GNTMAP_host_map;
535 grop.ref = ring_ref; 532 grop.ref = ring_ref;
536 grop.dom = xbdi->xbdi_domid; 533 grop.dom = xbdi->xbdi_domid;
537 err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, 534 err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
538 &grop, 1); 535 &grop, 1);
539 if (err || grop.status) { 536 if (err || grop.status) {
540 aprint_error("xbdback %s: can't map grant ref: %d/%d\n", 537 aprint_error("xbdback %s: can't map grant ref: %d/%d\n",
541 xbusd->xbusd_path, err, grop.status); 538 xbusd->xbusd_path, err, grop.status);
542 xenbus_dev_fatal(xbusd, EINVAL, 539 xenbus_dev_fatal(xbusd, EINVAL,
543 "can't map ring", xbusd->xbusd_otherend); 540 "can't map ring", xbusd->xbusd_otherend);
544 goto err; 541 goto err;
545 } 542 }
546 xbdi->xbdi_ring_handle = grop.handle; 543 xbdi->xbdi_ring_handle = grop.handle;
547 XENPRINTF(("xbdback %s: connect grhandle %d\n", xbusd->xbusd_path, grop.handle)); 544 XENPRINTF(("xbdback %s: connect grhandle %d\n", xbusd->xbusd_path, grop.handle));
548 545
549 switch(xbdi->xbdi_proto) { 546 switch(xbdi->xbdi_proto) {
550 case XBDIP_NATIVE: 547 case XBDIP_NATIVE:
551 { 548 {
552 blkif_sring_t *sring = (void *)xbdi->xbdi_ring_va; 549 blkif_sring_t *sring = (void *)xbdi->xbdi_ring_va;
553 BACK_RING_INIT(&xbdi->xbdi_ring.ring_n, sring, PAGE_SIZE); 550 BACK_RING_INIT(&xbdi->xbdi_ring.ring_n, sring, PAGE_SIZE);
554 break; 551 break;
555 } 552 }
556 case XBDIP_32: 553 case XBDIP_32:
557 { 554 {
558 blkif_x86_32_sring_t *sring = (void *)xbdi->xbdi_ring_va; 555 blkif_x86_32_sring_t *sring = (void *)xbdi->xbdi_ring_va;
559 BACK_RING_INIT(&xbdi->xbdi_ring.ring_32, sring, PAGE_SIZE); 556 BACK_RING_INIT(&xbdi->xbdi_ring.ring_32, sring, PAGE_SIZE);
560 break; 557 break;
561 } 558 }
562 case XBDIP_64: 559 case XBDIP_64:
563 { 560 {
564 blkif_x86_64_sring_t *sring = (void *)xbdi->xbdi_ring_va; 561 blkif_x86_64_sring_t *sring = (void *)xbdi->xbdi_ring_va;
565 BACK_RING_INIT(&xbdi->xbdi_ring.ring_64, sring, PAGE_SIZE); 562 BACK_RING_INIT(&xbdi->xbdi_ring.ring_64, sring, PAGE_SIZE);
566 break; 563 break;
567 } 564 }
568 } 565 }
569 566
570 evop.cmd = EVTCHNOP_bind_interdomain; 567 evop.cmd = EVTCHNOP_bind_interdomain;
571 evop.u.bind_interdomain.remote_dom = xbdi->xbdi_domid; 568 evop.u.bind_interdomain.remote_dom = xbdi->xbdi_domid;
572 evop.u.bind_interdomain.remote_port = revtchn; 569 evop.u.bind_interdomain.remote_port = revtchn;
573 err = HYPERVISOR_event_channel_op(&evop); 570 err = HYPERVISOR_event_channel_op(&evop);
574 if (err) { 571 if (err) {
575 aprint_error("blkback %s: " 572 aprint_error("blkback %s: "
576 "can't get event channel: %d\n", 573 "can't get event channel: %d\n",
577 xbusd->xbusd_otherend, err); 574 xbusd->xbusd_otherend, err);
578 xenbus_dev_fatal(xbusd, err, 575 xenbus_dev_fatal(xbusd, err,
579 "can't bind event channel", xbusd->xbusd_otherend); 576 "can't bind event channel", xbusd->xbusd_otherend);
580 goto err2; 577 goto err2;
581 } 578 }
582 XENPRINTF(("xbdback %s: connect evchannel %d\n", xbusd->xbusd_path, xbdi->xbdi_evtchn)); 579 XENPRINTF(("xbdback %s: connect evchannel %d\n", xbusd->xbusd_path, xbdi->xbdi_evtchn));
583 xbdi->xbdi_evtchn = evop.u.bind_interdomain.local_port; 580 xbdi->xbdi_evtchn = evop.u.bind_interdomain.local_port;
584 581
585 xbdi->xbdi_ih = xen_intr_establish_xname(-1, &xen_pic, xbdi->xbdi_evtchn, 582 xbdi->xbdi_ih = xen_intr_establish_xname(-1, &xen_pic, xbdi->xbdi_evtchn,
586 IST_LEVEL, IPL_BIO, xbdback_evthandler, xbdi, false, 583 IST_LEVEL, IPL_BIO, xbdback_evthandler, xbdi, false,
587 xbdi->xbdi_name); 584 xbdi->xbdi_name);
588 KASSERT(xbdi->xbdi_ih != NULL); 585 KASSERT(xbdi->xbdi_ih != NULL);
589 aprint_verbose("xbd backend domain %d handle %#x (%d) " 586 aprint_verbose("xbd backend domain %d handle %#x (%d) "
590 "using event channel %d, protocol %s\n", xbdi->xbdi_domid, 587 "using event channel %d, protocol %s\n", xbdi->xbdi_domid,
591 xbdi->xbdi_handle, xbdi->xbdi_handle, xbdi->xbdi_evtchn, proto); 588 xbdi->xbdi_handle, xbdi->xbdi_handle, xbdi->xbdi_evtchn, proto);
592 589
593 /* enable the xbdback event handler machinery */ 590 /* enable the xbdback event handler machinery */
594 xbdi->xbdi_status = WAITING; 591 xbdi->xbdi_status = WAITING;
595 hypervisor_unmask_event(xbdi->xbdi_evtchn); 592 hypervisor_unmask_event(xbdi->xbdi_evtchn);
596 hypervisor_notify_via_evtchn(xbdi->xbdi_evtchn); 593 hypervisor_notify_via_evtchn(xbdi->xbdi_evtchn);
597 594
598 if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, 595 if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
599 xbdback_thread, xbdi, NULL, "%s", xbdi->xbdi_name) == 0) 596 xbdback_thread, xbdi, NULL, "%s", xbdi->xbdi_name) == 0)
600 return 0; 597 return 0;
601 598
602err2: 599err2:
603 /* unmap ring */ 600 /* unmap ring */
604 ungrop.host_addr = xbdi->xbdi_ring_va; 601 ungrop.host_addr = xbdi->xbdi_ring_va;
605 ungrop.handle = xbdi->xbdi_ring_handle; 602 ungrop.handle = xbdi->xbdi_ring_handle;
606 ungrop.dev_bus_addr = 0; 603 ungrop.dev_bus_addr = 0;
607 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 604 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
608 &ungrop, 1); 605 &ungrop, 1);
609 if (err) 606 if (err)
610 aprint_error("xbdback %s: unmap_grant_ref failed: %d\n", 607 aprint_error("xbdback %s: unmap_grant_ref failed: %d\n",
611 xbusd->xbusd_path, err); 608 xbusd->xbusd_path, err);
612 609
613err: 610err:
614 /* free ring VA space */ 611 /* free ring VA space */
615 uvm_km_free(kernel_map, xbdi->xbdi_ring_va, PAGE_SIZE, UVM_KMF_VAONLY); 612 uvm_km_free(kernel_map, xbdi->xbdi_ring_va, PAGE_SIZE, UVM_KMF_VAONLY);
616 return -1; 613 return -1;
617} 614}
618 615
619/* 616/*
620 * Signal a xbdback thread to disconnect. Done in 'xenwatch' thread context. 617 * Signal a xbdback thread to disconnect. Done in 'xenwatch' thread context.
621 */ 618 */
622static void 619static void
623xbdback_disconnect(struct xbdback_instance *xbdi) 620xbdback_disconnect(struct xbdback_instance *xbdi)
624{ 621{
625  622
626 mutex_enter(&xbdi->xbdi_lock); 623 mutex_enter(&xbdi->xbdi_lock);
627 if (xbdi->xbdi_status == DISCONNECTED) { 624 if (xbdi->xbdi_status == DISCONNECTED) {
628 mutex_exit(&xbdi->xbdi_lock); 625 mutex_exit(&xbdi->xbdi_lock);
629 return; 626 return;
630 } 627 }
631 hypervisor_mask_event(xbdi->xbdi_evtchn); 628 hypervisor_mask_event(xbdi->xbdi_evtchn);
632 xen_intr_disestablish(xbdi->xbdi_ih); 629 xen_intr_disestablish(xbdi->xbdi_ih);
633 630
634 /* signal thread that we want to disconnect, then wait for it */ 631 /* signal thread that we want to disconnect, then wait for it */
635 xbdi->xbdi_status = DISCONNECTING; 632 xbdi->xbdi_status = DISCONNECTING;
636 cv_signal(&xbdi->xbdi_cv); 633 cv_signal(&xbdi->xbdi_cv);
637 634
638 while (xbdi->xbdi_status != DISCONNECTED) 635 while (xbdi->xbdi_status != DISCONNECTED)
639 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock); 636 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock);
640 637
641 mutex_exit(&xbdi->xbdi_lock); 638 mutex_exit(&xbdi->xbdi_lock);
642 639
643 xenbus_switch_state(xbdi->xbdi_xbusd, NULL, XenbusStateClosing); 640 xenbus_switch_state(xbdi->xbdi_xbusd, NULL, XenbusStateClosing);
644} 641}
645 642
646static void 643static void
647xbdback_frontend_changed(void *arg, XenbusState new_state) 644xbdback_frontend_changed(void *arg, XenbusState new_state)
648{ 645{
649 struct xbdback_instance *xbdi = arg; 646 struct xbdback_instance *xbdi = arg;
650 struct xenbus_device *xbusd = xbdi->xbdi_xbusd; 647 struct xenbus_device *xbusd = xbdi->xbdi_xbusd;
651 648
652 XENPRINTF(("xbdback %s: new state %d\n", xbusd->xbusd_path, new_state)); 649 XENPRINTF(("xbdback %s: new state %d\n", xbusd->xbusd_path, new_state));
653 switch(new_state) { 650 switch(new_state) {
654 case XenbusStateInitialising: 651 case XenbusStateInitialising:
655 break; 652 break;
656 case XenbusStateInitialised: 653 case XenbusStateInitialised:
657 case XenbusStateConnected: 654 case XenbusStateConnected:
658 if (xbdi->xbdi_status == WAITING || xbdi->xbdi_status == RUN) 655 if (xbdi->xbdi_status == WAITING || xbdi->xbdi_status == RUN)
659 break; 656 break;
660 xbdback_connect(xbdi); 657 xbdback_connect(xbdi);
661 break; 658 break;
662 case XenbusStateClosing: 659 case XenbusStateClosing:
663 xbdback_disconnect(xbdi); 660 xbdback_disconnect(xbdi);
664 break; 661 break;
665 case XenbusStateClosed: 662 case XenbusStateClosed:
666 /* otherend_changed() should handle it for us */ 663 /* otherend_changed() should handle it for us */
667 panic("xbdback_frontend_changed: closed\n"); 664 panic("xbdback_frontend_changed: closed\n");
668 case XenbusStateUnknown: 665 case XenbusStateUnknown:
669 case XenbusStateInitWait: 666 case XenbusStateInitWait:
670 default: 667 default:
671 aprint_error("xbdback %s: invalid frontend state %d\n", 668 aprint_error("xbdback %s: invalid frontend state %d\n",
672 xbusd->xbusd_path, new_state); 669 xbusd->xbusd_path, new_state);
673 } 670 }
674 return; 671 return;
675} 672}
676 673
677static void 674static void
678xbdback_backend_changed(struct xenbus_watch *watch, 675xbdback_backend_changed(struct xenbus_watch *watch,
679 const char **vec, unsigned int len) 676 const char **vec, unsigned int len)
680{ 677{
681 struct xenbus_device *xbusd = watch->xbw_dev; 678 struct xenbus_device *xbusd = watch->xbw_dev;
682 struct xbdback_instance *xbdi = xbusd->xbusd_u.b.b_cookie; 679 struct xbdback_instance *xbdi = xbusd->xbusd_u.b.b_cookie;
683 int err; 680 int err;
684 long dev; 681 long dev;
685 char mode[32]; 682 char mode[32];
686 struct xenbus_transaction *xbt; 683 struct xenbus_transaction *xbt;
687 const char *devname; 684 const char *devname;
688 int major; 685 int major;
689 686
690 err = xenbus_read_ul(NULL, xbusd->xbusd_path, "physical-device", 687 err = xenbus_read_ul(NULL, xbusd->xbusd_path, "physical-device",
691 &dev, 10); 688 &dev, 10);
692 /* 689 /*
693 * An error can occur as the watch can fire up just after being 690 * An error can occur as the watch can fire up just after being
694 * registered. So we have to ignore error :( 691 * registered. So we have to ignore error :(
695 */ 692 */
696 if (err) 693 if (err)
697 return; 694 return;
698 /* 695 /*
699 * we can also fire up after having opened the device, don't try 696 * we can also fire up after having opened the device, don't try
700 * to do it twice. 697 * to do it twice.
701 */ 698 */
702 if (xbdi->xbdi_vp != NULL) { 699 if (xbdi->xbdi_vp != NULL) {
703 if (xbdi->xbdi_status == WAITING || xbdi->xbdi_status == RUN) { 700 if (xbdi->xbdi_status == WAITING || xbdi->xbdi_status == RUN) {
704 if (xbdi->xbdi_dev != dev) { 701 if (xbdi->xbdi_dev != dev) {
705 printf("xbdback %s: changing physical device " 702 printf("xbdback %s: changing physical device "
706 "from %#"PRIx64" to %#lx not supported\n", 703 "from %#"PRIx64" to %#lx not supported\n",
707 xbusd->xbusd_path, xbdi->xbdi_dev, dev); 704 xbusd->xbusd_path, xbdi->xbdi_dev, dev);
708 } 705 }
709 } 706 }
710 return; 707 return;
711 } 708 }
712 xbdi->xbdi_dev = dev; 709 xbdi->xbdi_dev = dev;
713 err = xenbus_read(NULL, xbusd->xbusd_path, "mode", mode, sizeof(mode)); 710 err = xenbus_read(NULL, xbusd->xbusd_path, "mode", mode, sizeof(mode));
714 if (err) { 711 if (err) {
715 printf("xbdback: failed to read %s/mode: %d\n", 712 printf("xbdback: failed to read %s/mode: %d\n",
716 xbusd->xbusd_path, err); 713 xbusd->xbusd_path, err);
717 return; 714 return;
718 } 715 }
719 if (mode[0] == 'w') 716 if (mode[0] == 'w')
720 xbdi->xbdi_ro = false; 717 xbdi->xbdi_ro = false;
721 else 718 else
722 xbdi->xbdi_ro = true; 719 xbdi->xbdi_ro = true;
723 major = major(xbdi->xbdi_dev); 720 major = major(xbdi->xbdi_dev);
724 devname = devsw_blk2name(major); 721 devname = devsw_blk2name(major);
725 if (devname == NULL) { 722 if (devname == NULL) {
726 printf("xbdback %s: unknown device 0x%"PRIx64"\n", 723 printf("xbdback %s: unknown device 0x%"PRIx64"\n",
727 xbusd->xbusd_path, xbdi->xbdi_dev); 724 xbusd->xbusd_path, xbdi->xbdi_dev);
728 return; 725 return;
729 } 726 }
730 xbdi->xbdi_bdevsw = bdevsw_lookup(xbdi->xbdi_dev); 727 xbdi->xbdi_bdevsw = bdevsw_lookup(xbdi->xbdi_dev);
731 if (xbdi->xbdi_bdevsw == NULL) { 728 if (xbdi->xbdi_bdevsw == NULL) {
732 printf("xbdback %s: no bdevsw for device 0x%"PRIx64"\n", 729 printf("xbdback %s: no bdevsw for device 0x%"PRIx64"\n",
733 xbusd->xbusd_path, xbdi->xbdi_dev); 730 xbusd->xbusd_path, xbdi->xbdi_dev);
734 return; 731 return;
735 } 732 }
736 err = bdevvp(xbdi->xbdi_dev, &xbdi->xbdi_vp); 733 err = bdevvp(xbdi->xbdi_dev, &xbdi->xbdi_vp);
737 if (err) { 734 if (err) {
738 printf("xbdback %s: can't open device 0x%"PRIx64": %d\n", 735 printf("xbdback %s: can't open device 0x%"PRIx64": %d\n",
739 xbusd->xbusd_path, xbdi->xbdi_dev, err); 736 xbusd->xbusd_path, xbdi->xbdi_dev, err);
740 return; 737 return;
741 } 738 }
742 err = vn_lock(xbdi->xbdi_vp, LK_EXCLUSIVE | LK_RETRY); 739 err = vn_lock(xbdi->xbdi_vp, LK_EXCLUSIVE | LK_RETRY);
743 if (err) { 740 if (err) {
744 printf("xbdback %s: can't vn_lock device 0x%"PRIx64": %d\n", 741 printf("xbdback %s: can't vn_lock device 0x%"PRIx64": %d\n",
745 xbusd->xbusd_path, xbdi->xbdi_dev, err); 742 xbusd->xbusd_path, xbdi->xbdi_dev, err);
746 vrele(xbdi->xbdi_vp); 743 vrele(xbdi->xbdi_vp);
747 return; 744 return;
748 } 745 }
749 err = VOP_OPEN(xbdi->xbdi_vp, FREAD, NOCRED); 746 err = VOP_OPEN(xbdi->xbdi_vp, FREAD, NOCRED);
750 if (err) { 747 if (err) {
751 printf("xbdback %s: can't VOP_OPEN device 0x%"PRIx64": %d\n", 748 printf("xbdback %s: can't VOP_OPEN device 0x%"PRIx64": %d\n",
752 xbusd->xbusd_path, xbdi->xbdi_dev, err); 749 xbusd->xbusd_path, xbdi->xbdi_dev, err);
753 vput(xbdi->xbdi_vp); 750 vput(xbdi->xbdi_vp);
754 return; 751 return;
755 } 752 }
756 VOP_UNLOCK(xbdi->xbdi_vp); 753 VOP_UNLOCK(xbdi->xbdi_vp);
757 754
758 /* dk device; get wedge data */ 755 /* dk device; get wedge data */
759 struct dkwedge_info wi; 756 struct dkwedge_info wi;
760 if ((err = getdiskinfo(xbdi->xbdi_vp, &wi)) == 0) { 757 if ((err = getdiskinfo(xbdi->xbdi_vp, &wi)) == 0) {
761 xbdi->xbdi_size = wi.dkw_size; 758 xbdi->xbdi_size = wi.dkw_size;
762 printf("xbd backend: attach device %s (size %" PRIu64 ") " 759 printf("xbd backend: attach device %s (size %" PRIu64 ") "
763 "for domain %d\n", wi.dkw_devname, xbdi->xbdi_size, 760 "for domain %d\n", wi.dkw_devname, xbdi->xbdi_size,
764 xbdi->xbdi_domid); 761 xbdi->xbdi_domid);
765 } else { 762 } else {
766 /* If both Ioctls failed set device size to 0 and return */ 763 /* If both Ioctls failed set device size to 0 and return */
767 printf("xbdback %s: can't DIOCGWEDGEINFO device " 764 printf("xbdback %s: can't DIOCGWEDGEINFO device "
768 "0x%"PRIx64": %d\n", xbusd->xbusd_path, 765 "0x%"PRIx64": %d\n", xbusd->xbusd_path,
769 xbdi->xbdi_dev, err);  766 xbdi->xbdi_dev, err);
770 xbdi->xbdi_size = xbdi->xbdi_dev = 0; 767 xbdi->xbdi_size = xbdi->xbdi_dev = 0;
771 vn_close(xbdi->xbdi_vp, FREAD, NOCRED); 768 vn_close(xbdi->xbdi_vp, FREAD, NOCRED);
772 xbdi->xbdi_vp = NULL; 769 xbdi->xbdi_vp = NULL;
773 return; 770 return;
774 } 771 }
775again: 772again:
776 xbt = xenbus_transaction_start(); 773 xbt = xenbus_transaction_start();
777 if (xbt == NULL) { 774 if (xbt == NULL) {
778 printf("xbdback %s: can't start transaction\n", 775 printf("xbdback %s: can't start transaction\n",
779 xbusd->xbusd_path); 776 xbusd->xbusd_path);
780 return; 777 return;
781 } 778 }
782 err = xenbus_printf(xbt, xbusd->xbusd_path, "sectors", "%" PRIu64 , 779 err = xenbus_printf(xbt, xbusd->xbusd_path, "sectors", "%" PRIu64 ,
783 xbdi->xbdi_size); 780 xbdi->xbdi_size);
784 if (err) { 781 if (err) {
785 printf("xbdback: failed to write %s/sectors: %d\n", 782 printf("xbdback: failed to write %s/sectors: %d\n",
786 xbusd->xbusd_path, err); 783 xbusd->xbusd_path, err);
787 goto abort; 784 goto abort;
788 } 785 }
789 err = xenbus_printf(xbt, xbusd->xbusd_path, "info", "%u", 786 err = xenbus_printf(xbt, xbusd->xbusd_path, "info", "%u",
790 xbdi->xbdi_ro ? VDISK_READONLY : 0); 787 xbdi->xbdi_ro ? VDISK_READONLY : 0);
791 if (err) { 788 if (err) {
792 printf("xbdback: failed to write %s/info: %d\n", 789 printf("xbdback: failed to write %s/info: %d\n",
793 xbusd->xbusd_path, err); 790 xbusd->xbusd_path, err);
794 goto abort; 791 goto abort;
795 } 792 }
796 err = xenbus_printf(xbt, xbusd->xbusd_path, "sector-size", "%lu", 793 err = xenbus_printf(xbt, xbusd->xbusd_path, "sector-size", "%lu",
797 (u_long)DEV_BSIZE); 794 (u_long)DEV_BSIZE);
798 if (err) { 795 if (err) {
799 printf("xbdback: failed to write %s/sector-size: %d\n", 796 printf("xbdback: failed to write %s/sector-size: %d\n",
800 xbusd->xbusd_path, err); 797 xbusd->xbusd_path, err);
801 goto abort; 798 goto abort;
802 } 799 }
803 err = xenbus_printf(xbt, xbusd->xbusd_path, "feature-flush-cache", 800 err = xenbus_printf(xbt, xbusd->xbusd_path, "feature-flush-cache",
804 "%u", 1); 801 "%u", 1);
805 if (err) { 802 if (err) {
806 printf("xbdback: failed to write %s/feature-flush-cache: %d\n", 803 printf("xbdback: failed to write %s/feature-flush-cache: %d\n",
807 xbusd->xbusd_path, err); 804 xbusd->xbusd_path, err);
808 goto abort; 805 goto abort;
809 } 806 }
810 err = xenbus_transaction_end(xbt, 0); 807 err = xenbus_transaction_end(xbt, 0);
811 if (err == EAGAIN) 808 if (err == EAGAIN)
812 goto again; 809 goto again;
813 if (err) { 810 if (err) {
814 printf("xbdback %s: can't end transaction: %d\n", 811 printf("xbdback %s: can't end transaction: %d\n",
815 xbusd->xbusd_path, err); 812 xbusd->xbusd_path, err);
816 } 813 }
817 err = xenbus_switch_state(xbusd, NULL, XenbusStateConnected); 814 err = xenbus_switch_state(xbusd, NULL, XenbusStateConnected);
818 if (err) { 815 if (err) {
819 printf("xbdback %s: can't switch state: %d\n", 816 printf("xbdback %s: can't switch state: %d\n",
820 xbusd->xbusd_path, err); 817 xbusd->xbusd_path, err);
821 } 818 }
822 return; 819 return;
823abort: 820abort:
824 xenbus_transaction_end(xbt, 1); 821 xenbus_transaction_end(xbt, 1);
825} 822}
826 823
827/* 824/*
828 * Used by a xbdi thread to signal that it is now disconnected. 825 * Used by a xbdi thread to signal that it is now disconnected.
829 */ 826 */
830static void 827static void
831xbdback_finish_disconnect(struct xbdback_instance *xbdi) 828xbdback_finish_disconnect(struct xbdback_instance *xbdi)
832{ 829{
833 KASSERT(mutex_owned(&xbdi->xbdi_lock)); 830 KASSERT(mutex_owned(&xbdi->xbdi_lock));
834 KASSERT(xbdi->xbdi_status == DISCONNECTING); 831 KASSERT(xbdi->xbdi_status == DISCONNECTING);
835 832
836 xbdi->xbdi_status = DISCONNECTED; 833 xbdi->xbdi_status = DISCONNECTED;
837 834
838 cv_signal(&xbdi->xbdi_cv); 835 cv_signal(&xbdi->xbdi_cv);
839} 836}
840 837
841static bool 838static bool
842xbdif_lookup(domid_t dom , uint32_t handle) 839xbdif_lookup(domid_t dom , uint32_t handle)
843{ 840{
844 struct xbdback_instance *xbdi; 841 struct xbdback_instance *xbdi;
845 bool found = false; 842 bool found = false;
846 843
847 mutex_enter(&xbdback_lock); 844 mutex_enter(&xbdback_lock);
848 SLIST_FOREACH(xbdi, &xbdback_instances, next) { 845 SLIST_FOREACH(xbdi, &xbdback_instances, next) {
849 if (xbdi->xbdi_domid == dom && xbdi->xbdi_handle == handle) { 846 if (xbdi->xbdi_domid == dom && xbdi->xbdi_handle == handle) {
850 found = true; 847 found = true;
851 break; 848 break;
852 } 849 }
853 } 850 }
854 mutex_exit(&xbdback_lock); 851 mutex_exit(&xbdback_lock);
855 852
856 return found; 853 return found;
857} 854}
858 855
859static int 856static int
860xbdback_evthandler(void *arg) 857xbdback_evthandler(void *arg)
861{ 858{
862 struct xbdback_instance *xbdi = arg; 859 struct xbdback_instance *xbdi = arg;
863 860
864 XENPRINTF(("xbdback_evthandler domain %d: cont %p\n", 861 XENPRINTF(("xbdback_evthandler domain %d: cont %p\n",
865 xbdi->xbdi_domid, xbdi->xbdi_cont)); 862 xbdi->xbdi_domid, xbdi->xbdi_cont));
866 863
867 xbdback_wakeup_thread(xbdi); 864 xbdback_wakeup_thread(xbdi);
868 865
869 return 1; 866 return 1;
870} 867}
871 868
872/* 869/*
873 * Main thread routine for one xbdback instance. Woken up by 870 * 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. 871 * xbdback_evthandler when a domain has I/O work scheduled in a I/O ring.
875 */ 872 */
876static void 873static void
877xbdback_thread(void *arg) 874xbdback_thread(void *arg)
878{ 875{
879 struct xbdback_instance *xbdi = arg; 876 struct xbdback_instance *xbdi = arg;
880 877
881 for (;;) { 878 for (;;) {
882 mutex_enter(&xbdi->xbdi_lock); 879 mutex_enter(&xbdi->xbdi_lock);
883 switch (xbdi->xbdi_status) { 880 switch (xbdi->xbdi_status) {
884 case WAITING: 881 case WAITING:
885 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock); 882 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock);
886 mutex_exit(&xbdi->xbdi_lock); 883 mutex_exit(&xbdi->xbdi_lock);
887 break; 884 break;
888 case RUN: 885 case RUN:
889 xbdi->xbdi_status = WAITING; /* reset state */ 886 xbdi->xbdi_status = WAITING; /* reset state */
890 mutex_exit(&xbdi->xbdi_lock); 887 mutex_exit(&xbdi->xbdi_lock);
891 888
892 if (xbdi->xbdi_cont == NULL) { 889 if (xbdi->xbdi_cont == NULL) {
893 xbdi->xbdi_cont = xbdback_co_main; 890 xbdi->xbdi_cont = xbdback_co_main;
894 } 891 }
895 892
896 xbdback_trampoline(xbdi, xbdi); 893 xbdback_trampoline(xbdi, xbdi);
897 break; 894 break;
898 case DISCONNECTING: 895 case DISCONNECTING:
899 if (xbdi->xbdi_pendingreqs > 0) { 896 if (xbdi->xbdi_pendingreqs > 0) {
900 /* there are pending I/Os. Wait for them. */ 897 /* there are pending I/Os. Wait for them. */
901 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock); 898 cv_wait(&xbdi->xbdi_cv, &xbdi->xbdi_lock);
902 mutex_exit(&xbdi->xbdi_lock); 899 mutex_exit(&xbdi->xbdi_lock);
903 break; 900 break;
904 } 901 }
905  902
906 /* All I/Os should have been processed by now, 903 /* All I/Os should have been processed by now,
907 * xbdi_refcnt should drop to 0 */ 904 * xbdi_refcnt should drop to 0 */
908 xbdi_put(xbdi); 905 xbdi_put(xbdi);
909 KASSERT(xbdi->xbdi_refcnt == 0); 906 KASSERT(xbdi->xbdi_refcnt == 0);
910 mutex_exit(&xbdi->xbdi_lock); 907 mutex_exit(&xbdi->xbdi_lock);
911 kthread_exit(0); 908 kthread_exit(0);
912 break; 909 break;
913 default: 910 default:
914 panic("%s: invalid state %d", 911 panic("%s: invalid state %d",
915 xbdi->xbdi_name, xbdi->xbdi_status); 912 xbdi->xbdi_name, xbdi->xbdi_status);
916 } 913 }
917 } 914 }
918} 915}
919 916
920static void * 917static void *
921xbdback_co_main(struct xbdback_instance *xbdi, void *obj) 918xbdback_co_main(struct xbdback_instance *xbdi, void *obj)
922{ 919{
923 (void)obj; 920 (void)obj;
924 921
925 xbdi->xbdi_req_prod = xbdi->xbdi_ring.ring_n.sring->req_prod; 922 xbdi->xbdi_req_prod = xbdi->xbdi_ring.ring_n.sring->req_prod;
926 xen_rmb(); /* ensure we see all requests up to req_prod */ 923 xen_rmb(); /* ensure we see all requests up to req_prod */
927 /* 924 /*
928 * note that we'll eventually get a full ring of request. 925 * 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) 926 * in this case, MASK_BLKIF_IDX(req_cons) == MASK_BLKIF_IDX(req_prod)
930 */ 927 */
931 xbdi->xbdi_cont = xbdback_co_main_loop; 928 xbdi->xbdi_cont = xbdback_co_main_loop;
932 return xbdi; 929 return xbdi;
933} 930}
934 931
935/* 932/*
936 * Fetch a blkif request from the ring, and pass control to the appropriate 933 * Fetch a blkif request from the ring, and pass control to the appropriate
937 * continuation. 934 * continuation.
938 * If someone asked for disconnection, do not fetch any more request from 935 * If someone asked for disconnection, do not fetch any more request from
939 * the ring. 936 * the ring.
940 */ 937 */
941static void * 938static void *
942xbdback_co_main_loop(struct xbdback_instance *xbdi, void *obj)  939xbdback_co_main_loop(struct xbdback_instance *xbdi, void *obj)
943{ 940{
944 blkif_request_t *req; 941 blkif_request_t *req;
945 blkif_x86_32_request_t *req32; 942 blkif_x86_32_request_t *req32;
946 blkif_x86_64_request_t *req64; 943 blkif_x86_64_request_t *req64;
947 944
948 (void)obj; 945 (void)obj;
949 req = &xbdi->xbdi_xen_req; 946 req = &xbdi->xbdi_xen_req;
950 if (xbdi->xbdi_ring.ring_n.req_cons != xbdi->xbdi_req_prod) { 947 if (xbdi->xbdi_ring.ring_n.req_cons != xbdi->xbdi_req_prod) {
951 switch(xbdi->xbdi_proto) { 948 switch(xbdi->xbdi_proto) {
952 case XBDIP_NATIVE: 949 case XBDIP_NATIVE:
953 memcpy(req, RING_GET_REQUEST(&xbdi->xbdi_ring.ring_n, 950 memcpy(req, RING_GET_REQUEST(&xbdi->xbdi_ring.ring_n,
954 xbdi->xbdi_ring.ring_n.req_cons), 951 xbdi->xbdi_ring.ring_n.req_cons),
955 sizeof(blkif_request_t)); 952 sizeof(blkif_request_t));
956 break; 953 break;
957 case XBDIP_32: 954 case XBDIP_32:
958 req32 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_32, 955 req32 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_32,
959 xbdi->xbdi_ring.ring_n.req_cons); 956 xbdi->xbdi_ring.ring_n.req_cons);
960 req->operation = req32->operation; 957 req->operation = req32->operation;
961 req->nr_segments = req32->nr_segments; 958 req->nr_segments = req32->nr_segments;
962 req->handle = req32->handle; 959 req->handle = req32->handle;
963 req->id = req32->id; 960 req->id = req32->id;
964 req->sector_number = req32->sector_number; 961 req->sector_number = req32->sector_number;
965 break; 962 break;
966  963
967 case XBDIP_64: 964 case XBDIP_64:
968 req64 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_64, 965 req64 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_64,
969 xbdi->xbdi_ring.ring_n.req_cons); 966 xbdi->xbdi_ring.ring_n.req_cons);
970 req->operation = req64->operation; 967 req->operation = req64->operation;
971 req->nr_segments = req64->nr_segments; 968 req->nr_segments = req64->nr_segments;
972 req->handle = req64->handle; 969 req->handle = req64->handle;
973 req->id = req64->id; 970 req->id = req64->id;
974 req->sector_number = req64->sector_number; 971 req->sector_number = req64->sector_number;
975 break; 972 break;
976 } 973 }
977 __insn_barrier(); 974 __insn_barrier();
978 XENPRINTF(("xbdback op %d req_cons 0x%x req_prod 0x%x " 975 XENPRINTF(("xbdback op %d req_cons 0x%x req_prod 0x%x "
979 "resp_prod 0x%x id %" PRIu64 "\n", req->operation, 976 "resp_prod 0x%x id %" PRIu64 "\n", req->operation,
980 xbdi->xbdi_ring.ring_n.req_cons, 977 xbdi->xbdi_ring.ring_n.req_cons,
981 xbdi->xbdi_req_prod, 978 xbdi->xbdi_req_prod,
982 xbdi->xbdi_ring.ring_n.rsp_prod_pvt, 979 xbdi->xbdi_ring.ring_n.rsp_prod_pvt,
983 req->id)); 980 req->id));
984 switch(req->operation) { 981 switch(req->operation) {
985 case BLKIF_OP_READ: 982 case BLKIF_OP_READ:
986 case BLKIF_OP_WRITE: 983 case BLKIF_OP_WRITE:
987 xbdi->xbdi_cont = xbdback_co_io; 984 xbdi->xbdi_cont = xbdback_co_io;
988 break; 985 break;
989 case BLKIF_OP_FLUSH_DISKCACHE: 986 case BLKIF_OP_FLUSH_DISKCACHE:
990 xbdi_get(xbdi); 987 xbdi_get(xbdi);
991 xbdi->xbdi_cont = xbdback_co_cache_flush; 988 xbdi->xbdi_cont = xbdback_co_cache_flush;
992 break; 989 break;
993 default: 990 default:
994 if (ratecheck(&xbdi->xbdi_lasterr_time, 991 if (ratecheck(&xbdi->xbdi_lasterr_time,
995 &xbdback_err_intvl)) { 992 &xbdback_err_intvl)) {
996 printf("%s: unknown operation %d\n", 993 printf("%s: unknown operation %d\n",
997 xbdi->xbdi_name, req->operation); 994 xbdi->xbdi_name, req->operation);
998 } 995 }
999 xbdback_send_reply(xbdi, req->id, req->operation, 996 xbdback_send_reply(xbdi, req->id, req->operation,
1000 BLKIF_RSP_ERROR); 997 BLKIF_RSP_ERROR);
1001 xbdi->xbdi_cont = xbdback_co_main_incr; 998 xbdi->xbdi_cont = xbdback_co_main_incr;
1002 break; 999 break;
1003 } 1000 }
1004 } else { 1001 } else {
1005 KASSERT(xbdi->xbdi_io == NULL); 1002 KASSERT(xbdi->xbdi_io == NULL);
1006 xbdi->xbdi_cont = xbdback_co_main_done2; 1003 xbdi->xbdi_cont = xbdback_co_main_done2;
1007 } 1004 }
1008 return xbdi; 1005 return xbdi;
1009} 1006}
1010 1007
1011/* 1008/*
1012 * Increment consumer index and move on to the next request. In case 1009 * Increment consumer index and move on to the next request. In case
1013 * we want to disconnect, leave continuation now. 1010 * we want to disconnect, leave continuation now.
1014 */ 1011 */
1015static void * 1012static void *
1016xbdback_co_main_incr(struct xbdback_instance *xbdi, void *obj) 1013xbdback_co_main_incr(struct xbdback_instance *xbdi, void *obj)
1017{ 1014{
1018 (void)obj; 1015 (void)obj;
1019 blkif_back_ring_t *ring = &xbdi->xbdi_ring.ring_n; 1016 blkif_back_ring_t *ring = &xbdi->xbdi_ring.ring_n;
1020 1017
1021 ring->req_cons++; 1018 ring->req_cons++;
1022 1019
1023 /* 1020 /*
1024 * Do not bother with locking here when checking for xbdi_status: if 1021 * 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 1022 * we get a transient state, we will get the right value at
1026 * the next increment. 1023 * the next increment.
1027 */ 1024 */
1028 if (xbdi->xbdi_status == DISCONNECTING) 1025 if (xbdi->xbdi_status == DISCONNECTING)
1029 xbdi->xbdi_cont = NULL; 1026 xbdi->xbdi_cont = NULL;
1030 else 1027 else
1031 xbdi->xbdi_cont = xbdback_co_main_loop; 1028 xbdi->xbdi_cont = xbdback_co_main_loop;
1032 1029
1033 /* 1030 /*
1034 * Each time the thread processes a full ring of requests, give 1031 * Each time the thread processes a full ring of requests, give
1035 * a chance to other threads to process I/Os too 1032 * a chance to other threads to process I/Os too
1036 */ 1033 */
1037 if ((ring->req_cons % BLKIF_RING_SIZE) == 0) 1034 if ((ring->req_cons % BLKIF_RING_SIZE) == 0)
1038 yield(); 1035 yield();
1039 1036
1040 return xbdi; 1037 return xbdi;
1041} 1038}
1042 1039
1043/* 1040/*
1044 * Check for requests in the instance's ring. In case there are, start again 1041 * Check for requests in the instance's ring. In case there are, start again
1045 * from the beginning. If not, stall. 1042 * from the beginning. If not, stall.
1046 */ 1043 */
1047static void * 1044static void *
1048xbdback_co_main_done2(struct xbdback_instance *xbdi, void *obj) 1045xbdback_co_main_done2(struct xbdback_instance *xbdi, void *obj)
1049{ 1046{
1050 int work_to_do; 1047 int work_to_do;
1051 1048
1052 RING_FINAL_CHECK_FOR_REQUESTS(&xbdi->xbdi_ring.ring_n, work_to_do); 1049 RING_FINAL_CHECK_FOR_REQUESTS(&xbdi->xbdi_ring.ring_n, work_to_do);
1053 if (work_to_do) 1050 if (work_to_do)
1054 xbdi->xbdi_cont = xbdback_co_main; 1051 xbdi->xbdi_cont = xbdback_co_main;
1055 else 1052 else
1056 xbdi->xbdi_cont = NULL; 1053 xbdi->xbdi_cont = NULL;
1057 1054
1058 return xbdi; 1055 return xbdi;
1059} 1056}
1060 1057
1061/* 1058/*
1062 * Frontend requested a cache flush operation. 1059 * Frontend requested a cache flush operation.
1063 */ 1060 */
1064static void * 1061static void *
1065xbdback_co_cache_flush(struct xbdback_instance *xbdi, void *obj __unused) 1062xbdback_co_cache_flush(struct xbdback_instance *xbdi, void *obj __unused)
1066{ 1063{
1067 if (xbdi->xbdi_pendingreqs > 0) { 1064 if (xbdi->xbdi_pendingreqs > 0) {
1068 /* 1065 /*
1069 * There are pending requests. 1066 * There are pending requests.
1070 * Event or iodone() will restart processing 1067 * Event or iodone() will restart processing
1071 */ 1068 */
1072 xbdi->xbdi_cont = NULL; 1069 xbdi->xbdi_cont = NULL;
1073 xbdi_put(xbdi); 1070 xbdi_put(xbdi);
1074 return NULL; 1071 return NULL;
1075 } 1072 }
1076 xbdi->xbdi_cont = xbdback_co_cache_doflush; 1073 xbdi->xbdi_cont = xbdback_co_cache_doflush;
1077 return xbdback_pool_get(&xbdback_io_pool, xbdi); 1074 return xbdback_pool_get(&xbdback_io_pool, xbdi);
1078} 1075}
1079 1076
1080/* Start the flush work */ 1077/* Start the flush work */
1081static void * 1078static void *
1082xbdback_co_cache_doflush(struct xbdback_instance *xbdi, void *obj) 1079xbdback_co_cache_doflush(struct xbdback_instance *xbdi, void *obj)
1083{ 1080{
1084 struct xbdback_io *xbd_io; 1081 struct xbdback_io *xbd_io;
1085 1082
1086 XENPRINTF(("xbdback_co_cache_doflush %p %p\n", xbdi, obj)); 1083 XENPRINTF(("xbdback_co_cache_doflush %p %p\n", xbdi, obj));
1087 xbd_io = xbdi->xbdi_io = obj; 1084 xbd_io = xbdi->xbdi_io = obj;
1088 xbd_io->xio_xbdi = xbdi; 1085 xbd_io->xio_xbdi = xbdi;
1089 xbd_io->xio_operation = xbdi->xbdi_xen_req.operation; 1086 xbd_io->xio_operation = xbdi->xbdi_xen_req.operation;
1090 xbd_io->xio_id = xbdi->xbdi_xen_req.id; 1087 xbd_io->xio_id = xbdi->xbdi_xen_req.id;
1091 xbdi->xbdi_cont = xbdback_co_do_io; 1088 xbdi->xbdi_cont = xbdback_co_do_io;
1092 return xbdi; 1089 return xbdi;
1093} 1090}
1094 1091
1095/* 1092/*
1096 * A read or write I/O request must be processed. Do some checks first, 1093 * A read or write I/O request must be processed. Do some checks first,
1097 * then get the segment information directly from the ring request. 1094 * then get the segment information directly from the ring request.
1098 */ 1095 */
1099static void * 1096static void *
1100xbdback_co_io(struct xbdback_instance *xbdi, void *obj) 1097xbdback_co_io(struct xbdback_instance *xbdi, void *obj)
1101{  1098{
1102 int i, error; 1099 int i, error;
1103 blkif_request_t *req; 1100 blkif_request_t *req;
1104 blkif_x86_32_request_t *req32; 1101 blkif_x86_32_request_t *req32;
1105 blkif_x86_64_request_t *req64; 1102 blkif_x86_64_request_t *req64;
1106 1103
1107 (void)obj; 1104 (void)obj;
1108 1105
1109 /* some sanity checks */ 1106 /* some sanity checks */
1110 req = &xbdi->xbdi_xen_req; 1107 req = &xbdi->xbdi_xen_req;
1111 if (req->nr_segments < 1 || 1108 if (req->nr_segments < 1 ||
1112 req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { 1109 req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST) {
1113 if (ratecheck(&xbdi->xbdi_lasterr_time, 1110 if (ratecheck(&xbdi->xbdi_lasterr_time,
1114 &xbdback_err_intvl)) { 1111 &xbdback_err_intvl)) {
1115 printf("%s: invalid number of segments: %d\n", 1112 printf("%s: invalid number of segments: %d\n",
1116 xbdi->xbdi_name, 1113 xbdi->xbdi_name,
1117 xbdi->xbdi_xen_req.nr_segments); 1114 xbdi->xbdi_xen_req.nr_segments);
1118 } 1115 }
1119 error = EINVAL; 1116 error = EINVAL;
1120 goto end; 1117 goto end;
1121 } 1118 }
1122 1119
1123 KASSERT(req->operation == BLKIF_OP_READ || 1120 KASSERT(req->operation == BLKIF_OP_READ ||
1124 req->operation == BLKIF_OP_WRITE); 1121 req->operation == BLKIF_OP_WRITE);
1125 if (req->operation == BLKIF_OP_WRITE) { 1122 if (req->operation == BLKIF_OP_WRITE) {
1126 if (xbdi->xbdi_ro) { 1123 if (xbdi->xbdi_ro) {
1127 error = EROFS; 1124 error = EROFS;
1128 goto end; 1125 goto end;
1129 } 1126 }
1130 } 1127 }
1131 1128
1132 /* copy request segments */ 1129 /* copy request segments */
1133 switch(xbdi->xbdi_proto) { 1130 switch(xbdi->xbdi_proto) {
1134 case XBDIP_NATIVE: 1131 case XBDIP_NATIVE:
1135 /* already copied in xbdback_co_main_loop */ 1132 /* already copied in xbdback_co_main_loop */
1136 break; 1133 break;
1137 case XBDIP_32: 1134 case XBDIP_32:
1138 req32 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_32, 1135 req32 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_32,
1139 xbdi->xbdi_ring.ring_n.req_cons); 1136 xbdi->xbdi_ring.ring_n.req_cons);
1140 for (i = 0; i < req->nr_segments; i++) 1137 for (i = 0; i < req->nr_segments; i++)
1141 req->seg[i] = req32->seg[i]; 1138 req->seg[i] = req32->seg[i];
1142 break; 1139 break;
1143 case XBDIP_64: 1140 case XBDIP_64:
1144 req64 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_64, 1141 req64 = RING_GET_REQUEST(&xbdi->xbdi_ring.ring_64,
1145 xbdi->xbdi_ring.ring_n.req_cons); 1142 xbdi->xbdi_ring.ring_n.req_cons);
1146 for (i = 0; i < req->nr_segments; i++) 1143 for (i = 0; i < req->nr_segments; i++)
1147 req->seg[i] = req64->seg[i]; 1144 req->seg[i] = req64->seg[i];
1148 break; 1145 break;
1149 } 1146 }
1150 1147
1151 KASSERT(xbdi->xbdi_io == NULL); 1148 KASSERT(xbdi->xbdi_io == NULL);
1152 xbdi->xbdi_cont = xbdback_co_io_gotio; 1149 xbdi->xbdi_cont = xbdback_co_io_gotio;
1153 return xbdback_pool_get(&xbdback_io_pool, xbdi); 1150 return xbdback_pool_get(&xbdback_io_pool, xbdi);
1154 1151
1155 end: 1152 end:
1156 xbdback_send_reply(xbdi, xbdi->xbdi_xen_req.id, 1153 xbdback_send_reply(xbdi, xbdi->xbdi_xen_req.id,
1157 xbdi->xbdi_xen_req.operation, 1154 xbdi->xbdi_xen_req.operation,
1158 (error == EROFS) ? BLKIF_RSP_EOPNOTSUPP : BLKIF_RSP_ERROR); 1155 (error == EROFS) ? BLKIF_RSP_EOPNOTSUPP : BLKIF_RSP_ERROR);
1159 xbdi->xbdi_cont = xbdback_co_main_incr; 1156 xbdi->xbdi_cont = xbdback_co_main_incr;
1160 return xbdi; 1157 return xbdi;
1161} 1158}
1162 1159
1163/* Prepare an I/O buffer for a xbdback instance */ 1160/* Prepare an I/O buffer for a xbdback instance */
1164static void * 1161static void *
1165xbdback_co_io_gotio(struct xbdback_instance *xbdi, void *obj) 1162xbdback_co_io_gotio(struct xbdback_instance *xbdi, void *obj)
1166{ 1163{
1167 struct xbdback_io *xbd_io; 1164 struct xbdback_io *xbd_io;
1168 int buf_flags; 1165 int buf_flags;
1169 size_t bcount; 1166 size_t bcount;
1170 blkif_request_t *req; 1167 blkif_request_t *req;
1171 1168
1172 xbdi_get(xbdi); 1169 xbdi_get(xbdi);
1173 atomic_inc_uint(&xbdi->xbdi_pendingreqs); 1170 atomic_inc_uint(&xbdi->xbdi_pendingreqs);
1174  1171
1175 req = &xbdi->xbdi_xen_req; 1172 req = &xbdi->xbdi_xen_req;
1176 xbd_io = xbdi->xbdi_io = obj; 1173 xbd_io = xbdi->xbdi_io = obj;
1177 memset(xbd_io, 0, sizeof(*xbd_io)); 1174 memset(xbd_io, 0, sizeof(*xbd_io));
1178 buf_init(&xbd_io->xio_buf); 1175 buf_init(&xbd_io->xio_buf);
1179 xbd_io->xio_xbdi = xbdi; 1176 xbd_io->xio_xbdi = xbdi;
1180 xbd_io->xio_operation = req->operation; 1177 xbd_io->xio_operation = req->operation;
1181 xbd_io->xio_id = req->id; 1178 xbd_io->xio_id = req->id;
1182 1179
1183 /* Process segments */ 1180 /* Process segments */
1184 bcount = 0; 1181 bcount = 0;
1185 for (int i = 0; i < req->nr_segments; i++) { 1182 for (int i = 0; i < req->nr_segments; i++) {
1186 xbd_io->xio_gref[i] = req->seg[i].gref; 1183 xbd_io->xio_gref[i] = req->seg[i].gref;
1187 bcount += (req->seg[i].last_sect - req->seg[i].first_sect + 1) 1184 bcount += (req->seg[i].last_sect - req->seg[i].first_sect + 1)
1188 * VBD_BSIZE; 1185 * VBD_BSIZE;
1189 } 1186 }
1190 KASSERT(bcount <= MAXPHYS); 1187 KASSERT(bcount <= MAXPHYS);
1191 xbd_io->xio_nrma = req->nr_segments; 1188 xbd_io->xio_nrma = req->nr_segments;
1192 1189
1193 xbd_io->xio_start_offset = req->seg[0].first_sect * VBD_BSIZE; 1190 xbd_io->xio_start_offset = req->seg[0].first_sect * VBD_BSIZE;
1194 KASSERT(xbd_io->xio_start_offset < PAGE_SIZE); 1191 KASSERT(xbd_io->xio_start_offset < PAGE_SIZE);
1195 KASSERT(bcount + xbd_io->xio_start_offset < VBD_VA_SIZE); 1192 KASSERT(bcount + xbd_io->xio_start_offset < VBD_VA_SIZE);
1196 1193
1197 if (xbdi->xbdi_xen_req.operation == BLKIF_OP_WRITE) { 1194 if (xbdi->xbdi_xen_req.operation == BLKIF_OP_WRITE) {
1198 buf_flags = B_WRITE; 1195 buf_flags = B_WRITE;
1199 } else { 1196 } else {
1200 buf_flags = B_READ; 1197 buf_flags = B_READ;
1201 } 1198 }
1202 1199
1203 xbd_io->xio_buf.b_flags = buf_flags; 1200 xbd_io->xio_buf.b_flags = buf_flags;
1204 xbd_io->xio_buf.b_cflags = 0; 1201 xbd_io->xio_buf.b_cflags = 0;
1205 xbd_io->xio_buf.b_oflags = 0; 1202 xbd_io->xio_buf.b_oflags = 0;
1206 xbd_io->xio_buf.b_iodone = xbdback_iodone; 1203 xbd_io->xio_buf.b_iodone = xbdback_iodone;
1207 xbd_io->xio_buf.b_proc = NULL; 1204 xbd_io->xio_buf.b_proc = NULL;
1208 xbd_io->xio_buf.b_vp = xbdi->xbdi_vp; 1205 xbd_io->xio_buf.b_vp = xbdi->xbdi_vp;
1209 xbd_io->xio_buf.b_objlock = xbdi->xbdi_vp->v_interlock; 1206 xbd_io->xio_buf.b_objlock = xbdi->xbdi_vp->v_interlock;
1210 xbd_io->xio_buf.b_dev = xbdi->xbdi_dev; 1207 xbd_io->xio_buf.b_dev = xbdi->xbdi_dev;
1211 xbd_io->xio_buf.b_blkno = req->sector_number; 1208 xbd_io->xio_buf.b_blkno = req->sector_number;
1212 xbd_io->xio_buf.b_bcount = bcount; 1209 xbd_io->xio_buf.b_bcount = bcount;
1213 xbd_io->xio_buf.b_data = NULL; 1210 xbd_io->xio_buf.b_data = NULL;
1214 xbd_io->xio_buf.b_private = xbd_io; 1211 xbd_io->xio_buf.b_private = xbd_io;
1215 1212
1216 xbdi->xbdi_cont = xbdback_co_do_io; 1213 xbdi->xbdi_cont = xbdback_co_do_io;
1217 return xbdback_map_shm(xbdi->xbdi_io); 1214 return xbdback_map_shm(xbdi->xbdi_io);
1218} 1215}
1219 1216
1220static void 1217static void
1221xbdback_io_error(struct xbdback_io *xbd_io, int error) 1218xbdback_io_error(struct xbdback_io *xbd_io, int error)
1222{ 1219{
1223 xbd_io->xio_buf.b_error = error; 1220 xbd_io->xio_buf.b_error = error;
1224 xbdback_iodone(&xbd_io->xio_buf); 1221 xbdback_iodone(&xbd_io->xio_buf);
1225} 1222}
1226 1223
1227/* 1224/*
1228 * Main xbdback I/O routine. It can either perform a flush operation or 1225 * Main xbdback I/O routine. It can either perform a flush operation or
1229 * schedule a read/write operation. 1226 * schedule a read/write operation.
1230 */ 1227 */
1231static void * 1228static void *
1232xbdback_co_do_io(struct xbdback_instance *xbdi, void *obj) 1229xbdback_co_do_io(struct xbdback_instance *xbdi, void *obj)
1233{ 1230{
1234 struct xbdback_io *xbd_io = xbdi->xbdi_io; 1231 struct xbdback_io *xbd_io = xbdi->xbdi_io;
1235 1232
1236 switch (xbd_io->xio_operation) { 1233 switch (xbd_io->xio_operation) {
1237 case BLKIF_OP_FLUSH_DISKCACHE: 1234 case BLKIF_OP_FLUSH_DISKCACHE:
1238 { 1235 {
1239 int error; 1236 int error;
1240 int force = 1; 1237 int force = 1;
1241 1238
1242 error = VOP_IOCTL(xbdi->xbdi_vp, DIOCCACHESYNC, &force, FWRITE, 1239 error = VOP_IOCTL(xbdi->xbdi_vp, DIOCCACHESYNC, &force, FWRITE,
1243 kauth_cred_get()); 1240 kauth_cred_get());
1244 if (error) { 1241 if (error) {
1245 aprint_error("xbdback %s: DIOCCACHESYNC returned %d\n", 1242 aprint_error("xbdback %s: DIOCCACHESYNC returned %d\n",
1246 xbdi->xbdi_xbusd->xbusd_path, error); 1243 xbdi->xbdi_xbusd->xbusd_path, error);
1247 if (error == EOPNOTSUPP || error == ENOTTY) 1244 if (error == EOPNOTSUPP || error == ENOTTY)
1248 error = BLKIF_RSP_EOPNOTSUPP; 1245 error = BLKIF_RSP_EOPNOTSUPP;
1249 else 1246 else