1/* 2 * Copyright (c) 2014 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <string.h> 11 12#include <barrelfish/barrelfish.h> 13 14#include <virtio/virtio.h> 15#include <virtio/virtio_device.h> 16#include <virtio/devices/virtio_block.h> 17 18#include <dev/virtio/virtio_blk_dev.h> 19 20#include "device.h" 21#include "debug.h" 22 23/** 24 * \brief returns the topology information 25 * 26 * \param dev the virtio block device 27 * \param topo memory region to fill the topology information in 28 * (only valid if VIRTIO_BLK_F_TOPOLOGY) 29 * 30 * \returns true if VIRTIO_BLK_F_TOPOLOGY 31 * false otherwise 32 */ 33bool virtio_block_get_topology(struct virtio_device_blk *dev, 34 struct virtio_block_topology *topo) 35{ 36 /* can't return any data */ 37 if (!topo) { 38 return 0; 39 } 40 41 /* the device does not support topology */ 42 if (!virtio_device_has_feature(dev->vdev, VIRTIO_BLOCK_F_TOPOLOGY)) { 43 return 0; 44 } 45 46 topo->alignment_offset = virtio_blk_topo_blocks_offset_aligned_rdf(&dev 47 ->config_space); 48 topo->min_io_size = virtio_blk_topo_io_size_min_rdf(&dev->config_space); 49 topo->opt_io_size = virtio_blk_topo_io_size_opt_rdf(&dev->config_space); 50 topo->num_logic_per_phys = virtio_blk_topo_blocks_logic_per_phys_rdf(&dev 51 ->config_space); 52 53 return 1; 54} 55 56/** 57 * \brief returns the blocksize of 58 * 59 * \param dev the virtio block device 60 * \param geo memory region to fill the geometry information in 61 * (only valid if VIRTIO_BLK_F_GEOMETRY) 62 * 63 * \returns true if VIRTIO_BLK_F_GEOMETRY 64 * false otherwise 65 */ 66bool virtio_block_get_geometry(struct virtio_device_blk *dev, 67 struct virtio_block_geometry *geo) 68{ 69 if (!geo) { 70 return 0; 71 } 72 73 if (!virtio_device_has_feature(dev->vdev, VIRTIO_BLOCK_F_GEOMETRY)) { 74 return 0; 75 } 76 77 geo->cylinders = virtio_blk_geometry_cylinders_rdf(&dev->config_space); 78 geo->heads = virtio_blk_geometry_heads_rdf(&dev->config_space); 79 geo->sectors = virtio_blk_geometry_sectors_rdf(&dev->config_space); 80 81 return 0; 82} 83 84/** 85 * \brief reads the device configuration and copies it into the local memory 86 * 87 * \param dev the block device to read the configuration space. 88 * 89 * \returns SYS_ERR_OK on success 90 */ 91errval_t virtio_block_config_read(struct virtio_device_blk *dev) 92{ 93 VIRTIO_DEBUG_DT("reading device configuration\n"); 94 if (dev->config_addr == NULL) { 95 dev->config_addr = malloc(VIRTIO_BLOCK_CONFIG_SIZE); 96 if (dev->config_addr == NULL) { 97 return LIB_ERR_MALLOC_FAIL; 98 } 99 } 100 101 return virtio_device_config_read(dev->vdev, 102 dev->config_addr, 103 VIRTIO_BLOCK_CONFIG_SIZE); 104} 105 106#ifdef __VIRTIO_HOST__ 107static errval_t virtio_block_init_common(struct virtio_device *vdev, 108 void *arg) 109{ 110 return SYS_ERR_OK; 111} 112#else 113/** 114 * \brief handles the VirtIO block device common initialization. 115 * 116 * \param dev the VirtIO block device 117 * \param setup the setup information 118 * 119 * \returns SYS_ERR_OK on success 120 */ 121static errval_t virtio_block_init_common(struct virtio_device *vdev, 122 void *arg) 123{ 124 errval_t err; 125 126 VIRTIO_DEBUG_DT("Doing device specific setup: Block Device\n"); 127 128 struct virtio_device_setup *setup = arg; 129 struct virtio_device_blk *dev = virtio_device_get_type_state(vdev); 130 131 /* read the device configuration */ 132 err = virtio_block_config_read(dev); 133 if (err_is_fail(err)) { 134 return err; 135 } 136 137 if (setup->vq_num != VIRTIO_BLOCK_NUM_VIRTQUEUES) { 138 /* 139 * TODO: handle this case. 140 */ 141 assert(setup->vq_num == VIRTIO_BLOCK_NUM_VIRTQUEUES); 142 } 143 144 /* 145 * allocate the virtqueues 146 */ 147 err = virtio_device_virtqueue_alloc(dev->vdev, setup->vq_setup, setup->vq_num); 148 if (err_is_fail(err)) { 149 return err; 150 } 151 152 dev->vq = virtio_device_get_virtq(dev->vdev, 0); 153 assert(dev->vq); 154 155 dev->vdev->state = VIRTIO_DEVICE_S_READY; 156 157 return SYS_ERR_OK; 158} 159#endif 160 161 162/** 163 * \brief handles the VirtIO block device specific initialization. 164 * with the device registers already mapped 165 * 166 * \param dev the VirtIO block device 167 * \param setup the setup information 168 * 169 * \returns SYS_ERR_OK on success 170 */ 171errval_t virtio_block_init_device(struct virtio_device_blk *dev, 172 struct virtio_device_setup *setup) 173{ 174 if (setup->dev_type != VIRTIO_DEVICE_TYPE_BLOCK) { 175 VIRTIO_DEBUG_DT("ERROR: Device type was not VIRTIO_DEVICE_TYPE_BLOCK\n"); 176 return VIRTIO_ERR_DEVICE_TYPE; 177 } 178 179 setup->setup_fn = virtio_block_init_common; 180 setup->setup_arg = setup; 181 setup->dev_t_st = dev; 182 183 /* initialize the VirtIO device */ 184 return virtio_device_open(&dev->vdev, setup); 185} 186 187/** 188 * \brief handles the VirtIO block device specific initialization. 189 * the device registers are not mapped yet 190 * 191 * \param dev the VirtIO block device 192 * \param setup the setup information 193 * \param dev_cap the frame capability backing the device registers 194 * 195 * \returns SYS_ERR_OK on success 196 */ 197errval_t virtio_block_init_device_with_cap(struct virtio_device_blk *dev, 198 struct virtio_device_setup *setup, 199 struct capref dev_cap) 200{ 201 if (setup->dev_type != VIRTIO_DEVICE_TYPE_BLOCK) { 202 return VIRTIO_ERR_DEVICE_TYPE; 203 } 204 205 setup->setup_fn = virtio_block_init_common; 206 setup->setup_arg = setup; 207 208 /* initialize the VirtIO device */ 209 return virtio_device_open_with_cap(&dev->vdev, setup, dev_cap); 210} 211 212 213#ifdef __VIRTIO_HOST__ 214/* 215 * ---------------------------------------------------------------------------- 216 * Additional functions for the host 217 * ---------------------------------------------------------------------------- 218 */ 219 220/** 221 * \brief writes the configuration space values to the device configuration space 222 * 223 * \param bdev the VirtIO host block device 224 * 225 * \return SYS_ERR_OK on success 226 */ 227errval_t virtio_block_host_write_config(struct virtio_host_blk *bdev) 228{ 229 if (bdev->config_addr == NULL) { 230 return VIRTIO_ERR_ARG_INVALID; 231 } 232 233 if (bdev->config_tmp == NULL) { 234 bdev->config_tmp = malloc(VIRTIO_BLOCK_CONFIG_SIZE); 235 } 236 237 assert(bdev->config_tmp); 238 239 240 241 242 uint8_t signal = 0x0; 243 if (virtio_blk_capacity_rd(&bdev->config_space)) { 244 signal = 0x1; 245 } 246 247 // clear out the configuration space 248 memset(bdev->config_addr, 0, VIRTIO_BLOCK_CONFIG_SIZE); 249 250 251 252 // assert the config space changed interrupt 253 if (signal) { 254 255 } 256 257 return SYS_ERR_OK; 258} 259 260#endif 261 262