]> git.proxmox.com Git - qemu.git/blame - hw/scsi-generic.c
scsi: use scsi_req_complete
[qemu.git] / hw / scsi-generic.c
CommitLineData
2cc977e2
TS
1/*
2 * Generic SCSI Device support
3 *
4 * Copyright (c) 2007 Bull S.A.S.
5 * Based on code by Paul Brook
6 * Based on code by Fabrice Bellard
7 *
8 * Written by Laurent Vivier <Laurent.Vivier@bull.net>
9 *
10 * This code is licenced under the LGPL.
11 *
12 */
13
14#include "qemu-common.h"
2f792016 15#include "qemu-error.h"
43b443b6 16#include "scsi.h"
2446333c 17#include "blockdev.h"
2cc977e2 18
d52affa7 19#ifdef __linux__
2cc977e2
TS
20
21//#define DEBUG_SCSI
22
23#ifdef DEBUG_SCSI
001faf32
BS
24#define DPRINTF(fmt, ...) \
25do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
2cc977e2 26#else
001faf32 27#define DPRINTF(fmt, ...) do {} while(0)
2cc977e2
TS
28#endif
29
001faf32
BS
30#define BADF(fmt, ...) \
31do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
2cc977e2
TS
32
33#include <stdio.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include <scsi/sg.h>
0d65e1f8 38#include "scsi-defs.h"
2cc977e2 39
a9dd6843 40#define SCSI_SENSE_BUF_SIZE 96
2cc977e2
TS
41
42#define SG_ERR_DRIVER_TIMEOUT 0x06
43#define SG_ERR_DRIVER_SENSE 0x08
44
45#ifndef MAX_UINT
46#define MAX_UINT ((unsigned int)-1)
47#endif
48
d52affa7
GH
49typedef struct SCSIGenericState SCSIGenericState;
50
4c41d2ef
GH
51typedef struct SCSIGenericReq {
52 SCSIRequest req;
2cc977e2
TS
53 uint8_t *buf;
54 int buflen;
55 int len;
56 sg_io_hdr_t io_header;
4c41d2ef 57} SCSIGenericReq;
2cc977e2 58
d52affa7 59struct SCSIGenericState
2cc977e2 60{
d52affa7 61 SCSIDevice qdev;
428c149b 62 BlockDriverState *bs;
2cc977e2 63 int lun;
2cc977e2
TS
64 int driver_status;
65 uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
89c0f643 66 uint8_t senselen;
2cc977e2
TS
67};
68
5c6c0e51 69static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
2cc977e2 70{
89b08ae1 71 SCSIRequest *req;
2cc977e2 72
89b08ae1 73 req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun);
5c6c0e51 74 return req;
2cc977e2
TS
75}
76
ad2d30f7 77static void scsi_free_request(SCSIRequest *req)
2cc977e2 78{
ad2d30f7
PB
79 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
80
9af99d98 81 qemu_free(r->buf);
2cc977e2
TS
82}
83
2cc977e2
TS
84/* Helper function for command completion. */
85static void scsi_command_complete(void *opaque, int ret)
86{
4c41d2ef
GH
87 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
88 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
2cc977e2 89
d33e0ce2 90 r->req.aiocb = NULL;
2cc977e2 91 s->driver_status = r->io_header.driver_status;
89c0f643
AJ
92 if (s->driver_status & SG_ERR_DRIVER_SENSE)
93 s->senselen = r->io_header.sb_len_wr;
94
2cc977e2 95 if (ret != 0)
f0171327 96 r->req.status = BUSY;
2cc977e2
TS
97 else {
98 if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
f0171327 99 r->req.status = BUSY;
2cc977e2 100 BADF("Driver Timeout\n");
89c0f643 101 } else if (r->io_header.status)
ed3a34a3 102 r->req.status = r->io_header.status;
89c0f643 103 else if (s->driver_status & SG_ERR_DRIVER_SENSE)
f0171327 104 r->req.status = CHECK_CONDITION;
2cc977e2 105 else
f0171327 106 r->req.status = GOOD;
2cc977e2 107 }
89c0f643 108 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
ed3a34a3
GH
109 r, r->req.tag, r->req.status);
110
111 scsi_req_complete(&r->req);
2cc977e2
TS
112}
113
114/* Cancel a pending data transfer. */
5c6c0e51 115static void scsi_cancel_io(SCSIRequest *req)
2cc977e2 116{
5c6c0e51
HR
117 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
118
119 DPRINTF("Cancel tag=0x%x\n", req->tag);
120 if (r->req.aiocb) {
121 bdrv_aio_cancel(r->req.aiocb);
2cc977e2 122 }
5c6c0e51 123 r->req.aiocb = NULL;
2cc977e2
TS
124}
125
126static int execute_command(BlockDriverState *bdrv,
4c41d2ef 127 SCSIGenericReq *r, int direction,
2cc977e2
TS
128 BlockDriverCompletionFunc *complete)
129{
4c41d2ef
GH
130 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
131
2cc977e2
TS
132 r->io_header.interface_id = 'S';
133 r->io_header.dxfer_direction = direction;
134 r->io_header.dxferp = r->buf;
135 r->io_header.dxfer_len = r->buflen;
29362ebe
GH
136 r->io_header.cmdp = r->req.cmd.buf;
137 r->io_header.cmd_len = r->req.cmd.len;
4c41d2ef
GH
138 r->io_header.mx_sb_len = sizeof(s->sensebuf);
139 r->io_header.sbp = s->sensebuf;
2cc977e2
TS
140 r->io_header.timeout = MAX_UINT;
141 r->io_header.usr_ptr = r;
142 r->io_header.flags |= SG_FLAG_DIRECT_IO;
143
4c41d2ef
GH
144 r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
145 if (r->req.aiocb == NULL) {
2cc977e2
TS
146 BADF("execute_command: read failed !\n");
147 return -1;
148 }
149
150 return 0;
151}
152
153static void scsi_read_complete(void * opaque, int ret)
154{
4c41d2ef 155 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
2cc977e2
TS
156 int len;
157
d33e0ce2 158 r->req.aiocb = NULL;
2cc977e2 159 if (ret) {
aa2b1e89 160 DPRINTF("IO error ret %d\n", ret);
2cc977e2
TS
161 scsi_command_complete(r, ret);
162 return;
163 }
164 len = r->io_header.dxfer_len - r->io_header.resid;
4c41d2ef 165 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
2cc977e2
TS
166
167 r->len = -1;
40f16dd1 168 if (len == 0) {
89c0f643 169 scsi_command_complete(r, 0);
40f16dd1 170 } else {
ab9adc88 171 scsi_req_data(&r->req, len);
40f16dd1 172 }
2cc977e2
TS
173}
174
175/* Read more data from scsi device into buffer. */
5c6c0e51 176static void scsi_read_data(SCSIRequest *req)
2cc977e2 177{
5c6c0e51
HR
178 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
179 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
2cc977e2
TS
180 int ret;
181
5c6c0e51 182 DPRINTF("scsi_read_data 0x%x\n", req->tag);
2cc977e2
TS
183 if (r->len == -1) {
184 scsi_command_complete(r, 0);
185 return;
186 }
187
29362ebe 188 if (r->req.cmd.buf[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE)
2cc977e2 189 {
89c0f643
AJ
190 s->senselen = MIN(r->len, s->senselen);
191 memcpy(r->buf, s->sensebuf, s->senselen);
2cc977e2 192 r->io_header.driver_status = 0;
89c0f643
AJ
193 r->io_header.status = 0;
194 r->io_header.dxfer_len = s->senselen;
2cc977e2 195 r->len = -1;
4c41d2ef 196 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, s->senselen);
a9dd6843
AL
197 DPRINTF("Sense: %d %d %d %d %d %d %d %d\n",
198 r->buf[0], r->buf[1], r->buf[2], r->buf[3],
199 r->buf[4], r->buf[5], r->buf[6], r->buf[7]);
ab9adc88 200 scsi_req_data(&r->req, s->senselen);
2cc977e2
TS
201 return;
202 }
203
428c149b 204 ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
2cc977e2
TS
205 if (ret == -1) {
206 scsi_command_complete(r, -EINVAL);
207 return;
208 }
209}
210
211static void scsi_write_complete(void * opaque, int ret)
212{
4c41d2ef
GH
213 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
214 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
2cc977e2
TS
215
216 DPRINTF("scsi_write_complete() ret = %d\n", ret);
d33e0ce2 217 r->req.aiocb = NULL;
2cc977e2
TS
218 if (ret) {
219 DPRINTF("IO error\n");
220 scsi_command_complete(r, ret);
221 return;
222 }
223
29362ebe 224 if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
91376656 225 s->qdev.type == TYPE_TAPE) {
b07995e3 226 s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
aa2b1e89 227 DPRINTF("block size %d\n", s->qdev.blocksize);
89c0f643
AJ
228 }
229
2cc977e2
TS
230 scsi_command_complete(r, ret);
231}
232
233/* Write data to a scsi device. Returns nonzero on failure.
234 The transfer may complete asynchronously. */
5c6c0e51 235static int scsi_write_data(SCSIRequest *req)
2cc977e2 236{
5c6c0e51
HR
237 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
238 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
2cc977e2
TS
239 int ret;
240
5c6c0e51 241 DPRINTF("scsi_write_data 0x%x\n", req->tag);
2cc977e2
TS
242 if (r->len == 0) {
243 r->len = r->buflen;
ab9adc88 244 scsi_req_data(&r->req, r->len);
2cc977e2
TS
245 return 0;
246 }
247
428c149b 248 ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
2cc977e2
TS
249 if (ret == -1) {
250 scsi_command_complete(r, -EINVAL);
251 return 1;
252 }
253
254 return 0;
255}
256
257/* Return a pointer to the data buffer. */
5c6c0e51 258static uint8_t *scsi_get_buf(SCSIRequest *req)
2cc977e2 259{
5c6c0e51
HR
260 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
261
2cc977e2
TS
262 return r->buf;
263}
264
2ec749cb 265static void scsi_req_fixup(SCSIRequest *req)
2cc977e2 266{
2ec749cb 267 switch(req->cmd.buf[0]) {
2cc977e2 268 case WRITE_10:
2ec749cb 269 req->cmd.buf[1] &= ~0x08; /* disable FUA */
2cc977e2
TS
270 break;
271 case READ_10:
2ec749cb 272 req->cmd.buf[1] &= ~0x08; /* disable FUA */
a9dd6843
AL
273 break;
274 case REWIND:
275 case START_STOP:
2ec749cb
GH
276 if (req->dev->type == TYPE_TAPE) {
277 /* force IMMED, otherwise qemu waits end of command */
278 req->cmd.buf[1] = 0x01;
279 }
a9dd6843 280 break;
a9dd6843 281 }
a9dd6843
AL
282}
283
2cc977e2
TS
284/* Execute a scsi command. Returns the length of the data expected by the
285 command. This will be Positive for data transfers from the device
286 (eg. disk reads), negative for transfers to the device (eg. disk writes),
287 and zero if the command does not transfer any data. */
288
5c6c0e51 289static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
2cc977e2 290{
5c6c0e51
HR
291 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
292 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
2cc977e2
TS
293 int ret;
294
5c6c0e51 295 scsi_req_enqueue(req);
89c0f643 296 if (cmd[0] != REQUEST_SENSE &&
5c6c0e51
HR
297 (req->lun != s->lun || (cmd[1] >> 5) != s->lun)) {
298 DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : cmd[1] >> 5);
89c0f643
AJ
299
300 s->sensebuf[0] = 0x70;
301 s->sensebuf[1] = 0x00;
302 s->sensebuf[2] = ILLEGAL_REQUEST;
303 s->sensebuf[3] = 0x00;
304 s->sensebuf[4] = 0x00;
305 s->sensebuf[5] = 0x00;
306 s->sensebuf[6] = 0x00;
307 s->senselen = 7;
308 s->driver_status = SG_ERR_DRIVER_SENSE;
2b8b3bb9
PB
309 r->req.status = CHECK_CONDITION;
310 scsi_req_complete(&r->req);
89c0f643
AJ
311 return 0;
312 }
313
2ec749cb
GH
314 if (-1 == scsi_req_parse(&r->req, cmd)) {
315 BADF("Unsupported command length, command %x\n", cmd[0]);
ad2d30f7
PB
316 scsi_req_dequeue(&r->req);
317 scsi_req_unref(&r->req);
2ec749cb
GH
318 return 0;
319 }
320 scsi_req_fixup(&r->req);
321
aa2b1e89
BK
322 DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
323 r->req.cmd.xfer, cmd[0]);
324
325#ifdef DEBUG_SCSI
326 {
327 int i;
328 for (i = 1; i < r->req.cmd.len; i++) {
329 printf(" 0x%02x", cmd[i]);
330 }
331 printf("\n");
332 }
333#endif
2cc977e2 334
2ec749cb 335 if (r->req.cmd.xfer == 0) {
2cc977e2 336 if (r->buf != NULL)
e3c916e6 337 qemu_free(r->buf);
2cc977e2
TS
338 r->buflen = 0;
339 r->buf = NULL;
428c149b 340 ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
2cc977e2
TS
341 if (ret == -1) {
342 scsi_command_complete(r, -EINVAL);
2cc977e2
TS
343 }
344 return 0;
345 }
346
2ec749cb 347 if (r->buflen != r->req.cmd.xfer) {
2cc977e2 348 if (r->buf != NULL)
e3c916e6 349 qemu_free(r->buf);
2ec749cb
GH
350 r->buf = qemu_malloc(r->req.cmd.xfer);
351 r->buflen = r->req.cmd.xfer;
2cc977e2
TS
352 }
353
354 memset(r->buf, 0, r->buflen);
2ec749cb 355 r->len = r->req.cmd.xfer;
97a06435 356 if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
2cc977e2 357 r->len = 0;
5c6c0e51 358 return -r->req.cmd.xfer;
ad2d30f7 359 } else {
5c6c0e51 360 return r->req.cmd.xfer;
2cc977e2 361 }
2cc977e2
TS
362}
363
364static int get_blocksize(BlockDriverState *bdrv)
365{
366 uint8_t cmd[10];
367 uint8_t buf[8];
368 uint8_t sensebuf[8];
369 sg_io_hdr_t io_header;
370 int ret;
371
4f26a486
AL
372 memset(cmd, 0, sizeof(cmd));
373 memset(buf, 0, sizeof(buf));
2cc977e2
TS
374 cmd[0] = READ_CAPACITY;
375
376 memset(&io_header, 0, sizeof(io_header));
377 io_header.interface_id = 'S';
378 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
379 io_header.dxfer_len = sizeof(buf);
380 io_header.dxferp = buf;
381 io_header.cmdp = cmd;
382 io_header.cmd_len = sizeof(cmd);
383 io_header.mx_sb_len = sizeof(sensebuf);
384 io_header.sbp = sensebuf;
385 io_header.timeout = 6000; /* XXX */
386
221f715d 387 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
7d780669 388 if (ret < 0)
2cc977e2
TS
389 return -1;
390
391 return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
392}
393
89c0f643
AJ
394static int get_stream_blocksize(BlockDriverState *bdrv)
395{
396 uint8_t cmd[6];
397 uint8_t buf[12];
398 uint8_t sensebuf[8];
399 sg_io_hdr_t io_header;
400 int ret;
401
402 memset(cmd, 0, sizeof(cmd));
403 memset(buf, 0, sizeof(buf));
404 cmd[0] = MODE_SENSE;
405 cmd[4] = sizeof(buf);
406
407 memset(&io_header, 0, sizeof(io_header));
408 io_header.interface_id = 'S';
409 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
410 io_header.dxfer_len = sizeof(buf);
411 io_header.dxferp = buf;
412 io_header.cmdp = cmd;
413 io_header.cmd_len = sizeof(cmd);
414 io_header.mx_sb_len = sizeof(sensebuf);
415 io_header.sbp = sensebuf;
416 io_header.timeout = 6000; /* XXX */
417
221f715d 418 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
7d780669 419 if (ret < 0)
89c0f643
AJ
420 return -1;
421
422 return (buf[9] << 16) | (buf[10] << 8) | buf[11];
423}
424
f8b6d672
BK
425static void scsi_generic_reset(DeviceState *dev)
426{
427 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
428
c557e889 429 scsi_device_purge_requests(&s->qdev);
f8b6d672
BK
430}
431
432static void scsi_destroy(SCSIDevice *d)
433{
434 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
435
c557e889 436 scsi_device_purge_requests(&s->qdev);
f8b6cc00 437 blockdev_mark_auto_del(s->qdev.conf.bs);
2cc977e2
TS
438}
439
d52affa7 440static int scsi_generic_initfn(SCSIDevice *dev)
2cc977e2 441{
d52affa7 442 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
2cc977e2 443 int sg_version;
2cc977e2
TS
444 struct sg_scsi_id scsiid;
445
f8b6cc00 446 if (!s->qdev.conf.bs) {
1ecda02b 447 error_report("scsi-generic: drive property not set");
d52affa7
GH
448 return -1;
449 }
f8b6cc00 450 s->bs = s->qdev.conf.bs;
2cc977e2 451
d52affa7 452 /* check we are really using a /dev/sg* file */
428c149b 453 if (!bdrv_is_sg(s->bs)) {
1ecda02b 454 error_report("scsi-generic: not /dev/sg*");
d52affa7
GH
455 return -1;
456 }
2cc977e2 457
620f862e
MA
458 if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
459 error_report("Device doesn't support drive option werror");
460 return -1;
461 }
462 if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
463 error_report("Device doesn't support drive option rerror");
464 return -1;
465 }
466
2cc977e2 467 /* check we are using a driver managing SG_IO (version 3 and after */
428c149b 468 if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
d52affa7 469 sg_version < 30000) {
1ecda02b 470 error_report("scsi-generic: scsi generic interface too old");
d52affa7
GH
471 return -1;
472 }
2cc977e2
TS
473
474 /* get LUN of the /dev/sg? */
428c149b 475 if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
1ecda02b 476 error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
d52affa7
GH
477 return -1;
478 }
2cc977e2
TS
479
480 /* define device state */
2cc977e2 481 s->lun = scsiid.lun;
89c0f643 482 DPRINTF("LUN %d\n", s->lun);
91376656
GH
483 s->qdev.type = scsiid.scsi_type;
484 DPRINTF("device type %d\n", s->qdev.type);
485 if (s->qdev.type == TYPE_TAPE) {
428c149b 486 s->qdev.blocksize = get_stream_blocksize(s->bs);
b07995e3
GH
487 if (s->qdev.blocksize == -1)
488 s->qdev.blocksize = 0;
89c0f643 489 } else {
428c149b 490 s->qdev.blocksize = get_blocksize(s->bs);
89c0f643 491 /* removable media returns 0 if not present */
b07995e3 492 if (s->qdev.blocksize <= 0) {
91376656 493 if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM)
b07995e3 494 s->qdev.blocksize = 2048;
89c0f643 495 else
b07995e3 496 s->qdev.blocksize = 512;
89c0f643
AJ
497 }
498 }
b07995e3 499 DPRINTF("block size %d\n", s->qdev.blocksize);
2cc977e2
TS
500 s->driver_status = 0;
501 memset(s->sensebuf, 0, sizeof(s->sensebuf));
7d0d6950 502 bdrv_set_removable(s->bs, 0);
d52affa7
GH
503 return 0;
504}
2cc977e2 505
d52affa7
GH
506static SCSIDeviceInfo scsi_generic_info = {
507 .qdev.name = "scsi-generic",
508 .qdev.desc = "pass through generic scsi device (/dev/sg*)",
509 .qdev.size = sizeof(SCSIGenericState),
f8b6d672 510 .qdev.reset = scsi_generic_reset,
d52affa7
GH
511 .init = scsi_generic_initfn,
512 .destroy = scsi_destroy,
5c6c0e51 513 .alloc_req = scsi_new_request,
ad2d30f7 514 .free_req = scsi_free_request,
d52affa7
GH
515 .send_command = scsi_send_command,
516 .read_data = scsi_read_data,
517 .write_data = scsi_write_data,
518 .cancel_io = scsi_cancel_io,
519 .get_buf = scsi_get_buf,
520 .qdev.props = (Property[]) {
428c149b 521 DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
d52affa7
GH
522 DEFINE_PROP_END_OF_LIST(),
523 },
524};
2cc977e2 525
d52affa7
GH
526static void scsi_generic_register_devices(void)
527{
528 scsi_qdev_register(&scsi_generic_info);
2cc977e2 529}
d52affa7
GH
530device_init(scsi_generic_register_devices)
531
2cc977e2 532#endif /* __linux__ */