Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ f2e17508

History | View | Annotate | Download (30.4 kB)

1 2e5d83bb pbrook
/*
2 2e5d83bb pbrook
 * SCSI Device emulation
3 2e5d83bb pbrook
 *
4 2e5d83bb pbrook
 * Copyright (c) 2006 CodeSourcery.
5 2e5d83bb pbrook
 * Based on code by Fabrice Bellard
6 2e5d83bb pbrook
 *
7 2e5d83bb pbrook
 * Written by Paul Brook
8 2e5d83bb pbrook
 *
9 2e5d83bb pbrook
 * This code is licenced under the LGPL.
10 a917d384 pbrook
 *
11 a917d384 pbrook
 * Note that this file only handles the SCSI architecture model and device
12 1d4db89c balrog
 * commands.  Emulation of interface/link layer protocols is handled by
13 1d4db89c balrog
 * the host adapter emulator.
14 2e5d83bb pbrook
 */
15 2e5d83bb pbrook
16 fa879c64 aliguori
#include <qemu-common.h>
17 fa879c64 aliguori
#include <sysemu.h>
18 2e5d83bb pbrook
//#define DEBUG_SCSI
19 2e5d83bb pbrook
20 2e5d83bb pbrook
#ifdef DEBUG_SCSI
21 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) \
22 001faf32 Blue Swirl
do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
23 2e5d83bb pbrook
#else
24 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do {} while(0)
25 2e5d83bb pbrook
#endif
26 2e5d83bb pbrook
27 001faf32 Blue Swirl
#define BADF(fmt, ...) \
28 001faf32 Blue Swirl
do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
29 2e5d83bb pbrook
30 87ecb68b pbrook
#include "qemu-common.h"
31 87ecb68b pbrook
#include "block.h"
32 43b443b6 Gerd Hoffmann
#include "scsi.h"
33 0d65e1f8 Gerd Hoffmann
#include "scsi-defs.h"
34 22864256 blueswir1
35 f0f72ffe aurel32
#define SCSI_DMA_BUF_SIZE    131072
36 57575058 balrog
#define SCSI_MAX_INQUIRY_LEN 256
37 a917d384 pbrook
38 ea8a5d7f aliguori
#define SCSI_REQ_STATUS_RETRY 0x01
39 ea8a5d7f aliguori
40 d52affa7 Gerd Hoffmann
typedef struct SCSIDiskState SCSIDiskState;
41 d52affa7 Gerd Hoffmann
42 4c41d2ef Gerd Hoffmann
typedef struct SCSIDiskReq {
43 4c41d2ef Gerd Hoffmann
    SCSIRequest req;
44 e035b43d aliguori
    /* ??? We should probably keep track of whether the data transfer is
45 2e5d83bb pbrook
       a read or a write.  Currently we rely on the host getting it right.  */
46 a917d384 pbrook
    /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
47 e035b43d aliguori
    uint64_t sector;
48 e035b43d aliguori
    uint32_t sector_count;
49 c87c0672 aliguori
    struct iovec iov;
50 c87c0672 aliguori
    QEMUIOVector qiov;
51 ea8a5d7f aliguori
    uint32_t status;
52 4c41d2ef Gerd Hoffmann
} SCSIDiskReq;
53 a917d384 pbrook
54 d52affa7 Gerd Hoffmann
struct SCSIDiskState
55 a917d384 pbrook
{
56 d52affa7 Gerd Hoffmann
    SCSIDevice qdev;
57 a917d384 pbrook
    /* The qemu block layer uses a fixed 512 byte sector size.
58 a917d384 pbrook
       This is the number of 512 byte blocks in a single scsi sector.  */
59 a917d384 pbrook
    int cluster_size;
60 274fb0e1 aliguori
    uint64_t max_lba;
61 213189ab Markus Armbruster
    QEMUBH *bh;
62 2e5d83bb pbrook
};
63 2e5d83bb pbrook
64 89b08ae1 Gerd Hoffmann
static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
65 2e5d83bb pbrook
{
66 89b08ae1 Gerd Hoffmann
    SCSIRequest *req;
67 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
68 a917d384 pbrook
69 89b08ae1 Gerd Hoffmann
    req = scsi_req_alloc(sizeof(SCSIDiskReq), d, tag, lun);
70 89b08ae1 Gerd Hoffmann
    r = DO_UPCAST(SCSIDiskReq, req, req);
71 9af99d98 Gerd Hoffmann
    r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
72 a917d384 pbrook
    return r;
73 2e5d83bb pbrook
}
74 2e5d83bb pbrook
75 4c41d2ef Gerd Hoffmann
static void scsi_remove_request(SCSIDiskReq *r)
76 4d611c9a pbrook
{
77 9af99d98 Gerd Hoffmann
    qemu_free(r->iov.iov_base);
78 89b08ae1 Gerd Hoffmann
    scsi_req_free(&r->req);
79 4d611c9a pbrook
}
80 4d611c9a pbrook
81 4c41d2ef Gerd Hoffmann
static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag)
82 4d611c9a pbrook
{
83 89b08ae1 Gerd Hoffmann
    return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag));
84 a917d384 pbrook
}
85 a917d384 pbrook
86 ed3a34a3 Gerd Hoffmann
static void scsi_req_set_status(SCSIRequest *req, int status, int sense_code)
87 ed3a34a3 Gerd Hoffmann
{
88 ed3a34a3 Gerd Hoffmann
    req->status = status;
89 ed3a34a3 Gerd Hoffmann
    scsi_dev_set_sense(req->dev, sense_code);
90 ed3a34a3 Gerd Hoffmann
}
91 ed3a34a3 Gerd Hoffmann
92 a917d384 pbrook
/* Helper function for command completion.  */
93 4c41d2ef Gerd Hoffmann
static void scsi_command_complete(SCSIDiskReq *r, int status, int sense)
94 a917d384 pbrook
{
95 4c41d2ef Gerd Hoffmann
    DPRINTF("Command complete tag=0x%x status=%d sense=%d\n",
96 4c41d2ef Gerd Hoffmann
            r->req.tag, status, sense);
97 ed3a34a3 Gerd Hoffmann
    scsi_req_set_status(&r->req, status, sense);
98 ed3a34a3 Gerd Hoffmann
    scsi_req_complete(&r->req);
99 89b08ae1 Gerd Hoffmann
    scsi_remove_request(r);
100 4d611c9a pbrook
}
101 4d611c9a pbrook
102 4d611c9a pbrook
/* Cancel a pending data transfer.  */
103 8ccc2ace ths
static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
104 4d611c9a pbrook
{
105 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
106 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
107 a917d384 pbrook
    DPRINTF("Cancel tag=0x%x\n", tag);
108 a917d384 pbrook
    r = scsi_find_request(s, tag);
109 a917d384 pbrook
    if (r) {
110 4c41d2ef Gerd Hoffmann
        if (r->req.aiocb)
111 4c41d2ef Gerd Hoffmann
            bdrv_aio_cancel(r->req.aiocb);
112 4c41d2ef Gerd Hoffmann
        r->req.aiocb = NULL;
113 a917d384 pbrook
        scsi_remove_request(r);
114 a917d384 pbrook
    }
115 a917d384 pbrook
}
116 a917d384 pbrook
117 a917d384 pbrook
static void scsi_read_complete(void * opaque, int ret)
118 a917d384 pbrook
{
119 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
120 a917d384 pbrook
121 a917d384 pbrook
    if (ret) {
122 a917d384 pbrook
        DPRINTF("IO error\n");
123 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
124 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
125 4d611c9a pbrook
        return;
126 4d611c9a pbrook
    }
127 4c41d2ef Gerd Hoffmann
    DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->req.tag, r->iov.iov_len);
128 a917d384 pbrook
129 4c41d2ef Gerd Hoffmann
    r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
130 4d611c9a pbrook
}
131 4d611c9a pbrook
132 a917d384 pbrook
/* Read more data from scsi device into buffer.  */
133 8ccc2ace ths
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
134 2e5d83bb pbrook
{
135 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
136 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
137 2e5d83bb pbrook
    uint32_t n;
138 2e5d83bb pbrook
139 a917d384 pbrook
    r = scsi_find_request(s, tag);
140 a917d384 pbrook
    if (!r) {
141 a917d384 pbrook
        BADF("Bad read tag 0x%x\n", tag);
142 b1fa7164 blueswir1
        /* ??? This is the wrong error.  */
143 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
144 a917d384 pbrook
        return;
145 2e5d83bb pbrook
    }
146 a917d384 pbrook
    if (r->sector_count == (uint32_t)-1) {
147 0bf9e31a Blue Swirl
        DPRINTF("Read buf_len=%" PRId64 "\n", r->iov.iov_len);
148 a917d384 pbrook
        r->sector_count = 0;
149 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
150 a917d384 pbrook
        return;
151 2e5d83bb pbrook
    }
152 a917d384 pbrook
    DPRINTF("Read sector_count=%d\n", r->sector_count);
153 a917d384 pbrook
    if (r->sector_count == 0) {
154 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, GOOD, NO_SENSE);
155 a917d384 pbrook
        return;
156 2e5d83bb pbrook
    }
