xref: /qemu/hw/scsi/scsi-generic.c (revision b2d50a33)
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"
16856dfd8aSMarkus Armbruster #include "qemu/ctype.h"
1749ab747fSPaolo Bonzini #include "qemu/error-report.h"
180b8fa32fSMarkus Armbruster #include "qemu/module.h"
1949ab747fSPaolo Bonzini #include "hw/scsi/scsi.h"
20ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
21a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
22ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
233d4a8bf0SPaolo Bonzini #include "hw/scsi/emulation.h"
244be74634SMarkus Armbruster #include "sysemu/block-backend.h"
2556853498SLaurent Vivier #include "trace.h"
2649ab747fSPaolo Bonzini 
2749ab747fSPaolo Bonzini #ifdef __linux__
2849ab747fSPaolo Bonzini 
2949ab747fSPaolo Bonzini #include <scsi/sg.h>
3008e2c9f1SPaolo Bonzini #include "scsi/constants.h"
3149ab747fSPaolo Bonzini 
3249ab747fSPaolo Bonzini #ifndef MAX_UINT
3349ab747fSPaolo Bonzini #define MAX_UINT ((unsigned int)-1)
3449ab747fSPaolo Bonzini #endif
3549ab747fSPaolo Bonzini 
3649ab747fSPaolo Bonzini typedef struct SCSIGenericReq {
3749ab747fSPaolo Bonzini     SCSIRequest req;
3849ab747fSPaolo Bonzini     uint8_t *buf;
3949ab747fSPaolo Bonzini     int buflen;
4049ab747fSPaolo Bonzini     int len;
4149ab747fSPaolo Bonzini     sg_io_hdr_t io_header;
4249ab747fSPaolo Bonzini } SCSIGenericReq;
4349ab747fSPaolo Bonzini 
4449ab747fSPaolo Bonzini static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
4549ab747fSPaolo Bonzini {
4649ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
4749ab747fSPaolo Bonzini 
4849ab747fSPaolo Bonzini     qemu_put_sbe32s(f, &r->buflen);
4949ab747fSPaolo Bonzini     if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
5049ab747fSPaolo Bonzini         assert(!r->req.sg);
5149ab747fSPaolo Bonzini         qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
5249ab747fSPaolo Bonzini     }
5349ab747fSPaolo Bonzini }
5449ab747fSPaolo Bonzini 
5549ab747fSPaolo Bonzini static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
5649ab747fSPaolo Bonzini {
5749ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
5849ab747fSPaolo Bonzini 
5949ab747fSPaolo Bonzini     qemu_get_sbe32s(f, &r->buflen);
6049ab747fSPaolo Bonzini     if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
6149ab747fSPaolo Bonzini         assert(!r->req.sg);
6249ab747fSPaolo Bonzini         qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
6349ab747fSPaolo Bonzini     }
6449ab747fSPaolo Bonzini }
6549ab747fSPaolo Bonzini 
6649ab747fSPaolo Bonzini static void scsi_free_request(SCSIRequest *req)
6749ab747fSPaolo Bonzini {
6849ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
6949ab747fSPaolo Bonzini 
7049ab747fSPaolo Bonzini     g_free(r->buf);
7149ab747fSPaolo Bonzini }
7249ab747fSPaolo Bonzini 
7349ab747fSPaolo Bonzini /* Helper function for command completion.  */
74fa0d653bSPaolo Bonzini static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
7549ab747fSPaolo Bonzini {
7649ab747fSPaolo Bonzini     int status;
771ead6b4eSPaolo Bonzini     SCSISense sense;
7849ab747fSPaolo Bonzini 
79fa0d653bSPaolo Bonzini     assert(r->req.aiocb == NULL);
80fa0d653bSPaolo Bonzini 
816c25fa6cSFam Zheng     if (r->req.io_canceled) {
82d5776465SFam Zheng         scsi_req_cancel_complete(&r->req);
836c25fa6cSFam Zheng         goto done;
846c25fa6cSFam Zheng     }
851ead6b4eSPaolo Bonzini     status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
861ead6b4eSPaolo Bonzini     if (status == CHECK_CONDITION) {
8749ab747fSPaolo Bonzini         if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
8849ab747fSPaolo Bonzini             r->req.sense_len = r->io_header.sb_len_wr;
891ead6b4eSPaolo Bonzini         } else {
901ead6b4eSPaolo Bonzini             scsi_req_build_sense(&r->req, sense);
911ead6b4eSPaolo Bonzini         }
9249ab747fSPaolo Bonzini     }
9349ab747fSPaolo Bonzini 
9456853498SLaurent Vivier     trace_scsi_generic_command_complete_noio(r, r->req.tag, status);
9549ab747fSPaolo Bonzini 
9649ab747fSPaolo Bonzini     scsi_req_complete(&r->req, status);
976c25fa6cSFam Zheng done:
9849ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
9949ab747fSPaolo Bonzini }
10049ab747fSPaolo Bonzini 
101fa0d653bSPaolo Bonzini static void scsi_command_complete(void *opaque, int ret)
102fa0d653bSPaolo Bonzini {
103fa0d653bSPaolo Bonzini     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
104b9e413ddSPaolo Bonzini     SCSIDevice *s = r->req.dev;
105fa0d653bSPaolo Bonzini 
106fa0d653bSPaolo Bonzini     assert(r->req.aiocb != NULL);
107fa0d653bSPaolo Bonzini     r->req.aiocb = NULL;
108b9e413ddSPaolo Bonzini 
109b9e413ddSPaolo Bonzini     aio_context_acquire(blk_get_aio_context(s->conf.blk));
110fa0d653bSPaolo Bonzini     scsi_command_complete_noio(r, ret);
111b9e413ddSPaolo Bonzini     aio_context_release(blk_get_aio_context(s->conf.blk));
112fa0d653bSPaolo Bonzini }
113fa0d653bSPaolo Bonzini 
1144be74634SMarkus Armbruster static int execute_command(BlockBackend *blk,
11549ab747fSPaolo Bonzini                            SCSIGenericReq *r, int direction,
116097310b5SMarkus Armbruster                            BlockCompletionFunc *complete)
11749ab747fSPaolo Bonzini {
118c9b6609bSHannes Reinecke     SCSIDevice *s = r->req.dev;
119c9b6609bSHannes Reinecke 
12049ab747fSPaolo Bonzini     r->io_header.interface_id = 'S';
12149ab747fSPaolo Bonzini     r->io_header.dxfer_direction = direction;
12249ab747fSPaolo Bonzini     r->io_header.dxferp = r->buf;
12349ab747fSPaolo Bonzini     r->io_header.dxfer_len = r->buflen;
12449ab747fSPaolo Bonzini     r->io_header.cmdp = r->req.cmd.buf;
12549ab747fSPaolo Bonzini     r->io_header.cmd_len = r->req.cmd.len;
12649ab747fSPaolo Bonzini     r->io_header.mx_sb_len = sizeof(r->req.sense);
12749ab747fSPaolo Bonzini     r->io_header.sbp = r->req.sense;
128c9b6609bSHannes Reinecke     r->io_header.timeout = s->io_timeout * 1000;
12949ab747fSPaolo Bonzini     r->io_header.usr_ptr = r;
13049ab747fSPaolo Bonzini     r->io_header.flags |= SG_FLAG_DIRECT_IO;
13149ab747fSPaolo Bonzini 
132*b2d50a33SHannes Reinecke     trace_scsi_generic_aio_sgio_command(r->req.tag, r->req.cmd.buf[0],
133*b2d50a33SHannes Reinecke                                         r->io_header.timeout);
1344be74634SMarkus Armbruster     r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r);
135d836f8d3SPavel Hrdina     if (r->req.aiocb == NULL) {
136d836f8d3SPavel Hrdina         return -EIO;
137d836f8d3SPavel Hrdina     }
13849ab747fSPaolo Bonzini 
13949ab747fSPaolo Bonzini     return 0;
14049ab747fSPaolo Bonzini }
14149ab747fSPaolo Bonzini 
1420a96ca24SDaniel Henrique Barboza static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
1430a96ca24SDaniel Henrique Barboza {
1446c219fc8SPaolo Bonzini     uint8_t page, page_idx;
145a71c775bSDaniel Henrique Barboza 
1460a96ca24SDaniel Henrique Barboza     /*
1470a96ca24SDaniel Henrique Barboza      *  EVPD set to zero returns the standard INQUIRY data.
1480a96ca24SDaniel Henrique Barboza      *
1490a96ca24SDaniel Henrique Barboza      *  Check if scsi_version is unset (-1) to avoid re-defining it
1500a96ca24SDaniel Henrique Barboza      *  each time an INQUIRY with standard data is received.
1510a96ca24SDaniel Henrique Barboza      *  scsi_version is initialized with -1 in scsi_generic_reset
1520a96ca24SDaniel Henrique Barboza      *  and scsi_disk_reset, making sure that we'll set the
1530a96ca24SDaniel Henrique Barboza      *  scsi_version after a reset. If the version field of the
1540a96ca24SDaniel Henrique Barboza      *  INQUIRY response somehow changes after a guest reboot,
1550a96ca24SDaniel Henrique Barboza      *  we'll be able to keep track of it.
1560a96ca24SDaniel Henrique Barboza      *
1570a96ca24SDaniel Henrique Barboza      *  On SCSI-2 and older, first 3 bits of byte 2 is the
1580a96ca24SDaniel Henrique Barboza      *  ANSI-approved version, while on later versions the
1590a96ca24SDaniel Henrique Barboza      *  whole byte 2 contains the version. Check if we're dealing
1600a96ca24SDaniel Henrique Barboza      *  with a newer version and, in that case, assign the
1610a96ca24SDaniel Henrique Barboza      *  whole byte.
1620a96ca24SDaniel Henrique Barboza      */
1630a96ca24SDaniel Henrique Barboza     if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) {
1640a96ca24SDaniel Henrique Barboza         s->scsi_version = r->buf[2] & 0x07;
1650a96ca24SDaniel Henrique Barboza         if (s->scsi_version > 2) {
1660a96ca24SDaniel Henrique Barboza             s->scsi_version = r->buf[2];
1670a96ca24SDaniel Henrique Barboza         }
1680a96ca24SDaniel Henrique Barboza     }
169a71c775bSDaniel Henrique Barboza 
170afff2db6SDmitry Fomichev     if ((s->type == TYPE_DISK || s->type == TYPE_ZBC) &&
171afff2db6SDmitry Fomichev         (r->req.cmd.buf[1] & 0x01)) {
172a71c775bSDaniel Henrique Barboza         page = r->req.cmd.buf[2];
173a71c775bSDaniel Henrique Barboza         if (page == 0xb0) {
1740a96ca24SDaniel Henrique Barboza             uint32_t max_transfer =
1750a96ca24SDaniel Henrique Barboza                 blk_get_max_transfer(s->conf.blk) / s->blocksize;
1760a96ca24SDaniel Henrique Barboza 
1770a96ca24SDaniel Henrique Barboza             assert(max_transfer);
1780a96ca24SDaniel Henrique Barboza             stl_be_p(&r->buf[8], max_transfer);
1790a96ca24SDaniel Henrique Barboza             /* Also take care of the opt xfer len. */
1800a96ca24SDaniel Henrique Barboza             stl_be_p(&r->buf[12],
1810a96ca24SDaniel Henrique Barboza                     MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
182e909ff93SPaolo Bonzini         } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {
183a71c775bSDaniel Henrique Barboza             /*
184a71c775bSDaniel Henrique Barboza              * Now we're capable of supplying the VPD Block Limits
185a71c775bSDaniel Henrique Barboza              * response if the hardware can't. Add it in the INQUIRY
186a71c775bSDaniel Henrique Barboza              * Supported VPD pages response in case we are using the
187a71c775bSDaniel Henrique Barboza              * emulation for this device.
188a71c775bSDaniel Henrique Barboza              *
189a71c775bSDaniel Henrique Barboza              * This way, the guest kernel will be aware of the support
190a71c775bSDaniel Henrique Barboza              * and will use it to proper setup the SCSI device.
1916c219fc8SPaolo Bonzini              *
1926c219fc8SPaolo Bonzini              * VPD page numbers must be sorted, so insert 0xb0 at the
193e909ff93SPaolo Bonzini              * right place with an in-place insert.  When the while loop
194e909ff93SPaolo Bonzini              * begins the device response is at r[0] to r[page_idx - 1].
195a71c775bSDaniel Henrique Barboza              */
196e909ff93SPaolo Bonzini             page_idx = lduw_be_p(r->buf + 2) + 4;
197e909ff93SPaolo Bonzini             page_idx = MIN(page_idx, r->buflen);
198e909ff93SPaolo Bonzini             while (page_idx > 4 && r->buf[page_idx - 1] >= 0xb0) {
1996c219fc8SPaolo Bonzini                 if (page_idx < r->buflen) {
2006c219fc8SPaolo Bonzini                     r->buf[page_idx] = r->buf[page_idx - 1];
2016c219fc8SPaolo Bonzini                 }
202e909ff93SPaolo Bonzini                 page_idx--;
2036c219fc8SPaolo Bonzini             }
204e909ff93SPaolo Bonzini             if (page_idx < r->buflen) {
2056c219fc8SPaolo Bonzini                 r->buf[page_idx] = 0xb0;
206e909ff93SPaolo Bonzini             }
2076c219fc8SPaolo Bonzini             stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1);
2080a96ca24SDaniel Henrique Barboza         }
2090a96ca24SDaniel Henrique Barboza     }
210a71c775bSDaniel Henrique Barboza }
211a71c775bSDaniel Henrique Barboza 
2123d4a8bf0SPaolo Bonzini static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s)
213a71c775bSDaniel Henrique Barboza {
2143d4a8bf0SPaolo Bonzini     int len;
2153d4a8bf0SPaolo Bonzini     uint8_t buf[64];
2163d4a8bf0SPaolo Bonzini 
2173d4a8bf0SPaolo Bonzini     SCSIBlockLimits bl = {
2183d4a8bf0SPaolo Bonzini         .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize
2193d4a8bf0SPaolo Bonzini     };
2203d4a8bf0SPaolo Bonzini 
2213d4a8bf0SPaolo Bonzini     memset(r->buf, 0, r->buflen);
2223d4a8bf0SPaolo Bonzini     stb_p(buf, s->type);
2233d4a8bf0SPaolo Bonzini     stb_p(buf + 1, 0xb0);
2243d4a8bf0SPaolo Bonzini     len = scsi_emulate_block_limits(buf + 4, &bl);
2253d4a8bf0SPaolo Bonzini     assert(len <= sizeof(buf) - 4);
2263d4a8bf0SPaolo Bonzini     stw_be_p(buf + 2, len);
2273d4a8bf0SPaolo Bonzini 
2283d4a8bf0SPaolo Bonzini     memcpy(r->buf, buf, MIN(r->buflen, len + 4));
2293d4a8bf0SPaolo Bonzini 
230a71c775bSDaniel Henrique Barboza     r->io_header.sb_len_wr = 0;
231a71c775bSDaniel Henrique Barboza 
232a71c775bSDaniel Henrique Barboza     /*
233a71c775bSDaniel Henrique Barboza     * We have valid contents in the reply buffer but the
234a71c775bSDaniel Henrique Barboza     * io_header can report a sense error coming from
235a71c775bSDaniel Henrique Barboza     * the hardware in scsi_command_complete_noio. Clean
236a71c775bSDaniel Henrique Barboza     * up the io_header to avoid reporting it.
237a71c775bSDaniel Henrique Barboza     */
238a71c775bSDaniel Henrique Barboza     r->io_header.driver_status = 0;
239a71c775bSDaniel Henrique Barboza     r->io_header.status = 0;
240a71c775bSDaniel Henrique Barboza 
241a71c775bSDaniel Henrique Barboza     return r->buflen;
242a71c775bSDaniel Henrique Barboza }
2430a96ca24SDaniel Henrique Barboza 
24449ab747fSPaolo Bonzini static void scsi_read_complete(void * opaque, int ret)
24549ab747fSPaolo Bonzini {
24649ab747fSPaolo Bonzini     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
24749ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
24849ab747fSPaolo Bonzini     int len;
24949ab747fSPaolo Bonzini 
250fa0d653bSPaolo Bonzini     assert(r->req.aiocb != NULL);
25149ab747fSPaolo Bonzini     r->req.aiocb = NULL;
252fa0d653bSPaolo Bonzini 
253b9e413ddSPaolo Bonzini     aio_context_acquire(blk_get_aio_context(s->conf.blk));
254b9e413ddSPaolo Bonzini 
2556c25fa6cSFam Zheng     if (ret || r->req.io_canceled) {
256fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
257b9e413ddSPaolo Bonzini         goto done;
25849ab747fSPaolo Bonzini     }
259fa0d653bSPaolo Bonzini 
26049ab747fSPaolo Bonzini     len = r->io_header.dxfer_len - r->io_header.resid;
26156853498SLaurent Vivier     trace_scsi_generic_read_complete(r->req.tag, len);
26249ab747fSPaolo Bonzini 
26349ab747fSPaolo Bonzini     r->len = -1;
264a71c775bSDaniel Henrique Barboza 
2651849f297SShin'ichiro Kawasaki     if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
2661849f297SShin'ichiro Kawasaki         SCSISense sense =
2671849f297SShin'ichiro Kawasaki             scsi_parse_sense_buf(r->req.sense, r->io_header.sb_len_wr);
2681849f297SShin'ichiro Kawasaki 
269a71c775bSDaniel Henrique Barboza         /*
270a71c775bSDaniel Henrique Barboza          * Check if this is a VPD Block Limits request that
271a71c775bSDaniel Henrique Barboza          * resulted in sense error but would need emulation.
272a71c775bSDaniel Henrique Barboza          * In this case, emulate a valid VPD response.
273a71c775bSDaniel Henrique Barboza          */
2741849f297SShin'ichiro Kawasaki         if (sense.key == ILLEGAL_REQUEST &&
2751849f297SShin'ichiro Kawasaki             s->needs_vpd_bl_emulation &&
2763d4a8bf0SPaolo Bonzini             r->req.cmd.buf[0] == INQUIRY &&
2773d4a8bf0SPaolo Bonzini             (r->req.cmd.buf[1] & 0x01) &&
2783d4a8bf0SPaolo Bonzini             r->req.cmd.buf[2] == 0xb0) {
2793d4a8bf0SPaolo Bonzini             len = scsi_generic_emulate_block_limits(r, s);
280a71c775bSDaniel Henrique Barboza             /*
2811849f297SShin'ichiro Kawasaki              * It's okay to jup to req_complete: no need to
2821849f297SShin'ichiro Kawasaki              * let scsi_handle_inquiry_reply handle an
283a71c775bSDaniel Henrique Barboza              * INQUIRY VPD BL request we created manually.
284a71c775bSDaniel Henrique Barboza              */
2851849f297SShin'ichiro Kawasaki         }
2861849f297SShin'ichiro Kawasaki         if (sense.key) {
287a71c775bSDaniel Henrique Barboza             goto req_complete;
288a71c775bSDaniel Henrique Barboza         }
289a71c775bSDaniel Henrique Barboza     }
290a71c775bSDaniel Henrique Barboza 
29149ab747fSPaolo Bonzini     if (len == 0) {
292fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, 0);
293b9e413ddSPaolo Bonzini         goto done;
294fa0d653bSPaolo Bonzini     }
295fa0d653bSPaolo Bonzini 
29649ab747fSPaolo Bonzini     /* Snoop READ CAPACITY output to set the blocksize.  */
29753254e56SPaolo Bonzini     if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
29853254e56SPaolo Bonzini         (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
29949ab747fSPaolo Bonzini         s->blocksize = ldl_be_p(&r->buf[4]);
30053254e56SPaolo Bonzini         s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
30149ab747fSPaolo Bonzini     } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
30249ab747fSPaolo Bonzini                (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
30349ab747fSPaolo Bonzini         s->blocksize = ldl_be_p(&r->buf[8]);
30449ab747fSPaolo Bonzini         s->max_lba = ldq_be_p(&r->buf[0]);
30549ab747fSPaolo Bonzini     }
3064be74634SMarkus Armbruster     blk_set_guest_block_size(s->conf.blk, s->blocksize);
30749ab747fSPaolo Bonzini 
308afff2db6SDmitry Fomichev     /*
309afff2db6SDmitry Fomichev      * Patch MODE SENSE device specific parameters if the BDS is opened
3100eb2baebSPaolo Bonzini      * readonly.
3110eb2baebSPaolo Bonzini      */
312afff2db6SDmitry Fomichev     if ((s->type == TYPE_DISK || s->type == TYPE_TAPE || s->type == TYPE_ZBC) &&
31386b1cf32SKevin Wolf         !blk_is_writable(s->conf.blk) &&
3140eb2baebSPaolo Bonzini         (r->req.cmd.buf[0] == MODE_SENSE ||
3150eb2baebSPaolo Bonzini          r->req.cmd.buf[0] == MODE_SENSE_10) &&
3160eb2baebSPaolo Bonzini         (r->req.cmd.buf[1] & 0x8) == 0) {
3170eb2baebSPaolo Bonzini         if (r->req.cmd.buf[0] == MODE_SENSE) {
3180eb2baebSPaolo Bonzini             r->buf[2] |= 0x80;
3190eb2baebSPaolo Bonzini         } else  {
3200eb2baebSPaolo Bonzini             r->buf[3] |= 0x80;
3210eb2baebSPaolo Bonzini         }
3220eb2baebSPaolo Bonzini     }
32329e560f0SDaniel Henrique Barboza     if (r->req.cmd.buf[0] == INQUIRY) {
3240a96ca24SDaniel Henrique Barboza         scsi_handle_inquiry_reply(r, s);
32529e560f0SDaniel Henrique Barboza     }
326a71c775bSDaniel Henrique Barboza 
327a71c775bSDaniel Henrique Barboza req_complete:
32849ab747fSPaolo Bonzini     scsi_req_data(&r->req, len);
32949ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
330b9e413ddSPaolo Bonzini 
331b9e413ddSPaolo Bonzini done:
332b9e413ddSPaolo Bonzini     aio_context_release(blk_get_aio_context(s->conf.blk));
33349ab747fSPaolo Bonzini }
33449ab747fSPaolo Bonzini 
33549ab747fSPaolo Bonzini /* Read more data from scsi device into buffer.  */
33649ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req)
33749ab747fSPaolo Bonzini {
33849ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
33949ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
34049ab747fSPaolo Bonzini     int ret;
34149ab747fSPaolo Bonzini 
34256853498SLaurent Vivier     trace_scsi_generic_read_data(req->tag);
34349ab747fSPaolo Bonzini 
34449ab747fSPaolo Bonzini     /* The request is used as the AIO opaque value, so add a ref.  */
34549ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
34649ab747fSPaolo Bonzini     if (r->len == -1) {
347fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, 0);
34849ab747fSPaolo Bonzini         return;
34949ab747fSPaolo Bonzini     }
35049ab747fSPaolo Bonzini 
3514be74634SMarkus Armbruster     ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV,
3524be74634SMarkus Armbruster                           scsi_read_complete);
35349ab747fSPaolo Bonzini     if (ret < 0) {
354fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
35549ab747fSPaolo Bonzini     }
35649ab747fSPaolo Bonzini }
35749ab747fSPaolo Bonzini 
35849ab747fSPaolo Bonzini static void scsi_write_complete(void * opaque, int ret)
35949ab747fSPaolo Bonzini {
36049ab747fSPaolo Bonzini     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
36149ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
36249ab747fSPaolo Bonzini 
36356853498SLaurent Vivier     trace_scsi_generic_write_complete(ret);
364fa0d653bSPaolo Bonzini 
365fa0d653bSPaolo Bonzini     assert(r->req.aiocb != NULL);
36649ab747fSPaolo Bonzini     r->req.aiocb = NULL;
367fa0d653bSPaolo Bonzini 
368b9e413ddSPaolo Bonzini     aio_context_acquire(blk_get_aio_context(s->conf.blk));
369b9e413ddSPaolo Bonzini 
3706c25fa6cSFam Zheng     if (ret || r->req.io_canceled) {
371fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
372b9e413ddSPaolo Bonzini         goto done;
37349ab747fSPaolo Bonzini     }
37449ab747fSPaolo Bonzini 
37549ab747fSPaolo Bonzini     if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
37649ab747fSPaolo Bonzini         s->type == TYPE_TAPE) {
37749ab747fSPaolo Bonzini         s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
37856853498SLaurent Vivier         trace_scsi_generic_write_complete_blocksize(s->blocksize);
37949ab747fSPaolo Bonzini     }
38049ab747fSPaolo Bonzini 
381fa0d653bSPaolo Bonzini     scsi_command_complete_noio(r, ret);
382b9e413ddSPaolo Bonzini 
383b9e413ddSPaolo Bonzini done:
384b9e413ddSPaolo Bonzini     aio_context_release(blk_get_aio_context(s->conf.blk));
38549ab747fSPaolo Bonzini }
38649ab747fSPaolo Bonzini 
38749ab747fSPaolo Bonzini /* Write data to a scsi device.  Returns nonzero on failure.
38849ab747fSPaolo Bonzini    The transfer may complete asynchronously.  */
38949ab747fSPaolo Bonzini static void scsi_write_data(SCSIRequest *req)
39049ab747fSPaolo Bonzini {
39149ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
39249ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
39349ab747fSPaolo Bonzini     int ret;
39449ab747fSPaolo Bonzini 
39556853498SLaurent Vivier     trace_scsi_generic_write_data(req->tag);
39649ab747fSPaolo Bonzini     if (r->len == 0) {
39749ab747fSPaolo Bonzini         r->len = r->buflen;
39849ab747fSPaolo Bonzini         scsi_req_data(&r->req, r->len);
39949ab747fSPaolo Bonzini         return;
40049ab747fSPaolo Bonzini     }
40149ab747fSPaolo Bonzini 
40249ab747fSPaolo Bonzini     /* The request is used as the AIO opaque value, so add a ref.  */
40349ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
4044be74634SMarkus Armbruster     ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete);
40549ab747fSPaolo Bonzini     if (ret < 0) {
406fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
40749ab747fSPaolo Bonzini     }
40849ab747fSPaolo Bonzini }
40949ab747fSPaolo Bonzini 
41049ab747fSPaolo Bonzini /* Return a pointer to the data buffer.  */
41149ab747fSPaolo Bonzini static uint8_t *scsi_get_buf(SCSIRequest *req)
41249ab747fSPaolo Bonzini {
41349ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
41449ab747fSPaolo Bonzini 
41549ab747fSPaolo Bonzini     return r->buf;
41649ab747fSPaolo Bonzini }
41749ab747fSPaolo Bonzini 
41856853498SLaurent Vivier static void scsi_generic_command_dump(uint8_t *cmd, int len)
41956853498SLaurent Vivier {
42056853498SLaurent Vivier     int i;
42156853498SLaurent Vivier     char *line_buffer, *p;
42256853498SLaurent Vivier 
42356853498SLaurent Vivier     line_buffer = g_malloc(len * 5 + 1);
42456853498SLaurent Vivier 
42556853498SLaurent Vivier     for (i = 0, p = line_buffer; i < len; i++) {
42656853498SLaurent Vivier         p += sprintf(p, " 0x%02x", cmd[i]);
42756853498SLaurent Vivier     }
42856853498SLaurent Vivier     trace_scsi_generic_send_command(line_buffer);
42956853498SLaurent Vivier 
43056853498SLaurent Vivier     g_free(line_buffer);
43156853498SLaurent Vivier }
43256853498SLaurent Vivier 
43349ab747fSPaolo Bonzini /* Execute a scsi command.  Returns the length of the data expected by the
43449ab747fSPaolo Bonzini    command.  This will be Positive for data transfers from the device
43549ab747fSPaolo Bonzini    (eg. disk reads), negative for transfers to the device (eg. disk writes),
43649ab747fSPaolo Bonzini    and zero if the command does not transfer any data.  */
43749ab747fSPaolo Bonzini 
43849ab747fSPaolo Bonzini static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
43949ab747fSPaolo Bonzini {
44049ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
44149ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
44249ab747fSPaolo Bonzini     int ret;
44349ab747fSPaolo Bonzini 
44456853498SLaurent Vivier     if (trace_event_get_state_backends(TRACE_SCSI_GENERIC_SEND_COMMAND)) {
44556853498SLaurent Vivier         scsi_generic_command_dump(cmd, r->req.cmd.len);
44649ab747fSPaolo Bonzini     }
44749ab747fSPaolo Bonzini 
44849ab747fSPaolo Bonzini     if (r->req.cmd.xfer == 0) {
44949ab747fSPaolo Bonzini         g_free(r->buf);
45049ab747fSPaolo Bonzini         r->buflen = 0;
45149ab747fSPaolo Bonzini         r->buf = NULL;
45249ab747fSPaolo Bonzini         /* The request is used as the AIO opaque value, so add a ref.  */
45349ab747fSPaolo Bonzini         scsi_req_ref(&r->req);
4544be74634SMarkus Armbruster         ret = execute_command(s->conf.blk, r, SG_DXFER_NONE,
4554be74634SMarkus Armbruster                               scsi_command_complete);
45649ab747fSPaolo Bonzini         if (ret < 0) {
457fa0d653bSPaolo Bonzini             scsi_command_complete_noio(r, ret);
45849ab747fSPaolo Bonzini             return 0;
45949ab747fSPaolo Bonzini         }
46049ab747fSPaolo Bonzini         return 0;
46149ab747fSPaolo Bonzini     }
46249ab747fSPaolo Bonzini 
46349ab747fSPaolo Bonzini     if (r->buflen != r->req.cmd.xfer) {
46449ab747fSPaolo Bonzini         g_free(r->buf);
46549ab747fSPaolo Bonzini         r->buf = g_malloc(r->req.cmd.xfer);
46649ab747fSPaolo Bonzini         r->buflen = r->req.cmd.xfer;
46749ab747fSPaolo Bonzini     }
46849ab747fSPaolo Bonzini 
46949ab747fSPaolo Bonzini     memset(r->buf, 0, r->buflen);
47049ab747fSPaolo Bonzini     r->len = r->req.cmd.xfer;
47149ab747fSPaolo Bonzini     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
47249ab747fSPaolo Bonzini         r->len = 0;
47349ab747fSPaolo Bonzini         return -r->req.cmd.xfer;
47449ab747fSPaolo Bonzini     } else {
47549ab747fSPaolo Bonzini         return r->req.cmd.xfer;
47649ab747fSPaolo Bonzini     }
47749ab747fSPaolo Bonzini }
47849ab747fSPaolo Bonzini 
4799fd7e859SPaolo Bonzini static int read_naa_id(const uint8_t *p, uint64_t *p_wwn)
4809fd7e859SPaolo Bonzini {
4819fd7e859SPaolo Bonzini     int i;
4829fd7e859SPaolo Bonzini 
4839fd7e859SPaolo Bonzini     if ((p[1] & 0xF) == 3) {
4849fd7e859SPaolo Bonzini         /* NAA designator type */
4859fd7e859SPaolo Bonzini         if (p[3] != 8) {
4869fd7e859SPaolo Bonzini             return -EINVAL;
4879fd7e859SPaolo Bonzini         }
4889fd7e859SPaolo Bonzini         *p_wwn = ldq_be_p(p + 4);
4899fd7e859SPaolo Bonzini         return 0;
4909fd7e859SPaolo Bonzini     }
4919fd7e859SPaolo Bonzini 
4929fd7e859SPaolo Bonzini     if ((p[1] & 0xF) == 8) {
4939fd7e859SPaolo Bonzini         /* SCSI name string designator type */
4949fd7e859SPaolo Bonzini         if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) {
4959fd7e859SPaolo Bonzini             return -EINVAL;
4969fd7e859SPaolo Bonzini         }
4979fd7e859SPaolo Bonzini         if (p[3] > 20 && p[24] != ',') {
4989fd7e859SPaolo Bonzini             return -EINVAL;
4999fd7e859SPaolo Bonzini         }
5009fd7e859SPaolo Bonzini         *p_wwn = 0;
5019fd7e859SPaolo Bonzini         for (i = 8; i < 24; i++) {
50295a5befcSPeter Maydell             char c = qemu_toupper(p[i]);
5039fd7e859SPaolo Bonzini             c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10);
5049fd7e859SPaolo Bonzini             *p_wwn = (*p_wwn << 4) | c;
5059fd7e859SPaolo Bonzini         }
5069fd7e859SPaolo Bonzini         return 0;
5079fd7e859SPaolo Bonzini     }
5089fd7e859SPaolo Bonzini 
5099fd7e859SPaolo Bonzini     return -EINVAL;
5109fd7e859SPaolo Bonzini }
5119fd7e859SPaolo Bonzini 
512a0c7e35bSDaniel Henrique Barboza int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size,
513c9b6609bSHannes Reinecke                         uint8_t *buf, uint8_t buf_size, uint32_t timeout)
514a0c7e35bSDaniel Henrique Barboza {
515a0c7e35bSDaniel Henrique Barboza     sg_io_hdr_t io_header;
516a0c7e35bSDaniel Henrique Barboza     uint8_t sensebuf[8];
517a0c7e35bSDaniel Henrique Barboza     int ret;
518a0c7e35bSDaniel Henrique Barboza 
519a0c7e35bSDaniel Henrique Barboza     memset(&io_header, 0, sizeof(io_header));
520a0c7e35bSDaniel Henrique Barboza     io_header.interface_id = 'S';
521a0c7e35bSDaniel Henrique Barboza     io_header.dxfer_direction = SG_DXFER_FROM_DEV;
522a0c7e35bSDaniel Henrique Barboza     io_header.dxfer_len = buf_size;
523a0c7e35bSDaniel Henrique Barboza     io_header.dxferp = buf;
524a0c7e35bSDaniel Henrique Barboza     io_header.cmdp = cmd;
525a0c7e35bSDaniel Henrique Barboza     io_header.cmd_len = cmd_size;
526a0c7e35bSDaniel Henrique Barboza     io_header.mx_sb_len = sizeof(sensebuf);
527a0c7e35bSDaniel Henrique Barboza     io_header.sbp = sensebuf;
528c9b6609bSHannes Reinecke     io_header.timeout = timeout * 1000;
529a0c7e35bSDaniel Henrique Barboza 
530*b2d50a33SHannes Reinecke     trace_scsi_generic_ioctl_sgio_command(cmd[0], io_header.timeout);
531a0c7e35bSDaniel Henrique Barboza     ret = blk_ioctl(blk, SG_IO, &io_header);
532*b2d50a33SHannes Reinecke     if (ret < 0 || io_header.status ||
533*b2d50a33SHannes Reinecke         io_header.driver_status || io_header.host_status) {
534*b2d50a33SHannes Reinecke         trace_scsi_generic_ioctl_sgio_done(cmd[0], ret, io_header.status,
535*b2d50a33SHannes Reinecke                                            io_header.host_status);
536a0c7e35bSDaniel Henrique Barboza         return -1;
537a0c7e35bSDaniel Henrique Barboza     }
538a0c7e35bSDaniel Henrique Barboza     return 0;
539a0c7e35bSDaniel Henrique Barboza }
540a0c7e35bSDaniel Henrique Barboza 
541a71c775bSDaniel Henrique Barboza /*
542a71c775bSDaniel Henrique Barboza  * Executes an INQUIRY request with EVPD set to retrieve the
543a71c775bSDaniel Henrique Barboza  * available VPD pages of the device. If the device does
544a71c775bSDaniel Henrique Barboza  * not support the Block Limits page (page 0xb0), set
545a71c775bSDaniel Henrique Barboza  * the needs_vpd_bl_emulation flag for future use.
546a71c775bSDaniel Henrique Barboza  */
547a71c775bSDaniel Henrique Barboza static void scsi_generic_set_vpd_bl_emulation(SCSIDevice *s)
548a71c775bSDaniel Henrique Barboza {
549a71c775bSDaniel Henrique Barboza     uint8_t cmd[6];
550a71c775bSDaniel Henrique Barboza     uint8_t buf[250];
551a71c775bSDaniel Henrique Barboza     uint8_t page_len;
552a71c775bSDaniel Henrique Barboza     int ret, i;
553a71c775bSDaniel Henrique Barboza 
554a71c775bSDaniel Henrique Barboza     memset(cmd, 0, sizeof(cmd));
555a71c775bSDaniel Henrique Barboza     memset(buf, 0, sizeof(buf));
556a71c775bSDaniel Henrique Barboza     cmd[0] = INQUIRY;
557a71c775bSDaniel Henrique Barboza     cmd[1] = 1;
558a71c775bSDaniel Henrique Barboza     cmd[2] = 0x00;
559a71c775bSDaniel Henrique Barboza     cmd[4] = sizeof(buf);
560a71c775bSDaniel Henrique Barboza 
561a71c775bSDaniel Henrique Barboza     ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
562c9b6609bSHannes Reinecke                               buf, sizeof(buf), s->io_timeout);
563a71c775bSDaniel Henrique Barboza     if (ret < 0) {
564a71c775bSDaniel Henrique Barboza         /*
565a71c775bSDaniel Henrique Barboza          * Do not assume anything if we can't retrieve the
566a71c775bSDaniel Henrique Barboza          * INQUIRY response to assert the VPD Block Limits
567a71c775bSDaniel Henrique Barboza          * support.
568a71c775bSDaniel Henrique Barboza          */
569a71c775bSDaniel Henrique Barboza         s->needs_vpd_bl_emulation = false;
570a71c775bSDaniel Henrique Barboza         return;
571a71c775bSDaniel Henrique Barboza     }
572a71c775bSDaniel Henrique Barboza 
573a71c775bSDaniel Henrique Barboza     page_len = buf[3];
57457dbb58dSPaolo Bonzini     for (i = 4; i < MIN(sizeof(buf), page_len + 4); i++) {
575a71c775bSDaniel Henrique Barboza         if (buf[i] == 0xb0) {
576a71c775bSDaniel Henrique Barboza             s->needs_vpd_bl_emulation = false;
577a71c775bSDaniel Henrique Barboza             return;
578a71c775bSDaniel Henrique Barboza         }
579a71c775bSDaniel Henrique Barboza     }
580a71c775bSDaniel Henrique Barboza     s->needs_vpd_bl_emulation = true;
581a71c775bSDaniel Henrique Barboza }
582a71c775bSDaniel Henrique Barboza 
583a71c775bSDaniel Henrique Barboza static void scsi_generic_read_device_identification(SCSIDevice *s)
5849fd7e859SPaolo Bonzini {
5859fd7e859SPaolo Bonzini     uint8_t cmd[6];
5869fd7e859SPaolo Bonzini     uint8_t buf[250];
5879fd7e859SPaolo Bonzini     int ret;
5889fd7e859SPaolo Bonzini     int i, len;
5899fd7e859SPaolo Bonzini 
5909fd7e859SPaolo Bonzini     memset(cmd, 0, sizeof(cmd));
5919fd7e859SPaolo Bonzini     memset(buf, 0, sizeof(buf));
5929fd7e859SPaolo Bonzini     cmd[0] = INQUIRY;
5939fd7e859SPaolo Bonzini     cmd[1] = 1;
5949fd7e859SPaolo Bonzini     cmd[2] = 0x83;
5959fd7e859SPaolo Bonzini     cmd[4] = sizeof(buf);
5969fd7e859SPaolo Bonzini 
597a0c7e35bSDaniel Henrique Barboza     ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
598c9b6609bSHannes Reinecke                               buf, sizeof(buf), s->io_timeout);
599a0c7e35bSDaniel Henrique Barboza     if (ret < 0) {
6009fd7e859SPaolo Bonzini         return;
6019fd7e859SPaolo Bonzini     }
6029fd7e859SPaolo Bonzini 
6039fd7e859SPaolo Bonzini     len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4);
6049fd7e859SPaolo Bonzini     for (i = 0; i + 3 <= len; ) {
6059fd7e859SPaolo Bonzini         const uint8_t *p = &buf[i + 4];
6069fd7e859SPaolo Bonzini         uint64_t wwn;
6079fd7e859SPaolo Bonzini 
6089fd7e859SPaolo Bonzini         if (i + (p[3] + 4) > len) {
6099fd7e859SPaolo Bonzini             break;
6109fd7e859SPaolo Bonzini         }
6119fd7e859SPaolo Bonzini 
6129fd7e859SPaolo Bonzini         if ((p[1] & 0x10) == 0) {
6139fd7e859SPaolo Bonzini             /* Associated with the logical unit */
6149fd7e859SPaolo Bonzini             if (read_naa_id(p, &wwn) == 0) {
6159fd7e859SPaolo Bonzini                 s->wwn = wwn;
6169fd7e859SPaolo Bonzini             }
6179fd7e859SPaolo Bonzini         } else if ((p[1] & 0x10) == 0x10) {
6189fd7e859SPaolo Bonzini             /* Associated with the target port */
6199fd7e859SPaolo Bonzini             if (read_naa_id(p, &wwn) == 0) {
6209fd7e859SPaolo Bonzini                 s->port_wwn = wwn;
6219fd7e859SPaolo Bonzini             }
6229fd7e859SPaolo Bonzini         }
6239fd7e859SPaolo Bonzini 
6249fd7e859SPaolo Bonzini         i += p[3] + 4;
6259fd7e859SPaolo Bonzini     }
6269fd7e859SPaolo Bonzini }
6279fd7e859SPaolo Bonzini 
628a71c775bSDaniel Henrique Barboza void scsi_generic_read_device_inquiry(SCSIDevice *s)
629a71c775bSDaniel Henrique Barboza {
630a71c775bSDaniel Henrique Barboza     scsi_generic_read_device_identification(s);
631afff2db6SDmitry Fomichev     if (s->type == TYPE_DISK || s->type == TYPE_ZBC) {
632a71c775bSDaniel Henrique Barboza         scsi_generic_set_vpd_bl_emulation(s);
633a71c775bSDaniel Henrique Barboza     } else {
634a71c775bSDaniel Henrique Barboza         s->needs_vpd_bl_emulation = false;
635a71c775bSDaniel Henrique Barboza     }
636a71c775bSDaniel Henrique Barboza }
637a71c775bSDaniel Henrique Barboza 
6384be74634SMarkus Armbruster static int get_stream_blocksize(BlockBackend *blk)
63949ab747fSPaolo Bonzini {
64049ab747fSPaolo Bonzini     uint8_t cmd[6];
64149ab747fSPaolo Bonzini     uint8_t buf[12];
64249ab747fSPaolo Bonzini     int ret;
64349ab747fSPaolo Bonzini 
64449ab747fSPaolo Bonzini     memset(cmd, 0, sizeof(cmd));
64549ab747fSPaolo Bonzini     memset(buf, 0, sizeof(buf));
64649ab747fSPaolo Bonzini     cmd[0] = MODE_SENSE;
64749ab747fSPaolo Bonzini     cmd[4] = sizeof(buf);
64849ab747fSPaolo Bonzini 
649c9b6609bSHannes Reinecke     ret = scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf), 6);
650a0c7e35bSDaniel Henrique Barboza     if (ret < 0) {
65149ab747fSPaolo Bonzini         return -1;
65249ab747fSPaolo Bonzini     }
653a0c7e35bSDaniel Henrique Barboza 
65449ab747fSPaolo Bonzini     return (buf[9] << 16) | (buf[10] << 8) | buf[11];
65549ab747fSPaolo Bonzini }
65649ab747fSPaolo Bonzini 
65749ab747fSPaolo Bonzini static void scsi_generic_reset(DeviceState *dev)
65849ab747fSPaolo Bonzini {
65949ab747fSPaolo Bonzini     SCSIDevice *s = SCSI_DEVICE(dev);
66049ab747fSPaolo Bonzini 
6612343be0dSPaolo Bonzini     s->scsi_version = s->default_scsi_version;
66249ab747fSPaolo Bonzini     scsi_device_purge_requests(s, SENSE_CODE(RESET));
66349ab747fSPaolo Bonzini }
66449ab747fSPaolo Bonzini 
665a818a4b6SFam Zheng static void scsi_generic_realize(SCSIDevice *s, Error **errp)
66649ab747fSPaolo Bonzini {
6676ee143a0SPaolo Bonzini     int rc;
66849ab747fSPaolo Bonzini     int sg_version;
66949ab747fSPaolo Bonzini     struct sg_scsi_id scsiid;
67049ab747fSPaolo Bonzini 
6714be74634SMarkus Armbruster     if (!s->conf.blk) {
672a818a4b6SFam Zheng         error_setg(errp, "drive property not set");
673a818a4b6SFam Zheng         return;
67449ab747fSPaolo Bonzini     }
67549ab747fSPaolo Bonzini 
6764be74634SMarkus Armbruster     if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
677a818a4b6SFam Zheng         error_setg(errp, "Device doesn't support drive option werror");
678a818a4b6SFam Zheng         return;
67949ab747fSPaolo Bonzini     }
6804be74634SMarkus Armbruster     if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
681a818a4b6SFam Zheng         error_setg(errp, "Device doesn't support drive option rerror");
682a818a4b6SFam Zheng         return;
68349ab747fSPaolo Bonzini     }
68449ab747fSPaolo Bonzini 
68549ab747fSPaolo Bonzini     /* check we are using a driver managing SG_IO (version 3 and after */
6864be74634SMarkus Armbruster     rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version);
6876ee143a0SPaolo Bonzini     if (rc < 0) {
68809c2c6ffSPaolo Bonzini         error_setg_errno(errp, -rc, "cannot get SG_IO version number");
68909c2c6ffSPaolo Bonzini         if (rc != -EPERM) {
69009c2c6ffSPaolo Bonzini             error_append_hint(errp, "Is this a SCSI device?\n");
69109c2c6ffSPaolo Bonzini         }
692a818a4b6SFam Zheng         return;
69349ab747fSPaolo Bonzini     }
69449ab747fSPaolo Bonzini     if (sg_version < 30000) {
695a818a4b6SFam Zheng         error_setg(errp, "scsi generic interface too old");
696a818a4b6SFam Zheng         return;
69749ab747fSPaolo Bonzini     }
69849ab747fSPaolo Bonzini 
69949ab747fSPaolo Bonzini     /* get LUN of the /dev/sg? */
7004be74634SMarkus Armbruster     if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) {
701a818a4b6SFam Zheng         error_setg(errp, "SG_GET_SCSI_ID ioctl failed");
702a818a4b6SFam Zheng         return;
70349ab747fSPaolo Bonzini     }
704c6caae55SFam Zheng     if (!blkconf_apply_backend_options(&s->conf,
70586b1cf32SKevin Wolf                                        !blk_supports_write_perm(s->conf.blk),
706c6caae55SFam Zheng                                        true, errp)) {
707d9bcd6f7SFam Zheng         return;
708d9bcd6f7SFam Zheng     }
70949ab747fSPaolo Bonzini 
71049ab747fSPaolo Bonzini     /* define device state */
71149ab747fSPaolo Bonzini     s->type = scsiid.scsi_type;
71256853498SLaurent Vivier     trace_scsi_generic_realize_type(s->type);
71349ab747fSPaolo Bonzini 
71449ab747fSPaolo Bonzini     switch (s->type) {
71549ab747fSPaolo Bonzini     case TYPE_TAPE:
7164be74634SMarkus Armbruster         s->blocksize = get_stream_blocksize(s->conf.blk);
71749ab747fSPaolo Bonzini         if (s->blocksize == -1) {
71849ab747fSPaolo Bonzini             s->blocksize = 0;
71949ab747fSPaolo Bonzini         }
72049ab747fSPaolo Bonzini         break;
72149ab747fSPaolo Bonzini 
72249ab747fSPaolo Bonzini         /* Make a guess for block devices, we'll fix it when the guest sends.
72349ab747fSPaolo Bonzini          * READ CAPACITY.  If they don't, they likely would assume these sizes
72449ab747fSPaolo Bonzini          * anyway. (TODO: they could also send MODE SENSE).
72549ab747fSPaolo Bonzini          */
72649ab747fSPaolo Bonzini     case TYPE_ROM:
72749ab747fSPaolo Bonzini     case TYPE_WORM:
72849ab747fSPaolo Bonzini         s->blocksize = 2048;
72949ab747fSPaolo Bonzini         break;
73049ab747fSPaolo Bonzini     default:
73149ab747fSPaolo Bonzini         s->blocksize = 512;
73249ab747fSPaolo Bonzini         break;
73349ab747fSPaolo Bonzini     }
73449ab747fSPaolo Bonzini 
73556853498SLaurent Vivier     trace_scsi_generic_realize_blocksize(s->blocksize);
7369fd7e859SPaolo Bonzini 
73729e560f0SDaniel Henrique Barboza     /* Only used by scsi-block, but initialize it nevertheless to be clean.  */
73829e560f0SDaniel Henrique Barboza     s->default_scsi_version = -1;
739c9b6609bSHannes Reinecke     s->io_timeout = DEFAULT_IO_TIMEOUT;
740a71c775bSDaniel Henrique Barboza     scsi_generic_read_device_inquiry(s);
74149ab747fSPaolo Bonzini }
74249ab747fSPaolo Bonzini 
74349ab747fSPaolo Bonzini const SCSIReqOps scsi_generic_req_ops = {
74449ab747fSPaolo Bonzini     .size         = sizeof(SCSIGenericReq),
74549ab747fSPaolo Bonzini     .free_req     = scsi_free_request,
74649ab747fSPaolo Bonzini     .send_command = scsi_send_command,
74749ab747fSPaolo Bonzini     .read_data    = scsi_read_data,
74849ab747fSPaolo Bonzini     .write_data   = scsi_write_data,
74949ab747fSPaolo Bonzini     .get_buf      = scsi_get_buf,
75049ab747fSPaolo Bonzini     .load_request = scsi_generic_load_request,
75149ab747fSPaolo Bonzini     .save_request = scsi_generic_save_request,
75249ab747fSPaolo Bonzini };
75349ab747fSPaolo Bonzini 
75449ab747fSPaolo Bonzini static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
75549ab747fSPaolo Bonzini                                      uint8_t *buf, void *hba_private)
75649ab747fSPaolo Bonzini {
7579be38598SEduardo Habkost     return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
75849ab747fSPaolo Bonzini }
75949ab747fSPaolo Bonzini 
76049ab747fSPaolo Bonzini static Property scsi_generic_properties[] = {
7614be74634SMarkus Armbruster     DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
762d9bcd6f7SFam Zheng     DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false),
763c9b6609bSHannes Reinecke     DEFINE_PROP_UINT32("io_timeout", SCSIDevice, io_timeout,
764c9b6609bSHannes Reinecke                        DEFAULT_IO_TIMEOUT),
76549ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
76649ab747fSPaolo Bonzini };
76749ab747fSPaolo Bonzini 
7683e7e180aSPaolo Bonzini static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
7693e7e180aSPaolo Bonzini                                   uint8_t *buf, void *hba_private)
7703e7e180aSPaolo Bonzini {
7713e7e180aSPaolo Bonzini     return scsi_bus_parse_cdb(dev, cmd, buf, hba_private);
7723e7e180aSPaolo Bonzini }
7733e7e180aSPaolo Bonzini 
77449ab747fSPaolo Bonzini static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
77549ab747fSPaolo Bonzini {
77649ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
77749ab747fSPaolo Bonzini     SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
77849ab747fSPaolo Bonzini 
779a818a4b6SFam Zheng     sc->realize      = scsi_generic_realize;
78049ab747fSPaolo Bonzini     sc->alloc_req    = scsi_new_request;
7813e7e180aSPaolo Bonzini     sc->parse_cdb    = scsi_generic_parse_cdb;
78249ab747fSPaolo Bonzini     dc->fw_name = "disk";
78349ab747fSPaolo Bonzini     dc->desc = "pass through generic scsi device (/dev/sg*)";
78449ab747fSPaolo Bonzini     dc->reset = scsi_generic_reset;
7854f67d30bSMarc-André Lureau     device_class_set_props(dc, scsi_generic_properties);
78649ab747fSPaolo Bonzini     dc->vmsd  = &vmstate_scsi_device;
78749ab747fSPaolo Bonzini }
78849ab747fSPaolo Bonzini 
78949ab747fSPaolo Bonzini static const TypeInfo scsi_generic_info = {
79049ab747fSPaolo Bonzini     .name          = "scsi-generic",
79149ab747fSPaolo Bonzini     .parent        = TYPE_SCSI_DEVICE,
79249ab747fSPaolo Bonzini     .instance_size = sizeof(SCSIDevice),
79349ab747fSPaolo Bonzini     .class_init    = scsi_generic_class_initfn,
79449ab747fSPaolo Bonzini };
79549ab747fSPaolo Bonzini 
79649ab747fSPaolo Bonzini static void scsi_generic_register_types(void)
79749ab747fSPaolo Bonzini {
79849ab747fSPaolo Bonzini     type_register_static(&scsi_generic_info);
79949ab747fSPaolo Bonzini }
80049ab747fSPaolo Bonzini 
80149ab747fSPaolo Bonzini type_init(scsi_generic_register_types)
80249ab747fSPaolo Bonzini 
80349ab747fSPaolo Bonzini #endif /* __linux__ */
804