1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "qemu-common.h"
15#include "qemu/error-report.h"
16#include "hw/scsi/scsi.h"
17#include "sysemu/blockdev.h"
18
19#ifdef __linux__
20
21
22
23#ifdef DEBUG_SCSI
24#define DPRINTF(fmt, ...) \
25do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
26#else
27#define DPRINTF(fmt, ...) do {} while(0)
28#endif
29
30#define BADF(fmt, ...) \
31do { 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 "block/scsi.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#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
49
50#ifndef MAX_UINT
51#define MAX_UINT ((unsigned int)-1)
52#endif
53
54typedef struct SCSIGenericReq {
55 SCSIRequest req;
56 uint8_t *buf;
57 int buflen;
58 int len;
59 sg_io_hdr_t io_header;
60} SCSIGenericReq;
61
62static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
63{
64 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
65
66 qemu_put_sbe32s(f, &r->buflen);
67 if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
68 assert(!r->req.sg);
69 qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
70 }
71}
72
73static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
74{
75 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
76
77 qemu_get_sbe32s(f, &r->buflen);
78 if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
79 assert(!r->req.sg);
80 qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
81 }
82}
83
84static void scsi_free_request(SCSIRequest *req)
85{
86 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
87
88 g_free(r->buf);
89}
90
91
92static void scsi_command_complete(void *opaque, int ret)
93{
94 int status;
95 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
96
97 r->req.aiocb = NULL;
98 if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
99 r->req.sense_len = r->io_header.sb_len_wr;
100 }
101
102 if (ret != 0) {
103 switch (ret) {
104 case -EDOM:
105 status = TASK_SET_FULL;
106 break;
107 case -ENOMEM:
108 status = CHECK_CONDITION;
109 scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
110 break;
111 default:
112 status = CHECK_CONDITION;
113 scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
114 break;
115 }
116 } else {
117 if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
118 r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
119 r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
120 (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
121 status = BUSY;
122 BADF("Driver Timeout\n");
123 } else if (r->io_header.host_status) {
124 status = CHECK_CONDITION;
125 scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
126 } else if (r->io_header.status) {
127 status = r->io_header.status;
128 } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
129 status = CHECK_CONDITION;
130 } else {
131 status = GOOD;
132 }
133 }
134 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
135 r, r->req.tag, status);
136
137 scsi_req_complete(&r->req, status);
138 if (!r->req.io_canceled) {
139 scsi_req_unref(&r->req);
140 }
141}
142
143
144static void scsi_cancel_io(SCSIRequest *req)
145{
146 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
147
148 DPRINTF("Cancel tag=0x%x\n", req->tag);
149 if (r->req.aiocb) {
150 bdrv_aio_cancel(r->req.aiocb);
151
152
153
154
155 scsi_req_unref(&r->req);
156 }
157 r->req.aiocb = NULL;
158}
159
160static int execute_command(BlockDriverState *bdrv,
161 SCSIGenericReq *r, int direction,
162 BlockDriverCompletionFunc *complete)
163{
164 r->io_header.interface_id = 'S';
165 r->io_header.dxfer_direction = direction;
166 r->io_header.dxferp = r->buf;
167 r->io_header.dxfer_len = r->buflen;
168 r->io_header.cmdp = r->req.cmd.buf;
169 r->io_header.cmd_len = r->req.cmd.len;
170 r->io_header.mx_sb_len = sizeof(r->req.sense);
171 r->io_header.sbp = r->req.sense;
172 r->io_header.timeout = MAX_UINT;
173 r->io_header.usr_ptr = r;
174 r->io_header.flags |= SG_FLAG_DIRECT_IO;
175
176 r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
177 if (r->req.aiocb == NULL) {
178 return -EIO;
179 }
180
181 return 0;
182}
183
184static void scsi_read_complete(void * opaque, int ret)
185{
186 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
187 SCSIDevice *s = r->req.dev;
188 int len;
189
190 r->req.aiocb = NULL;
191 if (ret) {
192 DPRINTF("IO error ret %d\n", ret);
193 scsi_command_complete(r, ret);
194 return;
195 }
196 len = r->io_header.dxfer_len - r->io_header.resid;
197 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
198
199 r->len = -1;
200 if (len == 0) {
201 scsi_command_complete(r, 0);
202 } else {
203
204 if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
205 (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
206 s->blocksize = ldl_be_p(&r->buf[4]);
207 s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
208 } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
209 (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
210 s->blocksize = ldl_be_p(&r->buf[8]);
211 s->max_lba = ldq_be_p(&r->buf[0]);
212 }
213 bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
214
215 scsi_req_data(&r->req, len);
216 if (!r->req.io_canceled) {
217 scsi_req_unref(&r->req);
218 }
219 }
220}
221
222
223static void scsi_read_data(SCSIRequest *req)
224{
225 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
226 SCSIDevice *s = r->req.dev;
227 int ret;
228
229 DPRINTF("scsi_read_data 0x%x\n", req->tag);
230
231
232 scsi_req_ref(&r->req);
233 if (r->len == -1) {
234 scsi_command_complete(r, 0);
235 return;
236 }
237
238 ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
239 if (ret < 0) {
240 scsi_command_complete(r, ret);
241 }
242}
243
244static void scsi_write_complete(void * opaque, int ret)
245{
246 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
247 SCSIDevice *s = r->req.dev;
248
249 DPRINTF("scsi_write_complete() ret = %d\n", ret);
250 r->req.aiocb = NULL;
251 if (ret) {
252 DPRINTF("IO error\n");
253 scsi_command_complete(r, ret);
254 return;
255 }
256
257 if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
258 s->type == TYPE_TAPE) {
259 s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
260 DPRINTF("block size %d\n", s->blocksize);
261 }
262
263 scsi_command_complete(r, ret);
264}
265
266
267
268static void scsi_write_data(SCSIRequest *req)
269{
270 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
271 SCSIDevice *s = r->req.dev;
272 int ret;
273
274 DPRINTF("scsi_write_data 0x%x\n", req->tag);
275 if (r->len == 0) {
276 r->len = r->buflen;
277 scsi_req_data(&r->req, r->len);
278 return;
279 }
280
281
282 scsi_req_ref(&r->req);
283 ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
284 if (ret < 0) {
285 scsi_command_complete(r, ret);
286 }
287}
288
289
290static uint8_t *scsi_get_buf(SCSIRequest *req)
291{
292 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
293
294 return r->buf;
295}
296
297
298
299
300
301
302static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
303{
304 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
305 SCSIDevice *s = r->req.dev;
306 int ret;
307
308 DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
309 r->req.cmd.xfer, cmd[0]);
310
311#ifdef DEBUG_SCSI
312 {
313 int i;
314 for (i = 1; i < r->req.cmd.len; i++) {
315 printf(" 0x%02x", cmd[i]);
316 }
317 printf("\n");
318 }
319#endif
320
321 if (r->req.cmd.xfer == 0) {
322 if (r->buf != NULL)
323 g_free(r->buf);
324 r->buflen = 0;
325 r->buf = NULL;
326
327 scsi_req_ref(&r->req);
328 ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
329 if (ret < 0) {
330 scsi_command_complete(r, ret);
331 return 0;
332 }
333 return 0;
334 }
335
336 if (r->buflen != r->req.cmd.xfer) {
337 if (r->buf != NULL)
338 g_free(r->buf);
339 r->buf = g_malloc(r->req.cmd.xfer);
340 r->buflen = r->req.cmd.xfer;
341 }
342
343 memset(r->buf, 0, r->buflen);
344 r->len = r->req.cmd.xfer;
345 if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
346 r->len = 0;
347 return -r->req.cmd.xfer;
348 } else {
349 return r->req.cmd.xfer;
350 }
351}
352
353static int get_stream_blocksize(BlockDriverState *bdrv)
354{
355 uint8_t cmd[6];
356 uint8_t buf[12];
357 uint8_t sensebuf[8];
358 sg_io_hdr_t io_header;
359 int ret;
360
361 memset(cmd, 0, sizeof(cmd));
362 memset(buf, 0, sizeof(buf));
363 cmd[0] = MODE_SENSE;
364 cmd[4] = sizeof(buf);
365
366 memset(&io_header, 0, sizeof(io_header));
367 io_header.interface_id = 'S';
368 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
369 io_header.dxfer_len = sizeof(buf);
370 io_header.dxferp = buf;
371 io_header.cmdp = cmd;
372 io_header.cmd_len = sizeof(cmd);
373 io_header.mx_sb_len = sizeof(sensebuf);
374 io_header.sbp = sensebuf;
375 io_header.timeout = 6000;
376
377 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
378 if (ret < 0 || io_header.driver_status || io_header.host_status) {
379 return -1;
380 }
381 return (buf[9] << 16) | (buf[10] << 8) | buf[11];
382}
383
384static void scsi_generic_reset(DeviceState *dev)
385{
386 SCSIDevice *s = SCSI_DEVICE(dev);
387
388 scsi_device_purge_requests(s, SENSE_CODE(RESET));
389}
390
391static void scsi_destroy(SCSIDevice *s)
392{
393 scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
394 blockdev_mark_auto_del(s->conf.bs);
395}
396
397static int scsi_generic_initfn(SCSIDevice *s)
398{
399 int sg_version;
400 struct sg_scsi_id scsiid;
401
402 if (!s->conf.bs) {
403 error_report("drive property not set");
404 return -1;
405 }
406
407 if (bdrv_get_on_error(s->conf.bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
408 error_report("Device doesn't support drive option werror");
409 return -1;
410 }
411 if (bdrv_get_on_error(s->conf.bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
412 error_report("Device doesn't support drive option rerror");
413 return -1;
414 }
415
416
417 if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) {
418 error_report("scsi generic interface not supported");
419 return -1;
420 }
421 if (sg_version < 30000) {
422 error_report("scsi generic interface too old");
423 return -1;
424 }
425
426
427 if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
428 error_report("SG_GET_SCSI_ID ioctl failed");
429 return -1;
430 }
431
432
433 s->type = scsiid.scsi_type;
434 DPRINTF("device type %d\n", s->type);
435 if (s->type == TYPE_DISK || s->type == TYPE_ROM) {
436 add_boot_device_path(s->conf.bootindex, &s->qdev, NULL);
437 }
438
439 switch (s->type) {
440 case TYPE_TAPE:
441 s->blocksize = get_stream_blocksize(s->conf.bs);
442 if (s->blocksize == -1) {
443 s->blocksize = 0;
444 }
445 break;
446
447
448
449
450
451 case TYPE_ROM:
452 case TYPE_WORM:
453 s->blocksize = 2048;
454 break;
455 default:
456 s->blocksize = 512;
457 break;
458 }
459
460 DPRINTF("block size %d\n", s->blocksize);
461 return 0;
462}
463
464const SCSIReqOps scsi_generic_req_ops = {
465 .size = sizeof(SCSIGenericReq),
466 .free_req = scsi_free_request,
467 .send_command = scsi_send_command,
468 .read_data = scsi_read_data,
469 .write_data = scsi_write_data,
470 .cancel_io = scsi_cancel_io,
471 .get_buf = scsi_get_buf,
472 .load_request = scsi_generic_load_request,
473 .save_request = scsi_generic_save_request,
474};
475
476static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
477 uint8_t *buf, void *hba_private)
478{
479 SCSIRequest *req;
480
481 req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
482 return req;
483}
484
485static Property scsi_generic_properties[] = {
486 DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs),
487 DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1),
488 DEFINE_PROP_END_OF_LIST(),
489};
490
491static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
492{
493 DeviceClass *dc = DEVICE_CLASS(klass);
494 SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
495
496 sc->init = scsi_generic_initfn;
497 sc->destroy = scsi_destroy;
498 sc->alloc_req = scsi_new_request;
499 dc->fw_name = "disk";
500 dc->desc = "pass through generic scsi device (/dev/sg*)";
501 dc->reset = scsi_generic_reset;
502 dc->props = scsi_generic_properties;
503 dc->vmsd = &vmstate_scsi_device;
504}
505
506static const TypeInfo scsi_generic_info = {
507 .name = "scsi-generic",
508 .parent = TYPE_SCSI_DEVICE,
509 .instance_size = sizeof(SCSIDevice),
510 .class_init = scsi_generic_class_initfn,
511};
512
513static void scsi_generic_register_types(void)
514{
515 type_register_static(&scsi_generic_info);
516}
517
518type_init(scsi_generic_register_types)
519
520#endif
521