|
|
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.