xref: /qemu/hw/scsi/scsi-generic.c (revision 2343be0d)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * Generic SCSI Device support
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2007 Bull S.A.S.
549ab747fSPaolo Bonzini  * Based on code by Paul Brook
649ab747fSPaolo Bonzini  * Based on code by Fabrice Bellard
749ab747fSPaolo Bonzini  *
849ab747fSPaolo Bonzini  * Written by Laurent Vivier <Laurent.Vivier@bull.net>
949ab747fSPaolo Bonzini  *
1049ab747fSPaolo Bonzini  * This code is licensed under the LGPL.
1149ab747fSPaolo Bonzini  *
1249ab747fSPaolo Bonzini  */
1349ab747fSPaolo Bonzini 
14a4ab4792SPeter Maydell #include "qemu/osdep.h"
15da34e65cSMarkus Armbruster #include "qapi/error.h"
1649ab747fSPaolo Bonzini #include "qemu-common.h"
1749ab747fSPaolo Bonzini #include "qemu/error-report.h"
1849ab747fSPaolo Bonzini #include "hw/scsi/scsi.h"
194be74634SMarkus Armbruster #include "sysemu/block-backend.h"
2049ab747fSPaolo Bonzini #include "sysemu/blockdev.h"
2149ab747fSPaolo Bonzini 
2249ab747fSPaolo Bonzini #ifdef __linux__
2349ab747fSPaolo Bonzini 
2449ab747fSPaolo Bonzini //#define DEBUG_SCSI
2549ab747fSPaolo Bonzini 
2649ab747fSPaolo Bonzini #ifdef DEBUG_SCSI
2749ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) \
2849ab747fSPaolo Bonzini do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
2949ab747fSPaolo Bonzini #else
3049ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) do {} while(0)
3149ab747fSPaolo Bonzini #endif
3249ab747fSPaolo Bonzini 
3349ab747fSPaolo Bonzini #define BADF(fmt, ...) \
3449ab747fSPaolo Bonzini do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
3549ab747fSPaolo Bonzini 
3649ab747fSPaolo Bonzini #include <scsi/sg.h>
3708e2c9f1SPaolo Bonzini #include "scsi/constants.h"
3849ab747fSPaolo Bonzini 
3949ab747fSPaolo Bonzini #ifndef MAX_UINT
4049ab747fSPaolo Bonzini #define MAX_UINT ((unsigned int)-1)
4149ab747fSPaolo Bonzini #endif
4249ab747fSPaolo Bonzini 
4349ab747fSPaolo Bonzini typedef struct SCSIGenericReq {
4449ab747fSPaolo Bonzini     SCSIRequest req;
4549ab747fSPaolo Bonzini     uint8_t *buf;
4649ab747fSPaolo Bonzini     int buflen;
4749ab747fSPaolo Bonzini     int len;
4849ab747fSPaolo Bonzini     sg_io_hdr_t io_header;
4949ab747fSPaolo Bonzini } SCSIGenericReq;
5049ab747fSPaolo Bonzini 
5149ab747fSPaolo Bonzini static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
5249ab747fSPaolo Bonzini {
5349ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
5449ab747fSPaolo Bonzini 
5549ab747fSPaolo Bonzini     qemu_put_sbe32s(f, &r->buflen);
5649ab747fSPaolo Bonzini     if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
5749ab747fSPaolo Bonzini         assert(!r->req.sg);
5849ab747fSPaolo Bonzini         qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
5949ab747fSPaolo Bonzini     }
6049ab747fSPaolo Bonzini }
6149ab747fSPaolo Bonzini 
6249ab747fSPaolo Bonzini static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
6349ab747fSPaolo Bonzini {
6449ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
6549ab747fSPaolo Bonzini 
6649ab747fSPaolo Bonzini     qemu_get_sbe32s(f, &r->buflen);
6749ab747fSPaolo Bonzini     if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
6849ab747fSPaolo Bonzini         assert(!r->req.sg);
6949ab747fSPaolo Bonzini         qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
7049ab747fSPaolo Bonzini     }
7149ab747fSPaolo Bonzini }
7249ab747fSPaolo Bonzini 
7349ab747fSPaolo Bonzini static void scsi_free_request(SCSIRequest *req)
7449ab747fSPaolo Bonzini {
7549ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
7649ab747fSPaolo Bonzini 
7749ab747fSPaolo Bonzini     g_free(r->buf);
7849ab747fSPaolo Bonzini }
7949ab747fSPaolo Bonzini 
8049ab747fSPaolo Bonzini /* Helper function for command completion.  */
81fa0d653bSPaolo Bonzini static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
8249ab747fSPaolo Bonzini {
8349ab747fSPaolo Bonzini     int status;
841ead6b4eSPaolo Bonzini     SCSISense sense;
8549ab747fSPaolo Bonzini 
86fa0d653bSPaolo Bonzini     assert(r->req.aiocb == NULL);
87fa0d653bSPaolo Bonzini 
886c25fa6cSFam Zheng     if (r->req.io_canceled) {
89d5776465SFam Zheng         scsi_req_cancel_complete(&r->req);
906c25fa6cSFam Zheng         goto done;
916c25fa6cSFam Zheng     }
921ead6b4eSPaolo Bonzini     status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
931ead6b4eSPaolo Bonzini     if (status == CHECK_CONDITION) {
9449ab747fSPaolo Bonzini         if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
9549ab747fSPaolo Bonzini             r->req.sense_len = r->io_header.sb_len_wr;
961ead6b4eSPaolo Bonzini         } else {
971ead6b4eSPaolo Bonzini             scsi_req_build_sense(&r->req, sense);
981ead6b4eSPaolo Bonzini         }
9949ab747fSPaolo Bonzini     }
10049ab747fSPaolo Bonzini 
10149ab747fSPaolo Bonzini     DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
10249ab747fSPaolo Bonzini             r, r->req.tag, status);
10349ab747fSPaolo Bonzini 
10449ab747fSPaolo Bonzini     scsi_req_complete(&r->req, status);
1056c25fa6cSFam Zheng done:
10649ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
10749ab747fSPaolo Bonzini }
10849ab747fSPaolo Bonzini 
109fa0d653bSPaolo Bonzini static void scsi_command_complete(void *opaque, int ret)
110fa0d653bSPaolo Bonzini {
111fa0d653bSPaolo Bonzini     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
112b9e413ddSPaolo Bonzini     SCSIDevice *s = r->req.dev;
113fa0d653bSPaolo Bonzini 
114fa0d653bSPaolo Bonzini     assert(r->req.aiocb != NULL);
115fa0d653bSPaolo Bonzini     r->req.aiocb = NULL;
116b9e413ddSPaolo Bonzini 
117b9e413ddSPaolo Bonzini     aio_context_acquire(blk_get_aio_context(s->conf.blk));
118fa0d653bSPaolo Bonzini     scsi_command_complete_noio(r, ret);
119b9e413ddSPaolo Bonzini     aio_context_release(blk_get_aio_context(s->conf.blk));
120fa0d653bSPaolo Bonzini }
121fa0d653bSPaolo Bonzini 
1224be74634SMarkus Armbruster static int execute_command(BlockBackend *blk,
12349ab747fSPaolo Bonzini                            SCSIGenericReq *r, int direction,
124097310b5SMarkus Armbruster                            BlockCompletionFunc *complete)
12549ab747fSPaolo Bonzini {
12649ab747fSPaolo Bonzini     r->io_header.interface_id = 'S';
12749ab747fSPaolo Bonzini     r->io_header.dxfer_direction = direction;
12849ab747fSPaolo Bonzini     r->io_header.dxferp = r->buf;
12949ab747fSPaolo Bonzini     r->io_header.dxfer_len = r->buflen;
13049ab747fSPaolo Bonzini     r->io_header.cmdp = r->req.cmd.buf;
13149ab747fSPaolo Bonzini     r->io_header.cmd_len = r->req.cmd.len;
13249ab747fSPaolo Bonzini     r->io_header.mx_sb_len = sizeof(r->req.sense);
13349ab747fSPaolo Bonzini     r->io_header.sbp = r->req.sense;
13449ab747fSPaolo Bonzini     r->io_header.timeout = MAX_UINT;
13549ab747fSPaolo Bonzini     r->io_header.usr_ptr = r;
13649ab747fSPaolo Bonzini     r->io_header.flags |= SG_FLAG_DIRECT_IO;
13749ab747fSPaolo Bonzini 
1384be74634SMarkus Armbruster     r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r);
139d836f8d3SPavel Hrdina     if (r->req.aiocb == NULL) {
140d836f8d3SPavel Hrdina         return -EIO;
141d836f8d3SPavel Hrdina     }
14249ab747fSPaolo Bonzini 
14349ab747fSPaolo Bonzini     return 0;
14449ab747fSPaolo Bonzini }
14549ab747fSPaolo Bonzini 
14649ab747fSPaolo Bonzini static void scsi_read_complete(void * opaque, int ret)
14749ab747fSPaolo Bonzini {
14849ab747fSPaolo Bonzini     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
14949ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
15049ab747fSPaolo Bonzini     int len;
15149ab747fSPaolo Bonzini 
152fa0d653bSPaolo Bonzini     assert(r->req.aiocb != NULL);
15349ab747fSPaolo Bonzini     r->req.aiocb = NULL;
154fa0d653bSPaolo Bonzini 
155b9e413ddSPaolo Bonzini     aio_context_acquire(blk_get_aio_context(s->conf.blk));
156b9e413ddSPaolo Bonzini 
1576c25fa6cSFam Zheng     if (ret || r->req.io_canceled) {
158fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
159b9e413ddSPaolo Bonzini         goto done;
16049ab747fSPaolo Bonzini     }
161fa0d653bSPaolo Bonzini 
16249ab747fSPaolo Bonzini     len = r->io_header.dxfer_len - r->io_header.resid;
16349ab747fSPaolo Bonzini     DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
16449ab747fSPaolo Bonzini 
16549ab747fSPaolo Bonzini     r->len = -1;
16649ab747fSPaolo Bonzini     if (len == 0) {
167fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, 0);
168b9e413ddSPaolo Bonzini         goto done;
169fa0d653bSPaolo Bonzini     }
170fa0d653bSPaolo Bonzini 
17149ab747fSPaolo Bonzini     /* Snoop READ CAPACITY output to set the blocksize.  */
17253254e56SPaolo Bonzini     if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
17353254e56SPaolo Bonzini         (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
17449ab747fSPaolo Bonzini         s->blocksize = ldl_be_p(&r->buf[4]);
17553254e56SPaolo Bonzini         s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
17649ab747fSPaolo Bonzini     } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
17749ab747fSPaolo Bonzini                (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
17849ab747fSPaolo Bonzini         s->blocksize = ldl_be_p(&r->buf[8]);
17949ab747fSPaolo Bonzini         s->max_lba = ldq_be_p(&r->buf[0]);
18049ab747fSPaolo Bonzini     }
1814be74634SMarkus Armbruster     blk_set_guest_block_size(s->conf.blk, s->blocksize);
18249ab747fSPaolo Bonzini 
1830eb2baebSPaolo Bonzini     /* Patch MODE SENSE device specific parameters if the BDS is opened
1840eb2baebSPaolo Bonzini      * readonly.
1850eb2baebSPaolo Bonzini      */
1860eb2baebSPaolo Bonzini     if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) &&
1870eb2baebSPaolo Bonzini         blk_is_read_only(s->conf.blk) &&
1880eb2baebSPaolo Bonzini         (r->req.cmd.buf[0] == MODE_SENSE ||
1890eb2baebSPaolo Bonzini          r->req.cmd.buf[0] == MODE_SENSE_10) &&
1900eb2baebSPaolo Bonzini         (r->req.cmd.buf[1] & 0x8) == 0) {
1910eb2baebSPaolo Bonzini         if (r->req.cmd.buf[0] == MODE_SENSE) {
1920eb2baebSPaolo Bonzini             r->buf[2] |= 0x80;
1930eb2baebSPaolo Bonzini         } else  {
1940eb2baebSPaolo Bonzini             r->buf[3] |= 0x80;
1950eb2baebSPaolo Bonzini         }
1960eb2baebSPaolo Bonzini     }
197063143d5SFam Zheng     if (s->type == TYPE_DISK &&
198063143d5SFam Zheng         r->req.cmd.buf[0] == INQUIRY &&
199063143d5SFam Zheng         r->req.cmd.buf[2] == 0xb0) {
2005def6b80SEric Blake         uint32_t max_transfer =
2015def6b80SEric Blake             blk_get_max_transfer(s->conf.blk) / s->blocksize;
20224ce9a20SEric Blake 
2035def6b80SEric Blake         assert(max_transfer);
2045def6b80SEric Blake         stl_be_p(&r->buf[8], max_transfer);
205063143d5SFam Zheng         /* Also take care of the opt xfer len. */
206bed58b44SFam Zheng         stl_be_p(&r->buf[12],
207bed58b44SFam Zheng                  MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
208063143d5SFam Zheng     }
20949ab747fSPaolo Bonzini     scsi_req_data(&r->req, len);
21049ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
211b9e413ddSPaolo Bonzini 
212b9e413ddSPaolo Bonzini done:
213b9e413ddSPaolo Bonzini     aio_context_release(blk_get_aio_context(s->conf.blk));
21449ab747fSPaolo Bonzini }
21549ab747fSPaolo Bonzini 
21649ab747fSPaolo Bonzini /* Read more data from scsi device into buffer.  */
21749ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req)
21849ab747fSPaolo Bonzini {
21949ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
22049ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
22149ab747fSPaolo Bonzini     int ret;
22249ab747fSPaolo Bonzini 
2232e144aa7SEric Farman     DPRINTF("scsi_read_data tag=0x%x\n", req->tag);
22449ab747fSPaolo Bonzini 
22549ab747fSPaolo Bonzini     /* The request is used as the AIO opaque value, so add a ref.  */
22649ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
22749ab747fSPaolo Bonzini     if (r->len == -1) {
228fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, 0);
22949ab747fSPaolo Bonzini         return;
23049ab747fSPaolo Bonzini     }
23149ab747fSPaolo Bonzini 
2324be74634SMarkus Armbruster     ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV,
2334be74634SMarkus Armbruster                           scsi_read_complete);
23449ab747fSPaolo Bonzini     if (ret < 0) {
235fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
23649ab747fSPaolo Bonzini     }
23749ab747fSPaolo Bonzini }
23849ab747fSPaolo Bonzini 
23949ab747fSPaolo Bonzini static void scsi_write_complete(void * opaque, int ret)
24049ab747fSPaolo Bonzini {
24149ab747fSPaolo Bonzini     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
24249ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
24349ab747fSPaolo Bonzini 
24449ab747fSPaolo Bonzini     DPRINTF("scsi_write_complete() ret = %d\n", ret);
245fa0d653bSPaolo Bonzini 
246fa0d653bSPaolo Bonzini     assert(r->req.aiocb != NULL);
24749ab747fSPaolo Bonzini     r->req.aiocb = NULL;
248fa0d653bSPaolo Bonzini 
249b9e413ddSPaolo Bonzini     aio_context_acquire(blk_get_aio_context(s->conf.blk));
250b9e413ddSPaolo Bonzini 
2516c25fa6cSFam Zheng     if (ret || r->req.io_canceled) {
252fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
253b9e413ddSPaolo Bonzini         goto done;
25449ab747fSPaolo Bonzini     }
25549ab747fSPaolo Bonzini 
25649ab747fSPaolo Bonzini     if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
25749ab747fSPaolo Bonzini         s->type == TYPE_TAPE) {
25849ab747fSPaolo Bonzini         s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
25949ab747fSPaolo Bonzini         DPRINTF("block size %d\n", s->blocksize);
26049ab747fSPaolo Bonzini     }
26149ab747fSPaolo Bonzini 
262fa0d653bSPaolo Bonzini     scsi_command_complete_noio(r, ret);
263b9e413ddSPaolo Bonzini 
264b9e413ddSPaolo Bonzini done:
265b9e413ddSPaolo Bonzini     aio_context_release(blk_get_aio_context(s->conf.blk));
26649ab747fSPaolo Bonzini }
26749ab747fSPaolo Bonzini 
26849ab747fSPaolo Bonzini /* Write data to a scsi device.  Returns nonzero on failure.
26949ab747fSPaolo Bonzini    The transfer may complete asynchronously.  */
27049ab747fSPaolo Bonzini static void scsi_write_data(SCSIRequest *req)
27149ab747fSPaolo Bonzini {
27249ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
27349ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
27449ab747fSPaolo Bonzini     int ret;
27549ab747fSPaolo Bonzini 
2762e144aa7SEric Farman     DPRINTF("scsi_write_data tag=0x%x\n", req->tag);
27749ab747fSPaolo Bonzini     if (r->len == 0) {
27849ab747fSPaolo Bonzini         r->len = r->buflen;
27949ab747fSPaolo Bonzini         scsi_req_data(&r->req, r->len);
28049ab747fSPaolo Bonzini         return;
28149ab747fSPaolo Bonzini     }
28249ab747fSPaolo Bonzini 
28349ab747fSPaolo Bonzini     /* The request is used as the AIO opaque value, so add a ref.  */
28449ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
2854be74634SMarkus Armbruster     ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete);
28649ab747fSPaolo Bonzini     if (ret < 0) {
287fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
28849ab747fSPaolo Bonzini     }
28949ab747fSPaolo Bonzini }
29049ab747fSPaolo Bonzini 
29149ab747fSPaolo Bonzini /* Return a pointer to the data buffer.  */
29249ab747fSPaolo Bonzini static uint8_t *scsi_get_buf(SCSIRequest *req)
29349ab747fSPaolo Bonzini {
29449ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
29549ab747fSPaolo Bonzini 
29649ab747fSPaolo Bonzini     return r->buf;
29749ab747fSPaolo Bonzini }
29849ab747fSPaolo Bonzini 
29949ab747fSPaolo Bonzini /* Execute a scsi command.  Returns the length of the data expected by the
30049ab747fSPaolo Bonzini    command.  This will be Positive for data transfers from the device
30149ab747fSPaolo Bonzini    (eg. disk reads), negative for transfers to the device (eg. disk writes),
30249ab747fSPaolo Bonzini    and zero if the command does not transfer any data.  */
30349ab747fSPaolo Bonzini 
30449ab747fSPaolo Bonzini static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
30549ab747fSPaolo Bonzini {
30649ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
30749ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
30849ab747fSPaolo Bonzini     int ret;
30949ab747fSPaolo Bonzini 
31049ab747fSPaolo Bonzini #ifdef DEBUG_SCSI
3112e144aa7SEric Farman     DPRINTF("Command: data=0x%02x", cmd[0]);
31249ab747fSPaolo Bonzini     {
31349ab747fSPaolo Bonzini         int i;
31449ab747fSPaolo Bonzini         for (i = 1; i < r->req.cmd.len; i++) {
31549ab747fSPaolo Bonzini             printf(" 0x%02x", cmd[i]);
31649ab747fSPaolo Bonzini         }
31749ab747fSPaolo Bonzini         printf("\n");
31849ab747fSPaolo Bonzini     }
31949ab747fSPaolo Bonzini #endif
32049ab747fSPaolo Bonzini 
32149ab747fSPaolo Bonzini     if (r->req.cmd.xfer == 0) {
32249ab747fSPaolo Bonzini         g_free(r->buf);
32349ab747fSPaolo Bonzini         r->buflen = 0;
32449ab747fSPaolo Bonzini         r->buf = NULL;
32549ab747fSPaolo Bonzini         /* The request is used as the AIO opaque value, so add a ref.  */
32649ab747fSPaolo Bonzini         scsi_req_ref(&r->req);
3274be74634SMarkus Armbruster         ret = execute_command(s->conf.blk, r, SG_DXFER_NONE,
3284be74634SMarkus Armbruster                               scsi_command_complete);
32949ab747fSPaolo Bonzini         if (ret < 0) {
330fa0d653bSPaolo Bonzini             scsi_command_complete_noio(r, ret);
33149ab747fSPaolo Bonzini             return 0;
33249ab747fSPaolo Bonzini         }
33349ab747fSPaolo Bonzini         return 0;
33449ab747fSPaolo Bonzini     }
33549ab747fSPaolo Bonzini 
33649ab747fSPaolo Bonzini     if (r->buflen != r->req.cmd.xfer) {
33749ab747fSPaolo Bonzini         g_free(r->buf);
33849ab747fSPaolo Bonzini         r->buf = g_malloc(r->req.cmd.xfer);
33949ab747fSPaolo Bonzini         r->buflen = r->req.cmd.xfer;
34049ab747fSPaolo Bonzini     }
34149ab747fSPaolo Bonzini 
34249ab747fSPaolo Bonzini     memset(r->buf, 0, r->buflen);
34349ab747fSPaolo Bonzini     r->len = r->req.cmd.xfer;
34449ab747fSPaolo Bonzini     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
34549ab747fSPaolo Bonzini         r->len = 0;
34649ab747fSPaolo Bonzini         return -r->req.cmd.xfer;
34749ab747fSPaolo Bonzini     } else {
34849ab747fSPaolo Bonzini         return r->req.cmd.xfer;
34949ab747fSPaolo Bonzini     }
35049ab747fSPaolo Bonzini }
35149ab747fSPaolo Bonzini 
3529fd7e859SPaolo Bonzini static int read_naa_id(const uint8_t *p, uint64_t *p_wwn)
3539fd7e859SPaolo Bonzini {
3549fd7e859SPaolo Bonzini     int i;
3559fd7e859SPaolo Bonzini 
3569fd7e859SPaolo Bonzini     if ((p[1] & 0xF) == 3) {
3579fd7e859SPaolo Bonzini         /* NAA designator type */
3589fd7e859SPaolo Bonzini         if (p[3] != 8) {
3599fd7e859SPaolo Bonzini             return -EINVAL;
3609fd7e859SPaolo Bonzini         }
3619fd7e859SPaolo Bonzini         *p_wwn = ldq_be_p(p + 4);
3629fd7e859SPaolo Bonzini         return 0;
3639fd7e859SPaolo Bonzini     }
3649fd7e859SPaolo Bonzini 
3659fd7e859SPaolo Bonzini     if ((p[1] & 0xF) == 8) {
3669fd7e859SPaolo Bonzini         /* SCSI name string designator type */
3679fd7e859SPaolo Bonzini         if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) {
3689fd7e859SPaolo Bonzini             return -EINVAL;
3699fd7e859SPaolo Bonzini         }
3709fd7e859SPaolo Bonzini         if (p[3] > 20 && p[24] != ',') {
3719fd7e859SPaolo Bonzini             return -EINVAL;
3729fd7e859SPaolo Bonzini         }
3739fd7e859SPaolo Bonzini         *p_wwn = 0;
3749fd7e859SPaolo Bonzini         for (i = 8; i < 24; i++) {
37595a5befcSPeter Maydell             char c = qemu_toupper(p[i]);
3769fd7e859SPaolo Bonzini             c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10);
3779fd7e859SPaolo Bonzini             *p_wwn = (*p_wwn << 4) | c;
3789fd7e859SPaolo Bonzini         }
3799fd7e859SPaolo Bonzini         return 0;
3809fd7e859SPaolo Bonzini     }
3819fd7e859SPaolo Bonzini 
3829fd7e859SPaolo Bonzini     return -EINVAL;
3839fd7e859SPaolo Bonzini }
3849fd7e859SPaolo Bonzini 
3859fd7e859SPaolo Bonzini void scsi_generic_read_device_identification(SCSIDevice *s)
3869fd7e859SPaolo Bonzini {
3879fd7e859SPaolo Bonzini     uint8_t cmd[6];
3889fd7e859SPaolo Bonzini     uint8_t buf[250];
3899fd7e859SPaolo Bonzini     uint8_t sensebuf[8];
3909fd7e859SPaolo Bonzini     sg_io_hdr_t io_header;
3919fd7e859SPaolo Bonzini     int ret;
3929fd7e859SPaolo Bonzini     int i, len;
3939fd7e859SPaolo Bonzini 
3949fd7e859SPaolo Bonzini     memset(cmd, 0, sizeof(cmd));
3959fd7e859SPaolo Bonzini     memset(buf, 0, sizeof(buf));
3969fd7e859SPaolo Bonzini     cmd[0] = INQUIRY;
3979fd7e859SPaolo Bonzini     cmd[1] = 1;
3989fd7e859SPaolo Bonzini     cmd[2] = 0x83;
3999fd7e859SPaolo Bonzini     cmd[4] = sizeof(buf);
4009fd7e859SPaolo Bonzini 
4019fd7e859SPaolo Bonzini     memset(&io_header, 0, sizeof(io_header));
4029fd7e859SPaolo Bonzini     io_header.interface_id = 'S';
4039fd7e859SPaolo Bonzini     io_header.dxfer_direction = SG_DXFER_FROM_DEV;
4049fd7e859SPaolo Bonzini     io_header.dxfer_len = sizeof(buf);
4059fd7e859SPaolo Bonzini     io_header.dxferp = buf;
4069fd7e859SPaolo Bonzini     io_header.cmdp = cmd;
4079fd7e859SPaolo Bonzini     io_header.cmd_len = sizeof(cmd);
4089fd7e859SPaolo Bonzini     io_header.mx_sb_len = sizeof(sensebuf);
4099fd7e859SPaolo Bonzini     io_header.sbp = sensebuf;
4109fd7e859SPaolo Bonzini     io_header.timeout = 6000; /* XXX */
4119fd7e859SPaolo Bonzini 
4129fd7e859SPaolo Bonzini     ret = blk_ioctl(s->conf.blk, SG_IO, &io_header);
4139fd7e859SPaolo Bonzini     if (ret < 0 || io_header.driver_status || io_header.host_status) {
4149fd7e859SPaolo Bonzini         return;
4159fd7e859SPaolo Bonzini     }
4169fd7e859SPaolo Bonzini 
4179fd7e859SPaolo Bonzini     len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4);
4189fd7e859SPaolo Bonzini     for (i = 0; i + 3 <= len; ) {
4199fd7e859SPaolo Bonzini         const uint8_t *p = &buf[i + 4];
4209fd7e859SPaolo Bonzini         uint64_t wwn;
4219fd7e859SPaolo Bonzini 
4229fd7e859SPaolo Bonzini         if (i + (p[3] + 4) > len) {
4239fd7e859SPaolo Bonzini             break;
4249fd7e859SPaolo Bonzini         }
4259fd7e859SPaolo Bonzini 
4269fd7e859SPaolo Bonzini         if ((p[1] & 0x10) == 0) {
4279fd7e859SPaolo Bonzini             /* Associated with the logical unit */
4289fd7e859SPaolo Bonzini             if (read_naa_id(p, &wwn) == 0) {
4299fd7e859SPaolo Bonzini                 s->wwn = wwn;
4309fd7e859SPaolo Bonzini             }
4319fd7e859SPaolo Bonzini         } else if ((p[1] & 0x10) == 0x10) {
4329fd7e859SPaolo Bonzini             /* Associated with the target port */
4339fd7e859SPaolo Bonzini             if (read_naa_id(p, &wwn) == 0) {
4349fd7e859SPaolo Bonzini                 s->port_wwn = wwn;
4359fd7e859SPaolo Bonzini             }
4369fd7e859SPaolo Bonzini         }
4379fd7e859SPaolo Bonzini 
4389fd7e859SPaolo Bonzini         i += p[3] + 4;
4399fd7e859SPaolo Bonzini     }
4409fd7e859SPaolo Bonzini }
4419fd7e859SPaolo Bonzini 
4424be74634SMarkus Armbruster static int get_stream_blocksize(BlockBackend *blk)
44349ab747fSPaolo Bonzini {
44449ab747fSPaolo Bonzini     uint8_t cmd[6];
44549ab747fSPaolo Bonzini     uint8_t buf[12];
44649ab747fSPaolo Bonzini     uint8_t sensebuf[8];
44749ab747fSPaolo Bonzini     sg_io_hdr_t io_header;
44849ab747fSPaolo Bonzini     int ret;
44949ab747fSPaolo Bonzini 
45049ab747fSPaolo Bonzini     memset(cmd, 0, sizeof(cmd));
45149ab747fSPaolo Bonzini     memset(buf, 0, sizeof(buf));
45249ab747fSPaolo Bonzini     cmd[0] = MODE_SENSE;
45349ab747fSPaolo Bonzini     cmd[4] = sizeof(buf);
45449ab747fSPaolo Bonzini 
45549ab747fSPaolo Bonzini     memset(&io_header, 0, sizeof(io_header));
45649ab747fSPaolo Bonzini     io_header.interface_id = 'S';
45749ab747fSPaolo Bonzini     io_header.dxfer_direction = SG_DXFER_FROM_DEV;
45849ab747fSPaolo Bonzini     io_header.dxfer_len = sizeof(buf);
45949ab747fSPaolo Bonzini     io_header.dxferp = buf;
46049ab747fSPaolo Bonzini     io_header.cmdp = cmd;
46149ab747fSPaolo Bonzini     io_header.cmd_len = sizeof(cmd);
46249ab747fSPaolo Bonzini     io_header.mx_sb_len = sizeof(sensebuf);
46349ab747fSPaolo Bonzini     io_header.sbp = sensebuf;
46449ab747fSPaolo Bonzini     io_header.timeout = 6000; /* XXX */
46549ab747fSPaolo Bonzini 
4664be74634SMarkus Armbruster     ret = blk_ioctl(blk, SG_IO, &io_header);
46749ab747fSPaolo Bonzini     if (ret < 0 || io_header.driver_status || io_header.host_status) {
46849ab747fSPaolo Bonzini         return -1;
46949ab747fSPaolo Bonzini     }
47049ab747fSPaolo Bonzini     return (buf[9] << 16) | (buf[10] << 8) | buf[11];
47149ab747fSPaolo Bonzini }
47249ab747fSPaolo Bonzini 
47349ab747fSPaolo Bonzini static void scsi_generic_reset(DeviceState *dev)
47449ab747fSPaolo Bonzini {
47549ab747fSPaolo Bonzini     SCSIDevice *s = SCSI_DEVICE(dev);
47649ab747fSPaolo Bonzini 
477*2343be0dSPaolo Bonzini     s->scsi_version = s->default_scsi_version;
47849ab747fSPaolo Bonzini     scsi_device_purge_requests(s, SENSE_CODE(RESET));
47949ab747fSPaolo Bonzini }
48049ab747fSPaolo Bonzini 
481a818a4b6SFam Zheng static void scsi_generic_realize(SCSIDevice *s, Error **errp)
48249ab747fSPaolo Bonzini {
4836ee143a0SPaolo Bonzini     int rc;
48449ab747fSPaolo Bonzini     int sg_version;
48549ab747fSPaolo Bonzini     struct sg_scsi_id scsiid;
48649ab747fSPaolo Bonzini 
4874be74634SMarkus Armbruster     if (!s->conf.blk) {
488a818a4b6SFam Zheng         error_setg(errp, "drive property not set");
489a818a4b6SFam Zheng         return;
49049ab747fSPaolo Bonzini     }
49149ab747fSPaolo Bonzini 
4924be74634SMarkus Armbruster     if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
493a818a4b6SFam Zheng         error_setg(errp, "Device doesn't support drive option werror");
494a818a4b6SFam Zheng         return;
49549ab747fSPaolo Bonzini     }
4964be74634SMarkus Armbruster     if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
497a818a4b6SFam Zheng         error_setg(errp, "Device doesn't support drive option rerror");
498a818a4b6SFam Zheng         return;
49949ab747fSPaolo Bonzini     }
50049ab747fSPaolo Bonzini 
50149ab747fSPaolo Bonzini     /* check we are using a driver managing SG_IO (version 3 and after */
5024be74634SMarkus Armbruster     rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version);
5036ee143a0SPaolo Bonzini     if (rc < 0) {
50409c2c6ffSPaolo Bonzini         error_setg_errno(errp, -rc, "cannot get SG_IO version number");
50509c2c6ffSPaolo Bonzini         if (rc != -EPERM) {
50609c2c6ffSPaolo Bonzini             error_append_hint(errp, "Is this a SCSI device?\n");
50709c2c6ffSPaolo Bonzini         }
508a818a4b6SFam Zheng         return;
50949ab747fSPaolo Bonzini     }
51049ab747fSPaolo Bonzini     if (sg_version < 30000) {
511a818a4b6SFam Zheng         error_setg(errp, "scsi generic interface too old");
512a818a4b6SFam Zheng         return;
51349ab747fSPaolo Bonzini     }
51449ab747fSPaolo Bonzini 
51549ab747fSPaolo Bonzini     /* get LUN of the /dev/sg? */
5164be74634SMarkus Armbruster     if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) {
517a818a4b6SFam Zheng         error_setg(errp, "SG_GET_SCSI_ID ioctl failed");
518a818a4b6SFam Zheng         return;
51949ab747fSPaolo Bonzini     }
520c6caae55SFam Zheng     if (!blkconf_apply_backend_options(&s->conf,
521d9bcd6f7SFam Zheng                                        blk_is_read_only(s->conf.blk),
522c6caae55SFam Zheng                                        true, errp)) {
523d9bcd6f7SFam Zheng         return;
524d9bcd6f7SFam Zheng     }
52549ab747fSPaolo Bonzini 
52649ab747fSPaolo Bonzini     /* define device state */
52749ab747fSPaolo Bonzini     s->type = scsiid.scsi_type;
52849ab747fSPaolo Bonzini     DPRINTF("device type %d\n", s->type);
52949ab747fSPaolo Bonzini 
53049ab747fSPaolo Bonzini     switch (s->type) {
53149ab747fSPaolo Bonzini     case TYPE_TAPE:
5324be74634SMarkus Armbruster         s->blocksize = get_stream_blocksize(s->conf.blk);
53349ab747fSPaolo Bonzini         if (s->blocksize == -1) {
53449ab747fSPaolo Bonzini             s->blocksize = 0;
53549ab747fSPaolo Bonzini         }
53649ab747fSPaolo Bonzini         break;
53749ab747fSPaolo Bonzini 
53849ab747fSPaolo Bonzini         /* Make a guess for block devices, we'll fix it when the guest sends.
53949ab747fSPaolo Bonzini          * READ CAPACITY.  If they don't, they likely would assume these sizes
54049ab747fSPaolo Bonzini          * anyway. (TODO: they could also send MODE SENSE).
54149ab747fSPaolo Bonzini          */
54249ab747fSPaolo Bonzini     case TYPE_ROM:
54349ab747fSPaolo Bonzini     case TYPE_WORM:
54449ab747fSPaolo Bonzini         s->blocksize = 2048;
54549ab747fSPaolo Bonzini         break;
54649ab747fSPaolo Bonzini     default:
54749ab747fSPaolo Bonzini         s->blocksize = 512;
54849ab747fSPaolo Bonzini         break;
54949ab747fSPaolo Bonzini     }
55049ab747fSPaolo Bonzini 
55149ab747fSPaolo Bonzini     DPRINTF("block size %d\n", s->blocksize);
5529fd7e859SPaolo Bonzini 
5539fd7e859SPaolo Bonzini     scsi_generic_read_device_identification(s);
55449ab747fSPaolo Bonzini }
55549ab747fSPaolo Bonzini 
55649ab747fSPaolo Bonzini const SCSIReqOps scsi_generic_req_ops = {
55749ab747fSPaolo Bonzini     .size         = sizeof(SCSIGenericReq),
55849ab747fSPaolo Bonzini     .free_req     = scsi_free_request,
55949ab747fSPaolo Bonzini     .send_command = scsi_send_command,
56049ab747fSPaolo Bonzini     .read_data    = scsi_read_data,
56149ab747fSPaolo Bonzini     .write_data   = scsi_write_data,
56249ab747fSPaolo Bonzini     .get_buf      = scsi_get_buf,
56349ab747fSPaolo Bonzini     .load_request = scsi_generic_load_request,
56449ab747fSPaolo Bonzini     .save_request = scsi_generic_save_request,
56549ab747fSPaolo Bonzini };
56649ab747fSPaolo Bonzini 
56749ab747fSPaolo Bonzini static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
56849ab747fSPaolo Bonzini                                      uint8_t *buf, void *hba_private)
56949ab747fSPaolo Bonzini {
5709be38598SEduardo Habkost     return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
57149ab747fSPaolo Bonzini }
57249ab747fSPaolo Bonzini 
57349ab747fSPaolo Bonzini static Property scsi_generic_properties[] = {
5744be74634SMarkus Armbruster     DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
575d9bcd6f7SFam Zheng     DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false),
57649ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
57749ab747fSPaolo Bonzini };
57849ab747fSPaolo Bonzini 
5793e7e180aSPaolo Bonzini static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
5803e7e180aSPaolo Bonzini                                   uint8_t *buf, void *hba_private)
5813e7e180aSPaolo Bonzini {
5823e7e180aSPaolo Bonzini     return scsi_bus_parse_cdb(dev, cmd, buf, hba_private);
5833e7e180aSPaolo Bonzini }
5843e7e180aSPaolo Bonzini 
58549ab747fSPaolo Bonzini static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
58649ab747fSPaolo Bonzini {
58749ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
58849ab747fSPaolo Bonzini     SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
58949ab747fSPaolo Bonzini 
590a818a4b6SFam Zheng     sc->realize      = scsi_generic_realize;
59149ab747fSPaolo Bonzini     sc->alloc_req    = scsi_new_request;
5923e7e180aSPaolo Bonzini     sc->parse_cdb    = scsi_generic_parse_cdb;
59349ab747fSPaolo Bonzini     dc->fw_name = "disk";
59449ab747fSPaolo Bonzini     dc->desc = "pass through generic scsi device (/dev/sg*)";
59549ab747fSPaolo Bonzini     dc->reset = scsi_generic_reset;
59649ab747fSPaolo Bonzini     dc->props = scsi_generic_properties;
59749ab747fSPaolo Bonzini     dc->vmsd  = &vmstate_scsi_device;
59849ab747fSPaolo Bonzini }
59949ab747fSPaolo Bonzini 
60049ab747fSPaolo Bonzini static const TypeInfo scsi_generic_info = {
60149ab747fSPaolo Bonzini     .name          = "scsi-generic",
60249ab747fSPaolo Bonzini     .parent        = TYPE_SCSI_DEVICE,
60349ab747fSPaolo Bonzini     .instance_size = sizeof(SCSIDevice),
60449ab747fSPaolo Bonzini     .class_init    = scsi_generic_class_initfn,
60549ab747fSPaolo Bonzini };
60649ab747fSPaolo Bonzini 
60749ab747fSPaolo Bonzini static void scsi_generic_register_types(void)
60849ab747fSPaolo Bonzini {
60949ab747fSPaolo Bonzini     type_register_static(&scsi_generic_info);
61049ab747fSPaolo Bonzini }
61149ab747fSPaolo Bonzini 
61249ab747fSPaolo Bonzini type_init(scsi_generic_register_types)
61349ab747fSPaolo Bonzini 
61449ab747fSPaolo Bonzini #endif /* __linux__ */
615