157 2e5d83bb pbrook
158 a917d384 pbrook
    n = r->sector_count;
159 a917d384 pbrook
    if (n > SCSI_DMA_BUF_SIZE / 512)
160 a917d384 pbrook
        n = SCSI_DMA_BUF_SIZE / 512;
161 a917d384 pbrook
162 c87c0672 aliguori
    r->iov.iov_len = n * 512;
163 c87c0672 aliguori
    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
164 251882b7 Gerd Hoffmann
    r->req.aiocb = bdrv_aio_readv(s->qdev.dinfo->bdrv, r->sector, &r->qiov, n,
165 c87c0672 aliguori
                              scsi_read_complete, r);
166 4c41d2ef Gerd Hoffmann
    if (r->req.aiocb == NULL)
167 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
168 a917d384 pbrook
    r->sector += n;
169 a917d384 pbrook
    r->sector_count -= n;
170 2e5d83bb pbrook
}
171 2e5d83bb pbrook
172 4c41d2ef Gerd Hoffmann
static int scsi_handle_write_error(SCSIDiskReq *r, int error)
173 ea8a5d7f aliguori
{
174 4c41d2ef Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
175 f7850099 Kevin Wolf
    BlockInterfaceErrorAction action =
176 f7850099 Kevin Wolf
        drive_get_on_error(s->qdev.dinfo->bdrv, 0);
177 ea8a5d7f aliguori
178 ea8a5d7f aliguori
    if (action == BLOCK_ERR_IGNORE)
179 ea8a5d7f aliguori
        return 0;
180 ea8a5d7f aliguori
181 ea8a5d7f aliguori
    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
182 ea8a5d7f aliguori
            || action == BLOCK_ERR_STOP_ANY) {
183 ea8a5d7f aliguori
        r->status |= SCSI_REQ_STATUS_RETRY;
184 ea8a5d7f aliguori
        vm_stop(0);
185 ea8a5d7f aliguori
    } else {
186 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION,
187 0d65e1f8 Gerd Hoffmann
                HARDWARE_ERROR);
188 ea8a5d7f aliguori
    }
189 ea8a5d7f aliguori
190 ea8a5d7f aliguori
    return 1;
191 ea8a5d7f aliguori
}
192 ea8a5d7f aliguori
193 4d611c9a pbrook
static void scsi_write_complete(void * opaque, int ret)
194 4d611c9a pbrook
{
195 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
196 a917d384 pbrook
    uint32_t len;
197 ea8a5d7f aliguori
    uint32_t n;
198 ea8a5d7f aliguori
199 4c41d2ef Gerd Hoffmann
    r->req.aiocb = NULL;
200 4d611c9a pbrook
201 4d611c9a pbrook
    if (ret) {
202 ea8a5d7f aliguori
        if (scsi_handle_write_error(r, -ret))
203 ea8a5d7f aliguori
            return;
204 4d611c9a pbrook
    }
205 4d611c9a pbrook
206 c87c0672 aliguori
    n = r->iov.iov_len / 512;
207 ea8a5d7f aliguori
    r->sector += n;
208 ea8a5d7f aliguori
    r->sector_count -= n;
209 a917d384 pbrook
    if (r->sector_count == 0) {
210 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, GOOD, NO_SENSE);
211 a917d384 pbrook
    } else {
212 a917d384 pbrook
        len = r->sector_count * 512;
213 a917d384 pbrook
        if (len > SCSI_DMA_BUF_SIZE) {
214 a917d384 pbrook
            len = SCSI_DMA_BUF_SIZE;
215 a917d384 pbrook
        }
216 c87c0672 aliguori
        r->iov.iov_len = len;
217 4c41d2ef Gerd Hoffmann
        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
218 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len);
219 4d611c9a pbrook
    }
220 4d611c9a pbrook
}
221 4d611c9a pbrook
222 4c41d2ef Gerd Hoffmann
static void scsi_write_request(SCSIDiskReq *r)
223 ea8a5d7f aliguori
{
224 4c41d2ef Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
225 ea8a5d7f aliguori
    uint32_t n;
226 ea8a5d7f aliguori
227 c87c0672 aliguori
    n = r->iov.iov_len / 512;
228 ea8a5d7f aliguori
    if (n) {
229 c87c0672 aliguori
        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
230 251882b7 Gerd Hoffmann
        r->req.aiocb = bdrv_aio_writev(s->qdev.dinfo->bdrv, r->sector, &r->qiov, n,
231 c87c0672 aliguori
                                   scsi_write_complete, r);
232 4c41d2ef Gerd Hoffmann
        if (r->req.aiocb == NULL)
233 0d65e1f8 Gerd Hoffmann
            scsi_command_complete(r, CHECK_CONDITION,
234 0d65e1f8 Gerd Hoffmann
                                  HARDWARE_ERROR);
235 ea8a5d7f aliguori
    } else {
236 ea8a5d7f aliguori
        /* Invoke completion routine to fetch data from host.  */
237 ea8a5d7f aliguori
        scsi_write_complete(r, 0);
238 ea8a5d7f aliguori
    }
239 ea8a5d7f aliguori
}
240 ea8a5d7f aliguori
241 4d611c9a pbrook
/* Write data to a scsi device.  Returns nonzero on failure.
242 4d611c9a pbrook
   The transfer may complete asynchronously.  */
243 8ccc2ace ths
static int scsi_write_data(SCSIDevice *d, uint32_t tag)
244 2e5d83bb pbrook
{
245 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
246 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
247 2e5d83bb pbrook
248 a917d384 pbrook
    DPRINTF("Write data tag=0x%x\n", tag);
249 a917d384 pbrook
    r = scsi_find_request(s, tag);
250 a917d384 pbrook
    if (!r) {
251 a917d384 pbrook
        BADF("Bad write tag 0x%x\n", tag);
252 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
253 2e5d83bb pbrook
        return 1;
254 2e5d83bb pbrook
    }
255 ea8a5d7f aliguori
256 4c41d2ef Gerd Hoffmann
    if (r->req.aiocb)
257 a917d384 pbrook
        BADF("Data transfer already in progress\n");
258 ea8a5d7f aliguori
259 ea8a5d7f aliguori
    scsi_write_request(r);
260 2e5d83bb pbrook
261 a917d384 pbrook
    return 0;
262 a917d384 pbrook
}
263 2e5d83bb pbrook
264 213189ab Markus Armbruster
static void scsi_dma_restart_bh(void *opaque)
265 ea8a5d7f aliguori
{
266 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
267 9af99d98 Gerd Hoffmann
    SCSIRequest *req;
268 9af99d98 Gerd Hoffmann
    SCSIDiskReq *r;
269 213189ab Markus Armbruster
270 213189ab Markus Armbruster
    qemu_bh_delete(s->bh);
271 213189ab Markus Armbruster
    s->bh = NULL;
272 ea8a5d7f aliguori
273 9af99d98 Gerd Hoffmann
    QTAILQ_FOREACH(req, &s->qdev.requests, next) {
274 9af99d98 Gerd Hoffmann
        r = DO_UPCAST(SCSIDiskReq, req, req);
275 ea8a5d7f aliguori
        if (r->status & SCSI_REQ_STATUS_RETRY) {
276 ea8a5d7f aliguori
            r->status &= ~SCSI_REQ_STATUS_RETRY;
277 ea8a5d7f aliguori
            scsi_write_request(r); 
278 ea8a5d7f aliguori
        }
279 ea8a5d7f aliguori
    }
280 ea8a5d7f aliguori
}
281 ea8a5d7f aliguori
282 213189ab Markus Armbruster
static void scsi_dma_restart_cb(void *opaque, int running, int reason)
283 213189ab Markus Armbruster
{
284 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
285 213189ab Markus Armbruster
286 213189ab Markus Armbruster
    if (!running)
287 213189ab Markus Armbruster
        return;
288 213189ab Markus Armbruster
289 213189ab Markus Armbruster
    if (!s->bh) {
290 213189ab Markus Armbruster
        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
291 213189ab Markus Armbruster
        qemu_bh_schedule(s->bh);
292 213189ab Markus Armbruster
    }
293 213189ab Markus Armbruster
}
294 213189ab Markus Armbruster
295 a917d384 pbrook
/* Return a pointer to the data buffer.  */
296 8ccc2ace ths
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
297 a917d384 pbrook
{
298 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
299 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
300 2e5d83bb pbrook
301 a917d384 pbrook
    r = scsi_find_request(s, tag);
302 a917d384 pbrook
    if (!r) {
303 a917d384 pbrook
        BADF("Bad buffer tag 0x%x\n", tag);
304 a917d384 pbrook
        return NULL;
305 4d611c9a pbrook
    }
306 3f4cb3d3 blueswir1
    return (uint8_t *)r->iov.iov_base;
307 2e5d83bb pbrook
}
308 2e5d83bb pbrook
309 0b06c059 Gerd Hoffmann
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
310 0b06c059 Gerd Hoffmann
{
311 0b06c059 Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
312 0b06c059 Gerd Hoffmann
    int buflen = 0;
313 0b06c059 Gerd Hoffmann
314 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[1] & 0x2) {
315 0b06c059 Gerd Hoffmann
        /* Command support data - optional, not implemented */
316 0b06c059 Gerd Hoffmann
        BADF("optional INQUIRY command support request not implemented\n");
317 0b06c059 Gerd Hoffmann
        return -1;
318 0b06c059 Gerd Hoffmann
    }
