diff options
Diffstat (limited to 'qemu/roms/seabios/src/hw/virtio-blk.c')
-rw-r--r-- | qemu/roms/seabios/src/hw/virtio-blk.c | 126 |
1 files changed, 84 insertions, 42 deletions
diff --git a/qemu/roms/seabios/src/hw/virtio-blk.c b/qemu/roms/seabios/src/hw/virtio-blk.c index e2dbd3c94..20a79ebba 100644 --- a/qemu/roms/seabios/src/hw/virtio-blk.c +++ b/qemu/roms/seabios/src/hw/virtio-blk.c @@ -25,7 +25,7 @@ struct virtiodrive_s { struct drive_s drive; struct vring_virtqueue *vq; - u16 ioaddr; + struct vp_device vp; }; static int @@ -33,7 +33,7 @@ virtio_blk_op(struct disk_op_s *op, int write) { struct virtiodrive_s *vdrive_gf = container_of(op->drive_gf, struct virtiodrive_s, drive); - struct vring_virtqueue *vq = GET_GLOBALFLAT(vdrive_gf->vq); + struct vring_virtqueue *vq = vdrive_gf->vq; struct virtio_blk_outhdr hdr = { .type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN, .ioprio = 0, @@ -42,15 +42,15 @@ virtio_blk_op(struct disk_op_s *op, int write) u8 status = VIRTIO_BLK_S_UNSUPP; struct vring_list sg[] = { { - .addr = MAKE_FLATPTR(GET_SEG(SS), &hdr), + .addr = (void*)(&hdr), .length = sizeof(hdr), }, { .addr = op->buf_fl, - .length = GET_GLOBALFLAT(vdrive_gf->drive.blksize) * op->count, + .length = vdrive_gf->drive.blksize * op->count, }, { - .addr = MAKE_FLATPTR(GET_SEG(SS), &status), + .addr = (void*)(&status), .length = sizeof(status), }, }; @@ -60,7 +60,7 @@ virtio_blk_op(struct disk_op_s *op, int write) vring_add_buf(vq, sg, 2, 1, 0, 0); else vring_add_buf(vq, sg, 1, 2, 0, 0); - vring_kick(GET_GLOBALFLAT(vdrive_gf->ioaddr), vq, 1); + vring_kick(&vdrive_gf->vp, vq, 1); /* Wait for reply */ while (!vring_more_used(vq)) @@ -72,13 +72,13 @@ virtio_blk_op(struct disk_op_s *op, int write) /* Clear interrupt status register. Avoid leaving interrupts stuck if * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. */ - vp_get_isr(GET_GLOBALFLAT(vdrive_gf->ioaddr)); + vp_get_isr(&vdrive_gf->vp); return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; } int -process_virtio_blk_op(struct disk_op_s *op) +virtio_blk_process_op(struct disk_op_s *op) { if (! CONFIG_VIRTIO_BLK) return 0; @@ -87,14 +87,8 @@ process_virtio_blk_op(struct disk_op_s *op) return virtio_blk_op(op, 0); case CMD_WRITE: return virtio_blk_op(op, 1); - case CMD_FORMAT: - case CMD_RESET: - case CMD_ISREADY: - case CMD_VERIFY: - case CMD_SEEK: - return DISK_RET_SUCCESS; default: - return DISK_RET_EPARAM; + return default_process_op(op); } } @@ -102,6 +96,7 @@ static void init_virtio_blk(struct pci_device *pci) { u16 bdf = pci->bdf; + u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER; dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); struct virtiodrive_s *vdrive = malloc_fseg(sizeof(*vdrive)); @@ -113,47 +108,93 @@ init_virtio_blk(struct pci_device *pci) vdrive->drive.type = DTYPE_VIRTIO_BLK; vdrive->drive.cntl_id = bdf; - u16 ioaddr = vp_init_simple(bdf); - vdrive->ioaddr = ioaddr; - if (vp_find_vq(ioaddr, 0, &vdrive->vq) < 0 ) { + vp_init_simple(&vdrive->vp, pci); + if (vp_find_vq(&vdrive->vp, 0, &vdrive->vq) < 0 ) { dprintf(1, "fail to find vq for virtio-blk %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); goto fail; } - struct virtio_blk_config cfg; - vp_get(ioaddr, 0, &cfg, sizeof(cfg)); - - u32 f = vp_get_features(ioaddr); - vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ? - cfg.blk_size : DISK_SECTOR_SIZE; - - vdrive->drive.sectors = cfg.capacity; - dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n", - pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), - vdrive->drive.blksize, (u32)vdrive->drive.sectors); - - if (vdrive->drive.blksize != DISK_SECTOR_SIZE) { - dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + if (vdrive->vp.use_modern) { + struct vp_device *vp = &vdrive->vp; + u64 features = vp_get_features(vp); + u64 version1 = 1ull << VIRTIO_F_VERSION_1; + u64 blk_size = 1ull << VIRTIO_BLK_F_BLK_SIZE; + if (!(features & version1)) { + dprintf(1, "modern device without virtio_1 feature bit: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + } + + features = features & (version1 | blk_size); + vp_set_features(vp, features); + status |= VIRTIO_CONFIG_S_FEATURES_OK; + vp_set_status(vp, status); + if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) { + dprintf(1, "device didn't accept features: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + } + + vdrive->drive.sectors = + vp_read(&vp->device, struct virtio_blk_config, capacity); + if (features & blk_size) { + vdrive->drive.blksize = + vp_read(&vp->device, struct virtio_blk_config, blk_size); + } else { + vdrive->drive.blksize = DISK_SECTOR_SIZE; + } + if (vdrive->drive.blksize != DISK_SECTOR_SIZE) { + dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive->drive.blksize); + goto fail; + } + dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), - vdrive->drive.blksize); - goto fail; + vdrive->drive.blksize, (u32)vdrive->drive.sectors); + + vdrive->drive.pchs.cylinder = + vp_read(&vp->device, struct virtio_blk_config, cylinders); + vdrive->drive.pchs.head = + vp_read(&vp->device, struct virtio_blk_config, heads); + vdrive->drive.pchs.sector = + vp_read(&vp->device, struct virtio_blk_config, sectors); + } else { + struct virtio_blk_config cfg; + vp_get_legacy(&vdrive->vp, 0, &cfg, sizeof(cfg)); + + u64 f = vp_get_features(&vdrive->vp); + vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ? + cfg.blk_size : DISK_SECTOR_SIZE; + + vdrive->drive.sectors = cfg.capacity; + dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive->drive.blksize, (u32)vdrive->drive.sectors); + + if (vdrive->drive.blksize != DISK_SECTOR_SIZE) { + dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive->drive.blksize); + goto fail; + } + vdrive->drive.pchs.cylinder = cfg.cylinders; + vdrive->drive.pchs.head = cfg.heads; + vdrive->drive.pchs.sector = cfg.sectors; } - vdrive->drive.pchs.cylinder = cfg.cylinders; - vdrive->drive.pchs.head = cfg.heads; - vdrive->drive.pchs.sector = cfg.sectors; char *desc = znprintf(MAXDESCSIZE, "Virtio disk PCI:%x:%x", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); boot_add_hd(&vdrive->drive, desc, bootprio_find_pci_device(pci)); - vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); + status |= VIRTIO_CONFIG_S_DRIVER_OK; + vp_set_status(&vdrive->vp, status); return; fail: - vp_reset(ioaddr); + vp_reset(&vdrive->vp); free(vdrive->vq); free(vdrive); } @@ -169,8 +210,9 @@ virtio_blk_setup(void) struct pci_device *pci; foreachpci(pci) { - if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET - || pci->device != PCI_DEVICE_ID_VIRTIO_BLK) + if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET || + (pci->device != PCI_DEVICE_ID_VIRTIO_BLK_09 && + pci->device != PCI_DEVICE_ID_VIRTIO_BLK_10)) continue; init_virtio_blk(pci); } |