blob: cb5d4f125d27a86228a637e00b4d82389de49b08 [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
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
Gerd Hoffmannd52affa2009-08-31 14:24:04 +020049typedef struct SCSIGenericState SCSIGenericState;
50
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010051typedef struct SCSIGenericReq {
52 SCSIRequest req;
ths2cc977e2007-12-24 16:11:51 +000053 uint8_t *buf;
54 int buflen;
55 int len;
56 sg_io_hdr_t io_header;
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010057} SCSIGenericReq;
ths2cc977e2007-12-24 16:11:51 +000058
Gerd Hoffmannd52affa2009-08-31 14:24:04 +020059struct SCSIGenericState
ths2cc977e2007-12-24 16:11:51 +000060{
Gerd Hoffmannd52affa2009-08-31 14:24:04 +020061 SCSIDevice qdev;
Christoph Hellwig428c1492010-02-10 23:37:09 +010062 BlockDriverState *bs;
ths2cc977e2007-12-24 16:11:51 +000063};
64
Paolo Bonziniad2d30f2011-04-18 16:01:56 +020065static void scsi_free_request(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +000066{
Paolo Bonziniad2d30f2011-04-18 16:01:56 +020067 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
68
Anthony Liguori7267c092011-08-20 22:09:37 -050069 g_free(r->buf);
ths2cc977e2007-12-24 16:11:51 +000070}
71
ths2cc977e2007-12-24 16:11:51 +000072/* Helper function for command completion. */
73static void scsi_command_complete(void *opaque, int ret)
74{
Paolo Bonzini682a9b22011-08-03 10:49:06 +020075 int status;
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010076 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
ths2cc977e2007-12-24 16:11:51 +000077
Paolo Bonzinid33e0ce2011-05-25 16:53:46 +020078 r->req.aiocb = NULL;
Paolo Bonzinib45ef672011-08-03 10:49:07 +020079 if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE)
80 r->req.sense_len = r->io_header.sb_len_wr;
aurel3289c0f642008-10-17 08:08:56 +000081
Hannes Reineckea1f0cce2011-04-18 12:53:14 +020082 if (ret != 0) {
83 switch (ret) {
Paolo Bonzini2e7cc4d2011-04-18 14:29:16 +020084 case -EDOM:
Paolo Bonzini682a9b22011-08-03 10:49:06 +020085 status = TASK_SET_FULL;
Paolo Bonzini2e7cc4d2011-04-18 14:29:16 +020086 break;
Hannes Reineckea1f0cce2011-04-18 12:53:14 +020087 case -ENOMEM:
Paolo Bonzini682a9b22011-08-03 10:49:06 +020088 status = CHECK_CONDITION;
Paolo Bonzinib45ef672011-08-03 10:49:07 +020089 scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
Hannes Reineckea1f0cce2011-04-18 12:53:14 +020090 break;
91 default:
Paolo Bonzini682a9b22011-08-03 10:49:06 +020092 status = CHECK_CONDITION;
Paolo Bonzinib45ef672011-08-03 10:49:07 +020093 scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
Hannes Reineckea1f0cce2011-04-18 12:53:14 +020094 break;
95 }
96 } else {
Paolo Bonzinib45ef672011-08-03 10:49:07 +020097 if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
Paolo Bonzini682a9b22011-08-03 10:49:06 +020098 status = BUSY;
ths2cc977e2007-12-24 16:11:51 +000099 BADF("Driver Timeout\n");
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200100 } else if (r->io_header.status) {
101 status = r->io_header.status;
Paolo Bonzinib45ef672011-08-03 10:49:07 +0200102 } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200103 status = CHECK_CONDITION;
104 } else {
105 status = GOOD;
106 }
ths2cc977e2007-12-24 16:11:51 +0000107 }
aurel3289c0f642008-10-17 08:08:56 +0000108 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200109 r, r->req.tag, status);
Gerd Hoffmanned3a34a2009-11-26 15:34:00 +0100110
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200111 scsi_req_complete(&r->req, status);
ths2cc977e2007-12-24 16:11:51 +0000112}
113
114/* Cancel a pending data transfer. */
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200115static void scsi_cancel_io(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +0000116{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200117 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
118
119 DPRINTF("Cancel tag=0x%x\n", req->tag);
120 if (r->req.aiocb) {
121 bdrv_aio_cancel(r->req.aiocb);
ths2cc977e2007-12-24 16:11:51 +0000122 }
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200123 r->req.aiocb = NULL;
ths2cc977e2007-12-24 16:11:51 +0000124}
125
126static int execute_command(BlockDriverState *bdrv,
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100127 SCSIGenericReq *r, int direction,
ths2cc977e2007-12-24 16:11:51 +0000128 BlockDriverCompletionFunc *complete)
129{
ths2cc977e2007-12-24 16:11:51 +0000130 r->io_header.interface_id = 'S';
131 r->io_header.dxfer_direction = direction;
132 r->io_header.dxferp = r->buf;
133 r->io_header.dxfer_len = r->buflen;
Gerd Hoffmann29362eb2009-11-26 15:33:51 +0100134 r->io_header.cmdp = r->req.cmd.buf;
135 r->io_header.cmd_len = r->req.cmd.len;
Paolo Bonzinib45ef672011-08-03 10:49:07 +0200136 r->io_header.mx_sb_len = sizeof(r->req.sense);
137 r->io_header.sbp = r->req.sense;
ths2cc977e2007-12-24 16:11:51 +0000138 r->io_header.timeout = MAX_UINT;
139 r->io_header.usr_ptr = r;
140 r->io_header.flags |= SG_FLAG_DIRECT_IO;
141
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100142 r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
143 if (r->req.aiocb == NULL) {
ths2cc977e2007-12-24 16:11:51 +0000144 BADF("execute_command: read failed !\n");
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200145 return -ENOMEM;
ths2cc977e2007-12-24 16:11:51 +0000146 }
147
148 return 0;
149}
150
151static void scsi_read_complete(void * opaque, int ret)
152{
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100153 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
ths2cc977e2007-12-24 16:11:51 +0000154 int len;
155
Paolo Bonzinid33e0ce2011-05-25 16:53:46 +0200156 r->req.aiocb = NULL;
ths2cc977e2007-12-24 16:11:51 +0000157 if (ret) {
Bernhard Kohlaa2b1e82010-09-01 16:33:21 +0200158 DPRINTF("IO error ret %d\n", ret);
ths2cc977e2007-12-24 16:11:51 +0000159 scsi_command_complete(r, ret);
160 return;
161 }
162 len = r->io_header.dxfer_len - r->io_header.resid;
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100163 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
ths2cc977e2007-12-24 16:11:51 +0000164
165 r->len = -1;
Paolo Bonzini40f16dd2011-05-03 14:15:59 +0200166 if (len == 0) {
aurel3289c0f642008-10-17 08:08:56 +0000167 scsi_command_complete(r, 0);
Paolo Bonzini40f16dd2011-05-03 14:15:59 +0200168 } else {
Paolo Bonziniab9adc82011-04-18 14:59:13 +0200169 scsi_req_data(&r->req, len);
Paolo Bonzini40f16dd2011-05-03 14:15:59 +0200170 }
ths2cc977e2007-12-24 16:11:51 +0000171}
172
173/* Read more data from scsi device into buffer. */
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200174static void scsi_read_data(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +0000175{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200176 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
177 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
ths2cc977e2007-12-24 16:11:51 +0000178 int ret;
179
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200180 DPRINTF("scsi_read_data 0x%x\n", req->tag);
ths2cc977e2007-12-24 16:11:51 +0000181 if (r->len == -1) {
182 scsi_command_complete(r, 0);
183 return;
184 }
185
Christoph Hellwig428c1492010-02-10 23:37:09 +0100186 ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200187 if (ret < 0) {
188 scsi_command_complete(r, ret);
ths2cc977e2007-12-24 16:11:51 +0000189 return;
190 }
191}
192
193static void scsi_write_complete(void * opaque, int ret)
194{
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +0100195 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
196 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
ths2cc977e2007-12-24 16:11:51 +0000197
198 DPRINTF("scsi_write_complete() ret = %d\n", ret);
Paolo Bonzinid33e0ce2011-05-25 16:53:46 +0200199 r->req.aiocb = NULL;
ths2cc977e2007-12-24 16:11:51 +0000200 if (ret) {
201 DPRINTF("IO error\n");
202 scsi_command_complete(r, ret);
203 return;
204 }
205
Gerd Hoffmann29362eb2009-11-26 15:33:51 +0100206 if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
Gerd Hoffmann91376652009-11-26 15:33:54 +0100207 s->qdev.type == TYPE_TAPE) {
Gerd Hoffmannb07995e2009-11-26 15:33:52 +0100208 s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
Bernhard Kohlaa2b1e82010-09-01 16:33:21 +0200209 DPRINTF("block size %d\n", s->qdev.blocksize);
aurel3289c0f642008-10-17 08:08:56 +0000210 }
211
ths2cc977e2007-12-24 16:11:51 +0000212 scsi_command_complete(r, ret);
213}
214
215/* Write data to a scsi device. Returns nonzero on failure.
216 The transfer may complete asynchronously. */
Paolo Bonzini42741212011-04-22 09:39:16 +0200217static void scsi_write_data(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +0000218{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200219 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
220 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
ths2cc977e2007-12-24 16:11:51 +0000221 int ret;
222
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200223 DPRINTF("scsi_write_data 0x%x\n", req->tag);
ths2cc977e2007-12-24 16:11:51 +0000224 if (r->len == 0) {
225 r->len = r->buflen;
Paolo Bonziniab9adc82011-04-18 14:59:13 +0200226 scsi_req_data(&r->req, r->len);
Paolo Bonzini42741212011-04-22 09:39:16 +0200227 return;
ths2cc977e2007-12-24 16:11:51 +0000228 }
229
Christoph Hellwig428c1492010-02-10 23:37:09 +0100230 ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200231 if (ret < 0) {
232 scsi_command_complete(r, ret);
ths2cc977e2007-12-24 16:11:51 +0000233 }
ths2cc977e2007-12-24 16:11:51 +0000234}
235
236/* Return a pointer to the data buffer. */
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200237static uint8_t *scsi_get_buf(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +0000238{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200239 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
240
ths2cc977e2007-12-24 16:11:51 +0000241 return r->buf;
242}
243
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100244static void scsi_req_fixup(SCSIRequest *req)
ths2cc977e2007-12-24 16:11:51 +0000245{
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100246 switch(req->cmd.buf[0]) {
ths2cc977e2007-12-24 16:11:51 +0000247 case WRITE_10:
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100248 req->cmd.buf[1] &= ~0x08; /* disable FUA */
ths2cc977e2007-12-24 16:11:51 +0000249 break;
250 case READ_10:
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100251 req->cmd.buf[1] &= ~0x08; /* disable FUA */
aliguoria9dd6842008-09-23 13:38:44 +0000252 break;
253 case REWIND:
254 case START_STOP:
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100255 if (req->dev->type == TYPE_TAPE) {
256 /* force IMMED, otherwise qemu waits end of command */
257 req->cmd.buf[1] = 0x01;
258 }
aliguoria9dd6842008-09-23 13:38:44 +0000259 break;
aliguoria9dd6842008-09-23 13:38:44 +0000260 }
aliguoria9dd6842008-09-23 13:38:44 +0000261}
262
ths2cc977e2007-12-24 16:11:51 +0000263/* Execute a scsi command. Returns the length of the data expected by the
264 command. This will be Positive for data transfers from the device
265 (eg. disk reads), negative for transfers to the device (eg. disk writes),
266 and zero if the command does not transfer any data. */
267
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200268static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
ths2cc977e2007-12-24 16:11:51 +0000269{
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200270 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
271 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
ths2cc977e2007-12-24 16:11:51 +0000272 int ret;
273
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100274 scsi_req_fixup(&r->req);
ths2cc977e2007-12-24 16:11:51 +0000275
Bernhard Kohlaa2b1e82010-09-01 16:33:21 +0200276 DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
277 r->req.cmd.xfer, cmd[0]);
278
279#ifdef DEBUG_SCSI
280 {
281 int i;
282 for (i = 1; i < r->req.cmd.len; i++) {
283 printf(" 0x%02x", cmd[i]);
284 }
285 printf("\n");
286 }
287#endif
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100288
289 if (r->req.cmd.xfer == 0) {
ths2cc977e2007-12-24 16:11:51 +0000290 if (r->buf != NULL)
Anthony Liguori7267c092011-08-20 22:09:37 -0500291 g_free(r->buf);
ths2cc977e2007-12-24 16:11:51 +0000292 r->buflen = 0;
293 r->buf = NULL;
Christoph Hellwig428c1492010-02-10 23:37:09 +0100294 ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200295 if (ret < 0) {
296 scsi_command_complete(r, ret);
297 return 0;
ths2cc977e2007-12-24 16:11:51 +0000298 }
299 return 0;
300 }
301
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100302 if (r->buflen != r->req.cmd.xfer) {
ths2cc977e2007-12-24 16:11:51 +0000303 if (r->buf != NULL)
Anthony Liguori7267c092011-08-20 22:09:37 -0500304 g_free(r->buf);
305 r->buf = g_malloc(r->req.cmd.xfer);
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100306 r->buflen = r->req.cmd.xfer;
ths2cc977e2007-12-24 16:11:51 +0000307 }
308
309 memset(r->buf, 0, r->buflen);
Gerd Hoffmann2ec749c2009-11-26 15:33:55 +0100310 r->len = r->req.cmd.xfer;
Gerd Hoffmann97a06432009-11-26 15:33:57 +0100311 if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
ths2cc977e2007-12-24 16:11:51 +0000312 r->len = 0;
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200313 return -r->req.cmd.xfer;
Paolo Bonziniad2d30f2011-04-18 16:01:56 +0200314 } else {
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200315 return r->req.cmd.xfer;
ths2cc977e2007-12-24 16:11:51 +0000316 }
ths2cc977e2007-12-24 16:11:51 +0000317}
318
319static int get_blocksize(BlockDriverState *bdrv)
320{
321 uint8_t cmd[10];
322 uint8_t buf[8];
323 uint8_t sensebuf[8];
324 sg_io_hdr_t io_header;
325 int ret;
326
aliguori4f26a482008-09-22 15:27:54 +0000327 memset(cmd, 0, sizeof(cmd));
328 memset(buf, 0, sizeof(buf));
Hannes Reinecke5e30a072011-07-22 16:51:15 +0200329 cmd[0] = READ_CAPACITY_10;
ths2cc977e2007-12-24 16:11:51 +0000330
331 memset(&io_header, 0, sizeof(io_header));
332 io_header.interface_id = 'S';
333 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
334 io_header.dxfer_len = sizeof(buf);
335 io_header.dxferp = buf;
336 io_header.cmdp = cmd;
337 io_header.cmd_len = sizeof(cmd);
338 io_header.mx_sb_len = sizeof(sensebuf);
339 io_header.sbp = sensebuf;
340 io_header.timeout = 6000; /* XXX */
341
aliguori221f7152009-03-28 17:28:41 +0000342 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
aliguori7d780662009-03-12 19:57:08 +0000343 if (ret < 0)
ths2cc977e2007-12-24 16:11:51 +0000344 return -1;
345
346 return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
347}
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);
aliguori7d780662009-03-12 19:57:08 +0000374 if (ret < 0)
aurel3289c0f642008-10-17 08:08:56 +0000375 return -1;
376
377 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{
382 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
383
Paolo Bonzinic7b48872011-08-03 10:49:18 +0200384 scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
Bernhard Kohlf8b6d672010-09-06 16:07:33 +0200385}
386
387static void scsi_destroy(SCSIDevice *d)
388{
389 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
390
Paolo Bonzinic7b48872011-08-03 10:49:18 +0200391 scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
Markus Armbrusterf8b6cc02010-05-05 16:36:52 +0200392 blockdev_mark_auto_del(s->qdev.conf.bs);
ths2cc977e2007-12-24 16:11:51 +0000393}
394
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200395static int scsi_generic_initfn(SCSIDevice *dev)
ths2cc977e2007-12-24 16:11:51 +0000396{
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200397 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
ths2cc977e2007-12-24 16:11:51 +0000398 int sg_version;
ths2cc977e2007-12-24 16:11:51 +0000399 struct sg_scsi_id scsiid;
400
Markus Armbrusterf8b6cc02010-05-05 16:36:52 +0200401 if (!s->qdev.conf.bs) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100402 error_report("scsi-generic: drive property not set");
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200403 return -1;
404 }
Markus Armbrusterf8b6cc02010-05-05 16:36:52 +0200405 s->bs = s->qdev.conf.bs;
ths2cc977e2007-12-24 16:11:51 +0000406
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200407 /* check we are really using a /dev/sg* file */
Christoph Hellwig428c1492010-02-10 23:37:09 +0100408 if (!bdrv_is_sg(s->bs)) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100409 error_report("scsi-generic: not /dev/sg*");
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200410 return -1;
411 }
ths2cc977e2007-12-24 16:11:51 +0000412
Markus Armbruster620f8622010-05-27 20:02:28 +0200413 if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
414 error_report("Device doesn't support drive option werror");
415 return -1;
416 }
417 if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
418 error_report("Device doesn't support drive option rerror");
419 return -1;
420 }
421
ths2cc977e2007-12-24 16:11:51 +0000422 /* check we are using a driver managing SG_IO (version 3 and after */
Christoph Hellwig428c1492010-02-10 23:37:09 +0100423 if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200424 sg_version < 30000) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100425 error_report("scsi-generic: scsi generic interface too old");
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200426 return -1;
427 }
ths2cc977e2007-12-24 16:11:51 +0000428
429 /* get LUN of the /dev/sg? */
Christoph Hellwig428c1492010-02-10 23:37:09 +0100430 if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100431 error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200432 return -1;
433 }
ths2cc977e2007-12-24 16:11:51 +0000434
435 /* define device state */
Gerd Hoffmann91376652009-11-26 15:33:54 +0100436 s->qdev.type = scsiid.scsi_type;
437 DPRINTF("device type %d\n", s->qdev.type);
438 if (s->qdev.type == TYPE_TAPE) {
Christoph Hellwig428c1492010-02-10 23:37:09 +0100439 s->qdev.blocksize = get_stream_blocksize(s->bs);
Gerd Hoffmannb07995e2009-11-26 15:33:52 +0100440 if (s->qdev.blocksize == -1)
441 s->qdev.blocksize = 0;
aurel3289c0f642008-10-17 08:08:56 +0000442 } else {
Christoph Hellwig428c1492010-02-10 23:37:09 +0100443 s->qdev.blocksize = get_blocksize(s->bs);
aurel3289c0f642008-10-17 08:08:56 +0000444 /* removable media returns 0 if not present */
Gerd Hoffmannb07995e2009-11-26 15:33:52 +0100445 if (s->qdev.blocksize <= 0) {
Gerd Hoffmann91376652009-11-26 15:33:54 +0100446 if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM)
Gerd Hoffmannb07995e2009-11-26 15:33:52 +0100447 s->qdev.blocksize = 2048;
aurel3289c0f642008-10-17 08:08:56 +0000448 else
Gerd Hoffmannb07995e2009-11-26 15:33:52 +0100449 s->qdev.blocksize = 512;
aurel3289c0f642008-10-17 08:08:56 +0000450 }
451 }
Gerd Hoffmannb07995e2009-11-26 15:33:52 +0100452 DPRINTF("block size %d\n", s->qdev.blocksize);
Markus Armbruster7d0d6952010-06-25 13:42:14 +0200453 bdrv_set_removable(s->bs, 0);
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200454 return 0;
ths2cc977e2007-12-24 16:11:51 +0000455}
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200456
Paolo Bonzini8dbd4572011-08-03 10:49:08 +0200457static SCSIReqOps scsi_generic_req_ops = {
458 .size = sizeof(SCSIGenericReq),
Paolo Bonzini12010e72011-08-03 10:49:09 +0200459 .free_req = scsi_free_request,
460 .send_command = scsi_send_command,
461 .read_data = scsi_read_data,
462 .write_data = scsi_write_data,
463 .cancel_io = scsi_cancel_io,
464 .get_buf = scsi_get_buf,
Paolo Bonzini8dbd4572011-08-03 10:49:08 +0200465};
466
467static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
468 void *hba_private)
469{
470 SCSIRequest *req;
471
472 req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
473 return req;
474}
475
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200476static SCSIDeviceInfo scsi_generic_info = {
477 .qdev.name = "scsi-generic",
478 .qdev.desc = "pass through generic scsi device (/dev/sg*)",
479 .qdev.size = sizeof(SCSIGenericState),
Bernhard Kohlf8b6d672010-09-06 16:07:33 +0200480 .qdev.reset = scsi_generic_reset,
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200481 .init = scsi_generic_initfn,
482 .destroy = scsi_destroy,
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +0200483 .alloc_req = scsi_new_request,
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200484 .qdev.props = (Property[]) {
Christoph Hellwig428c1492010-02-10 23:37:09 +0100485 DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
Gerd Hoffmannd52affa2009-08-31 14:24:04 +0200486 DEFINE_PROP_END_OF_LIST(),
487 },
488};
489
490static void scsi_generic_register_devices(void)
491{
492 scsi_qdev_register(&scsi_generic_info);
493}
494device_init(scsi_generic_register_devices)
495
ths2cc977e2007-12-24 16:11:51 +0000496#endif /* __linux__ */