319 0b06c059 Gerd Hoffmann
320 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[1] & 0x1) {
321 0b06c059 Gerd Hoffmann
        /* Vital product data */
322 0b06c059 Gerd Hoffmann
        uint8_t page_code = req->cmd.buf[2];
323 0b06c059 Gerd Hoffmann
        if (req->cmd.xfer < 4) {
324 0b06c059 Gerd Hoffmann
            BADF("Error: Inquiry (EVPD[%02X]) buffer size %zd is "
325 0b06c059 Gerd Hoffmann
                 "less than 4\n", page_code, req->cmd.xfer);
326 0b06c059 Gerd Hoffmann
            return -1;
327 0b06c059 Gerd Hoffmann
        }
328 0b06c059 Gerd Hoffmann
329 0b06c059 Gerd Hoffmann
        if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) {
330 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 5;
331 0b06c059 Gerd Hoffmann
        } else {
332 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;
333 0b06c059 Gerd Hoffmann
        }
334 0b06c059 Gerd Hoffmann
        outbuf[buflen++] = page_code ; // this page
335 0b06c059 Gerd Hoffmann
        outbuf[buflen++] = 0x00;
336 0b06c059 Gerd Hoffmann
337 0b06c059 Gerd Hoffmann
        switch (page_code) {
338 0b06c059 Gerd Hoffmann
        case 0x00: /* Supported page codes, mandatory */
339 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Supported pages] "
340 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
341 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 3;    // number of pages
342 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x00; // list of supported pages (this page)
343 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x80; // unit serial number
344 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x83; // device identification
345 0b06c059 Gerd Hoffmann
            break;
346 0b06c059 Gerd Hoffmann
347 0b06c059 Gerd Hoffmann
        case 0x80: /* Device serial number, optional */
348 0b06c059 Gerd Hoffmann
        {
349 407f879a Blue Swirl
            const char *serial = req->dev->dinfo->serial ?
350 407f879a Blue Swirl
                req->dev->dinfo->serial : "0";
351 0b06c059 Gerd Hoffmann
            int l = strlen(serial);
352 0b06c059 Gerd Hoffmann
353 0b06c059 Gerd Hoffmann
            if (l > req->cmd.xfer)
354 0b06c059 Gerd Hoffmann
                l = req->cmd.xfer;
355 0b06c059 Gerd Hoffmann
            if (l > 20)
356 0b06c059 Gerd Hoffmann
                l = 20;
357 0b06c059 Gerd Hoffmann
358 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Serial number] "
359 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
360 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = l;
361 0b06c059 Gerd Hoffmann
            memcpy(outbuf+buflen, serial, l);
362 0b06c059 Gerd Hoffmann
            buflen += l;
363 0b06c059 Gerd Hoffmann
            break;
364 0b06c059 Gerd Hoffmann
        }
365 0b06c059 Gerd Hoffmann
366 0b06c059 Gerd Hoffmann
        case 0x83: /* Device identification page, mandatory */
367 0b06c059 Gerd Hoffmann
        {
368 0b06c059 Gerd Hoffmann
            int max_len = 255 - 8;
369 0b06c059 Gerd Hoffmann
            int id_len = strlen(bdrv_get_device_name(bdrv));
370 0b06c059 Gerd Hoffmann
371 0b06c059 Gerd Hoffmann
            if (id_len > max_len)
372 0b06c059 Gerd Hoffmann
                id_len = max_len;
373 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Device identification] "
374 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
375 0b06c059 Gerd Hoffmann
376 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 3 + id_len;
377 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x2; // ASCII
378 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;   // not officially assigned
379 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;   // reserved
380 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = id_len; // length of data following
381 0b06c059 Gerd Hoffmann
382 0b06c059 Gerd Hoffmann
            memcpy(outbuf+buflen, bdrv_get_device_name(bdrv), id_len);
383 0b06c059 Gerd Hoffmann
            buflen += id_len;
384 0b06c059 Gerd Hoffmann
            break;
385 0b06c059 Gerd Hoffmann
        }
386 0b06c059 Gerd Hoffmann
        default:
387 0b06c059 Gerd Hoffmann
            BADF("Error: unsupported Inquiry (EVPD[%02X]) "
388 0b06c059 Gerd Hoffmann
                 "buffer size %zd\n", page_code, req->cmd.xfer);
389 0b06c059 Gerd Hoffmann
            return -1;
390 0b06c059 Gerd Hoffmann
        }
391 0b06c059 Gerd Hoffmann
        /* done with EVPD */
392 0b06c059 Gerd Hoffmann
        return buflen;
393 0b06c059 Gerd Hoffmann
    }
394 0b06c059 Gerd Hoffmann
395 0b06c059 Gerd Hoffmann
    /* Standard INQUIRY data */
396 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[2] != 0) {
397 0b06c059 Gerd Hoffmann
        BADF("Error: Inquiry (STANDARD) page or code "
398 0b06c059 Gerd Hoffmann
             "is non-zero [%02X]\n", req->cmd.buf[2]);
399 0b06c059 Gerd Hoffmann
        return -1;
400 0b06c059 Gerd Hoffmann
    }
401 0b06c059 Gerd Hoffmann
402 0b06c059 Gerd Hoffmann
    /* PAGE CODE == 0 */
403 0b06c059 Gerd Hoffmann
    if (req->cmd.xfer < 5) {
404 0b06c059 Gerd Hoffmann
        BADF("Error: Inquiry (STANDARD) buffer size %zd "
405 0b06c059 Gerd Hoffmann
             "is less than 5\n", req->cmd.xfer);
406 0b06c059 Gerd Hoffmann
        return -1;
407 0b06c059 Gerd Hoffmann
    }
408 0b06c059 Gerd Hoffmann
409 0b06c059 Gerd Hoffmann
    if (req->cmd.xfer < 36) {
410 0b06c059 Gerd Hoffmann
        BADF("Error: Inquiry (STANDARD) buffer size %zd "
411 0b06c059 Gerd Hoffmann
             "is less than 36 (TODO: only 5 required)\n", req->cmd.xfer);
412 0b06c059 Gerd Hoffmann
    }
413 0b06c059 Gerd Hoffmann
414 0b06c059 Gerd Hoffmann
    buflen = req->cmd.xfer;
415 0b06c059 Gerd Hoffmann
    if (buflen > SCSI_MAX_INQUIRY_LEN)
416 0b06c059 Gerd Hoffmann
        buflen = SCSI_MAX_INQUIRY_LEN;
417 0b06c059 Gerd Hoffmann
418 0b06c059 Gerd Hoffmann
    memset(outbuf, 0, buflen);
419 0b06c059 Gerd Hoffmann
420 0b06c059 Gerd Hoffmann
    if (req->lun || req->cmd.buf[1] >> 5) {
421 0b06c059 Gerd Hoffmann
        outbuf[0] = 0x7f;        /* LUN not supported */
422 0b06c059 Gerd Hoffmann
        return buflen;
423 0b06c059 Gerd Hoffmann
    }
424 0b06c059 Gerd Hoffmann
425 0b06c059 Gerd Hoffmann
    if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) {
426 0b06c059 Gerd Hoffmann
        outbuf[0] = 5;
427 0b06c059 Gerd Hoffmann
        outbuf[1] = 0x80;
428 550fe6c6 Laszlo Ast
        memcpy(&outbuf[16], "QEMU CD-ROM     ", 16);
429 0b06c059 Gerd Hoffmann
    } else {
430 0b06c059 Gerd Hoffmann
        outbuf[0] = 0;
431 550fe6c6 Laszlo Ast
        memcpy(&outbuf[16], "QEMU HARDDISK   ", 16);
432 0b06c059 Gerd Hoffmann
    }
433 550fe6c6 Laszlo Ast
    memcpy(&outbuf[8], "QEMU    ", 8);
434 0b06c059 Gerd Hoffmann
    memcpy(&outbuf[32], QEMU_VERSION, 4);
435 0b06c059 Gerd Hoffmann
    /* Identify device as SCSI-3 rev 1.
436 0b06c059 Gerd Hoffmann
       Some later commands are also implemented. */
437 0b06c059 Gerd Hoffmann
    outbuf[2] = 3;
438 0b06c059 Gerd Hoffmann
    outbuf[3] = 2; /* Format 2 */
439 0b06c059 Gerd Hoffmann
    outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
440 0b06c059 Gerd Hoffmann
    /* Sync data transfer and TCQ.  */
