scsi-generic: look at host status
[qemu.git] / hw / scsi-generic.c
blob5ad3d573eba825745fe4f8753b9b53037a669828
1 /*
2 * Generic SCSI Device support
4 * Copyright (c) 2007 Bull S.A.S.
5 * Based on code by Paul Brook
6 * Based on code by Fabrice Bellard
8 * Written by Laurent Vivier <Laurent.Vivier@bull.net>
10 * This code is licensed under the LGPL.
14 #include "qemu-common.h"
15 #include "qemu-error.h"
16 #include "scsi.h"
17 #include "blockdev.h"
19 #ifdef __linux__
21 //#define DEBUG_SCSI
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
30 #define BADF(fmt, ...) \
31 do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
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"
40 #define SCSI_SENSE_BUF_SIZE 96
42 #define SG_ERR_DRIVER_TIMEOUT 0x06
43 #define SG_ERR_DRIVER_SENSE 0x08
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
50 #ifndef MAX_UINT
51 #define MAX_UINT ((unsigned int)-1)
52 #endif
54 typedef struct SCSIGenericReq {
55 SCSIRequest req;
56 uint8_t *buf;
57 int buflen;
58 int len;
59 sg_io_hdr_t io_header;
60 } SCSIGenericReq;
62 static void scsi_free_request(SCSIRequest *req)
64 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
66 g_free(r->buf);
69 /* Helper function for command completion. */
70 static void scsi_command_complete(void *opaque, int ret)
72 int status;
73 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
75 r->req.aiocb = NULL;
76 if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
77 r->req.sense_len = r->io_header.sb_len_wr;
80 if (ret != 0) {
81 switch (ret) {
82 case -EDOM:
83 status = TASK_SET_FULL;
84 break;
85 case -ENOMEM:
86 status = CHECK_CONDITION;
87 scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
88 break;
89 default:
90 status = CHECK_CONDITION;
91 scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
92 break;
94 } else {
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)) {
99 status = BUSY;
100 BADF("Driver Timeout\n");
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));
104 } else if (r->io_header.status) {
105 status = r->io_header.status;
106 } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
107 status = CHECK_CONDITION;
108 } else {
109 status = GOOD;
112 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
113 r, r->req.tag, status);
115 scsi_req_complete(&r->req, status);
118 /* Cancel a pending data transfer. */
119 static void scsi_cancel_io(SCSIRequest *req)
121 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
123 DPRINTF("Cancel tag=0x%x\n", req->tag);
124 if (r->req.aiocb) {
125 bdrv_aio_cancel(r->req.aiocb);
127 r->req.aiocb = NULL;
130 static int execute_command(BlockDriverState *bdrv,
131 SCSIGenericReq *r, int direction,
132 BlockDriverCompletionFunc *complete)
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;
138 r->io_header.cmdp = r->req.cmd.buf;
139 r->io_header.cmd_len = r->req.cmd.len;
140 r->io_header.mx_sb_len = sizeof(r->req.sense);
141 r->io_header.sbp = r->req.sense;
142 r->io_header.timeout = MAX_UINT;
143 r->io_header.usr_ptr = r;
144 r->io_header.flags |= SG_FLAG_DIRECT_IO;
146 r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
147 if (r->req.aiocb == NULL) {
148 BADF("execute_command: read failed !\n");
149 return -ENOMEM;
152 return 0;
155 static void scsi_read_complete(void * opaque, int ret)
157 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
158 int len;
160 r->req.aiocb = NULL;
161 if (ret) {
162 DPRINTF("IO error ret %d\n", ret);
163 scsi_command_complete(r, ret);
164 return;
166 len = r->io_header.dxfer_len - r->io_header.resid;
167 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
169 r->len = -1;
170 if (len == 0) {
171 scsi_command_complete(r, 0);
172 } else {
173 scsi_req_data(&r->req, len);
177 /* Read more data from scsi device into buffer. */
178 static void scsi_read_data(SCSIRequest *req)
180 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
181 SCSIDevice *s = r->req.dev;
182 int ret;
184 DPRINTF("scsi_read_data 0x%x\n", req->tag);
185 if (r->len == -1) {
186 scsi_command_complete(r, 0);
187 return;
190 ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
191 if (ret < 0) {
192 scsi_command_complete(r, ret);
196 static void scsi_write_complete(void * opaque, int ret)
198 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
199 SCSIDevice *s = r->req.dev;
201 DPRINTF("scsi_write_complete() ret = %d\n", ret);
202 r->req.aiocb = NULL;
203 if (ret) {
204 DPRINTF("IO error\n");
205 scsi_command_complete(r, ret);
206 return;
209 if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
210 s->type == TYPE_TAPE) {
211 s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
212 DPRINTF("block size %d\n", s->blocksize);
215 scsi_command_complete(r, ret);
218 /* Write data to a scsi device. Returns nonzero on failure.
219 The transfer may complete asynchronously. */
220 static void scsi_write_data(SCSIRequest *req)
222 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
223 SCSIDevice *s = r->req.dev;
224 int ret;
226 DPRINTF("scsi_write_data 0x%x\n", req->tag);
227 if (r->len == 0) {
228 r->len = r->buflen;
229 scsi_req_data(&r->req, r->len);
230 return;
233 ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
234 if (ret < 0) {
235 scsi_command_complete(r, ret);
239 /* Return a pointer to the data buffer. */
240 static uint8_t *scsi_get_buf(SCSIRequest *req)
242 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
244 return r->buf;
247 /* Execute a scsi command. Returns the length of the data expected by the
248 command. This will be Positive for data transfers from the device
249 (eg. disk reads), negative for transfers to the device (eg. disk writes),
250 and zero if the command does not transfer any data. */
252 static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
254 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
255 SCSIDevice *s = r->req.dev;
256 int ret;
258 DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
259 r->req.cmd.xfer, cmd[0]);
261 #ifdef DEBUG_SCSI
263 int i;
264 for (i = 1; i < r->req.cmd.len; i++) {
265 printf(" 0x%02x", cmd[i]);
267 printf("\n");
269 #endif
271 if (r->req.cmd.xfer == 0) {
272 if (r->buf != NULL)
273 g_free(r->buf);
274 r->buflen = 0;
275 r->buf = NULL;
276 ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
277 if (ret < 0) {
278 scsi_command_complete(r, ret);
279 return 0;
281 return 0;
284 if (r->buflen != r->req.cmd.xfer) {
285 if (r->buf != NULL)
286 g_free(r->buf);
287 r->buf = g_malloc(r->req.cmd.xfer);
288 r->buflen = r->req.cmd.xfer;
291 memset(r->buf, 0, r->buflen);
292 r->len = r->req.cmd.xfer;
293 if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
294 r->len = 0;
295 return -r->req.cmd.xfer;
296 } else {
297 return r->req.cmd.xfer;
301 static int get_blocksize(BlockDriverState *bdrv)
303 uint8_t cmd[10];
304 uint8_t buf[8];
305 uint8_t sensebuf[8];
306 sg_io_hdr_t io_header;
307 int ret;
309 memset(cmd, 0, sizeof(cmd));
310 memset(buf, 0, sizeof(buf));
311 cmd[0] = READ_CAPACITY_10;
313 memset(&io_header, 0, sizeof(io_header));
314 io_header.interface_id = 'S';
315 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
316 io_header.dxfer_len = sizeof(buf);
317 io_header.dxferp = buf;
318 io_header.cmdp = cmd;
319 io_header.cmd_len = sizeof(cmd);
320 io_header.mx_sb_len = sizeof(sensebuf);
321 io_header.sbp = sensebuf;
322 io_header.timeout = 6000; /* XXX */
324 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
325 if (ret < 0 || io_header.driver_status || io_header.host_status) {
326 return -1;
328 return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
331 static int get_stream_blocksize(BlockDriverState *bdrv)
333 uint8_t cmd[6];
334 uint8_t buf[12];
335 uint8_t sensebuf[8];
336 sg_io_hdr_t io_header;
337 int ret;
339 memset(cmd, 0, sizeof(cmd));
340 memset(buf, 0, sizeof(buf));
341 cmd[0] = MODE_SENSE;
342 cmd[4] = sizeof(buf);
344 memset(&io_header, 0, sizeof(io_header));
345 io_header.interface_id = 'S';
346 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
347 io_header.dxfer_len = sizeof(buf);
348 io_header.dxferp = buf;
349 io_header.cmdp = cmd;
350 io_header.cmd_len = sizeof(cmd);
351 io_header.mx_sb_len = sizeof(sensebuf);
352 io_header.sbp = sensebuf;
353 io_header.timeout = 6000; /* XXX */
355 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
356 if (ret < 0 || io_header.driver_status || io_header.host_status) {
357 return -1;
359 return (buf[9] << 16) | (buf[10] << 8) | buf[11];
362 static void scsi_generic_reset(DeviceState *dev)
364 SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
366 scsi_device_purge_requests(s, SENSE_CODE(RESET));
369 static void scsi_destroy(SCSIDevice *s)
371 scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
372 blockdev_mark_auto_del(s->conf.bs);
375 static int scsi_generic_initfn(SCSIDevice *s)
377 int sg_version;
378 struct sg_scsi_id scsiid;
380 if (!s->conf.bs) {
381 error_report("scsi-generic: drive property not set");
382 return -1;
385 /* check we are really using a /dev/sg* file */
386 if (!bdrv_is_sg(s->conf.bs)) {
387 error_report("scsi-generic: not /dev/sg*");
388 return -1;
391 if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
392 error_report("Device doesn't support drive option werror");
393 return -1;
395 if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
396 error_report("Device doesn't support drive option rerror");
397 return -1;
400 /* check we are using a driver managing SG_IO (version 3 and after */
401 if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
402 sg_version < 30000) {
403 error_report("scsi-generic: scsi generic interface too old");
404 return -1;
407 /* get LUN of the /dev/sg? */
408 if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
409 error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
410 return -1;
413 /* define device state */
414 s->type = scsiid.scsi_type;
415 DPRINTF("device type %d\n", s->type);
416 if (s->type == TYPE_TAPE) {
417 s->blocksize = get_stream_blocksize(s->conf.bs);
418 if (s->blocksize == -1) {
419 s->blocksize = 0;
421 } else {
422 s->blocksize = get_blocksize(s->conf.bs);
423 /* removable media returns 0 if not present */
424 if (s->blocksize <= 0) {
425 if (s->type == TYPE_ROM || s->type == TYPE_WORM) {
426 s->blocksize = 2048;
427 } else {
428 s->blocksize = 512;
433 DPRINTF("block size %d\n", s->blocksize);
434 return 0;
437 static SCSIReqOps scsi_generic_req_ops = {
438 .size = sizeof(SCSIGenericReq),
439 .free_req = scsi_free_request,
440 .send_command = scsi_send_command,
441 .read_data = scsi_read_data,
442 .write_data = scsi_write_data,
443 .cancel_io = scsi_cancel_io,
444 .get_buf = scsi_get_buf,
447 static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
448 void *hba_private)
450 SCSIRequest *req;
452 req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
453 return req;
456 static SCSIDeviceInfo scsi_generic_info = {
457 .qdev.name = "scsi-generic",
458 .qdev.desc = "pass through generic scsi device (/dev/sg*)",
459 .qdev.size = sizeof(SCSIDevice),
460 .qdev.reset = scsi_generic_reset,
461 .init = scsi_generic_initfn,
462 .destroy = scsi_destroy,
463 .alloc_req = scsi_new_request,
464 .qdev.props = (Property[]) {
465 DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
466 DEFINE_PROP_END_OF_LIST(),
470 static void scsi_generic_register_devices(void)
472 scsi_qdev_register(&scsi_generic_info);
474 device_init(scsi_generic_register_devices)
476 #endif /* __linux__ */