Annotation of qemu/roms/seabios/src/virtio-blk.c, revision 1.1.1.2

1.1       root        1: // Virtio block boot support.
                      2: //
                      3: // Copyright (C) 2010 Red Hat Inc.
                      4: //
                      5: // Authors:
                      6: //  Gleb Natapov <[email protected]>
                      7: //
                      8: // This file may be distributed under the terms of the GNU LGPLv3 license.
                      9: 
                     10: #include "util.h" // dprintf
                     11: #include "pci.h" // foreachpci
                     12: #include "config.h" // CONFIG_*
                     13: #include "biosvar.h" // GET_GLOBAL
                     14: #include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
                     15: #include "pci_regs.h" // PCI_VENDOR_ID
                     16: #include "boot.h" // add_bcv_internal
                     17: #include "virtio-pci.h"
                     18: #include "virtio-ring.h"
                     19: #include "virtio-blk.h"
                     20: #include "disk.h"
                     21: 
                     22: struct virtiodrive_s {
                     23:     struct drive_s drive;
                     24:     struct vring_virtqueue *vq;
                     25:     u16 ioaddr;
                     26: };
                     27: 
                     28: static int
1.1.1.2 ! root       29: virtio_blk_op(struct disk_op_s *op, int write)
1.1       root       30: {
                     31:     struct virtiodrive_s *vdrive_g =
                     32:         container_of(op->drive_g, struct virtiodrive_s, drive);
                     33:     struct vring_virtqueue *vq = GET_GLOBAL(vdrive_g->vq);
                     34:     struct virtio_blk_outhdr hdr = {
1.1.1.2 ! root       35:         .type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN,
1.1       root       36:         .ioprio = 0,
                     37:         .sector = op->lba,
                     38:     };
                     39:     u8 status = VIRTIO_BLK_S_UNSUPP;
                     40:     struct vring_list sg[] = {
                     41:         {
                     42:             .addr      = MAKE_FLATPTR(GET_SEG(SS), &hdr),
                     43:             .length    = sizeof(hdr),
                     44:         },
                     45:         {
                     46:             .addr      = op->buf_fl,
                     47:             .length    = GET_GLOBAL(vdrive_g->drive.blksize) * op->count,
                     48:         },
                     49:         {
                     50:             .addr      = MAKE_FLATPTR(GET_SEG(SS), &status),
                     51:             .length    = sizeof(status),
                     52:         },
                     53:     };
                     54: 
                     55:     /* Add to virtqueue and kick host */
1.1.1.2 ! root       56:     if (write)
        !            57:         vring_add_buf(vq, sg, 2, 1, 0, 0);
        !            58:     else
        !            59:         vring_add_buf(vq, sg, 1, 2, 0, 0);
1.1       root       60:     vring_kick(GET_GLOBAL(vdrive_g->ioaddr), vq, 1);
                     61: 
                     62:     /* Wait for reply */
                     63:     while (!vring_more_used(vq))
                     64:         usleep(5);
                     65: 
                     66:     /* Reclaim virtqueue element */
                     67:     vring_get_buf(vq, NULL);
                     68: 
                     69:     /* Clear interrupt status register.  Avoid leaving interrupts stuck if
                     70:      * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
                     71:      */
                     72:     vp_get_isr(GET_GLOBAL(vdrive_g->ioaddr));
                     73: 
                     74:     return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
                     75: }
                     76: 
                     77: int
                     78: process_virtio_op(struct disk_op_s *op)
                     79: {
                     80:     if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
                     81:         return 0;
                     82:     switch (op->command) {
                     83:     case CMD_READ:
1.1.1.2 ! root       84:         return virtio_blk_op(op, 0);
1.1       root       85:     case CMD_WRITE:
1.1.1.2 ! root       86:         return virtio_blk_op(op, 1);
        !            87:     case CMD_FORMAT:
1.1       root       88:     case CMD_RESET:
                     89:     case CMD_ISREADY:
                     90:     case CMD_VERIFY:
                     91:     case CMD_SEEK:
                     92:         return DISK_RET_SUCCESS;
                     93:     default:
                     94:         op->count = 0;
                     95:         return DISK_RET_EPARAM;
                     96:     }
                     97: }
                     98: 
                     99: static void
                    100: init_virtio_blk(u16 bdf)
                    101: {
                    102:     dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf),
                    103:             pci_bdf_to_dev(bdf));
                    104:     char *desc = malloc_tmphigh(MAXDESCSIZE);
                    105:     struct virtiodrive_s *vdrive_g = malloc_fseg(sizeof(*vdrive_g));
                    106:     struct vring_virtqueue *vq = memalign_low(PAGE_SIZE, sizeof(*vq));
                    107:     if (!vdrive_g || !desc || !vq) {
                    108:         warn_noalloc();
                    109:         goto fail;
                    110:     }
                    111:     memset(vdrive_g, 0, sizeof(*vdrive_g));