441 0b06c059 Gerd Hoffmann
    outbuf[7] = 0x10 | (req->bus->tcq ? 0x02 : 0);
442 0b06c059 Gerd Hoffmann
    return buflen;
443 0b06c059 Gerd Hoffmann
}
444 0b06c059 Gerd Hoffmann
445 ebddfcbe Gerd Hoffmann
static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
446 ebddfcbe Gerd Hoffmann
{
447 ebddfcbe Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
448 ebddfcbe Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
449 ebddfcbe Gerd Hoffmann
    int cylinders, heads, secs;
450 ebddfcbe Gerd Hoffmann
451 ebddfcbe Gerd Hoffmann
    switch (page) {
452 ebddfcbe Gerd Hoffmann
    case 4: /* Rigid disk device geometry page. */
453 ebddfcbe Gerd Hoffmann
        p[0] = 4;
454 ebddfcbe Gerd Hoffmann
        p[1] = 0x16;
455 ebddfcbe Gerd Hoffmann
        /* if a geometry hint is available, use it */
456 ebddfcbe Gerd Hoffmann
        bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
457 ebddfcbe Gerd Hoffmann
        p[2] = (cylinders >> 16) & 0xff;
458 ebddfcbe Gerd Hoffmann
        p[3] = (cylinders >> 8) & 0xff;
459 ebddfcbe Gerd Hoffmann
        p[4] = cylinders & 0xff;
460 ebddfcbe Gerd Hoffmann
        p[5] = heads & 0xff;
461 ebddfcbe Gerd Hoffmann
        /* Write precomp start cylinder, disabled */
462 ebddfcbe Gerd Hoffmann
        p[6] = (cylinders >> 16) & 0xff;
463 ebddfcbe Gerd Hoffmann
        p[7] = (cylinders >> 8) & 0xff;
464 ebddfcbe Gerd Hoffmann
        p[8] = cylinders & 0xff;
465 ebddfcbe Gerd Hoffmann
        /* Reduced current start cylinder, disabled */
466 ebddfcbe Gerd Hoffmann
        p[9] = (cylinders >> 16) & 0xff;
467 ebddfcbe Gerd Hoffmann
        p[10] = (cylinders >> 8) & 0xff;
468 ebddfcbe Gerd Hoffmann
        p[11] = cylinders & 0xff;
469 ebddfcbe Gerd Hoffmann
        /* Device step rate [ns], 200ns */
470 ebddfcbe Gerd Hoffmann
        p[12] = 0;
471 ebddfcbe Gerd Hoffmann
        p[13] = 200;
472 ebddfcbe Gerd Hoffmann
        /* Landing zone cylinder */
473 ebddfcbe Gerd Hoffmann
        p[14] = 0xff;
474 ebddfcbe Gerd Hoffmann
        p[15] =  0xff;
475 ebddfcbe Gerd Hoffmann
        p[16] = 0xff;
476 ebddfcbe Gerd Hoffmann
        /* Medium rotation rate [rpm], 5400 rpm */
477 ebddfcbe Gerd Hoffmann
        p[20] = (5400 >> 8) & 0xff;
478 ebddfcbe Gerd Hoffmann
        p[21] = 5400 & 0xff;
479 ebddfcbe Gerd Hoffmann
        return 0x16;
480 ebddfcbe Gerd Hoffmann
481 ebddfcbe Gerd Hoffmann
    case 5: /* Flexible disk device geometry page. */
482 ebddfcbe Gerd Hoffmann
        p[0] = 5;
483 ebddfcbe Gerd Hoffmann
        p[1] = 0x1e;
484 ebddfcbe Gerd Hoffmann
        /* Transfer rate [kbit/s], 5Mbit/s */
485 ebddfcbe Gerd Hoffmann
        p[2] = 5000 >> 8;
486 ebddfcbe Gerd Hoffmann
        p[3] = 5000 & 0xff;
487 ebddfcbe Gerd Hoffmann
        /* if a geometry hint is available, use it */
488 ebddfcbe Gerd Hoffmann
        bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
489 ebddfcbe Gerd Hoffmann
        p[4] = heads & 0xff;
490 ebddfcbe Gerd Hoffmann
        p[5] = secs & 0xff;
491 ebddfcbe Gerd Hoffmann
        p[6] = s->cluster_size * 2;
492 ebddfcbe Gerd Hoffmann
        p[8] = (cylinders >> 8) & 0xff;
493 ebddfcbe Gerd Hoffmann
        p[9] = cylinders & 0xff;
494 ebddfcbe Gerd Hoffmann
        /* Write precomp start cylinder, disabled */
495 ebddfcbe Gerd Hoffmann
        p[10] = (cylinders >> 8) & 0xff;
496 ebddfcbe Gerd Hoffmann
        p[11] = cylinders & 0xff;
497 ebddfcbe Gerd Hoffmann
        /* Reduced current start cylinder, disabled */
498 ebddfcbe Gerd Hoffmann
        p[12] = (cylinders >> 8) & 0xff;
499 ebddfcbe Gerd Hoffmann
        p[13] = cylinders & 0xff;
500 ebddfcbe Gerd Hoffmann
        /* Device step rate [100us], 100us */
501 ebddfcbe Gerd Hoffmann
        p[14] = 0;
502 ebddfcbe Gerd Hoffmann
        p[15] = 1;
503 ebddfcbe Gerd Hoffmann
        /* Device step pulse width [us], 1us */
504 ebddfcbe Gerd Hoffmann
        p[16] = 1;
505 ebddfcbe Gerd Hoffmann
        /* Device head settle delay [100us], 100us */
506 ebddfcbe Gerd Hoffmann
        p[17] = 0;
507 ebddfcbe Gerd Hoffmann
        p[18] = 1;
508 ebddfcbe Gerd Hoffmann
        /* Motor on delay [0.1s], 0.1s */
509 ebddfcbe Gerd Hoffmann
        p[19] = 1;
510 ebddfcbe Gerd Hoffmann
        /* Motor off delay [0.1s], 0.1s */
511 ebddfcbe Gerd Hoffmann
        p[20] = 1;
512 ebddfcbe Gerd Hoffmann
        /* Medium rotation rate [rpm], 5400 rpm */
513 ebddfcbe Gerd Hoffmann
        p[28] = (5400 >> 8) & 0xff;
514 ebddfcbe Gerd Hoffmann
        p[29] = 5400 & 0xff;
515 ebddfcbe Gerd Hoffmann
        return 0x1e;
516 ebddfcbe Gerd Hoffmann
517 ebddfcbe Gerd Hoffmann
    case 8: /* Caching page.  */
518 ebddfcbe Gerd Hoffmann
        p[0] = 8;
519 ebddfcbe Gerd Hoffmann
        p[1] = 0x12;
520 ebddfcbe Gerd Hoffmann
        if (bdrv_enable_write_cache(s->qdev.dinfo->bdrv)) {
521 ebddfcbe Gerd Hoffmann
            p[2] = 4; /* WCE */
522 ebddfcbe Gerd Hoffmann
        }
523 ebddfcbe Gerd Hoffmann
        return 20;
524 ebddfcbe Gerd Hoffmann
525 ebddfcbe Gerd Hoffmann
    case 0x2a: /* CD Capabilities and Mechanical Status page. */
526 ebddfcbe Gerd Hoffmann
        if (bdrv_get_type_hint(bdrv) != BDRV_TYPE_CDROM)
527 ebddfcbe Gerd Hoffmann
            return 0;
528 ebddfcbe Gerd Hoffmann
        p[0] = 0x2a;
529 ebddfcbe Gerd Hoffmann
        p[1] = 0x14;
530 ebddfcbe Gerd Hoffmann
        p[2] = 3; // CD-R & CD-RW read
531 ebddfcbe Gerd Hoffmann
        p[3] = 0; // Writing not supported
532 ebddfcbe Gerd Hoffmann
        p[4] = 0x7f; /* Audio, composite, digital out,
533 ebddfcbe Gerd Hoffmann
                        mode 2 form 1&2, multi session */
534 ebddfcbe Gerd Hoffmann
        p[5] = 0xff; /* CD DA, DA accurate, RW supported,
535 ebddfcbe Gerd Hoffmann
                        RW corrected, C2 errors, ISRC,
536 ebddfcbe Gerd Hoffmann
                        UPC, Bar code */
537 ebddfcbe Gerd Hoffmann
        p[6] = 0x2d | (bdrv_is_locked(s->qdev.dinfo->bdrv)? 2 : 0);
538 ebddfcbe Gerd Hoffmann
        /* Locking supported, jumper present, eject, tray */
539 ebddfcbe Gerd Hoffmann
        p[7] = 0; /* no volume & mute control, no
540 ebddfcbe Gerd Hoffmann
                     changer */
541 ebddfcbe Gerd Hoffmann
        p[8] = (50 * 176) >> 8; // 50x read speed
542 ebddfcbe Gerd Hoffmann
        p[9] = (50 * 176) & 0xff;
543 ebddfcbe Gerd Hoffmann
        p[10] = 0 >> 8; // No volume
544 ebddfcbe Gerd Hoffmann
        p[11] = 0 & 0xff;
545 ebddfcbe Gerd Hoffmann
        p[12] = 2048 >> 8; // 2M buffer
546 ebddfcbe Gerd Hoffmann
        p[13] = 2048 & 0xff;
547 ebddfcbe Gerd Hoffmann
        p[14] = (16 * 176) >> 8; // 16x read speed current
548 ebddfcbe Gerd Hoffmann
        p[15] = (16 * 176) & 0xff;
549 ebddfcbe Gerd Hoffmann
        p[18] = (16 * 176) >> 8; // 16x write speed
550 ebddfcbe Gerd Hoffmann
        p[19] = (16 * 176) & 0xff;
551 ebddfcbe Gerd Hoffmann
        p[20] = (16 * 176) >> 8; // 16x write speed current
552 ebddfcbe Gerd Hoffmann
        p[21] = (16 * 176) & 0xff;
553 ebddfcbe Gerd Hoffmann
        return 22;
554 ebddfcbe Gerd Hoffmann
555 ebddfcbe Gerd Hoffmann
    default:
556 ebddfcbe Gerd Hoffmann
        return 0;
557 ebddfcbe Gerd Hoffmann
    }
558 ebddfcbe Gerd Hoffmann
}
559 ebddfcbe Gerd Hoffmann
560 ebddfcbe Gerd Hoffmann
static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
561 ebddfcbe Gerd Hoffmann
{
562 ebddfcbe Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
563 ebddfcbe Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
564 ebddfcbe Gerd Hoffmann
    uint64_t nb_sectors;
565 ebddfcbe Gerd Hoffmann
    int page, dbd, buflen;
566 ebddfcbe Gerd Hoffmann
    uint8_t *p;
567 ebddfcbe Gerd Hoffmann
568 ebddfcbe Gerd Hoffmann
    dbd = req->cmd.buf[1]  & 0x8;
569 ebddfcbe Gerd Hoffmann
    page = req->cmd.buf[2] & 0x3f;
570 ebddfcbe Gerd Hoffmann
    DPRINTF("Mode Sense (page %d, len %zd)\n", page, req->cmd.xfer);
571 ebddfcbe Gerd Hoffmann
    memset(outbuf, 0, req->cmd.xfer);
572 ebddfcbe Gerd Hoffmann
    p = outbuf;
573 ebddfcbe Gerd Hoffmann
574 ebddfcbe Gerd Hoffmann
    p[1] = 0; /* Default media type.  */
575 ebddfcbe Gerd Hoffmann
    p[3] = 0; /* Block descriptor length.  */
576 ebddfcbe Gerd Hoffmann
    if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM ||
577 ebddfcbe Gerd Hoffmann
        bdrv_is_read_only(bdrv)) {
578 ebddfcbe Gerd Hoffmann
        p[2] = 0x80; /* Readonly.  */
579 ebddfcbe Gerd Hoffmann
    }
