]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/pci_virtio_block.c
Upgrade to 1.6.16
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / pci_virtio_block.c
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  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
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$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
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
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdint.h>
44 #include <string.h>
45 #include <strings.h>
46 #include <unistd.h>
47 #include <assert.h>
48 #include <pthread.h>
49
50 #include "bhyverun.h"
51 #include "pci_emul.h"
52 #include "virtio.h"
53
54 #define VTBLK_RINGSZ    64
55
56 #define VTBLK_CFGSZ     28
57
58 #define VTBLK_R_CFG             VTCFG_R_CFG1 
59 #define VTBLK_R_CFG_END         VTBLK_R_CFG + VTBLK_CFGSZ -1
60 #define VTBLK_R_MAX             VTBLK_R_CFG_END
61
62 #define VTBLK_REGSZ             VTBLK_R_MAX+1
63
64 #define VTBLK_MAXSEGS   32
65
66 #define VTBLK_S_OK      0
67 #define VTBLK_S_IOERR   1
68
69 /*
70  * Host capabilities
71  */
72 #define VTBLK_S_HOSTCAPS      \
73   ( 0x00000004 |        /* host maximum request segments */ \
74     0x10000000 )        /* supports indirect descriptors */
75
76 static int use_msix = 1;
77
78 struct vring_hqueue {
79         /* Internal state */
80         uint16_t        hq_size;
81         uint16_t        hq_cur_aidx;            /* trails behind 'avail_idx' */
82
83          /* Host-context pointers to the queue */
84         struct virtio_desc *hq_dtable;
85         uint16_t        *hq_avail_flags;
86         uint16_t        *hq_avail_idx;          /* monotonically increasing */
87         uint16_t        *hq_avail_ring;
88
89         uint16_t        *hq_used_flags;
90         uint16_t        *hq_used_idx;           /* monotonically increasing */
91         struct virtio_used *hq_used_ring;
92 };
93
94 /*
95  * Config space
96  */
97 struct vtblk_config {
98         uint64_t        vbc_capacity;
99         uint32_t        vbc_size_max;
100         uint32_t        vbc_seg_max;
101         uint16_t        vbc_geom_c;
102         uint8_t         vbc_geom_h;
103         uint8_t         vbc_geom_s;
104         uint32_t        vbc_blk_size;
105         uint32_t        vbc_sectors_max;
106 } __packed;
107 CTASSERT(sizeof(struct vtblk_config) == VTBLK_CFGSZ);
108
109 /*
110  * Fixed-size block header
111  */
112 struct virtio_blk_hdr {
113 #define VBH_OP_READ     0
114 #define VBH_OP_WRITE    1
115         uint32_t        vbh_type;
116         uint32_t        vbh_ioprio;
117         uint64_t        vbh_sector;
118 } __packed;
119
120 /*
121  * Debug printf
122  */
123 static int pci_vtblk_debug;
124 #define DPRINTF(params) if (pci_vtblk_debug) printf params
125 #define WPRINTF(params) printf params
126
127 /*
128  * Per-device softc
129  */
130 struct pci_vtblk_softc {
131         struct pci_devinst *vbsc_pi;
132         int             vbsc_fd;
133         int             vbsc_status;
134         int             vbsc_isr;
135         int             vbsc_lastq;
136         uint32_t        vbsc_features;
137         uint64_t        vbsc_pfn;
138         struct vring_hqueue vbsc_q;
139         struct vtblk_config vbsc_cfg;   
140         uint16_t        msix_table_idx_req;
141         uint16_t        msix_table_idx_cfg;
142 };
143
144 /* 
145  * Return the size of IO BAR that maps virtio header and device specific
146  * region. The size would vary depending on whether MSI-X is enabled or 
147  * not
148  */ 
149 static uint64_t
150 pci_vtblk_iosize(struct pci_devinst *pi)
151 {
152
153         if (pci_msix_enabled(pi)) 
154                 return (VTBLK_REGSZ);
155         else
156                 return (VTBLK_REGSZ - (VTCFG_R_CFG1 - VTCFG_R_MSIX));
157 }
158
159 /*
160  * Return the number of available descriptors in the vring taking care
161  * of the 16-bit index wraparound.
162  */
163 static int
164 hq_num_avail(struct vring_hqueue *hq)
165 {
166         int ndesc;
167
168         if (*hq->hq_avail_idx >= hq->hq_cur_aidx)
169                 ndesc = *hq->hq_avail_idx - hq->hq_cur_aidx;
170         else
171                 ndesc = UINT16_MAX - hq->hq_cur_aidx + *hq->hq_avail_idx + 1;
172
173         assert(ndesc >= 0 && ndesc <= hq->hq_size);
174
175         return (ndesc);
176 }
177
178 static void
179 pci_vtblk_update_status(struct pci_vtblk_softc *sc, uint32_t value)
180 {
181         if (value == 0) {
182                 DPRINTF(("vtblk: device reset requested !\n"));
183         }
184
185         sc->vbsc_status = value;
186 }
187
188 static void
189 pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vring_hqueue *hq)
190 {
191         struct iovec iov[VTBLK_MAXSEGS];
192         struct virtio_blk_hdr *vbh;
193         struct virtio_desc *vd, *vid;
194         struct virtio_used *vu;
195         uint8_t *status;
196         int i;
197         int err;
198         int iolen;
199         int nsegs;
200         int uidx, aidx, didx;
201         int writeop;
202         off_t offset;
203
204         uidx = *hq->hq_used_idx;
205         aidx = hq->hq_cur_aidx;
206         didx = hq->hq_avail_ring[aidx % hq->hq_size];
207         assert(didx >= 0 && didx < hq->hq_size);
208
209         vd = &hq->hq_dtable[didx];
210
211         /*
212          * Verify that the descriptor is indirect, and obtain
213          * the pointer to the indirect descriptor.
214          * There has to be space for at least 3 descriptors
215          * in the indirect descriptor array: the block header,
216          * 1 or more data descriptors, and a status byte.
217          */
218         assert(vd->vd_flags & VRING_DESC_F_INDIRECT);
219
220         nsegs = vd->vd_len / sizeof(struct virtio_desc);
221         assert(nsegs >= 3);
222         assert(nsegs < VTBLK_MAXSEGS + 2);
223
224         vid = paddr_guest2host(vd->vd_addr);
225         assert((vid->vd_flags & VRING_DESC_F_INDIRECT) == 0);
226
227         /*
228          * The first descriptor will be the read-only fixed header
229          */
230         vbh = paddr_guest2host(vid[0].vd_addr);
231         assert(vid[0].vd_len == sizeof(struct virtio_blk_hdr));
232         assert(vid[0].vd_flags & VRING_DESC_F_NEXT);
233         assert((vid[0].vd_flags & VRING_DESC_F_WRITE) == 0);
234
235         writeop = (vbh->vbh_type == VBH_OP_WRITE);
236
237         offset = vbh->vbh_sector * DEV_BSIZE;
238
239         /*
240          * Build up the iovec based on the guest's data descriptors
241          */
242         for (i = 1, iolen = 0; i < nsegs - 1; i++) {
243                 iov[i-1].iov_base = paddr_guest2host(vid[i].vd_addr);
244                 iov[i-1].iov_len = vid[i].vd_len;
245                 iolen += vid[i].vd_len;
246
247                 assert(vid[i].vd_flags & VRING_DESC_F_NEXT);
248                 assert((vid[i].vd_flags & VRING_DESC_F_INDIRECT) == 0);
249
250                 /*
251                  * - write op implies read-only descriptor,
252                  * - read op implies write-only descriptor,
253                  * therefore test the inverse of the descriptor bit
254                  * to the op.
255                  */
256                 assert(((vid[i].vd_flags & VRING_DESC_F_WRITE) == 0) ==
257                        writeop);
258         }
259
260         /* Lastly, get the address of the status byte */
261         status = paddr_guest2host(vid[nsegs - 1].vd_addr);
262         assert(vid[nsegs - 1].vd_len == 1);
263         assert((vid[nsegs - 1].vd_flags & VRING_DESC_F_NEXT) == 0);
264         assert(vid[nsegs - 1].vd_flags & VRING_DESC_F_WRITE);
265
266         DPRINTF(("virtio-block: %s op, %d bytes, %d segs, offset %ld\n\r", 
267                  writeop ? "write" : "read", iolen, nsegs - 2, offset));
268
269         if (writeop){
270                 err = pwritev(sc->vbsc_fd, iov, nsegs - 2, offset);
271         } else {
272                 err = preadv(sc->vbsc_fd, iov, nsegs - 2, offset);
273         }
274
275         *status = err < 0 ? VTBLK_S_IOERR : VTBLK_S_OK;
276
277         /*
278          * Return the single indirect descriptor back to the host
279          */
280         vu = &hq->hq_used_ring[uidx % hq->hq_size];
281         vu->vu_idx = didx;
282         vu->vu_tlen = 1;
283         hq->hq_cur_aidx++;
284         *hq->hq_used_idx += 1;
285 }
286
287 static void
288 pci_vtblk_qnotify(struct pci_vtblk_softc *sc)
289 {
290         struct vring_hqueue *hq = &sc->vbsc_q;
291         int i;
292         int ndescs;
293
294         /*
295          * Calculate number of ring entries to process
296          */
297         ndescs = hq_num_avail(hq);
298
299         if (ndescs == 0)
300                 return;
301
302         /*
303          * Run through all the entries, placing them into iovecs and
304          * sending when an end-of-packet is found
305          */
306         for (i = 0; i < ndescs; i++)
307                 pci_vtblk_proc(sc, hq);
308
309         /*
310          * Generate an interrupt if able
311          */
312         if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) { 
313                 if (use_msix) {
314                         pci_generate_msix(sc->vbsc_pi, sc->msix_table_idx_req); 
315                 } else if (sc->vbsc_isr == 0) {
316                         sc->vbsc_isr = 1;
317                         pci_generate_msi(sc->vbsc_pi, 0);
318                 }
319         }
320         
321 }
322
323 static void
324 pci_vtblk_ring_init(struct pci_vtblk_softc *sc, uint64_t pfn)
325 {
326         struct vring_hqueue *hq;
327
328         sc->vbsc_pfn = pfn << VRING_PFN;
329         
330         /*
331          * Set up host pointers to the various parts of the
332          * queue
333          */
334         hq = &sc->vbsc_q;
335         hq->hq_size = VTBLK_RINGSZ;
336
337         hq->hq_dtable = paddr_guest2host(pfn << VRING_PFN);
338         hq->hq_avail_flags =  (uint16_t *)(hq->hq_dtable + hq->hq_size);
339         hq->hq_avail_idx = hq->hq_avail_flags + 1;
340         hq->hq_avail_ring = hq->hq_avail_flags + 2;
341         hq->hq_used_flags = (uint16_t *)roundup2((uintptr_t)hq->hq_avail_ring,
342                                                  VRING_ALIGN);
343         hq->hq_used_idx = hq->hq_used_flags + 1;
344         hq->hq_used_ring = (struct virtio_used *)(hq->hq_used_flags + 2);
345
346         /*
347          * Initialize queue indexes
348          */
349         hq->hq_cur_aidx = 0;
350 }
351
352 static int
353 pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
354 {
355         struct stat sbuf;
356         struct pci_vtblk_softc *sc;
357         off_t size;     
358         int fd;
359         int sectsz;
360         const char *env_msi;
361
362         if (opts == NULL) {
363                 printf("virtio-block: backing device required\n");
364                 return (1);
365         }
366
367         /*
368          * Access to guest memory is required. Fail if
369          * memory not mapped
370          */
371         if (paddr_guest2host(0) == NULL)
372                 return (1);
373
374         /*
375          * The supplied backing file has to exist
376          */
377         fd = open(opts, O_RDWR);
378         if (fd < 0) {
379                 perror("Could not open backing file");
380                 return (1);
381         }
382
383         if (fstat(fd, &sbuf) < 0) {
384                 perror("Could not stat backing file");
385                 close(fd);
386                 return (1);
387         }
388
389         /*
390          * Deal with raw devices
391          */
392         size = sbuf.st_size;
393         sectsz = DEV_BSIZE;
394         if (S_ISCHR(sbuf.st_mode)) {
395                 if (ioctl(fd, DIOCGMEDIASIZE, &size) < 0 ||
396                     ioctl(fd, DIOCGSECTORSIZE, &sectsz)) {
397                         perror("Could not fetch dev blk/sector size");
398                         close(fd);
399                         return (1);
400                 }
401                 assert(size != 0);
402                 assert(sectsz != 0);
403         }
404
405         sc = malloc(sizeof(struct pci_vtblk_softc));
406         memset(sc, 0, sizeof(struct pci_vtblk_softc));
407
408         pi->pi_arg = sc;
409         sc->vbsc_pi = pi;
410         sc->vbsc_fd = fd;
411
412         /* setup virtio block config space */
413         sc->vbsc_cfg.vbc_capacity = size / sectsz;
414         sc->vbsc_cfg.vbc_seg_max = VTBLK_MAXSEGS;
415         sc->vbsc_cfg.vbc_blk_size = sectsz;
416         sc->vbsc_cfg.vbc_size_max = 0;  /* not negotiated */
417         sc->vbsc_cfg.vbc_geom_c = 0;    /* no geometry */
418         sc->vbsc_cfg.vbc_geom_h = 0;
419         sc->vbsc_cfg.vbc_geom_s = 0;
420         sc->vbsc_cfg.vbc_sectors_max = 0;
421
422         /* initialize config space */
423         pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_BLOCK);
424         pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
425         pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);
426         pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_BLOCK);
427
428         if ((env_msi = getenv("BHYVE_USE_MSI"))) {
429                 if (strcasecmp(env_msi, "yes") == 0)
430                         use_msix = 0;
431         } 
432
433         if (use_msix) {
434                 /* MSI-X Support */
435                 sc->msix_table_idx_req = VIRTIO_MSI_NO_VECTOR;  
436                 sc->msix_table_idx_cfg = VIRTIO_MSI_NO_VECTOR;  
437                 
438                 if (pci_emul_add_msixcap(pi, 2, 1))
439                         return (1);
440         } else {
441                 /* MSI Support */       
442                 pci_emul_add_msicap(pi, 1);
443         }       
444         
445         pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VTBLK_REGSZ);
446
447         return (0);
448 }
449
450 static uint64_t
451 vtblk_adjust_offset(struct pci_devinst *pi, uint64_t offset)
452 {
453         /*
454          * Device specific offsets used by guest would change 
455          * based on whether MSI-X capability is enabled or not
456          */ 
457         if (!pci_msix_enabled(pi)) {
458                 if (offset >= VTCFG_R_MSIX) 
459                         return (offset + (VTCFG_R_CFG1 - VTCFG_R_MSIX));
460         }
461
462         return (offset);
463 }
464
465 static void
466 pci_vtblk_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
467                 int baridx, uint64_t offset, int size, uint64_t value)
468 {
469         struct pci_vtblk_softc *sc = pi->pi_arg;
470
471         if (use_msix) {
472                 if (baridx == pci_msix_table_bar(pi) ||
473                     baridx == pci_msix_pba_bar(pi)) {
474                         pci_emul_msix_twrite(pi, offset, size, value);
475                         return;
476                 }
477         }
478         
479         assert(baridx == 0);
480
481         if (offset + size > pci_vtblk_iosize(pi)) {
482                 DPRINTF(("vtblk_write: 2big, offset %ld size %d\n",
483                          offset, size));
484                 return;
485         }
486
487         offset = vtblk_adjust_offset(pi, offset);
488         
489         switch (offset) {
490         case VTCFG_R_GUESTCAP:
491                 assert(size == 4);
492                 sc->vbsc_features = value & VTBLK_S_HOSTCAPS;
493                 break;
494         case VTCFG_R_PFN:
495                 assert(size == 4);
496                 pci_vtblk_ring_init(sc, value);
497                 break;
498         case VTCFG_R_QSEL:
499                 assert(size == 2);
500                 sc->vbsc_lastq = value;
501                 break;
502         case VTCFG_R_QNOTIFY:
503                 assert(size == 2);
504                 assert(value == 0);
505                 pci_vtblk_qnotify(sc);
506                 break;
507         case VTCFG_R_STATUS:
508                 assert(size == 1);
509                 pci_vtblk_update_status(sc, value);
510                 break;
511         case VTCFG_R_CFGVEC:
512                 assert(size == 2);
513                 sc->msix_table_idx_cfg = value; 
514                 break;  
515         case VTCFG_R_QVEC:
516                 assert(size == 2);
517                 sc->msix_table_idx_req = value;
518                 break;  
519         case VTCFG_R_HOSTCAP:
520         case VTCFG_R_QNUM:
521         case VTCFG_R_ISR:
522         case VTBLK_R_CFG ... VTBLK_R_CFG_END:
523                 DPRINTF(("vtblk: write to readonly reg %ld\n\r", offset));
524                 break;
525         default:
526                 DPRINTF(("vtblk: unknown i/o write offset %ld\n\r", offset));
527                 value = 0;
528                 break;
529         }
530 }
531
532 uint64_t
533 pci_vtblk_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
534                int baridx, uint64_t offset, int size)
535 {
536         struct pci_vtblk_softc *sc = pi->pi_arg;
537         void *ptr;
538         uint32_t value;
539
540         if (use_msix) {
541                 if (baridx == pci_msix_table_bar(pi) ||
542                     baridx == pci_msix_pba_bar(pi)) {
543                         return (pci_emul_msix_tread(pi, offset, size));
544                 }
545         }
546
547         assert(baridx == 0);
548
549         if (offset + size > pci_vtblk_iosize(pi)) {
550                 DPRINTF(("vtblk_read: 2big, offset %ld size %d\n",
551                          offset, size));
552                 return (0);
553         }
554
555         offset = vtblk_adjust_offset(pi, offset);
556
557         switch (offset) {
558         case VTCFG_R_HOSTCAP:
559                 assert(size == 4);
560                 value = VTBLK_S_HOSTCAPS;
561                 break;
562         case VTCFG_R_GUESTCAP:
563                 assert(size == 4);
564                 value = sc->vbsc_features; /* XXX never read ? */
565                 break;
566         case VTCFG_R_PFN:
567                 assert(size == 4);
568                 value = sc->vbsc_pfn >> VRING_PFN;
569                 break;
570         case VTCFG_R_QNUM:
571                 value = (sc->vbsc_lastq == 0) ? VTBLK_RINGSZ: 0;
572                 break;
573         case VTCFG_R_QSEL:
574                 assert(size == 2);
575                 value = sc->vbsc_lastq; /* XXX never read ? */
576                 break;
577         case VTCFG_R_QNOTIFY:
578                 assert(size == 2);
579                 value = 0; /* XXX never read ? */
580                 break;
581         case VTCFG_R_STATUS:
582                 assert(size == 1);
583                 value = sc->vbsc_status;
584                 break;
585         case VTCFG_R_ISR:
586                 assert(size == 1);
587                 value = sc->vbsc_isr;
588                 sc->vbsc_isr = 0;     /* a read clears this flag */
589                 break;
590         case VTCFG_R_CFGVEC:
591                 assert(size == 2);
592                 value = sc->msix_table_idx_cfg;
593                 break;
594         case VTCFG_R_QVEC:
595                 assert(size == 2);
596                 value = sc->msix_table_idx_req;
597                 break;  
598         case VTBLK_R_CFG ... VTBLK_R_CFG_END:
599                 assert(size + offset <= (VTBLK_R_CFG_END + 1));
600                 ptr = (uint8_t *)&sc->vbsc_cfg + offset - VTBLK_R_CFG;
601                 if (size == 1) {
602                         value = *(uint8_t *) ptr;
603                 } else if (size == 2) {
604                         value = *(uint16_t *) ptr;
605                 } else {
606                         value = *(uint32_t *) ptr;
607                 }
608                 break;
609         default:
610                 DPRINTF(("vtblk: unknown i/o read offset %ld\n\r", offset));
611                 value = 0;
612                 break;
613         }
614
615         return (value);
616 }
617
618 struct pci_devemu pci_de_vblk = {
619         .pe_emu =       "virtio-blk",
620         .pe_init =      pci_vtblk_init,
621         .pe_barwrite =  pci_vtblk_write,
622         .pe_barread =   pci_vtblk_read
623 };
624 PCI_EMUL_SET(pci_de_vblk);