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

--- 287 unchanged lines hidden ---