580 ebddfcbe Gerd Hoffmann
    p += 4;
581 ebddfcbe Gerd Hoffmann
582 ebddfcbe Gerd Hoffmann
    bdrv_get_geometry(bdrv, &nb_sectors);
583 ebddfcbe Gerd Hoffmann
    if ((~dbd) & nb_sectors) {
584 ebddfcbe Gerd Hoffmann
        outbuf[3] = 8; /* Block descriptor length  */
585 ebddfcbe Gerd Hoffmann
        nb_sectors /= s->cluster_size;
586 ebddfcbe Gerd Hoffmann
        nb_sectors--;
587 ebddfcbe Gerd Hoffmann
        if (nb_sectors > 0xffffff)
588 ebddfcbe Gerd Hoffmann
            nb_sectors = 0xffffff;
589 ebddfcbe Gerd Hoffmann
        p[0] = 0; /* media density code */
590 ebddfcbe Gerd Hoffmann
        p[1] = (nb_sectors >> 16) & 0xff;
591 ebddfcbe Gerd Hoffmann
        p[2] = (nb_sectors >> 8) & 0xff;
592 ebddfcbe Gerd Hoffmann
        p[3] = nb_sectors & 0xff;
593 ebddfcbe Gerd Hoffmann
        p[4] = 0; /* reserved */
594 ebddfcbe Gerd Hoffmann
        p[5] = 0; /* bytes 5-7 are the sector size in bytes */
595 ebddfcbe Gerd Hoffmann
        p[6] = s->cluster_size * 2;
596 ebddfcbe Gerd Hoffmann
        p[7] = 0;
597 ebddfcbe Gerd Hoffmann
        p += 8;
598 ebddfcbe Gerd Hoffmann
    }
599 ebddfcbe Gerd Hoffmann
600 ebddfcbe Gerd Hoffmann
    switch (page) {
601 ebddfcbe Gerd Hoffmann
    case 0x04:
602 ebddfcbe Gerd Hoffmann
    case 0x05:
603 ebddfcbe Gerd Hoffmann
    case 0x08:
604 ebddfcbe Gerd Hoffmann
    case 0x2a:
605 ebddfcbe Gerd Hoffmann
        p += mode_sense_page(req, page, p);
606 ebddfcbe Gerd Hoffmann
        break;
607 ebddfcbe Gerd Hoffmann
    case 0x3f:
608 ebddfcbe Gerd Hoffmann
        p += mode_sense_page(req, 0x08, p);
609 ebddfcbe Gerd Hoffmann
        p += mode_sense_page(req, 0x2a, p);
610 ebddfcbe Gerd Hoffmann
        break;
611 ebddfcbe Gerd Hoffmann
    }
612 ebddfcbe Gerd Hoffmann
613 ebddfcbe Gerd Hoffmann
    buflen = p - outbuf;
614 ebddfcbe Gerd Hoffmann
    outbuf[0] = buflen - 4;
615 ebddfcbe Gerd Hoffmann
    if (buflen > req->cmd.xfer)
616 ebddfcbe Gerd Hoffmann
        buflen = req->cmd.xfer;
617 ebddfcbe Gerd Hoffmann
    return buflen;
618 ebddfcbe Gerd Hoffmann
}
619 ebddfcbe Gerd Hoffmann
620 02880f43 Gerd Hoffmann
static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
621 02880f43 Gerd Hoffmann
{
622 02880f43 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
623 02880f43 Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
624 02880f43 Gerd Hoffmann
    int start_track, format, msf, toclen;
625 02880f43 Gerd Hoffmann
    uint64_t nb_sectors;
626 02880f43 Gerd Hoffmann
627 02880f43 Gerd Hoffmann
    msf = req->cmd.buf[1] & 2;
628 02880f43 Gerd Hoffmann
    format = req->cmd.buf[2] & 0xf;
629 02880f43 Gerd Hoffmann
    start_track = req->cmd.buf[6];
630 02880f43 Gerd Hoffmann
    bdrv_get_geometry(bdrv, &nb_sectors);
631 02880f43 Gerd Hoffmann
    DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
632 02880f43 Gerd Hoffmann
    nb_sectors /= s->cluster_size;
633 02880f43 Gerd Hoffmann
    switch (format) {
634 02880f43 Gerd Hoffmann
    case 0:
635 02880f43 Gerd Hoffmann
        toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
636 02880f43 Gerd Hoffmann
        break;
637 02880f43 Gerd Hoffmann
    case 1:
638 02880f43 Gerd Hoffmann
        /* multi session : only a single session defined */
639 02880f43 Gerd Hoffmann
        toclen = 12;
640 02880f43 Gerd Hoffmann
        memset(outbuf, 0, 12);
641 02880f43 Gerd Hoffmann
        outbuf[1] = 0x0a;
642 02880f43 Gerd Hoffmann
        outbuf[2] = 0x01;
643 02880f43 Gerd Hoffmann
        outbuf[3] = 0x01;
644 02880f43 Gerd Hoffmann
        break;
645 02880f43 Gerd Hoffmann
    case 2:
646 02880f43 Gerd Hoffmann
        toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track);
647 02880f43 Gerd Hoffmann
        break;
648 02880f43 Gerd Hoffmann
    default:
649 02880f43 Gerd Hoffmann
        return -1;
650 02880f43 Gerd Hoffmann
    }
651 02880f43 Gerd Hoffmann
    if (toclen > req->cmd.xfer)
652 02880f43 Gerd Hoffmann
        toclen = req->cmd.xfer;
653 02880f43 Gerd Hoffmann
    return toclen;
