]> Git Repo - qemu.git/blob - hw/scsi-generic.c
scsi: pass cdb to alloc_req
[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 <[email protected]>
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 #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
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;
61
62 static void scsi_free_request(SCSIRequest *req)
63 {
64     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
65
66     g_free(r->buf);
67 }
68
69 /* Helper function for command completion.  */
70 static void scsi_command_complete(void *opaque, int ret)
71 {
72     int status;
73     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
74
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;
78     }
79
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;
93         }
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;
110         }
111     }
112     DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
113             r, r->req.tag, status);
114
115     scsi_req_complete(&r->req, status);
116 }
117
118 /* Cancel a pending data transfer.  */
119 static void scsi_cancel_io(SCSIRequest *req)
120 {
121     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
122
123     DPRINTF("Cancel tag=0x%x\n", req->tag);
124     if (r->req.aiocb) {
125         bdrv_aio_cancel(r->req.aiocb);
126     }
127     r->req.aiocb = NULL;
128 }
129
130 static int execute_command(BlockDriverState *bdrv,
131                            SCSIGenericReq *r, int direction,
132                            BlockDriverCompletionFunc *complete)
133 {
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;
145
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;
150     }
151
152     return 0;
153 }
154
155 static void scsi_read_complete(void * opaque, int ret)
156 {
157     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
158     SCSIDevice *s = r->req.dev;
159     int len;
160
161     r->req.aiocb = NULL;
162     if (ret) {
163         DPRINTF("IO error ret %d\n", ret);
164         scsi_command_complete(r, ret);
165         return;
166     }
167     len = r->io_header.dxfer_len - r->io_header.resid;
168     DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
169
170     r->len = -1;
171     if (len == 0) {
172         scsi_command_complete(r, 0);
173     } else {
174         /* Snoop READ CAPACITY output to set the blocksize.  */
175         if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
176             s->blocksize = ldl_be_p(&r->buf[4]);
177             s->max_lba = ldl_be_p(&r->buf[0]);
178         } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
179                    (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
180             s->blocksize = ldl_be_p(&r->buf[8]);
181             s->max_lba = ldq_be_p(&r->buf[0]);
182         }
183         bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
184
185         scsi_req_data(&r->req, len);
186     }
187 }
188
189 /* Read more data from scsi device into buffer.  */
190 static void scsi_read_data(SCSIRequest *req)
191 {
192     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
193     SCSIDevice *s = r->req.dev;
194     int ret;
195
196     DPRINTF("scsi_read_data 0x%x\n", req->tag);
197     if (r->len == -1) {
198         scsi_command_complete(r, 0);
199         return;
200     }
201
202     ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
203     if (ret < 0) {
204         scsi_command_complete(r, ret);
205     }
206 }
207
208 static void scsi_write_complete(void * opaque, int ret)
209 {
210     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
211     SCSIDevice *s = r->req.dev;
212
213     DPRINTF("scsi_write_complete() ret = %d\n", ret);
214     r->req.aiocb = NULL;
215     if (ret) {
216         DPRINTF("IO error\n");
217         scsi_command_complete(r, ret);
218         return;
219     }
220
221     if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
222         s->type == TYPE_TAPE) {
223         s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
224         DPRINTF("block size %d\n", s->blocksize);
225     }
226
227     scsi_command_complete(r, ret);
228 }
229
230 /* Write data to a scsi device.  Returns nonzero on failure.
231    The transfer may complete asynchronously.  */
232 static void scsi_write_data(SCSIRequest *req)
233 {
234     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
235     SCSIDevice *s = r->req.dev;
236     int ret;
237
238     DPRINTF("scsi_write_data 0x%x\n", req->tag);
239     if (r->len == 0) {
240         r->len = r->buflen;
241         scsi_req_data(&r->req, r->len);
242         return;
243     }
244
245     ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
246     if (ret < 0) {
247         scsi_command_complete(r, ret);
248     }
249 }
250
251 /* Return a pointer to the data buffer.  */
252 static uint8_t *scsi_get_buf(SCSIRequest *req)
253 {
254     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
255
256     return r->buf;
257 }
258
259 /* Execute a scsi command.  Returns the length of the data expected by the
260    command.  This will be Positive for data transfers from the device
261    (eg. disk reads), negative for transfers to the device (eg. disk writes),
262    and zero if the command does not transfer any data.  */
263
264 static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
265 {
266     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
267     SCSIDevice *s = r->req.dev;
268     int ret;
269
270     DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
271             r->req.cmd.xfer, cmd[0]);
272
273 #ifdef DEBUG_SCSI
274     {
275         int i;
276         for (i = 1; i < r->req.cmd.len; i++) {
277             printf(" 0x%02x", cmd[i]);
278         }
279         printf("\n");
280     }
281 #endif
282
283     if (r->req.cmd.xfer == 0) {
284         if (r->buf != NULL)
285             g_free(r->buf);
286         r->buflen = 0;
287         r->buf = NULL;
288         ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
289         if (ret < 0) {
290             scsi_command_complete(r, ret);
291             return 0;
292         }
293         return 0;
294     }
295
296     if (r->buflen != r->req.cmd.xfer) {
297         if (r->buf != NULL)
298             g_free(r->buf);
299         r->buf = g_malloc(r->req.cmd.xfer);
300         r->buflen = r->req.cmd.xfer;
301     }
302
303     memset(r->buf, 0, r->buflen);
304     r->len = r->req.cmd.xfer;
305     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
306         r->len = 0;
307         return -r->req.cmd.xfer;
308     } else {
309         return r->req.cmd.xfer;
310     }
311 }
312
313 static int get_stream_blocksize(BlockDriverState *bdrv)
314 {
315     uint8_t cmd[6];
316     uint8_t buf[12];
317     uint8_t sensebuf[8];
318     sg_io_hdr_t io_header;
319     int ret;
320
321     memset(cmd, 0, sizeof(cmd));
322     memset(buf, 0, sizeof(buf));
323     cmd[0] = MODE_SENSE;
324     cmd[4] = sizeof(buf);
325
326     memset(&io_header, 0, sizeof(io_header));
327     io_header.interface_id = 'S';
328     io_header.dxfer_direction = SG_DXFER_FROM_DEV;
329     io_header.dxfer_len = sizeof(buf);
330     io_header.dxferp = buf;
331     io_header.cmdp = cmd;
332     io_header.cmd_len = sizeof(cmd);
333     io_header.mx_sb_len = sizeof(sensebuf);
334     io_header.sbp = sensebuf;
335     io_header.timeout = 6000; /* XXX */
336
337     ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
338     if (ret < 0 || io_header.driver_status || io_header.host_status) {
339         return -1;
340     }
341     return (buf[9] << 16) | (buf[10] << 8) | buf[11];
342 }
343
344 static void scsi_generic_reset(DeviceState *dev)
345 {
346     SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
347
348     scsi_device_purge_requests(s, SENSE_CODE(RESET));
349 }
350
351 static void scsi_destroy(SCSIDevice *s)
352 {
353     scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
354     blockdev_mark_auto_del(s->conf.bs);
355 }
356
357 static int scsi_generic_initfn(SCSIDevice *s)
358 {
359     int sg_version;
360     struct sg_scsi_id scsiid;
361
362     if (!s->conf.bs) {
363         error_report("scsi-generic: drive property not set");
364         return -1;
365     }
366
367     /* check we are really using a /dev/sg* file */
368     if (!bdrv_is_sg(s->conf.bs)) {
369         error_report("scsi-generic: not /dev/sg*");
370         return -1;
371     }
372
373     if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
374         error_report("Device doesn't support drive option werror");
375         return -1;
376     }
377     if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
378         error_report("Device doesn't support drive option rerror");
379         return -1;
380     }
381
382     /* check we are using a driver managing SG_IO (version 3 and after */
383     if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
384         sg_version < 30000) {
385         error_report("scsi-generic: scsi generic interface too old");
386         return -1;
387     }
388
389     /* get LUN of the /dev/sg? */
390     if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
391         error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
392         return -1;
393     }
394
395     /* define device state */
396     s->type = scsiid.scsi_type;
397     DPRINTF("device type %d\n", s->type);
398     switch (s->type) {
399     case TYPE_TAPE:
400         s->blocksize = get_stream_blocksize(s->conf.bs);
401         if (s->blocksize == -1) {
402             s->blocksize = 0;
403         }
404         break;
405
406         /* Make a guess for block devices, we'll fix it when the guest sends.
407          * READ CAPACITY.  If they don't, they likely would assume these sizes
408          * anyway. (TODO: they could also send MODE SENSE).
409          */
410     case TYPE_ROM:
411     case TYPE_WORM:
412         s->blocksize = 2048;
413         break;
414     default:
415         s->blocksize = 512;
416         break;
417     }
418
419     DPRINTF("block size %d\n", s->blocksize);
420     return 0;
421 }
422
423 const SCSIReqOps scsi_generic_req_ops = {
424     .size         = sizeof(SCSIGenericReq),
425     .free_req     = scsi_free_request,
426     .send_command = scsi_send_command,
427     .read_data    = scsi_read_data,
428     .write_data   = scsi_write_data,
429     .cancel_io    = scsi_cancel_io,
430     .get_buf      = scsi_get_buf,
431 };
432
433 static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
434                                      uint8_t *buf, void *hba_private)
435 {
436     SCSIRequest *req;
437
438     req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
439     return req;
440 }
441
442 static SCSIDeviceInfo scsi_generic_info = {
443     .qdev.name    = "scsi-generic",
444     .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
445     .qdev.size    = sizeof(SCSIDevice),
446     .qdev.reset   = scsi_generic_reset,
447     .init         = scsi_generic_initfn,
448     .destroy      = scsi_destroy,
449     .alloc_req    = scsi_new_request,
450     .qdev.props   = (Property[]) {
451         DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
452         DEFINE_PROP_END_OF_LIST(),
453     },
454 };
455
456 static void scsi_generic_register_devices(void)
457 {
458     scsi_qdev_register(&scsi_generic_info);
459 }
460 device_init(scsi_generic_register_devices)
461
462 #endif /* __linux__ */
This page took 0.049054 seconds and 4 git commands to generate.