|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.