654 02880f43 Gerd Hoffmann
}
655 02880f43 Gerd Hoffmann
656 aa5dbdc1 Gerd Hoffmann
static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
657 aa5dbdc1 Gerd Hoffmann
{
658 e7e25e32 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
659 aa5dbdc1 Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
660 e7e25e32 Gerd Hoffmann
    uint64_t nb_sectors;
661 aa5dbdc1 Gerd Hoffmann
    int buflen = 0;
662 aa5dbdc1 Gerd Hoffmann
663 aa5dbdc1 Gerd Hoffmann
    switch (req->cmd.buf[0]) {
664 aa5dbdc1 Gerd Hoffmann
    case TEST_UNIT_READY:
665 aa5dbdc1 Gerd Hoffmann
        if (!bdrv_is_inserted(bdrv))
666 aa5dbdc1 Gerd Hoffmann
            goto not_ready;
667 aa5dbdc1 Gerd Hoffmann
        break;
668 51ad87c9 Gerd Hoffmann
    case REQUEST_SENSE:
669 51ad87c9 Gerd Hoffmann
        if (req->cmd.xfer < 4)
670 51ad87c9 Gerd Hoffmann
            goto illegal_request;
671 51ad87c9 Gerd Hoffmann
        memset(outbuf, 0, 4);
672 51ad87c9 Gerd Hoffmann
        buflen = 4;
673 51ad87c9 Gerd Hoffmann
        if (req->dev->sense.key == NOT_READY && req->cmd.xfer >= 18) {
674 51ad87c9 Gerd Hoffmann
            memset(outbuf, 0, 18);
675 51ad87c9 Gerd Hoffmann
            buflen = 18;
676 51ad87c9 Gerd Hoffmann
            outbuf[7] = 10;
677 51ad87c9 Gerd Hoffmann
            /* asc 0x3a, ascq 0: Medium not present */
678 51ad87c9 Gerd Hoffmann
            outbuf[12] = 0x3a;
679 51ad87c9 Gerd Hoffmann
            outbuf[13] = 0;
680 51ad87c9 Gerd Hoffmann
        }
681 51ad87c9 Gerd Hoffmann
        outbuf[0] = 0xf0;
682 51ad87c9 Gerd Hoffmann
        outbuf[1] = 0;
683 51ad87c9 Gerd Hoffmann
        outbuf[2] = req->dev->sense.key;
684 51ad87c9 Gerd Hoffmann
        scsi_dev_clear_sense(req->dev);
685 51ad87c9 Gerd Hoffmann
        break;
686 0b06c059 Gerd Hoffmann
    case INQUIRY:
687 0b06c059 Gerd Hoffmann
        buflen = scsi_disk_emulate_inquiry(req, outbuf);
688 0b06c059 Gerd Hoffmann
        if (buflen < 0)
689 0b06c059 Gerd Hoffmann
            goto illegal_request;
690 0b06c059 Gerd Hoffmann
        break;
691 ebddfcbe Gerd Hoffmann
    case MODE_SENSE:
692 ebddfcbe Gerd Hoffmann
    case MODE_SENSE_10:
693 ebddfcbe Gerd Hoffmann
        buflen = scsi_disk_emulate_mode_sense(req, outbuf);
694 ebddfcbe Gerd Hoffmann
        if (buflen < 0)
695 ebddfcbe Gerd Hoffmann
            goto illegal_request;
696 ebddfcbe Gerd Hoffmann
        break;
697 02880f43 Gerd Hoffmann
    case READ_TOC:
698 02880f43 Gerd Hoffmann
        buflen = scsi_disk_emulate_read_toc(req, outbuf);
699 02880f43 Gerd Hoffmann
        if (buflen < 0)
700 02880f43 Gerd Hoffmann
            goto illegal_request;
701 02880f43 Gerd Hoffmann
        break;
702 3d53ba18 Gerd Hoffmann
    case RESERVE:
703 3d53ba18 Gerd Hoffmann
        if (req->cmd.buf[1] & 1)
704 3d53ba18 Gerd Hoffmann
            goto illegal_request;
705 3d53ba18 Gerd Hoffmann
        break;
706 3d53ba18 Gerd Hoffmann
    case RESERVE_10:
707 3d53ba18 Gerd Hoffmann
        if (req->cmd.buf[1] & 3)
708 3d53ba18 Gerd Hoffmann
            goto illegal_request;
709 3d53ba18 Gerd Hoffmann
        break;
710 3d53ba18 Gerd Hoffmann
    case RELEASE:
711 3d53ba18 Gerd Hoffmann
        if (req->cmd.buf[1] & 1)
712 3d53ba18 Gerd Hoffmann
            goto illegal_request;
713 3d53ba18 Gerd Hoffmann
        break;
714 3d53ba18 Gerd Hoffmann
    case RELEASE_10:
715 3d53ba18 Gerd Hoffmann
        if (req->cmd.buf[1] & 3)
716 3d53ba18 Gerd Hoffmann
            goto illegal_request;
717 3d53ba18 Gerd Hoffmann
        break;
718 8d3628ff Gerd Hoffmann
    case START_STOP:
719 8d3628ff Gerd Hoffmann
        if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM && (req->cmd.buf[4] & 2)) {
720 8d3628ff Gerd Hoffmann
            /* load/eject medium */
721 8d3628ff Gerd Hoffmann
            bdrv_eject(bdrv, !(req->cmd.buf[4] & 1));
722 8d3628ff Gerd Hoffmann
        }
723 8d3628ff Gerd Hoffmann
        break;
724 c68b9f34 Gerd Hoffmann
    case ALLOW_MEDIUM_REMOVAL:
725 c68b9f34 Gerd Hoffmann
        bdrv_set_locked(bdrv, req->cmd.buf[4] & 1);
726 c68b9f34 Gerd Hoffmann
        break;
727 e7e25e32 Gerd Hoffmann
    case READ_CAPACITY:
728 e7e25e32 Gerd Hoffmann
        /* The normal LEN field for this command is zero.  */
729 e7e25e32 Gerd Hoffmann
        memset(outbuf, 0, 8);
730 e7e25e32 Gerd Hoffmann
        bdrv_get_geometry(bdrv, &nb_sectors);
731 e7e25e32 Gerd Hoffmann
        if (!nb_sectors)
732 e7e25e32 Gerd Hoffmann
            goto not_ready;
733 e7e25e32 Gerd Hoffmann
        nb_sectors /= s->cluster_size;
734 e7e25e32 Gerd Hoffmann
        /* Returned value is the address of the last sector.  */
735 e7e25e32 Gerd Hoffmann
        nb_sectors--;
736 e7e25e32 Gerd Hoffmann
        /* Remember the new size for read/write sanity checking. */
737 e7e25e32 Gerd Hoffmann
        s->max_lba = nb_sectors;
738 e7e25e32 Gerd Hoffmann
        /* Clip to 2TB, instead of returning capacity modulo 2TB. */
739 e7e25e32 Gerd Hoffmann
        if (nb_sectors > UINT32_MAX)
740 e7e25e32 Gerd Hoffmann
            nb_sectors = UINT32_MAX;
741 e7e25e32 Gerd Hoffmann
        outbuf[0] = (nb_sectors >> 24) & 0xff;
742 e7e25e32 Gerd Hoffmann
        outbuf[1] = (nb_sectors >> 16) & 0xff;
743 e7e25e32 Gerd Hoffmann
        outbuf[2] = (nb_sectors >> 8) & 0xff;
744 e7e25e32 Gerd Hoffmann
        outbuf[3] = nb_sectors & 0xff;
745 e7e25e32 Gerd Hoffmann
        outbuf[4] = 0;
746 e7e25e32 Gerd Hoffmann
        outbuf[5] = 0;
747 e7e25e32 Gerd Hoffmann
        outbuf[6] = s->cluster_size * 2;
748 e7e25e32 Gerd Hoffmann
        outbuf[7] = 0;
749 e7e25e32 Gerd Hoffmann
        buflen = 8;
750 e7e25e32 Gerd Hoffmann
        break;
751 fc903943 Gerd Hoffmann
    case SYNCHRONIZE_CACHE:
752 fc903943 Gerd Hoffmann
        bdrv_flush(bdrv);
753 fc903943 Gerd Hoffmann
        break;
754 38215553 Gerd Hoffmann
    case GET_CONFIGURATION:
755 38215553 Gerd Hoffmann
        memset(outbuf, 0, 8);
756 38215553 Gerd Hoffmann
        /* ??? This should probably return much more information.  For now
757 38215553 Gerd Hoffmann
           just return the basic header indicating the CD-ROM profile.  */
758 38215553 Gerd Hoffmann
        outbuf[7] = 8; // CD-ROM
759 38215553 Gerd Hoffmann
        buflen = 8;
760 38215553 Gerd Hoffmann
        break;
761 5dd90e2a Gerd Hoffmann
    case SERVICE_ACTION_IN:
762 5dd90e2a Gerd Hoffmann
        /* Service Action In subcommands. */
763 5dd90e2a Gerd Hoffmann
        if ((req->cmd.buf[1] & 31) == 0x10) {
764 5dd90e2a Gerd Hoffmann
            DPRINTF("SAI READ CAPACITY(16)\n");
765 5dd90e2a Gerd Hoffmann
            memset(outbuf, 0, req->cmd.xfer);
766 5dd90e2a Gerd Hoffmann
            bdrv_get_geometry(bdrv, &nb_sectors);
767 5dd90e2a Gerd Hoffmann
            if (!nb_sectors)
768 5dd90e2a Gerd Hoffmann
                goto not_ready;
769 5dd90e2a Gerd Hoffmann
            nb_sectors /= s->cluster_size;
770 5dd90e2a Gerd Hoffmann
            /* Returned value is the address of the last sector.  */
771 5dd90e2a Gerd Hoffmann
            nb_sectors--;
772 5dd90e2a Gerd Hoffmann
            /* Remember the new size for read/write sanity checking. */
773 5dd90e2a Gerd Hoffmann
            s->max_lba = nb_sectors;
774 5dd90e2a Gerd Hoffmann
            outbuf[0] = (nb_sectors >> 56) & 0xff;
775 5dd90e2a Gerd Hoffmann
            outbuf[1] = (nb_sectors >> 48) & 0xff;
776 5dd90e2a Gerd Hoffmann
            outbuf[2] = (nb_sectors >> 40) & 0xff;
777 5dd90e2a Gerd Hoffmann
            outbuf[3] = (nb_sectors >> 32) & 0xff;
778 5dd90e2a Gerd Hoffmann
            outbuf[4] = (nb_sectors >> 24) & 0xff;
779 5dd90e2a Gerd Hoffmann
            outbuf[5] = (nb_sectors >> 16) & 0xff;
780 5dd90e2a Gerd Hoffmann
            outbuf[6] = (nb_sectors >> 8) & 0xff;
781 5dd90e2a Gerd Hoffmann
            outbuf[7] = nb_sectors & 0xff;
782 5dd90e2a Gerd Hoffmann
            outbuf[8] = 0;
783 5dd90e2a Gerd Hoffmann
            outbuf[9] = 0;
784 5dd90e2a Gerd Hoffmann
            outbuf[10] = s->cluster_size * 2;
785 5dd90e2a Gerd Hoffmann
            outbuf[11] = 0;
786 5dd90e2a Gerd Hoffmann
            /* Protection, exponent and lowest lba field left blank. */
787 5dd90e2a Gerd Hoffmann
            buflen = req->cmd.xfer;
788 5dd90e2a Gerd Hoffmann
            break;
789 5dd90e2a Gerd Hoffmann
        }
790 5dd90e2a Gerd Hoffmann
        DPRINTF("Unsupported Service Action In\n");
791 5dd90e2a Gerd Hoffmann
        goto illegal_request;
792 39ec9a50 Gerd Hoffmann
    case REPORT_LUNS:
793 39ec9a50 Gerd Hoffmann
        if (req->cmd.xfer < 16)
794 39ec9a50 Gerd Hoffmann
            goto illegal_request;
795 39ec9a50 Gerd Hoffmann
        memset(outbuf, 0, 16);
796 39ec9a50 Gerd Hoffmann
        outbuf[3] = 8;
797 39ec9a50 Gerd Hoffmann
        buflen = 16;
798 39ec9a50 Gerd Hoffmann
        break;
799 88f8a5ed Gerd Hoffmann
    case VERIFY:
800 88f8a5ed Gerd Hoffmann
        break;
801 aa5dbdc1 Gerd Hoffmann
    default:
802 aa5dbdc1 Gerd Hoffmann
        goto illegal_request;
803 aa5dbdc1 Gerd Hoffmann
    }
