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