blob: d856d23b3bceb8ab5977cb53cd57cd13305dd402 [file] [log] [blame]
ths2cc977e2007-12-24 16:11:51 +00001/*
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 *
Matthew Fernandez8e31bf32011-06-26 12:21:35 +100010 * This code is licensed under the LGPL.
ths2cc977e2007-12-24 16:11:51 +000011 *
12 */
13
14#include "qemu-common.h"
Markus Armbruster2f792012010-02-18 16:24:31 +010015#include "qemu-error.h"
Gerd Hoffmann43b443b2009-10-30 09:54:00 +010016#include "scsi.h"
Blue Swirl24463332010-08-24 15:22:24 +000017#include "blockdev.h"
ths2cc977e2007-12-24 16:11:51 +000018
Gerd Hoffmannd52affa2009-08-31 14:24:04 +020019#ifdef __linux__
ths2cc977e2007-12-24 16:11:51 +000020
21//#define DEBUG_SCSI
22
23#ifdef DEBUG_SCSI
Blue Swirl001faf32009-05-13 17:53:17 +000024#define DPRINTF(fmt, ...) \
25do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
ths2cc977e2007-12-24 16:11:51 +000026#else
Blue Swirl001faf32009-05-13 17:53:17 +000027#define DPRINTF(fmt, ...) do {} while(0)
ths2cc977e2007-12-24 16:11:51 +000028#endif
29
Blue Swirl001faf32009-05-13 17:53:17 +000030#define BADF(fmt, ...) \
31do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
ths2cc977e2007-12-24 16:11:51 +000032
33#include <stdio.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include <scsi/sg.h>
Gerd Hoffmann0d65e1f2009-11-26 15:33:53 +010038#include "scsi-defs.h"
ths2cc977e2007-12-24 16:11:51 +000039
aliguoria9dd6842008-09-23 13:38:44 +000040#define SCSI_SENSE_BUF_SIZE 96
ths2cc977e2007-12-24 16:11:51 +000041
Paolo Bonzinia3b16e72011-10-12 14:53:43 +020042#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
ths2cc977e2007-12-24 16:11:51 +000049
50#ifndef MAX_UINT
51#define MAX_UINT ((unsigned int)-1)
52#endif
53
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010054typedef struct SCSIGenericReq {
55 SCSIRequest req;
ths2cc977e2007-12-24 16:11:51 +000056 uint8_t *buf;
57 int buflen;
58 int len;
59 sg_io_hdr_t io_header;
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010060} SCSIGenericReq;
ths2cc977e2007-12-24 16:11:51 +000061
Paolo Bonzini56b1fc42011-12-15 07:24:30 -050062static 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
Paolo Bonziniad2d30f2011-04-18 16:01:56 +020084static void scsi_free_request(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +000085{
Paolo Bonziniad2d30f2011-04-18 16:01:56 +020086 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
87
Anthony Liguori7267c092011-08-20 22:09:37 -050088 g_free(r->buf);
ths2cc977e2007-12-24 16:11:51 +000089}
90
ths2cc977e2007-12-24 16:11:51 +000091/* Helper function for command completion. */
92static void scsi_command_complete(void *opaque, int ret)
93{
Paolo Bonzini682a9b22011-08-03 10:49:06 +020094 int status;
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010095 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
ths2cc977e2007-12-24 16:11:51 +000096
Paolo Bonzinid33e0ce2011-05-25 16:53:46 +020097 r->req.aiocb = NULL;
Paolo Bonzinia3b16e72011-10-12 14:53:43 +020098 if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
Paolo Bonzinib45ef672011-08-03 10:49:07 +020099 r->req.sense_len = r->io_header.sb_len_wr;
Paolo Bonzinia3b16e72011-10-12 14:53:43 +0200100 }
aurel3289c0f642008-10-17 08:08:56 +0000101
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200102 if (ret != 0) {
103 switch (ret) {
Paolo Bonzini2e7cc4d2011-04-18 14:29:16 +0200104 case -EDOM:
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200105 status = TASK_SET_FULL;
Paolo Bonzini2e7cc4d2011-04-18 14:29:16 +0200106 break;
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200107 case -ENOMEM:
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200108 status = CHECK_CONDITION;
Paolo Bonzinib45ef672011-08-03 10:49:07 +0200109 scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200110 break;
111 default:
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200112 status = CHECK_CONDITION;
Paolo Bonzinib45ef672011-08-03 10:49:07 +0200113 scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200114 break;
115 }
116 } else {
Paolo Bonzinia3b16e72011-10-12 14:53:43 +0200117 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)) {
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200121 status = BUSY;
ths2cc977e2007-12-24 16:11:51 +0000122 BADF("Driver Timeout\n");
Paolo Bonzinia3b16e72011-10-12 14:53:43 +0200123 } else if (r->io_header.host_status) {
124 status = CHECK_CONDITION;
125 scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200126 } else if (r->io_header.status) {
127 status = r->io_header.status;
Paolo Bonzinib45ef672011-08-03 10:49:07 +0200128 } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200129 status = CHECK_CONDITION;
130 } else {
131 status = GOOD;
132 }
ths2cc977e2007-12-24 16:11:51 +0000133 }
aurel3289c0f642008-10-17 08:08:56 +0000134 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200135 r, r->req.tag, status);
Gerd Hoffmanned3a34a2009-11-26 15:34:00 +0100136
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200137 scsi_req_complete(&r->req, status);
Paolo Bonzinic9501c92011-10-25 12:53:35 +0200138 if (!r->req.io_canceled) {
139 scsi_req_unref(&r->req);
140 }
ths2cc977e2007-12-24 16:11:51 +0000141}
142
143/* Cancel a pending data transfer. */
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200144static void scsi_cancel_io(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +0000145{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200146 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);
Paolo Bonzinic9501c92011-10-25 12:53:35 +0200151
152 /* This reference was left in by scsi_*_data. We take ownership of
153 * it independent of whether bdrv_aio_cancel completes the request
154 * or not. */
155 scsi_req_unref(&r->req);
ths2cc977e2007-12-24 16:11:51 +0000156 }
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200157 r->req.aiocb = NULL;
ths2cc977e2007-12-24 16:11:51 +0000158}
159
160static int execute_command(BlockDriverState *bdrv,
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100161 SCSIGenericReq *r, int direction,
ths2cc977e2007-12-24 16:11:51 +0000162 BlockDriverCompletionFunc *complete)
163{
ths2cc977e2007-12-24 16:11:51 +0000164 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;
Gerd Hoffmann29362eb2009-11-26 15:33:51 +0100168 r->io_header.cmdp = r->req.cmd.buf;
169 r->io_header.cmd_len = r->req.cmd.len;
Paolo Bonzinib45ef672011-08-03 10:49:07 +0200170 r->io_header.mx_sb_len = sizeof(r->req.sense);
171 r->io_header.sbp = r->req.sense;
ths2cc977e2007-12-24 16:11:51 +0000172 r->io_header.timeout = MAX_UINT;
173 r->io_header.usr_ptr = r;
174 r->io_header.flags |= SG_FLAG_DIRECT_IO;
175
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100176 r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
ths2cc977e2007-12-24 16:11:51 +0000177
178 return 0;
179}
180
181static void scsi_read_complete(void * opaque, int ret)
182{
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100183 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
Paolo Bonzini9b6eef82011-10-13 10:36:27 +0200184 SCSIDevice *s = r->req.dev;
ths2cc977e2007-12-24 16:11:51 +0000185 int len;
186
Paolo Bonzinid33e0ce2011-05-25 16:53:46 +0200187 r->req.aiocb = NULL;
ths2cc977e2007-12-24 16:11:51 +0000188 if (ret) {
Bernhard Kohlaa2b1e82010-09-01 16:33:21 +0200189 DPRINTF("IO error ret %d\n", ret);
ths2cc977e2007-12-24 16:11:51 +0000190 scsi_command_complete(r, ret);
191 return;
192 }
193 len = r->io_header.dxfer_len - r->io_header.resid;
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100194 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
ths2cc977e2007-12-24 16:11:51 +0000195
196 r->len = -1;
Paolo Bonzini40f16dd2011-05-03 14:15:59 +0200197 if (len == 0) {
aurel3289c0f642008-10-17 08:08:56 +0000198 scsi_command_complete(r, 0);
Paolo Bonzini40f16dd2011-05-03 14:15:59 +0200199 } else {
Paolo Bonzini9b6eef82011-10-13 10:36:27 +0200200 /* Snoop READ CAPACITY output to set the blocksize. */
201 if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
202 s->blocksize = ldl_be_p(&r->buf[4]);
Paolo Bonzini78779032011-10-13 10:39:50 +0200203 s->max_lba = ldl_be_p(&r->buf[0]);
Paolo Bonzini9b6eef82011-10-13 10:36:27 +0200204 } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
205 (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
206 s->blocksize = ldl_be_p(&r->buf[8]);
Paolo Bonzini78779032011-10-13 10:39:50 +0200207 s->max_lba = ldq_be_p(&r->buf[0]);
Paolo Bonzini9b6eef82011-10-13 10:36:27 +0200208 }
209 bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
210
Paolo Bonziniab9adc82011-04-18 14:59:13 +0200211 scsi_req_data(&r->req, len);
Paolo Bonzinic9501c92011-10-25 12:53:35 +0200212 if (!r->req.io_canceled) {
213 scsi_req_unref(&r->req);
214 }
Paolo Bonzini40f16dd2011-05-03 14:15:59 +0200215 }
ths2cc977e2007-12-24 16:11:51 +0000216}
217
218/* Read more data from scsi device into buffer. */
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200219static void scsi_read_data(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +0000220{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200221 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
Paolo Bonzini8869e102011-10-12 12:49:35 +0200222 SCSIDevice *s = r->req.dev;
ths2cc977e2007-12-24 16:11:51 +0000223 int ret;
224
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200225 DPRINTF("scsi_read_data 0x%x\n", req->tag);
Paolo Bonzinic9501c92011-10-25 12:53:35 +0200226
227 /* The request is used as the AIO opaque value, so add a ref. */
228 scsi_req_ref(&r->req);
ths2cc977e2007-12-24 16:11:51 +0000229 if (r->len == -1) {
230 scsi_command_complete(r, 0);
231 return;
232 }
233
Paolo Bonzini8869e102011-10-12 12:49:35 +0200234 ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200235 if (ret < 0) {
236 scsi_command_complete(r, ret);
ths2cc977e2007-12-24 16:11:51 +0000237 }
238}
239
240static void scsi_write_complete(void * opaque, int ret)
241{
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100242 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
Paolo Bonzini8869e102011-10-12 12:49:35 +0200243 SCSIDevice *s = r->req.dev;
ths2cc977e2007-12-24 16:11:51 +0000244
245 DPRINTF("scsi_write_complete() ret = %d\n", ret);
Paolo Bonzinid33e0ce2011-05-25 16:53:46 +0200246 r->req.aiocb = NULL;
ths2cc977e2007-12-24 16:11:51 +0000247 if (ret) {
248 DPRINTF("IO error\n");
249 scsi_command_complete(r, ret);
250 return;
251 }
252
Gerd Hoffmann29362eb2009-11-26 15:33:51 +0100253 if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
Paolo Bonzini8869e102011-10-12 12:49:35 +0200254 s->type == TYPE_TAPE) {
255 s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
256 DPRINTF("block size %d\n", s->blocksize);
aurel3289c0f642008-10-17 08:08:56 +0000257 }
258
ths2cc977e2007-12-24 16:11:51 +0000259 scsi_command_complete(r, ret);
260}
261
262/* Write data to a scsi device. Returns nonzero on failure.
263 The transfer may complete asynchronously. */
Paolo Bonzini42741212011-04-22 09:39:16 +0200264static void scsi_write_data(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +0000265{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200266 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
Paolo Bonzini8869e102011-10-12 12:49:35 +0200267 SCSIDevice *s = r->req.dev;
ths2cc977e2007-12-24 16:11:51 +0000268 int ret;
269
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200270 DPRINTF("scsi_write_data 0x%x\n", req->tag);
ths2cc977e2007-12-24 16:11:51 +0000271 if (r->len == 0) {
272 r->len = r->buflen;
Paolo Bonziniab9adc82011-04-18 14:59:13 +0200273 scsi_req_data(&r->req, r->len);
Paolo Bonzini42741212011-04-22 09:39:16 +0200274 return;
ths2cc977e2007-12-24 16:11:51 +0000275 }
276
Paolo Bonzinic9501c92011-10-25 12:53:35 +0200277 /* The request is used as the AIO opaque value, so add a ref. */
278 scsi_req_ref(&r->req);
Paolo Bonzini8869e102011-10-12 12:49:35 +0200279 ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200280 if (ret < 0) {
281 scsi_command_complete(r, ret);
ths2cc977e2007-12-24 16:11:51 +0000282 }
ths2cc977e2007-12-24 16:11:51 +0000283}
284
285/* Return a pointer to the data buffer. */
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200286static uint8_t *scsi_get_buf(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +0000287{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200288 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
289
ths2cc977e2007-12-24 16:11:51 +0000290 return r->buf;
291}
292
ths2cc977e2007-12-24 16:11:51 +0000293/* Execute a scsi command. Returns the length of the data expected by the
294 command. This will be Positive for data transfers from the device
295 (eg. disk reads), negative for transfers to the device (eg. disk writes),
296 and zero if the command does not transfer any data. */
297
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200298static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
ths2cc977e2007-12-24 16:11:51 +0000299{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200300 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
Paolo Bonzini8869e102011-10-12 12:49:35 +0200301 SCSIDevice *s = r->req.dev;
ths2cc977e2007-12-24 16:11:51 +0000302 int ret;
303
Bernhard Kohlaa2b1e82010-09-01 16:33:21 +0200304 DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
305 r->req.cmd.xfer, cmd[0]);
306
307#ifdef DEBUG_SCSI
308 {
309 int i;
310 for (i = 1; i < r->req.cmd.len; i++) {
311 printf(" 0x%02x", cmd[i]);
312 }
313 printf("\n");
314 }
315#endif
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100316
317 if (r->req.cmd.xfer == 0) {
ths2cc977e2007-12-24 16:11:51 +0000318 if (r->buf != NULL)
Anthony Liguori7267c092011-08-20 22:09:37 -0500319 g_free(r->buf);
ths2cc977e2007-12-24 16:11:51 +0000320 r->buflen = 0;
321 r->buf = NULL;
Paolo Bonzinic9501c92011-10-25 12:53:35 +0200322 /* The request is used as the AIO opaque value, so add a ref. */
323 scsi_req_ref(&r->req);
Paolo Bonzini8869e102011-10-12 12:49:35 +0200324 ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200325 if (ret < 0) {
326 scsi_command_complete(r, ret);
327 return 0;
ths2cc977e2007-12-24 16:11:51 +0000328 }
329 return 0;
330 }
331
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100332 if (r->buflen != r->req.cmd.xfer) {
ths2cc977e2007-12-24 16:11:51 +0000333 if (r->buf != NULL)
Anthony Liguori7267c092011-08-20 22:09:37 -0500334 g_free(r->buf);
335 r->buf = g_malloc(r->req.cmd.xfer);
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100336 r->buflen = r->req.cmd.xfer;
ths2cc977e2007-12-24 16:11:51 +0000337 }
338
339 memset(r->buf, 0, r->buflen);
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100340 r->len = r->req.cmd.xfer;
Gerd Hoffmann97a06432009-11-26 15:33:57 +0100341 if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
ths2cc977e2007-12-24 16:11:51 +0000342 r->len = 0;
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200343 return -r->req.cmd.xfer;
Paolo Bonziniad2d30f2011-04-18 16:01:56 +0200344 } else {
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200345 return r->req.cmd.xfer;
ths2cc977e2007-12-24 16:11:51 +0000346 }
ths2cc977e2007-12-24 16:11:51 +0000347}
348
aurel3289c0f642008-10-17 08:08:56 +0000349static int get_stream_blocksize(BlockDriverState *bdrv)
350{
351 uint8_t cmd[6];
352 uint8_t buf[12];
353 uint8_t sensebuf[8];
354 sg_io_hdr_t io_header;
355 int ret;
356
357 memset(cmd, 0, sizeof(cmd));
358 memset(buf, 0, sizeof(buf));
359 cmd[0] = MODE_SENSE;
360 cmd[4] = sizeof(buf);
361
362 memset(&io_header, 0, sizeof(io_header));
363 io_header.interface_id = 'S';
364 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
365 io_header.dxfer_len = sizeof(buf);
366 io_header.dxferp = buf;
367 io_header.cmdp = cmd;
368 io_header.cmd_len = sizeof(cmd);
369 io_header.mx_sb_len = sizeof(sensebuf);
370 io_header.sbp = sensebuf;
371 io_header.timeout = 6000; /* XXX */
372
aliguori221f7152009-03-28 17:28:41 +0000373 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
Paolo Bonzinife0ed712011-10-12 14:49:48 +0200374 if (ret < 0 || io_header.driver_status || io_header.host_status) {
aurel3289c0f642008-10-17 08:08:56 +0000375 return -1;
Paolo Bonzinife0ed712011-10-12 14:49:48 +0200376 }
aurel3289c0f642008-10-17 08:08:56 +0000377 return (buf[9] << 16) | (buf[10] << 8) | buf[11];
378}
379
Bernhard Kohlf8b6d672010-09-06 16:07:33 +0200380static void scsi_generic_reset(DeviceState *dev)
381{
Anthony Liguorib9eea3e2011-12-15 14:50:08 -0600382 SCSIDevice *s = SCSI_DEVICE(dev);
Bernhard Kohlf8b6d672010-09-06 16:07:33 +0200383
Paolo Bonzini8869e102011-10-12 12:49:35 +0200384 scsi_device_purge_requests(s, SENSE_CODE(RESET));
Bernhard Kohlf8b6d672010-09-06 16:07:33 +0200385}
386
Paolo Bonzini8869e102011-10-12 12:49:35 +0200387static void scsi_destroy(SCSIDevice *s)
Bernhard Kohlf8b6d672010-09-06 16:07:33 +0200388{
Paolo Bonzini8869e102011-10-12 12:49:35 +0200389 scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
390 blockdev_mark_auto_del(s->conf.bs);
ths2cc977e2007-12-24 16:11:51 +0000391}
392
Paolo Bonzini8869e102011-10-12 12:49:35 +0200393static int scsi_generic_initfn(SCSIDevice *s)
ths2cc977e2007-12-24 16:11:51 +0000394{
395 int sg_version;
ths2cc977e2007-12-24 16:11:51 +0000396 struct sg_scsi_id scsiid;
397
Paolo Bonzini8869e102011-10-12 12:49:35 +0200398 if (!s->conf.bs) {
Markus Armbruster6a84cb12011-12-21 11:37:57 +0100399 error_report("drive property not set");
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200400 return -1;
401 }
ths2cc977e2007-12-24 16:11:51 +0000402
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200403 /* check we are really using a /dev/sg* file */
Paolo Bonzini8869e102011-10-12 12:49:35 +0200404 if (!bdrv_is_sg(s->conf.bs)) {
Markus Armbruster6a84cb12011-12-21 11:37:57 +0100405 error_report("not /dev/sg*");
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200406 return -1;
407 }
ths2cc977e2007-12-24 16:11:51 +0000408
Paolo Bonzini8869e102011-10-12 12:49:35 +0200409 if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
Markus Armbruster620f8622010-05-27 20:02:28 +0200410 error_report("Device doesn't support drive option werror");
411 return -1;
412 }
Paolo Bonzini8869e102011-10-12 12:49:35 +0200413 if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
Markus Armbruster620f8622010-05-27 20:02:28 +0200414 error_report("Device doesn't support drive option rerror");
415 return -1;
416 }
417
ths2cc977e2007-12-24 16:11:51 +0000418 /* check we are using a driver managing SG_IO (version 3 and after */
Paolo Bonzini8869e102011-10-12 12:49:35 +0200419 if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200420 sg_version < 30000) {
Markus Armbruster6a84cb12011-12-21 11:37:57 +0100421 error_report("scsi generic interface too old");
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200422 return -1;
423 }
ths2cc977e2007-12-24 16:11:51 +0000424
425 /* get LUN of the /dev/sg? */
Paolo Bonzini8869e102011-10-12 12:49:35 +0200426 if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
Markus Armbruster6a84cb12011-12-21 11:37:57 +0100427 error_report("SG_GET_SCSI_ID ioctl failed");
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200428 return -1;
429 }
ths2cc977e2007-12-24 16:11:51 +0000430
431 /* define device state */
Paolo Bonzini8869e102011-10-12 12:49:35 +0200432 s->type = scsiid.scsi_type;
433 DPRINTF("device type %d\n", s->type);
Paolo Bonzini28b77652011-11-18 16:32:02 +0100434 if (s->type == TYPE_DISK || s->type == TYPE_ROM) {
435 add_boot_device_path(s->conf.bootindex, &s->qdev, NULL);
436 }
437
Paolo Bonzini9b6eef82011-10-13 10:36:27 +0200438 switch (s->type) {
439 case TYPE_TAPE:
Paolo Bonzini8869e102011-10-12 12:49:35 +0200440 s->blocksize = get_stream_blocksize(s->conf.bs);
441 if (s->blocksize == -1) {
442 s->blocksize = 0;
443 }
Paolo Bonzini9b6eef82011-10-13 10:36:27 +0200444 break;
445
446 /* Make a guess for block devices, we'll fix it when the guest sends.
447 * READ CAPACITY. If they don't, they likely would assume these sizes
448 * anyway. (TODO: they could also send MODE SENSE).
449 */
450 case TYPE_ROM:
451 case TYPE_WORM:
452 s->blocksize = 2048;
453 break;
454 default:
455 s->blocksize = 512;
456 break;
aurel3289c0f642008-10-17 08:08:56 +0000457 }
Paolo Bonzini8869e102011-10-12 12:49:35 +0200458
459 DPRINTF("block size %d\n", s->blocksize);
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200460 return 0;
ths2cc977e2007-12-24 16:11:51 +0000461}
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200462
Paolo Bonzini765d1522011-10-12 12:54:31 +0200463const SCSIReqOps scsi_generic_req_ops = {
Paolo Bonzini8dbd4572011-08-03 10:49:08 +0200464 .size = sizeof(SCSIGenericReq),
Paolo Bonzini12010e72011-08-03 10:49:09 +0200465 .free_req = scsi_free_request,
466 .send_command = scsi_send_command,
467 .read_data = scsi_read_data,
468 .write_data = scsi_write_data,
469 .cancel_io = scsi_cancel_io,
470 .get_buf = scsi_get_buf,
Paolo Bonzini56b1fc42011-12-15 07:24:30 -0500471 .load_request = scsi_generic_load_request,
472 .save_request = scsi_generic_save_request,
Paolo Bonzini8dbd4572011-08-03 10:49:08 +0200473};
474
475static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
Paolo Bonzini63db0f02011-10-12 12:58:31 +0200476 uint8_t *buf, void *hba_private)
Paolo Bonzini8dbd4572011-08-03 10:49:08 +0200477{
478 SCSIRequest *req;
479
480 req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
481 return req;
482}
483
Anthony Liguori39bffca2011-12-07 21:34:16 -0600484static Property scsi_generic_properties[] = {
485 DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
486 DEFINE_PROP_END_OF_LIST(),
487};
488
Anthony Liguorib9eea3e2011-12-15 14:50:08 -0600489static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
490{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600491 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguorib9eea3e2011-12-15 14:50:08 -0600492 SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
493
494 sc->init = scsi_generic_initfn;
495 sc->destroy = scsi_destroy;
496 sc->alloc_req = scsi_new_request;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600497 dc->fw_name = "disk";
498 dc->desc = "pass through generic scsi device (/dev/sg*)";
499 dc->reset = scsi_generic_reset;
500 dc->props = scsi_generic_properties;
Paolo Bonzini56b1fc42011-12-15 07:24:30 -0500501 dc->vmsd = &vmstate_scsi_device;
Anthony Liguorib9eea3e2011-12-15 14:50:08 -0600502}
503
Anthony Liguori39bffca2011-12-07 21:34:16 -0600504static TypeInfo scsi_generic_info = {
505 .name = "scsi-generic",
506 .parent = TYPE_SCSI_DEVICE,
507 .instance_size = sizeof(SCSIDevice),
508 .class_init = scsi_generic_class_initfn,
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200509};
510
Andreas Färber83f7d432012-02-09 15:20:55 +0100511static void scsi_generic_register_types(void)
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200512{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600513 type_register_static(&scsi_generic_info);
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200514}
Andreas Färber83f7d432012-02-09 15:20:55 +0100515
516type_init(scsi_generic_register_types)
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200517
ths2cc977e2007-12-24 16:11:51 +0000518#endif /* __linux__ */