804 aa5dbdc1 Gerd Hoffmann
    scsi_req_set_status(req, GOOD, NO_SENSE);
805 aa5dbdc1 Gerd Hoffmann
    return buflen;
806 aa5dbdc1 Gerd Hoffmann
807 aa5dbdc1 Gerd Hoffmann
not_ready:
808 aa5dbdc1 Gerd Hoffmann
    scsi_req_set_status(req, CHECK_CONDITION, NOT_READY);
809 aa5dbdc1 Gerd Hoffmann
    return 0;
810 aa5dbdc1 Gerd Hoffmann
811 aa5dbdc1 Gerd Hoffmann
illegal_request:
812 aa5dbdc1 Gerd Hoffmann
    scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST);
813 aa5dbdc1 Gerd Hoffmann
    return 0;
814 aa5dbdc1 Gerd Hoffmann
}
815 aa5dbdc1 Gerd Hoffmann
816 2e5d83bb pbrook
/* Execute a scsi command.  Returns the length of the data expected by the
817 2e5d83bb pbrook
   command.  This will be Positive for data transfers from the device
818 2e5d83bb pbrook
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
819 2e5d83bb pbrook
   and zero if the command does not transfer any data.  */
820 2e5d83bb pbrook
821 8ccc2ace ths
static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
822 8ccc2ace ths
                                 uint8_t *buf, int lun)
823 2e5d83bb pbrook
{
824 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
825 86106e59 aliguori
    uint64_t lba;
826 2e5d83bb pbrook
    uint32_t len;
827 2e5d83bb pbrook
    int cmdlen;
828 2e5d83bb pbrook
    int is_write;
829 a917d384 pbrook
    uint8_t command;
830 a917d384 pbrook
    uint8_t *outbuf;
831 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
832 aa5dbdc1 Gerd Hoffmann
    int rc;
833 a917d384 pbrook
834 a917d384 pbrook
    command = buf[0];
835 a917d384 pbrook
    r = scsi_find_request(s, tag);
836 a917d384 pbrook
    if (r) {
837 a917d384 pbrook
        BADF("Tag 0x%x already in use\n", tag);
838 8ccc2ace ths
        scsi_cancel_io(d, tag);
839 a917d384 pbrook
    }
840 a917d384 pbrook
    /* ??? Tags are not unique for different luns.  We only implement a
841 a917d384 pbrook
       single lun, so this should not matter.  */
842 89b08ae1 Gerd Hoffmann
    r = scsi_new_request(d, tag, lun);
843 3f4cb3d3 blueswir1
    outbuf = (uint8_t *)r->iov.iov_base;
844 2e5d83bb pbrook
    is_write = 0;
845 a917d384 pbrook
    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
846 a917d384 pbrook
    switch (command >> 5) {
847 2e5d83bb pbrook
    case 0:
848 86106e59 aliguori
        lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
849 86106e59 aliguori
              (((uint64_t) buf[1] & 0x1f) << 16);
850 2e5d83bb pbrook
        len = buf[4];
851 2e5d83bb pbrook
        cmdlen = 6;
852 2e5d83bb pbrook
        break;
853 2e5d83bb pbrook
    case 1:
854 2e5d83bb pbrook
    case 2:
855 86106e59 aliguori
        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
856 86106e59 aliguori
              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
857 2e5d83bb pbrook
        len = buf[8] | (buf[7] << 8);
858 2e5d83bb pbrook
        cmdlen = 10;
859 2e5d83bb pbrook
        break;
860 2e5d83bb pbrook
    case 4:
861 86106e59 aliguori
        lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
862 86106e59 aliguori
              ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
863 86106e59 aliguori
              ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
864 86106e59 aliguori
              ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
865 2e5d83bb pbrook
        len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
866 2e5d83bb pbrook
        cmdlen = 16;
867 2e5d83bb pbrook
        break;
868 2e5d83bb pbrook
    case 5:
869 86106e59 aliguori
        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
870 86106e59 aliguori
              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
871 2e5d83bb pbrook
        len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
872 2e5d83bb pbrook
        cmdlen = 12;
873 2e5d83bb pbrook
        break;
874 2e5d83bb pbrook
    default:
875 a917d384 pbrook
        BADF("Unsupported command length, command %x\n", command);
876 2e5d83bb pbrook
        goto fail;
877 2e5d83bb pbrook
    }
878 2e5d83bb pbrook
#ifdef DEBUG_SCSI
879 2e5d83bb pbrook
    {
880 2e5d83bb pbrook
        int i;
881 2e5d83bb pbrook
        for (i = 1; i < cmdlen; i++) {
882 2e5d83bb pbrook
            printf(" 0x%02x", buf[i]);
883 2e5d83bb pbrook
        }
884 2e5d83bb pbrook
        printf("\n");
885 2e5d83bb pbrook
    }
886 2e5d83bb pbrook
#endif
887 aa5dbdc1 Gerd Hoffmann
888 aa5dbdc1 Gerd Hoffmann
    if (scsi_req_parse(&r->req, buf) != 0) {
889 aa5dbdc1 Gerd Hoffmann
        BADF("Unsupported command length, command %x\n", command);
890 aa5dbdc1 Gerd Hoffmann
        goto fail;
891 aa5dbdc1 Gerd Hoffmann
    }
892 aa5dbdc1 Gerd Hoffmann
    assert(r->req.cmd.len == cmdlen);
893 aa5dbdc1 Gerd Hoffmann
    assert(r->req.cmd.lba == lba);
894 aa5dbdc1 Gerd Hoffmann
895 0fc5c15a pbrook
    if (lun || buf[1] >> 5) {
896 2e5d83bb pbrook
        /* Only LUN 0 supported.  */
897 0fc5c15a pbrook
        DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
898 ebf46023 Gerd Hoffmann
        if (command != REQUEST_SENSE && command != INQUIRY)
899 22864256 blueswir1
            goto fail;
900 2e5d83bb pbrook
    }
901 a917d384 pbrook
    switch (command) {
902 ebf46023 Gerd Hoffmann
    case TEST_UNIT_READY:
903 51ad87c9 Gerd Hoffmann
    case REQUEST_SENSE:
904 0b06c059 Gerd Hoffmann
    case INQUIRY:
905 ebddfcbe Gerd Hoffmann
    case MODE_SENSE:
906 ebddfcbe Gerd Hoffmann
    case MODE_SENSE_10:
907 3d53ba18 Gerd Hoffmann
    case RESERVE:
908 3d53ba18 Gerd Hoffmann
    case RESERVE_10:
909 3d53ba18 Gerd Hoffmann
    case RELEASE:
910 3d53ba18 Gerd Hoffmann
    case RELEASE_10:
911 8d3628ff Gerd Hoffmann
    case START_STOP:
912 c68b9f34 Gerd Hoffmann
    case ALLOW_MEDIUM_REMOVAL:
913 e7e25e32 Gerd Hoffmann
    case READ_CAPACITY:
914 fc903943 Gerd Hoffmann
    case SYNCHRONIZE_CACHE:
915 02880f43 Gerd Hoffmann
    case READ_TOC:
916 38215553 Gerd Hoffmann
    case GET_CONFIGURATION:
917 5dd90e2a Gerd Hoffmann
    case SERVICE_ACTION_IN:
918 39ec9a50 Gerd Hoffmann
    case REPORT_LUNS:
919 88f8a5ed Gerd Hoffmann
    case VERIFY:
920 aa5dbdc1 Gerd Hoffmann
        rc = scsi_disk_emulate_command(&r->req, outbuf);
921 aa5dbdc1 Gerd Hoffmann
        if (rc > 0) {
922 aa5dbdc1 Gerd Hoffmann
            r->iov.iov_len = rc;
923 aa5dbdc1 Gerd Hoffmann
        } else {
924 aa5dbdc1 Gerd Hoffmann
            scsi_req_complete(&r->req);
925 aa5dbdc1 Gerd Hoffmann
            scsi_remove_request(r);
926 0b06c059 Gerd Hoffmann
            return 0;
927 aa5dbdc1 Gerd Hoffmann
        }
928 0b06c059 Gerd Hoffmann
        break;
929 ebf46023 Gerd Hoffmann
    case READ_6:
930 ebf46023 Gerd Hoffmann
    case READ_10:
931 bd536cf3 Gerd Hoffmann
    case READ_12:
932 bd536cf3 Gerd Hoffmann
    case READ_16:
933 0bf9e31a Blue Swirl
        DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len);
934 274fb0e1 aliguori
        if (lba > s->max_lba)
935 274fb0e1 aliguori
            goto illegal_lba;
936 a917d384 pbrook
        r->sector = lba * s->cluster_size;
937 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
938 2e5d83bb pbrook
        break;
939 ebf46023 Gerd Hoffmann
    case WRITE_6:
940 ebf46023 Gerd Hoffmann
    case WRITE_10:
941 bd536cf3 Gerd Hoffmann
    case WRITE_12:
942 bd536cf3 Gerd Hoffmann
    case WRITE_16:
943 0bf9e31a Blue Swirl
        DPRINTF("Write (sector %" PRId64 ", count %d)\n", lba, len);
944 274fb0e1 aliguori
        if (lba > s->max_lba)
945 274fb0e1 aliguori
            goto illegal_lba;
946 a917d384 pbrook
        r->sector = lba * s->cluster_size;
947 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
948 2e5d83bb pbrook
        is_write = 1;
949 2e5d83bb pbrook
        break;
950 2e5d83bb pbrook
    default:
951 2e5d83bb pbrook
        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
952 2e5d83bb pbrook
    fail:
953 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
954 2e5d83bb pbrook
        return 0;
955 274fb0e1 aliguori
    illegal_lba:
956 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
957 274fb0e1 aliguori
        return 0;
958 2e5d83bb pbrook
    }
