]> Git Repo - qemu.git/blame - hw/scsi-generic.c
scsi: introduce SCSIReqOps
[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 <[email protected]>
9 *
8e31bf38 10 * This code is licensed under the LGPL.
2cc977e2
TS
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};
65
ad2d30f7 66static void scsi_free_request(SCSIRequest *req)
2cc977e2 67{
ad2d30f7
PB
68 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
69
9af99d98 70 qemu_free(r->buf);
2cc977e2
TS
71}
72
2cc977e2
TS
73/* Helper function for command completion. */
74static void scsi_command_complete(void *opaque, int ret)
75{
682a9b21 76 int status;
4c41d2ef 77 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
2cc977e2 78
d33e0ce2 79 r->req.aiocb = NULL;
b45ef674
PB
80 if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE)
81 r->req.sense_len = r->io_header.sb_len_wr;
89c0f643 82
a1f0cce2
HR
83 if (ret != 0) {
84 switch (ret) {
2e7cc4d6 85 case -EDOM:
682a9b21 86 status = TASK_SET_FULL;
2e7cc4d6 87 break;
a1f0cce2 88 case -EINVAL:
682a9b21 89 status = CHECK_CONDITION;
b45ef674 90 scsi_req_build_sense(&r->req, SENSE_CODE(INVALID_FIELD));
a1f0cce2
HR
91 break;
92 case -ENOMEM:
682a9b21 93 status = CHECK_CONDITION;
b45ef674 94 scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
a1f0cce2
HR
95 break;
96 default:
682a9b21 97 status = CHECK_CONDITION;
b45ef674 98 scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
a1f0cce2
HR
99 break;
100 }
101 } else {
b45ef674 102 if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
682a9b21 103 status = BUSY;
2cc977e2 104 BADF("Driver Timeout\n");
682a9b21
PB
105 } else if (r->io_header.status) {
106 status = r->io_header.status;
b45ef674 107 } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
682a9b21
PB
108 status = CHECK_CONDITION;
109 } else {
110 status = GOOD;
111 }
2cc977e2 112 }
89c0f643 113 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
682a9b21 114 r, r->req.tag, status);
ed3a34a3 115
682a9b21 116 scsi_req_complete(&r->req, status);
2cc977e2
TS
117}
118
119/* Cancel a pending data transfer. */
5c6c0e51 120static void scsi_cancel_io(SCSIRequest *req)
2cc977e2 121{
5c6c0e51
HR
122 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
123
124 DPRINTF("Cancel tag=0x%x\n", req->tag);
125 if (r->req.aiocb) {
126 bdrv_aio_cancel(r->req.aiocb);
2cc977e2 127 }
5c6c0e51 128 r->req.aiocb = NULL;
2cc977e2
TS
129}
130
131static int execute_command(BlockDriverState *bdrv,
4c41d2ef 132 SCSIGenericReq *r, int direction,
2cc977e2
TS
133 BlockDriverCompletionFunc *complete)
134{
2cc977e2
TS
135 r->io_header.interface_id = 'S';
136 r->io_header.dxfer_direction = direction;
137 r->io_header.dxferp = r->buf;
138 r->io_header.dxfer_len = r->buflen;
29362ebe
GH
139 r->io_header.cmdp = r->req.cmd.buf;
140 r->io_header.cmd_len = r->req.cmd.len;
b45ef674
PB
141 r->io_header.mx_sb_len = sizeof(r->req.sense);
142 r->io_header.sbp = r->req.sense;
2cc977e2
TS
143 r->io_header.timeout = MAX_UINT;
144 r->io_header.usr_ptr = r;
145 r->io_header.flags |= SG_FLAG_DIRECT_IO;
146
4c41d2ef
GH
147 r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
148 if (r->req.aiocb == NULL) {
2cc977e2 149 BADF("execute_command: read failed !\n");
a1f0cce2 150 return -ENOMEM;
2cc977e2
TS
151 }
152
153 return 0;
154}
155
156static void scsi_read_complete(void * opaque, int ret)
157{
4c41d2ef 158 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
2cc977e2
TS
159 int len;
160
d33e0ce2 161 r->req.aiocb = NULL;
2cc977e2 162 if (ret) {
aa2b1e89 163 DPRINTF("IO error ret %d\n", ret);
2cc977e2
TS
164 scsi_command_complete(r, ret);
165 return;
166 }
167 len = r->io_header.dxfer_len - r->io_header.resid;
4c41d2ef 168 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
2cc977e2
TS
169
170 r->len = -1;
40f16dd1 171 if (len == 0) {
89c0f643 172 scsi_command_complete(r, 0);
40f16dd1 173 } else {
ab9adc88 174 scsi_req_data(&r->req, len);
40f16dd1 175 }
2cc977e2
TS
176}
177
178/* Read more data from scsi device into buffer. */
5c6c0e51 179static void scsi_read_data(SCSIRequest *req)
2cc977e2 180{
5c6c0e51
HR
181 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
182 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
2cc977e2
TS
183 int ret;
184
5c6c0e51 185 DPRINTF("scsi_read_data 0x%x\n", req->tag);
2cc977e2
TS
186 if (r->len == -1) {
187 scsi_command_complete(r, 0);
188 return;
189 }
190
b45ef674 191 if (r->req.cmd.buf[0] == REQUEST_SENSE) {
2cc977e2 192 r->io_header.driver_status = 0;
89c0f643 193 r->io_header.status = 0;
b45ef674
PB
194 r->io_header.dxfer_len =
195 scsi_device_get_sense(&s->qdev, r->buf, r->req.cmd.xfer,
196 (r->req.cmd.buf[1] & 1) == 0);
2cc977e2 197 r->len = -1;
b45ef674 198 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, r->io_header.dxfer_len);
a9dd6843
AL
199 DPRINTF("Sense: %d %d %d %d %d %d %d %d\n",
200 r->buf[0], r->buf[1], r->buf[2], r->buf[3],
201 r->buf[4], r->buf[5], r->buf[6], r->buf[7]);
b45ef674
PB
202 scsi_req_data(&r->req, r->io_header.dxfer_len);
203 /* The sense buffer is cleared when we return GOOD */
2cc977e2
TS
204 return;
205 }
206
428c149b 207 ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
a1f0cce2
HR
208 if (ret < 0) {
209 scsi_command_complete(r, ret);
2cc977e2
TS
210 return;
211 }
212}
213
214static void scsi_write_complete(void * opaque, int ret)
215{
4c41d2ef
GH
216 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
217 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
2cc977e2
TS
218
219 DPRINTF("scsi_write_complete() ret = %d\n", ret);
d33e0ce2 220 r->req.aiocb = NULL;
2cc977e2
TS
221 if (ret) {
222 DPRINTF("IO error\n");
223 scsi_command_complete(r, ret);
224 return;
225 }
226
29362ebe 227 if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
91376656 228 s->qdev.type == TYPE_TAPE) {
b07995e3 229 s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
aa2b1e89 230 DPRINTF("block size %d\n", s->qdev.blocksize);
89c0f643
AJ
231 }
232
2cc977e2
TS
233 scsi_command_complete(r, ret);
234}
235
236/* Write data to a scsi device. Returns nonzero on failure.
237 The transfer may complete asynchronously. */
42741212 238static void scsi_write_data(SCSIRequest *req)
2cc977e2 239{
5c6c0e51
HR
240 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
241 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
2cc977e2
TS
242 int ret;
243
5c6c0e51 244 DPRINTF("scsi_write_data 0x%x\n", req->tag);
2cc977e2
TS
245 if (r->len == 0) {
246 r->len = r->buflen;
ab9adc88 247 scsi_req_data(&r->req, r->len);
42741212 248 return;
2cc977e2
TS
249 }
250
428c149b 251 ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
a1f0cce2
HR
252 if (ret < 0) {
253 scsi_command_complete(r, ret);
2cc977e2 254 }
2cc977e2
TS
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
1455084e
PB
295 if (cmd[0] != REQUEST_SENSE && req->lun != s->lun) {
296 DPRINTF("Unimplemented LUN %d\n", req->lun);
b45ef674 297 scsi_req_build_sense(&r->req, SENSE_CODE(LUN_NOT_SUPPORTED));
682a9b21 298 scsi_req_complete(&r->req, CHECK_CONDITION);
89c0f643
AJ
299 return 0;
300 }
301
2ec749cb
GH
302 if (-1 == scsi_req_parse(&r->req, cmd)) {
303 BADF("Unsupported command length, command %x\n", cmd[0]);
a1f0cce2 304 scsi_command_complete(r, -EINVAL);
2ec749cb
GH
305 return 0;
306 }
307 scsi_req_fixup(&r->req);
308
aa2b1e89
BK
309 DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
310 r->req.cmd.xfer, cmd[0]);
311
312#ifdef DEBUG_SCSI
313 {
314 int i;
315 for (i = 1; i < r->req.cmd.len; i++) {
316 printf(" 0x%02x", cmd[i]);
317 }
318 printf("\n");
319 }
320#endif
2cc977e2 321
2ec749cb 322 if (r->req.cmd.xfer == 0) {
2cc977e2 323 if (r->buf != NULL)
e3c916e6 324 qemu_free(r->buf);
2cc977e2
TS
325 r->buflen = 0;
326 r->buf = NULL;
428c149b 327 ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
a1f0cce2
HR
328 if (ret < 0) {
329 scsi_command_complete(r, ret);
330 return 0;
2cc977e2
TS
331 }
332 return 0;
333 }
334
2ec749cb 335 if (r->buflen != r->req.cmd.xfer) {
2cc977e2 336 if (r->buf != NULL)
e3c916e6 337 qemu_free(r->buf);
2ec749cb
GH
338 r->buf = qemu_malloc(r->req.cmd.xfer);
339 r->buflen = r->req.cmd.xfer;
2cc977e2
TS
340 }
341
342 memset(r->buf, 0, r->buflen);
2ec749cb 343 r->len = r->req.cmd.xfer;
97a06435 344 if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
2cc977e2 345 r->len = 0;
5c6c0e51 346 return -r->req.cmd.xfer;
ad2d30f7 347 } else {
5c6c0e51 348 return r->req.cmd.xfer;
2cc977e2 349 }
2cc977e2
TS
350}
351
352static int get_blocksize(BlockDriverState *bdrv)
353{
354 uint8_t cmd[10];
355 uint8_t buf[8];
356 uint8_t sensebuf[8];
357 sg_io_hdr_t io_header;
358 int ret;
359
4f26a486
AL
360 memset(cmd, 0, sizeof(cmd));
361 memset(buf, 0, sizeof(buf));
5e30a07d 362 cmd[0] = READ_CAPACITY_10;
2cc977e2
TS
363
364 memset(&io_header, 0, sizeof(io_header));
365 io_header.interface_id = 'S';
366 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
367 io_header.dxfer_len = sizeof(buf);
368 io_header.dxferp = buf;
369 io_header.cmdp = cmd;
370 io_header.cmd_len = sizeof(cmd);
371 io_header.mx_sb_len = sizeof(sensebuf);
372 io_header.sbp = sensebuf;
373 io_header.timeout = 6000; /* XXX */
374
221f715d 375 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
7d780669 376 if (ret < 0)
2cc977e2
TS
377 return -1;
378
379 return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
380}
381
89c0f643
AJ
382static int get_stream_blocksize(BlockDriverState *bdrv)
383{
384 uint8_t cmd[6];
385 uint8_t buf[12];
386 uint8_t sensebuf[8];
387 sg_io_hdr_t io_header;
388 int ret;
389
390 memset(cmd, 0, sizeof(cmd));
391 memset(buf, 0, sizeof(buf));
392 cmd[0] = MODE_SENSE;
393 cmd[4] = sizeof(buf);
394
395 memset(&io_header, 0, sizeof(io_header));
396 io_header.interface_id = 'S';
397 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
398 io_header.dxfer_len = sizeof(buf);
399 io_header.dxferp = buf;
400 io_header.cmdp = cmd;
401 io_header.cmd_len = sizeof(cmd);
402 io_header.mx_sb_len = sizeof(sensebuf);
403 io_header.sbp = sensebuf;
404 io_header.timeout = 6000; /* XXX */
405
221f715d 406 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
7d780669 407 if (ret < 0)
89c0f643
AJ
408 return -1;
409
410 return (buf[9] << 16) | (buf[10] << 8) | buf[11];
411}
412
f8b6d672
BK
413static void scsi_generic_reset(DeviceState *dev)
414{
415 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
416
c557e889 417 scsi_device_purge_requests(&s->qdev);
f8b6d672
BK
418}
419
420static void scsi_destroy(SCSIDevice *d)
421{
422 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
423
c557e889 424 scsi_device_purge_requests(&s->qdev);
f8b6cc00 425 blockdev_mark_auto_del(s->qdev.conf.bs);
2cc977e2
TS
426}
427
d52affa7 428static int scsi_generic_initfn(SCSIDevice *dev)
2cc977e2 429{
d52affa7 430 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
2cc977e2 431 int sg_version;
2cc977e2
TS
432 struct sg_scsi_id scsiid;
433
f8b6cc00 434 if (!s->qdev.conf.bs) {
1ecda02b 435 error_report("scsi-generic: drive property not set");
d52affa7
GH
436 return -1;
437 }
f8b6cc00 438 s->bs = s->qdev.conf.bs;
2cc977e2 439
d52affa7 440 /* check we are really using a /dev/sg* file */
428c149b 441 if (!bdrv_is_sg(s->bs)) {
1ecda02b 442 error_report("scsi-generic: not /dev/sg*");
d52affa7
GH
443 return -1;
444 }
2cc977e2 445
620f862e
MA
446 if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
447 error_report("Device doesn't support drive option werror");
448 return -1;
449 }
450 if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
451 error_report("Device doesn't support drive option rerror");
452 return -1;
453 }
454
2cc977e2 455 /* check we are using a driver managing SG_IO (version 3 and after */
428c149b 456 if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
d52affa7 457 sg_version < 30000) {
1ecda02b 458 error_report("scsi-generic: scsi generic interface too old");
d52affa7
GH
459 return -1;
460 }
2cc977e2
TS
461
462 /* get LUN of the /dev/sg? */
428c149b 463 if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
1ecda02b 464 error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
d52affa7
GH
465 return -1;
466 }
2cc977e2
TS
467
468 /* define device state */
2cc977e2 469 s->lun = scsiid.lun;
89c0f643 470 DPRINTF("LUN %d\n", s->lun);
91376656
GH
471 s->qdev.type = scsiid.scsi_type;
472 DPRINTF("device type %d\n", s->qdev.type);
473 if (s->qdev.type == TYPE_TAPE) {
428c149b 474 s->qdev.blocksize = get_stream_blocksize(s->bs);
b07995e3
GH
475 if (s->qdev.blocksize == -1)
476 s->qdev.blocksize = 0;
89c0f643 477 } else {
428c149b 478 s->qdev.blocksize = get_blocksize(s->bs);
89c0f643 479 /* removable media returns 0 if not present */
b07995e3 480 if (s->qdev.blocksize <= 0) {
91376656 481 if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM)
b07995e3 482 s->qdev.blocksize = 2048;
89c0f643 483 else
b07995e3 484 s->qdev.blocksize = 512;
89c0f643
AJ
485 }
486 }
b07995e3 487 DPRINTF("block size %d\n", s->qdev.blocksize);
7d0d6950 488 bdrv_set_removable(s->bs, 0);
d52affa7
GH
489 return 0;
490}
2cc977e2 491
8dbd4574
PB
492static SCSIReqOps scsi_generic_req_ops = {
493 .size = sizeof(SCSIGenericReq),
494};
495
496static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
497 void *hba_private)
498{
499 SCSIRequest *req;
500
501 req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
502 return req;
503}
504
d52affa7
GH
505static SCSIDeviceInfo scsi_generic_info = {
506 .qdev.name = "scsi-generic",
507 .qdev.desc = "pass through generic scsi device (/dev/sg*)",
508 .qdev.size = sizeof(SCSIGenericState),
f8b6d672 509 .qdev.reset = scsi_generic_reset,
d52affa7
GH
510 .init = scsi_generic_initfn,
511 .destroy = scsi_destroy,
5c6c0e51 512 .alloc_req = scsi_new_request,
ad2d30f7 513 .free_req = scsi_free_request,
d52affa7
GH
514 .send_command = scsi_send_command,
515 .read_data = scsi_read_data,
516 .write_data = scsi_write_data,
517 .cancel_io = scsi_cancel_io,
518 .get_buf = scsi_get_buf,
519 .qdev.props = (Property[]) {
428c149b 520 DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
d52affa7
GH
521 DEFINE_PROP_END_OF_LIST(),
522 },
523};
2cc977e2 524
d52affa7
GH
525static void scsi_generic_register_devices(void)
526{
527 scsi_qdev_register(&scsi_generic_info);
2cc977e2 528}
d52affa7
GH
529device_init(scsi_generic_register_devices)
530
2cc977e2 531#endif /* __linux__ */
This page took 0.629836 seconds and 4 git commands to generate.