1.1.1.2 ! root      112:     memset(vq, 0, sizeof(*vq));
1.1       root      113:     vdrive_g->drive.type = DTYPE_VIRTIO;
                    114:     vdrive_g->drive.cntl_id = bdf;
                    115:     vdrive_g->vq = vq;
                    116: 
                    117:     u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
                    118:         PCI_BASE_ADDRESS_IO_MASK;
                    119: 
                    120:     vdrive_g->ioaddr = ioaddr;
                    121: 
                    122:     vp_reset(ioaddr);
                    123:     vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
                    124:                   VIRTIO_CONFIG_S_DRIVER );
                    125: 
                    126:     if (vp_find_vq(ioaddr, 0, vdrive_g->vq) < 0 ) {
                    127:         dprintf(1, "fail to find vq for virtio-blk %x:%x\n",
                    128:                 pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
                    129:         goto fail;
                    130:     }
                    131: 
                    132:     struct virtio_blk_config cfg;
                    133:     vp_get(ioaddr, 0, &cfg, sizeof(cfg));
                    134: 
                    135:     u32 f = vp_get_features(ioaddr);
                    136:     vdrive_g->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
                    137:         cfg.blk_size : DISK_SECTOR_SIZE;
                    138: 
                    139:     vdrive_g->drive.sectors = cfg.capacity;
                    140:     dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
                    141:             pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
                    142:             vdrive_g->drive.blksize, (u32)vdrive_g->drive.sectors);
                    143: 
                    144:     if (vdrive_g->drive.blksize != DISK_SECTOR_SIZE) {
                    145:         dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
                    146:                 pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
                    147:                 vdrive_g->drive.blksize);
                    148:         goto fail;
                    149:     }
                    150: 
                    151:     vdrive_g->drive.pchs.cylinders = cfg.cylinders;
                    152:     vdrive_g->drive.pchs.heads = cfg.heads;
                    153:     vdrive_g->drive.pchs.spt = cfg.sectors;
                    154: 
                    155:     setup_translation(&vdrive_g->drive);
                    156:     add_bcv_internal(&vdrive_g->drive);
                    157: 
                    158:     snprintf(desc, MAXDESCSIZE, "Virtio disk PCI:%x:%x",
                    159:              pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
                    160: 
                    161:     vdrive_g->drive.desc = desc;
                    162: 
                    163:     vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
                    164:                   VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
                    165:     return;
                    166: 
                    167: fail:
                    168:     free(vdrive_g);
                    169:     free(desc);
                    170:     free(vq);
                    171: }
                    172: 
                    173: void
                    174: virtio_blk_setup(void)
                    175: {
                    176:     ASSERT32FLAT();
                    177:     if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
                    178:         return;
                    179: 
                    180:     dprintf(3, "init virtio-blk\n");
                    181: 
                    182:     int bdf, max;
                    183:     u32 id = PCI_VENDOR_ID_REDHAT_QUMRANET | (PCI_DEVICE_ID_VIRTIO_BLK << 16);
                    184:     foreachpci(bdf, max) {
                    185:         u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
                    186:         if (v != id)
                    187:             continue;
                    188:         init_virtio_blk(bdf);
                    189:     }
                    190: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.