959 c87c0672 aliguori
    if (r->sector_count == 0 && r->iov.iov_len == 0) {
960 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, GOOD, NO_SENSE);
961 a917d384 pbrook
    }
962 c87c0672 aliguori
    len = r->sector_count * 512 + r->iov.iov_len;
963 a917d384 pbrook
    if (is_write) {
964 a917d384 pbrook
        return -len;
965 a917d384 pbrook
    } else {
966 a917d384 pbrook
        if (!r->sector_count)
967 a917d384 pbrook
            r->sector_count = -1;
968 a917d384 pbrook
        return len;
969 2e5d83bb pbrook
    }
970 2e5d83bb pbrook
}
971 2e5d83bb pbrook
972 56a14938 Gerd Hoffmann
static void scsi_destroy(SCSIDevice *dev)
973 56a14938 Gerd Hoffmann
{
974 56a14938 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
975 9af99d98 Gerd Hoffmann
    SCSIDiskReq *r;
976 56a14938 Gerd Hoffmann
977 9af99d98 Gerd Hoffmann
    while (!QTAILQ_EMPTY(&s->qdev.requests)) {
978 9af99d98 Gerd Hoffmann
        r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests));
979 9af99d98 Gerd Hoffmann
        scsi_remove_request(r);
980 9af99d98 Gerd Hoffmann
    }
981 251882b7 Gerd Hoffmann
    drive_uninit(s->qdev.dinfo);
982 56a14938 Gerd Hoffmann
}
983 56a14938 Gerd Hoffmann
984 d52affa7 Gerd Hoffmann
static int scsi_disk_initfn(SCSIDevice *dev)
985 2e5d83bb pbrook
{
986 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
987 274fb0e1 aliguori
    uint64_t nb_sectors;
988 2e5d83bb pbrook
989 251882b7 Gerd Hoffmann
    if (!s->qdev.dinfo || !s->qdev.dinfo->bdrv) {
990 d52affa7 Gerd Hoffmann
        qemu_error("scsi-disk: drive property not set\n");
991 d52affa7 Gerd Hoffmann
        return -1;
992 d52affa7 Gerd Hoffmann
    }
993 d52affa7 Gerd Hoffmann
994 251882b7 Gerd Hoffmann
    if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) {
995 7c22dd52 pbrook
        s->cluster_size = 4;
996 2e5d83bb pbrook
    } else {
997 7c22dd52 pbrook
        s->cluster_size = 1;
998 2e5d83bb pbrook
    }
999 b07995e3 Gerd Hoffmann
    s->qdev.blocksize = 512 * s->cluster_size;
1000 91376656 Gerd Hoffmann
    s->qdev.type = TYPE_DISK;
1001 251882b7 Gerd Hoffmann
    bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors);
1002 274fb0e1 aliguori
    nb_sectors /= s->cluster_size;
1003 274fb0e1 aliguori
    if (nb_sectors)
1004 274fb0e1 aliguori
        nb_sectors--;
1005 274fb0e1 aliguori
    s->max_lba = nb_sectors;
1006 ea8a5d7f aliguori
    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
1007 d52affa7 Gerd Hoffmann
    return 0;
1008 d52affa7 Gerd Hoffmann
}
1009 d52affa7 Gerd Hoffmann
1010 d52affa7 Gerd Hoffmann
static SCSIDeviceInfo scsi_disk_info = {
1011 d52affa7 Gerd Hoffmann
    .qdev.name    = "scsi-disk",
1012 d52affa7 Gerd Hoffmann
    .qdev.desc    = "virtual scsi disk or cdrom",
1013 d52affa7 Gerd Hoffmann
    .qdev.size    = sizeof(SCSIDiskState),
1014 d52affa7 Gerd Hoffmann
    .init         = scsi_disk_initfn,
1015 56a14938 Gerd Hoffmann
    .destroy      = scsi_destroy,
1016 d52affa7 Gerd Hoffmann
    .send_command = scsi_send_command,
1017 d52affa7 Gerd Hoffmann
    .read_data    = scsi_read_data,
1018 d52affa7 Gerd Hoffmann
    .write_data   = scsi_write_data,
1019 d52affa7 Gerd Hoffmann
    .cancel_io    = scsi_cancel_io,
1020 d52affa7 Gerd Hoffmann
    .get_buf      = scsi_get_buf,
1021 d52affa7 Gerd Hoffmann
    .qdev.props   = (Property[]) {
1022 251882b7 Gerd Hoffmann
        DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.dinfo),
1023 d52affa7 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
1024 d52affa7 Gerd Hoffmann
    },
1025 d52affa7 Gerd Hoffmann
};
1026 d52affa7 Gerd Hoffmann
1027 d52affa7 Gerd Hoffmann
static void scsi_disk_register_devices(void)
1028 d52affa7 Gerd Hoffmann
{
1029 d52affa7 Gerd Hoffmann
    scsi_qdev_register(&scsi_disk_info);
1030 8ccc2ace ths
}
1031 d52affa7 Gerd Hoffmann
device_init(scsi_disk_register_devices)