1
/******************************************************************************
2
* Copyright (c) 2012 IBM Corporation
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
10
* IBM Corporation - initial implementation
11
*****************************************************************************/
18
#include "virtio-internal.h"
19
#include "virtio-scsi.h"
21
int virtioscsi_send(struct virtio_device *dev,
22
struct virtio_scsi_req_cmd *req,
23
struct virtio_scsi_resp_cmd *resp,
24
int is_read, void *buf, uint64_t buf_len)
26
struct vring_desc *vq_desc; /* Descriptor vring */
27
struct vring_avail *vq_avail; /* "Available" vring */
28
struct vring_used *vq_used; /* "Used" vring */
30
volatile uint16_t *current_used_idx;
31
uint16_t last_used_idx, avail_idx;
33
uint32_t vq_size, time;
35
int vq = VIRTIO_SCSI_REQUEST_VQ;
37
vq_size = virtio_get_qsize(dev, vq);
38
vq_desc = virtio_get_vring_desc(dev, vq);
39
vq_avail = virtio_get_vring_avail(dev, vq);
40
vq_used = virtio_get_vring_used(dev, vq);
42
avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx);
44
last_used_idx = vq_used->idx;
45
current_used_idx = &vq_used->idx;
47
/* Determine descriptor index */
48
id = (avail_idx * 3) % vq_size;
49
virtio_fill_desc(&vq_desc[id], dev->is_modern, (uint64_t)req, sizeof(*req), VRING_DESC_F_NEXT,
52
if (buf == NULL || buf_len == 0) {
53
/* Set up descriptor for response information */
54
virtio_fill_desc(&vq_desc[(id + 1) % vq_size], dev->is_modern,
55
(uint64_t)resp, sizeof(*resp),
56
VRING_DESC_F_WRITE, 0);
58
/* Set up descriptor for response information */
59
virtio_fill_desc(&vq_desc[(id + 1) % vq_size], dev->is_modern,
60
(uint64_t)resp, sizeof(*resp),
61
VRING_DESC_F_NEXT | VRING_DESC_F_WRITE,
63
/* Set up virtqueue descriptor for data from device */
64
virtio_fill_desc(&vq_desc[(id + 2) % vq_size], dev->is_modern,
65
(uint64_t)buf, buf_len, VRING_DESC_F_WRITE, 0);
67
/* Set up virtqueue descriptor for data to device */
68
virtio_fill_desc(&vq_desc[(id + 1) % vq_size], dev->is_modern,
69
(uint64_t)buf, buf_len, VRING_DESC_F_NEXT,
71
/* Set up descriptor for response information */
72
virtio_fill_desc(&vq_desc[(id + 2) % vq_size], dev->is_modern,
73
(uint64_t)resp, sizeof(*resp),
74
VRING_DESC_F_WRITE, 0);
77
vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16(dev, id);
79
vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1);
81
/* Tell HV that the vq is ready */
82
virtio_queue_notify(dev, vq);
84
/* Wait for host to consume the descriptor */
85
time = SLOF_GetTimer() + VIRTIO_TIMEOUT;
86
while (*current_used_idx == last_used_idx) {
87
// do something better
89
if (time < SLOF_GetTimer())
97
* Initialize virtio-block device.
98
* @param dev pointer to virtio device information
100
int virtioscsi_init(struct virtio_device *dev)
102
struct vqs vq_ctrl, vq_event, vq_request;
103
int status = VIRTIO_STAT_ACKNOWLEDGE;
107
// XXX That will clear the virtq base. We need to move
108
// initializing it to here anyway
110
// virtio_reset_device(dev);
112
/* Acknowledge device. */
113
virtio_set_status(dev, status);
115
/* Tell HV that we know how to drive the device. */
116
status |= VIRTIO_STAT_DRIVER;
117
virtio_set_status(dev, status);
119
/* Device specific setup - we do not support special features right now */
120
if (dev->is_modern) {
121
if (virtio_negotiate_guest_features(dev, VIRTIO_F_VERSION_1))
123
virtio_get_status(dev, &status);
125
virtio_set_guest_features(dev, 0);
128
if (virtio_queue_init_vq(dev, &vq_ctrl, VIRTIO_SCSI_CONTROL_VQ) ||
129
virtio_queue_init_vq(dev, &vq_event, VIRTIO_SCSI_EVENT_VQ) ||
130
virtio_queue_init_vq(dev, &vq_request, VIRTIO_SCSI_REQUEST_VQ))
133
flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
134
vq_ctrl.avail->flags = flags;
135
vq_ctrl.avail->idx = 0;
137
vq_event.avail->flags = flags;
138
vq_event.avail->idx = 0;
140
vq_request.avail->flags = flags;
141
vq_request.avail->idx = 0;
143
/* Tell HV that setup succeeded */
144
status |= VIRTIO_STAT_DRIVER_OK;
145
virtio_set_status(dev, status);
149
printf("%s: failed\n", __func__);
150
status |= VIRTIO_STAT_FAILED;
151
virtio_set_status(dev, status);
156
* Shutdown the virtio-block device.
157
* @param dev pointer to virtio device information
159
void virtioscsi_shutdown(struct virtio_device *dev)
162
virtio_set_status(dev, VIRTIO_STAT_FAILED);
165
virtio_reset_device(dev);