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