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