Deleted Added
sdiff udiff text old ( 248477 ) new ( 249813 )
full compact
1/*-
2 * Copyright (c) 2011 NetApp, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/usr.sbin/bhyve/pci_virtio_block.c 248477 2013-03-18 22:38:30Z neel $
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_virtio_block.c 248477 2013-03-18 22:38:30Z neel $");
31
32#include <sys/param.h>
33#include <sys/linker_set.h>
34#include <sys/stat.h>
35#include <sys/uio.h>
36#include <sys/ioctl.h>
37#include <sys/disk.h>
38

--- 143 unchanged lines hidden (view full) ---

182 return (ndesc);
183}
184
185static void
186pci_vtblk_update_status(struct pci_vtblk_softc *sc, uint32_t value)
187{
188 if (value == 0) {
189 DPRINTF(("vtblk: device reset requested !\n"));
190 }
191
192 sc->vbsc_status = value;
193}
194
195static void
196pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vring_hqueue *hq)
197{
198 struct iovec iov[VTBLK_MAXSEGS];
199 struct virtio_blk_hdr *vbh;
200 struct virtio_desc *vd, *vid;
201 struct virtio_used *vu;
202 uint8_t *status;
203 int i;
204 int err;
205 int iolen;
206 int nsegs;
207 int uidx, aidx, didx;
208 int writeop, type;
209 off_t offset;
210
211 uidx = *hq->hq_used_idx;
212 aidx = hq->hq_cur_aidx;
213 didx = hq->hq_avail_ring[aidx % hq->hq_size];
214 assert(didx >= 0 && didx < hq->hq_size);
215
216 vd = &hq->hq_dtable[didx];
217
218 /*
219 * Verify that the descriptor is indirect, and obtain
220 * the pointer to the indirect descriptor.
221 * There has to be space for at least 3 descriptors
222 * in the indirect descriptor array: the block header,
223 * 1 or more data descriptors, and a status byte.
224 */
225 assert(vd->vd_flags & VRING_DESC_F_INDIRECT);
226
227 nsegs = vd->vd_len / sizeof(struct virtio_desc);
228 assert(nsegs >= 3);
229 assert(nsegs < VTBLK_MAXSEGS + 2);
230
231 vid = paddr_guest2host(vtblk_ctx(sc), vd->vd_addr, vd->vd_len);
232 assert((vid->vd_flags & VRING_DESC_F_INDIRECT) == 0);
233
234 /*
235 * The first descriptor will be the read-only fixed header
236 */
237 vbh = paddr_guest2host(vtblk_ctx(sc), vid[0].vd_addr,
238 sizeof(struct virtio_blk_hdr));
239 assert(vid[0].vd_len == sizeof(struct virtio_blk_hdr));
240 assert(vid[0].vd_flags & VRING_DESC_F_NEXT);
241 assert((vid[0].vd_flags & VRING_DESC_F_WRITE) == 0);
242
243 /*
244 * XXX
245 * The guest should not be setting the BARRIER flag because
246 * we don't advertise the capability.
247 */
248 type = vbh->vbh_type & ~VBH_FLAG_BARRIER;
249 writeop = (type == VBH_OP_WRITE);
250
251 offset = vbh->vbh_sector * DEV_BSIZE;
252
253 /*
254 * Build up the iovec based on the guest's data descriptors
255 */
256 for (i = 1, iolen = 0; i < nsegs - 1; i++) {
257 iov[i-1].iov_base = paddr_guest2host(vtblk_ctx(sc),
258 vid[i].vd_addr, vid[i].vd_len);
259 iov[i-1].iov_len = vid[i].vd_len;
260 iolen += vid[i].vd_len;
261
262 assert(vid[i].vd_flags & VRING_DESC_F_NEXT);
263 assert((vid[i].vd_flags & VRING_DESC_F_INDIRECT) == 0);
264
265 /*
266 * - write op implies read-only descriptor,
267 * - read op implies write-only descriptor,
268 * therefore test the inverse of the descriptor bit
269 * to the op.
270 */
271 assert(((vid[i].vd_flags & VRING_DESC_F_WRITE) == 0) ==
272 writeop);
273 }
274
275 /* Lastly, get the address of the status byte */
276 status = paddr_guest2host(vtblk_ctx(sc), vid[nsegs - 1].vd_addr, 1);
277 assert(vid[nsegs - 1].vd_len == 1);
278 assert((vid[nsegs - 1].vd_flags & VRING_DESC_F_NEXT) == 0);
279 assert(vid[nsegs - 1].vd_flags & VRING_DESC_F_WRITE);
280
281 DPRINTF(("virtio-block: %s op, %d bytes, %d segs, offset %ld\n\r",
282 writeop ? "write" : "read", iolen, nsegs - 2, offset));
283
284 if (writeop){
285 err = pwritev(sc->vbsc_fd, iov, nsegs - 2, offset);
286 } else {
287 err = preadv(sc->vbsc_fd, iov, nsegs - 2, offset);
288 }
289
290 *status = err < 0 ? VTBLK_S_IOERR : VTBLK_S_OK;
291
292 /*
293 * Return the single indirect descriptor back to the host
294 */
295 vu = &hq->hq_used_ring[uidx % hq->hq_size];
296 vu->vu_idx = didx;
297 vu->vu_tlen = 1;
298 hq->hq_cur_aidx++;
299 *hq->hq_used_idx += 1;
300}
301
302static void
303pci_vtblk_qnotify(struct pci_vtblk_softc *sc)
304{
305 struct vring_hqueue *hq = &sc->vbsc_q;
306 int i;
307 int ndescs;
308
309 /*
310 * Calculate number of ring entries to process
311 */
312 ndescs = hq_num_avail(hq);
313
314 if (ndescs == 0)
315 return;
316
317 /*
318 * Run through all the entries, placing them into iovecs and
319 * sending when an end-of-packet is found
320 */
321 for (i = 0; i < ndescs; i++)
322 pci_vtblk_proc(sc, hq);
323
324 /*
325 * Generate an interrupt if able
326 */
327 if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
328 if (use_msix) {
329 pci_generate_msix(sc->vbsc_pi, sc->msix_table_idx_req);
330 } else if (sc->vbsc_isr == 0) {
331 sc->vbsc_isr = 1;
332 pci_generate_msi(sc->vbsc_pi, 0);
333 }
334 }
335
336}
337
338static void
339pci_vtblk_ring_init(struct pci_vtblk_softc *sc, uint64_t pfn)
340{
341 struct vring_hqueue *hq;
342
343 sc->vbsc_pfn = pfn << VRING_PFN;
344
345 /*
346 * Set up host pointers to the various parts of the

--- 287 unchanged lines hidden ---