Annotation of qemu/roms/SLOF/lib/libvirtio/virtio-blk.c, revision 1.1.1.1

1.1       root        1: /******************************************************************************
                      2:  * Copyright (c) 2011 IBM Corporation
                      3:  * All rights reserved.
                      4:  * This program and the accompanying materials
                      5:  * are made available under the terms of the BSD License
                      6:  * which accompanies this distribution, and is available at
                      7:  * http://www.opensource.org/licenses/bsd-license.php
                      8:  *
                      9:  * Contributors:
                     10:  *     IBM Corporation - initial implementation
                     11:  *****************************************************************************/
                     12: 
                     13: #include <stdio.h>
                     14: #include "virtio.h"
                     15: #include "virtio-blk.h"
                     16: 
                     17: #define sync()  asm volatile (" sync \n" ::: "memory")
                     18: 
                     19: 
                     20: /**
                     21:  * Initialize virtio-block device.
                     22:  * @param  dev  pointer to virtio device information
                     23:  */
                     24: int
                     25: virtioblk_init(struct virtio_device *dev)
                     26: {
                     27:        struct vring_avail *vq_avail;
                     28: 
                     29:        /* Reset device */
                     30:        // XXX That will clear the virtq base. We need to move
                     31:        //     initializing it to here anyway
                     32:        //
                     33:        //       virtio_reset_device(dev);
                     34: 
                     35:        /* Acknowledge device. */
                     36:        virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
                     37: 
                     38:        /* Tell HV that we know how to drive the device. */
                     39:        virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
                     40: 
                     41:        /* Device specific setup - we do not support special features right now */
                     42:        virtio_set_guest_features(dev,  0);
                     43: 
                     44:        vq_avail = virtio_get_vring_avail(dev, 0);
                     45:        vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
                     46:        vq_avail->idx = 0;
                     47: 
                     48:        /* Tell HV that setup succeeded */
                     49:        virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
                     50:                                |VIRTIO_STAT_DRIVER_OK);
                     51: 
                     52:        return 0;
                     53: }
                     54: 
                     55: 
                     56: /**
                     57:  * Shutdown the virtio-block device.
                     58:  * @param  dev  pointer to virtio device information
                     59:  */
                     60: void
                     61: virtioblk_shutdown(struct virtio_device *dev)
                     62: {
                     63:        /* Quiesce device */
                     64:        virtio_set_status(dev, VIRTIO_STAT_FAILED);
                     65: 
                     66:        /* Reset device */
                     67:        virtio_reset_device(dev);
                     68: }
                     69: 
                     70: 
                     71: /**
                     72:  * Read blocks
                     73:  * @param  reg  pointer to "reg" property
                     74:  * @param  buf  pointer to destination buffer
                     75:  * @param  blocknum  block number of the first block that should be read
                     76:  * @param  cnt  amount of blocks that should be read
                     77:  * @return number of blocks that have been read successfully
                     78:  */
                     79: int
                     80: virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
                     81: {
                     82:        struct vring_desc *desc;
                     83:        int id, i;
                     84:        static struct virtio_blk_req blkhdr;
                     85:        //struct virtio_blk_config *blkconf;
                     86:        uint64_t capacity;
                     87:        uint32_t vq_size;
                     88:        struct vring_desc *vq_desc;             /* Descriptor vring */
                     89:        struct vring_avail *vq_avail;           /* "Available" vring */
                     90:        struct vring_used *vq_used;             /* "Used" vring */
                     91:        volatile uint8_t status = -1;
                     92:        volatile uint16_t *current_used_idx;
                     93:        uint16_t last_used_idx;
                     94: 
                     95:        //printf("virtioblk_read: dev=%p buf=%p blocknum=%li count=%li\n",
                     96:        //      dev, buf, blocknum, cnt);
                     97: 
                     98:        /* Check whether request is within disk capacity */
                     99:        capacity = virtio_get_config(dev, 0, sizeof(capacity));
                    100:        if (blocknum + cnt - 1 > capacity) {
                    101:                puts("virtioblk_read: Access beyond end of device!");
                    102:                return 0;
                    103:        }
                    104: 
                    105:        vq_size = virtio_get_qsize(dev, 0);
                    106:        vq_desc = virtio_get_vring_desc(dev, 0);
                    107:        vq_avail = virtio_get_vring_avail(dev, 0);
                    108:        vq_used = virtio_get_vring_used(dev, 0);
                    109: 
                    110:        last_used_idx = vq_used->idx;
                    111:        current_used_idx = &vq_used->idx;
                    112: 
                    113:        /* Set up header */
                    114:        blkhdr.type = VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER;
                    115:        blkhdr.ioprio = 1;
                    116:        blkhdr.sector = blocknum;
                    117: 
                    118:        /* Determine descriptor index */
                    119:        id = (vq_avail->idx * 3) % vq_size;
                    120: 
                    121:        /* Set up virtqueue descriptor for header */
                    122:        desc = &vq_desc[id];
                    123:        desc->addr = (uint64_t)&blkhdr;
                    124:        desc->len = sizeof(struct virtio_blk_req);
                    125:        desc->flags = VRING_DESC_F_NEXT;
                    126:        desc->next = (id + 1) % vq_size;
                    127: 
                    128:        /* Set up virtqueue descriptor for data */
                    129:        desc = &vq_desc[(id + 1) % vq_size];
                    130:        desc->addr = (uint64_t)buf;
                    131:        desc->len = cnt * 512;
                    132:        desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
                    133:        desc->next = (id + 2) % vq_size;
                    134: 
                    135:        /* Set up virtqueue descriptor for status */
                    136:        desc = &vq_desc[(id + 2) % vq_size];
                    137:        desc->addr = (uint64_t)&status;
                    138:        desc->len = 1;
                    139:        desc->flags = VRING_DESC_F_WRITE;
                    140:        desc->next = 0;
                    141: 
                    142:        vq_avail->ring[vq_avail->idx % vq_size] = id;
                    143:        sync();
                    144:        vq_avail->idx += 1;
                    145: 
                    146:        /* Tell HV that the queue is ready */
                    147:        virtio_queue_notify(dev, 0);
                    148: 
                    149:        /* Wait for host to consume the descriptor */
                    150:        i = 10000000;
                    151:        while (*current_used_idx == last_used_idx && i-- > 0) {
                    152:                // do something better
                    153:                sync();
                    154:        }
                    155: 
                    156:        if (status == 0)
                    157:                return cnt;
                    158: 
                    159:        printf("virtioblk_read failed! status = %i\n", status);
                    160: 
                    161:        return 0;
                    162: }

unix.superglobalmegacorp.com

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