xref: /qemu/hw/scsi/scsi-generic.c (revision 3d4a8bf0)
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"
19*3d4a8bf0SPaolo Bonzini #include "hw/scsi/emulation.h"
204be74634SMarkus Armbruster #include "sysemu/block-backend.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 
1460a96ca24SDaniel Henrique Barboza static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
1470a96ca24SDaniel Henrique Barboza {
1486c219fc8SPaolo Bonzini     uint8_t page, page_idx;
149a71c775bSDaniel Henrique Barboza 
1500a96ca24SDaniel Henrique Barboza     /*
1510a96ca24SDaniel Henrique Barboza      *  EVPD set to zero returns the standard INQUIRY data.
1520a96ca24SDaniel Henrique Barboza      *
1530a96ca24SDaniel Henrique Barboza      *  Check if scsi_version is unset (-1) to avoid re-defining it
1540a96ca24SDaniel Henrique Barboza      *  each time an INQUIRY with standard data is received.
1550a96ca24SDaniel Henrique Barboza      *  scsi_version is initialized with -1 in scsi_generic_reset
1560a96ca24SDaniel Henrique Barboza      *  and scsi_disk_reset, making sure that we'll set the
1570a96ca24SDaniel Henrique Barboza      *  scsi_version after a reset. If the version field of the
1580a96ca24SDaniel Henrique Barboza      *  INQUIRY response somehow changes after a guest reboot,
1590a96ca24SDaniel Henrique Barboza      *  we'll be able to keep track of it.
1600a96ca24SDaniel Henrique Barboza      *
1610a96ca24SDaniel Henrique Barboza      *  On SCSI-2 and older, first 3 bits of byte 2 is the
1620a96ca24SDaniel Henrique Barboza      *  ANSI-approved version, while on later versions the
1630a96ca24SDaniel Henrique Barboza      *  whole byte 2 contains the version. Check if we're dealing
1640a96ca24SDaniel Henrique Barboza      *  with a newer version and, in that case, assign the
1650a96ca24SDaniel Henrique Barboza      *  whole byte.
1660a96ca24SDaniel Henrique Barboza      */
1670a96ca24SDaniel Henrique Barboza     if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) {
1680a96ca24SDaniel Henrique Barboza         s->scsi_version = r->buf[2] & 0x07;
1690a96ca24SDaniel Henrique Barboza         if (s->scsi_version > 2) {
1700a96ca24SDaniel Henrique Barboza             s->scsi_version = r->buf[2];
1710a96ca24SDaniel Henrique Barboza         }
1720a96ca24SDaniel Henrique Barboza     }
173a71c775bSDaniel Henrique Barboza 
174a71c775bSDaniel Henrique Barboza     if (s->type == TYPE_DISK && (r->req.cmd.buf[1] & 0x01)) {
175a71c775bSDaniel Henrique Barboza         page = r->req.cmd.buf[2];
176a71c775bSDaniel Henrique Barboza         if (page == 0xb0) {
1770a96ca24SDaniel Henrique Barboza             uint32_t max_transfer =
1780a96ca24SDaniel Henrique Barboza                 blk_get_max_transfer(s->conf.blk) / s->blocksize;
1790a96ca24SDaniel Henrique Barboza 
1800a96ca24SDaniel Henrique Barboza             assert(max_transfer);
1810a96ca24SDaniel Henrique Barboza             stl_be_p(&r->buf[8], max_transfer);
1820a96ca24SDaniel Henrique Barboza             /* Also take care of the opt xfer len. */
1830a96ca24SDaniel Henrique Barboza             stl_be_p(&r->buf[12],
1840a96ca24SDaniel Henrique Barboza                     MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
185*3d4a8bf0SPaolo Bonzini         } else if (s->needs_vpd_bl_emulation && page == 0x00) {
186a71c775bSDaniel Henrique Barboza             /*
187a71c775bSDaniel Henrique Barboza              * Now we're capable of supplying the VPD Block Limits
188a71c775bSDaniel Henrique Barboza              * response if the hardware can't. Add it in the INQUIRY
189a71c775bSDaniel Henrique Barboza              * Supported VPD pages response in case we are using the
190a71c775bSDaniel Henrique Barboza              * emulation for this device.
191a71c775bSDaniel Henrique Barboza              *
192a71c775bSDaniel Henrique Barboza              * This way, the guest kernel will be aware of the support
193a71c775bSDaniel Henrique Barboza              * and will use it to proper setup the SCSI device.
1946c219fc8SPaolo Bonzini              *
1956c219fc8SPaolo Bonzini              * VPD page numbers must be sorted, so insert 0xb0 at the
1966c219fc8SPaolo Bonzini              * right place with an in-place insert.  After the initialization
1976c219fc8SPaolo Bonzini              * part of the for loop is executed, the device response is
1986c219fc8SPaolo Bonzini              * at r[0] to r[page_idx - 1].
199a71c775bSDaniel Henrique Barboza              */
2006c219fc8SPaolo Bonzini             for (page_idx = lduw_be_p(r->buf + 2) + 4;
2016c219fc8SPaolo Bonzini                  page_idx > 4 && r->buf[page_idx - 1] >= 0xb0;
2026c219fc8SPaolo Bonzini                  page_idx--) {
2036c219fc8SPaolo Bonzini                 if (page_idx < r->buflen) {
2046c219fc8SPaolo Bonzini                     r->buf[page_idx] = r->buf[page_idx - 1];
2056c219fc8SPaolo Bonzini                 }
2066c219fc8SPaolo Bonzini             }
2076c219fc8SPaolo Bonzini             r->buf[page_idx] = 0xb0;
2086c219fc8SPaolo Bonzini             stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1);
2090a96ca24SDaniel Henrique Barboza         }
2100a96ca24SDaniel Henrique Barboza     }
211a71c775bSDaniel Henrique Barboza }
212a71c775bSDaniel Henrique Barboza 
213*3d4a8bf0SPaolo Bonzini static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s)
214a71c775bSDaniel Henrique Barboza {
215*3d4a8bf0SPaolo Bonzini     int len;
216*3d4a8bf0SPaolo Bonzini     uint8_t buf[64];
217*3d4a8bf0SPaolo Bonzini 
218*3d4a8bf0SPaolo Bonzini     SCSIBlockLimits bl = {
219*3d4a8bf0SPaolo Bonzini         .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize
220*3d4a8bf0SPaolo Bonzini     };
221*3d4a8bf0SPaolo Bonzini 
222*3d4a8bf0SPaolo Bonzini     memset(r->buf, 0, r->buflen);
223*3d4a8bf0SPaolo Bonzini     stb_p(buf, s->type);
224*3d4a8bf0SPaolo Bonzini     stb_p(buf + 1, 0xb0);
225*3d4a8bf0SPaolo Bonzini     len = scsi_emulate_block_limits(buf + 4, &bl);
226*3d4a8bf0SPaolo Bonzini     assert(len <= sizeof(buf) - 4);
227*3d4a8bf0SPaolo Bonzini     stw_be_p(buf + 2, len);
228*3d4a8bf0SPaolo Bonzini 
229*3d4a8bf0SPaolo Bonzini     memcpy(r->buf, buf, MIN(r->buflen, len + 4));
230*3d4a8bf0SPaolo Bonzini 
231a71c775bSDaniel Henrique Barboza     r->io_header.sb_len_wr = 0;
232a71c775bSDaniel Henrique Barboza 
233a71c775bSDaniel Henrique Barboza     /*
234a71c775bSDaniel Henrique Barboza     * We have valid contents in the reply buffer but the
235a71c775bSDaniel Henrique Barboza     * io_header can report a sense error coming from
236a71c775bSDaniel Henrique Barboza     * the hardware in scsi_command_complete_noio. Clean
237a71c775bSDaniel Henrique Barboza     * up the io_header to avoid reporting it.
238a71c775bSDaniel Henrique Barboza     */
239a71c775bSDaniel Henrique Barboza     r->io_header.driver_status = 0;
240a71c775bSDaniel Henrique Barboza     r->io_header.status = 0;
241a71c775bSDaniel Henrique Barboza 
242a71c775bSDaniel Henrique Barboza     return r->buflen;
243a71c775bSDaniel Henrique Barboza }
2440a96ca24SDaniel Henrique Barboza 
24549ab747fSPaolo Bonzini static void scsi_read_complete(void * opaque, int ret)
24649ab747fSPaolo Bonzini {
24749ab747fSPaolo Bonzini     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
24849ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
249a71c775bSDaniel Henrique Barboza     SCSISense sense;
25049ab747fSPaolo Bonzini     int len;
25149ab747fSPaolo Bonzini 
252fa0d653bSPaolo Bonzini     assert(r->req.aiocb != NULL);
25349ab747fSPaolo Bonzini     r->req.aiocb = NULL;
254fa0d653bSPaolo Bonzini 
255b9e413ddSPaolo Bonzini     aio_context_acquire(blk_get_aio_context(s->conf.blk));
256b9e413ddSPaolo Bonzini 
2576c25fa6cSFam Zheng     if (ret || r->req.io_canceled) {
258fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
259b9e413ddSPaolo Bonzini         goto done;
26049ab747fSPaolo Bonzini     }
261fa0d653bSPaolo Bonzini 
26249ab747fSPaolo Bonzini     len = r->io_header.dxfer_len - r->io_header.resid;
26349ab747fSPaolo Bonzini     DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
26449ab747fSPaolo Bonzini 
26549ab747fSPaolo Bonzini     r->len = -1;
266a71c775bSDaniel Henrique Barboza 
267a71c775bSDaniel Henrique Barboza     /*
268a71c775bSDaniel Henrique Barboza      * Check if this is a VPD Block Limits request that
269a71c775bSDaniel Henrique Barboza      * resulted in sense error but would need emulation.
270a71c775bSDaniel Henrique Barboza      * In this case, emulate a valid VPD response.
271a71c775bSDaniel Henrique Barboza      */
272*3d4a8bf0SPaolo Bonzini     if (s->needs_vpd_bl_emulation &&
273*3d4a8bf0SPaolo Bonzini         r->req.cmd.buf[0] == INQUIRY &&
274*3d4a8bf0SPaolo Bonzini         (r->req.cmd.buf[1] & 0x01) &&
275*3d4a8bf0SPaolo Bonzini         r->req.cmd.buf[2] == 0xb0) {
276*3d4a8bf0SPaolo Bonzini         if (sg_io_sense_from_errno(-ret, &r->io_header, &sense)) {
277*3d4a8bf0SPaolo Bonzini             len = scsi_generic_emulate_block_limits(r, s);
278a71c775bSDaniel Henrique Barboza             /*
279a71c775bSDaniel Henrique Barboza              * No need to let scsi_read_complete go on and handle an
280a71c775bSDaniel Henrique Barboza              * INQUIRY VPD BL request we created manually.
281a71c775bSDaniel Henrique Barboza              */
282a71c775bSDaniel Henrique Barboza             goto req_complete;
283a71c775bSDaniel Henrique Barboza         }
284a71c775bSDaniel Henrique Barboza     }
285a71c775bSDaniel Henrique Barboza 
28649ab747fSPaolo Bonzini     if (len == 0) {
287fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, 0);
288b9e413ddSPaolo Bonzini         goto done;
289fa0d653bSPaolo Bonzini     }
290fa0d653bSPaolo Bonzini 
29149ab747fSPaolo Bonzini     /* Snoop READ CAPACITY output to set the blocksize.  */
29253254e56SPaolo Bonzini     if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
29353254e56SPaolo Bonzini         (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
29449ab747fSPaolo Bonzini         s->blocksize = ldl_be_p(&r->buf[4]);
29553254e56SPaolo Bonzini         s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
29649ab747fSPaolo Bonzini     } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
29749ab747fSPaolo Bonzini                (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
29849ab747fSPaolo Bonzini         s->blocksize = ldl_be_p(&r->buf[8]);
29949ab747fSPaolo Bonzini         s->max_lba = ldq_be_p(&r->buf[0]);
30049ab747fSPaolo Bonzini     }
3014be74634SMarkus Armbruster     blk_set_guest_block_size(s->conf.blk, s->blocksize);
30249ab747fSPaolo Bonzini 
3030eb2baebSPaolo Bonzini     /* Patch MODE SENSE device specific parameters if the BDS is opened
3040eb2baebSPaolo Bonzini      * readonly.
3050eb2baebSPaolo Bonzini      */
3060eb2baebSPaolo Bonzini     if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) &&
3070eb2baebSPaolo Bonzini         blk_is_read_only(s->conf.blk) &&
3080eb2baebSPaolo Bonzini         (r->req.cmd.buf[0] == MODE_SENSE ||
3090eb2baebSPaolo Bonzini          r->req.cmd.buf[0] == MODE_SENSE_10) &&
3100eb2baebSPaolo Bonzini         (r->req.cmd.buf[1] & 0x8) == 0) {
3110eb2baebSPaolo Bonzini         if (r->req.cmd.buf[0] == MODE_SENSE) {
3120eb2baebSPaolo Bonzini             r->buf[2] |= 0x80;
3130eb2baebSPaolo Bonzini         } else  {
3140eb2baebSPaolo Bonzini             r->buf[3] |= 0x80;
3150eb2baebSPaolo Bonzini         }
3160eb2baebSPaolo Bonzini     }
31729e560f0SDaniel Henrique Barboza     if (r->req.cmd.buf[0] == INQUIRY) {
3180a96ca24SDaniel Henrique Barboza         scsi_handle_inquiry_reply(r, s);
31929e560f0SDaniel Henrique Barboza     }
320a71c775bSDaniel Henrique Barboza 
321a71c775bSDaniel Henrique Barboza req_complete:
32249ab747fSPaolo Bonzini     scsi_req_data(&r->req, len);
32349ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
324b9e413ddSPaolo Bonzini 
325b9e413ddSPaolo Bonzini done:
326b9e413ddSPaolo Bonzini     aio_context_release(blk_get_aio_context(s->conf.blk));
32749ab747fSPaolo Bonzini }
32849ab747fSPaolo Bonzini 
32949ab747fSPaolo Bonzini /* Read more data from scsi device into buffer.  */
33049ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req)
33149ab747fSPaolo Bonzini {
33249ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
33349ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
33449ab747fSPaolo Bonzini     int ret;
33549ab747fSPaolo Bonzini 
3362e144aa7SEric Farman     DPRINTF("scsi_read_data tag=0x%x\n", req->tag);
33749ab747fSPaolo Bonzini 
33849ab747fSPaolo Bonzini     /* The request is used as the AIO opaque value, so add a ref.  */
33949ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
34049ab747fSPaolo Bonzini     if (r->len == -1) {
341fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, 0);
34249ab747fSPaolo Bonzini         return;
34349ab747fSPaolo Bonzini     }
34449ab747fSPaolo Bonzini 
3454be74634SMarkus Armbruster     ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV,
3464be74634SMarkus Armbruster                           scsi_read_complete);
34749ab747fSPaolo Bonzini     if (ret < 0) {
348fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
34949ab747fSPaolo Bonzini     }
35049ab747fSPaolo Bonzini }
35149ab747fSPaolo Bonzini 
35249ab747fSPaolo Bonzini static void scsi_write_complete(void * opaque, int ret)
35349ab747fSPaolo Bonzini {
35449ab747fSPaolo Bonzini     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
35549ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
35649ab747fSPaolo Bonzini 
35749ab747fSPaolo Bonzini     DPRINTF("scsi_write_complete() ret = %d\n", ret);
358fa0d653bSPaolo Bonzini 
359fa0d653bSPaolo Bonzini     assert(r->req.aiocb != NULL);
36049ab747fSPaolo Bonzini     r->req.aiocb = NULL;
361fa0d653bSPaolo Bonzini 
362b9e413ddSPaolo Bonzini     aio_context_acquire(blk_get_aio_context(s->conf.blk));
363b9e413ddSPaolo Bonzini 
3646c25fa6cSFam Zheng     if (ret || r->req.io_canceled) {
365fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
366b9e413ddSPaolo Bonzini         goto done;
36749ab747fSPaolo Bonzini     }
36849ab747fSPaolo Bonzini 
36949ab747fSPaolo Bonzini     if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
37049ab747fSPaolo Bonzini         s->type == TYPE_TAPE) {
37149ab747fSPaolo Bonzini         s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
37249ab747fSPaolo Bonzini         DPRINTF("block size %d\n", s->blocksize);
37349ab747fSPaolo Bonzini     }
37449ab747fSPaolo Bonzini 
375fa0d653bSPaolo Bonzini     scsi_command_complete_noio(r, ret);
376b9e413ddSPaolo Bonzini 
377b9e413ddSPaolo Bonzini done:
378b9e413ddSPaolo Bonzini     aio_context_release(blk_get_aio_context(s->conf.blk));
37949ab747fSPaolo Bonzini }
38049ab747fSPaolo Bonzini 
38149ab747fSPaolo Bonzini /* Write data to a scsi device.  Returns nonzero on failure.
38249ab747fSPaolo Bonzini    The transfer may complete asynchronously.  */
38349ab747fSPaolo Bonzini static void scsi_write_data(SCSIRequest *req)
38449ab747fSPaolo Bonzini {
38549ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
38649ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
38749ab747fSPaolo Bonzini     int ret;
38849ab747fSPaolo Bonzini 
3892e144aa7SEric Farman     DPRINTF("scsi_write_data tag=0x%x\n", req->tag);
39049ab747fSPaolo Bonzini     if (r->len == 0) {
39149ab747fSPaolo Bonzini         r->len = r->buflen;
39249ab747fSPaolo Bonzini         scsi_req_data(&r->req, r->len);
39349ab747fSPaolo Bonzini         return;
39449ab747fSPaolo Bonzini     }
39549ab747fSPaolo Bonzini 
39649ab747fSPaolo Bonzini     /* The request is used as the AIO opaque value, so add a ref.  */
39749ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
3984be74634SMarkus Armbruster     ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete);
39949ab747fSPaolo Bonzini     if (ret < 0) {
400fa0d653bSPaolo Bonzini         scsi_command_complete_noio(r, ret);
40149ab747fSPaolo Bonzini     }
40249ab747fSPaolo Bonzini }
40349ab747fSPaolo Bonzini 
40449ab747fSPaolo Bonzini /* Return a pointer to the data buffer.  */
40549ab747fSPaolo Bonzini static uint8_t *scsi_get_buf(SCSIRequest *req)
40649ab747fSPaolo Bonzini {
40749ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
40849ab747fSPaolo Bonzini 
40949ab747fSPaolo Bonzini     return r->buf;
41049ab747fSPaolo Bonzini }
41149ab747fSPaolo Bonzini 
41249ab747fSPaolo Bonzini /* Execute a scsi command.  Returns the length of the data expected by the
41349ab747fSPaolo Bonzini    command.  This will be Positive for data transfers from the device
41449ab747fSPaolo Bonzini    (eg. disk reads), negative for transfers to the device (eg. disk writes),
41549ab747fSPaolo Bonzini    and zero if the command does not transfer any data.  */
41649ab747fSPaolo Bonzini 
41749ab747fSPaolo Bonzini static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
41849ab747fSPaolo Bonzini {
41949ab747fSPaolo Bonzini     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
42049ab747fSPaolo Bonzini     SCSIDevice *s = r->req.dev;
42149ab747fSPaolo Bonzini     int ret;
42249ab747fSPaolo Bonzini 
42349ab747fSPaolo Bonzini #ifdef DEBUG_SCSI
4242e144aa7SEric Farman     DPRINTF("Command: data=0x%02x", cmd[0]);
42549ab747fSPaolo Bonzini     {
42649ab747fSPaolo Bonzini         int i;
42749ab747fSPaolo Bonzini         for (i = 1; i < r->req.cmd.len; i++) {
42849ab747fSPaolo Bonzini             printf(" 0x%02x", cmd[i]);
42949ab747fSPaolo Bonzini         }
43049ab747fSPaolo Bonzini         printf("\n");
43149ab747fSPaolo Bonzini     }
43249ab747fSPaolo Bonzini #endif
43349ab747fSPaolo Bonzini 
43449ab747fSPaolo Bonzini     if (r->req.cmd.xfer == 0) {
43549ab747fSPaolo Bonzini         g_free(r->buf);
43649ab747fSPaolo Bonzini         r->buflen = 0;
43749ab747fSPaolo Bonzini         r->buf = NULL;
43849ab747fSPaolo Bonzini         /* The request is used as the AIO opaque value, so add a ref.  */
43949ab747fSPaolo Bonzini         scsi_req_ref(&r->req);
4404be74634SMarkus Armbruster         ret = execute_command(s->conf.blk, r, SG_DXFER_NONE,
4414be74634SMarkus Armbruster                               scsi_command_complete);
44249ab747fSPaolo Bonzini         if (ret < 0) {
443fa0d653bSPaolo Bonzini             scsi_command_complete_noio(r, ret);
44449ab747fSPaolo Bonzini             return 0;
44549ab747fSPaolo Bonzini         }
44649ab747fSPaolo Bonzini         return 0;
44749ab747fSPaolo Bonzini     }
44849ab747fSPaolo Bonzini 
44949ab747fSPaolo Bonzini     if (r->buflen != r->req.cmd.xfer) {
45049ab747fSPaolo Bonzini         g_free(r->buf);
45149ab747fSPaolo Bonzini         r->buf = g_malloc(r->req.cmd.xfer);
45249ab747fSPaolo Bonzini         r->buflen = r->req.cmd.xfer;
45349ab747fSPaolo Bonzini     }
45449ab747fSPaolo Bonzini 
45549ab747fSPaolo Bonzini     memset(r->buf, 0, r->buflen);
45649ab747fSPaolo Bonzini     r->len = r->req.cmd.xfer;
45749ab747fSPaolo Bonzini     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
45849ab747fSPaolo Bonzini         r->len = 0;
45949ab747fSPaolo Bonzini         return -r->req.cmd.xfer;
46049ab747fSPaolo Bonzini     } else {
46149ab747fSPaolo Bonzini         return r->req.cmd.xfer;
46249ab747fSPaolo Bonzini     }
46349ab747fSPaolo Bonzini }
46449ab747fSPaolo Bonzini 
4659fd7e859SPaolo Bonzini static int read_naa_id(const uint8_t *p, uint64_t *p_wwn)
4669fd7e859SPaolo Bonzini {
4679fd7e859SPaolo Bonzini     int i;
4689fd7e859SPaolo Bonzini 
4699fd7e859SPaolo Bonzini     if ((p[1] & 0xF) == 3) {
4709fd7e859SPaolo Bonzini         /* NAA designator type */
4719fd7e859SPaolo Bonzini         if (p[3] != 8) {
4729fd7e859SPaolo Bonzini             return -EINVAL;
4739fd7e859SPaolo Bonzini         }
4749fd7e859SPaolo Bonzini         *p_wwn = ldq_be_p(p + 4);
4759fd7e859SPaolo Bonzini         return 0;
4769fd7e859SPaolo Bonzini     }
4779fd7e859SPaolo Bonzini 
4789fd7e859SPaolo Bonzini     if ((p[1] & 0xF) == 8) {
4799fd7e859SPaolo Bonzini         /* SCSI name string designator type */
4809fd7e859SPaolo Bonzini         if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) {
4819fd7e859SPaolo Bonzini             return -EINVAL;
4829fd7e859SPaolo Bonzini         }
4839fd7e859SPaolo Bonzini         if (p[3] > 20 && p[24] != ',') {
4849fd7e859SPaolo Bonzini             return -EINVAL;
4859fd7e859SPaolo Bonzini         }
4869fd7e859SPaolo Bonzini         *p_wwn = 0;
4879fd7e859SPaolo Bonzini         for (i = 8; i < 24; i++) {
48895a5befcSPeter Maydell             char c = qemu_toupper(p[i]);
4899fd7e859SPaolo Bonzini             c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10);
4909fd7e859SPaolo Bonzini             *p_wwn = (*p_wwn << 4) | c;
4919fd7e859SPaolo Bonzini         }
4929fd7e859SPaolo Bonzini         return 0;
4939fd7e859SPaolo Bonzini     }
4949fd7e859SPaolo Bonzini 
4959fd7e859SPaolo Bonzini     return -EINVAL;
4969fd7e859SPaolo Bonzini }
4979fd7e859SPaolo Bonzini 
498a0c7e35bSDaniel Henrique Barboza int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size,
499a0c7e35bSDaniel Henrique Barboza                         uint8_t *buf, uint8_t buf_size)
500a0c7e35bSDaniel Henrique Barboza {
501a0c7e35bSDaniel Henrique Barboza     sg_io_hdr_t io_header;
502a0c7e35bSDaniel Henrique Barboza     uint8_t sensebuf[8];
503a0c7e35bSDaniel Henrique Barboza     int ret;
504a0c7e35bSDaniel Henrique Barboza 
505a0c7e35bSDaniel Henrique Barboza     memset(&io_header, 0, sizeof(io_header));
506a0c7e35bSDaniel Henrique Barboza     io_header.interface_id = 'S';
507a0c7e35bSDaniel Henrique Barboza     io_header.dxfer_direction = SG_DXFER_FROM_DEV;
508a0c7e35bSDaniel Henrique Barboza     io_header.dxfer_len = buf_size;
509a0c7e35bSDaniel Henrique Barboza     io_header.dxferp = buf;
510a0c7e35bSDaniel Henrique Barboza     io_header.cmdp = cmd;
511a0c7e35bSDaniel Henrique Barboza     io_header.cmd_len = cmd_size;
512a0c7e35bSDaniel Henrique Barboza     io_header.mx_sb_len = sizeof(sensebuf);
513a0c7e35bSDaniel Henrique Barboza     io_header.sbp = sensebuf;
514a0c7e35bSDaniel Henrique Barboza     io_header.timeout = 6000; /* XXX */
515a0c7e35bSDaniel Henrique Barboza 
516a0c7e35bSDaniel Henrique Barboza     ret = blk_ioctl(blk, SG_IO, &io_header);
517a0c7e35bSDaniel Henrique Barboza     if (ret < 0 || io_header.driver_status || io_header.host_status) {
518a0c7e35bSDaniel Henrique Barboza         return -1;
519a0c7e35bSDaniel Henrique Barboza     }
520a0c7e35bSDaniel Henrique Barboza     return 0;
521a0c7e35bSDaniel Henrique Barboza }
522a0c7e35bSDaniel Henrique Barboza 
523a71c775bSDaniel Henrique Barboza /*
524a71c775bSDaniel Henrique Barboza  * Executes an INQUIRY request with EVPD set to retrieve the
525a71c775bSDaniel Henrique Barboza  * available VPD pages of the device. If the device does
526a71c775bSDaniel Henrique Barboza  * not support the Block Limits page (page 0xb0), set
527a71c775bSDaniel Henrique Barboza  * the needs_vpd_bl_emulation flag for future use.
528a71c775bSDaniel Henrique Barboza  */
529a71c775bSDaniel Henrique Barboza static void scsi_generic_set_vpd_bl_emulation(SCSIDevice *s)
530a71c775bSDaniel Henrique Barboza {
531a71c775bSDaniel Henrique Barboza     uint8_t cmd[6];
532a71c775bSDaniel Henrique Barboza     uint8_t buf[250];
533a71c775bSDaniel Henrique Barboza     uint8_t page_len;
534a71c775bSDaniel Henrique Barboza     int ret, i;
535a71c775bSDaniel Henrique Barboza 
536a71c775bSDaniel Henrique Barboza     memset(cmd, 0, sizeof(cmd));
537a71c775bSDaniel Henrique Barboza     memset(buf, 0, sizeof(buf));
538a71c775bSDaniel Henrique Barboza     cmd[0] = INQUIRY;
539a71c775bSDaniel Henrique Barboza     cmd[1] = 1;
540a71c775bSDaniel Henrique Barboza     cmd[2] = 0x00;
541a71c775bSDaniel Henrique Barboza     cmd[4] = sizeof(buf);
542a71c775bSDaniel Henrique Barboza 
543a71c775bSDaniel Henrique Barboza     ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
544a71c775bSDaniel Henrique Barboza                               buf, sizeof(buf));
545a71c775bSDaniel Henrique Barboza     if (ret < 0) {
546a71c775bSDaniel Henrique Barboza         /*
547a71c775bSDaniel Henrique Barboza          * Do not assume anything if we can't retrieve the
548a71c775bSDaniel Henrique Barboza          * INQUIRY response to assert the VPD Block Limits
549a71c775bSDaniel Henrique Barboza          * support.
550a71c775bSDaniel Henrique Barboza          */
551a71c775bSDaniel Henrique Barboza         s->needs_vpd_bl_emulation = false;
552a71c775bSDaniel Henrique Barboza         return;
553a71c775bSDaniel Henrique Barboza     }
554a71c775bSDaniel Henrique Barboza 
555a71c775bSDaniel Henrique Barboza     page_len = buf[3];
55657dbb58dSPaolo Bonzini     for (i = 4; i < MIN(sizeof(buf), page_len + 4); i++) {
557a71c775bSDaniel Henrique Barboza         if (buf[i] == 0xb0) {
558a71c775bSDaniel Henrique Barboza             s->needs_vpd_bl_emulation = false;
559a71c775bSDaniel Henrique Barboza             return;
560a71c775bSDaniel Henrique Barboza         }
561a71c775bSDaniel Henrique Barboza     }
562a71c775bSDaniel Henrique Barboza     s->needs_vpd_bl_emulation = true;
563a71c775bSDaniel Henrique Barboza }
564a71c775bSDaniel Henrique Barboza 
565a71c775bSDaniel Henrique Barboza static void scsi_generic_read_device_identification(SCSIDevice *s)
5669fd7e859SPaolo Bonzini {
5679fd7e859SPaolo Bonzini     uint8_t cmd[6];
5689fd7e859SPaolo Bonzini     uint8_t buf[250];
5699fd7e859SPaolo Bonzini     int ret;
5709fd7e859SPaolo Bonzini     int i, len;
5719fd7e859SPaolo Bonzini 
5729fd7e859SPaolo Bonzini     memset(cmd, 0, sizeof(cmd));
5739fd7e859SPaolo Bonzini     memset(buf, 0, sizeof(buf));
5749fd7e859SPaolo Bonzini     cmd[0] = INQUIRY;
5759fd7e859SPaolo Bonzini     cmd[1] = 1;
5769fd7e859SPaolo Bonzini     cmd[2] = 0x83;
5779fd7e859SPaolo Bonzini     cmd[4] = sizeof(buf);
5789fd7e859SPaolo Bonzini 
579a0c7e35bSDaniel Henrique Barboza     ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
580a0c7e35bSDaniel Henrique Barboza                               buf, sizeof(buf));
581a0c7e35bSDaniel Henrique Barboza     if (ret < 0) {
5829fd7e859SPaolo Bonzini         return;
5839fd7e859SPaolo Bonzini     }
5849fd7e859SPaolo Bonzini 
5859fd7e859SPaolo Bonzini     len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4);
5869fd7e859SPaolo Bonzini     for (i = 0; i + 3 <= len; ) {
5879fd7e859SPaolo Bonzini         const uint8_t *p = &buf[i + 4];
5889fd7e859SPaolo Bonzini         uint64_t wwn;
5899fd7e859SPaolo Bonzini 
5909fd7e859SPaolo Bonzini         if (i + (p[3] + 4) > len) {
5919fd7e859SPaolo Bonzini             break;
5929fd7e859SPaolo Bonzini         }
5939fd7e859SPaolo Bonzini 
5949fd7e859SPaolo Bonzini         if ((p[1] & 0x10) == 0) {
5959fd7e859SPaolo Bonzini             /* Associated with the logical unit */
5969fd7e859SPaolo Bonzini             if (read_naa_id(p, &wwn) == 0) {
5979fd7e859SPaolo Bonzini                 s->wwn = wwn;
5989fd7e859SPaolo Bonzini             }
5999fd7e859SPaolo Bonzini         } else if ((p[1] & 0x10) == 0x10) {
6009fd7e859SPaolo Bonzini             /* Associated with the target port */
6019fd7e859SPaolo Bonzini             if (read_naa_id(p, &wwn) == 0) {
6029fd7e859SPaolo Bonzini                 s->port_wwn = wwn;
6039fd7e859SPaolo Bonzini             }
6049fd7e859SPaolo Bonzini         }
6059fd7e859SPaolo Bonzini 
6069fd7e859SPaolo Bonzini         i += p[3] + 4;
6079fd7e859SPaolo Bonzini     }
6089fd7e859SPaolo Bonzini }
6099fd7e859SPaolo Bonzini 
610a71c775bSDaniel Henrique Barboza void scsi_generic_read_device_inquiry(SCSIDevice *s)
611a71c775bSDaniel Henrique Barboza {
612a71c775bSDaniel Henrique Barboza     scsi_generic_read_device_identification(s);
613a71c775bSDaniel Henrique Barboza     if (s->type == TYPE_DISK) {
614a71c775bSDaniel Henrique Barboza         scsi_generic_set_vpd_bl_emulation(s);
615a71c775bSDaniel Henrique Barboza     } else {
616a71c775bSDaniel Henrique Barboza         s->needs_vpd_bl_emulation = false;
617a71c775bSDaniel Henrique Barboza     }
618a71c775bSDaniel Henrique Barboza }
619a71c775bSDaniel Henrique Barboza 
6204be74634SMarkus Armbruster static int get_stream_blocksize(BlockBackend *blk)
62149ab747fSPaolo Bonzini {
62249ab747fSPaolo Bonzini     uint8_t cmd[6];
62349ab747fSPaolo Bonzini     uint8_t buf[12];
62449ab747fSPaolo Bonzini     int ret;
62549ab747fSPaolo Bonzini 
62649ab747fSPaolo Bonzini     memset(cmd, 0, sizeof(cmd));
62749ab747fSPaolo Bonzini     memset(buf, 0, sizeof(buf));
62849ab747fSPaolo Bonzini     cmd[0] = MODE_SENSE;
62949ab747fSPaolo Bonzini     cmd[4] = sizeof(buf);
63049ab747fSPaolo Bonzini 
631a0c7e35bSDaniel Henrique Barboza     ret = scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf));
632a0c7e35bSDaniel Henrique Barboza     if (ret < 0) {
63349ab747fSPaolo Bonzini         return -1;
63449ab747fSPaolo Bonzini     }
635a0c7e35bSDaniel Henrique Barboza 
63649ab747fSPaolo Bonzini     return (buf[9] << 16) | (buf[10] << 8) | buf[11];
63749ab747fSPaolo Bonzini }
63849ab747fSPaolo Bonzini 
63949ab747fSPaolo Bonzini static void scsi_generic_reset(DeviceState *dev)
64049ab747fSPaolo Bonzini {
64149ab747fSPaolo Bonzini     SCSIDevice *s = SCSI_DEVICE(dev);
64249ab747fSPaolo Bonzini 
6432343be0dSPaolo Bonzini     s->scsi_version = s->default_scsi_version;
64449ab747fSPaolo Bonzini     scsi_device_purge_requests(s, SENSE_CODE(RESET));
64549ab747fSPaolo Bonzini }
64649ab747fSPaolo Bonzini 
647a818a4b6SFam Zheng static void scsi_generic_realize(SCSIDevice *s, Error **errp)
64849ab747fSPaolo Bonzini {
6496ee143a0SPaolo Bonzini     int rc;
65049ab747fSPaolo Bonzini     int sg_version;
65149ab747fSPaolo Bonzini     struct sg_scsi_id scsiid;
65249ab747fSPaolo Bonzini 
6534be74634SMarkus Armbruster     if (!s->conf.blk) {
654a818a4b6SFam Zheng         error_setg(errp, "drive property not set");
655a818a4b6SFam Zheng         return;
65649ab747fSPaolo Bonzini     }
65749ab747fSPaolo Bonzini 
6584be74634SMarkus Armbruster     if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
659a818a4b6SFam Zheng         error_setg(errp, "Device doesn't support drive option werror");
660a818a4b6SFam Zheng         return;
66149ab747fSPaolo Bonzini     }
6624be74634SMarkus Armbruster     if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
663a818a4b6SFam Zheng         error_setg(errp, "Device doesn't support drive option rerror");
664a818a4b6SFam Zheng         return;
66549ab747fSPaolo Bonzini     }
66649ab747fSPaolo Bonzini 
66749ab747fSPaolo Bonzini     /* check we are using a driver managing SG_IO (version 3 and after */
6684be74634SMarkus Armbruster     rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version);
6696ee143a0SPaolo Bonzini     if (rc < 0) {
67009c2c6ffSPaolo Bonzini         error_setg_errno(errp, -rc, "cannot get SG_IO version number");
67109c2c6ffSPaolo Bonzini         if (rc != -EPERM) {
67209c2c6ffSPaolo Bonzini             error_append_hint(errp, "Is this a SCSI device?\n");
67309c2c6ffSPaolo Bonzini         }
674a818a4b6SFam Zheng         return;
67549ab747fSPaolo Bonzini     }
67649ab747fSPaolo Bonzini     if (sg_version < 30000) {
677a818a4b6SFam Zheng         error_setg(errp, "scsi generic interface too old");
678a818a4b6SFam Zheng         return;
67949ab747fSPaolo Bonzini     }
68049ab747fSPaolo Bonzini 
68149ab747fSPaolo Bonzini     /* get LUN of the /dev/sg? */
6824be74634SMarkus Armbruster     if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) {
683a818a4b6SFam Zheng         error_setg(errp, "SG_GET_SCSI_ID ioctl failed");
684a818a4b6SFam Zheng         return;
68549ab747fSPaolo Bonzini     }
686c6caae55SFam Zheng     if (!blkconf_apply_backend_options(&s->conf,
687d9bcd6f7SFam Zheng                                        blk_is_read_only(s->conf.blk),
688c6caae55SFam Zheng                                        true, errp)) {
689d9bcd6f7SFam Zheng         return;
690d9bcd6f7SFam Zheng     }
69149ab747fSPaolo Bonzini 
69249ab747fSPaolo Bonzini     /* define device state */
69349ab747fSPaolo Bonzini     s->type = scsiid.scsi_type;
69449ab747fSPaolo Bonzini     DPRINTF("device type %d\n", s->type);
69549ab747fSPaolo Bonzini 
69649ab747fSPaolo Bonzini     switch (s->type) {
69749ab747fSPaolo Bonzini     case TYPE_TAPE:
6984be74634SMarkus Armbruster         s->blocksize = get_stream_blocksize(s->conf.blk);
69949ab747fSPaolo Bonzini         if (s->blocksize == -1) {
70049ab747fSPaolo Bonzini             s->blocksize = 0;
70149ab747fSPaolo Bonzini         }
70249ab747fSPaolo Bonzini         break;
70349ab747fSPaolo Bonzini 
70449ab747fSPaolo Bonzini         /* Make a guess for block devices, we'll fix it when the guest sends.
70549ab747fSPaolo Bonzini          * READ CAPACITY.  If they don't, they likely would assume these sizes
70649ab747fSPaolo Bonzini          * anyway. (TODO: they could also send MODE SENSE).
70749ab747fSPaolo Bonzini          */
70849ab747fSPaolo Bonzini     case TYPE_ROM:
70949ab747fSPaolo Bonzini     case TYPE_WORM:
71049ab747fSPaolo Bonzini         s->blocksize = 2048;
71149ab747fSPaolo Bonzini         break;
71249ab747fSPaolo Bonzini     default:
71349ab747fSPaolo Bonzini         s->blocksize = 512;
71449ab747fSPaolo Bonzini         break;
71549ab747fSPaolo Bonzini     }
71649ab747fSPaolo Bonzini 
71749ab747fSPaolo Bonzini     DPRINTF("block size %d\n", s->blocksize);
7189fd7e859SPaolo Bonzini 
71929e560f0SDaniel Henrique Barboza     /* Only used by scsi-block, but initialize it nevertheless to be clean.  */
72029e560f0SDaniel Henrique Barboza     s->default_scsi_version = -1;
721a71c775bSDaniel Henrique Barboza     scsi_generic_read_device_inquiry(s);
72249ab747fSPaolo Bonzini }
72349ab747fSPaolo Bonzini 
72449ab747fSPaolo Bonzini const SCSIReqOps scsi_generic_req_ops = {
72549ab747fSPaolo Bonzini     .size         = sizeof(SCSIGenericReq),
72649ab747fSPaolo Bonzini     .free_req     = scsi_free_request,
72749ab747fSPaolo Bonzini     .send_command = scsi_send_command,
72849ab747fSPaolo Bonzini     .read_data    = scsi_read_data,
72949ab747fSPaolo Bonzini     .write_data   = scsi_write_data,
73049ab747fSPaolo Bonzini     .get_buf      = scsi_get_buf,
73149ab747fSPaolo Bonzini     .load_request = scsi_generic_load_request,
73249ab747fSPaolo Bonzini     .save_request = scsi_generic_save_request,
73349ab747fSPaolo Bonzini };
73449ab747fSPaolo Bonzini 
73549ab747fSPaolo Bonzini static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
73649ab747fSPaolo Bonzini                                      uint8_t *buf, void *hba_private)
73749ab747fSPaolo Bonzini {
7389be38598SEduardo Habkost     return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
73949ab747fSPaolo Bonzini }
74049ab747fSPaolo Bonzini 
74149ab747fSPaolo Bonzini static Property scsi_generic_properties[] = {
7424be74634SMarkus Armbruster     DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
743d9bcd6f7SFam Zheng     DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false),
74449ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
74549ab747fSPaolo Bonzini };
74649ab747fSPaolo Bonzini 
7473e7e180aSPaolo Bonzini static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
7483e7e180aSPaolo Bonzini                                   uint8_t *buf, void *hba_private)
7493e7e180aSPaolo Bonzini {
7503e7e180aSPaolo Bonzini     return scsi_bus_parse_cdb(dev, cmd, buf, hba_private);
7513e7e180aSPaolo Bonzini }
7523e7e180aSPaolo Bonzini 
75349ab747fSPaolo Bonzini static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
75449ab747fSPaolo Bonzini {
75549ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
75649ab747fSPaolo Bonzini     SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
75749ab747fSPaolo Bonzini 
758a818a4b6SFam Zheng     sc->realize      = scsi_generic_realize;
75949ab747fSPaolo Bonzini     sc->alloc_req    = scsi_new_request;
7603e7e180aSPaolo Bonzini     sc->parse_cdb    = scsi_generic_parse_cdb;
76149ab747fSPaolo Bonzini     dc->fw_name = "disk";
76249ab747fSPaolo Bonzini     dc->desc = "pass through generic scsi device (/dev/sg*)";
76349ab747fSPaolo Bonzini     dc->reset = scsi_generic_reset;
76449ab747fSPaolo Bonzini     dc->props = scsi_generic_properties;
76549ab747fSPaolo Bonzini     dc->vmsd  = &vmstate_scsi_device;
76649ab747fSPaolo Bonzini }
76749ab747fSPaolo Bonzini 
76849ab747fSPaolo Bonzini static const TypeInfo scsi_generic_info = {
76949ab747fSPaolo Bonzini     .name          = "scsi-generic",
77049ab747fSPaolo Bonzini     .parent        = TYPE_SCSI_DEVICE,
77149ab747fSPaolo Bonzini     .instance_size = sizeof(SCSIDevice),
77249ab747fSPaolo Bonzini     .class_init    = scsi_generic_class_initfn,
77349ab747fSPaolo Bonzini };
77449ab747fSPaolo Bonzini 
77549ab747fSPaolo Bonzini static void scsi_generic_register_types(void)
77649ab747fSPaolo Bonzini {
77749ab747fSPaolo Bonzini     type_register_static(&scsi_generic_info);
77849ab747fSPaolo Bonzini }
77949ab747fSPaolo Bonzini 
78049ab747fSPaolo Bonzini type_init(scsi_generic_register_types)
78149ab747fSPaolo Bonzini 
78249ab747fSPaolo Bonzini #endif /* __linux__ */
783