]> git.proxmox.com Git - qemu.git/blame - hw/scsi-generic.c
scsi-generic: check ioctl statuses when SG_IO succeeds
[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 *
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
4c41d2ef
GH
49typedef struct SCSIGenericReq {
50 SCSIRequest req;
2cc977e2
TS
51 uint8_t *buf;
52 int buflen;
53 int len;
54 sg_io_hdr_t io_header;
4c41d2ef 55} SCSIGenericReq;
2cc977e2 56
ad2d30f7 57static void scsi_free_request(SCSIRequest *req)
2cc977e2 58{
ad2d30f7
PB
59 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
60
7267c094 61 g_free(r->buf);
2cc977e2
TS
62}
63
2cc977e2
TS
64/* Helper function for command completion. */
65static void scsi_command_complete(void *opaque, int ret)
66{
682a9b21 67 int status;
4c41d2ef 68 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
2cc977e2 69
d33e0ce2 70 r->req.aiocb = NULL;
b45ef674
PB
71 if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE)
72 r->req.sense_len = r->io_header.sb_len_wr;
89c0f643 73
a1f0cce2
HR
74 if (ret != 0) {
75 switch (ret) {
2e7cc4d6 76 case -EDOM:
682a9b21 77 status = TASK_SET_FULL;
2e7cc4d6 78 break;
a1f0cce2 79 case -ENOMEM:
682a9b21 80 status = CHECK_CONDITION;
b45ef674 81 scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
a1f0cce2
HR
82 break;
83 default:
682a9b21 84 status = CHECK_CONDITION;
b45ef674 85 scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
a1f0cce2
HR
86 break;
87 }
88 } else {
b45ef674 89 if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
682a9b21 90 status = BUSY;
2cc977e2 91 BADF("Driver Timeout\n");
682a9b21
PB
92 } else if (r->io_header.status) {
93 status = r->io_header.status;
b45ef674 94 } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
682a9b21
PB
95 status = CHECK_CONDITION;
96 } else {
97 status = GOOD;
98 }
2cc977e2 99 }
89c0f643 100 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
682a9b21 101 r, r->req.tag, status);
ed3a34a3 102
682a9b21 103 scsi_req_complete(&r->req, status);
2cc977e2
TS
104}
105
106/* Cancel a pending data transfer. */
5c6c0e51 107static void scsi_cancel_io(SCSIRequest *req)
2cc977e2 108{
5c6c0e51
HR
109 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
110
111 DPRINTF("Cancel tag=0x%x\n", req->tag);
112 if (r->req.aiocb) {
113 bdrv_aio_cancel(r->req.aiocb);
2cc977e2 114 }
5c6c0e51 115 r->req.aiocb = NULL;
2cc977e2
TS
116}
117
118static int execute_command(BlockDriverState *bdrv,
4c41d2ef 119 SCSIGenericReq *r, int direction,
2cc977e2
TS
120 BlockDriverCompletionFunc *complete)
121{
2cc977e2
TS
122 r->io_header.interface_id = 'S';
123 r->io_header.dxfer_direction = direction;
124 r->io_header.dxferp = r->buf;
125 r->io_header.dxfer_len = r->buflen;
29362ebe
GH
126 r->io_header.cmdp = r->req.cmd.buf;
127 r->io_header.cmd_len = r->req.cmd.len;
b45ef674
PB
128 r->io_header.mx_sb_len = sizeof(r->req.sense);
129 r->io_header.sbp = r->req.sense;
2cc977e2
TS
130 r->io_header.timeout = MAX_UINT;
131 r->io_header.usr_ptr = r;
132 r->io_header.flags |= SG_FLAG_DIRECT_IO;
133
4c41d2ef
GH
134 r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
135 if (r->req.aiocb == NULL) {
2cc977e2 136 BADF("execute_command: read failed !\n");
a1f0cce2 137 return -ENOMEM;
2cc977e2
TS
138 }
139
140 return 0;
141}
142
143static void scsi_read_complete(void * opaque, int ret)
144{
4c41d2ef 145 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
2cc977e2
TS
146 int len;
147
d33e0ce2 148 r->req.aiocb = NULL;
2cc977e2 149 if (ret) {
aa2b1e89 150 DPRINTF("IO error ret %d\n", ret);
2cc977e2
TS
151 scsi_command_complete(r, ret);
152 return;
153 }
154 len = r->io_header.dxfer_len - r->io_header.resid;
4c41d2ef 155 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
2cc977e2
TS
156
157 r->len = -1;
40f16dd1 158 if (len == 0) {
89c0f643 159 scsi_command_complete(r, 0);
40f16dd1 160 } else {
ab9adc88 161 scsi_req_data(&r->req, len);
40f16dd1 162 }
2cc977e2
TS
163}
164
165/* Read more data from scsi device into buffer. */
5c6c0e51 166static void scsi_read_data(SCSIRequest *req)
2cc977e2 167{
5c6c0e51 168 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
8869e103 169 SCSIDevice *s = r->req.dev;
2cc977e2
TS
170 int ret;
171
5c6c0e51 172 DPRINTF("scsi_read_data 0x%x\n", req->tag);
2cc977e2
TS
173 if (r->len == -1) {
174 scsi_command_complete(r, 0);
175 return;
176 }
177
8869e103 178 ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
a1f0cce2
HR
179 if (ret < 0) {
180 scsi_command_complete(r, ret);
2cc977e2
TS
181 }
182}
183
184static void scsi_write_complete(void * opaque, int ret)
185{
4c41d2ef 186 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
8869e103 187 SCSIDevice *s = r->req.dev;
2cc977e2
TS
188
189 DPRINTF("scsi_write_complete() ret = %d\n", ret);
d33e0ce2 190 r->req.aiocb = NULL;
2cc977e2
TS
191 if (ret) {
192 DPRINTF("IO error\n");
193 scsi_command_complete(r, ret);
194 return;
195 }
196
29362ebe 197 if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
8869e103
PB
198 s->type == TYPE_TAPE) {
199 s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
200 DPRINTF("block size %d\n", s->blocksize);
89c0f643
AJ
201 }
202
2cc977e2
TS
203 scsi_command_complete(r, ret);
204}
205
206/* Write data to a scsi device. Returns nonzero on failure.
207 The transfer may complete asynchronously. */
42741212 208static void scsi_write_data(SCSIRequest *req)
2cc977e2 209{
5c6c0e51 210 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
8869e103 211 SCSIDevice *s = r->req.dev;
2cc977e2
TS
212 int ret;
213
5c6c0e51 214 DPRINTF("scsi_write_data 0x%x\n", req->tag);
2cc977e2
TS
215 if (r->len == 0) {
216 r->len = r->buflen;
ab9adc88 217 scsi_req_data(&r->req, r->len);
42741212 218 return;
2cc977e2
TS
219 }
220
8869e103 221 ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
a1f0cce2
HR
222 if (ret < 0) {
223 scsi_command_complete(r, ret);
2cc977e2 224 }
2cc977e2
TS
225}
226
227/* Return a pointer to the data buffer. */
5c6c0e51 228static uint8_t *scsi_get_buf(SCSIRequest *req)
2cc977e2 229{
5c6c0e51
HR
230 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
231
2cc977e2
TS
232 return r->buf;
233}
234
2cc977e2
TS
235/* Execute a scsi command. Returns the length of the data expected by the
236 command. This will be Positive for data transfers from the device
237 (eg. disk reads), negative for transfers to the device (eg. disk writes),
238 and zero if the command does not transfer any data. */
239
5c6c0e51 240static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
2cc977e2 241{
5c6c0e51 242 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
8869e103 243 SCSIDevice *s = r->req.dev;
2cc977e2
TS
244 int ret;
245
aa2b1e89
BK
246 DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
247 r->req.cmd.xfer, cmd[0]);
248
249#ifdef DEBUG_SCSI
250 {
251 int i;
252 for (i = 1; i < r->req.cmd.len; i++) {
253 printf(" 0x%02x", cmd[i]);
254 }
255 printf("\n");
256 }
257#endif
2cc977e2 258
2ec749cb 259 if (r->req.cmd.xfer == 0) {
2cc977e2 260 if (r->buf != NULL)
7267c094 261 g_free(r->buf);
2cc977e2
TS
262 r->buflen = 0;
263 r->buf = NULL;
8869e103 264 ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
a1f0cce2
HR
265 if (ret < 0) {
266 scsi_command_complete(r, ret);
267 return 0;
2cc977e2
TS
268 }
269 return 0;
270 }
271
2ec749cb 272 if (r->buflen != r->req.cmd.xfer) {
2cc977e2 273 if (r->buf != NULL)
7267c094
AL
274 g_free(r->buf);
275 r->buf = g_malloc(r->req.cmd.xfer);
2ec749cb 276 r->buflen = r->req.cmd.xfer;
2cc977e2
TS
277 }
278
279 memset(r->buf, 0, r->buflen);
2ec749cb 280 r->len = r->req.cmd.xfer;
97a06435 281 if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
2cc977e2 282 r->len = 0;
5c6c0e51 283 return -r->req.cmd.xfer;
ad2d30f7 284 } else {
5c6c0e51 285 return r->req.cmd.xfer;
2cc977e2 286 }
2cc977e2
TS
287}
288
289static int get_blocksize(BlockDriverState *bdrv)
290{
291 uint8_t cmd[10];
292 uint8_t buf[8];
293 uint8_t sensebuf[8];
294 sg_io_hdr_t io_header;
295 int ret;
296
4f26a486
AL
297 memset(cmd, 0, sizeof(cmd));
298 memset(buf, 0, sizeof(buf));
5e30a07d 299 cmd[0] = READ_CAPACITY_10;
2cc977e2
TS
300
301 memset(&io_header, 0, sizeof(io_header));
302 io_header.interface_id = 'S';
303 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
304 io_header.dxfer_len = sizeof(buf);
305 io_header.dxferp = buf;
306 io_header.cmdp = cmd;
307 io_header.cmd_len = sizeof(cmd);
308 io_header.mx_sb_len = sizeof(sensebuf);
309 io_header.sbp = sensebuf;
310 io_header.timeout = 6000; /* XXX */
311
221f715d 312 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
fe0ed712 313 if (ret < 0 || io_header.driver_status || io_header.host_status) {
2cc977e2 314 return -1;
fe0ed712 315 }
2cc977e2
TS
316 return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
317}
318
89c0f643
AJ
319static int get_stream_blocksize(BlockDriverState *bdrv)
320{
321 uint8_t cmd[6];
322 uint8_t buf[12];
323 uint8_t sensebuf[8];
324 sg_io_hdr_t io_header;
325 int ret;
326
327 memset(cmd, 0, sizeof(cmd));
328 memset(buf, 0, sizeof(buf));
329 cmd[0] = MODE_SENSE;
330 cmd[4] = sizeof(buf);
331
332 memset(&io_header, 0, sizeof(io_header));
333 io_header.interface_id = 'S';
334 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
335 io_header.dxfer_len = sizeof(buf);
336 io_header.dxferp = buf;
337 io_header.cmdp = cmd;
338 io_header.cmd_len = sizeof(cmd);
339 io_header.mx_sb_len = sizeof(sensebuf);
340 io_header.sbp = sensebuf;
341 io_header.timeout = 6000; /* XXX */
342
221f715d 343 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
fe0ed712 344 if (ret < 0 || io_header.driver_status || io_header.host_status) {
89c0f643 345 return -1;
fe0ed712 346 }
89c0f643
AJ
347 return (buf[9] << 16) | (buf[10] << 8) | buf[11];
348}
349
f8b6d672
BK
350static void scsi_generic_reset(DeviceState *dev)
351{
8869e103 352 SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
f8b6d672 353
8869e103 354 scsi_device_purge_requests(s, SENSE_CODE(RESET));
f8b6d672
BK
355}
356
8869e103 357static void scsi_destroy(SCSIDevice *s)
f8b6d672 358{
8869e103
PB
359 scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
360 blockdev_mark_auto_del(s->conf.bs);
2cc977e2
TS
361}
362
8869e103 363static int scsi_generic_initfn(SCSIDevice *s)
2cc977e2
TS
364{
365 int sg_version;
2cc977e2
TS
366 struct sg_scsi_id scsiid;
367
8869e103 368 if (!s->conf.bs) {
1ecda02b 369 error_report("scsi-generic: drive property not set");
d52affa7
GH
370 return -1;
371 }
2cc977e2 372
d52affa7 373 /* check we are really using a /dev/sg* file */
8869e103 374 if (!bdrv_is_sg(s->conf.bs)) {
1ecda02b 375 error_report("scsi-generic: not /dev/sg*");
d52affa7
GH
376 return -1;
377 }
2cc977e2 378
8869e103 379 if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
620f862e
MA
380 error_report("Device doesn't support drive option werror");
381 return -1;
382 }
8869e103 383 if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
620f862e
MA
384 error_report("Device doesn't support drive option rerror");
385 return -1;
386 }
387
2cc977e2 388 /* check we are using a driver managing SG_IO (version 3 and after */
8869e103 389 if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
d52affa7 390 sg_version < 30000) {
1ecda02b 391 error_report("scsi-generic: scsi generic interface too old");
d52affa7
GH
392 return -1;
393 }
2cc977e2
TS
394
395 /* get LUN of the /dev/sg? */
8869e103 396 if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
1ecda02b 397 error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
d52affa7
GH
398 return -1;
399 }
2cc977e2
TS
400
401 /* define device state */
8869e103
PB
402 s->type = scsiid.scsi_type;
403 DPRINTF("device type %d\n", s->type);
404 if (s->type == TYPE_TAPE) {
405 s->blocksize = get_stream_blocksize(s->conf.bs);
406 if (s->blocksize == -1) {
407 s->blocksize = 0;
408 }
89c0f643 409 } else {
8869e103 410 s->blocksize = get_blocksize(s->conf.bs);
89c0f643 411 /* removable media returns 0 if not present */
8869e103
PB
412 if (s->blocksize <= 0) {
413 if (s->type == TYPE_ROM || s->type == TYPE_WORM) {
414 s->blocksize = 2048;
415 } else {
416 s->blocksize = 512;
417 }
89c0f643
AJ
418 }
419 }
8869e103
PB
420
421 DPRINTF("block size %d\n", s->blocksize);
d52affa7
GH
422 return 0;
423}
2cc977e2 424
8dbd4574
PB
425static SCSIReqOps scsi_generic_req_ops = {
426 .size = sizeof(SCSIGenericReq),
12010e7b
PB
427 .free_req = scsi_free_request,
428 .send_command = scsi_send_command,
429 .read_data = scsi_read_data,
430 .write_data = scsi_write_data,
431 .cancel_io = scsi_cancel_io,
432 .get_buf = scsi_get_buf,
8dbd4574
PB
433};
434
435static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
436 void *hba_private)
437{
438 SCSIRequest *req;
439
440 req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
441 return req;
442}
443
d52affa7
GH
444static SCSIDeviceInfo scsi_generic_info = {
445 .qdev.name = "scsi-generic",
446 .qdev.desc = "pass through generic scsi device (/dev/sg*)",
8869e103 447 .qdev.size = sizeof(SCSIDevice),
f8b6d672 448 .qdev.reset = scsi_generic_reset,
d52affa7
GH
449 .init = scsi_generic_initfn,
450 .destroy = scsi_destroy,
5c6c0e51 451 .alloc_req = scsi_new_request,
d52affa7 452 .qdev.props = (Property[]) {
8869e103 453 DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
d52affa7
GH
454 DEFINE_PROP_END_OF_LIST(),
455 },
456};
2cc977e2 457
d52affa7
GH
458static void scsi_generic_register_devices(void)
459{
460 scsi_qdev_register(&scsi_generic_info);
2cc977e2 461}
d52affa7
GH
462device_init(scsi_generic_register_devices)
463
2cc977e2 464#endif /* __linux__ */