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 --- |