~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/SLOF/lib/libvirtio/virtio-scsi.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 * Copyright (c) 2012 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 <string.h>
 
15
#include <cpu.h>
 
16
#include <helpers.h>
 
17
#include "virtio.h"
 
18
#include "virtio-internal.h"
 
19
#include "virtio-scsi.h"
 
20
 
 
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)
 
25
{
 
26
        struct vring_desc *vq_desc;             /* Descriptor vring */
 
27
        struct vring_avail *vq_avail;           /* "Available" vring */
 
28
        struct vring_used *vq_used;             /* "Used" vring */
 
29
 
 
30
        volatile uint16_t *current_used_idx;
 
31
        uint16_t last_used_idx, avail_idx;
 
32
        int id;
 
33
        uint32_t vq_size, time;
 
34
 
 
35
        int vq = VIRTIO_SCSI_REQUEST_VQ;
 
36
 
 
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);
 
41
 
 
42
        avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx);
 
43
 
 
44
        last_used_idx = vq_used->idx;
 
45
        current_used_idx = &vq_used->idx;
 
46
 
 
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,
 
50
                         (id + 1) % vq_size);
 
51
 
 
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);
 
57
        } else if (is_read) {
 
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,
 
62
                                 (id + 2) % vq_size);
 
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);
 
66
        } else {
 
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,
 
70
                                 (id + 2) % vq_size);
 
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);
 
75
        }
 
76
 
 
77
        vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16(dev, id);
 
78
        mb();
 
79
        vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1);
 
80
 
 
81
        /* Tell HV that the vq is ready */
 
82
        virtio_queue_notify(dev, vq);
 
83
 
 
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
 
88
                mb();
 
89
                if (time < SLOF_GetTimer())
 
90
                        break;
 
91
        }
 
92
 
 
93
        return 0;
 
94
}
 
95
 
 
96
/**
 
97
 * Initialize virtio-block device.
 
98
 * @param  dev  pointer to virtio device information
 
99
 */
 
100
int virtioscsi_init(struct virtio_device *dev)
 
101
{
 
102
        struct vqs vq_ctrl, vq_event, vq_request;
 
103
        int status = VIRTIO_STAT_ACKNOWLEDGE;
 
104
        uint16_t flags;
 
105
 
 
106
        /* Reset device */
 
107
        // XXX That will clear the virtq base. We need to move
 
108
        //     initializing it to here anyway
 
109
        //
 
110
        //     virtio_reset_device(dev);
 
111
 
 
112
        /* Acknowledge device. */
 
113
        virtio_set_status(dev, status);
 
114
 
 
115
        /* Tell HV that we know how to drive the device. */
 
116
        status |= VIRTIO_STAT_DRIVER;
 
117
        virtio_set_status(dev, status);
 
118
 
 
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))
 
122
                        goto dev_error;
 
123
                virtio_get_status(dev, &status);
 
124
        } else {
 
125
                virtio_set_guest_features(dev, 0);
 
126
        }
 
127
 
 
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))
 
131
                goto dev_error;
 
132
 
 
133
        flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
 
134
        vq_ctrl.avail->flags = flags;
 
135
        vq_ctrl.avail->idx = 0;
 
136
 
 
137
        vq_event.avail->flags = flags;
 
138
        vq_event.avail->idx = 0;
 
139
 
 
140
        vq_request.avail->flags = flags;
 
141
        vq_request.avail->idx = 0;
 
142
 
 
143
        /* Tell HV that setup succeeded */
 
144
        status |= VIRTIO_STAT_DRIVER_OK;
 
145
        virtio_set_status(dev, status);
 
146
 
 
147
        return 0;
 
148
dev_error:
 
149
        printf("%s: failed\n", __func__);
 
150
        status |= VIRTIO_STAT_FAILED;
 
151
        virtio_set_status(dev, status);
 
152
        return -1;
 
153
}
 
154
 
 
155
/**
 
156
 * Shutdown the virtio-block device.
 
157
 * @param  dev  pointer to virtio device information
 
158
 */
 
159
void virtioscsi_shutdown(struct virtio_device *dev)
 
160
{
 
161
        /* Quiesce device */
 
162
        virtio_set_status(dev, VIRTIO_STAT_FAILED);
 
163
 
 
164
        /* Reset device */
 
165
        virtio_reset_device(dev);
 
166
}